feat(分诊队列): 实现分诊队列核心功能与日志记录

新增分诊队列相关服务接口与实现,包括队列管理、叫号操作和日志记录
添加DivLogService和CallRecordService用于记录分诊操作和叫号历史
在CurrentDayEncounterDto和TriageQueueItem中增加seqNo字段用于显示预约序号
实现分诊操作日志记录功能,包括添加队列、移除队列、叫号、完成等操作
新增CallType枚举定义叫号类型,并实现叫号记录功能
优化队列状态映射逻辑,支持更多状态类型显示
This commit is contained in:
wangjian963
2026-04-30 16:02:52 +08:00
parent 81daaccdda
commit 4a01825a30
8 changed files with 139 additions and 75 deletions

View File

@@ -525,10 +525,11 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
ParticipantType.ADMITTER.getCode(), ParticipantType.REGISTRATION_DOCTOR.getCode(), queryWrapper,
ChargeItemContext.REGISTER.getValue(), PaymentStatus.SUCCESS.getValue());
// 过滤候选池排除列表(如果是从智能候选池查询,排除已加入队列的患者)
// 检查请求参数 excludeFromCandidatePool,如果为 true 或未设置,则过滤排除列表
// 过滤候选池排除列表
// 仅当调用方显式传 excludeFromCandidatePool=true 时才过滤,避免非分诊场景(挂号/收费)
// 因未传参导致默认过滤,使已入队患者不可见
String excludeParam = request.getParameter("excludeFromCandidatePool");
boolean shouldExclude = excludeParam == null || "true".equalsIgnoreCase(excludeParam);
boolean shouldExclude = "true".equalsIgnoreCase(excludeParam);
if (shouldExclude && currentDayEncounter != null && !currentDayEncounter.getRecords().isEmpty()) {
try {
// 获取当前租户和日期

View File

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.core.domain.model.LoginUser;
import com.core.common.utils.AgeCalculatorUtil;
import com.core.common.utils.SecurityUtils;
import com.openhis.administration.domain.Encounter;
@@ -17,7 +18,9 @@ import com.openhis.common.constant.CommonConstants;
import com.openhis.common.enums.*;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.triageandqueuemanage.domain.DivLog;
import com.openhis.triageandqueuemanage.domain.TriageQueueItem;
import com.openhis.triageandqueuemanage.service.DivLogService;
import com.openhis.triageandqueuemanage.service.TriageQueueItemService;
import com.openhis.web.doctorstation.appservice.*;
import com.openhis.web.doctorstation.dto.PatientInfoDto;
@@ -32,6 +35,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
@@ -70,6 +74,10 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
@Resource
private TriageQueueItemService triageQueueItemService;
@Resource
private DivLogService divLogService;
/**
* 查询就诊患者信息
*
@@ -194,10 +202,13 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getEncounterId, encounterId)
// 限定当天日期,避免复诊患者匹配到历史队列记录
.eq(TriageQueueItem::getQueueDate, LocalDate.now())
.eq(TriageQueueItem::getDeleteFlag, "0")
);
if (queueItem != null) {
queueItem.setStatus(20); // 20=IN_CLINIC(诊中),患者进入诊室接诊
// 使用 TriageQueueStatus 枚举替代原有硬编码数字 20保证状态值一致性
queueItem.setStatus(TriageQueueStatus.IN_CLINIC.getValue());
queueItem.setUpdateTime(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS));
triageQueueItemService.updateById(queueItem);
log.info("接诊时更新队列状态为IN_CLINIC(诊中)encounterId={}, queueItemId={}", encounterId, queueItem.getId());
@@ -253,40 +264,38 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
return R.fail("非就诊中患者不能完诊");
}
// 2. 查找队列项
// 2. 查找队列项(限定当天,避免复诊患者匹配到历史队列记录)
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
TriageQueueItem queueItem = triageQueueItemService.getOne(
new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getEncounterId, encounterId)
.eq(TriageQueueItem::getQueueDate, LocalDate.now())
.eq(TriageQueueItem::getDeleteFlag, "0")
);
// 如果队列项存在,检查状态并更新
// 允许从 CALLING(10) 或 IN_CLINIC(20) 完成就诊
// 如果队列项存在且未完成,更新队列状态为已完成
// 使用排除法而非白名单:只要不是"已完成"就可以完诊,覆盖跳过、等待等非标准流转状态
if (queueItem != null &&
(Integer.valueOf(10).equals(queueItem.getStatus()) ||
Integer.valueOf(20).equals(queueItem.getStatus()))) {
!TriageQueueStatus.COMPLETED.getValue().equals(queueItem.getStatus())) {
// 更新队列状态为已完成
java.time.LocalDateTime nowLocal = java.time.LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS);
queueItem.setStatus(30); // 30=COMPLETED(已完成)
queueItem.setStatus(TriageQueueStatus.COMPLETED.getValue());
queueItem.setUpdateTime(nowLocal);
triageQueueItemService.updateById(queueItem);
// 写入 div_log 审计日志
// 写入 div_log 审计日志(使用实体+Service替代原生JDBC SQL避免SQL注入风险便于维护
try {
Long userId = SecurityUtils.getLoginUser().getUserId();
String divLogSql = "INSERT INTO hisdev.div_log "
+ "(pool_id, slot_id, queue_no, op_user_id, action, create_time) "
+ "VALUES (?, ?, ?, ?, 30, NOW()::timestamp(0))";
// action=30 表示 COMPLETED(已完成),与 triage_queue_item.status 数字编码保持一致
// 0=WAITING, 10=CALLING, 20=IN_CLINIC, 30=COMPLETED, 40=SKIPPED, 50=REFUNDED, 60=FOLLOW
jdbcTemplate.update(divLogSql,
queueItem.getPoolId(), // pool_id: 号源池ID来自 adm_schedule_pool.id
queueItem.getSlotId(), // slot_id: 号源槽位ID来自 adm_schedule_slot.id
queueItem.getQueueOrder(), // queue_no: 队列序号
userId); // op_user_id: 操作用户ID
LoginUser loginUser = SecurityUtils.getLoginUser();
DivLog divLog = new DivLog()
.setPoolId(queueItem.getPoolId())
.setSlotId(queueItem.getSlotId())
.setOpUserId(loginUser != null ? loginUser.getUserId() : null)
.setAction("COMPLETE")
.setCreateTime(LocalDateTime.now())
.setUpdateAt(LocalDateTime.now())
.setCreatedAt(LocalDateTime.now());
divLogService.save(divLog);
} catch (Exception e) {
log.error("写入div_log审计日志失败", e);
// 审计日志失败不影响主流程

View File

@@ -77,7 +77,6 @@ import com.openhis.yb.service.IClinicSettleService;
import com.openhis.yb.service.IInpatientSettleService;
import com.openhis.yb.service.IRegService;
import com.openhis.yb.service.YbManager;
import com.openhis.web.triageandqueuemanage.appservice.impl.TriageQueueAppServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.StringUtil;
@@ -2150,7 +2149,7 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
.setRoomNo(null)
.setPoolId(queuePoolId)
.setSlotId(queueSlotId)
.setStatus(TriageQueueAppServiceImpl.STATUS_WAITING) // 0=WAITING(等待中)
.setStatus(TriageQueueStatus.WAITING.getValue()) // 使用枚举替代硬编码常量,保持状态值一致
.setQueueOrder(maxOrder + 1)
.setDeleteFlag("0")
.setCreateTime(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS))

View File

@@ -3,8 +3,14 @@ package com.openhis.web.triageandqueuemanage.appservice.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.core.common.core.domain.R;
import com.core.common.utils.SecurityUtils;
import com.openhis.administration.domain.Encounter;
import com.openhis.administration.mapper.EncounterMapper;
import com.openhis.common.enums.EncounterStatus;
import com.openhis.common.enums.EncounterSubjectStatus;
import com.openhis.common.enums.TriageQueueStatus;
import com.openhis.triageandqueuemanage.domain.CallRecord;
import com.openhis.triageandqueuemanage.domain.DivLog;
import com.openhis.triageandqueuemanage.domain.TriageCandidateExclusion;
@@ -34,18 +40,8 @@ import java.util.stream.Collectors;
@Service
public class TriageQueueAppServiceImpl implements TriageQueueAppService {
/**
* 分诊队列状态常量(数字编码)
* 0=WAITING(等待中), 10=CALLING(呼叫中), 20=IN_CLINIC(诊中),
* 30=COMPLETED(已完成), 40=SKIPPED(已跳过), 50=REFUNDED(已退费), 60=FOLLOW(已随访)
*/
public static final Integer STATUS_WAITING = 0;
public static final Integer STATUS_CALLING = 10;
public static final Integer STATUS_IN_CLINIC = 20;
public static final Integer STATUS_COMPLETED = 30;
public static final Integer STATUS_SKIPPED = 40;
public static final Integer STATUS_REFUNDED = 50;
public static final Integer STATUS_FOLLOW = 60;
// 状态常量已迁移至 TriageQueueStatus 枚举,原硬编码 STATU_WAITING/STATU_CALLING 等已删除,
// 避免散落在多个 Service 类中的魔法数字造成不一致
@Resource
private TriageQueueItemService triageQueueItemService;
@@ -65,6 +61,9 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
@Resource
private ScheduleSlotMapper scheduleSlotMapper;
@Resource
private EncounterMapper encounterMapper;
@Override
public R<?> list(Long organizationId, LocalDate date) {
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
@@ -75,7 +74,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getQueueDate, qd)
.eq(TriageQueueItem::getDeleteFlag, "0")
.ne(TriageQueueItem::getStatus, STATUS_COMPLETED)
.ne(TriageQueueItem::getStatus, TriageQueueStatus.COMPLETED.getValue())
.orderByAsc(TriageQueueItem::getQueueOrder);
// 如果指定了科室,按科室过滤;否则查询所有科室(全科模式)
@@ -98,7 +97,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
if (list != null && !list.isEmpty()) {
int beforeSize = list.size();
list = list.stream()
.filter(item -> !STATUS_COMPLETED.equals(item.getStatus()))
.filter(item -> !TriageQueueStatus.COMPLETED.getValue().equals(item.getStatus()))
.collect(java.util.stream.Collectors.toList());
}
return R.ok(list);
@@ -130,7 +129,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
.eq(TriageQueueItem::getOrganizationId, orgId)
.eq(TriageQueueItem::getQueueDate, qd)
.eq(TriageQueueItem::getDeleteFlag, "0")
.ne(TriageQueueItem::getStatus, STATUS_COMPLETED));
.ne(TriageQueueItem::getStatus, TriageQueueStatus.COMPLETED.getValue()));
int maxOrder = existing.stream().map(TriageQueueItem::getQueueOrder).filter(Objects::nonNull).max(Integer::compareTo).orElse(0);
@@ -155,7 +154,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
.setPoolId(it.getPoolId()) // ✅ 号源池ID用于div_log审计
.setSlotId(it.getSlotId()) // ✅ 号源槽位ID用于div_log审计
.setSeqNo(it.getSeqNo()) // ✅ 预约序号(用于叫号显示)
.setStatus(STATUS_WAITING)
.setStatus(TriageQueueStatus.WAITING.getValue())
.setQueueOrder(++maxOrder)
.setDeleteFlag("0")
.setCreateTime(LocalDateTime.now())
@@ -285,8 +284,8 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
if (selected == null) return R.fail("队列项不存在");
// 只将"等待"状态的患者转为"叫号中",允许有多个"叫号中"的患者
if (STATUS_WAITING.equals(selected.getStatus())) {
selected.setStatus(STATUS_CALLING).setUpdateTime(LocalDateTime.now());
if (TriageQueueStatus.WAITING.getValue().equals(selected.getStatus())) {
selected.setStatus(TriageQueueStatus.CALLING.getValue()).setUpdateTime(LocalDateTime.now());
triageQueueItemService.updateById(selected);
// 叫号后推送 SSE 消息(实时通知显示屏刷新)
@@ -295,7 +294,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
writeDivLog(selected.getPoolId(), selected.getSlotId(), "CALL");
writeCallRecord(selected.getId(), selected.getPractitionerId(), CallType.CALL, selected.getRoomNo());
return R.ok(true);
} else if (STATUS_CALLING.equals(selected.getStatus())) {
} else if (TriageQueueStatus.CALLING.getValue().equals(selected.getStatus())) {
// 如果已经是"叫号中"状态,直接返回成功(不做任何操作)
return R.ok(true);
} else {
@@ -324,7 +323,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
return R.fail("队列项不存在");
}
// 验证状态
if (!STATUS_CALLING.equals(calling.getStatus())) {
if (!TriageQueueStatus.CALLING.getValue().equals(calling.getStatus())) {
return R.fail("只能完成\"叫号中\"状态的患者,当前患者状态为:" + calling.getStatus());
}
} else {
@@ -334,7 +333,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
LambdaQueryWrapper<TriageQueueItem> callingWrapper = new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getDeleteFlag, "0")
.eq(TriageQueueItem::getStatus, STATUS_CALLING)
.eq(TriageQueueItem::getStatus, TriageQueueStatus.CALLING.getValue())
.orderByAsc(TriageQueueItem::getQueueOrder)
.last("LIMIT 1");
@@ -353,16 +352,33 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
Long actualOrgId = calling.getOrganizationId();
// 1) 叫号中 -> 完成(移出列表)
calling.setStatus(STATUS_COMPLETED).setUpdateTime(LocalDateTime.now());
calling.setStatus(TriageQueueStatus.COMPLETED.getValue()).setUpdateTime(LocalDateTime.now());
triageQueueItemService.updateById(calling);
// 同步更新就诊状态为诊毕
// 分诊台完诊原只更新队列状态未同步encounter表导致与医生站完诊行为不一致
if (calling.getEncounterId() != null) {
try {
java.util.Date now = new java.util.Date();
encounterMapper.update(null,
new LambdaUpdateWrapper<Encounter>()
.eq(Encounter::getId, calling.getEncounterId())
.set(Encounter::getStatusEnum, EncounterStatus.DISCHARGED.getValue())
.set(Encounter::getSubjectStatusEnum, EncounterSubjectStatus.DEPARTED.getValue())
.set(Encounter::getEndTime, now)
.set(Encounter::getUpdateTime, now));
} catch (Exception e) {
log.error("更新就诊状态为诊毕失败, encounterId={}", calling.getEncounterId(), e);
}
}
// 2) 自动推进下一个等待为叫号中(同一科室,包含跳过状态,不限制日期)
LambdaQueryWrapper<TriageQueueItem> nextWrapper = new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getDeleteFlag, "0")
.and(w -> w.eq(TriageQueueItem::getStatus, STATUS_WAITING)
.and(w -> w.eq(TriageQueueItem::getStatus, TriageQueueStatus.WAITING.getValue())
.or()
.eq(TriageQueueItem::getStatus, STATUS_SKIPPED))
.eq(TriageQueueItem::getStatus, TriageQueueStatus.SKIPPED.getValue()))
.orderByAsc(TriageQueueItem::getQueueOrder)
.last("LIMIT 1");
@@ -374,7 +390,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
TriageQueueItem next = triageQueueItemService.getOne(nextWrapper, false);
if (next != null) {
next.setStatus(STATUS_CALLING).setUpdateTime(LocalDateTime.now());
next.setStatus(TriageQueueStatus.CALLING.getValue()).setUpdateTime(LocalDateTime.now());
triageQueueItemService.updateById(next);
}
@@ -428,7 +444,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
return R.fail("队列项不存在");
}
// 验证状态
if (!STATUS_CALLING.equals(calling.getStatus())) {
if (!TriageQueueStatus.CALLING.getValue().equals(calling.getStatus())) {
return R.fail("只能对\"叫号中\"状态的患者进行" + ("SKIP".equals(action) ? "跳过" : "过号重排") + ",当前患者状态为:" + calling.getStatus());
}
} else {
@@ -438,7 +454,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
LambdaQueryWrapper<TriageQueueItem> callingWrapper = new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getDeleteFlag, "0")
.eq(TriageQueueItem::getStatus, STATUS_CALLING)
.eq(TriageQueueItem::getStatus, TriageQueueStatus.CALLING.getValue())
.orderByAsc(TriageQueueItem::getQueueOrder)
.last("LIMIT 1");
@@ -458,9 +474,9 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
LambdaQueryWrapper<TriageQueueItem> nextWrapper = new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getDeleteFlag, "0")
.and(w -> w.eq(TriageQueueItem::getStatus, STATUS_WAITING)
.and(w -> w.eq(TriageQueueItem::getStatus, TriageQueueStatus.WAITING.getValue())
.or()
.eq(TriageQueueItem::getStatus, STATUS_SKIPPED))
.eq(TriageQueueItem::getStatus, TriageQueueStatus.SKIPPED.getValue()))
.orderByAsc(TriageQueueItem::getQueueOrder)
.last("LIMIT 1");
@@ -479,7 +495,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getOrganizationId, actualOrgId)
.eq(TriageQueueItem::getDeleteFlag, "0")
.ne(TriageQueueItem::getStatus, STATUS_COMPLETED))
.ne(TriageQueueItem::getStatus, TriageQueueStatus.COMPLETED.getValue()))
.stream()
.map(TriageQueueItem::getQueueOrder)
.filter(Objects::nonNull)
@@ -487,11 +503,11 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
.orElse(0);
// 1) 叫号中 -> 跳过,并移到末尾
calling.setStatus(STATUS_SKIPPED).setQueueOrder(maxOrder + 1).setUpdateTime(LocalDateTime.now());
calling.setStatus(TriageQueueStatus.SKIPPED.getValue()).setQueueOrder(maxOrder + 1).setUpdateTime(LocalDateTime.now());
triageQueueItemService.updateById(calling);
// 2) 自动推进下一个等待为叫号中
next.setStatus(STATUS_CALLING).setUpdateTime(LocalDateTime.now());
next.setStatus(TriageQueueStatus.CALLING.getValue()).setUpdateTime(LocalDateTime.now());
triageQueueItemService.updateById(next);
recalcOrders(actualOrgId, null);
@@ -517,7 +533,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
return R.fail("队列项不存在");
}
// 验证状态:必须是"叫号中"状态
if (!STATUS_CALLING.equals(calling.getStatus())) {
if (!TriageQueueStatus.CALLING.getValue().equals(calling.getStatus())) {
return R.fail("只能对\"叫号中\"状态的患者执行\"下一患者\"操作,当前患者状态为:" + calling.getStatus());
}
} else {
@@ -527,7 +543,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
LambdaQueryWrapper<TriageQueueItem> callingWrapper = new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getDeleteFlag, "0")
.eq(TriageQueueItem::getStatus, STATUS_CALLING)
.eq(TriageQueueItem::getStatus, TriageQueueStatus.CALLING.getValue())
.orderByAsc(TriageQueueItem::getQueueOrder)
.last("LIMIT 1");
@@ -542,7 +558,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
// 当前叫号中 -> 完成(如果不存在,就当作从头找第一位等待)
if (calling != null) {
calling.setStatus(STATUS_COMPLETED).setUpdateTime(LocalDateTime.now());
calling.setStatus(TriageQueueStatus.COMPLETED.getValue()).setUpdateTime(LocalDateTime.now());
triageQueueItemService.updateById(calling);
actualOrgId = calling.getOrganizationId(); // 使用叫号中患者所在的科室
} else {
@@ -557,9 +573,9 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
LambdaQueryWrapper<TriageQueueItem> nextWrapper = new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getDeleteFlag, "0")
.and(w -> w.eq(TriageQueueItem::getStatus, STATUS_WAITING)
.and(w -> w.eq(TriageQueueItem::getStatus, TriageQueueStatus.WAITING.getValue())
.or()
.eq(TriageQueueItem::getStatus, STATUS_SKIPPED))
.eq(TriageQueueItem::getStatus, TriageQueueStatus.SKIPPED.getValue()))
.orderByAsc(TriageQueueItem::getQueueOrder)
.last("LIMIT 1");
@@ -576,7 +592,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
return R.fail("当前没有等待的患者");
}
next.setStatus(STATUS_CALLING).setUpdateTime(LocalDateTime.now());
next.setStatus(TriageQueueStatus.CALLING.getValue()).setUpdateTime(LocalDateTime.now());
triageQueueItemService.updateById(next);
if (next.getOrganizationId() != null) {
@@ -598,7 +614,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getOrganizationId, orgId)
.eq(TriageQueueItem::getDeleteFlag, "0")
.ne(TriageQueueItem::getStatus, STATUS_COMPLETED);
.ne(TriageQueueItem::getStatus, TriageQueueStatus.COMPLETED.getValue());
// 如果 qd 不为 null才添加日期限制
if (qd != null) {
wrapper.eq(TriageQueueItem::getQueueDate, qd);
@@ -613,7 +629,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
.eq(TriageQueueItem::getOrganizationId, orgId)
.eq(TriageQueueItem::getQueueDate, qd)
.eq(TriageQueueItem::getDeleteFlag, "0")
.eq(TriageQueueItem::getStatus, STATUS_CALLING)
.eq(TriageQueueItem::getStatus, TriageQueueStatus.CALLING.getValue())
.last("LIMIT 1"), false);
}
@@ -658,7 +674,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
.eq(TriageQueueItem::getQueueDate, qd)
.eq(TriageQueueItem::getOrganizationId, organizationId)
.eq(TriageQueueItem::getTenantId, tenantId)
.in(TriageQueueItem::getStatus, STATUS_WAITING, STATUS_CALLING)
.in(TriageQueueItem::getStatus, TriageQueueStatus.WAITING.getValue(), TriageQueueStatus.CALLING.getValue())
.eq(TriageQueueItem::getDeleteFlag, "0")
.orderByAsc(TriageQueueItem::getQueueOrder)
);
@@ -677,7 +693,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
// 2. 查找当前叫号中的患者CALLING 状态)
TriageQueueItem callingItem = allItems.stream()
.filter(item -> STATUS_CALLING.equals(item.getStatus()))
.filter(item -> TriageQueueStatus.CALLING.getValue().equals(item.getStatus()))
.findFirst()
.orElse(null);
@@ -742,7 +758,7 @@ public class TriageQueueAppServiceImpl implements TriageQueueAppService {
patients.add(patient);
// 统计等待人数(不包括 CALLING 状态)
if (STATUS_WAITING.equals(item.getStatus())) {
if (TriageQueueStatus.WAITING.getValue().equals(item.getStatus())) {
totalWaiting++;
}
}

View File

@@ -339,7 +339,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND sr.id IS NULL
<if test="ew.sqlSegment != null and ew.sqlSegment != ''">
<![CDATA[
AND ${ew.sqlSegment.replace('tenant_id', 's.tenant_id').replace('create_time', 's.create_time').replace('surgery_no', 's.surgery_no').replace('surgery_name', 's.surgery_name').replace('patient_name', 's.patient_name').replace('main_surgeon_name', 's.main_surgeon_name').replace('anesthetist_name', 's.anesthetist_name').replace('org_name', 's.org_name').replace('status_enum', 's.status_enum').replace('planned_time', 's.planned_time')}
AND ${ew.sqlSegment.replace('tenant_id', 's.tenant_id').replace('create_time', 's.create_time').replace('surgery_no', 's.surgery_no').replace('surgery_name', 's.surgery_name').replace('patient_name', 's.patient_name').replace('main_surgeon_name', 's.main_surgeon_name').replace('anesthetist_name', 's.anesthetist_name').replace('org_name', 's.org_name').replace('status_enum', 's.status_enum').replace('planned_time', 's.planned_time').replace('encounter_id', 's.encounter_id')/* 补充encounter_id替换修复多表关联时字段歧义 */}
]]>
</if>
</where>

View File

@@ -0,0 +1,35 @@
package com.openhis.common.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 智能分诊队列状态
*/
@Getter
@AllArgsConstructor
public enum TriageQueueStatus implements HisEnumInterface {
WAITING(0, "waiting", "等待"),
CALLING(10, "calling", "叫号中"),
IN_CLINIC(20, "in-clinic", "就诊中"),
COMPLETED(30, "completed", "完成"),
SKIPPED(40, "skipped", "跳过");
@EnumValue
private final Integer value;
private final String code;
private final String info;
public static TriageQueueStatus getByValue(Integer value) {
if (value == null) {
return null;
}
for (TriageQueueStatus val : values()) {
if (val.getValue().equals(value)) {
return val;
}
}
return null;
}
}

View File

@@ -37,7 +37,8 @@ export function getCandidatePool(params) {
pageNo: params?.pageNo || 1,
pageSize: params?.pageSize || 10000,
searchKey: params?.searchKey || '',
statusEnum: params?.statusEnum ?? 1 // 1=PLANNED(待诊),已挂号未接诊的患者;不传或传-1会返回已接诊的患者
statusEnum: params?.statusEnum ?? 1, // 1=PLANNED(待诊),已挂号未接诊的患者
excludeFromCandidatePool: true // 显式传参过滤已入队患者,配合后端 opt-in 逻辑
},
skipErrorMsg: true // 跳过错误提示,由组件处理
})

