| src/api/ecg/room/index.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/config/axios/service.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/hooks/web/useIdleLogout.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/permission.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/utils/releaseBed.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/utils/seatGuard.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/ecg/checktype/QueueSequenceForm.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/ecg/doctor/DevInstall.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/ecg/doctor/Routine.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/ecg/doctor/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/ecg/room/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/ecg/room/index.ts
@@ -167,6 +167,16 @@ return await request.get({ url: `/clinic/room/close-biz` }) }, /** * 管çåå¼ºå¶æ¸ 空工ä½ï¼å»çä¸çå¿ç¦»åº§ / æ¢äººä½¿ç¨åä¸å·¥ä½ï¼ã * * ä¸å»çèªå·±çã离座ãä¸åï¼è¿éå¯ä»¥æ¸ **ä»»ä½äºº**å ç¨çå·¥ä½ã * å端åªå¨è¯¥å·¥ä½å¤äºãå»çå¨å² / æåãä¸å·²è¢«å ç¨æ¶æçæï¼ç©ºé²å·¥ä½ä¼æ¥"ç¶æä¸å 许"ã */ forceClearBed: async (params: { roomId: number | null; bedNo: string | null }) => { return await request.post({ url: `/clinic/room/force-clear-bed`, params }) }, /** ã鿩工使¨¡å¼ãææ¬æºIPå¹é å·¥ä½ï¼æ¨¡å¼ 1/3ï¼ï¼è¿åå端è¯å«å°çIP + åéå·¥ä½ï¼å·²æåºï¼ */ getIpBed: async () => { return await request.get({ url: `/clinic/room/get-ip-bed` }) src/config/axios/service.ts
@@ -14,7 +14,6 @@ import { resetRouter } from '@/router' import { deleteUserCache } from '@/hooks/web/useCache' import { releaseBedOnExit } from '@/utils/releaseBed' const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE const { result_code, base_url, request_timeout } = config @@ -24,6 +23,17 @@ 'æ æçå·æ°ä»¤ç', // å·æ°ä»¤ç被å 餿¶ï¼ä¸ç¨æç¤º 'å·æ°ä»¤çå·²è¿æ' // 使ç¨å·æ°ä»¤çï¼å·æ°è·åæ°ç访é®ä»¤çæ¶ï¼ç»æå ä¸ºè¿æå¤±è´¥ï¼æ¤æ¶éè¦å¿½ç¥ãå¦åï¼ä¼å¯¼è´ç»§ç» 401ï¼æ æ³è·³è½¬å°ç»åºçé¢ ] /** * ãæ¬éæ±ã"å·¥ä½å¤±æ"ç±»ä¸å¡ç ï¼**ä¸å¨è¿éå¼¹å ¨å±æç¤º**ã * * å·¥ä½å°æ¯ 5 ç§è½®è¯¢ä¸æ¬¡ï¼è¥è¿éæ¯æ¬¡é½ `ElNotification.error`ï¼ç°åºå°±ä¼çå° * ãè¯·éæ°å°±åº§ãä¸ç´å¨è·³ãæ¹ç±å·¥ä½å°é¡µé¢ç¨ {@link utils/seatGuard} 䏿¬¡æ§æç¤ºï¼ * å¹¶åæèªå·±ç轮询ã * * 1_010_002_001 = è¯·éæ°å°±åº§ï¼ROOM_NOT_SITï¼ */ const SILENT_BIZ_CODES: number[] = [1010002001] // æ¯å¦æ¾ç¤ºéæ°ç»å½ export const isRelogin = { show: false } // Axios æ æç¥å·æ°ä»¤çï¼åè https://www.dashingdog.cn/article/11 ä¸ https://segmentfault.com/a/1190000020210980 å®ç° @@ -177,9 +187,16 @@ console.log(msg) return handleAuthorized() } else { ElNotification.error({ title: msg }) // ãæ¬éæ±ãå·¥ä½å¤±æç±»ä¸å¡ç ä¸å¼¹å ¨å±æç¤ºï¼ç±å·¥ä½å°ä¸æ¬¡æ§æç¤º + å轮询ï¼ï¼é¿å æ¯ 5 ç§å·å± if (SILENT_BIZ_CODES.indexOf(Number(code)) === -1) { ElNotification.error({ title: msg }) } } return Promise.reject('error') // ãæ¬éæ±ãæä¸å¡ç 带è¿å¼å¸¸å¯¹è±¡ï¼é¡µé¢å¯æ®æ¤è¯å«ã已䏿¯è¯¥å·¥ä½ä¸»äººãå¹¶åæ¢è½®è¯¢ã // ä»ç¨ Error å®ä¾ï¼ä¿è¯æ¢æç e?.message ç¨æ³ä¸åå½±åã const bizErr: any = new Error(msg) bizErr.code = Number(code) return Promise.reject(bizErr) } else { return data } @@ -207,13 +224,16 @@ const handleAuthorized = () => { const { t } = useI18n() // ãéæ¾è¯çåºä½ãé´æå¤±è´¥ â æ¬è½®ç»å½å³å°ç»æï¼å¿ é¡»å éæ¾å»çå ç¨çåºä½ï¼ // å¦å该åºä½ä¼ä¸ç´æ¾ç¤ºè¢«å ç¨ï¼`clinic_room.doc_id` ä¸ä¸ºç©ºï¼ï¼å«çå»çéä¸å°ã // ãæ¬æ¬¡åæ´ãé´æå¤±è´¥**ä¸åéæ¾**è¯å®¤å·¥ä½ï¼`clinic_room.doc_id`ï¼ã // // â ï¸ é¡ºåºè¦æ±ï¼releaseBedOnExit å é¨è¦è¯» localStorage éç访é®ä»¤çæ¥å¸¦ // Authorization å¤´ï¼æä»¥**å¿ é¡»å¨ removeToken() ä¹å**è°ç¨ï¼ä¸ awaitï¼ // 以å é»å¡ä¸é¢çæ¸ çä¸è·³è½¬ï¼å¤±è´¥ä¹ä¸å½±åæµç¨ï¼ã void releaseBedOnExit('auth-failed') // åå®ç°ï¼401 / å·æ°ä»¤ç失败æ¶ä¼è° `releaseBedOnExit('auth-failed')`ï¼ // æå»çå ç¨ç工使¸ 空ãä½è¿ä¼æ"令çå°æ"è¯¯å½æ"å»ç离å¼"ï¼ // å»çåªæ¯ç¦»å¼çµèè¶ è¿ token æææï¼æç½ç»æå¨å¯¼è´å·æ°å¤±è´¥ï¼ï¼ // åæ¥å°±è¢«è¿«éæ°å ¥åº§ï¼å·¥ä½å°è¿ä¼æç¤º"è¯·éæ°å°±å"ã // // ç°å¨çå£å¾ï¼å·¥ä½éæ¾åªåçå¨**ç¨æ·ä¸»å¨æä½**ï¼æå¨ã离座ã/ãæå¨éåºç»å½ãï¼ï¼ // 令ç失æåªæ¸ æ¬å°åè¯å¹¶è·³ç»å½é¡µï¼éæ°ç»å½åå·¥ä½ä»å¨ï¼å¯ç´æ¥ç»§ç»ä½¿ç¨ã // å»çççä¸çå¿ç¦»åº§çå åºï¼éè¯ç»ä¸æ¸ 空 + è¯å®¤ç®¡çé¡µãæ¸ 空工ä½ãã // ãä¿®å¤ãé´æå¤±è´¥æ¶**ç«å³**æ¸ çæ¬å°åè¯ä¸ç¨æ·ç¼åï¼ä¸åçç¨æ·ç¹å»å¼¹çªã // src/hooks/web/useIdleLogout.ts
@@ -1,7 +1,6 @@ import { watch } from 'vue' import { useIdle } from '@vueuse/core' import { ElMessage } from 'element-plus' import { releaseBedOnExit } from '@/utils/releaseBed' /** * 空é²è¶ æ¶èªå¨éåºï¼éæ±ï¼30 åéä¸æä½æè¦æ±éæ°è¾å ¥å¯ç ï¼ã @@ -18,6 +17,7 @@ * · æä»»ä½é¼ æ /é®ç/触æ¸/æ»å¨æä½ â 计æ¶å¨éç½®ï¼ * · è¿ç» 30 åé**æ 任使ä½** â 䏻卿¸ çç»å½æå¹¶è·³è½¬ç»å½é¡µï¼è¦æ±éæ°è¾å¯ç ï¼ï¼ * · ææä½æ¶ä¸ä¸»å¨ç»åºï¼token èªèº«çç»æç± axios æ¦æªå¨ç refresh-token è´è´£ï¼ã * · ãæ¬æ¬¡ã空é²ç»åº**ä¸åéæ¾è¯å®¤å·¥ä½**ï¼å·¥ä½ä¿çï¼éæ°ç»å½å³å¯ç»§ç»ä½¿ç¨ï¼ã * * ç¨æ³ï¼å¨ permission.ts ä¸è°ç¨ä¸æ¬¡å³å¯ï¼å é¨èªå¸¦å¹çä¿æ¤ï¼ï¼ * setupIdleLogout() @@ -99,26 +99,28 @@ } /** * å®é æ§è¡ç©ºé²ç»åºï¼éæ¾åºä½ + æ¸ çæ¬å°åè¯å¹¶è·³è½¬ç»å½é¡µã * å®é æ§è¡ç©ºé²ç»åºï¼**åªæ¸ æ¬å°åè¯å¹¶è·³è½¬ç»å½é¡µï¼ä¸éæ¾å·¥ä½**ã * * 乿以ä¸è°ç¨ userStore.loginOut()ï¼é£æ¯"主å¨éåº"ï¼ï¼ * · é£ä¸ªæ¥å£ä¼è¯·æ±å端注é token â 对æ¬åºæ¯æ²¡å¿ è¦ï¼ä¸å¯è½å ç½ç»é®é¢å¡ä½ï¼ * · 空é²ç»åºåªéä¿è¯æ¬å°åè¯æ¸ å¹²å + åå°ç»å½é¡µã * * â ï¸ ä½**å¿ é¡»**åç¬è°ä¸æ¬¡ãéæ¾åºä½ãï¼ * å»çå¨ãè¯å®¤éæ©ã页é好åºä½åå°±å ç¨äºè¯¥åºä½ï¼`clinic_room.doc_id`ï¼ã * åå æ¬å½æ°åªæ¸ æ¬å°åè¯ãä¸éç¥å端 â 空é²è¶ æ¶ååºä½**ä¸ç´æ¾ç¤ºè¢«å ç¨**ï¼ * å ¶ä»å»çéä¸å°è¿ä¸ªåºä½ãè¿æ£æ¯"å»çå¿äºç¦»åº§å°±éåºç³»ç»"ç主è¦åºæ¯ã * ãéè¦åæ´ï¼æ¬æ¬¡ï¼ã空é²è¶ æ¶**ä¸åéæ¾è¯å®¤å·¥ä½**ã * --------------------------------------------------------------- * åå æ¬å½æ°ä¼å è° `releaseBedOnExit('idle-timeout')`ï¼æ `clinic_room.doc_id` æ¸ ç©ºã * 宿µé®é¢ï¼å»ç离å¼çµè 30 åé以ä¸ï¼ä¾å¦å»åæ£æ¥ãç¦»å¼ 1 å°æ¶åæ¥ï¼ï¼ * 忥æ¶å·¥ä½å·²ç»è¢«éæ¾ â å·¥ä½å°åªè½åªè¯»ãå¹¶æç¤º"è¯·éæ°å°±å"ï¼ * èå»çæ¬äººå¹¶æ²¡æç¦»åº§ãè¿ä¸ç¬¦åå®é 使ç¨åºæ¯ã * * ç°å¨çå£å¾ï¼ * · 空é²è¶ æ¶ â **åªè¦æ±éæ°è¾å ¥å¯ç **ï¼token æ¸ æãåç»å½é¡µï¼ï¼**å·¥ä½ä¿ç**ï¼ * · éæ°ç»å½å `roomStore.fetchMySeat()` ä¼èªå¨æ¢å¤ãæçå·¥ä½ãï¼å¯ç´æ¥ç»§ç»ä½¿ç¨ï¼ * · å·¥ä½çéæ¾åªåçå¨**ç¨æ·ä¸»å¨æä½**ï¼æå¨ã离座ããæå¨ãéåºç»å½ãã * · å»çççä¸çå¿ç¦»åº§çå åºï¼â éè¯æ¶ç³»ç»ç»ä¸æ¸ 空å½çå·¥ä½ï¼â¡ 管çåå¯å¨ * è¯å®¤ç®¡çé¡µãæ¸ 空工ä½ãã */ async function doIdleLogout(): Promise<void> { ElMessage.warning(`å·²è¶ è¿ ${IDLE_TIMEOUT_MINUTES} åéæªæä½ï¼è¯·éæ°ç»å½`) // å éæ¾åºä½ï¼åæ¸ åè¯ ââ 顺åºä¸è½åï¼éæ¾æ¥å£éè¦æºå¸¦å½å令ç try { await releaseBedOnExit('idle-timeout') } catch { /* releaseBedOnExit å é¨å·²å åºï¼ä¸ä¼æéï¼æ¤å¤ä» 为é²å¾¡æ§åæ³ */ } cleanupCredentials() src/permission.ts
@@ -13,7 +13,6 @@ import { useRoomStoreWithOut } from "@/store/modules/room"; // éæ±ï¼30 åéæ æä½æè¦æ±éæ°ç»å½ï¼åç«¯ç©ºé²æ£æµï¼ import { setupIdleLogout } from '@/hooks/web/useIdleLogout' import { setupBedReleaseOnUnload } from '@/utils/releaseBed' const { start, done } = useNProgress() @@ -222,10 +221,12 @@ // ========================================================================== if (getAccessToken() && to.path !== '/login') { setupIdleLogout() // éæ±ï¼éåºç³»ç»æ¶èªå¨éåºå ç¨çè¯çåºä½ã // 注å `pagehide` å åºï¼å ³éæ ç¾é¡µ/å·æ°/跳走ï¼ââ å é¨èªå¸¦å¹çä¿æ¤ï¼ // åªæ¯"å°½åè为"çæåä¸å±ï¼ä¸»è¦ä¿éå¨ useIdleLogout / userStore.loginOut / // axios ç handleAuthorized ä¸å¤æç¡®çéåºè·¯å¾ä¸ã setupBedReleaseOnUnload() // ãæ¬æ¬¡åæ´ã**已移é¤** `setupBedReleaseOnUnload()`ï¼pagehide + sendBeaconï¼ã // // åè¡ä¸ºï¼å ³éæ ç¾é¡µ / å·æ° / 跳走æ¶é½ä¼éæ¾å ç¨çå·¥ä½ï¼å¯¼è´ // · æ F5 å·æ°ä¸æ¬¡å°±ä¸¢å·¥ä½ï¼ // · æµè§å¨å´©æºæ¢å¤ãåèµ°ä¸ä¼å¿åæ¥ï¼ä¹å¯è½å pagehide 丢工ä½ã // ç°å¨å·¥ä½åªå¨**ç¨æ·ä¸»å¨æä½**æ¶éæ¾ï¼æå¨ã离座ããæå¨ãéåºç»å½ãã // å»çä¸çå¿ç¦»åº§çå åºï¼â éè¯æ¶ç»ä¸æ¸ 空å½çå·¥ä½ï¼â¡ 管çåãæ¸ 空工ä½ãã } }) src/utils/releaseBed.ts
@@ -2,7 +2,7 @@ import { getAccessToken } from '@/utils/auth' /** * éåºç³»ç»æ¶èªå¨éæ¾è¯å®¤å·¥ä½ï¼éæ±ï¼å»ç常å¿è®°ã离座ãå°±éåºç³»ç»ï¼ã * æå¨ãéåºç»å½ãæ¶éæ¾è¯å®¤å·¥ä½ã * * èæ¯ * ---- @@ -10,20 +10,23 @@ * ï¼å端åå¨ `clinic_room.doc_id` / `status`ï¼ã * è¥å»çä¸ç¹ã离座ãèç´æ¥éåºç³»ç»ï¼åºä½ä¼ä¸ç´æ¾ç¤ºè¢«å ç¨ï¼å ¶ä»å»çæ æ³ä½¿ç¨ã * * è¦ççéåºè·¯å¾ * -------------- * 1. æå¨ç¹ãéåºç»å½ã â å端 `/system/auth/logout` å·²ä¼ç¦»åº§ï¼AuthControllerï¼ï¼ * æ¬å½æ°å¨å ¶ä¹ååå 䏿¬¡ï¼ä¿è¯å³ä½¿ logout 请æ±å¤±è´¥ä¹å·²éæ¾ï¼ * 2. **ç©ºé² 30 åéèªå¨ç»åº**ï¼`useIdleLogout`ï¼â åå åªæ¸ æ¬å°åè¯ãä¸è°å端 â åºä½ä¸éæ¾ï¼ * è¿æ¯æ¬æ¬¡ä¿®å¤çæ ¸å¿åºæ¯ï¼ * 3. **令ç失æ/å·æ°å¤±è´¥è¢«å¼ºå¶ç»åº**ï¼`config/axios/service.ts` ç `handleAuthorized`ï¼ï¼ * 4. å ³é/å·æ°é¡µé¢åç `pagehide` å åºã * ãéè¦åæ´ï¼æ¬æ¬¡ï¼ãåªä¿çãæå¨éåºç»å½ãè¿ä¸æ¡è·¯å¾ * --------------------------------------------------------------- * åå è¦ç 4 æ¡è·¯å¾ï¼æå¨éåºãç©ºé² 30 åéèªå¨ç»åºã令ç失æ(401)ã`pagehide`ï¼å·æ°/å ³é¡µï¼ã * 宿µé®é¢ï¼å䏿¡ä¼æã令çå°æ / å·æ°é¡µé¢ / 离å¼ä¸ä¼å¿ãè¯¯å½æãå»ç离座ãï¼ * 导è´å·¥ä½è¢«æ¸ 空 ââ å»ç忥çå°å·¥ä½å°åªå©åªè¯»ãå¹¶æç¤º"è¯·éæ°å°±å"ï¼èå·¥ä½å·²å空é²ã * * ç°å¨çå£å¾ï¼ * · **åªææå¨ãéåºç»å½ã**ï¼ä»¥åè¯å®¤éæ©é¡µçæå¨ã离座ãï¼æéæ¾å·¥ä½ï¼ * · 空é²è¶ æ¶ï¼`useIdleLogout`ï¼åªè¦æ±éæ°è¾å¯ç ï¼å·¥ä½ä¿çï¼ * · 401 / å·æ°ä»¤çå¤±è´¥åªæ¸ æ¬å°åè¯ï¼å·¥ä½ä¿çï¼ * · ä¸å注å `pagehide` å åºï¼å·æ°é¡µé¢ä¸åºè¯¥ä¸¢å·¥ä½ï¼ï¼ * · å»çççä¸çå¿ç¦»åº§çå åºï¼â éè¯æ¶ç³»ç»ç»ä¸æ¸ 空å½çå·¥ä½ï¼â¡ 管çåãæ¸ 空工ä½ãã * * 为ä»ä¹ç¨**裸 axios** è䏿¯é¡¹ç®ç request * ---------------------------------------- * 项ç®ç `request` æäº 401 æ¦æªå¨ï¼èæ¬å½æ°**æ°æ°æ¯å¨ 401 ä¹å**被è°ç¨çã * è¥èµ°æ¦æªå¨ï¼ä¼å次触å"å·æ°ä»¤ç失败 â 强å¶ç»åº â åè°æ¬å½æ°"çéå½ã * 裸 axios 䏿任使¦æªå¨ï¼å¤©ç¶æå¼è¿æ¡é¾ã * æ¬å½æ°å¯è½å¨é´æç¶æä¸ç¨³æ¶è¢«è°ç¨ï¼è¥èµ°é¡¹ç® request ç 401 æ¦æªå¨ï¼ * ä¼å次触å"å·æ°ä»¤ç失败 â 强å¶ç»åº"çéå½ã裸 axios 䏿任使¦æªå¨ï¼å¤©ç¶æå¼è¿æ¡é¾ã * * 为ä»ä¹ç¨**æå¡ç«¯æ userId 忥**è䏿¯åç«¯ä¼ åºä½å· * ------------------------------------------------ @@ -31,9 +34,7 @@ * å°±ä¼"鿾䏿"ãæ å端æä¾æ åæ¥å£ `/ecg/doctor/release-my-beds`ï¼æå½åç»å½ç¨æ· * åæ¥å ¶å ç¨çå ¨é¨åºä½ãå端åªé带ä¸ä»¤çã * * â ï¸ æ¬æä»¶**ä¸è¦ import `@/config/axios/config`**ï¼ * `config/axios/service.ts` éè¦ import æ¬æä»¶ï¼å¨ 401 å¤çééæ¾åºä½ï¼ï¼ * è¥æ¬æä»¶åå import å®ç configï¼ä¼å½¢æå¾ªç¯ä¾èµã * â ï¸ æ¬æä»¶**ä¸è¦ import `@/config/axios/config`**ï¼é¿å ä¸ service.ts å½¢æå¾ªç¯ä¾èµã * è¿éç´æ¥ç¨åä¸ä¸ªç¯å¢åéæ¼æ¥ï¼ææç价䏿 ç¯ã * * 失败å¤çï¼æ¬å½æ°**æ°¸ä¸æå¼å¸¸**ï¼éåºæµç¨ä¸åºå å®è䏿ï¼ã @@ -68,39 +69,4 @@ } finally { releasing = false } } /** * 注å `pagehide` å åºï¼å ³éæ ç¾é¡µ/å·æ°/跳走æ¶å°è¯éæ¾åºä½ã * * ç¨ `sendBeacon` èé ajax ââ 页é¢å¸è½½æ¶æ®é请æ±ä¼è¢«æµè§å¨åæ¶ï¼beacon ä¸ä¼ã * ä½ beacon **æ æ³èªå®ä¹è¯·æ±å¤´**ï¼ä¸è½å¸¦ Authorizationï¼ï¼æ æ¹ç¨ URL ä¼ ä»¤çï¼ * å端 `SecurityProperties.tokenParameter` é»è®¤å°±æ¯ `"token"`ï¼ * ä¸ `TokenAuthenticationFilter` ä¼è¯»åå®ï¼è§ `obtainAuthorization`ï¼ã * * 注æï¼æ¬é¡¹æ¯**å°½åè为**çå åºï¼ä¸ä½ä¸ºä¸»è¦ææ®µ ââ * ä¸»è¦ææ®µæ¯ä¸é¢ 1/2/3 䏿¡æç¡®è·¯å¾ã */ export function setupBedReleaseOnUnload(): void { if (typeof window === 'undefined') return // å¹çï¼é¿å HMR / éå¤è°ç¨å¯¼è´é夿³¨å if ((window as any).__bedReleaseUnloadBound) return ;(window as any).__bedReleaseUnloadBound = true window.addEventListener('pagehide', () => { const token = getAccessToken() if (!token) return try { const url = `${BASE_URL}/ecg/doctor/release-my-beds?token=${encodeURIComponent(token)}` const ok = navigator.sendBeacon?.(url) if (!ok) { // sendBeacon ä¸å¯ç¨/被æç»æ¶ï¼éå忥 XHR æå䏿 const xhr = new XMLHttpRequest() xhr.open('POST', url, false) // 忥ï¼ç¡®ä¿å¸è½½åååº xhr.send() } } catch { /* 忽ç¥ï¼å¸è½½é¶æ®µä¸åºæ¥é */ } }) } src/utils/seatGuard.ts
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,73 @@ import { ElMessageBox } from 'element-plus' /** * å·¥ä½å®å«ï¼ãè¯·éæ°å°±åº§ãç±»é误ç䏿¬¡æ§æç¤º + è½®è¯¢åæ¢è¾ å©ã * * èæ¯ * ---- * å·¥ä½å°ï¼å«å·æ£æ¥ / 设å¤é¢ç¨ / 设å¤è£ æºï¼æ¯ **5 ç§** è½®è¯¢ä¸æ¬¡ `bed-doctor-get`ã * å½å½åè´¦å·å·²ç»ä¸æ¯è¯¥å·¥ä½ç主人ï¼å·¥ä½è¢«éæ¾ / å¨å«ççµèå ¥åº§ / 被管ç忏 ç©ºï¼æ¶ï¼ * å端è¿åä¸å¡ç `1_010_002_001`ãè¯·éæ°å°±åº§ãï¼å端åå **æ¯è½®é½å¼¹ä¸æ¬¡**ï¼ * ç°åºçå°çå°±æ¯"ç³»ç»ä¸ç´è·³åºè¯·éæ°å°±åº§!"ã * * è¿éæä¾ä¸¤ä¸ªè½åï¼ * · åªæç¤ºä¸æ¬¡ï¼ä¸æ¬¡æ§å¼¹çªï¼å¸¦ãå»éå·¥ä½ãï¼ï¼ä¸åå·å±ï¼ * · 页颿®æ¤**åæè½®è¯¢å®æ¶å¨**ï¼çéæ°éå°å·¥ä½å忢å¤ã * * å¤å®ä¾æ®ï¼å端 {@code ErrorCodeConstants.ROOM_NOT_SIT = 1_010_002_001}ã */ /** ãè¯·éæ°å°±åº§ãä¸å¡ç ï¼å端 ROOM_NOT_SITï¼ */ export const SEAT_INVALID_CODE = 1010002001 /** æä¸ªè¯·æ±å¼å¸¸æ¯å¦å±äº"已䏿¯è¯¥å·¥ä½ä¸»äºº" */ export function isSeatInvalidError(e: any): boolean { if (!e) return false const code = Number(e.code ?? e.bizCode ?? NaN) if (Number.isFinite(code) && code === SEAT_INVALID_CODE) return true // å åºï¼ä¸ªå«é¾è·¯åªæ msg ä¼ ä¸æ¥ const msg = String(e.message ?? e.msg ?? e) return msg.indexOf('è¯·éæ°å°±åº§') !== -1 } let notified = false /** æ¯å¦å·²ç»æç¤ºè¿ï¼ä¾¿äºé¡µé¢å¤æï¼ */ export function isSeatInvalidNotified(): boolean { return notified } /** * å·¥ä½å¤±ææç¤ºï¼**æ´ä¸ªä¼è¯åªå¼¹ä¸æ¬¡**ï¼é¿å 5 ç§è½®è¯¢ææç¤ºå·æ"ä¸ç´è·³"ã * * ç¹ãå»éå·¥ä½ãâ æ´é¡µè·³è½¬å°éå·¥ä½é¡µï¼ç¨ location èé router.pushï¼ * éå·¥ä½é¡µæ¯é¡¶å±è·¯ç±ï¼æ´é¡µè·³è½¬è½é¡ºå¸¦éç½®åå·¥ä½å°ç宿¶å¨ä¸æ¬å°ç¶æï¼ã */ export function notifySeatInvalidOnce(): void { if (notified) return notified = true ElMessageBox.confirm( 'å½åè´¦å·å·²ä¸æ¯è¿ä¸ªå·¥ä½ç主人ï¼å¯è½å·¥ä½å·²è¢«éæ¾ãå¨å ¶å®çµèä¸å ¥åº§ï¼æè¢«ç®¡ç忏 空ï¼ã\n' + 'è¯·éæ°éæ©å·¥ä½ååæä½ã', 'è¯·éæ°å°±åº§', { confirmButtonText: 'å»éå·¥ä½', cancelButtonText: 'ç¨å', type: 'warning', closeOnClickModal: false } ) .then(() => { window.location.href = '/roomselect' }) .catch(() => { /* ç¨æ·éæ©ãç¨åãï¼ä¿æé¡µé¢åªè¯»ï¼ä¸åéå¤å¼¹ */ }) } /** * éæ°è·å¾å·¥ä½ï¼éæ°å ¥åº§ / åæ¢å·¥ä½ / èªå¨æ¢å¤ï¼åå¤ä½ï¼å è®¸ä¸æ¬¡åæç¤ºä¸æ¬¡ã */ export function resetSeatInvalidNotify(): void { notified = false } src/views/ecg/checktype/QueueSequenceForm.vue
@@ -7,7 +7,7 @@ èæ¯ï¼è¯¥è¡¨åå æ¯å¤©èªå¨çæï¼ç°å·²æ¹ä¸ºæå·¥ç»´æ¤ï¼æ¤å没æç»´æ¤çé¢ã --> <Dialog :title="dialogTitle" v-model="dialogVisible" width="1000px"> <Dialog :title="dialogTitle" v-model="dialogVisible" width="65%" > <!-- é¡¶é¨è¯´æï¼è¿äºå段çå«ä¹ä¸"æ¯æ¥éç½®"çå ³ç³» --> <el-alert type="info" :closable="false" class="mb-10px"> <template #title> @@ -19,7 +19,8 @@ <div class="text-12px leading-5"> · <b>èµ·å§åºå·</b>ï¼æ¯å¤©èªå¨éç½®æ¶åå°è¯¥å¼ï¼<b>ä¸é</b>ï¼å°è¾¾åè¯¥æ¶æ®µè§ä¸ºã已满ãï¼æ£è ç¾å°ä¼é¡ºå»¶å°åç»æ¶æ®µã<br /> · <b>å½ååºå·</b>ï¼å·²åå°å å·ï¼ä¸è¬æ éæå·¥æ¹ï¼æ¯æ¥éç½®ä¼èªå¨åå°"èµ·å§åºå·"ï¼ã<br /> · <b>åºå·ä¸éå¿ é¡»å¤§äºèµ·å§åºå·</b>ï¼å¦åè¯¥æ¶æ®µæ°¸è¿æ æ³åå·ã<br /> · <b>é¢å®é¢åº¦</b> = ä¸é â èµ·å§åºå·ï¼åªè¯»ï¼ã<b>ä¸é = èµ·å§åºå· è¡¨ç¤ºè¯¥æ¶æ®µæ²¡æåé¢</b>ï¼å 许ä¿åï¼é¢å®é¢åº¦æ¾ç¤º 0 å¹¶æ 红ï¼ã<br /> · ä¸é <b>ä¸è½å°äº</b>èµ·å§åºå·ï¼å¦åè¯¥æ¶æ®µæ°¸è¿æ æ³åå·ã<br /> · å䏿£æ¥é¡¹ç®ä¸<b>å䏿¶æ®µåªè½æä¸æ¡è§å</b>ï¼é夿·»å ä¼è¢«æç»ã </div> </el-alert> @@ -36,107 +37,155 @@ </span> </div> <el-table v-loading="loading" :data="list" :stripe="true" border height="420px"> <el-table-column label="æ¶æ®µ" align="center" min-width="130px"> <el-table v-loading="loading" :data="list" :stripe="true" border class="qs-table" height="calc(100vh - 300px)" > <!-- ============ â æ¶æ®µ ============ --> <el-table-column label="æ¶æ®µ" align="center" width="96"> <template #default="scope"> <b>{{ formatTimeSlot(scope.row.timeSlot) }}</b> <div class="text-11px text-gray-400">{{ scope.row.timeSlot }}</div> <b class="text-12px" :title="String(scope.row.timeSlot ?? '')"> {{ formatTimeSlot(scope.row.timeSlot) }} </b> </template> </el-table-column> <el-table-column label="æ®é-èµ·å§åºå·" align="center" min-width="120px"> <template #default="scope"> <el-input-number v-model="scope.row.queueSet" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="æ®é-ä¸é" align="center" min-width="110px"> <template #default="scope"> <el-input-number v-model="scope.row.queueFull" :min="1" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="æ®é-å½ååºå·" align="center" min-width="115px"> <template #default="scope"> <el-input-number v-model="scope.row.queueNo" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> <!-- ============ â¡ æ£å¸¸é¢çº¦ ============ --> <el-table-column label="æ£å¸¸é¢çº¦" align="center"> <el-table-column label="èµ·å§åºå·" align="center" width="90"> <template #default="scope"> <el-input-number v-model="scope.row.queueSet" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="ä¸é" align="center" width="80"> <template #default="scope"> <el-input-number v-model="scope.row.queueFull" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="é¢å®é¢åº¦" align="center" width="90"> <template #default="scope"> <span class="qs-quota" :class="{ 'qs-quota--zero': quotaOf(scope.row.queueSet, scope.row.queueFull) <= 0 }" :title="`ä¸é ${scope.row.queueFull ?? 0} â èµ·å§ ${scope.row.queueSet ?? 0}`" > {{ quotaOf(scope.row.queueSet, scope.row.queueFull) }} </span> </template> </el-table-column> <el-table-column label="å½ååºå·" align="center" width="90"> <template #default="scope"> <el-input-number v-model="scope.row.queueNo" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="ç¶æ" align="center" width="90"> <template #default="scope"> <el-tag v-if="isFull(scope.row)" type="danger" size="small">已满</el-tag> <el-tag v-else type="success" size="small">å¯åå·</el-tag> </template> </el-table-column> </el-table-column> <el-table-column label="VIP-èµ·å§åºå·" align="center" min-width="115px"> <template #default="scope"> <el-input-number v-model="scope.row.queueVipSet" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="VIP-ä¸é" align="center" min-width="105px"> <template #default="scope"> <el-input-number v-model="scope.row.queueVipFull" :min="1" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="VIP-å½ååºå·" align="center" min-width="110px"> <template #default="scope"> <el-input-number v-model="scope.row.queueVipNo" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> <!-- ============ ⢠é¢ç ============ --> <el-table-column label="é¢ç" align="center"> <el-table-column label="èµ·å§åºå·" align="center" width="90"> <template #default="scope"> <el-input-number v-model="scope.row.queueVipSet" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="ä¸é" align="center" width="80"> <template #default="scope"> <el-input-number v-model="scope.row.queueVipFull" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="é¢å®é¢åº¦" align="center" width="90"> <template #default="scope"> <span class="qs-quota" :class="{ 'qs-quota--zero': quotaOf(scope.row.queueVipSet, scope.row.queueVipFull) <= 0 }" :title="`ä¸é ${scope.row.queueVipFull ?? 0} â èµ·å§ ${scope.row.queueVipSet ?? 0}`" > {{ quotaOf(scope.row.queueVipSet, scope.row.queueVipFull) }} </span> </template> </el-table-column> <el-table-column label="å½ååºå·" align="center" width="90"> <template #default="scope"> <el-input-number v-model="scope.row.queueVipNo" :min="0" :controls="false" size="small" style="width: 100%" @change="markChanged(scope.row)" /> </template> </el-table-column> <el-table-column label="ç¶æ" align="center" width="90"> <template #default="scope"> <el-tag v-if="isFullVip(scope.row)" type="danger" size="small">已满</el-tag> <el-tag v-else type="success" size="small">å¯åå·</el-tag> </template> </el-table-column> </el-table-column> <el-table-column label="ç¶æ" align="center" width="90px"> <template #default="scope"> <el-tag v-if="isFull(scope.row)" type="danger" size="small">已满</el-tag> <el-tag v-else type="success" size="small">å¯åå·</el-tag> </template> </el-table-column> <el-table-column label="æä½" align="center" width="160px" fixed="right"> <!-- ============ ⣠æä½ ============ --> <el-table-column label="æä½" align="center" width="160" fixed="right"> <template #default="scope"> <el-button link type="primary" :loading="savingId === scope.row.id" @click="handleRowSave(scope.row)" > ä¿å </el-button> <el-button link type="primary" @click="openForm('update', scope.row)">ç¼è¾</el-button> <el-button link type="danger" @click="handleDelete(scope.row)">å é¤</el-button> <el-button link type="primary" @click="openForm('update', scope.row)"> ç¼è¾ </el-button> <el-button link type="danger" @click="handleDelete(scope.row)"> å é¤ </el-button> </template> </el-table-column> </el-table> @@ -174,13 +223,15 @@ <el-input-number v-model="formData.queueSet" :min="0" class="w-full" /> </el-form-item> <el-form-item label="æ®é-ä¸é" prop="queueFull"> <el-input-number v-model="formData.queueFull" :min="1" class="w-full" /> <!-- ãæ¬æ¬¡éæ±ãä¸éå 许çäºèµ·å§åºå·ï¼=è¯¥æ¶æ®µæ åé¢ï¼ï¼æ min æ¹ä¸º 0 --> <el-input-number v-model="formData.queueFull" :min="0" class="w-full" /> </el-form-item> <el-form-item label="VIP-èµ·å§åºå·" prop="queueVipSet"> <el-input-number v-model="formData.queueVipSet" :min="0" class="w-full" /> </el-form-item> <el-form-item label="VIP-ä¸é" prop="queueVipFull"> <el-input-number v-model="formData.queueVipFull" :min="1" class="w-full" /> <!-- ãæ¬æ¬¡éæ±ãåæ®éä¸éï¼å 许çäºèµ·å§åºå· --> <el-input-number v-model="formData.queueVipFull" :min="0" class="w-full" /> </el-form-item> <el-form-item label="æ®é-å½ååºå·"> <el-input-number v-model="formData.queueNo" :min="0" class="w-full" /> @@ -256,8 +307,23 @@ { validator: (_rule: any, value: any, callback: any) => { const set = formData.value.queueSet if (value !== undefined && value !== null && set !== undefined && set !== null && value <= set) { callback(new Error('ä¸éå¿ é¡»å¤§äºèµ·å§åºå·ï¼å¦åè¯¥æ¶æ®µæ æ³åå·')) // ãæ¬æ¬¡éæ±ãä¸é = èµ·å§åºå· æ¯**åæ³**çï¼è¡¨ç¤ºè¯¥æ¶æ®µæ²¡æåé¢ï¼é¢å®é¢åº¦ 0ï¼ï¼å 许ä¿åã // åªæãä¸é < èµ·å§åºå·ãææ¯é ç½®é误ï¼è¯¥æ¶æ®µæ°¸è¿æ æ³åå·ï¼ã if (value !== undefined && value !== null && set !== undefined && set !== null && value < set) { callback(new Error('ä¸éä¸è½å°äºèµ·å§åºå·ï¼çäºè¡¨ç¤ºè¯¥æ¶æ®µæ²¡æåé¢ï¼')) } else { callback() } }, trigger: 'blur' } ], queueVipFull: [ { validator: (_rule: any, value: any, callback: any) => { const set = formData.value.queueVipSet if (value !== undefined && value !== null && set !== undefined && set !== null && value < set) { callback(new Error('é¢çä¸éä¸è½å°äºé¢çèµ·å§åºå·ï¼çäºè¡¨ç¤ºé¢ç没æåé¢ï¼')) } else { callback() } @@ -306,15 +372,47 @@ } } /** è¯¥æ¶æ®µæ¯å¦å·²æ»¡ï¼å½ååºå· >= ä¸éï¼ */ const isFull = (row: QueueSequenceVO) => (row.queueNo ?? 0) >= (row.queueFull ?? 0) && (row.queueFull ?? 0) > 0 /** * é¢å®é¢åº¦ = ä¸é â èµ·å§åºå·ï¼å°äº 0 æ 0 æ¾ç¤ºï¼ã * * ãæ¬æ¬¡éæ±ã该ååªè¯»ï¼å¼ä¸º 0 æ¶åå æ ¼æµ çº¢åº ââ 表示è¿ä¸ªæ¶æ®µ**没æåé¢**ã * ãä¸é = èµ·å§åºå·ãæ¯åæ³é ç½®ï¼æ å颿¶æ®µï¼ï¼ä¸åå½ä½é误ã */ const quotaOf = (set?: number | null, full?: number | null) => Math.max(0, (full ?? 0) - (set ?? 0)) /** * è¯¥æ¶æ®µæ¯å¦å·²æ»¡ï¼æ£å¸¸é¢çº¦ï¼ã * * 满çä¸¤ç§æ å½¢ï¼ * â é¢å®é¢åº¦ <= 0ï¼ä¸é <= èµ·å§åºå·ï¼â æ¬æ¥å°±æ²¡æåé¢ï¼ * â¡ å½ååºå·å·²è¾¾å°ä¸éã */ const isFull = (row: QueueSequenceVO) => { if (quotaOf(row.queueSet, row.queueFull) <= 0) return true return (row.queueNo ?? 0) >= (row.queueFull ?? 0) } /** è¯¥æ¶æ®µæ¯å¦å·²æ»¡ï¼é¢çç»ï¼ï¼å£å¾åä¸ */ const isFullVip = (row: QueueSequenceVO) => { if (quotaOf(row.queueVipSet, row.queueVipFull) <= 0) return true return (row.queueVipNo ?? 0) >= (row.queueVipFull ?? 0) } /** è¡å ä¿åï¼åªæ¹æ°å¼ï¼ä¸å¨æ¶æ®µï¼ */ const handleRowSave = async (row: QueueSequenceVO) => { if (!row.id) return if ((row.queueFull ?? 0) <= (row.queueSet ?? 0)) { message.error(`æ¶æ®µ ${formatTimeSlot(row.timeSlot)}ï¼ä¸éå¿ é¡»å¤§äºèµ·å§åºå·`) // ãæ¬æ¬¡éæ±ãåªæãä¸é < èµ·å§åºå·ãææ¯é误ï¼ç¸çè¡¨ç¤ºè¯¥æ¶æ®µæ²¡æåé¢ï¼å 许ä¿åã if ((row.queueFull ?? 0) < (row.queueSet ?? 0)) { message.error( `æ¶æ®µ ${formatTimeSlot(row.timeSlot)}ï¼ä¸éä¸è½å°äºèµ·å§åºå·ï¼çäºè¡¨ç¤ºè¯¥æ¶æ®µæ²¡æåé¢ï¼` ) return } if ((row.queueVipFull ?? 0) < (row.queueVipSet ?? 0)) { message.error( `æ¶æ®µ ${formatTimeSlot(row.timeSlot)}ï¼é¢çä¸éä¸è½å°äºé¢çèµ·å§åºå·ï¼çäºè¡¨ç¤ºé¢ç没æåé¢ï¼` ) return } savingId.value = row.id @@ -388,3 +486,35 @@ await getList() } </script> <style scoped lang="scss"> /* ãæ¬æ¬¡è°æ´ãåå·æ¢å¤ä¸ºç³»ç»é»è®¤ï¼**å è®¸æ¨ªåæ»å¨**ï¼ Â· ä¸åå缩åå·ä¸å è¾¹è· ââ è¡¨ä½æ¢å¤é»è®¤åå·ï¼14pxï¼ãè¾å ¥æ¡é»è®¤åå·ãç¶ææ ç¾ç¨ small é»è®¤æ ·å¼ï¼ · åå®½ç±æ¨¡æ¿åºå®ï¼æ¶æ®µ 96 + æ£å¸¸é¢çº¦ 5 å + é¢ç 5 å + æä½ 160ï¼ï¼ æ»å®½è¶ è¿å¼¹çªå®½åº¦æ¶è¡¨æ ¼åºç°**æ¨ªåæ»å¨æ¡**ï¼æä½å fixed="right" å§ç»å¯è§ï¼ · è¡¨æ ¼é«åº¦ calc(100vh - 300px)ï¼ç«å夿¾ç¤ºå è¡ï¼é¡µé¢æ¬èº«ä¸åºç°æ»å¨æ¡ã */ .qs-table { /* è¡å æ°åè¾å ¥å 满åå æ ¼ï¼ä¸ç¼©å°åå·ï¼åªæ§å¶å®½åº¦ï¼ */ :deep(.el-input-number) { width: 100%; } } /* é¢å®é¢åº¦ï¼åªè¯»ï¼ï¼å¼ä¸º 0 æ¶æµ 红åºï¼è¡¨ç¤ºè¯¥æ¶æ®µæ²¡æåé¢ */ .qs-quota { display: inline-block; padding: 1px 6px; border-radius: 3px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--el-text-color-primary); } .qs-quota--zero { color: var(--el-color-danger); background-color: var(--el-color-danger-light-9); box-shadow: inset 0 0 0 1px var(--el-color-danger-light-5); } </style> src/views/ecg/doctor/DevInstall.vue
@@ -9,8 +9,9 @@ import QueuePanel from "@/views/ecg/doctor/components/QueuePanel.vue"; import DoctorPageLayout from "@/components/DoctorPageLayout/src/DoctorPageLayout.vue"; import {DoctorApi, PatientStatisticVO, RoomBedVO} from '@/api/ecg/doctor'; import { notifySeatInvalidOnce, isSeatInvalidError, resetSeatInvalidNotify } from '@/utils/seatGuard' import {QueueVO} from "@/api/ecg/queue"; import {ElMessage, ElMessageBox, ElNotification} from "element-plus"; import {ElMessage, ElMessageBox} from "element-plus"; import {useRoomStore} from "@/store/modules/room"; const roomStore = useRoomStore(); @@ -89,11 +90,9 @@ const initLoad = async () => { if (roomBedVO.value.roomId == null) { ElNotification.error({ message: 'è¯·éæ°å°±åº§!', type: 'info', duration: 3000 // èªå¨å ³éæ¶é´ï¼é»è®¤ä¸º3000ms }) // ãæ¬éæ±ãæ²¡æå·¥ä½ï¼åæè½®è¯¢å¹¶åªæç¤ºä¸æ¬¡ï¼åæ¥æ¯ 5 ç§å¼¹ä¸æ¬¡ï¼ç°åºè¡¨ç°å°±æ¯ä¸ç´è·³ï¼ timerRunFlag = false notifySeatInvalidOnce() return } @@ -102,7 +101,19 @@ fetchInfo.value = `æè¿åæ° ${new Date().toLocaleTimeString()} · è¿å ${patientList.value.length} æ¡` getInstallingPatient() patientStat.value = await DoctorApi.getDevInstallStatistic(roomBedVO.value) const queueVO2 = await DoctorApi.bedDoctorGet(roomBedVO.value) // ãæ¬éæ±ãbed-doctor-get æ¯ãææ¯å¦è¿åå¨è¿éãçå¤å®ï¼å¤±è´¥è¯´æå·¥ä½å·²è¢«éæ¾ / ä»äººæ¥æï¼ // æ¤æ¶åæè½®è¯¢å¹¶ä¸æ¬¡æ§æç¤ºï¼é¿å æ¯ 5 ç§å·ä¸æ¬¡ãè¯·éæ°å°±åº§ãã let queueVO2: any try { queueVO2 = await DoctorApi.bedDoctorGet(roomBedVO.value) } catch (e: any) { if (isSeatInvalidError(e)) { timerRunFlag = false notifySeatInvalidOnce() return } throw e } // ãå åºãæ¥å£å¯è½è¿å nullï¼åæ¥ç´æ¥å .status 伿å¼å¸¸ã䏿æ¬è½®åç»æ¥éª¤ if (queueVO2 && queueVO2.status === 20) state.value = true @@ -239,6 +250,8 @@ roomBedVO.value.bedNo = roomStore.room.bedNo roomBedVO.value.checkTypes = roomStore.room.checkTypes roomBedVO.value.opType = roomStore.room.opType // ãæ¬éæ±ãéæ°æ¿å°å·¥ä½ -> å¤ä½ãå·¥ä½å¤±æãæç¤ºï¼å è®¸ä¸æ¬¡åæç¤ºä¸æ¬¡ resetSeatInvalidNotify() // ãæ¬æ¬¡éæ±ãæ¢å·¥ä½å**æ´é¡µæ°æ®é½æ¢ææ°å·¥ä½ç**ï¼ // â å æ¸ 空左侧"æ£è ä¿¡æ¯"ï¼é¿å è¿æ¾ç¤ºä¸ä¸ä¸ªå·¥ä½çæ£è ï¼ devInstallPanelRef.value?.setPatient?.(undefined) @@ -266,6 +279,7 @@ roomBedVO.value.bedNo = roomStore.room!.bedNo roomBedVO.value.checkTypes = roomStore.room!.checkTypes roomBedVO.value.opType = roomStore.room!.opType resetSeatInvalidNotify() timerRunFlag = true doctorTimer() src/views/ecg/doctor/Routine.vue
@@ -9,8 +9,9 @@ import QueuePanel from '@/views/ecg/doctor/components/QueuePanel.vue' import DoctorPageLayout from '@/components/DoctorPageLayout/src/DoctorPageLayout.vue' import { DoctorApi, PatientStatisticVO, RoomBedVO, } from '@/api/ecg/doctor' import { notifySeatInvalidOnce, isSeatInvalidError, resetSeatInvalidNotify } from '@/utils/seatGuard' import { QueueVO } from '@/api/ecg/queue' import { ElMessage, ElMessageBox, ElNotification } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus' import RoutinePanel from '@/views/ecg/doctor/components/RoutinePanel.vue' import { useRoomStore } from '@/store/modules/room' @@ -303,11 +304,9 @@ const initLoad = async () => { if (roomBedVO.roomId == null) { ElNotification.error({ message: 'è¯·éæ°å°±åº§!', type: 'info', duration: 3000 // èªå¨å ³éæ¶é´ï¼é»è®¤ä¸º3000ms }) // ãæ¬éæ±ãæ²¡æå·¥ä½ï¼**åæè½®è¯¢**å¹¶åªæç¤ºä¸æ¬¡ï¼åæ¥æ¯ 5 ç§å¼¹ä¸æ¬¡ï¼ç°åºè¡¨ç°å°±æ¯"ä¸ç´è·³"ï¼ timerRunFlag = false notifySeatInvalidOnce() return } @@ -318,7 +317,19 @@ loadRoomWaitingList() getOnstagePatient() patientStat.value = await DoctorApi.getPatientStatistic(roomBedVO) const queueVO2 = await DoctorApi.bedDoctorGet(roomBedVO) // ãæ¬éæ±ãbed-doctor-get æ¯"ææ¯å¦è¿åå¨è¿é"çå¤å®ï¼å¤±è´¥è¯´æå·¥ä½å·²è¢«éæ¾ / ä»äººæ¥æï¼ // æ¤æ¶åæè½®è¯¢å¹¶ä¸æ¬¡æ§æç¤ºï¼é¿å æ¯ 5 ç§å·ä¸æ¬¡"è¯·éæ°å°±åº§"ã let queueVO2: any try { queueVO2 = await DoctorApi.bedDoctorGet(roomBedVO) } catch (e: any) { if (isSeatInvalidError(e)) { timerRunFlag = false notifySeatInvalidOnce() return } throw e } // ãå åºãæ¥å£å¯è½è¿å nullï¼åæ¥ç´æ¥å .status 伿å¼å¸¸ã䏿æ¬è½®åç»æ¥éª¤ if (queueVO2 && queueVO2.status === 20) state.value = true else if (queueVO2 && queueVO2.status === 30) state.value = false @@ -366,6 +377,8 @@ roomBedVO.bedNo = roomStore.room.bedNo roomBedVO.checkTypes = roomStore.room.checkTypes roomBedVO.opType = roomStore.room.opType // ãæ¬éæ±ãéæ°æ¿å°å·¥ä½ -> å¤ä½ãå·¥ä½å¤±æãæç¤ºï¼å è®¸ä¸æ¬¡åæç¤ºä¸æ¬¡ resetSeatInvalidNotify() // ãæ¬æ¬¡éæ±ãæ¢å·¥ä½å**æ´é¡µæ°æ®é½æ¢ææ°å·¥ä½ç**ï¼ // â å æ¸ 空左侧"æ£è ä¿¡æ¯"ï¼é¿å è¿æ¾ç¤ºä¸ä¸ä¸ªå·¥ä½çæ£è ï¼ routimePanelRef.value?.setPatient?.(undefined) @@ -394,6 +407,7 @@ roomBedVO.bedNo = roomStore.room!.bedNo roomBedVO.checkTypes = roomStore.room!.checkTypes roomBedVO.opType = roomStore.room!.opType resetSeatInvalidNotify() timerRunFlag = true doctorTimer() src/views/ecg/doctor/index.vue
@@ -10,8 +10,9 @@ import QueuePanel from "@/views/ecg/doctor/components/QueuePanel.vue"; import DoctorPageLayout from "@/components/DoctorPageLayout/src/DoctorPageLayout.vue"; import {DoctorApi, PatientStatisticVO, RoomBedVO} from '@/api/ecg/doctor'; import { notifySeatInvalidOnce, isSeatInvalidError, resetSeatInvalidNotify } from '@/utils/seatGuard' import {QueueVO} from "@/api/ecg/queue"; import {ElMessage, ElMessageBox, ElNotification} from "element-plus"; import {ElMessage, ElMessageBox} from "element-plus"; import DevReadyPanel from "@/views/ecg/doctor/components/DevReadyPanel.vue"; import {useRoomStore} from "@/store/modules/room"; @@ -243,11 +244,9 @@ const initLoad = async () => { if (roomBedVO.roomId == null) { ElNotification.error({ message: 'è¯·éæ°å°±åº§!', type: 'info', duration: 3000 // èªå¨å ³éæ¶é´ï¼é»è®¤ä¸º3000ms }) // ãæ¬éæ±ãæ²¡æå·¥ä½ï¼åæè½®è¯¢å¹¶åªæç¤ºä¸æ¬¡ï¼åæ¥æ¯ 5 ç§å¼¹ä¸æ¬¡ï¼ç°åºè¡¨ç°å°±æ¯ä¸ç´è·³ï¼ timerRunFlag = false notifySeatInvalidOnce() return } @@ -258,7 +257,19 @@ loadRoomWaitingList() getOnstagePatient() patientStat.value = await DoctorApi.getDevReadyStatistic(roomBedVO) const queueVO2 = await DoctorApi.bedDoctorGet(roomBedVO) // ãæ¬éæ±ãbed-doctor-get æ¯ãææ¯å¦è¿åå¨è¿éãçå¤å®ï¼å¤±è´¥è¯´æå·¥ä½å·²è¢«éæ¾ / ä»äººæ¥æï¼ // æ¤æ¶åæè½®è¯¢å¹¶ä¸æ¬¡æ§æç¤ºï¼é¿å æ¯ 5 ç§å·ä¸æ¬¡ãè¯·éæ°å°±åº§ãã let queueVO2: any try { queueVO2 = await DoctorApi.bedDoctorGet(roomBedVO) } catch (e: any) { if (isSeatInvalidError(e)) { timerRunFlag = false notifySeatInvalidOnce() return } throw e } // ãå åºãæ¥å£å¯è½è¿å nullï¼åæ¥ç´æ¥å .status 伿å¼å¸¸ã䏿æ¬è½®åç»æ¥éª¤ if (queueVO2 && queueVO2.status === 20) // å·¥ä½ç¶æ æå»ç state.value = true @@ -305,6 +316,8 @@ roomBedVO.bedNo = roomStore.room.bedNo roomBedVO.checkTypes = roomStore.room.checkTypes roomBedVO.opType = roomStore.room.opType // ãæ¬éæ±ãéæ°æ¿å°å·¥ä½ -> å¤ä½ãå·¥ä½å¤±æãæç¤ºï¼å è®¸ä¸æ¬¡åæç¤ºä¸æ¬¡ resetSeatInvalidNotify() // ãæ¬æ¬¡éæ±ãæ¢å·¥ä½å**æ´é¡µæ°æ®é½æ¢ææ°å·¥ä½ç**ï¼ // â å æ¸ 空左侧"æ£è ä¿¡æ¯"ï¼é¿å è¿æ¾ç¤ºä¸ä¸ä¸ªå·¥ä½çæ£è ï¼ devReadyPanelRef.value?.setPatient?.(undefined) @@ -333,6 +346,7 @@ roomBedVO.bedNo = roomStore.room!.bedNo roomBedVO.checkTypes = roomStore.room!.checkTypes roomBedVO.opType = roomStore.room!.opType resetSeatInvalidNotify() timerRunFlag = true doctorTimer() src/views/ecg/room/index.vue
@@ -104,6 +104,31 @@ > å é¤ </el-button> <!-- ãæ¬æ¬¡éæ±ã管çåå¼ºå¶æ¸ 空工ä½ï¼å»çä¸çå¿ç¦»åº§ / æ¢äººä½¿ç¨åä¸å·¥ä½æ¶ç¨ã · æéï¼`v-hasPermi` æ¯"ä»»ä¸å½ä¸å³æ¾ç¤º"ï¼è¿éåæ¶æ¥å `clinic:room:update`ï¼å端æ¥å£è¦æ±çï¼ ä¸ `ecg:room:update`ï¼æ¬é¡µå ¶å®æé®ç¨çé£å¥ï¼ï¼é¿å è§è²åªé äºå ¶ä¸ä¸å¥æ¶æé®è¢«éèã å端ä»ä¸¥æ ¼æ ¡éª `clinic:room:update`ã · åªæ"已被å ç¨"ï¼docId æå¼ï¼ç工使å¯ç¹ï¼ç©ºé²å·¥ä½ç½®ç°å¹¶æç¤ºï¼é¿å ç¹äºææ¥"ç¶æä¸å 许"ã --> <el-tooltip :disabled="!!scope.row.docId" content="该工ä½å½å空é²ï¼æ 鿏 空" placement="top" > <span style="margin-left: 12px"> <el-button link type="warning" :disabled="!scope.row.docId" @click="handleForceClearBed(scope.row)" v-hasPermi="['clinic:room:update', 'ecg:room:update']" > æ¸ ç©ºå·¥ä½ </el-button> </span> </el-tooltip> </template> </el-table-column> </el-table> @@ -207,8 +232,29 @@ } catch {} } /** å¯¼åºæé®æä½ */ const handleExport = async () => { /** * ãæ¬æ¬¡éæ±ã管çåå¼ºå¶æ¸ 空工ä½ã * * ç¨éï¼å»çä¸çå¿è®°ã离座ãâ å·¥ä½ä¸ç´è¢«å ç¨ï¼å«çå»çåä¸ä¸ï¼ * ææ¢äººä½¿ç¨åä¸å·¥ä½æ¶éè¦æä¸ä¸ä½æ¸ æã * * æå¡ç«¯åªå¨è¯¥å·¥ä½å¤äºãå»çå¨å² / æåãä¸å·²è¢«å ç¨æ¶æå è®¸æ¸ ç©ºï¼ * 空é²å·¥ä½ä¼è¿åãå½åå·¥ä½ç¶æä¸å 许该æä½ãââè¿æ¯é¢æè¡ä¸ºï¼æ éç¹æ®å¤çã */ const handleForceClearBed = async (row: RoomVO) => { const who = row.docName ? `ã${row.docName}ã` : 'å½åå»ç' try { await message.confirm( `ç¡®è®¤æ¸ ç©ºå·¥ä½ã${row.roomName ?? ''} · ${row.bedNo ?? ''}ãåï¼\n` + `该工ä½å½åç±${who}å ç¨ï¼æ¸ 空å对æ¹å°åæ"ä» å´è§"ï¼éè¦éæ°å ¥åº§æè½æä½ã` ) await RoomApi.forceClearBed({ roomId: row.roomId, bedNo: row.bedNo }) message.success('å·²æ¸ ç©ºè¯¥å·¥ä½') await getList() } catch {} } /** å¯¼åºæé®æä½ */const handleExport = async () => { try { // 导åºçäºæ¬¡ç¡®è®¤ await message.exportConfirm()