package cn.lihu.jh.module.ecg.controller.admin.callingscreen; import cn.hutool.extra.servlet.ServletUtil; import cn.lihu.jh.framework.common.pojo.CommonResult; import cn.lihu.jh.framework.common.util.object.BeanUtils; import cn.lihu.jh.module.ecg.dal.dataobject.checktype.CheckTypeDO; import cn.lihu.jh.module.ecg.dal.dataobject.queue.QueueDO; import cn.lihu.jh.module.ecg.dal.mysql.checktype.CheckTypeMapper; import cn.lihu.jh.module.ecg.service.callingscreen.CallingScreenService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static cn.lihu.jh.framework.common.pojo.CommonResult.error; import static cn.lihu.jh.framework.common.pojo.CommonResult.success; @Tag(name = "叫号屏 ") @RestController @RequestMapping("/ecg/screen") @Validated @Slf4j public class CallingScreenController { @Resource private CallingScreenService callingScreenService; /** 用于给屏幕数据补「排队号前缀」(check_type.seq_prefix) */ @Resource private CheckTypeMapper checkTypeMapper; /** 【重叫】用于给屏幕数据补"最近一次叫号记录id"(call_patient) */ @Resource private cn.lihu.jh.module.ecg.dal.mysql.call.CallMapper callMapper; @GetMapping("/display-col-info") @Operation(summary = "列上显示的检查类型名称") @PermitAll public CommonResult>> displayColInfo() { Map> map = callingScreenService.getDisplayColInfo(); return success( map ); } @GetMapping("/big-screen-data") @Operation(summary = "大屏叫号数据") @PermitAll public CommonResult>> callingData() { Map> map = callingScreenService.getBigScreenPatient(); Map> mapVO = new HashMap<>(); // 屏幕要显示「前缀 + 排队号」,设备未登录拿不到检查项目字典,故由后端一并下发(每次请求读一次) Map seqPrefixMap = getSeqPrefixMap(); // 【重叫】一并下发"最近一次叫号记录id",屏幕据此重新播报 Map callIdMap = getLatestCallIdMap(); map.keySet().forEach( displayCol -> { //log.info("dispayCol: " + displayCol); List columnQueueDOList = map.get(displayCol); List screenQueueRespVOList = BeanUtils.toBean(columnQueueDOList, ScreenQueueRespVO.class); fillSeqPrefix(screenQueueRespVOList, seqPrefixMap); fillCallId(screenQueueRespVOList, callIdMap); mapVO.put(displayCol, screenQueueRespVOList); }); return success( mapVO ); } @GetMapping("/room-screen-data") @Operation(summary = "诊间屏数据") @PermitAll public CommonResult>> callingDataRoom(HttpServletRequest request, @RequestParam(value = "roomId", required = false)Long roomId) { String reqIp = ServletUtil.getClientIP(request); List queueDOList1 = callingScreenService.getRoomCheckRelatedPatient(reqIp, roomId); List queueDOList2 = callingScreenService.getRoomInstallRelatedPatient(reqIp, roomId); Map> mapVO = new HashMap<>(); List waitingVOList = BeanUtils.toBean(queueDOList1, ScreenQueueRespVO.class); List installVOList = BeanUtils.toBean(queueDOList2, ScreenQueueRespVO.class); // 屏幕要显示「前缀 + 排队号」,设备未登录拿不到检查项目字典,故由后端一并下发(每次请求读一次) Map seqPrefixMap = getSeqPrefixMap(); Map callIdMap = getLatestCallIdMap(); fillSeqPrefix(waitingVOList, seqPrefixMap); fillSeqPrefix(installVOList, seqPrefixMap); fillCallId(waitingVOList, callIdMap); fillCallId(installVOList, callIdMap); mapVO.put(1, waitingVOList); mapVO.put(2, installVOList); return success( mapVO ); } /** * 给屏幕数据补上「排队号显示前缀」= {@code check_type.seq_prefix}。 * *

【号统一(本需求)】排队号按检查项目各自编号,不同检查项目会出现相同数字, * 屏幕上必须带前缀才分得清(例:A5 / B5)。屏幕设备不登录、无法调用检查项目接口, * 因此在这里补齐。 * *

每次请求查一次全表建映射(检查项目只有十几个,量级很小): * 不做长期缓存,避免管理员改了前缀后屏幕一直显示旧值。 * 查不到配置时留空串——宁可只显示数字,也不要让屏幕报错或空白。 */ private void fillSeqPrefix(List voList, Map seqPrefixMap) { if (voList == null || voList.isEmpty() || seqPrefixMap == null) { return; } voList.forEach(vo -> vo.setSeqPrefix(seqPrefixMap.getOrDefault(vo.getBookCheckType(), ""))); } /* ==================== 重叫:下发"最近一次叫号记录id" ==================== */ /** * 给屏幕数据补上 {@code callId}(该患者最近一次叫号记录的 id)。 * *

为什么需要:屏幕播报靠"数据变化"触发 —— 大屏判断"某患者新出现在叫号列"、 * 诊间屏判断"诊中第一人变化"。而医生点「重叫」时**患者还是那个人、诊室还是那个诊室**, * 队列数据一点没变,两块屏自然不会再播。重叫会新增一条叫号记录(call_patient), * 把它的 id 下发后,屏幕只要发现 callId 变了就重新播报。 */ private void fillCallId(List voList, Map callIdMap) { if (voList == null || voList.isEmpty() || callIdMap == null || callIdMap.isEmpty()) { return; } voList.forEach(vo -> { if (null != vo.getPatId()) { vo.setCallId(callIdMap.get(vo.getPatId())); } }); } /** 一次查询取到「患者编号 → 最近一次叫号记录 id」;失败时返回空映射(屏幕按老逻辑播报) */ private Map getLatestCallIdMap() { try { Map map = new HashMap<>(); for (Map row : callMapper.selectLatestCallIds()) { Object patId = row.get("patId"); Object callId = row.get("callId"); if (null != patId && callId instanceof Number) { map.put(String.valueOf(patId), ((Number) callId).longValue()); } } return map; } catch (Exception e) { log.error("[getLatestCallIdMap] 读取最近叫号记录失败,重叫将不会触发屏幕重播", e); return new HashMap<>(); } } /** 读一次检查项目配置,得到「检查项目值 → 排队号前缀」映射;失败时返回空映射(屏幕只显示号) */ private Map getSeqPrefixMap() { try { return checkTypeMapper.simpleCheckTypeList().stream() .filter(checkType -> null != checkType.getValue()) .collect(Collectors.toMap(CheckTypeDO::getValue, checkType -> null == checkType.getSeqPrefix() ? "" : checkType.getSeqPrefix(), (a, b) -> a)); } catch (Exception e) { log.error("[getSeqPrefixMap] 读取检查项目前缀失败,屏幕将只显示号", e); return new HashMap<>(); } } }