Merge branch 'ID1766-添加推送登录功能' into test
| | |
| | | // module.exports = { |
| | | // plugins: { |
| | | // 'postcss-pxtorem': { |
| | | // rootValue: 37.5, |
| | | // propList: ['*'], |
| | | // include: file => { |
| | | // if (!file) return false; |
| | | // const normalized = file.replace(/\\/g, '/'); |
| | | // // 只转换 mobile 目录里的样式 OR element-plus 目录里的样式 |
| | | // // 但 element-plus 样式只在 mobile 目录被引用时才生效,需保证引用范围 |
| | | // return normalized.includes('/src/views/mobile/') || normalized.includes('/node_modules/element-plus/'); |
| | | // }, |
| | | // exclude: file => { |
| | | // if (!file) return false; |
| | | // const normalized = file.replace(/\\/g, '/'); |
| | | // // 排除除 element-plus 外的 node_modules,防止无关样式被转 |
| | | // if (/node_modules/.test(normalized) && !normalized.includes('/node_modules/element-plus/')) { |
| | | // return true; |
| | | // } |
| | | // return false; |
| | | // }, |
| | | // minPixelValue: 2, |
| | | // } |
| | | // } |
| | | // } |
| | | |
| | | module.exports = { |
| | | plugins: { |
| | | 'postcss-pxtorem': { |
| | | rootValue: 37.5, |
| | | propList: ['*'], |
| | | // include: file => { |
| | | // if (!file) return false; |
| | | // const normalized = file.replace(/\\/g, '/'); |
| | | // // 只转换 mobile 目录里的样式 OR element-plus 目录里的样式 |
| | | // // 但 element-plus 样式只在 mobile 目录被引用时才生效,需保证引用范围 |
| | | // return normalized.includes('/src/views/mobile/') || normalized.includes('/node_modules/element-plus/'); |
| | | // }, |
| | | // exclude: file => { |
| | | // if (!file) return false; |
| | | // const normalized = file.replace(/\\/g, '/'); |
| | | // // 排除除 element-plus 外的 node_modules,防止无关样式被转 |
| | | // if (/node_modules/.test(normalized) && !normalized.includes('/node_modules/element-plus/')) { |
| | | // return true; |
| | | // } |
| | | // return false; |
| | | // }, |
| | | // ✅ 用正则匹配路径,不依赖字符串 includes |
| | | include: [ |
| | | /src[\/\\]views[\/\\]mobile/, // 只转 mobile 目录 |
| | | /node_modules[\/\\]element-plus/ // 转 element-plus 样式 |
| | | ], |
| | | // ✅ 排除其他 node_modules |
| | | exclude: (file) => /node_modules/.test(file) && !/node_modules[\/\\]element-plus/.test(file), |
| | | minPixelValue: 2, |
| | | } |
| | | } |
| New file |
| | |
| | | export interface ListParams { |
| | | page: number; |
| | | size: number; |
| | | wherecondition: string; |
| | | ordercondition: string; |
| | | } |
| New file |
| | |
| | | import request from "@/utils/axios"; |
| | | import type { DictTypeParams } from './types/index.type'; |
| | | |
| | | |
| | | export function getDictTypeApi(params: DictTypeParams) { |
| | | return request({ |
| | | url: '/dict/base/info/listDictValuesByType', |
| | | method: 'post', |
| | | headers: { |
| | | 'Content-Type': 'application/x-www-form-urlencoded' |
| | | }, |
| | | params, |
| | | }) |
| | | } |
| New file |
| | |
| | | export enum DictType { |
| | | 穿刺方式 = 'in_med_cc_method', |
| | | 穿刺针类型 = 'in_med_cc_zhen_type', |
| | | 穿刺方向 = 'in_med_cc_ccfx' |
| | | } |
| | | |
| | | export interface DictTypeParams { |
| | | dictType: DictType; |
| | | } |
| New file |
| | |
| | | import request from "@/utils/axios"; |
| | | import type { InventoryItemListParams } from './types/itemDict.type'; |
| | | |
| | | /** |
| | | * 获取库存字典api |
| | | * @param params |
| | | * @returns |
| | | */ |
| | | export function getInventoryItemListApi(params: InventoryItemListParams) { |
| | | return request({ |
| | | url: '/inventory/item/detail/info/list', |
| | | method: 'post', |
| | | params |
| | | }) |
| | | } |
| New file |
| | |
| | | import { ListParams } from '@/api/commom.type'; |
| | | |
| | | |
| | | export interface InventoryItemListParams extends ListParams { |
| | | isPure?: number; |
| | | } |
| New file |
| | |
| | | import request from "@/utils/axios"; |
| | | import type { |
| | | StartRecord, |
| | | RecordData, |
| | | } from "../patient_hemo_med_start/types/index.type"; |
| | | |
| | | /** |
| | | * 获取开始透析数据api |
| | | * @param params `recordCode=${recordCode}` |
| | | * @returns |
| | | */ |
| | | export function addDefaultRowApi( |
| | | params: string |
| | | ): Promise<{ data: StartRecord }> { |
| | | return request({ |
| | | url: "/patient/hemo/med/start/addDefaultRow", |
| | | method: "post", |
| | | headers: { |
| | | "Content-Type": "application/x-www-form-urlencoded", |
| | | }, |
| | | data: params, |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 修改开始透析数据api |
| | | * @param params |
| | | * @returns |
| | | */ |
| | | export function updateMedstartDataApi(params: StartRecord) { |
| | | return request({ |
| | | url: "/patient/hemo/med/start/update", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 获取结束透析数据api |
| | | * @param params `recordCode=${recordCode}` |
| | | * @returns |
| | | */ |
| | | export function addDefaultEndRowApi( |
| | | params: string |
| | | ): Promise<{ data: RecordData }> { |
| | | return request({ |
| | | url: "/patient/hemo/med/end/addDefaultRow", |
| | | method: "post", |
| | | headers: { |
| | | "Content-Type": "application/x-www-form-urlencoded", |
| | | }, |
| | | data: params, |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 修改结束透析数据api |
| | | * @param params |
| | | * @returns |
| | | */ |
| | | export function updateEndRowApi(params: RecordData) { |
| | | return request({ |
| | | url: "/patient/hemo/med/end/update", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | } |
| New file |
| | |
| | | export interface StartRecord { |
| | | code: string; |
| | | createTime: string; // "2025-09-12 17:06:42" |
| | | createUser: string | null; |
| | | deletedTime: string | null; |
| | | doneByg: string; |
| | | doneBygName: string; |
| | | doneBygSpecName: string; |
| | | doneGl: string; |
| | | doneGlName: string; |
| | | doneGlSpecName: string; |
| | | id: number | null; |
| | | isDeleted: number | null; |
| | | monitorDataCode: string; |
| | | recordCode: string; |
| | | remark: string; |
| | | schemeName: string; |
| | | /** 穿刺方向 */ |
| | | startCcASideDirection: string; |
| | | startCcNurse: string; |
| | | startCcNurseName: string; |
| | | /** 穿刺方式 */ |
| | | startCcType: string; |
| | | startCcZhenA: string; |
| | | startCcZhenAName: string; |
| | | startCcZhenASpecName: string; |
| | | startCcZhenType: string; |
| | | startCcZhenV: string; |
| | | startCcZhenVName: string; |
| | | startCcZhenVSpecName: string; |
| | | startEntranceType: string; |
| | | startIsCcOrHy: number | null; |
| | | startIsSave: number | null; |
| | | startMedNurse: string; |
| | | startMedNurseName: string; |
| | | startTime: string | null; |
| | | startTxqNo: string; |
| | | startUpNurse: string; |
| | | startUpNurseName: string; |
| | | startUseHlb: string; |
| | | startUseHlbName: string; |
| | | startUseHlbSpecName: string; |
| | | startUseNsy: string; |
| | | startUseNsyName: string; |
| | | startUseNsySpecName: string; |
| | | startYcNurse: string; |
| | | startYcNurseName: string; |
| | | startYingxue: string; |
| | | updateTime: string; |
| | | updateUser: string | null; |
| | | } |
| | | |
| | | export interface RecordData { |
| | | code: string; |
| | | createTime: string; |
| | | createUser: string | null; |
| | | deletedTime: string | null; |
| | | endDownNurse: string; |
| | | endDownNurseName: string; |
| | | endHuixue: string; |
| | | endTime: string; |
| | | id: number | null; |
| | | isDeleted: number | null; |
| | | lastTimeMonitorDataTime: string; |
| | | monitorDataCode: string; |
| | | recordCode: string; |
| | | remark: string; |
| | | updateTime: string; |
| | | updateUser: string | null; |
| | | } |
| New file |
| | |
| | | import request from "@/utils/axios"; |
| | | |
| | | /** |
| | | * 副屏退出登录Api |
| | | * @returns |
| | | */ |
| | | export function logOutApi(params: string) { |
| | | return request({ |
| | | url: "/user/info/logoutForSubScreen", |
| | | method: "post", |
| | | headers: { |
| | | "Content-Type": "application/x-www-form-urlencoded", |
| | | }, |
| | | data: params, |
| | | }); |
| | | } |
| New file |
| | |
| | | import request from "@/utils/axios"; |
| | | |
| | | /** |
| | | * 根据角色获取用户列表api |
| | | * @param params |
| | | * @returns |
| | | */ |
| | | export function getUsersByRoleCodeApi(params: string) { |
| | | return request({ |
| | | url: "/user/info/getUsersByRoleCode", |
| | | method: "post", |
| | | headers: { |
| | | "Content-Type": "application/x-www-form-urlencoded", |
| | | }, |
| | | data: params, |
| | | }); |
| | | } |
| | |
| | | @font-face { |
| | | font-family: "iconfont"; /* Project id 5011061 */ |
| | | src: url('//at.alicdn.com/t/c/font_5011061_crebeujq91a.woff2?t=1756705233110') format('woff2'), |
| | | url('//at.alicdn.com/t/c/font_5011061_crebeujq91a.woff?t=1756705233110') format('woff'), |
| | | url('//at.alicdn.com/t/c/font_5011061_crebeujq91a.ttf?t=1756705233110') format('truetype'); |
| | | src: url('../font/iconfont.woff2') format('woff2'), |
| | | url('../font/iconfont.woff') format('woff'), |
| | | url('../font/iconfont.ttf') format('truetype'); |
| | | } |
| | | |
| | | .iconfont { |
| | |
| | | .icon-saoma:before { |
| | | content: "\e749"; |
| | | } |
| | | |
| | |
| | | import VConsole from 'vconsole' |
| | | import { createPinia } from 'pinia' |
| | | import '@/assets/css/iconfont.css' |
| | | import zhCn from 'element-plus/dist/locale/zh-cn.mjs' |
| | | |
| | | if (import.meta.env.VITE_ENV === 'development') { |
| | | // 如果需要在手机平板上打开控制台,安装一个这个 |
| | | const vConsole = new VConsole() |
| | |
| | | |
| | | const app = createApp(App) |
| | | |
| | | app.use(router).use(pinia).use(ElementPlus).use(Vant).mount('#app') |
| | | app.use(router).use(pinia).use(ElementPlus, { locale: zhCn }).use(Vant).mount('#app') |
| | |
| | | } from "./type/bedsideAuxiliaryScreen.type"; |
| | | import { ElMessage } from "element-plus/es"; |
| | | import { Local } from "@/utils/storage"; |
| | | import type { UserInfo } from './type/user.type'; |
| | | import type { DeviceLoginRecord } from './type/user.type'; |
| | | import { logOutApi } from "@/api/user"; |
| | | |
| | | export const useBedsideAuxiliaryScreenStore = defineStore( |
| | | "bedsideAuxiliaryScreen", |
| | |
| | | const taskData = ref<Task[]>([]); |
| | | |
| | | /** 用户信息 */ |
| | | const userInfo = ref<UserInfo | null>(Local.get('userInfo')); |
| | | |
| | | /** 用户token */ |
| | | const token = ref<string>(Local.get('token')); |
| | | const userInfo = ref<DeviceLoginRecord | null>(null); |
| | | |
| | | /** 设置副屏版本号 */ |
| | | const setVersion = (val: string) => { |
| | |
| | | }; |
| | | |
| | | /** 设置用户信息 */ |
| | | const setUserInfo = (user: UserInfo) => { |
| | | const setUserInfo = (user: DeviceLoginRecord | null) => { |
| | | userInfo.value = user; |
| | | Local.set('userInfo', user); |
| | | }; |
| | | |
| | | /** 设置token */ |
| | | const setToken = (str: string) => { |
| | | token.value = str; |
| | | Local.set('token', str); |
| | | } |
| | | |
| | | /** 退出登录 */ |
| | | const logout = () => { |
| | | Local.remove('token'); |
| | | Local.remove('userInfo'); |
| | | token.value = ''; |
| | | userInfo.value = null; |
| | | const logout = async (deviceCodeStr: string) => { |
| | | await logOutApi(deviceCodeStr); |
| | | setUserInfo(null); |
| | | }; |
| | | |
| | | // SSE 相关状态 |
| | |
| | | } |
| | | |
| | | deviceData.value = formatDeviceData(deviceData.value, dataBody); |
| | | // 当前登录的用户信息 |
| | | setUserInfo(dataBody.当前登录状态); |
| | | |
| | | // 判断本地的版本号与远程的版本号是否一致,如果不一致则执行刷新操作 |
| | | if (dataBody.服务端版本号 !== version.value) { |
| | | refreshVersion(dataBody.服务端版本号); |
| | |
| | | setVersion, |
| | | refreshVersion, |
| | | userInfo, |
| | | token, |
| | | setUserInfo, |
| | | setToken, |
| | | logout, |
| | | }; |
| | | } |
| | |
| | | import { tryConvertToInt, deepClone } from "@/utils/utils"; |
| | | import { Local } from "@/utils/storage"; |
| | | import dayjs from "dayjs"; |
| | | import type { DeviceLoginRecord } from './user.type'; |
| | | export interface IotInfo { |
| | | 属性历史列表: any[]; |
| | | 床号: string; |
| | |
| | | 管路: string[]; |
| | | 透析器: string[]; |
| | | 透析模式: string[]; |
| | | 透析单编号: string; |
| | | } |
| | | |
| | | enum EPushType { |
| | |
| | | 自定义配置项: Customconfiguration; |
| | | 服务端版本号: string; |
| | | 是否需要立即刷新: 0 | 1; |
| | | 当前登录状态: DeviceLoginRecord | null; |
| | | } |
| | | |
| | | interface Customconfiguration { |
| | |
| | | sphygmomanometer: Sphygmomanometer; |
| | | customConfiguration: Customconfiguration; |
| | | 患者出生日期: string; |
| | | 客户编号: string; |
| | | } |
| | | |
| | | export const defaultSphygmomanometer = () :Sphygmomanometer => { |
| | |
| | | carePackage: any[]; |
| | | punctureNeedle: PunctureNeedle[]; |
| | | vascularAccess: VascularAccess[]; |
| | | 透析单编号: string; |
| | | } |
| | | |
| | | export const defaultconsumablesCollection = (): ConsumablesCollection => { |
| | |
| | | 管路: [], |
| | | 透析器: [], |
| | | 透析模式: [], |
| | | 透析单编号: '', |
| | | }; |
| | | }; |
| | | |
| | |
| | | carePackage: [], // 一次性使用透析护理包列表 |
| | | punctureNeedle: [], // 穿刺针列表 |
| | | vascularAccess: [], // 血管通路列表 |
| | | 透析单编号: '' |
| | | }; |
| | | }; |
| | | |
| | |
| | | 体重增长_透前_上次透后: number | null; // 体重增长(透前-上次透后) |
| | | 体重增持_透前_干体重: number | null; // 体重增长(透前-干体重) |
| | | 四点血压图数据: 四点血压图数据[]; |
| | | 透析单编号: string; |
| | | } |
| | | |
| | | export const defaultSignedIn = (): SignedIn => { |
| | |
| | | 体重增长_透前_上次透后: null, // 体重增长(透前-上次透后) |
| | | 体重增持_透前_干体重: null, // 体重增长(透前-干体重) |
| | | 四点血压图数据: [], |
| | | 透析单编号: '', |
| | | }; |
| | | }; |
| | | |
| | |
| | | venousPressure2: number | null; // 静脉压 |
| | | transmembranePressure2: number | null; // 跨膜压 |
| | | 处方脱水量: number | null; // 处方脱水量 |
| | | 透析单编号: string; |
| | | } |
| | | |
| | | export interface MonitoringRecord { |
| | |
| | | venousPressure2: null, // 静脉压 |
| | | transmembranePressure2: null, // 跨膜压 |
| | | 处方脱水量: null, |
| | | 透析单编号: '' |
| | | }; |
| | | }; |
| | | |
| | |
| | | // @ts-ignore |
| | | pageType, // 当前要展示的页面 |
| | | treatmentStatus: EMedStatus.NOT_CHECKED_IN, // 透析状态 |
| | | 客户编号: "", |
| | | consumablesCollection: defaultconsumablesCollection(), // 未排班时需要的数据 |
| | | notSignedIn: defalutNotSignedIn(), // 未签到时需要的数据 |
| | | signedIn: defaultSignedIn(), // 已签到时需要的数据 |
| | |
| | | // 默认床号(设备号) |
| | | result.devicdeNo = seeMsg.IOT信息?.床号; |
| | | result.deviceCode = seeMsg.IOT信息?.设备唯一编号; |
| | | |
| | | |
| | | // 自定义配置项 |
| | | result.customConfiguration = seeMsg.自定义配置项 ?? defaultCustomconfiguration(); |
| | |
| | | result.patFormNumber = seeMsg.透析状态?.患者门诊住院号; |
| | | result.患者出生日期 = seeMsg.透析状态?.患者出生日期 || ""; |
| | | |
| | | result.客户编号 = seeMsg.透析状态?.clientCode; |
| | | |
| | | |
| | | // 未签到页面需要显示的 |
| | | if (treatmentStatus === EMedStatus.NOT_CHECKED_IN) { |
| | | result.pageType = EPageType.NOT_SIGNED_IN; |
| | |
| | | notSignedIn.punctureNeedle = seeMsg.透析状态?.穿刺针列表 ?? []; |
| | | notSignedIn.vascularAccess = seeMsg.透析状态?.血管通路列表 ?? []; |
| | | notSignedIn.anticoagulant = seeMsg.透析状态?.抗凝剂列表 ?? []; |
| | | notSignedIn.透析单编号 = seeMsg.透析状态?.透析单编号; |
| | | |
| | | result.notSignedIn = notSignedIn; |
| | | } |
| | |
| | | signedIn.上次透析单所属日期 = dayjs(signedIn.四点血压图数据[0].透析日期).format("YYYY-MM-DD"); |
| | | // signedIn.本次透析单所属日期 = dayjs(signedIn.四点血压图数据[0].透析日期).format("YYYY-MM-DD"); |
| | | } |
| | | signedIn.透析单编号 = seeMsg.透析状态?.透析单编号; |
| | | result.signedIn = signedIn; |
| | | } |
| | | // 剩下的全使用治疗中的页面 |
| | |
| | | ?.realTimeKtvCalcDetailResultInfo ?? []; |
| | | underTreatment.dialysisAge = seeMsg.透析状态?.透析龄 ?? null; |
| | | underTreatment.处方脱水量 = seeMsg.透析状态?.处方脱水量 ?? null; |
| | | underTreatment.透析单编号 = seeMsg.透析状态?.透析单编号; |
| | | |
| | | result.underTreatment = underTreatment; |
| | | } |
| | |
| | | export interface UserInfo { |
| | | 用户头像: string; |
| | | 用户昵称: string; |
| | | } |
| | | |
| | | export const defaultUserInfo = (): UserInfo => { |
| | | return { |
| | | 用户头像: '', |
| | | 用户昵称: '' |
| | | } |
| | | export interface DeviceLoginRecord { |
| | | clientCode: string; |
| | | code: string; |
| | | createTime: string; // 格式:YYYY-MM-DD HH:mm:ss |
| | | createUser: string | null; |
| | | deletedTime: string | null; |
| | | deviceCode: string; |
| | | id: number; |
| | | isDeleted: number; // 0/1 标识 |
| | | loginTime: string; // 格式:YYYY-MM-DD HH:mm:ss |
| | | remark: string | null; |
| | | token: string | null; |
| | | updateTime: string; // 格式:YYYY-MM-DD HH:mm:ss |
| | | updateUser: string | null; |
| | | userCode: string; |
| | | userName: string; |
| | | userAvatar: string | null; |
| | | } |
| New file |
| | |
| | | import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios' |
| | | import Qs from 'qs' |
| | | import { useBedsideAuxiliaryScreenStore } from '@/store/bedsideAuxiliaryScreen' |
| | | import { ElMessage } from 'element-plus/es' |
| | | |
| | | // ====== 配置 ====== |
| | | const BASE_URL = import.meta.env.VITE_API_BASE_URL |
| | | const TIME_OUT = 60 * 1 * 1000 |
| | | |
| | | // 正在进行中的请求列表,避免重复请求 |
| | | let reqList: string[] = [] |
| | | |
| | | /** |
| | | * 允许某个请求再次发送 |
| | | */ |
| | | const allowRequest = (url?: string) => { |
| | | if (!url) return |
| | | const idx = reqList.indexOf(url) |
| | | if (idx > -1) reqList.splice(idx, 1) |
| | | } |
| | | |
| | | /** |
| | | * 创建 axios 实例 |
| | | */ |
| | | const instance = axios.create({ |
| | | baseURL: BASE_URL, |
| | | timeout: TIME_OUT, |
| | | paramsSerializer: (params) => Qs.stringify(params, { arrayFormat: 'brackets' }), |
| | | }) |
| | | |
| | | // ====== 错误处理函数 ====== |
| | | const errorHandle = (status: number, error: any): void => { |
| | | const msg = error?.msg || error?.message || '' |
| | | switch (status) { |
| | | case 401: |
| | | ElMessage.error(`Error Code: 401, Message: ${msg || '登录失效,请重新登录'}`); |
| | | break |
| | | case 403: |
| | | ElMessage.error(`Error Code: 403, Message: ${msg || '你没有访问权限'}`); |
| | | break |
| | | case 500: |
| | | ElMessage.error(`Error Code: 500, Message: ${msg || '后台错误,请联系管理员'}`); |
| | | break |
| | | case 502: |
| | | alert() |
| | | ElMessage.error(`Error Code: 502, Message: ${msg || '平台环境异常'}`); |
| | | break |
| | | default: |
| | | ElMessage.error(`Error Code: ${status}, Message: ${msg || '未知错误,请刷新重试'}`); |
| | | } |
| | | } |
| | | |
| | | // ====== 请求拦截 ====== |
| | | instance.interceptors.request.use( |
| | | (config: InternalAxiosRequestConfig) => { |
| | | const store = useBedsideAuxiliaryScreenStore() |
| | | |
| | | // 加 token |
| | | if (store.userInfo?.token) { |
| | | config.headers.set('Authorization', `Bearer ${store.userInfo.token}`) |
| | | } |
| | | |
| | | // 防止同一接口短时间内重复请求 |
| | | if (config.url) { |
| | | if (reqList.includes(config.url)) { |
| | | // return Promise.reject(new axios.Cancel(`重复请求:${config.url}`)) |
| | | } else { |
| | | reqList.push(config.url) |
| | | } |
| | | } |
| | | |
| | | return config |
| | | }, |
| | | (error) => Promise.reject(error), |
| | | ) |
| | | |
| | | // ====== 响应拦截 ====== |
| | | instance.interceptors.response.use( |
| | | (res: AxiosResponse) => { |
| | | |
| | | // setTimeout(() => allowRequest(res.config.url), 1000) |
| | | if (String(res.status).charAt(0) !== '2') { |
| | | return Promise.reject({ |
| | | code: res.status, |
| | | message: res.data?.message || '请求异常,请刷新重试', |
| | | }) |
| | | } |
| | | if (res.data?.code === 200) return res.data |
| | | const whiteList: string[] = [] |
| | | const requestUrl: string = res?.config?.url || '' |
| | | const isInWhiteList = whiteList.some((item) => requestUrl.includes(item)) |
| | | ElMessage.error(res.data.message); |
| | | if (isInWhiteList) return Promise.reject(res.data) |
| | | return Promise.reject(res.data) |
| | | }, |
| | | |
| | | |
| | | (err: unknown) => { |
| | | |
| | | const anyErr = err as any |
| | | const configUrl = anyErr?.config?.url |
| | | // 失败后 1s 允许再次请求 |
| | | // setTimeout(() => allowRequest(configUrl), 1000) |
| | | |
| | | // 先判断是否是取消请求 |
| | | // if (axios.isCancel(err as any)) { |
| | | // console.warn('请求被取消:', (err as any)?.message) |
| | | // return Promise.reject(err) |
| | | // } |
| | | |
| | | // 判断是否为 axios 的错误类型(有 response) |
| | | if (axios.isAxiosError(err)) { |
| | | const axErr = err // 现在 TypeScript 知道这是 AxiosError |
| | | if (axErr.response) { |
| | | // 使用你现有的错误处理函数 |
| | | errorHandle(axErr.response.status, axErr.response.data) |
| | | |
| | | if (axErr.response.status === 401) { |
| | | ElMessage.error('请登录'); |
| | | } |
| | | return Promise.reject(axErr.response.data || axErr.response) |
| | | } |
| | | |
| | | ElMessage.error('网络请求失败, 请刷新重试'); |
| | | return Promise.reject(axErr) |
| | | } |
| | | |
| | | //(未知错误) |
| | | ElMessage.error('网络请求失败, 请刷新重试'); |
| | | return Promise.reject(err) |
| | | }, |
| | | ) |
| | | |
| | | export default instance |
| | |
| | | } catch (error) { |
| | | throw error; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 推出登录 |
| | | * @param deviceCode |
| | | * @returns |
| | | */ |
| | | export const logoutForSubScreen = async(deviceCode: string) => { |
| | | try { |
| | | const response = await axios.post(`${apiBaseUrl}/user/info/logoutForSubScreen`, { deviceCode }, { |
| | | headers: { |
| | | 'Content-Type': 'application/x-www-form-urlencoded' |
| | | } |
| | | }); |
| | | return response.data |
| | | } catch (error) { |
| | | throw error; |
| | | } |
| | | } |
| New file |
| | |
| | | <template> |
| | | <div class="end-dialysis-container"> |
| | | <el-dialog |
| | | v-model="show" |
| | | center |
| | | title="结束透析" |
| | | width="80%" |
| | | :show-close="false" |
| | | class="end-dialysis-dialog" |
| | | :destroy-on-close="true" |
| | | :close-on-click-modal="false" |
| | | > |
| | | <template #header> |
| | | <div class="end-dialysis-header"> |
| | | <span class="header-title">结束透析</span> |
| | | <img |
| | | :src="closeImg" |
| | | class="header-close" |
| | | @click="handleCancel" |
| | | alt="" |
| | | /> |
| | | </div> |
| | | </template> |
| | | <div class="end-dialysis-content" v-loading="loading"> |
| | | <el-form :model="formData" size="large"> |
| | | <el-row :gutter="10"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="结束时间"> |
| | | <el-row> |
| | | <el-col :span="8"> |
| | | <el-date-picker |
| | | v-model="formData.endData" |
| | | :clearable="false" |
| | | type="date" |
| | | placeholder="选择日期" |
| | | format="YYYY/MM/DD" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 100%" |
| | | /> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-time-select |
| | | :clearable="false" |
| | | v-model="formData.endTime" |
| | | start="00:00" |
| | | step="00:01" |
| | | end="23:59" |
| | | placeholder="选择时间" |
| | | style="width: 100%" |
| | | /> |
| | | </el-col> |
| | | <el-col :span="3"> |
| | | <el-button type="primary" @click="addTime(1)" |
| | | >时间+1</el-button |
| | | > |
| | | </el-col> |
| | | <el-col :span="3"> |
| | | <el-button type="primary" @click="addTime(0.5)" |
| | | >时间+0.5</el-button |
| | | > |
| | | </el-col> |
| | | </el-row> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="10"> |
| | | <el-col :span="8"> |
| | | <el-form-item label="下机护士"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="formData.endDownNurse" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in nurseOptions" |
| | | :key="item.code" |
| | | :label="item.userName" |
| | | :disabled="item.isValid === 0" |
| | | :value="item.code" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="回血(ml/min)"> |
| | | <el-input style="width: 100%" v-model="formData.endHuixue" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </div> |
| | | <template #footer> |
| | | <div class="my-button cancel" @click="handleCancel">取消</div> |
| | | <div |
| | | class="my-button confirm" |
| | | :class="loading ? 'cancel' : ''" |
| | | @click="handleConfirm" |
| | | > |
| | | 确认 |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { computed, reactive, toRefs } from "vue"; |
| | | import closeImg from "@/img/close.png"; |
| | | import { |
| | | addDefaultEndRowApi, |
| | | updateEndRowApi, |
| | | } from "@/api/patient_hemo_med_start/index"; |
| | | import type { RecordData } from "@/api/patient_hemo_med_start/types/index.type"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | import dayjs from "dayjs"; |
| | | import { getUsersByRoleCodeApi } from "@/api/user/index"; |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | | interface FormData { |
| | | id: number; |
| | | recordCode: string; |
| | | endTime: string; |
| | | endDownNurse: string; |
| | | endDownNurseName: string; |
| | | lastTimeMonitorDataTime: string; |
| | | endHuixue: string; |
| | | endData: string; |
| | | } |
| | | |
| | | interface State { |
| | | show: boolean; |
| | | loading: boolean; |
| | | formData: FormData; |
| | | nurseOptions: any[]; |
| | | defaultEndTime: string; |
| | | } |
| | | export default { |
| | | name: "EndDialysis", |
| | | setup() { |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const state = reactive<State>({ |
| | | show: false, |
| | | loading: false, |
| | | formData: { |
| | | id: 0, |
| | | recordCode: "", |
| | | endTime: "", |
| | | endDownNurse: "", |
| | | endDownNurseName: "", |
| | | lastTimeMonitorDataTime: "", |
| | | endHuixue: "", |
| | | endData: "", |
| | | }, |
| | | nurseOptions: [], |
| | | defaultEndTime: "", // 默认的日期,原始数据,用于计算 |
| | | }); |
| | | |
| | | const recordCode = computed(() => { |
| | | return bedsideAuxiliaryScreenStore.deviceData.underTreatment.透析单编号; |
| | | }); |
| | | |
| | | const clientCode = computed(() => { |
| | | return bedsideAuxiliaryScreenStore.deviceData.客户编号; |
| | | }); |
| | | |
| | | const userCode = computed(() => { |
| | | return bedsideAuxiliaryScreenStore.userInfo.userCode; |
| | | }); |
| | | |
| | | const openDialog = async () => { |
| | | state.loading = true; |
| | | state.show = true; |
| | | try { |
| | | const { data } = await addDefaultEndRowApi( |
| | | `recordCode=${recordCode.value}` |
| | | ); |
| | | |
| | | const dataCopy = JSON.parse(JSON.stringify(data)); |
| | | const notLs = [null, ""]; |
| | | |
| | | if (notLs.includes(data.endDownNurse)) { |
| | | dataCopy.endDownNurse = userCode.value; |
| | | } |
| | | |
| | | if (notLs.includes(data.endTime)) { |
| | | dataCopy.endTime = dayjs().format("HH:mm"); |
| | | // @ts-ignore |
| | | dataCopy.endData = dayjs().format("YYYY-MM-DD"); |
| | | state.defaultEndTime = dayjs().format("YYYY-MM-DD HH:mm"); |
| | | } else { |
| | | dataCopy.endTime = dayjs(data.endTime).format("HH:mm"); |
| | | // @ts-ignore |
| | | dataCopy.endData = dayjs(data.endTime).format("YYYY-MM-DD"); |
| | | state.defaultEndTime = dayjs(data.endTime).format("YYYY-MM-DD HH:mm"); |
| | | } |
| | | state.formData = dataCopy as unknown as FormData; |
| | | await getNurses(); |
| | | } catch (error) { |
| | | setTimeout(() => { |
| | | state.show = false; |
| | | }, 1000); |
| | | } finally { |
| | | state.loading = false; |
| | | } |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | state.show = false; |
| | | }; |
| | | |
| | | const handleConfirm = async () => { |
| | | if (state.loading) return false; |
| | | state.loading = true; |
| | | try { |
| | | const paramsData = Object.assign({}, state.formData, { |
| | | endTime: dayjs( |
| | | `${state.formData.endData} ${state.formData.endTime}` |
| | | ).format("YYYY-MM-DD HH:mm:ss"), |
| | | }); |
| | | await updateEndRowApi(paramsData as unknown as RecordData); |
| | | ElMessage.success("操作成功!"); |
| | | state.show = false; |
| | | } finally { |
| | | state.loading = false; |
| | | } |
| | | }; |
| | | |
| | | const addTime = (hourNum: number) => { |
| | | if (["", null].includes(state.formData.lastTimeMonitorDataTime)) |
| | | return false; |
| | | const addDate = addHours( |
| | | state.formData.lastTimeMonitorDataTime + "", |
| | | hourNum |
| | | ); |
| | | state.formData.endData = dayjs(addDate).format("YYYY-MM-DD"); |
| | | state.formData.endTime = dayjs(addDate).format("HH:mm"); |
| | | }; |
| | | |
| | | const addHours = (dateStr: string, hours: number): string => { |
| | | return dayjs(dateStr).add(hours, "hour").format("YYYY-MM-DD HH:mm:ss"); |
| | | }; |
| | | |
| | | /** |
| | | * 获取护士数据 |
| | | */ |
| | | const getNurses = async () => { |
| | | const { data } = await getUsersByRoleCodeApi( |
| | | `clientCode=${clientCode.value}&roleClass=nurse` |
| | | ); |
| | | state.nurseOptions = data; |
| | | }; |
| | | |
| | | return { |
| | | ...toRefs(state), |
| | | closeImg, |
| | | handleCancel, |
| | | handleConfirm, |
| | | openDialog, |
| | | addTime, |
| | | }; |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .end-dialysis-container { |
| | | ::v-deep(.el-dialog) { |
| | | padding: 0; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | } |
| | | ::v-deep(.el-dialog__footer) { |
| | | padding: 4px; |
| | | } |
| | | ::v-deep(.el-upload-dragger) { |
| | | height: 65px; |
| | | padding: 0 !important; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | ::v-deep(.el-upload-dragger .el-icon--upload) { |
| | | display: none; |
| | | } |
| | | ::v-deep(.el-dialog__header) { |
| | | padding-bottom: 6px; |
| | | } |
| | | .end-dialysis-header { |
| | | position: relative; |
| | | height: 16px; |
| | | background: #769aff; |
| | | .header-title { |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translateX(-50%) translateY(-50%); |
| | | font-family: AlibabaPuHuiTi, AlibabaPuHuiTi; |
| | | font-weight: 500; |
| | | font-size: 8px; |
| | | color: #ffffff; |
| | | line-height: 11px; |
| | | text-align: center; |
| | | } |
| | | .header-close { |
| | | position: absolute; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | right: 6px; |
| | | width: 15px; |
| | | height: 15px; |
| | | transition: transform 0.2s; |
| | | |
| | | &:active { |
| | | opacity: 0.6; |
| | | transform: translateY(-50%) scale(0.95); |
| | | } |
| | | } |
| | | } |
| | | .end-dialysis-content { |
| | | padding: 0 12px 0px 12px; |
| | | margin-bottom: 4px; |
| | | border-bottom: 1px solid #d8d8d8; |
| | | } |
| | | .my-button { |
| | | display: inline-block; |
| | | border-radius: 2px; |
| | | padding: 0px 10px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 7px; |
| | | color: #ffffff; |
| | | line-height: 16px; |
| | | letter-spacing: 1px; |
| | | text-align: center; |
| | | font-style: normal; |
| | | transition: transform 0.1s ease, opacity 0.1s ease; |
| | | cursor: pointer; |
| | | &:active { |
| | | transform: scale(0.95); |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | &:not(:first-child) { |
| | | margin-left: 6px; |
| | | } |
| | | |
| | | &.confirm { |
| | | background: #769aff; |
| | | } |
| | | &.cancel { |
| | | background: #bbc6dd; |
| | | } |
| | | &.refresh { |
| | | background: #e6a23c; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | alt="" |
| | | @click="openSettingDeviceDialog" |
| | | /> |
| | | <img :src="userImg" class="btn-img" alt="" @click="openLoginDialog" /> |
| | | <img v-if="userInfo?.code" :src="userInfo?.userAvatar" class="btn-img" alt="" @click="openLoginDialog" /> |
| | | <img v-else :src="userImg" class="btn-img" alt="" @click="openLoginDialog" /> |
| | | </div> |
| | | </div> |
| | | <!-- 设置设备编号组件 --> |
| | |
| | | } |
| | | }); |
| | | |
| | | |
| | | const userInfo = computed(() => { |
| | | if (!bedsideAuxiliaryScreenStore.userInfo) return null |
| | | return Object.assign({}, bedsideAuxiliaryScreenStore.userInfo, { |
| | | userAvatar: bedsideAuxiliaryScreenStore.userInfo?.userAvatar ? bedsideAuxiliaryScreenStore.userInfo?.userAvatar : generateCircularAvatar(bedsideAuxiliaryScreenStore.userInfo?.userName) |
| | | }); |
| | | }); |
| | | |
| | | watch( |
| | | () => bedsideAuxiliaryScreenStore.taskData?.[0]?.countdown, |
| | | (val) => { |
| | |
| | | loginDialogRef.value.openDialog(); |
| | | }; |
| | | |
| | | function generateCircularAvatar(name: string, size = 100): string { |
| | | console.log('name: ', name) |
| | | const canvas = document.createElement('canvas'); |
| | | canvas.width = size; |
| | | canvas.height = size; |
| | | const ctx = canvas.getContext('2d')!; |
| | | |
| | | // 绘制圆形背景 |
| | | ctx.fillStyle = '#dae5ec'; |
| | | ctx.beginPath(); |
| | | ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2); |
| | | ctx.fill(); |
| | | |
| | | // 绘制文字(第一个字) |
| | | ctx.fillStyle = '#70a3dd'; // 字体颜色 |
| | | ctx.font = `${size * 0.5}px sans-serif`; // 字体大小为头像大小的一半 |
| | | ctx.textAlign = 'center'; |
| | | ctx.textBaseline = 'middle'; |
| | | ctx.fillText(name.charAt(0), size / 2, size / 2); |
| | | |
| | | return canvas.toDataURL('image/png'); // 返回 Base64 图片 |
| | | } |
| | | |
| | | onUnmounted(() => { |
| | | clearTimer(); |
| | | }); |
| | |
| | | }); |
| | | |
| | | const isLoginng = computed(() => { |
| | | return !!bedsideAuxiliaryScreenStore.token; |
| | | return !!bedsideAuxiliaryScreenStore.userInfo?.code; |
| | | }); |
| | | |
| | | const qrCodeData = computed(() => { |
| | | return { |
| | | deviceCode: bedsideAuxiliaryScreenStore.deviceCode, |
| | | deviceNo: bedsideAuxiliaryScreenStore.deviceData.devicdeNo, |
| | | }; |
| | | }); |
| | | |
| | | const userInfo = computed(() => { |
| | | const userInfo = bedsideAuxiliaryScreenStore.userInfo; |
| | | if (!userInfo) return null; |
| | | return { |
| | | ...userInfo, |
| | | 床号: bedsideAuxiliaryScreenStore.deviceData.devicdeNo, |
| | | 设备编号: bedsideAuxiliaryScreenStore.deviceCode |
| | | } |
| | | }); |
| | | |
| | | const openDialog = () => { |
| | |
| | | }; |
| | | |
| | | const onLogout = () => { |
| | | if (state.loading) return ElMessage.warning('正在退出中...') |
| | | ElMessageBox.confirm("是否确认退出当前登录用户?", "提示", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | bedsideAuxiliaryScreenStore.logout(); |
| | | ElMessage({ |
| | | type: "success", |
| | | message: "退出成功!", |
| | | }); |
| | | .then(async() => { |
| | | state.loading = true |
| | | try { |
| | | await bedsideAuxiliaryScreenStore.logout(`deviceCode=${bedsideAuxiliaryScreenStore.deviceCode}`); |
| | | handleCancel(); |
| | | ElMessage.success('退出登录成功') |
| | | handleCancel(); |
| | | } catch (error) { |
| | | console.error('error: ', error) |
| | | // ElMessage.error('退出登录失败') |
| | | } finally { |
| | | state.loading = false; |
| | | } |
| | | }) |
| | | .catch(() => {}); |
| | | }; |
| | |
| | | handleCancel, |
| | | openDialog, |
| | | onLogout, |
| | | userInfo, |
| | | }; |
| | | }, |
| | | }; |
| | |
| | | <template> |
| | | <div class="userinfo-container"> |
| | | <img :src="userInfo.用户头像" alt="" srcset="" class="user-avatar"> |
| | | <div class="user-text">当前账户:{{ userInfo.用户昵称 }}</div> |
| | | <img :src="userInfo.userAvatar" alt="" srcset="" class="user-avatar" /> |
| | | <div class="user-text">当前账户:{{ userInfo.userName }}</div> |
| | | <div class="user-text">床号:{{ userInfo.床号 }}</div> |
| | | <div class="user-text">设备号:{{ userInfo.设备编号 }}</div> |
| | | </div> |
| | |
| | | <script lang="ts"> |
| | | import { computed } from "vue"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | import { defaultUserInfo } from '@/store/type/user.type'; |
| | | |
| | | export default { |
| | | name: "UserInfo", |
| | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const userInfo = computed(() => { |
| | | const userInfo = bedsideAuxiliaryScreenStore.userInfo || defaultUserInfo(); |
| | | const userInfo = bedsideAuxiliaryScreenStore.userInfo; |
| | | if (!userInfo) return null; |
| | | return { |
| | | ...userInfo, |
| | | 床号: bedsideAuxiliaryScreenStore.deviceData.devicdeNo, |
| | | 设备编号: bedsideAuxiliaryScreenStore.deviceCode |
| | | } |
| | | 设备编号: bedsideAuxiliaryScreenStore.deviceCode, |
| | | userAvatar: userInfo?.userAvatar ? userInfo?.userAvatar : generateCircularAvatar(userInfo?.userName) |
| | | }; |
| | | }); |
| | | |
| | | function generateCircularAvatar(name: string, size = 100): string { |
| | | console.log("name: ", name); |
| | | const canvas = document.createElement("canvas"); |
| | | canvas.width = size; |
| | | canvas.height = size; |
| | | const ctx = canvas.getContext("2d")!; |
| | | |
| | | // 绘制圆形背景 |
| | | ctx.fillStyle = "#769aff"; |
| | | ctx.beginPath(); |
| | | ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2); |
| | | ctx.fill(); |
| | | |
| | | // 绘制文字(第一个字) |
| | | ctx.fillStyle = "#FFFFFF"; // 字体颜色 |
| | | ctx.font = `${size * 0.5}px sans-serif`; // 字体大小为头像大小的一半 |
| | | ctx.textAlign = "center"; |
| | | ctx.textBaseline = "middle"; |
| | | ctx.fillText(name.charAt(0), size / 2, size / 2); |
| | | |
| | | return canvas.toDataURL("image/png"); // 返回 Base64 图片 |
| | | } |
| | | |
| | | return { |
| | | userInfo |
| | | userInfo, |
| | | }; |
| | | }, |
| | | }; |
| | |
| | | |
| | | <style lang="less" scoped> |
| | | .userinfo-container { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | .user-avatar { |
| | | width: 15px; |
| | | height: 15px; |
| | | border-radius: 50%; |
| | | overflow: hidden; |
| | | margin-bottom: 5px; |
| | | } |
| | | .user-text { |
| | | font-size: 5px; |
| | | color: #000; |
| | | margin-bottom: 4px; |
| | | } |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | .user-avatar { |
| | | width: 15px; |
| | | height: 15px; |
| | | border-radius: 50%; |
| | | overflow: hidden; |
| | | margin-bottom: 5px; |
| | | } |
| | | .user-text { |
| | | font-size: 5px; |
| | | color: #000; |
| | | margin-bottom: 4px; |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div class="start-dialysis-container"> |
| | | <el-dialog |
| | | v-model="show" |
| | | center |
| | | title="开始透析" |
| | | width="80%" |
| | | :show-close="false" |
| | | class="start-dialysis-dialog" |
| | | :destroy-on-close="true" |
| | | :close-on-click-modal="false" |
| | | > |
| | | <template #header> |
| | | <div class="start-dialysis-header"> |
| | | <span class="header-title">开始透析</span> |
| | | <img |
| | | :src="closeImg" |
| | | class="header-close" |
| | | @click="handleCancel" |
| | | alt="" |
| | | /> |
| | | </div> |
| | | </template> |
| | | <div class="start-dialysis-content" v-loading="loading"> |
| | | <el-form :model="formData" size="large"> |
| | | <el-row :gutter="10"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="开始时间"> |
| | | <el-time-select |
| | | v-model="formData.startTime" |
| | | start="00:00" |
| | | step="00:01" |
| | | end="23:59" |
| | | placeholder="请选择" |
| | | :clearable="false" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="治疗护士"> |
| | | <el-select |
| | | @change="onStartMedNurseChange" |
| | | style="width: 100%" |
| | | v-model="formData.startMedNurse" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in nurseOptions" |
| | | :key="item.code" |
| | | :label="item.userName" |
| | | :disabled="item.isValid === 0" |
| | | :value="item.code" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="上机护士"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="formData.startUpNurse" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in nurseOptions" |
| | | :key="item.code" |
| | | :label="item.userName" |
| | | :disabled="item.isValid === 0" |
| | | :value="item.code" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="预充管路"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="formData.startYcNurse" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in nurseOptions" |
| | | :key="item.code" |
| | | :label="item.userName" |
| | | :disabled="item.isValid === 0" |
| | | :value="item.code" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="穿刺/换药"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="formData.startIsCcOrHy" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="(item, index) in startIsCcOrHyOptions" |
| | | :key="index" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <template v-if="formData.startIsCcOrHy === 1"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="换药护士"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="formData.startCcNurse" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in nurseOptions" |
| | | :key="item.code" |
| | | :label="item.userName" |
| | | :disabled="item.isValid === 0" |
| | | :value="item.code" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </template> |
| | | <template v-else-if="formData.startIsCcOrHy === 0"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="穿刺护士"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="formData.startCcNurse" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in nurseOptions" |
| | | :key="item.code" |
| | | :label="item.userName" |
| | | :disabled="item.isValid === 0" |
| | | :value="item.code" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </template> |
| | | <template v-else-if="formData.startIsCcOrHy === 2"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="换药护士"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="formData.startCcNurse" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in nurseOptions" |
| | | :key="item.code" |
| | | :label="item.userName" |
| | | :disabled="item.isValid === 0" |
| | | :value="item.code" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </template> |
| | | <template |
| | | v-if=" |
| | | formData.startIsCcOrHy === 2 || formData.startIsCcOrHy === 0 |
| | | " |
| | | > |
| | | <el-col :span="6"> |
| | | <el-form-item label="穿刺方式" prop="doneCcType"> |
| | | <el-select |
| | | style="width: 100%" |
| | | multiple |
| | | v-model="formData.startCcType" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in punctureMethodOptions" |
| | | :key="item.code" |
| | | :label="item.dictText" |
| | | :value="item.dictText" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="穿刺针A"> |
| | | <el-select |
| | | clearable |
| | | style="width: 100%" |
| | | v-model="formData.startCcZhenA" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in punctureNeedleOptions" |
| | | :key="item.code" |
| | | :label="item.itemName + ' ' + item.itemSpec" |
| | | :value="item.code" |
| | | :disabled="item.isShow !== 1" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item clearable label="穿刺针V"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="formData.startCcZhenV" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in punctureNeedleOptions" |
| | | :key="item.code" |
| | | :label="item.itemName + ' ' + item.itemSpec" |
| | | :value="item.code" |
| | | :disabled="item.isShow !== 1" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="穿刺方向"> |
| | | <el-select |
| | | style="width: 100%" |
| | | multiple |
| | | v-model="formData.startCcASideDirection" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="item in punctureDirectionOptions" |
| | | :key="item.code" |
| | | :label="item.dictText" |
| | | :value="item.dictText" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </template> |
| | | <el-col :span="6"> |
| | | <el-form-item label="引血(ml/min)"> |
| | | <el-input style="width: 100%" v-model="formData.startYingxue" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="透析器编号"> |
| | | <el-input style="width: 100%" v-model="formData.startTxqNo" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="入科方式"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="formData.startEntranceType" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="(item, index) in startEntranceTypeOptions" |
| | | :key="index" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="一次性使用管路"> |
| | | <el-select v-model="formData.doneGl" placeholder="请选择"> |
| | | <el-option |
| | | v-for="(item, index) in disposablePipelineOptions" |
| | | :key="index" |
| | | :label="item.itemName + ' ' + item.itemSpec" |
| | | :value="item.code" |
| | | :disabled="item.isShow !== 1" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="血滤管"> |
| | | <el-select |
| | | v-model="formData.doneByg" |
| | | :disabled="formData.schemeName !== 'HDF'" |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="(item, index) in hemofiltrationTubeOptions" |
| | | :key="index" |
| | | :label="item.itemName + ' ' + item.itemSpec" |
| | | :value="item.code" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="透析浓缩液"> |
| | | <el-select |
| | | v-model="formData.startUseNsy" |
| | | multiple |
| | | filterable |
| | | clearable |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="(item, index) in doneUseNsyOptions" |
| | | :key="index" |
| | | :label="item.itemName + ' ' + item.itemSpec" |
| | | :value="item.code" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-form-item label="透析护理包"> |
| | | <el-select |
| | | v-model="formData.startUseHlb" |
| | | filterable |
| | | clearable |
| | | placeholder="请选择" |
| | | > |
| | | <el-option |
| | | v-for="(item, index) in doneUseHlbOptions" |
| | | :key="index" |
| | | :label="item.itemName + ' ' + item.itemSpec" |
| | | :value="item.code" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </div> |
| | | <template #footer> |
| | | <div class="my-button cancel" @click="handleCancel">取消</div> |
| | | <div |
| | | class="my-button confirm" |
| | | :class="loading ? 'cancel' : ''" |
| | | @click="handleConfirm" |
| | | > |
| | | 确认 |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { computed, reactive, toRefs } from "vue"; |
| | | import closeImg from "@/img/close.png"; |
| | | import { |
| | | addDefaultRowApi, |
| | | updateMedstartDataApi, |
| | | } from "@/api/patient_hemo_med_start/index"; |
| | | import type { StartRecord } from "@/api/patient_hemo_med_start/types/index.type"; |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | import { getInventoryItemListApi } from "@/api/inventory/itemDict"; |
| | | import { getUsersByRoleCodeApi } from "@/api/user/index"; |
| | | import { getDictTypeApi } from "@/api/dict/index"; |
| | | import { DictType } from "@/api/dict/types/index.type"; |
| | | import dayjs from "dayjs"; |
| | | import { ElMessage } from "element-plus/es"; |
| | | |
| | | interface FormData |
| | | extends Omit< |
| | | StartRecord, |
| | | "startCcType" | "startCcASideDirection" | "startUseNsy" |
| | | > { |
| | | /** 穿刺方式 */ |
| | | startCcType: string[]; |
| | | /** 穿刺方向 */ |
| | | startCcASideDirection: string[]; |
| | | startUseNsy: string[]; |
| | | } |
| | | |
| | | interface State { |
| | | loading: boolean; |
| | | show: boolean; |
| | | formData: FormData; |
| | | doneUseNsyOptions: any[]; |
| | | doneUseHlbOptions: any[]; |
| | | disposablePipelineOptions: any[]; |
| | | hemofiltrationTubeOptions: any[]; |
| | | nurseOptions: any[]; |
| | | punctureMethodOptions: any[]; |
| | | typePunctureNeedleOptions: any[]; |
| | | punctureDirectionOptions: any[]; |
| | | punctureNeedleOptions: any[]; |
| | | startIsCcOrHyOptions: any[]; |
| | | startEntranceTypeOptions: any[]; |
| | | startDate: string; |
| | | } |
| | | export default { |
| | | name: "StartDialysis", |
| | | setup() { |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const state = reactive<State>({ |
| | | loading: false, |
| | | show: false, |
| | | formData: { |
| | | code: "", |
| | | createTime: "", |
| | | createUser: null, |
| | | deletedTime: null, |
| | | doneByg: "", |
| | | doneBygName: "", |
| | | doneBygSpecName: "", |
| | | doneGl: "", |
| | | doneGlName: "", |
| | | doneGlSpecName: "", |
| | | id: null, |
| | | isDeleted: null, |
| | | monitorDataCode: "", |
| | | recordCode: "", |
| | | remark: "", |
| | | schemeName: "", |
| | | /** 穿刺方向 */ |
| | | startCcASideDirection: [], |
| | | startCcNurse: "", |
| | | startCcNurseName: "", |
| | | /** 穿刺方式 */ |
| | | startCcType: [], |
| | | startCcZhenA: "", |
| | | startCcZhenAName: "", |
| | | startCcZhenASpecName: "", |
| | | startCcZhenType: "", |
| | | startCcZhenV: "", |
| | | startCcZhenVName: "", |
| | | startCcZhenVSpecName: "", |
| | | startEntranceType: "", |
| | | startIsCcOrHy: null, |
| | | startIsSave: null, |
| | | startMedNurse: "", |
| | | startMedNurseName: "", |
| | | startTime: null, |
| | | startTxqNo: "", |
| | | startUpNurse: "", |
| | | startUpNurseName: "", |
| | | startUseHlb: "", |
| | | startUseHlbName: "", |
| | | startUseHlbSpecName: "", |
| | | startUseNsy: [], |
| | | startUseNsyName: "", |
| | | startUseNsySpecName: "", |
| | | startYcNurse: "", |
| | | startYcNurseName: "", |
| | | startYingxue: "", |
| | | updateTime: "", |
| | | updateUser: null, |
| | | }, |
| | | doneUseNsyOptions: [], // 透析浓缩液列表 |
| | | doneUseHlbOptions: [], // 透析护理包列表 |
| | | disposablePipelineOptions: [], // 一次性使用管路列表 |
| | | hemofiltrationTubeOptions: [], // 血滤管列表 |
| | | nurseOptions: [], // 护士列表 |
| | | punctureMethodOptions: [], // 穿刺方式列表 |
| | | typePunctureNeedleOptions: [], // 穿刺针类型列表 |
| | | punctureDirectionOptions: [], // 穿刺方向列表 |
| | | punctureNeedleOptions: [], // 穿刺针列表 |
| | | startIsCcOrHyOptions: [ |
| | | { label: "穿刺", value: 0 }, |
| | | { label: "换药", value: 1 }, |
| | | { label: "穿刺+换药", value: 2 }, |
| | | ], |
| | | startEntranceTypeOptions: [ |
| | | { label: "步行", value: "步行" }, |
| | | { label: "扶行", value: "扶行" }, |
| | | { label: "轮椅", value: "轮椅" }, |
| | | { label: "平床", value: "平床" }, |
| | | { label: "床旁", value: "床旁" }, |
| | | { label: "助行器", value: "助行器" }, |
| | | ], |
| | | startDate: "", // 日期部分 |
| | | }); |
| | | |
| | | const recordCode = computed(() => { |
| | | return bedsideAuxiliaryScreenStore.deviceData.signedIn.透析单编号; |
| | | }); |
| | | |
| | | const clientCode = computed(() => { |
| | | return bedsideAuxiliaryScreenStore.deviceData.客户编号; |
| | | }); |
| | | |
| | | const userCode = computed(() => { |
| | | return bedsideAuxiliaryScreenStore.userInfo.userCode; |
| | | }); |
| | | |
| | | const openDialog = async () => { |
| | | state.show = true; |
| | | state.loading = true; |
| | | try { |
| | | const promiseFuns = [ |
| | | getDoneUseNsys(), |
| | | getdoneUseHlbs(), |
| | | getDisposablePipelines(), |
| | | getHemofiltrationTubes(), |
| | | getPunctureNeedles(), |
| | | getNurses(), |
| | | getPunctureMethods(), |
| | | getTypePunctureNeedles(), |
| | | getPunctureDirectionOptions(), |
| | | ]; |
| | | // if (state.doneUseNsyOptions.length <= 0) { |
| | | // promiseFuns.push(getDoneUseNsys()); |
| | | // } |
| | | // if (state.doneUseHlbOptions.length <= 0) { |
| | | // promiseFuns.push(getdoneUseHlbs()); |
| | | // } |
| | | // if (state.disposablePipelineOptions.length <= 0) { |
| | | // promiseFuns.push(getDisposablePipelines()); |
| | | // } |
| | | // if (state.hemofiltrationTubeOptions.length <= 0) { |
| | | // promiseFuns.push(getHemofiltrationTubes()); |
| | | // } |
| | | // if (state.punctureNeedleOptions.length <= 0) { |
| | | // promiseFuns.push(getPunctureNeedles()); |
| | | // } |
| | | // if (state.nurseOptions.length <= 0) { |
| | | // promiseFuns.push(getNurses()); |
| | | // } |
| | | // if (state.punctureMethodOptions.length <= 0) { |
| | | // promiseFuns.push(getPunctureMethods()); |
| | | // } |
| | | // if (state.typePunctureNeedleOptions.length <= 0) { |
| | | // promiseFuns.push(getTypePunctureNeedles()); |
| | | // } |
| | | // if (state.punctureDirectionOptions.length <= 0) { |
| | | // promiseFuns.push(getPunctureDirectionOptions()); |
| | | // } |
| | | await Promise.all(promiseFuns); |
| | | await getStartData(); |
| | | } catch (error) { |
| | | console.error("开始透析初始化失败", error); |
| | | state.show = false; |
| | | } finally { |
| | | state.loading = false; |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 获取开始透析默认数据 |
| | | */ |
| | | const getStartData = async () => { |
| | | const { data } = await addDefaultRowApi(`recordCode=${recordCode.value}`); |
| | | const dataCopy = JSON.parse(JSON.stringify(data)); |
| | | const nots = ["", null]; |
| | | |
| | | if (!nots.includes(data.startCcType)) { |
| | | // @ts-ignore |
| | | dataCopy.startCcType = data.startCcType.split(","); |
| | | } else { |
| | | // @ts-ignore |
| | | dataCopy.startCcType = []; |
| | | } |
| | | |
| | | if (!nots.includes(data.startCcASideDirection)) { |
| | | // @ts-ignore |
| | | dataCopy.startCcASideDirection = data.startCcASideDirection.split(","); |
| | | } else { |
| | | // @ts-ignore |
| | | dataCopy.startCcASideDirection = []; |
| | | } |
| | | |
| | | if (nots.includes(data.startTime)) { |
| | | dataCopy.startTime = dayjs().format("HH:mm"); |
| | | state.startDate = dayjs().format("YYYY-MM-DD"); |
| | | } else { |
| | | dataCopy.startTime = dayjs(data.startTime).format("HH:mm"); |
| | | state.startDate = dayjs(data.startTime).format("YYYY-MM-DD"); |
| | | } |
| | | |
| | | if (nots.includes(data.startMedNurse)) { |
| | | dataCopy.startMedNurse = userCode.value; |
| | | } |
| | | |
| | | if (nots.includes(data.startCcNurse)) { |
| | | dataCopy.startCcNurse = userCode.value; |
| | | } |
| | | if (nots.includes(data.startUpNurse)) { |
| | | dataCopy.startUpNurse = userCode.value; |
| | | } |
| | | if (nots.includes(data.startYcNurse)) { |
| | | dataCopy.startYcNurse = userCode.value; |
| | | } |
| | | if (!nots.includes(data.startUseNsy)) { |
| | | // @ts-ignore |
| | | dataCopy.startUseNsy = data.startUseNsy.split(","); |
| | | } else { |
| | | // @ts-ignore |
| | | dataCopy.startUseNsy = []; |
| | | } |
| | | |
| | | if (data.schemeName !== "HDF") { |
| | | // 如果透析模式不算HDF的话血滤管置空 |
| | | dataCopy.doneByg = ""; |
| | | dataCopy.doneBygName = ""; |
| | | } else { |
| | | const defaultXlg = state.hemofiltrationTubeOptions.find( |
| | | (e) => e.itemName === "义鑫血液净化补液管路(HDIT-1)" |
| | | ); |
| | | if (defaultXlg) { |
| | | dataCopy.doneByg = defaultXlg.code; |
| | | dataCopy.doneBygName = defaultXlg.itemName; |
| | | } |
| | | } |
| | | state.formData = dataCopy as unknown as FormData; |
| | | }; |
| | | |
| | | /** |
| | | * 获取透析浓缩液字典数据 |
| | | */ |
| | | const getDoneUseNsys = async () => { |
| | | const params = { |
| | | page: 0, |
| | | size: 0, |
| | | wherecondition: `inventory_type_code='IT2112291619002680' and is_show = 1 and client_code='${clientCode.value}'`, |
| | | ordercondition: "item_is_use desc, item_sort_order asc", |
| | | isPure: 0, |
| | | }; |
| | | const { data } = await getInventoryItemListApi(params); |
| | | state.doneUseNsyOptions = data.list; |
| | | }; |
| | | |
| | | /** |
| | | * 获取透析护理包字典数据 |
| | | */ |
| | | const getdoneUseHlbs = async () => { |
| | | const params = { |
| | | page: 0, |
| | | size: 0, |
| | | wherecondition: `inventory_type_code='IT2112291619003161' and is_show = 1 and client_code='${clientCode.value}'`, |
| | | ordercondition: "item_is_use desc, item_sort_order asc", |
| | | isPure: 0, |
| | | }; |
| | | const { data } = await getInventoryItemListApi(params); |
| | | state.doneUseHlbOptions = data.list; |
| | | }; |
| | | |
| | | /** |
| | | * 获取一次性使用管路字典数据 |
| | | */ |
| | | const getDisposablePipelines = async () => { |
| | | const params = { |
| | | page: 0, |
| | | size: 0, |
| | | wherecondition: `inventory_type_code='IT2112291619006054' and is_show = 1 and client_code='${clientCode.value}'`, |
| | | ordercondition: "item_is_use desc, item_sort_order asc", |
| | | isPure: 0, |
| | | }; |
| | | const { data } = await getInventoryItemListApi(params); |
| | | state.disposablePipelineOptions = data.list; |
| | | }; |
| | | |
| | | /** |
| | | * 获取血滤管字典数据 |
| | | */ |
| | | const getHemofiltrationTubes = async () => { |
| | | const params = { |
| | | page: 1, |
| | | size: 10, |
| | | wherecondition: `inventory_type_code='IT9024215920713quQV' and is_show = 1 and client_code='${clientCode.value}'`, |
| | | ordercondition: "item_is_use desc, item_sort_order asc", |
| | | isPure: 0, |
| | | }; |
| | | const { data } = await getInventoryItemListApi(params); |
| | | state.hemofiltrationTubeOptions = data.list; |
| | | }; |
| | | |
| | | /** |
| | | * 获取穿刺针字典数据 |
| | | */ |
| | | const getPunctureNeedles = async () => { |
| | | const params = { |
| | | page: 1, |
| | | size: 10, |
| | | wherecondition: `(inventory_type_code='IT3561011130526051' OR inventory_type_code='IT2112291619000061') and client_code='${clientCode.value}'`, |
| | | ordercondition: "item_is_use desc, item_sort_order asc", |
| | | }; |
| | | const { data } = await getInventoryItemListApi(params); |
| | | state.punctureNeedleOptions = data.list; |
| | | }; |
| | | |
| | | /** |
| | | * 获取护士数据 |
| | | */ |
| | | const getNurses = async () => { |
| | | const { data } = await getUsersByRoleCodeApi( |
| | | `clientCode=${clientCode.value}&roleClass=nurse` |
| | | ); |
| | | state.nurseOptions = data; |
| | | }; |
| | | |
| | | /** |
| | | * 获取穿刺方式字典数据 |
| | | */ |
| | | const getPunctureMethods = async () => { |
| | | const { data } = await getDictTypeApi({ dictType: DictType.穿刺方式 }); |
| | | state.punctureMethodOptions = data; |
| | | }; |
| | | |
| | | /** |
| | | * 获取穿刺针类型字典数据 |
| | | */ |
| | | const getTypePunctureNeedles = async () => { |
| | | const { data } = await getDictTypeApi({ dictType: DictType.穿刺针类型 }); |
| | | state.typePunctureNeedleOptions = data; |
| | | }; |
| | | |
| | | /** |
| | | * 获取穿刺针方向字典数据 |
| | | */ |
| | | const getPunctureDirectionOptions = async () => { |
| | | const { data } = await getDictTypeApi({ dictType: DictType.穿刺方向 }); |
| | | state.punctureDirectionOptions = data; |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | state.show = false; |
| | | state.loading = false; |
| | | }; |
| | | |
| | | const handleConfirm = async () => { |
| | | state.loading = true; |
| | | try { |
| | | const paramsData = Object.assign({}, state.formData, { |
| | | startCcASideDirection: |
| | | state.formData.startCcASideDirection.toString(), |
| | | startCcType: state.formData.startCcType.toString(), |
| | | startUseNsy: state.formData.startUseNsy.join(","), |
| | | startTime: `${state.startDate} ${state.formData.startTime}:00`, |
| | | }); |
| | | await updateMedstartDataApi(paramsData); |
| | | ElMessage.success("操作成功!"); |
| | | state.show = false; |
| | | } finally { |
| | | state.loading = false; |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * 治疗护士的改变 |
| | | * @param val |
| | | */ |
| | | const onStartMedNurseChange = (val: string) => { |
| | | state.formData.startCcNurse = val; |
| | | state.formData.startUpNurse = val; |
| | | state.formData.startYcNurse = val; |
| | | }; |
| | | |
| | | return { |
| | | ...toRefs(state), |
| | | closeImg, |
| | | handleCancel, |
| | | openDialog, |
| | | handleConfirm, |
| | | onStartMedNurseChange, |
| | | }; |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .start-dialysis-container { |
| | | ::v-deep(.el-dialog) { |
| | | padding: 0; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | } |
| | | ::v-deep(.el-dialog__footer) { |
| | | padding: 4px; |
| | | } |
| | | ::v-deep(.el-upload-dragger) { |
| | | height: 65px; |
| | | padding: 0 !important; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | ::v-deep(.el-upload-dragger .el-icon--upload) { |
| | | display: none; |
| | | } |
| | | ::v-deep(.el-dialog__header) { |
| | | padding-bottom: 6px; |
| | | } |
| | | .start-dialysis-header { |
| | | position: relative; |
| | | height: 16px; |
| | | background: #769aff; |
| | | .header-title { |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translateX(-50%) translateY(-50%); |
| | | font-family: AlibabaPuHuiTi, AlibabaPuHuiTi; |
| | | font-weight: 500; |
| | | font-size: 8px; |
| | | color: #ffffff; |
| | | line-height: 11px; |
| | | text-align: center; |
| | | } |
| | | .header-close { |
| | | position: absolute; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | right: 6px; |
| | | width: 15px; |
| | | height: 15px; |
| | | transition: transform 0.2s; |
| | | |
| | | &:active { |
| | | opacity: 0.6; |
| | | transform: translateY(-50%) scale(0.95); |
| | | } |
| | | } |
| | | } |
| | | .start-dialysis-content { |
| | | padding: 0 12px 0px 12px; |
| | | margin-bottom: 4px; |
| | | border-bottom: 1px solid #d8d8d8; |
| | | } |
| | | .my-button { |
| | | display: inline-block; |
| | | border-radius: 2px; |
| | | padding: 0px 10px; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 7px; |
| | | color: #ffffff; |
| | | line-height: 16px; |
| | | letter-spacing: 1px; |
| | | text-align: center; |
| | | font-style: normal; |
| | | transition: transform 0.1s ease, opacity 0.1s ease; |
| | | cursor: pointer; |
| | | &:active { |
| | | transform: scale(0.95); |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | &:not(:first-child) { |
| | | margin-left: 6px; |
| | | } |
| | | |
| | | &.confirm { |
| | | background: #769aff; |
| | | } |
| | | &.cancel { |
| | | background: #bbc6dd; |
| | | } |
| | | &.refresh { |
| | | background: #e6a23c; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <tr> |
| | | <td>体重增长</td> |
| | | <td class="flex-td"> |
| | | <span class="sub-text">(透前-干体重)</span><span class="text-right">{{ weightGain2 }}kg</span> |
| | | <span class="sub-text">(透前-干体重)</span |
| | | ><span class="text-right">{{ weightGain2 }}kg</span> |
| | | </td> |
| | | </tr> |
| | | <!-- <tr> |
| | |
| | | @click="() => onScheduledTasksClick()" |
| | | class="btn" |
| | | /> |
| | | <BlockBotttom |
| | | <!-- <BlockBotttom |
| | | :icon="jiaoHaoImg" |
| | | text="叫号" |
| | | backgroundColor="#20C6B6" |
| | | @click="() => onCallBumberClick()" |
| | | class="btn" |
| | | /> |
| | | /> --> |
| | | <BlockBotttom |
| | | v-if="isShowStartBtn" |
| | | :icon="kaiShiImg" |
| | | text="开始" |
| | | backgroundColor="#409EFF" |
| | |
| | | </div> |
| | | <!-- 定时任务 --> |
| | | <ScheduledTaskDialog ref="scheduledTaskDialogRef" /> |
| | | <!-- 开始透析组件 --> |
| | | <StartDialysis ref="startDialysisRef" /> |
| | | </div> |
| | | </template> |
| | | <script lang="ts" setup name="SignedIn"> |
| | |
| | | // @ts-ignore |
| | | import BlockBotttom from "../components/BlockBotttom.vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { EMedStatus } from '@/store/type/bedsideAuxiliaryScreen.type'; |
| | | const ScheduledTaskDialog = defineAsyncComponent( |
| | | () => import("../components/ScheduledTask.vue") |
| | | ); |
| | | const StartDialysis = defineAsyncComponent(() => import('../components/StartDialysis/index.vue')); |
| | | |
| | | interface Props { |
| | | height: number; |
| | |
| | | |
| | | const bloodPressureRectangularChart = ref<HTMLElement | null>(null); |
| | | const scheduledTaskDialogRef = ref<any>(null); |
| | | |
| | | const startDialysisRef = ref<any>(null); |
| | | |
| | | const pageData = computed(() => { |
| | | return Object.assign(bedsideAuxiliaryScreenStore.deviceData.signedIn, { |
| | |
| | | return formattedValue; |
| | | }); |
| | | |
| | | /** |
| | | * 是否显示开始透析按钮 |
| | | */ |
| | | const isShowStartBtn = computed(() => { |
| | | return +bedsideAuxiliaryScreenStore.deviceData.treatmentStatus === EMedStatus.SIGNED_IN; |
| | | }) |
| | | |
| | | watch( |
| | | () => pageData.value.四点血压图数据, |
| | | (newVal) => { |
| | | genderBloodPressureRectangularChart(newVal); |
| | | }); |
| | | } |
| | | ); |
| | | |
| | | /** 点击定时任务 */ |
| | | const onScheduledTasksClick = () => { |
| | |
| | | }; |
| | | |
| | | const onStartClick = () => { |
| | | ElMessage({ |
| | | message: "功能开发中,敬请期待!", |
| | | type: "warning", |
| | | }); |
| | | if ( |
| | | !bedsideAuxiliaryScreenStore.deviceCode || |
| | | !bedsideAuxiliaryScreenStore.deviceData.deviceCode |
| | | ) |
| | | return ElMessage.warning("未初始化或正在进行初始化操作中"); |
| | | if (!bedsideAuxiliaryScreenStore.userInfo?.token) |
| | | return ElMessage.warning("请登录"); |
| | | startDialysisRef.value?.openDialog(); |
| | | }; |
| | | |
| | | const genderBloodPressureRectangularChart = (datas: 四点血压图数据[] | null) => { |
| | | const genderBloodPressureRectangularChart = ( |
| | | datas: 四点血压图数据[] | null |
| | | ) => { |
| | | if (!bloodPressureRectangularChart.value) return; |
| | | |
| | | const benchmarkData = { width: 386, height: 280 }; |
| | | |
| | | // 获取容器宽高(90% 缩放) |
| | | const containerWidth = bloodPressureRectangularChart.value.offsetWidth * 0.9; |
| | | const containerHeight = bloodPressureRectangularChart.value.offsetHeight * 0.9; |
| | | const containerHeight = |
| | | bloodPressureRectangularChart.value.offsetHeight * 0.9; |
| | | |
| | | // 获取设备像素比 |
| | | const dpr = window.devicePixelRatio || 1; |
| | |
| | | |
| | | // ========== 血压数据 ========== |
| | | const measurements = [ |
| | | { systolic: datas?.[0]?.血压1_透前收缩压 ?? 0, diastolic: datas?.[0]?.血压1_透前舒张压 ?? 0 }, |
| | | { systolic: datas?.[0]?.血压2_前半程最低收缩压 ?? 0, diastolic: datas?.[0]?.血压2_前半程最低舒张压 ?? 0 }, |
| | | { systolic: datas?.[0]?.血压3_后半程最低收缩压 ?? 0, diastolic: datas?.[0]?.血压3_后半程最低舒张压 ?? 0 }, |
| | | { systolic: datas?.[0]?.血压4_透后收缩压 ?? 0, diastolic: datas?.[0]?.血压4_透后舒张压 ?? 0 }, |
| | | { |
| | | systolic: datas?.[0]?.血压1_透前收缩压 ?? 0, |
| | | diastolic: datas?.[0]?.血压1_透前舒张压 ?? 0, |
| | | }, |
| | | { |
| | | systolic: datas?.[0]?.血压2_前半程最低收缩压 ?? 0, |
| | | diastolic: datas?.[0]?.血压2_前半程最低舒张压 ?? 0, |
| | | }, |
| | | { |
| | | systolic: datas?.[0]?.血压3_后半程最低收缩压 ?? 0, |
| | | diastolic: datas?.[0]?.血压3_后半程最低舒张压 ?? 0, |
| | | }, |
| | | { |
| | | systolic: datas?.[0]?.血压4_透后收缩压 ?? 0, |
| | | diastolic: datas?.[0]?.血压4_透后舒张压 ?? 0, |
| | | }, |
| | | ]; |
| | | |
| | | const measurementWidth = chartWidth / (measurements.length + 1); |
| | |
| | | const cylinderHeight = 计算脱水量刻度 * (datas?.[0]?.超滤总量 || 0); |
| | | const 体重增长_透前减干体重 = weightGain2.value; |
| | | const 透前减干体重减超滤总量差值 = |
| | | Math.round( |
| | | (体重增长_透前减干体重 - (datas?.[0]?.超滤总量 || 0)) * 10 |
| | | ) / 10; |
| | | |
| | | Math.round((体重增长_透前减干体重 - (datas?.[0]?.超滤总量 || 0)) * 10) / 10; |
| | | |
| | | drawCylinder( |
| | | ctx, |
| | |
| | | datas?.[0]?.脱水百分比 ?? 0, |
| | | datas?.[0]?.透后体重减干体重的差值 ?? 0, |
| | | 体重增长_透前减干体重, |
| | | 透前减干体重减超滤总量差值, |
| | | 透前减干体重减超滤总量差值 |
| | | ); |
| | | |
| | | ctx.restore(); // 恢复 |
| | | }; |
| | | |
| | | |
| | | |
| | | const drawCylinder = ( |
| | | ctx: CanvasRenderingContext2D, |
| | |
| | | 脱水百分比: number, // 脱水百分比 |
| | | 透后体重减干体重的差值: number, // 透后体重减干体重的差值 |
| | | 体重增长_透前减干体重: number, // 体重增长_透前减干体重 |
| | | 透前减干体重减超滤总量差值: number, // 透前减干体重减超滤总量差值 |
| | | 透前减干体重减超滤总量差值: number // 透前减干体重减超滤总量差值 |
| | | ) => { |
| | | ctx.beginPath(); |
| | | ctx.arc(x, y + height, radius, 0, Math.PI * 2); |
| | |
| | | |
| | | // 如果超滤总量 与 体重增长_透前减干体重 相等,则显示 "/超滤总量" |
| | | if (Number(超滤总量) && 体重增长_透前减干体重 === Number(超滤总量)) { |
| | | ctx.font = `${baseFontSize * scale}px Arial`; |
| | | ctx.textAlign = "center"; |
| | | ctx.fillStyle = "#07c160"; |
| | | ctx.fillText('/' + 超滤总量, textX, canvasHeight - height + height * 0.3 + 10); |
| | | ctx.font = `${baseFontSize * scale}px Arial`; |
| | | ctx.textAlign = "center"; |
| | | ctx.fillStyle = "#07c160"; |
| | | ctx.fillText( |
| | | "/" + 超滤总量, |
| | | textX, |
| | | canvasHeight - height + height * 0.3 + 10 |
| | | ); |
| | | } else { |
| | | // 透析前-干体重 |
| | | ctx.font = `${baseFontSize * scale}px Arial`; |
| | | ctx.textAlign = "center"; |
| | | ctx.fillStyle = "#409EFF"; |
| | | ctx.fillText(体重增长_透前减干体重 + '', textX, canvasHeight - height + 10); |
| | | ctx.fillText(体重增长_透前减干体重 + "", textX, canvasHeight - height + 10); |
| | | // 超滤总量 |
| | | ctx.font = `${baseFontSize * scale}px Arial`; |
| | | ctx.textAlign = "center"; |
| | | ctx.fillStyle = "#07c160"; |
| | | ctx.fillText(超滤总量, textX, canvasHeight - height + height * 0.3 + 10); |
| | | } |
| | | |
| | | |
| | | |
| | | if (透前减干体重减超滤总量差值 > 0) { |
| | | ctx.font = `${baseFontSize * scale}px Arial`; |
| | |
| | | font-size: 3px; |
| | | color: #666; |
| | | margin-right: 1.2px; |
| | | white-space: nowrap; |
| | | white-space: nowrap; |
| | | } |
| | | // .text-right { |
| | | // position: absolute; |
| | |
| | | @click="() => onScheduledTasksClick()" |
| | | class="btn" |
| | | /> |
| | | <BlockBotttom |
| | | <!-- <BlockBotttom |
| | | :icon="jiaoHaoImg" |
| | | text="叫号" |
| | | backgroundColor="#20C6B6" |
| | | @click="() => onCallBumberClick()" |
| | | class="btn" |
| | | /> |
| | | <BlockBotttom |
| | | /> --> |
| | | <!-- <BlockBotttom |
| | | :icon="addImg" |
| | | text="添加记录" |
| | | backgroundColor="#409EFF" |
| | | @click="() => onAddRecordClick()" |
| | | class="btn" |
| | | /> |
| | | /> --> |
| | | <BlockBotttom |
| | | v-if="!whetherDialysisHasBeenEnded" |
| | | :icon="kaiShiImg" |
| | |
| | | </div> |
| | | <!-- 定时任务 --> |
| | | <ScheduledTaskDialog ref="scheduledTaskDialogRef" /> |
| | | <!-- 结束透析组件 --> |
| | | <EndDialysis ref="endDialysisRef" /> |
| | | </div> |
| | | </template> |
| | | <script lang="ts" setup name="UnderTreatment"> |
| | |
| | | const ScheduledTaskDialog = defineAsyncComponent( |
| | | () => import("../components/ScheduledTask.vue") |
| | | ); |
| | | const EndDialysis = defineAsyncComponent(() => import("../components/EndDialysis/index.vue")); |
| | | import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen"; |
| | | import { |
| | | formatSubstituteMode, |
| | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const scheduledTaskDialogRef = ref<any>(null); |
| | | const endDialysisRef = ref<any>(null); |
| | | |
| | | // ktv趋势图的 |
| | | const ktvListEchartRef = ref<HTMLElement | null>(null); |
| | |
| | | +bedsideAuxiliaryScreenStore.deviceData.treatmentStatus >= EMedStatus.END |
| | | ); |
| | | }); |
| | | |
| | | |
| | | |
| | | watch( |
| | | () => pageData.value.ktvList, |
| | |
| | | |
| | | /** 结束透析 */ |
| | | const onEndClick = () => { |
| | | ElMessage({ |
| | | message: "功能开发中,敬请期待!", |
| | | type: "warning", |
| | | }); |
| | | if ( |
| | | !bedsideAuxiliaryScreenStore.deviceCode || |
| | | !bedsideAuxiliaryScreenStore.deviceData.deviceCode |
| | | ) |
| | | return ElMessage.warning("未初始化或正在进行初始化操作中"); |
| | | if (!bedsideAuxiliaryScreenStore.userInfo?.token) |
| | | return ElMessage.warning("请登录"); |
| | | endDialysisRef.value?.openDialog(); |
| | | }; |
| | | |
| | | onMounted(() => { |