506 门诊挂号:门诊诊前退号后,数据库多表状态值变更与 PRD 定义不符

CommonConstants.AppointmentOrderStatus 常量 → OrderStatus 枚举重构
   新增枚举:0=患者取消 / 1=有效 / 2=系统取消 / 3=已完成
   退号流程加乐观锁防并发,slot 状态改回待约,退号日志独立事务 修复 XML 中 Integer 比较用字符串的问题
Bug #411 — 诊室过滤栏从科室下拉框改为诊室按钮组
This commit is contained in:
wangjian963
2026-05-11 13:51:47 +08:00
committed by 关羽
parent 777ba71c7d
commit 9215c288d3
9 changed files with 259 additions and 172 deletions

View File

@@ -198,53 +198,52 @@
</el-button>
</div>
<div class="queue-actions-right">
<el-button
:type="showOnlyWaiting ? 'primary' : ''"
size="small"
@click="showOnlyWaiting = true"
>
只显示等待
</el-button>
<el-button
:type="!showOnlyWaiting ? 'primary' : ''"
size="small"
@click="showOnlyWaiting = false"
>
显示全部状态
</el-button>
</div>
</div>
</div>
</div>
<!-- 底部控制面板 -->
<div class="footer-section">
<!-- 诊室快速过滤栏 -->
<!-- Bug #411诊室快速过滤栏筛选维度从科室改为诊室 -->
<div class="filter-section">
<div class="filter-label">
诊室快速过滤栏
</div>
<div class="filter-select-wrapper">
<el-select
v-model="selectedClinicRoom"
placeholder="请选择诊室"
clearable
filterable
style="width: 100%"
size="default"
>
<el-option
label="全部"
value="all"
/>
<el-option
v-for="room in clinicRoomList"
<div class="filter-left">
<div class="filter-label">
诊室快速过滤栏
</div>
<div class="filter-button-wrapper">
<el-button
:type="selectedRoom === 'all' ? 'primary' : ''"
size="small"
@click="selectedRoom = 'all'"
>
全部
</el-button>
<el-button
v-for="room in uniqueRooms"
:key="room"
:label="room"
:value="room"
/>
</el-select>
:type="selectedRoom === room ? 'primary' : ''"
size="small"
@click="selectedRoom = room"
>
{{ room }}
</el-button>
</div>
</div>
<div class="filter-right">
<el-button
:type="showOnlyWaiting ? 'primary' : ''"
size="small"
@click="showOnlyWaiting = true"
>
只显示等待
</el-button>
<el-button
:type="!showOnlyWaiting ? 'primary' : ''"
size="small"
@click="showOnlyWaiting = false"
>
显示全部状态
</el-button>
</div>
</div>
@@ -680,10 +679,8 @@ const selectedCandidates = ref([])
// 显示选项
const showOnlyWaiting = ref(false)
// 诊室过滤(按诊室维度筛选
const selectedClinicRoom = ref('all')
// 诊室列表(从数据中动态提取)
const clinicRoomList = ref([])
// Bug #411诊室过滤替代原来的科室下拉框selectedDept/departmentList 已移除
const selectedRoom = ref('all')
// 修复【#397】动态获取当前科室名称
const currentDeptName = computed(() => {
@@ -906,11 +903,12 @@ const mapFrontendStatusToBackend = (status) => {
// 从数据库加载队列
const loadQueueFromDb = async () => {
try {
// 使用当前登录人科室
// Bug #411不再按科室选筛加载后端默认按当前登录人科室查询
const organizationId = undefined
// 只查询今天的患者
const today = new Date()
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`
console.log('【心内科】loadQueueFromDb 开始date=', todayStr)
const res = await getTriageQueueList({ date: todayStr }).catch((err) => {
const res = await getTriageQueueList({ organizationId, date: todayStr }).catch((err) => {
console.error('【心内科】loadQueueFromDb 请求异常:', err)
return { code: 500, msg: err?.message || '请求失败', data: null }
})
@@ -1138,8 +1136,6 @@ const loadDataFromApi = async () => {
// 同步当前呼叫(队列从 DB 加载后已同步;这里再兜底一次)
syncCurrentCallFromQueue()
// 提取诊室列表供过滤栏使用
extractClinicRooms()
console.log('【心内科】数据加载完成:候选池', originalCandidatePoolList.value.length, '条,队列', originalQueueList.value.length, '条')
ElMessage.success('【心内科】已从门诊挂号接口加载数据')
} catch (e) {
@@ -1151,42 +1147,35 @@ const loadDataFromApi = async () => {
totalSignedIn.value = originalCandidatePoolList.value.length
totalInQueue.value = originalQueueList.value.length
syncCurrentCallFromQueue()
extractClinicRooms()
}
}
// 原始数据存储(用于过滤)
const originalCandidatePoolList = ref(getInitialCandidatePoolList())
// 提取诊室列表(从队列和候选池数据中动态获取
const extractClinicRooms = () => {
const roomSet = new Set()
// 从队列中提取
originalQueueList.value.forEach(item => {
if (item.room && item.room !== '-') {
roomSet.add(item.room)
}
})
// 从候选池中提取
originalCandidatePoolList.value.forEach(item => {
if (item.room && item.room !== '-') {
roomSet.add(item.room)
}
})
clinicRoomList.value = Array.from(roomSet).sort()
}
// 过滤后的智能候选池数据
// 过滤后的智能候选池数据(按诊室过滤
const filteredCandidatePoolList = computed(() => {
if (selectedClinicRoom.value === 'all') {
if (selectedRoom.value === 'all') {
return originalCandidatePoolList.value
}
return originalCandidatePoolList.value.filter(item => item.room === selectedClinicRoom.value)
return originalCandidatePoolList.value.filter(item => item.room === selectedRoom.value)
})
// 原始队列数据存储(用于过滤)
const originalQueueList = ref(getInitialQueueList())
// 动态计算已加载数据中的唯一诊室列表(依赖上方两个 ref确保声明顺序正确
const uniqueRooms = computed(() => {
const rooms = new Set()
originalCandidatePoolList.value.forEach(item => {
if (item.room && item.room !== '-') rooms.add(item.room)
})
originalQueueList.value.forEach(item => {
if (item.room && item.room !== '-') rooms.add(item.room)
})
return Array.from(rooms).sort()
})
const parseMmSsToSeconds = (mmss) => {
if (!mmss || typeof mmss !== 'string') return 0
const [mm, ss] = mmss.split(':')
@@ -1203,7 +1192,7 @@ const formatSecondsToMmSs = (totalSeconds) => {
return `${mm}:${ss}`
}
// 过滤后的智能队列数据(同时考虑诊室过滤状态过滤)
// 过滤后的智能队列数据(Bug #411诊室过滤 + 状态过滤)
const filteredQueueList = computed(() => {
let filtered = originalQueueList.value
@@ -1211,8 +1200,8 @@ const filteredQueueList = computed(() => {
filtered = filtered.filter(item => item.status !== '已完成')
// 再按诊室过滤
if (selectedClinicRoom.value !== 'all') {
filtered = filtered.filter(item => item.room === selectedClinicRoom.value)
if (selectedRoom.value !== 'all') {
filtered = filtered.filter(item => item.room === selectedRoom.value)
}
// 再按状态过滤(只显示等待)
@@ -1723,16 +1712,12 @@ const handleNextPatient = async () => {
reqData.id = selectedQueueRow.value.id
reqData.organizationId = selectedQueueRow.value.organizationId
} else {
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
// 全科模式:优先用"当前叫号中/第一个等待"所在科室
let orgId = null
{
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
const waiting = originalQueueList.value.find((i) => i.status === '等待')
console.log('【心内科】handleNextPatient 查找:叫号中=', calling?.patientName, '等待=', waiting?.patientName)
orgId = calling?.organizationId ?? waiting?.organizationId
console.log('【心内科】handleNextPatient 确定的 orgId=', orgId)
}
// Bug #411已移除 selectedDept改为从队列数据中动态获取科室
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
const waiting = originalQueueList.value.find((i) => i.status === '等待')
console.log('【心内科】handleNextPatient 查找:叫号中=', calling?.patientName, '等待=', waiting?.patientName)
const orgId = calling?.organizationId ?? waiting?.organizationId
console.log('【心内科】handleNextPatient 确定的 orgId=', orgId)
if (orgId != null) {
reqData.organizationId = orgId
}
@@ -1761,13 +1746,9 @@ const handleSkip = async () => {
reqData.id = selectedQueueRow.value.id
reqData.organizationId = selectedQueueRow.value.organizationId
} else {
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
// 全科模式:优先用”当前叫号中”所在科室
let orgId = null
{
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
orgId = calling?.organizationId
}
// 如果没有选中患者,使用当前叫号中的科室
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
const orgId = calling?.organizationId
if (orgId != null) {
reqData.organizationId = orgId
}
@@ -1795,13 +1776,9 @@ const handleComplete = async () => {
reqData.id = selectedQueueRow.value.id
reqData.organizationId = selectedQueueRow.value.organizationId
} else {
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
// 全科模式:优先用”当前叫号中”所在科室
let orgId = null
{
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
orgId = calling?.organizationId
}
// 如果没有选中患者,使用当前叫号中的科室
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
const orgId = calling?.organizationId
if (orgId != null) {
reqData.organizationId = orgId
}
@@ -1829,13 +1806,9 @@ const handleRequeue = async () => {
reqData.id = selectedQueueRow.value.id
reqData.organizationId = selectedQueueRow.value.organizationId
} else {
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
// 全科模式:优先用”当前叫号中”所在科室
let orgId = null
{
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
orgId = calling?.organizationId
}
// 如果没有选中患者,使用当前叫号中的科室
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
const orgId = calling?.organizationId
if (orgId != null) {
reqData.organizationId = orgId
}
@@ -2219,10 +2192,6 @@ onUnmounted(() => {
gap: 10px;
}
.queue-actions-right {
display: flex;
gap: 10px;
}
}
.candidate-actions {
@@ -2244,16 +2213,32 @@ onUnmounted(() => {
.filter-section {
margin-bottom: 20px;
display: flex;
align-items: flex-start;
justify-content: space-between;
.filter-label {
font-size: 14px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
.filter-left {
flex: 1;
.filter-label {
font-size: 14px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.filter-button-wrapper {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
}
.filter-select-wrapper {
width: 100%;
.filter-right {
display: flex;
gap: 8px;
flex-shrink: 0;
align-self: flex-end;
}
}