From 68ff33beff11310e830b0615b5a81f83fad0f683 Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期日, 08 十一月 2026 23:33:14 +0800
Subject: [PATCH] ai优化

---
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/room/RoomServiceImpl.java |  403 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 403 insertions(+), 0 deletions(-)

diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/room/RoomServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/room/RoomServiceImpl.java
index 532d6de..01e9c09 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/room/RoomServiceImpl.java
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/room/RoomServiceImpl.java
@@ -3,9 +3,14 @@
 import java.util.*;
 import javax.annotation.Resource;
 
+import cn.lihu.jh.framework.common.exception.ErrorCode;
+import cn.lihu.jh.framework.common.exception.enums.GlobalErrorCodeConstants;
 import cn.lihu.jh.framework.common.pojo.PageResult;
+import cn.lihu.jh.module.ecg.utils.IpUtils;
 import cn.lihu.jh.module.ecg.controller.admin.room.vo.MonitorInfoVO;
+import cn.lihu.jh.module.ecg.controller.admin.room.vo.RoomSeatRespVO;
 import cn.lihu.jh.module.ecg.dal.dataobject.room.RoomDO;
+import cn.lihu.jh.module.ecg.dal.dataobject.queue.QueueDO;
 import cn.lihu.jh.module.ecg.dal.dataobject.room.RoomProfile;
 import cn.lihu.jh.module.ecg.enums.RoomCallingScreenEnum;
 import cn.lihu.jh.module.ecg.service.queue.QueueService;
@@ -15,12 +20,16 @@
 
 import cn.lihu.jh.module.ecg.controller.admin.room.vo.RoomPageReqVO;
 import cn.lihu.jh.module.ecg.controller.admin.room.vo.RoomSaveReqVO;
+import cn.lihu.jh.module.ecg.controller.admin.room.vo.RoomSelectBedRespVO;
 import cn.lihu.jh.module.ecg.dal.mysql.room.RoomMapper;
 import cn.lihu.jh.module.ecg.enums.BedStatusEnum;
 import cn.lihu.jh.framework.common.util.object.BeanUtils;
+import lombok.extern.slf4j.Slf4j;
 
 import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.ROOM_INVALID_STATUS;
 import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.ROOM_NOT_EXISTS;
+import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.ROOM_NOT_OWNER;
 
 /**
  * 璇婂鍜岃瘖鐤楀簥 Service 瀹炵幇绫�
@@ -29,6 +38,7 @@
  */
 @Service
 @Validated
