打印服务

This commit is contained in:
wuyy 2026-04-02 18:01:47 +08:00
parent 7dee664561
commit 4909e9b67b
12 changed files with 331 additions and 140 deletions

View File

@ -348,9 +348,9 @@ const setLabel = (val: any) => {
const clearHandle = () => { const clearHandle = () => {
selectShowValue.value = ''; selectShowValue.value = '';
currentRow.value = null; currentRow.value = null;
tableRef.value.clearCurrentRow();
emits("update:data", null); emits("update:data", null);
emits('getDataValue', null); emits('getDataValue', null);
tableRef.value?.clearCurrentRow();
}; };
</script> </script>

View File

@ -2,11 +2,11 @@
<section class="app-main"> <section class="app-main">
<router-view v-slot="{ Component, route }"> <router-view v-slot="{ Component, route }">
<transition name="fade-transform" mode="out-in"> <transition name="fade-transform" mode="out-in">
<keep-alive :include="tagsViewStore.cachedViews"> <el-watermark :font="font" :content="content">
<el-watermark :font="font" :content="content"> <keep-alive :include="tagsViewStore.cachedViews">
<component v-if="!route.meta.link" :is="Component" :key="route.path" /> <component v-if="!route.meta.link" :is="Component" :key="route.path" />
</el-watermark> </keep-alive>
</keep-alive> </el-watermark>
</transition> </transition>
</router-view> </router-view>
<iframe-toggle /> <iframe-toggle />

View File

@ -15,7 +15,22 @@ export default {
method: 'get', method: 'get',
url: url, url: url,
responseType: 'blob', responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() } headers: { 'Authorization': 'Bearer ' + getToken() },
onDownloadProgress: (progressEvent) => {
// console.log(progressEvent)
//progressEvent.loaded 下载文件的当前大小
//progressEvent.total 下载文件的总大小 如果后端没有返回 请让他加上
let progressPercent = Math.round((progressEvent.loaded / progressEvent.total) * 100);
let loading = ElLoading.service({
lock: true,
text: `下载中,请稍候${progressPercent}%`,
background: 'rgba(0, 0, 0, 0.7)',
})
loading.setText(`下载中,请稍候${progressPercent}%`)
if (progressPercent == 100) {
loading.close()
}
}
}).then((res: any) => { }).then((res: any) => {
const isBlob = blobValidate(res.data) const isBlob = blobValidate(res.data)
if (isBlob) { if (isBlob) {

View File

@ -20,6 +20,7 @@ interface UserState {
roles: string[] roles: string[]
permissions: string[] permissions: string[]
sysLoginParam: Object sysLoginParam: Object
deptParam: Object
} }
const useUserStore = defineStore( const useUserStore = defineStore(
@ -35,6 +36,7 @@ const useUserStore = defineStore(
roles: [], roles: [],
permissions: [], permissions: [],
sysLoginParam: {}, // 登录参数 sysLoginParam: {}, // 登录参数
deptParam: {} // 部门参数
}), }),
actions: { actions: {
// 单点登录 // 单点登录
@ -79,6 +81,7 @@ const useUserStore = defineStore(
const user = res.user const user = res.user
let avatar = user.avatar || '' let avatar = user.avatar || ''
this.sysLoginParam = user.sysLoginParam this.sysLoginParam = user.sysLoginParam
this.deptParam = user.dept
if (!isHttp(avatar)) { if (!isHttp(avatar)) {
avatar = (isEmpty(avatar)) ? defAva : import.meta.env.VITE_APP_BASE_API + avatar avatar = (isEmpty(avatar)) ? defAva : import.meta.env.VITE_APP_BASE_API + avatar
} }

View File

@ -48,4 +48,29 @@ export function checkRole(value: string[]): boolean {
}) })
return hasRole return hasRole
} }
/**
* 管理员、检测机构权限校验
* @param value 校验值
* @returns {Boolean}
*/
export function checkDeptRole(value: string[]): boolean {
if (!value || !(value instanceof Array) || value.length === 0) {
console.error(`need roles! Like checkRole="['admin','editor']"`)
return false
}
const userStore = useUserStore()
const roles = userStore.roles
const permissionRoles = value
const deptParam = userStore.deptParam
// 取出 roleKey 进行判断
const hasRole = roles.some((role: any) => {
const roleKey = role.roleKey || ''
// 是超级管理员 admin 或者 包含指定角色 、 检测机构人员权限 203
return roleKey === 'admin' || permissionRoles.includes(roleKey) || deptParam.parentId == 203
})
return hasRole
}

View File