View File

@@ -840,7 +840,8 @@ const syncCurrentCallFromQueue = () => {
return
}
currentCall.value = {
number: String(calling.queueOrder),
// 优先显示预约序号 seqNo让患者凭挂号单号识别无预约序号时回退到排队序号
number: String(calling.seqNo ?? calling.queueOrder),
name: calling.patientName,
room: calling.room
}
@@ -877,7 +878,7 @@ const mapBackendStatusToFrontend = (status) => {
switch (numStatus) {
case 0: return '等待'
case 10: return '叫号中'
case 20: return '诊中'
case 20: return '诊中' // 统一文案,与医生站"就诊中"保持一致,原"诊中"过于简略
case 30: return '已完成'
case 40: return '跳过'
case 50: return '已退费'
@@ -894,7 +895,7 @@ const mapFrontendStatusToBackend = (status) => {
switch (status) {
case '叫号中': return 10
case '等待': return 0
case '诊中': return 20
case '诊中': return 20
case '已完成': return 30
case '跳过': return 40
case '已退费': return 50
@@ -960,6 +961,8 @@ const loadQueueFromDb = async () => {
return {
id: it.id,
queueOrder: it.queueOrder,
// 预约序号优先于queueOrder用于叫号屏显示患者凭此识别
seqNo: it.seqNo,
patientName: it.patientName ?? '-',
// 队列数据已从入队时存储的 healthcareName 读取(包含"预约"或"挂号"后缀)
appointmentType: it.healthcareName ?? '普通号挂号',
@@ -1715,8 +1718,8 @@ const handleSelectCall = async () => {
const latest = originalQueueList.value.find((i) => i.id === selectedQueueRow.value.id)
if (latest) {
selectedQueueRow.value = latest
// 如果有多个"叫号中"的患者,显示当前选中的这个
currentCall.value = { number: String(latest.queueOrder), name: latest.patientName, room: latest.room }
// 如果有多个"叫号中"的患者,显示当前选中的这个seqNo优先于queueOrder
currentCall.value = { number: String(latest.seqNo ?? latest.queueOrder), name: latest.patientName, room: latest.room }
}
// 统计当前"叫号中"的患者数量