+@Slf4j
 public class RoomServiceImpl implements RoomService {
 
     @Resource
@@ -39,6 +49,10 @@
 
     @Resource
     QueueService queueService;
+
+    /** 銆愪富/鍥磋銆戞寜鎮h�呭弽鏌ュ伐浣嶅仛涓讳汉鏍¢獙鏃堕渶瑕佽 queue 琛� */
+    @Resource
+    private cn.lihu.jh.module.ecg.dal.mysql.queue.QueueMapper queueMapper;
 
     @Override
     public Integer createRoom(RoomSaveReqVO createReqVO) {
@@ -141,6 +155,395 @@
         return roomMapper.selectPage(pageReqVO);
     }
 
+    /**
+     * 銆岄�夋嫨宸ヤ綅妯″紡銆�- 鎸夋湰鏈篒P鍖归厤宸ヤ綅銆�
+     * <p>鎺掑簭锛堝喅瀹氳嚜鍔ㄥ叆搴ч�夊摢涓�涓級锛氣憼 鏈汉宸插崰鐢紙鍒锋柊/閲嶈繘鐩存帴鎭㈠锛夆啋 鈶� 绌洪棽涓斿伐浣嶅彿鏈�灏�
+     * 鈫� 鈶� 琚粬浜哄崰鐢紙鍓嶇浼氭彁绀�"璇P瀵瑰簲宸ヤ綅宸茶XX鍗犵敤"锛岃浜哄伐澶勭悊锛夈��</p>
+     */
+    @Override
+    public List<RoomSelectBedRespVO.RoomSelectBedItem> matchBedsByIp(String ip, Long docId) {
+        String normalized = IpUtils.normalize(ip);
+        if (!IpUtils.isBindableIp(normalized)) {
+            return Collections.emptyList();
+        }
+        List<RoomDO> list = roomMapper.queueByIp(normalized);
+        if (list == null || list.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<RoomSelectBedRespVO.RoomSelectBedItem> items = new ArrayList<>(list.size());
+        for (RoomDO roomDO : list) {
+            RoomSelectBedRespVO.RoomSelectBedItem item = new RoomSelectBedRespVO.RoomSelectBedItem();
+            item.setId(roomDO.getId());
+            item.setRoomId(roomDO.getRoomId());
+            item.setRoomName(roomDO.getRoomName());
+            item.setBedNo(roomDO.getBedNo());
+            item.setIp(roomDO.getIp());
+            item.setDocId(roomDO.getDocId());
+            item.setDocName(roomDO.getDocName());
+            item.setOpType(roomDO.getOpType());
+            item.setCheckTypes(roomDO.getCheckTypes());
+            item.setStatus(roomDO.getStatus());
+            item.setOccupied(roomDO.getDocId() != null);
+            item.setMine(docId != null && docId.equals(roomDO.getDocId()));
+            items.add(item);
+        }
+        // 鎺掑簭锛氭湰浜哄凡鍗犵敤(0) 鈫� 绌洪棽(1) 鈫� 琚粬浜哄崰鐢�(2)锛涘悓妗f寜宸ヤ綅鍙�
+        items.sort(Comparator
+                .comparingInt((RoomSelectBedRespVO.RoomSelectBedItem i) -> {
+                    if (Boolean.TRUE.equals(i.getMine())) return 0;
+                    if (!Boolean.TRUE.equals(i.getOccupied())) return 1;
+                    return 2;
+                })
+                .thenComparing(RoomSelectBedRespVO.RoomSelectBedItem::getBedNo,
+                        Comparator.nullsLast(Comparator.naturalOrder())));
+        return items;
+    }
+
+    @Override
+    public Integer bindIpToBed(Integer id, String ip) {
+        // 鍥炵幆/鏈寚瀹�/闈炴硶鍦板潃缁戜笂鍘绘病鏈夋剰涔夛紙127.x銆�::1銆�0.0.0.0锛夛紝杩樹細璁╁悗缁尮閰嶅け鏁�
+        if (!IpUtils.isBindableIp(ip)) {
+            return 0;
+        }
+        Integer rows = roomMapper.updateIpById(id, IpUtils.normalize(ip));
+        log.info("[bindIpToBed][鎶婃湰鏈篒P缁戝畾鍒板伐浣峕 id={} ip={} 褰卞搷琛屾暟={}", id, ip, rows);
+        return rows;
+    }
+
+    @Override
+    public List<RoomDO> listIpBindings(String ip, Integer excludeId) {
+        if (!IpUtils.isBindableIp(ip)) {
+            return Collections.emptyList();
+        }
+        List<RoomDO> list = roomMapper.listByIpExcludeId(IpUtils.normalize(ip), excludeId);
+        return list == null ? Collections.emptyList() : list;
+    }
+
+    @Override
+    public RoomSeatRespVO autoSeatByIp(String ip, Long docId, String docName) {
+        RoomSeatRespVO resp = new RoomSeatRespVO();
+        String clientIp = IpUtils.normalize(ip);
+        resp.setClientIp(clientIp);
+
+        // 鈶� 鏈満IP涓嶅彲鐢紙鍥炵幆 / IPv6 / 鏈寚瀹� / 闈炴硶 / **鏈嶅姟鍣ㄨ嚜韬湴鍧�**锛夆啋 涓嶈兘浣滀负宸ヤ綅鏍囪瘑
+        if (!IpUtils.isBindableIp(clientIp)) {
+            // 鍖哄垎"璇嗗埆鍒扮殑鏄湇鍔″櫒鑷韩鍦板潃"涓庡叾瀹冧笉鍙敤鎯呭喌锛氬墠鑰呯幇鍦烘渶甯歌锛堝湪鏈嶅姟鍣ㄤ笂/杩滅▼妗岄潰閲岃闂級锛�
+            // 鎻愮ず璇鑳界洿鎺ユ寚鍚戣В鍐冲姙娉曪紝鑰屼笉鏄鎺掓煡鐨勪汉浠ヤ负鏄唬鐮佸潖浜嗐��
+            resp.setReason(IpUtils.isLocalAddress(clientIp) ? "ip_is_server" : "ip_invalid");
+            log.info("[autoSeatByIp] 鏈満IP涓嶅彲鐢紝涓嶈嚜鍔ㄥ叆搴�. clientIp={} docId={} 鏄湇鍔″櫒鑷韩鍦板潃={}",
+                    clientIp, docId, IpUtils.isLocalAddress(clientIp));
+            return resp;
+        }
+
+        // 宸叉寜銆屾湰浜哄凡鍗犵敤 鈫� 绌洪棽 鈫� 琚粬浜哄崰鐢ㄣ�嶆帓搴�
+        List<RoomSelectBedRespVO.RoomSelectBedItem> beds = matchBedsByIp(clientIp, docId);
+        if (beds.isEmpty()) {
+            // 璇� IP 娌℃湁瀵瑰簲浠讳綍宸ヤ綅锛氬伐浣嶆病褰� IP锛堢幇鍦哄涓� 0.0.0.0锛夛紝鎴栧伐浣嶅凡鍏抽棴
+            resp.setReason("nomatch");
+            log.info("[autoSeatByIp] 璇P娌℃湁鍖归厤鍒板伐浣嶏紙宸ヤ綅鏈綍IP / 宸插叧闂級. clientIp={} docId={}", clientIp, docId);
+            return resp;
+        }
+
+        // 鈶� 宸茬粡鏄垜鐨勫伐浣� 鈫� 骞傜瓑鎭㈠锛堝埛鏂�/閲嶈繘/涓婃娌℃甯哥搴ч兘璧拌繖鏉★級
+        RoomSelectBedRespVO.RoomSelectBedItem mine = beds.stream()
+                .filter(b -> Boolean.TRUE.equals(b.getMine())).findFirst().orElse(null);
+        if (null != mine) {
+            return doSeat(mine.getId(), mine.getRoomId(), mine.getBedNo(), docId, docName, resp, "mine");
+        }
+
+        // 鈶� 绌洪棽宸ヤ綅锛�**鎭板ソ涓�涓�**鎵嶈嚜鍔ㄥ叆搴�
+        List<RoomSelectBedRespVO.RoomSelectBedItem> free = beds.stream()
+                .filter(b -> !Boolean.TRUE.equals(b.getOccupied())).toList();
+        if (free.size() == 1) {
+            return doSeat(free.get(0).getId(), free.get(0).getRoomId(), free.get(0).getBedNo(),
+                    docId, docName, resp, "free");
+        }
+        if (free.size() > 1) {
+            // 杩欏彴鏈哄櫒瀵瑰簲澶氫釜绌洪棽宸ヤ綅 鈫� 鍧愰敊鐨勯闄╁ぇ浜庝究鍒╋紝浜や汉宸ョ偣閫�
+            resp.setReason("multi");
+            log.info("[autoSeatByIp] 璇P瀵瑰簲 {} 涓┖闂插伐浣嶏紝鏃犳硶纭畾鏄摢涓�涓紝浜や汉宸ラ�夋嫨. clientIp={}", free.size(), clientIp);
+            return resp;
+        }
+
+        // 鈶� 鍏ㄨ浠栦汉鍗犵敤 鈫� **涓嶈嚜鍔ㄦ尋鎺�**锛屼絾鎶婂�欓�夊伐浣嶄笌鍗犵敤浜哄甫鍥炲幓锛�
+        //    渚涘墠绔脊銆岃宸ヤ綅鐢� xxx 鍗犵敤锛屾槸鍚︽帴绠★紵銆嶏紙鏈渶姹傦細鎺ョ彮鍖荤敓鑷姪鎺ョ锛夈��
+        RoomSelectBedRespVO.RoomSelectBedItem occupied = beds.get(0);
+        resp.setReason("occupied");
+        resp.setOwnerName(occupied.getDocName());
+        // 銆愭湰闇�姹傘�戣ˉ榻愬�欓�夊伐浣嶄俊鎭細鍓嶇鍑繖浜涘瓧娈佃皟 /clinic/room/take-over-bed
+        resp.setId(occupied.getId());
+        resp.setRoomId(occupied.getRoomId());
+        resp.setRoomName(occupied.getRoomName());
+        resp.setBedNo(occupied.getBedNo());
+        resp.setIp(occupied.getIp());
+        resp.setDocId(occupied.getDocId());
+        resp.setDocName(occupied.getDocName());
+        resp.setCheckTypes(occupied.getCheckTypes());
+        resp.setOpType(occupied.getOpType());
+        log.info("[autoSeatByIp] 璇P瀵瑰簲鐨勫伐浣嶅凡琚粬浜哄崰鐢紝绛夊緟鍓嶇纭鏄惁鎺ョ. clientIp={} 宸ヤ綅={}/{} 鍗犵敤浜�={}({})",
+                clientIp, occupied.getRoomId(), occupied.getBedNo(), occupied.getDocName(), occupied.getDocId());
+        return resp;
+    }
+
+    /** 鎵ц鍏ュ骇骞跺洖濉粨鏋滐紙鍐呴儴鏂规硶锛屼緵 autoSeatByIp 鍚勫垎鏀鐢級 */
+    private RoomSeatRespVO doSeat(Integer bedId, Long roomId, String bedNo, Long docId, String docName,
+                                  RoomSeatRespVO resp, String branch) {
+        // 浼� bedId锛氬叆搴т紭鍏堟寜涓婚敭瀹氫綅锛岄伩鍏� bed_no 涓庡簱鍐呭�兼湁鑲夌溂闅捐鲸宸紓鏃舵洿鏂� 0 琛�
+        ErrorCode ec = queueService.startBedDoctorOn(roomId, bedNo, docId, docName, bedId);
+        if (!GlobalErrorCodeConstants.SUCCESS.equals(ec)) {
+            resp.setReason("error");
+            log.warn("[autoSeatByIp] 鍏ュ骇鏈敓鏁堬紙{}锛�. roomId={} bedNo={} docId={}", branch, roomId, bedNo, docId);
+            return resp;
+        }
+        fillSeatInfo(resp, roomMapper.getRoom(roomId, bedNo));
+        resp.setSeated(true);
+        log.info("[autoSeatByIp] 鑷姩鍏ュ骇鎴愬姛锛坽}锛�. docId={} roomId={} bedNo={}", branch, docId, roomId, bedNo);
+        return resp;
+    }
+
+    @Override
+    public RoomSeatRespVO getMySeat(Long docId) {
+        RoomSeatRespVO resp = new RoomSeatRespVO();
+        if (null == docId) {
+            return resp;
+        }
+        List<RoomDO> beds = roomMapper.getRoomByDocId(docId);
+        if (null == beds || beds.isEmpty()) {
+            return resp;
+        }
+        if (beds.size() > 1) {
+            // 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戝�肩彮鍖荤敓鍙悓鏃跺崰澶氫釜宸ヤ綅锛岃繖閲屼笉鍐嶆槸寮傚父鍦烘櫙锛�
+            // 鏈帴鍙e彧涓哄吋瀹规棫鍓嶇/鍏跺畠璋冪敤锛堣繑鍥炵涓�涓級锛屽畬鏁村垪琛ㄧ敤 getMySeats()銆�
+            log.info("[getMySeat] 璇ュ尰鐢熷崰鐢ㄤ簡 {} 涓伐浣嶏紝鏈帴鍙h繑鍥炵涓�涓紙瀹屾暣鍒楄〃瑙� /my-seats锛�. docId={}",
+                    beds.size(), docId);
+        }
+        fillSeatInfo(resp, beds.get(0));
+        resp.setSeated(true);
+        return resp;
+    }
+
+    @Override
+    public List<RoomSeatRespVO> getMySeats(Long docId) {
+        List<RoomSeatRespVO> result = new ArrayList<>();
+        if (null == docId) {
+            return result;
+        }
+        // 鍙彇銆屽尰鐢熷湪搴� / 鍖荤敓鏆傚仠銆嶄笖鏈垹闄ょ殑宸ヤ綅锛堟帓闄ゅ巻鍙叉畫鐣欙級
+        List<Integer> statusList = new ArrayList<>();
+        statusList.add(BedStatusEnum.DOCTOR_ON.getStatus());
+        statusList.add(BedStatusEnum.DOCTOR_PAUSE.getStatus());
+        List<RoomDO> beds = roomMapper.getMyActiveBeds(docId, statusList);
+        if (null == beds || beds.isEmpty()) {
+            return result;
+        }
+        for (RoomDO bed : beds) {
+            RoomSeatRespVO resp = new RoomSeatRespVO();
+            fillSeatInfo(resp, bed);
+            resp.setSeated(true);
+            result.add(resp);
+        }
+        return result;
+    }
+
+    /**
+     * 銆愭湰闇�姹偮锋帴鐝嚜鍔╂帴绠°�戞妸宸ヤ綅浠�"鍒汉鍗犵敤"鏀逛负"褰撳墠鐧诲綍浜哄崰鐢�"銆�
+     *
+     * <p>杩欐槸"鐧诲嚭涓嶉噴鏀惧伐浣�"鍦烘櫙涓嬶紝鎺ョ彮鍖荤敓绔嬪嵆鐢ㄤ笂宸ヤ綅鐨勫敮涓�鍏ュ彛锛堜笉闇�瑕佺鐞嗗憳锛夈��
+     * 鍘熷崰鐢ㄤ汉閭e彴鐢佃剳浼氬湪涓嬩竴娆� 5s 杞鏀跺埌銆岃閲嶆柊灏卞潗銆嶅苟杞彧璇伙紙鐜版湁閫昏緫锛夈��
+     *
+     * <p>銆屽己鍒舵竻绌� 鈫� 鎴戝叆搴с�嶅湪鍚屼竴浜嬪姟鍐呭畬鎴愶紝閬垮厤涓棿鎬佽绗笁鏂规姠鍒般��
+     */
+    @Override
+    @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class)
+    public void takeOverBed(Long roomId, String bedNo) {
+        Long userId = cn.lihu.jh.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId();
+        String userNickname = cn.lihu.jh.framework.security.core.util.SecurityFrameworkUtils.getLoginUserNickname();
+        if (null == userId) {
+            throw exception(ROOM_NOT_OWNER);
+        }
+        if (null == roomId || null == bedNo || bedNo.isEmpty()) {
+            throw exception(ROOM_NOT_EXISTS);
+        }
+        RoomDO bed = roomMapper.getRoom(roomId, bedNo);
+        if (null == bed) {
+            throw exception(ROOM_NOT_EXISTS);
+        }
+
+        // 鈶� 鏈潵灏卞睘浜庢垜 鈫� 骞傜瓑鎴愬姛
+        if (null != bed.getDocId() && bed.getDocId().equals(userId)) {
+            log.info("[takeOverBed] 宸ヤ綅鏈氨灞炰簬褰撳墠鐧诲綍浜猴紝鏃犻渶鎺ョ. 宸ヤ綅={}/{} docId={}", roomId, bedNo, userId);
+            return;
+        }
+
+        // 鈶� 绌洪棽 鈫� 鐩存帴鍏ュ骇锛�"鎺ョ"绛変环浜�"鍧愪笂鍘�"锛岀渷鎺夊墠绔啀鐐逛竴娆″叆搴э級
+        if (null == bed.getDocId()) {
+            ErrorCode onRet = queueService.startBedDoctorOn(roomId, bedNo, userId, userNickname, bed.getId());
+            if (!GlobalErrorCodeConstants.SUCCESS.equals(onRet)) {
+                log.warn("[takeOverBed] 绌洪棽宸ヤ綅鍏ュ骇澶辫触. 宸ヤ綅={}/{} ret={}", roomId, bedNo, onRet);
+                throw exception(ROOM_INVALID_STATUS);
+            }
+            return;
+        }
+
+        // 鈶� 琚粬浜哄崰鐢� 鈫� 瀹¤鏃ュ織 + 寮哄埗娓呯┖ + 绔嬪嵆鍏ュ骇
+        log.warn("[takeOverBed][鎺ョ彮鎺ョ] 宸ヤ綅={}/{} 鍘熷崰鐢ㄤ汉={}({}) 鈫� 鎺ョ浜�={}({})",
+                roomId, bedNo, bed.getDocName(), bed.getDocId(), userNickname, userId);
+        ErrorCode offRet = queueService.startBedDoctorOffByAdmin(roomId, bedNo);
+        if (!GlobalErrorCodeConstants.SUCCESS.equals(offRet)) {
+            log.warn("[takeOverBed] 鎺ョ鏃舵竻绌哄師鍗犵敤浜哄け璐�. 宸ヤ綅={}/{} ret={}", roomId, bedNo, offRet);
+            throw exception(ROOM_INVALID_STATUS);
+        }
+        ErrorCode onRet = queueService.startBedDoctorOn(roomId, bedNo, userId, userNickname, bed.getId());
+        if (!GlobalErrorCodeConstants.SUCCESS.equals(onRet)) {
+            log.warn("[takeOverBed] 鎺ョ鍚庡叆搴уけ璐�. 宸ヤ綅={}/{} ret={}", roomId, bedNo, onRet);
+            throw exception(ROOM_INVALID_STATUS);
+        }
+        log.info("[takeOverBed][鎺ョ彮鎺ョ] 瀹屾垚. 宸ヤ綅={}/{} 鏂板崰鐢ㄤ汉={}({})", roomId, bedNo, userNickname, userId);
+    }
+
+    @Override
+    public void assertBedOwner(Long roomId, String bedNo) {
+        Long userId = cn.lihu.jh.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId();
+        RoomDO bed = (null == roomId || null == bedNo || bedNo.isEmpty())
+                ? null : roomMapper.getRoom(roomId, bedNo);
+        if (null == bed) {
+            log.warn("[assertBedOwner] 宸ヤ綅涓嶅瓨鍦紝鎷掔粷鍐欐搷浣�. roomId={} bedNo={} docId={}", roomId, bedNo, userId);
+            throw exception(ROOM_NOT_OWNER);
+        }
+        if (null == bed.getDocId() || !bed.getDocId().equals(userId)) {
+            log.warn("[assertBedOwner] 闈炲伐浣嶄富浜猴紝鎷掔粷鍐欐搷浣滐紙鍥磋妯″紡锛�. roomId={} bedNo={} 鎴�={} 涓讳汉={}({})",
+                    roomId, bedNo, userId, bed.getDocName(), bed.getDocId());
+            throw exception(ROOM_NOT_OWNER);
+        }
+    }
+
+    @Override
+    public void assertBedOwnerByPatient(String patId, Integer checkType) {
+        QueueDO queue = resolvePatientBedQueue(patId, checkType);
+        if (null == queue) {
+            log.warn("[assertBedOwnerByPatient] 鎵句笉鍒拌鎮h�呭綋鍓嶆墍鍦ㄥ伐浣嶏紝鎷掔粷鍐欐搷浣�. patId={} checkType={}",
+                    patId, checkType);
+            throw exception(ROOM_NOT_OWNER);
+        }
+        assertBedOwner(queue.getRoomId(), queue.getBedNo());
+    }
+
+    @Override
+    public void assertBedOwnerByPatientSoft(String patId, Integer checkType) {
+        QueueDO queue = resolvePatientBedQueue(patId, checkType);
+        if (null == queue) {
+            // 纭垂/鍙栨秷纭垂甯稿湪娴佺▼鏈璋冪敤锛屾偅鑰呭彲鑳藉凡涓嶅湪宸ヤ綅闃熷垪涓婏紱
+            // 涓�寰嬫嫆缁濅細璇激姝e父涓氬姟锛岃繖閲屽彧璁拌鍛婃斁琛岋紙鍓嶇鍥磋妯″紡涓嬫寜閽凡绂佺敤锛夈��
+            log.warn("[assertBedOwnerByPatientSoft] 鎵句笉鍒拌鎮h�呭綋鍓嶆墍鍦ㄥ伐浣嶏紝鏀捐锛堜粎璁拌鍛婏級. patId={} checkType={}",
+                    patId, checkType);
+            return;
+        }
+        assertBedOwner(queue.getRoomId(), queue.getBedNo());
+    }
+
+    @Override
+    public void assertBedOwnerIs(Long roomId, String bedNo, Long ownerDocId) {
+        RoomDO bed = (null == roomId || null == bedNo || bedNo.isEmpty())
+                ? null : roomMapper.getRoom(roomId, bedNo);
+        if (null == bed || null == bed.getDocId() || !bed.getDocId().equals(ownerDocId)) {
+            log.warn("[assertBedOwnerIs] 宸ヤ綅褰撳墠涓讳汉涓庤姹傜殑 ownerDocId 涓嶄竴鑷达紝鎷掔粷. roomId={} bedNo={} 璇锋眰={} 瀹為檯={}",
+                    roomId, bedNo, ownerDocId, null == bed ? null : bed.getDocId());
+            throw exception(ROOM_NOT_OWNER);
+        }
+    }
+
+    /** 鎸夈�屾偅鑰� + 妫�鏌ラ」鐩�嶆壘褰撳墠鎵�鍦ㄥ伐浣嶇殑閭f潯闃熷垪琛岋紱鎵句笉鍒板伐浣嶈繑鍥� null */
+    private QueueDO resolvePatientBedQueue(String patId, Integer checkType) {
+        if (null == patId) {
+            return null;
+        }
+        QueueDO queue = queueMapper.getQueueByPatId(patId, checkType);
+        if (null == queue || null == queue.getRoomId() || null == queue.getBedNo()
+                || queue.getBedNo().trim().isEmpty()) {
+            return null;
+        }
+        return queue;
+    }
+
+    @Override
+    public Map<String, Object> diagnoseBed(Integer id, Long roomId, String bedNo) {
+        Map<String, Object> data = new LinkedHashMap<>();
+        String condition = String.format("id=%s, roomId=%s, bedNo=[%s](len=%s)",
+                id, roomId, bedNo, null == bedNo ? null : bedNo.length());
+        data.put("鏌ヨ鏉′欢", condition);
+
+        List<Map<String, Object>> rows = roomMapper.selectBedRawState(id, roomId, bedNo);
+        data.put("鍖归厤鍒扮殑琛屾暟", rows.size());
+        data.put("琛屾槑缁�", rows);
+
+        String verdict;
+        if (rows.isEmpty()) {
+            verdict = "搴撻噷銆愭煡涓嶅埌銆戣繖涓伐浣嶏紙鎸� id 涓� room_id+TRIM(bed_no) 閮芥病鍖归厤鍒帮級鈫� "
+                    + "鎸� roomId+bedNo 鍏ュ骇蹇呯劧鏇存柊 0 琛屻�佹姤鈥滆瘖瀹ゅ拰璇婄枟搴婄姸鎬佸紓甯糕�濄��"
+                    + "鏂扮増宸叉敮鎸佹寜 id 鍏ュ骇锛涜嫢浠嶅け璐ワ紝璇锋妸鏈粨鏋滃彂鍥炪��";
+        } else {
+            Map<String, Object> row = rows.get(0);
+            Integer rowStatus = toInt(row.get("status"));
+            Integer rowDeleted = toInt(row.get("deleted"));
+            Integer bedNoLen = toInt(row.get("bed_no_len"));
+            Object rowDocId = row.get("doc_id");
+            if (null != rowDeleted && 0 != rowDeleted) {
+                verdict = "璇ュ伐浣嶅湪搴撻噷鏄�愬凡鍒犻櫎銆�(deleted=1) 鈫� 鍏ュ骇涓嶄細鍛戒腑锛岃鎭㈠鏁版嵁鎴栭噸寤哄伐浣嶃��";
+            } else if (null != bedNoLen && null != bedNo && bedNoLen != bedNo.length()) {
+                verdict = String.format("搴撻噷 bed_no 鐨勯暱搴�(%d)涓庤姹傚��(%d)涓嶄竴鑷� 鈫� 璇锋眰閲岀殑宸ヤ綅缂栧彿涓庡簱鍐呬笉鍚�"
+                                + "锛堝父瑙佹槸缁撳熬绌烘牸/鍏ㄨ锛夛紝HEX=%s銆傛柊鐗堝凡鏀逛负鎸� id 鍏ュ骇锛屽彲缁曞紑璇ラ棶棰樸��",
+                        bedNoLen, bedNo.length(), row.get("bed_no_hex"));
+            } else if (null == rowStatus || (10 != rowStatus && 20 != rowStatus && 30 != rowStatus)) {
+                verdict = "璇ュ伐浣嶇姸鎬�=" + rowStatus + "锛�0=宸插叧闂級锛涗笉鍦ㄥ彲鍏ュ骇鐘舵�侊紙鍙叆搴х殑涓� 10/20/30锛夛紝"
+                        + "璇峰厛鍦ㄥ紑璇婅缃�/鐩戞帶椤垫妸瀹冨紑閫氥��";
+            } else if (null != rowDocId) {
+                verdict = "璇ュ伐浣嶅綋鍓嶇殑涓讳汉鏄��" + row.get("doc_name") + "銆�(doc_id=" + rowDocId + ")锛�"
+                        + "鑻ヨ繖灏辨槸浣犳湰浜猴紝璇存槑涓婃娌℃甯哥搴� 鈥斺�� 鏂扮増宸叉敮鎸佸箓绛夋仮澶嶅叆搴э紱"
+                        + "鑻ユ槸鍒汉锛屽垯涓嶈兘鍏ュ骇锛堜笉鎸ゆ帀姝e湪鎿嶄綔鐨勪汉锛夈��";
+            } else {
+                verdict = "璇ュ伐浣嶅綋鍓嶃�愬彲鍏ュ骇銆戙�傝嫢涔嬪墠浠嶆姤鈥滅姸鎬佸紓甯糕�濓紝璇锋妸鏈粨鏋滆繛鍚岄偅娆¤姹傚弬鏁颁竴璧峰彂鍥炪��";
+            }
+        }
+        data.put("璇婃柇缁撹", verdict);
+        log.info("[diagnoseBed][宸ヤ綅鐘舵�佽瘖鏂璢 {} 鈫� {}", condition, verdict);
+        return data;
+    }
+
+    /** 鍏煎 bit(1)/Boolean/Number 鐨勫彇鍊硷紙璇婃柇鎺ュ彛鐢級 */
+    private Integer toInt(Object v) {
+        if (null == v) {
+            return null;
+        }
+        if (v instanceof Boolean) {
+            return ((Boolean) v) ? 1 : 0;
+        }
+        if (v instanceof Number) {
+            return ((Number) v).intValue();
+        }
+        try {
+            return Integer.valueOf(String.valueOf(v).trim());
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /** 鎶婂伐浣嶅瓧娈垫嫹杩涘搷搴斾綋 */
+    private void fillSeatInfo(RoomSeatRespVO resp, RoomDO bed) {
+        if (null == bed) {
+            return;
+        }
+        resp.setId(bed.getId());
+        resp.setRoomId(bed.getRoomId());
+        resp.setRoomName(bed.getRoomName());
+        resp.setBedNo(bed.getBedNo());
+        resp.setIp(bed.getIp());
+        resp.setStatus(bed.getStatus());
+        resp.setDocId(bed.getDocId());
+        resp.setDocName(bed.getDocName());
+        resp.setCheckTypes(bed.getCheckTypes());
+        resp.setOpType(bed.getOpType());
+    }
+
     @Override
     public List<RoomDO> simpleRoomList() {
         List<BedStatusEnum> bedStatusEnumList = new ArrayList<BedStatusEnum>();

--
Gitblit v1.9.3