@ -7,15 +7,14 @@
import { ElMessageBox, ElMessage } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import { printcheck } from '@/api/checkCode/index' import { printcheck } from '@/api/checkCode/index'
import Download from '@/plugins/download' import Download from '@/plugins/download'
import { getWebSocketState } from '@/utils/webSocket';
export const checkPrintService = async (): Promise<boolean> => { //连接成功返回true,失败返回false export const checkPrintService = async (): Promise<boolean> => { //连接成功返回true,失败返回false
try { try {
const res = await printcheck() if (getWebSocketState() == 1) { // 1表示WebSocket已连接
if (res.code == 0) {
return true return true
} else { } else {
await showPrintServiceError(res.msg) await showPrintServiceError('打印服务未连接')
return false return false
} }
} catch (error) { } catch (error) {

103
src/utils/webSocket.ts Normal file
View File

@ -0,0 +1,103 @@
// WebSocket连接配置
type WebSocketOptions = {
fullUrl: string;
onMessage?: (data: string) => void;
onOpen?: () => void;
onError?: (error: Event) => void;
onClose?: () => void;
reconnectInterval?: number;
};
let websocket: WebSocket | null = null;
let reconnectTimer: any = null;
let isManualClose = false;
// 初始化WebSocket连接
export function initWebSocket(options: WebSocketOptions) {
const {
fullUrl,
onMessage,
onOpen,
onError,
onClose,
reconnectInterval = 3000
} = options;
// 关闭旧连接
if (websocket) {
websocket.close();
}
// 检查浏览器支持性
if (!('WebSocket' in window)) {
console.error('当前浏览器不支持WebSocket');
return;
}
// 创建WebSocket连接
try {
websocket = new WebSocket(fullUrl);
// 连接成功回调
websocket.onopen = () => {
clearTimeout(reconnectTimer!);
isManualClose = false;
onOpen?.();
};
// 接收消息回调
websocket.onmessage = (event) => {
onMessage?.(event.data);
};
// 错误回调
websocket.onerror = (error) => {
onError?.(error);
startReconnect(() => initWebSocket(options), reconnectInterval);
};
// 关闭回调
websocket.onclose = () => {
onClose?.();
if (!isManualClose) {
startReconnect(() => initWebSocket(options), reconnectInterval);
}
};
} catch (error) {
console.error('WebSocket连接创建失败:', error);
startReconnect(() => initWebSocket(options), reconnectInterval);
}
}
// 发送消息
export function sendWebSocketMessage(message: any): boolean {
if (websocket && websocket.readyState === WebSocket.OPEN) {
websocket.send(JSON.stringify(message));
return true;
}
console.error('WebSocket未连接,无法发送消息');
return false;
}
// 手动关闭WebSocket
export function closeWebSocket(): void {
isManualClose = true;
if (reconnectTimer) {
clearTimeout(reconnectTimer);
}
websocket?.close();
websocket = null;
}
// 启动重连
function startReconnect(connectCallback: () => void, interval: number): void {
if (reconnectTimer) {
clearTimeout(reconnectTimer);
}
reconnectTimer = setTimeout(connectCallback, interval);
}
// 获取当前连接状态
export function getWebSocketState(): number | null {
return websocket?.readyState || null;
}

View File

@ -11,10 +11,10 @@
<div class="box-shadow"> <div class="box-shadow">
<el-row class="top-box"> <el-row class="top-box">
<el-col :span="8" class="col_box"> <el-col :span="8" class="col_box">
<el-button type="primary" :loading="saveLoading" @click="saveHandle">保存</el-button> <el-button type="primary" :size="aotuSize" :loading="saveLoading" @click="saveHandle">保存</el-button>
<el-button type="primary" @click="addHandle">新增</el-button> <el-button type="primary" :size="aotuSize" @click="addHandle">新增</el-button>
<el-button type="primary" :loading="printLoading" @click="printHandle">打印</el-button> <el-button type="primary" :size="aotuSize" :loading="printLoading" @click="printHandle">打印</el-button>
<el-button type="danger" @click="deleteHandle">作废</el-button> <el-button type="danger" :size="aotuSize" @click="deleteHandle">作废</el-button>
</el-col> </el-col>
<el-col :span="16"> <el-col :span="16">
<div class="tips"> <div class="tips">
@ -72,12 +72,12 @@
<div class="box-shadow"> <div class="box-shadow">
<el-form :model="searchForm" inline> <el-form :model="searchForm" inline>
<el-form-item label="" prop="brxm"> <el-form-item label="" prop="brxm">
<el-input v-model="searchForm.brxm" clearable style="width: 8rem;" @change="handleQuery" <el-input v-model="searchForm.brxm" clearable style="width: 8rem;" @change="handleQuery" :size="aotuSize"
placeholder="请输入姓名" /> placeholder="请输入姓名" />
</el-form-item> </el-form-item>
<el-form-item label="" prop="status"> <el-form-item label="" prop="status">
<div class="radio_box"> <div class="radio_box">
<el-radio-group v-model="searchForm.status" @change="handleQuery" size="small"> <el-radio-group v-model="searchForm.status" @change="handleQuery" :size="aotuSize">
<el-radio :value="''">所有</el-radio> <el-radio :value="''">所有</el-radio>
<el-radio :value="item.value" v-for="item in dictData.SQDS">{{ item.label }}</el-radio> <el-radio :value="item.value" v-for="item in dictData.SQDS">{{ item.label }}</el-radio>
</el-radio-group> </el-radio-group>
@ -86,7 +86,7 @@
<el-form-item label="" prop="begdate"> <el-form-item label="" prop="begdate">
<div class="radio_box"> <div class="radio_box">
<el-radio-group v-model="searchForm.days" @change="changeDays" size="small"> <el-radio-group v-model="searchForm.days" @change="changeDays" :size="aotuSize">
<el-radio :value="3">近3天</el-radio> <el-radio :value="3">近3天</el-radio>
<el-radio :value="7">近7天</el-radio> <el-radio :value="7">近7天</el-radio>
<el-radio :value="0">此日 <el-radio :value="0">此日
@ -96,8 +96,8 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
<el-date-picker v-model="today" type="date" value-format="YYYY-MM-DD" style="width: 9rem;" <el-date-picker v-model="today" type="date" value-format="YYYY-MM-DD" style="width: 9rem;"
@change="dateHandle" /> &nbsp; :size="aotuSize" @change="dateHandle" /> &nbsp;
<el-button type="primary" icon="RefreshRight" @click="handleQuery">刷新</el-button> <el-button type="primary" icon="RefreshRight" :size="aotuSize" @click="handleQuery">刷新</el-button>
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -130,6 +130,9 @@ import { listitemclass } from "@/api/regional/dict/itemclass.ts";
import { classCom } from '@/utils/classCom'; import { classCom } from '@/utils/classCom';
import { useGroupTableData } from '@/utils/groupHelper' import { useGroupTableData } from '@/utils/groupHelper'
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
import { initWebSocket, sendWebSocketMessage, closeWebSocket, getWebSocketState } from '@/utils/webSocket';
const aotuSize = classCom.useAutoSize();
const labpat = ref({ const labpat = ref({
ageUnit: '1' ageUnit: '1'
}) })
@ -383,6 +386,7 @@ const printHandle = () => {
printLoading.value = true printLoading.value = true
reqPrint(uniqueData).then(res => { reqPrint(uniqueData).then(res => {
if (res.code == 0) { if (res.code == 0) {
sendWebSocketMessage(res.data)
handleRowClick({ row: rowInfo.value }) handleRowClick({ row: rowInfo.value })
ElMessage.success('正在打印中...') ElMessage.success('正在打印中...')
handleQuery() handleQuery()
@ -420,11 +424,17 @@ const xmcellStyle = ({ row, column }) => {
const searchList = ref([]) const searchList = ref([])
const handleTabClick = (tab) => { const handleTabClick = (tab) => {
const currentTab = xmdlList.value.find(item => item.dictCode === tab.paneName) if (tab.paneName) {
if (currentTab) { const currentTab = xmdlList.value.find(item => item.dictCode === tab.paneName)
searchList.value = processedTableData.value.filter(item => item.classid === currentTab.dictCode) if (currentTab) {
searchList.value = processedTableData.value.filter(item => item.classid === currentTab.dictCode)
filterData.value = [...searchList.value]
}
} else {
searchList.value = [...processedTableData.value]
filterData.value = [...searchList.value] filterData.value = [...searchList.value]
} }
} }
const processedTableData = ref([]) const processedTableData = ref([])
@ -582,6 +592,7 @@ const getXmList = () => {
listregdict({ dictType: 'CLASS' }).then(response => { listregdict({ dictType: 'CLASS' }).then(response => {
xmdlList.value = response.rows; xmdlList.value = response.rows;
xmdlList.value.unshift({ dictCode: '', dictName: '全部' })
activeName.value = xmdlList.value.length > 0 ? xmdlList.value[0].dictCode : ''; activeName.value = xmdlList.value.length > 0 ? xmdlList.value[0].dictCode : '';
handleTabClick({ paneName: activeName.value }); handleTabClick({ paneName: activeName.value });
}); });
@ -589,7 +600,24 @@ const getXmList = () => {
} }
const itemclassList = ref([]) // 容器类别 const itemclassList = ref([]) // 容器类别
const initSocket = () => {
initWebSocket({
fullUrl: `ws://localhost:9801`,
onOpen: () => {
console.log('WebSocket连接成功');
},
onMessage: (data) => {
console.log(`收到消息: `, JSON.parse(data));
},
onError: (error) => {
console.log(`连接错误: ${error.type}`);
},
onClose: () => {
console.log('WebSocket连接已关闭');
},
reconnectInterval: 3000 // 重连间隔(毫秒)
});
}
onMounted(() => { onMounted(() => {
getXmList() getXmList()
@ -602,7 +630,13 @@ onMounted(() => {
// 初始化初始值 // 初始化初始值
updateInitialData() updateInitialData()
initSocket()
}) })
// 页面卸载时清理
onUnmounted(() => {
closeWebSocket();
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@ -628,7 +662,7 @@ onMounted(() => {
.table-box { .table-box {
margin-top: 2px; margin-top: 2px;
height: calc(100% - 80px); height: calc(100% - 85px);
} }
.el-form-item { .el-form-item {
@ -682,6 +716,10 @@ onMounted(() => {
.el-radio { .el-radio {
margin-right: .3125rem; margin-right: .3125rem;
:deep(.el-radio__label) {
padding-left: .3125rem;
}
} }
} }

View File

@ -1,8 +1,6 @@
<template> <template>
<div class="login"> <div class="login">
<!-- <FloatingLines :enabled-waves="['top', 'middle', 'bottom']" :line-count="[10, 15, 20]" :line-distance="[8, 6, 4]" <el-form ref="loginRef" class="login-form" :model="loginForm" :rules="loginRules" :hide-required-asterisk="true">
:bend-radius="5.0" :bend-strength="-0.5" :interactive="true" :parallax="true" /> -->
<el-form ref="loginRef" class="login-form">
<div class="login-header"> <div class="login-header">
<div class="login-logo"> <div class="login-logo">
<img src="@/assets/images/logo_new.png" alt="系统Logo" /> <img src="@/assets/images/logo_new.png" alt="系统Logo" />
@ -17,14 +15,13 @@
<el-tabs v-model="activeName" type="card" @tab-click="handleClick" class="login-tabs"> <el-tabs v-model="activeName" type="card" @tab-click="handleClick" class="login-tabs">
<!-- 工号登录 Tab --> <!-- 工号登录 Tab -->
<el-tab-pane label="账号密码登录" name="first"> <el-tab-pane label="账号密码登录" name="first">
<el-form-item label="医疗机构:" prop="loginYLJG" class="custom-select"> <el-form-item label="医疗机构:" prop="loginParam.loginYLJG" class="custom-select">
<el-select v-model="loginForm.loginParam.loginYLJG" placeholder="请选择医疗机构" style="width: 100%" <el-select v-model="loginForm.loginParam.loginYLJG" placeholder="请选择医疗机构" style="width: 100%"
@change="handleChange"> @change="handleChange">
<template #prefix> <template #prefix>
<svg-icon icon-class="international" class="el-input__icon input-icon" /> <svg-icon icon-class="international" class="el-input__icon input-icon" />
</template> </template>
<el-option v-for="item in selectOptions" :key="item.id" :label="item.name" <el-option v-for="item in selectOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
:value="item.id.toString()"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -44,12 +41,6 @@
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<!-- 修复:移除空的el-form-item,验证码关闭时不渲染任何内容 -->
<el-form-item prop="code" v-if="!captchaEnabled" size="large">
</el-form-item>
<el-form-item prop="code" label="验 证 码 :" v-if="captchaEnabled"> <el-form-item prop="code" label="验 证 码 :" v-if="captchaEnabled">
<el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 53%" <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 53%"
@keyup.enter="handleLogin"> @keyup.enter="handleLogin">
@ -98,7 +89,7 @@
<div class="el-login-footer"> <div class="el-login-footer">
<span>版权所有(R){{ oem.copyrightyear }} {{ oem.compay }} 电话:{{ oem.phone }} E-mail:{{ oem.Email }} version:{{ <span>版权所有(R){{ oem.copyrightyear }} {{ oem.compay }} 电话:{{ oem.phone }} E-mail:{{ oem.Email }} version:{{
oem.version oem.version
}}</span> }}</span>
</div> </div>
</div> </div>
</template> </template>
@ -106,8 +97,7 @@
<script setup> <script setup>
import { ref, watch, getCurrentInstance, onMounted } from 'vue'; import { ref, watch, getCurrentInstance, onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { useFingerprint } from '@/utils/useFingerprint'; import { getCodeImg, getInfo, getLocalconfig, login } from "@/api/login";
import { getCodeImg, getInfo, getLocalconfig } from "@/api/login";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt"; import { encrypt, decrypt } from "@/utils/jsencrypt";
import useUserStore from '@/store/modules/user'; import useUserStore from '@/store/modules/user';
@ -127,25 +117,25 @@ const oem = ref({
Email: "", Email: "",
copyrightyear: "" copyrightyear: ""
}); });
const loginRef = ref(null); // 修复:直接用ref获取表单引用 const loginRef = useTemplateRef('loginRef');
const loginForm = ref({ const loginForm = ref({
username: "admin", username: "",
password: "", password: "",
rememberMe: false, rememberMe: false,
code: "", code: "",
uuid: "", uuid: "",
loginParam: { loginYLJG: undefined, localid: undefined, loginYLJGName: undefined } loginParam: { loginYLJG: 1, localid: undefined, loginYLJGName: '' }
}); });
const selectOptions = ref([]); const selectOptions = ref([]);
const loginRules = ref({ // 修复:改为ref响应式,方便动态修改 const loginRules = ref({
username: [{ required: true, trigger: "blur", message: "请输入您的账号" }], 'loginParam.loginYLJG': [{ required: true, message: '请选择医疗机构', trigger: 'change' }],
// password: [{ required: true, trigger: "blur", message: "请输入您的密码" }], username: [{ required: true, trigger: "blur", message: "请输入您的工号" }],
hospid: [{ required: true, message: '请选择医疗机构', trigger: 'change' }], password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
code: [{ required: true, trigger: "change", message: "请输入验证码" }] code: [{ required: true, trigger: "change", message: "请输入验证码" }]
}); });
const codeUrl = ref(""); const codeUrl = ref("");
const loading = ref(false); const loading = ref(false);
const captchaEnabled = ref(true); const captchaEnabled = ref(false);
const register = ref(false); const register = ref(false);
const redirect = ref(undefined); const redirect = ref(undefined);
@ -166,33 +156,37 @@ const handleChange = (value) => {
loginForm.value.loginParam.loginYLJGName = item?.name || ''; loginForm.value.loginParam.loginYLJGName = item?.name || '';
} }
// 登录方法(修复proxy.$refs问题) // 登录方法
const handleLogin = async () => { const handleLogin = async () => {
loginForm.value.loginParam.loginYLJG loginRef.value.validate((valid) => {
loading.value = true; if (valid) {
Cookies.set("czlisjy_username", loginForm.value.username, { expires: 30 }); loading.value = true;
Cookies.set("czlisjy_loginYLJG", loginForm.value.loginParam.loginYLJG, { expires: 30 }); Cookies.set("czlisjy_username", loginForm.value.username, { expires: 30 });
Cookies.set("czlisjy_loginYLJGName", loginForm.value.loginParam.loginYLJGName, { expires: 30 }); Cookies.set("czlisjy_loginYLJG", loginForm.value.loginParam.loginYLJG, { expires: 30 });
// 调用action的登录方法 Cookies.set("czlisjy_loginYLJGName", loginForm.value.loginParam.loginYLJGName, { expires: 30 });
userStore.login(loginForm.value).then(() => { // loginForm.value.password = encrypt(loginForm.value.password); // 密码加密
const query = route.query;
const otherQueryParams = Object.keys(query).reduce((acc, cur) => { userStore.login(loginForm.value).then(() => {
if (cur !== "redirect") { const query = route.query;
acc[cur] = query[cur]; const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
} if (cur !== "redirect") {
return acc; acc[cur] = query[cur];
}, {}); }
const targetPath = redirect.value || "/"; return acc;
if (route.path !== targetPath) { }, {});
router.push({ path: targetPath, query: otherQueryParams }); const targetPath = redirect.value || "/";
if (route.path !== targetPath) {
router.push({ path: targetPath, query: otherQueryParams });
}
}).catch(() => {
loading.value = false;
// 重新获取验证码
if (captchaEnabled.value) {
getCode();
}
});
} }
}).catch(() => { })
loading.value = false;
// 重新获取验证码
if (captchaEnabled.value) {
getCode();
}
});
}; };
// 获取验证码 // 获取验证码
@ -203,12 +197,6 @@ const getCode = () => {
codeUrl.value = "data:image/gif;base64," + res.img; codeUrl.value = "data:image/gif;base64," + res.img;
loginForm.value.uuid = res.uuid; loginForm.value.uuid = res.uuid;
} }
// 验证码关闭时移除校验规则,避免报错
if (!captchaEnabled.value) {
loginRules.value.code = [];
} else {
loginRules.value.code = [{ required: true, trigger: "change", message: "请输入验证码" }];
}
}); });
}; };
@ -216,53 +204,31 @@ const getCode = () => {
const getCookie = () => { const getCookie = () => {
const cookieUsername = Cookies.get("czlisjy_username"); const cookieUsername = Cookies.get("czlisjy_username");
const cookieloginYLJG = Cookies.get("czlisjy_loginYLJG"); const cookieloginYLJG = Cookies.get("czlisjy_loginYLJG");
if (cookieUsername !== undefined && cookieUsername !== null && cookieUsername !== "") { loginForm.value.username = cookieUsername;
loginForm.value.username = cookieUsername; if (cookieloginYLJG) {
loginForm.value.loginParam.loginYLJG = Number(cookieloginYLJG);
loginForm.value.loginParam.loginYLJGName = selectOptions.value.find(item => item.id == cookieloginYLJG)?.name || '';
} else {
loginForm.value.loginParam.loginYLJG = selectOptions.value[0]?.id || 1;
loginForm.value.loginParam.loginYLJGName = selectOptions.value[0]?.name || '';
} }
if (cookieloginYLJG !== undefined && cookieloginYLJG !== null && cookieloginYLJG !== "") {
loginForm.value.loginParam.loginYLJG = cookieloginYLJG;
}
// const cookieloginYLJGName = Cookies.get("czlisjy_loginYLJGName");
// if (cookieloginYLJGName !== undefined && cookieloginYLJGName !== null && cookieloginYLJGName !== "") {
// loginForm.value.loginParam.loginYLJGName = cookieloginYLJGName;
// }
}; };
// 获取本地配置 // 获取本地配置
const Localconfig = (localid) => { const Localconfig = () => {
getLocalconfig({ localid }).then(res => { getLocalconfig().then(res => {
if (res) { if (res) {
const { localconfig, hosplist, oem: oemData } = res; const { localconfig, hosplist, oem: oemData } = res;
mbStore.setDefaultConfig(localconfig) mbStore.setDefaultConfig(localconfig)
if (oemData) oem.value = oemData; if (oemData) oem.value = oemData;
selectOptions.value = hosplist || [];
if (JSON.stringify(selectOptions.value) !== JSON.stringify(hosplist)) { getCookie();
selectOptions.value = hosplist || [];
// 判重后赋值,避免重复修改触发更新
if (!selectOptions.value.some(item => item.id === loginForm.value.hospid)) {
loginForm.value.loginParam.loginYLJG = selectOptions.value[0]?.id || 1;
loginForm.value.loginParam.loginYLJGName = selectOptions.value[0]?.name || '';
}
getCookie();
}
} }
}).catch(err => { }).catch(err => {
console.error("获取本地配置失败:", err); console.error("获取本地配置失败:", err);
}); });
}; };
// 获取指纹并加载配置
const { getFingerprint } = useFingerprint();
const refreshFingerprint = async () => {
try {
const res = await getFingerprint();
loginForm.value.loginParam.localid = res.visitorId
Localconfig(res.visitorId);
} catch (err) {
console.error("获取指纹失败:", err);
Localconfig("default"); // 兜底使用默认ID
}
};
// Tab切换事件(移除activeName手动赋值,避免递归) // Tab切换事件(移除activeName手动赋值,避免递归)
const handleClick = (tab) => { const handleClick = (tab) => {
@ -273,11 +239,9 @@ const handleClick = (tab) => {
} }
}; };
// 页面挂载时初始化
onMounted(() => { Localconfig();
refreshFingerprint(); getCode();
getCode();
});
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>

View File

@ -6,7 +6,7 @@
<el-col :span="4"> <el-col :span="4">
<el-form-item label="委托机构:" prop="srcHospName"> <el-form-item label="委托机构:" prop="srcHospName">
<el-input v-model="queryParams.srcHospName" :title="queryParams.srcHospName" :size="aotuSize" readonly <el-input v-model="queryParams.srcHospName" :title="queryParams.srcHospName" :size="aotuSize" readonly
v-if="!checkRole(['admin'])" /> v-if="!checkDeptRole(['admin'])" />
<SelectTable v-model:data="queryParams.srcHospName" :fields="ksdhFields" :tableData="hosList" v-else <SelectTable v-model:data="queryParams.srcHospName" :fields="ksdhFields" :tableData="hosList" v-else
label="label" :size="aotuSize" value="label" placeholder="请选择委托机构" /> label="label" :size="aotuSize" value="label" placeholder="请选择委托机构" />
</el-form-item> </el-form-item>
@ -75,7 +75,8 @@
</div> </div>
<div> <div>
<CustomTable ref="tableRefs" :data="tableData" :columns="columns" :config="tableConfig" :pagination="pagination" <CustomTable ref="tableRefs" :data="tableData" :columns="columns" :config="tableConfig" :pagination="pagination"
@size-change="sizeChange" @page-change="currentChange" @row-click="rowHandle"> @size-change="sizeChange" @page-change="currentChange" @row-click="rowHandle" :enableColumnDrag="true"
@column-drag-end="handleColumnDragEnd">
<template #patAge="{ row }"> <template #patAge="{ row }">
{{ row.patAge }}{{ formatDict(row.ageUnit, 'AU') }} {{ row.patAge }}{{ formatDict(row.ageUnit, 'AU') }}
</template> </template>
@ -85,6 +86,9 @@
<template #patSex="{ row }"> <template #patSex="{ row }">
{{ row.patSex == 1 ? '男' : '女' }} {{ row.patSex == 1 ? '男' : '女' }}
</template> </template>
<template #brly="{ row }">
{{ formatDict(row.brly, 'PT') }}
</template>
</CustomTable> </CustomTable>
</div> </div>
<!-- 样本流程 --> <!-- 样本流程 -->
@ -116,24 +120,26 @@ import { listregdict } from "@/api/regional/dict/regdict";
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { getDictData, formatDict, dictData } from '@/hooks' import { getDictData, formatDict, dictData } from '@/hooks'
import { checkRole } from '@/utils/permission' import { checkDeptRole } from '@/utils/permission'
const userStore = useUserStore() const userStore = useUserStore()
const queryParams = ref({ const queryParams = ref({
pageSize: 50, pageSize: 50,
pageNum: 1, pageNum: 1,
srcHospName: userStore.sysLoginParam.loginYLJGName, srcHospName: '',
times: [], times: [],
dateType: '登记时间' dateType: '登记时间'
}) })
const tableData = ref([]) const tableData = ref([])
const columns = ref([ const columns = ref([
{ prop: 'barcode', label: '条码号', align: 'center', visible: true, width: 150 }, { prop: 'barcode', label: '条码号', align: 'center', visible: true, width: 150 },
{ prop: 'srcHospName', label: '委托机构', align: 'center', visible: true, width: 200 }, { prop: 'brly', label: '病人来源', align: 'center', visible: true, width: 100, slot: "brly" },
{ prop: 'patId', label: '病人代号', align: 'center', visible: true, width: 100 },
{ prop: 'patName', label: '姓名', align: 'center', visible: true, width: 100 }, { prop: 'patName', label: '姓名', align: 'center', visible: true, width: 100 },
{ prop: 'patSex', label: '性别', align: 'center', visible: true, width: 60, slot: "patSex" }, { prop: 'patSex', label: '性别', align: 'center', visible: true, width: 60, slot: "patSex" },
{ prop: 'patAge', label: '年龄', align: 'center', visible: true, slot: "patAge", width: 60 }, { prop: 'patAge', label: '年龄', align: 'center', visible: true, slot: "patAge", width: 60 },
{ prop: 'ch', label: '床号', align: 'center', visible: true, width: 60 },
{ prop: 'checkPUR', label: '申请项目', align: 'center', visible: true, width: 250 }, { prop: 'checkPUR', label: '申请项目', align: 'center', visible: true, width: 250 },
{ prop: 'orderTime', label: '申请时间', align: 'center', visible: true, width: 140 }, { prop: 'orderTime', label: '申请时间', align: 'center', visible: true, width: 140 },
{ prop: 'sampleTypeName', label: '标本类型', align: 'center', visible: true, }, { prop: 'sampleTypeName', label: '标本类型', align: 'center', visible: true, },
@ -144,6 +150,7 @@ const columns = ref([
{ prop: 'signInUserName', label: '签收人', align: 'center', visible: true, }, { prop: 'signInUserName', label: '签收人', align: 'center', visible: true, },
{ prop: 'signInTime', label: '签收时间', align: 'center', visible: true, width: 140 }, { prop: 'signInTime', label: '签收时间', align: 'center', visible: true, width: 140 },
{ prop: 'dstHospName', label: '检测机构名称', align: 'center', visible: true, width: 150 }, { prop: 'dstHospName', label: '检测机构名称', align: 'center', visible: true, width: 150 },
{ prop: 'srcHospName', label: '委托机构', align: 'center', visible: true, width: 200 },
]) ])
const tableConfig = ref({ const tableConfig = ref({
border: true, // 边框 border: true, // 边框
@ -152,6 +159,10 @@ const tableConfig = ref({
// fit: true, // 列宽自适应 // fit: true, // 列宽自适应
}) })
const handleColumnDragEnd = (newColumns: any) => {
columns.value = newColumns.columns
}
const pagination = ref({ const pagination = ref({
show: true, show: true,
total: 0, total: 0,
@ -205,7 +216,6 @@ const resetHandle = () => {
pageSize: 50, pageSize: 50,
pageNum: 1, pageNum: 1,
dateType: '登记时间', dateType: '登记时间',
srcHospName: userStore.sysLoginParam.loginYLJGName,
} }
getDays() getDays()
handleQuery() handleQuery()
@ -236,8 +246,21 @@ const getList = () => {
querySample(queryParams.value).then((res) => { querySample(queryParams.value).then((res) => {
tableData.value = res.rows tableData.value = res.rows
pagination.value.total = res.total pagination.value.total = res.total
tableRefs.value.setCurrentRow(res.rows[0]) if (res.rows.length > 0) {
rowHandle(res.rows[0]) tableRefs.value.setCurrentRow(res.rows[0])
rowHandle(res.rows[0])
} else {
timelineItems.value =
[
{ title: '检验申请', time: '' },
{ title: '标本采集', time: '' },
{ title: '标本送检', time: '' },
{ title: '标本签收', time: '' },
{ title: '上机检验', time: '' },
{ title: '结果审核', time: '' },
]
}
}) })
} }
@ -245,6 +268,13 @@ const getDays = () => {
const end = dayjs().format('YYYY-MM-DD'); const end = dayjs().format('YYYY-MM-DD');
const start = dayjs().subtract(2, 'day').format('YYYY-MM-DD'); //add 时间往后 const start = dayjs().subtract(2, 'day').format('YYYY-MM-DD'); //add 时间往后
queryParams.value.times = [start, end]; queryParams.value.times = [start, end];
// 医疗机构为1
if (userStore.sysLoginParam.loginYLJG == 1) {
queryParams.value.srcHospName = ''
} else {
queryParams.value.srcHospName = userStore.sysLoginParam.loginYLJGName
}
} }
const hosList = ref([]) const hosList = ref([])
@ -252,7 +282,7 @@ const regdictList = ref([])
onMounted(() => { onMounted(() => {
getDays() getDays()
handleQuery() handleQuery()
listhospital().then((res) => { listhospital({ pageSize: 100, pageNum: 1 }).then((res) => {
hosList.value = res.rows.map((item) => { hosList.value = res.rows.map((item) => {
return { return {
label: item.hospitalName, label: item.hospitalName,
@ -264,7 +294,7 @@ onMounted(() => {
listregdict({ pageSize: 100, pageNum: 1, dictType: 'ZT' }).then((res) => { listregdict({ pageSize: 100, pageNum: 1, dictType: 'ZT' }).then((res) => {
regdictList.value = res.rows; regdictList.value = res.rows;
}) })
getDictData('AU') getDictData('AU', 'PT')
}) })

View File

@ -51,6 +51,7 @@ const aotuSize = classCom.useAutoSize();
const queryParams = ref({ const queryParams = ref({
barcode: '', barcode: '',
}) })
const tableRefs = useTemplateRef('tableRefs')
const tableData = ref([]) const tableData = ref([])
const columns = ref([ const columns = ref([
{ type: 'selection', align: 'center', visible: true, width: 40 }, { type: 'selection', align: 'center', visible: true, width: 40 },
@ -123,6 +124,7 @@ const getList = () => {
sampleCollect({ barcode: queryParams.value.barcode }).then((res) => { sampleCollect({ barcode: queryParams.value.barcode }).then((res) => {
tableData.value.push(res.data) tableData.value.push(res.data)
queryParams.value.barcode = '' queryParams.value.barcode = ''
tableRefs.value.toggleRowSelection(res.data, true)
}) })
} }

View File

@ -8,7 +8,7 @@
<el-col :span="4"> <el-col :span="4">
<el-form-item label="委托机构:" prop="yljg"> <el-form-item label="委托机构:" prop="yljg">
<el-input v-model="queryParams.yljg" :title="queryParams.yljg" :size="aotuSize" readonly <el-input v-model="queryParams.yljg" :title="queryParams.yljg" :size="aotuSize" readonly
v-if="!checkRole(['admin'])" /> v-if="!checkDeptRole(['admin'])" />
<SelectTable v-model:data="queryParams.yljg" :fields="ksdhFields" :tableData="hosList" v-else <SelectTable v-model:data="queryParams.yljg" :fields="ksdhFields" :tableData="hosList" v-else
label="label" :size="aotuSize" value="label" placeholder="请选择委托机构" /> label="label" :size="aotuSize" value="label" placeholder="请选择委托机构" />
</el-form-item> </el-form-item>
@ -190,7 +190,7 @@ import * as echarts from 'echarts';
import { getDictData, formatDict, dictData } from '@/hooks' import { getDictData, formatDict, dictData } from '@/hooks'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { listhospital } from '@/api/regional/dict/hospital'; import { listhospital } from '@/api/regional/dict/hospital';
import { checkRole } from '@/utils/permission' import { checkDeptRole } from '@/utils/permission'
const userStore = useUserStore() const userStore = useUserStore()
const aotuSize = classCom.useAutoSize(); const aotuSize = classCom.useAutoSize();
const compactForm = ref<HTMLElement | null>(null); const compactForm = ref<HTMLElement | null>(null);
@ -234,7 +234,7 @@ const queryParams = reactive<QueryParams>({
dybz: '', dybz: '',
pageNum: 1, pageNum: 1,
pageSize: 20, pageSize: 20,
yljg: userStore.sysLoginParam.loginYLJGName, yljg: '',
}); });
const total = ref(0); const total = ref(0);
@ -247,7 +247,7 @@ const jzbz = ref()
const showSearch = ref(true); const showSearch = ref(true);
const queryRef = ref() const queryRef = ref()
// 项目点击数据 // 项目点击数据
const Info = ref<any>({}) const Info = ref(null)
// 定义校验规则 // 定义校验规则
const queryRules = ref({ const queryRules = ref({
// clientId: [ // clientId: [
@ -311,29 +311,27 @@ const rows = ref<any[]>([])
const tableData = ref([]) const tableData = ref([])
// 配置项 // 配置项
const columns = ref([ const columns = ref([
// { type: 'selection', visible: true, align: 'center', width: 30, label: '多选框' }, { prop: 'dybz', label: '印', align: 'center', visible: true, slot: 'dybz', width: 40 },
{ prop: 'yljg', label: '委托机构', align: 'center', visible: true, width: 200 }, { prop: 'alarmflag', label: '危', align: 'center', visible: true, slot: 'alarmflag', width: 40 },
{ prop: 'brdh', label: '病人代号', align: 'center', visible: true, width: 100 }, { prop: 'brdh', label: '病人代号', align: 'center', visible: true, width: 100 },
{ prop: 'brlyname', label: '病人类型', align: 'center', visible: true, width: 80 },
{ prop: 'brxm', label: '病人姓名', align: 'center', visible: true, }, { prop: 'brxm', label: '病人姓名', align: 'center', visible: true, },
{ prop: 'brxbname', label: '性别', align: 'center', visible: true, width: 40 }, { prop: 'brxbname', label: '性别', align: 'center', visible: true, width: 40 },
{ prop: 'ch', label: '床号', align: 'center', visible: true, width: 50 }, { prop: 'ch', label: '床号', align: 'center', visible: true, width: 50 },
{ prop: 'sqh', label: '条码号', align: 'center', visible: true, width: 140 },
{ prop: 'barcode_zt', label: '状态', align: 'center', visible: true, width: 100, slot: 'barcode_zt' }, { prop: 'barcode_zt', label: '状态', align: 'center', visible: true, width: 100, slot: 'barcode_zt' },
{ prop: 'jymd', label: '检验目的', align: 'center', visible: true, width: 200 }, { prop: 'jymd', label: '检验目的', align: 'center', visible: true, width: 200 },
{ prop: 'yblxname', label: '样本类型', align: 'center', visible: true, }, { prop: 'yblxname', label: '样本类型', align: 'center', visible: true, },
{ prop: 'sqsj', label: '申请时间', align: 'center', visible: true, width: 150 }, { prop: 'sqsj', label: '申请时间', align: 'center', visible: true, width: 150 },
{ prop: 'sqh', label: '条码号', align: 'center', visible: true, width: 140 },
{ prop: 'confirmtime', label: '报告时间', align: 'center', visible: true, sortable: true, width: 150 }, { prop: 'confirmtime', label: '报告时间', align: 'center', visible: true, sortable: true, width: 150 },
{ prop: 'sjysname', label: '送检医生', align: 'center', visible: true, width: 80 }, { prop: 'sjysname', label: '送检医生', align: 'center', visible: true, width: 80 },
{ prop: 'brlyname', label: '病人类型', align: 'center', visible: true, width: 80 },
{ prop: 'jyrq', label: '检验日期', align: 'center', visible: true, width: 100 }, { prop: 'jyrq', label: '检验日期', align: 'center', visible: true, width: 100 },
{ prop: 'applyid', label: '申请单号', align: 'center', visible: true, width: 120 }, { prop: 'applyid', label: '申请单号', align: 'center', visible: true, width: 120 },
{ prop: 'ybh', label: '样本号', align: 'center', visible: true, width: 60 }, { prop: 'ybh', label: '样本号', align: 'center', visible: true, width: 60 },
{ prop: 'yqmc', label: '仪器名称', align: 'center', visible: true, width: 150 }, { prop: 'yqmc', label: '仪器名称', align: 'center', visible: true, width: 150 },
{ prop: 'dybz', label: '印', align: 'center', visible: true, slot: 'dybz', width: 40 },
{ prop: 'jzbz', label: '急', align: 'center', visible: true, slot: 'jzbz', width: 40 }, { prop: 'jzbz', label: '急', align: 'center', visible: true, slot: 'jzbz', width: 40 },
{ prop: 'alarmflag', label: '危', align: 'center', visible: true, slot: 'alarmflag', width: 40 },
// { prop: 'yqdl', label: '仪器', align: 'center', visible: true, width: 100 },
{ prop: 'jcjg', label: '检验机构', align: 'center', visible: true, width: 150 }, { prop: 'jcjg', label: '检验机构', align: 'center', visible: true, width: 150 },
{ prop: 'yljg', label: '委托机构', align: 'center', visible: true, width: 200 },
]) ])
const selectionChange = (selection: any) => { const selectionChange = (selection: any) => {
@ -397,11 +395,14 @@ const handleColumnDragEnd = (newColumns: any) => {
// 打印单张Pdf // 打印单张Pdf
const printPdf = () => { const printPdf = () => {
if (!Info.value) return ElMessage.warning('请选择一条数据')
printLoading.value = true printLoading.value = true
reportPrintPdf({ bgdh: Info.value.bgdh }).then((res) => { reportPrintPdf({ bgdh: Info.value.bgdh }).then((res) => {
if (res.code == 0) { if (res.code == 0) {
if (!res.data) return ElMessage.warning('未找到打印文件') if (!res.data) return ElMessage.warning('未找到打印文件')
classCom.printBase64PDF(res.data) classCom.printBase64PDF(res.data)
ElMessage.success('正在打印中...')
handleQuery()
} }
}).finally(() => { }).finally(() => {
printLoading.value = false printLoading.value = false
@ -422,6 +423,9 @@ const cellStyleHd = ({ row, column, rowIndex, columnIndex }: {
if (column.label == "危" && row.alarmflag == "1") { if (column.label == "危" && row.alarmflag == "1") {
return { color: '#f00' }; return { color: '#f00' };
} }
if (row.dybz == 1) {
return { background: '#ccc' };
}
}; };
// 表格配置 // 表格配置
@ -738,10 +742,18 @@ onMounted(async () => {
const end = dayjs().format('YYYY-MM-DD'); const end = dayjs().format('YYYY-MM-DD');
const start = dayjs().subtract(2, 'day').format('YYYY-MM-DD'); //add 时间往后 const start = dayjs().subtract(2, 'day').format('YYYY-MM-DD'); //add 时间往后
queryParams.times = [start, end]; queryParams.times = [start, end];
console.log('userStore.sysLoginParam==>', userStore.sysLoginParam);
// 医疗机构为1
if (userStore.sysLoginParam.loginYLJG == 1) {
queryParams.yljg = ''
} else {
queryParams.yljg = userStore.sysLoginParam.loginYLJGName
}
getList() getList()
adjustTableHeight(); adjustTableHeight();
listhospital().then((res) => { listhospital({ pageSize: 100, pageNum: 1 }).then((res) => {
hosList.value = res.rows.map((item) => { hosList.value = res.rows.map((item) => {
return { return {
label: item.hospitalName, label: item.hospitalName,
@ -775,7 +787,7 @@ const getList = () => {
tableRefs.value.setCurrentRow(res.rows[0]) tableRefs.value.setCurrentRow(res.rows[0])
rowHandle(res.rows[0]) rowHandle(res.rows[0])
} else { } else {
Info.value = {} Info.value = null
rightTableData.value = [] rightTableData.value = []
bottomTableData.value = [] bottomTableData.value = []
} }