| | |
| | | import {defineComponent, PropType} from "vue"; |
| | | import { QueueVO } from '@/api/ecg/queue' |
| | | import {DICT_TYPE} from "@/utils/dict"; |
| | | import {PatientVO, DoctorApi, RoomBedVO} from "@/api/ecg/doctor"; |
| | | import {getCheckTypeName, getCheckTypeSeqPrefix} from "../../../../utils/checkTypeFormatter"; |
| | | import { PatientVO, DoctorApi, RoomBedVO } from "@/api/ecg/doctor"; |
| | | import { getCheckTypeName, getCheckTypeSeqPrefix } from "../../../../utils/checkTypeFormatter"; |
| | | import { useRoomStore } from '@/store/modules/room' |
| | | |
| | | defineComponent({ |
| | | name: 'QueuePanel' |
| | | }) |
| | | |
| | | const emit = defineEmits(['event_RecallFinish']) // 定义 success 事件,用于操作成功后的回调 |
| | | |
| | | const emit = defineEmits(['event_RecallFinish', 'event_PullWaiting', 'event_HurryUp']) // 定义 success 事件,用于操作成功后的回调 |
| | | const message = useMessage() // 消息弹窗 |
| | | |
| | | const props = defineProps({ |
| | |
| | | room: { |
| | | type: Object as PropType<RoomBedVO>, |
| | | required: true |
| | | }, |
| | | /** |
| | | * 【本诊室未分配】本工位检查类型下、**还没分配工位**的"排队中"患者。 |
| | | * 候诊列表看不到他们(列表按 room_id+bed_no 查),但大屏能看到 —— 医生可在此手工「拉入」。 |
| | | */ |
| | | waitingList: { |
| | | type: Array as PropType<QueueVO[]>, |
| | | default: () => [] |
| | | }, |
| | | /** |
| | | * 【自助诊断】"最近一次取数"的说明,例如 `最近取数 12:03:45 返回 0 条`。 |
| | | * 空列表时显示:时间不刷新=轮询没在跑;返回 0 条=后端确实没数据。 |
| | | */ |
| | | fetchInfo: { |
| | | type: String, |
| | | default: '' |
| | | } |
| | | }) |
| | | |
| | | /** 【主/围观】当前是否可操作:false 表示正在围观别人的工位(列表是别人的队列) */ |
| | | const roomStore = useRoomStore() |
| | | const canOperate = computed(() => roomStore.getCanOperate) |
| | | |
| | | /** 拉入排队中的患者(父页面负责调接口、刷新列表) */ |
| | | const pullWaiting = (item: any) => { |
| | | emit('event_PullWaiting', item) |
| | | } |
| | | |
| | | /** 立即补人(父页面负责调接口并把"结论"展示出来) */ |
| | | const hurryUp = () => { |
| | | emit('event_HurryUp') |
| | | } |
| | | |
| | | const recall = async (item) => { |
| | | const patientVO: PatientVO = { |
| | |
| | | } |
| | | |
| | | /** |
| | | * 需求:右侧患者列表要把「就诊中 / 已过号 / 候诊中」用不同颜色区分,方便医生识别。 |
| | | * 需求:右侧患者列表要把「就诊中 / 准备中(原候诊中) / 过号」用不同颜色区分,方便医生识别。 |
| | | * |
| | | * 颜色方案(左侧色条 + 浅色底 + 左侧竖线): |
| | | * · 就诊中(30) —— 蓝色(主色) :正在看的患者,最醒目 |
| | | * · 已过号(3/5) —— 红色 :需要关注(可能已错过叫号) |
| | | * · 候诊中(20/15) —— 绿色 :正常等待 |
| | | * · 其他 —— 灰色 :排队中/亲和/已领用/安装中等 |
| | | * 颜色方案(**只用文字颜色**,不再有整行背景色,也没有行首色条): |
| | | * · 就诊中(30) —— 蓝色(主色) + 姓名加粗 :正在看的患者,最醒目 |
| | | * · 过号(3/5) —— 红色 + 姓名加粗 :需要关注(可能已错过叫号) |
| | | * · 准备中(20/15) —— 绿色 :正常等待(20=准备中,原"候诊中") |
| | | * · 其他 —— 灰色 :排队中/亲和/已领用/安装中等 |
| | | * |
| | | * 之所以不只靠 dict-tag 的文字:医生扫一眼列表时要能**快速定位**当前就诊者与过号者, |
| | | * 颜色比文字更快。 |
| | | * 颜色比文字更快。改成"文字染色"是因为整行底色会让列表显得很花、也压掉了行与行的区分度。 |
| | | */ |
| | | const rowClass = (item: any): string => { |
| | | const st = Number(item?.status) |
| | | if (st === 30) return 'row-onstage' // 就诊中 |
| | | if (st === 3 || st === 5) return 'row-passed' // 已过号(含"已过号-排队") |
| | | if (st === 20 || st === 15) return 'row-ready' // 候诊中 / 已召回 |
| | | if (st === 20 || st === 15) return 'row-ready' // 准备中(原候诊中) / 已召回 |
| | | return 'row-other' |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <div class="queue-list"> |
| | | <!-- |
| | | 空列表提示(本次新增):把"这份列表属于哪个工位、我是什么身份"直接写出来。 |
| | | 现场出现过"患者列表是空的",光看空列表无法判断是排队真的没人、还是看错了工位 |
| | | (围观别人的工位 / 换了工位但患者还在原工位)。 |
| | | --> |
| | | <div v-if="!queue || queue.length === 0" class="queue-empty"> |
| | | <div class="queue-empty__title">暂无候诊患者</div> |
| | | <div class="queue-empty__meta"> |
| | | 当前列表:{{ room?.roomName || '—' }} · {{ room?.bedNo || '—' }} |
| | | <template v-if="!canOperate">(<b>围观模式 · 只读</b>,这是他人工位的队列)</template> |
| | | <template v-else>(我的工位)</template> |
| | | </div> |
| | | <!-- 自助诊断:一眼看出"轮询没跑"(时间不动)还是"后端返回 0 条" --> |
| | | <div v-if="fetchInfo" class="queue-empty__meta">{{ fetchInfo }}</div> |
| | | <!-- |
| | | 候诊区为空时的自救入口: |
| | | 系统**只有在【开诊】状态、且本工位没开【停止候诊】、且候诊人数未达上限**时才会自动补人; |
| | | 点这里立刻触发一次并直接告诉你被哪道门闸挡住了(后端返回"结论")。 |
| | | --> |
| | | <div class="queue-empty__meta"> |
| | | 系统只在【开诊】、本工位未开【停止候诊】、且候诊人数未达上限时才会自动补人; |
| | | <template v-if="canOperate"> |
| | | <el-button link type="primary" @click="hurryUp">立即补人(并查看原因)</el-button> |
| | | </template> |
| | | </div> |
| | | </div> |
| | | <div |
| | | v-for="(item, index) in queue" |
| | | :key="index" |
| | | class="queue-row" |
| | | :class="rowClass(item)" |
| | | > |
| | | <span class="col-seq"> {{item.seqNum}} </span> |
| | | <span class="col-bookseq"> {{getCheckTypeSeqPrefix(item.bookCheckType)}}{{item.bookSeqNum}} </span> |
| | | <!-- |
| | | 排队号(本需求):统一显示「检查项目前缀 + seq_num」,不再显示 bookSeqNum。 |
| | | 前缀来自 check_type.seq_prefix —— 号现在是**按检查项目各自编号**,不同检查项目之间 |
| | | 会出现相同数字,必须靠前缀区分(例:A12 / 12)。 |
| | | 加急(jump_flag=1)在号前面加红色「急」字,医生一眼可见。 |
| | | --> |
| | | <span class="col-seq"> |
| | | <span v-if="Number(item.jumpFlag) === 1" class="jump-badge">急</span> |
| | | {{ getCheckTypeSeqPrefix(item.bookCheckType) }}{{ item.seqNum }} |
| | | </span> |
| | | <span class="col-name"> {{item.patName}}{{item.passed === 0 ? "":"*"}} </span> |
| | | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="item.patGender" /> |
| | | {{getCheckTypeName(item.bookCheckType)}} |
| | | <dict-tag :type="DICT_TYPE.ECG_QUEUE_STATUS" :value="item.status" /> |
| | | <el-button v-if="item.status === 5 || item.status === 7" size="small" @click="recall(item)"> 召回 </el-button> |
| | | </div> |
| | | |
| | | <!-- |
| | | 【本诊室未分配】本工位检查类型下、还没分配工位的"排队中"患者。 |
| | | 为什么需要:候诊列表按 room_id + bed_no 查,只含"已分流到本工位"的人; |
| | | 而"排队中(10)"的人 bed_no 是空的 —— 大屏能看到他们,工作台原先看不到, |
| | | 医生会以为"患者列表没取到数据"。这里列出来,工位主人可一键「拉入」。 |
| | | --> |
| | | <div v-if="waitingList && waitingList.length > 0" class="room-waiting"> |
| | | <div class="room-waiting__title"> |
| | | 本诊室排队中(未分配工位){{ waitingList.length }} 人 |
| | | </div> |
| | | <div v-for="(item, index) in waitingList" :key="'w' + index" class="room-waiting__row"> |
| | | <span class="col-seq"> |
| | | <span v-if="Number(item.jumpFlag) === 1" class="jump-badge">急</span> |
| | | {{ getCheckTypeSeqPrefix(item.bookCheckType) }}{{ item.seqNum }} |
| | | </span> |
| | | <span class="col-name"> {{ item.patName }} </span> |
| | | {{ getCheckTypeName(item.bookCheckType) }} |
| | | <template v-if="canOperate"> |
| | | <el-button size="small" type="primary" plain @click="pullWaiting(item)"> 拉入 </el-button> |
| | | </template> |
| | | <span v-else class="room-waiting__readonly">(只读)</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | padding-left: 5px; |
| | | } |
| | | |
| | | /* 空列表提示(本次新增):把"这份列表属于哪个工位、我是什么身份"写清楚, |
| | | 避免把"看错了工位(围观/切换过)"当成"排队没人"。 */ |
| | | .queue-empty { |
| | | padding: 18px 8px; |
| | | text-align: center; |
| | | |
| | | &__title { |
| | | font-size: 15px; |
| | | color: var(--el-text-color-secondary); |
| | | } |
| | | |
| | | &__meta { |
| | | margin-top: 6px; |
| | | font-size: 13px; |
| | | line-height: 1.6; |
| | | color: var(--el-text-color-placeholder); |
| | | } |
| | | } |
| | | |
| | | /* |
| | | 「本诊室排队中(未分配工位)」分区(本次新增): |
| | | 与上面的候诊列表用一条浅色分隔线 + 小标题区分开,视觉上明确"这些人还没进本工位"。 |
| | | */ |
| | | .room-waiting { |
| | | margin-top: 10px; |
| | | padding-top: 8px; |
| | | border-top: 1px dashed var(--el-border-color); |
| | | |
| | | &__title { |
| | | margin-bottom: 4px; |
| | | font-size: 13px; |
| | | font-weight: 600; |
| | | color: var(--el-color-primary); |
| | | } |
| | | |
| | | &__row { |
| | | padding: 3px 6px; |
| | | margin-bottom: 3px; |
| | | color: var(--el-text-color-regular); |
| | | } |
| | | |
| | | &__readonly { |
| | | font-size: 12px; |
| | | color: var(--el-text-color-placeholder); |
| | | } |
| | | } |
| | | |
| | | /* |
| | | 行样式(本次需求): |
| | | · 去掉整行背景色,也去掉行首那条 4px 色条 —— 状态只靠**文字颜色**区分; |
| | | · 因此这里只保留间距/圆角,颜色规则全部下沉到下面的 .row-* 里。 |
| | | */ |
| | | .queue-row { |
| | | padding: 3px 6px; |
| | | margin-bottom: 3px; |
| | | border-left: 4px solid transparent; |
| | | border-radius: 3px; |
| | | line-height: 22px; |
| | | background-color: transparent; |
| | | } |
| | | |
| | | /* 就诊中:蓝色(主色)—— 当前正在处理的患者 */ |
| | | .row-onstage { |
| | | background-color: var(--el-color-primary-light-8); |
| | | border-left-color: var(--el-color-primary); |
| | | color: var(--el-color-primary); |
| | | |
| | | .col-name { |
| | | font-weight: 700; |
| | | color: var(--el-color-primary); |
| | | } |
| | | } |
| | | |
| | | /* 已过号:红色 —— 需提醒医生注意 */ |
| | | /* 过号:红色 —— 需提醒医生注意 */ |
| | | .row-passed { |
| | | background-color: var(--el-color-danger-light-8); |
| | | border-left-color: var(--el-color-danger); |
| | | color: var(--el-color-danger); |
| | | |
| | | .col-name { |
| | | font-weight: 600; |
| | | color: var(--el-color-danger); |
| | | } |
| | | } |
| | | |
| | | /* 候诊中 / 已召回:绿色 —— 正常等待 */ |
| | | /* 准备中(原"候诊中") / 已召回:绿色 —— 正常等待 */ |
| | | .row-ready { |
| | | background-color: var(--el-color-success-light-8); |
| | | border-left-color: var(--el-color-success); |
| | | color: var(--el-color-success); |
| | | } |
| | | |
| | | /* 其他状态:灰色,弱化显示 */ |
| | | .row-other { |
| | | background-color: var(--el-fill-color-light); |
| | | border-left-color: var(--el-border-color); |
| | | color: var(--el-text-color-secondary); |
| | | } |
| | | |
| | | .col-seq, |
| | | .col-bookseq, |
| | | .col-name { |
| | | display: inline-block; |
| | | } |
| | | /* 号 + 前缀 + 可能的「急」标记,给足宽度避免与姓名挤在一起 */ |
| | | .col-seq { |
| | | width: 30px; |
| | | } |
| | | .col-bookseq { |
| | | width: 40px; |
| | | width: 78px; |
| | | } |
| | | .col-name { |
| | | width: 70px; |
| | | } |
| | | |
| | | /* 加急标记:红底白字,紧贴在排队号前面 */ |
| | | .jump-badge { |
| | | display: inline-block; |
| | | padding: 0 3px; |
| | | margin-right: 2px; |
| | | border-radius: 2px; |
| | | background-color: var(--el-color-danger); |
| | | color: #fff; |
| | | font-size: 11px; |
| | | line-height: 15px; |
| | | vertical-align: 1px; |
| | | } |
| | | </style> |