| | |
| | | @Mapper |
| | | public interface RoomMapper extends BaseMapperX<RoomDO> { |
| | | |
| | | /** |
| | | * 诊室工位分页(诊室管理列表 / 导出共用)。 |
| | | * |
| | | * <p>排序(本需求):**诊室编号升序 → 工位号升序**,同一诊室有多个工位时顺序稳定。 |
| | | * 原实现是 {@code orderByDesc(id)}(后加的排最前),与"按诊室编号看"的现场习惯不符。 |
| | | */ |
| | | default PageResult<RoomDO> selectPage(RoomPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<RoomDO>() |
| | | .eqIfPresent(RoomDO::getRoomId, reqVO.getRoomId()) |
| | | .eqIfPresent(RoomDO::getBedNo, reqVO.getBedNo()) |
| | | .betweenIfPresent(RoomDO::getCreateTime, reqVO.getCreateTime()) |
| | | .orderByDesc(RoomDO::getId)); |
| | | .orderByAsc(RoomDO::getRoomId) |
| | | .orderByAsc(RoomDO::getBedNo)); |
| | | } |
| | | |
| | | @Select("select * from lihu.clinic_room where ip = #{ip}") |
| | | /** |
| | | * 按 IP 查该 IP 下**可用**的工位(供"按IP自动匹配工位"使用)。 |
| | | * |
| | | * <p>三条过滤缺一不可: |
| | | * <ul> |
| | | * <li>{@code deleted = 0}:原实现是裸查,已删除的工位也会被匹配到—— |
| | | * 一旦某 IP 被回收再分配给新工位,就会自动入座到历史脏工位上;</li> |
| | | * <li>{@code status != 0(已关闭)}:已关闭的工位不该被自动入座(否则人坐上去却没有候诊队列,看着像"没病人");</li> |
| | | * <li>{@code ip <> ''}:空 IP 不做匹配(避免历史空值行被扫到)。</li> |
| | | * </ul> |
| | | * 状态取值见 {@link cn.lihu.jh.module.ecg.enums.BedStatusEnum}:0已关闭 / 10已开通 / 20有医生 / 30暂停。</p> |
| | | */ |
| | | @Select("select * from lihu.clinic_room " + |
| | | " where ip = #{ip} and deleted = 0 and coalesce(status, 0) <> 0") |
| | | @Results({ |
| | | @Result(property = "checkTypes", column = "check_types", typeHandler = com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class) |
| | | }) |
| | | List<RoomDO> queueByIp(@Param("ip") String ip); |
| | | |
| | | /** |
| | | * 该 IP 是否已绑定在**别的**工位上(用于"选择工位模式"里写 IP 前的冲突检测)。 |
| | | * <p>一个工位只有一个 ip 字段,若两台电脑走同一出口 IP,后绑定的会把前面的抢走, |
| | | * 所以覆盖前要先让用户确认(前端拿到冲突工位后弹确认,再带 force 重调)。</p> |
| | | * |
| | | * @param ip 待绑定的 IP |
| | | * @param excludeId 排除的工位主键(通常是本次要绑定的那个),可为空 |
| | | */ |
| | | @Select("<script> " + |
| | | "SELECT * FROM lihu.clinic_room " + |
| | | " WHERE deleted = 0 AND ip = #{ip} " + |
| | | " <if test='excludeId != null'> AND id != #{excludeId} </if> " + |
| | | " ORDER BY id" + |
| | | "</script>") |
| | | @Results({ |
| | | @Result(property = "checkTypes", column = "check_types", typeHandler = com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class) |
| | | }) |
| | | List<RoomDO> listByIpExcludeId(@Param("ip") String ip, @Param("excludeId") Integer excludeId); |
| | | |
| | | /** |
| | | * 把本机 IP 写到指定工位(只改 ip 一个字段,供"选择工位模式 2/3"使用)。 |
| | | */ |
| | | @Update("update lihu.clinic_room set ip = #{ip} where id = #{id} and deleted = 0") |
| | | Integer updateIpById(@Param("id") Integer id, @Param("ip") String ip); |
| | | |
| | | @Update("<script> " + |
| | | "update lihu.clinic_room set status=#{newStatus}, doc_id=null, doc_name=null " + |
| | |
| | | |
| | | @Select("SELECT * FROM lihu.clinic_room where doc_id=#{docId}") |
| | | List<RoomDO> getRoomByDocId(@Param("docId")Long docId); |
| | | |
| | | /** |
| | | * 【本需求·一人多工位】该医生**当前有效**占用的全部工位。 |
| | | * |
| | | * <p>比 {@link #getRoomByDocId} 多了两个过滤: |
| | | * <ul> |
| | | * <li>{@code deleted = 0}:排除历史逻辑删除行(原 SQL 没有,可能返回脏行);</li> |
| | | * <li>{@code status in (20,30)}:只取「医生在座(DOCTOR_ON) / 医生暂停(DOCTOR_PAUSE)」, |
| | | * 排除数据不一致残留的"doc_id 还在但状态已回空闲"。两个值以常量传入,避免硬编码。</li> |
| | | * </ul> |
| | | */ |
| | | @Select("<script> " + |
| | | "SELECT * FROM lihu.clinic_room where doc_id = #{docId} and deleted = 0 " + |
| | | " and status in ( " + |
| | | " <foreach collection='statusList' separator=',' item='st'>#{st}</foreach> " + |
| | | " ) order by room_id, bed_no " + |
| | | "</script>") |
| | | List<RoomDO> getMyActiveBeds(@Param("docId") Long docId, @Param("statusList") List<Integer> statusList); |
| | | |
| | | /** |
| | | * 【本需求·统计按人合并】当前**在座医生数**(按 doc_id 去重)。 |
| | | * |
| | | * <p>一人多工位后,"在座工位数"会按工位累计(数值本身正确), |
| | | * 但监控页还需要"到底几个医生在岗",用它补一个指标。 |
| | | */ |
| | | @Select("<script> " + |
| | | "select count(distinct doc_id) from lihu.clinic_room " + |
| | | " where doc_id is not null and deleted = 0 and status in ( " + |
| | | " <foreach collection='statusList' separator=',' item='st'>#{st}</foreach> " + |
| | | " ) " + |
| | | "</script>") |
| | | Integer countSeatedDoctors(@Param("statusList") List<Integer> statusList); |
| | | |
| | | @Update("<script> " + |
| | | "update lihu.clinic_room set status=#{newStatus.status} " + |
| | |
| | | Integer setBedStopReady(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, |
| | | @Param("stopReady")Integer stopReady); |
| | | |
| | | /** |
| | | * 入座:把该工位的**主人**设为我(按 room_id + bed_no 定位)。 |
| | | * |
| | | * <p>【本次放宽 + 修复】 |
| | | * <ul> |
| | | * <li>可入座条件统一为:<b>(无主人 或 主人是我)且 状态 ∈ claimableStatusList</b>。 |
| | | * 状态集合由调用方传 {已开通, 有医生, 暂停}(**排除"已关闭"**)。<br> |
| | | * 原来"无主人"时只认"已开通":一旦数据里出现"doc_id 为空但状态仍是有医生/暂停" |
| | | * 这种不一致,医生站在工位前却始终坐不上,只报"状态异常",现场无从处理。</li> |
| | | * <li>主人是我时同样放行 → 上次没正常离座(关浏览器/超时)也能坐回自己的工位。</li> |
| | | * <li>主人是**别人**时更新 0 行,调用方据此拒绝(不挤掉正在操作的人)。</li> |
| | | * </ul> |
| | | */ |
| | | @Update("<script> " + |
| | | "update lihu.clinic_room set status=#{newStatus.status}, doc_id=#{docId}, doc_name=#{docName} " + |
| | | "where room_id=#{roomId} and bed_no=#{bedNo} and isNull(doc_id)" + |
| | | "and status in ( " + |
| | | " <foreach collection='curStatusList' separator=',' item='curStatus'>" + |
| | | " #{curStatus.status} " + |
| | | " </foreach> );" + |
| | | "update lihu.clinic_room set status=#{newStatus.status}, doc_id=#{docId}, doc_name=#{docName}, update_time=NOW() " + |
| | | "where room_id=#{roomId} and bed_no=#{bedNo} and deleted = 0 " + |
| | | " and ( isNull(doc_id) or doc_id = #{docId} ) " + |
| | | " and status in ( " + |
| | | " <foreach collection='claimableStatusList' separator=',' item='curStatus'>#{curStatus.status}</foreach> );" + |
| | | "</script>") |
| | | Integer setBedDoctorOn(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("docId")Long docId, @Param("docName")String docName, @Param("newStatus") BedStatusEnum newStatus, @Param("curStatusList") List<BedStatusEnum> curStatusList); |
| | | Integer setBedDoctorOn(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("docId")Long docId, @Param("docName")String docName, |
| | | @Param("newStatus") BedStatusEnum newStatus, |
| | | @Param("claimableStatusList") List<BedStatusEnum> claimableStatusList); |
| | | |
| | | /** |
| | | * 入座:同上,但按**主键 id** 定位。 |
| | | * |
| | | * <p>【本次修复】现场出现过"工位在库里明明是空闲的,入座却更新 0 行 → 报状态异常"。 |
| | | * 已确认不是被占用;剩下的可能是 {@code bed_no} 与请求值存在肉眼难辨的差异 |
| | | * (结尾空格、大小写、全角等 —— JSON 与复制粘贴都看不出来)。 |
| | | * 前端请求里本来就带 {@code id},因此优先按主键更新,彻底绕开这类问题。 |
| | | */ |
| | | @Update("<script> " + |
| | | "update lihu.clinic_room set status=#{newStatus.status}, doc_id=#{docId}, doc_name=#{docName}, update_time=NOW() " + |
| | | "where id=#{id} and deleted = 0 " + |
| | | " and ( isNull(doc_id) or doc_id = #{docId} ) " + |
| | | " and status in ( " + |
| | | " <foreach collection='claimableStatusList' separator=',' item='curStatus'>#{curStatus.status}</foreach> );" + |
| | | "</script>") |
| | | Integer setBedDoctorOnById(@Param("id")Integer id, @Param("docId")Long docId, @Param("docName")String docName, |
| | | @Param("newStatus") BedStatusEnum newStatus, |
| | | @Param("claimableStatusList") List<BedStatusEnum> claimableStatusList); |
| | | |
| | | /** |
| | | * 诊断用:取工位**原始行**(含 {@code bed_no} 的长度与十六进制,用于发现结尾空格/全角差异)。 |
| | | * |
| | | * <p>传入 id 时按 id 查(含已删除行);否则按 room_id + {@code TRIM(bed_no)} 宽松查。 |
| | | * 返回 Map 而不是 DO:这里要把 {@code deleted}、长度、HEX 这些"非实体字段"一起带出来。 |
| | | */ |
| | | @Select("<script>" + |
| | | "select id, room_id, room_name, bed_no," + |
| | | " CHAR_LENGTH(bed_no) as bed_no_len, HEX(bed_no) as bed_no_hex," + |
| | | " ip, status, doc_id, doc_name, op_type, deleted, update_time" + |
| | | " from lihu.clinic_room" + |
| | | " where 1 = 1" + |
| | | " <if test='id != null'> and id = #{id} </if>" + |
| | | " <if test='id == null'> and room_id = #{roomId} and TRIM(bed_no) = TRIM(#{bedNo}) </if>" + |
| | | " order by deleted, id" + |
| | | "</script>") |
| | | List<Map<String, Object>> selectBedRawState(@Param("id") Integer id, @Param("roomId") Long roomId, @Param("bedNo") String bedNo); |
| | | |
| | | /** |
| | | * 【本需求】一个用户只允许占一个工位:入座成功后,把**我的其它工位**释放掉。 |
| | | * |
| | | * <p>只清 {@code doc_id/doc_name} 并把状态置回"已开通",不动 check_types / ip / stop_ready; |
| | | * 用 {@code not (room_id = ? and bed_no = ?)} 排除本次入座的工位,避免把自己刚坐上的也清掉。 |
| | | * |
| | | * @param keepRoomId 本次入座的诊室编号(保留不动) |
| | | * @param keepBedNo 本次入座的工位号(保留不动) |
| | | */ |
| | | @Update("<script> " + |
| | | "update lihu.clinic_room set status=#{newStatus.status}, doc_id=null, doc_name=null, update_time=NOW() " + |
| | | "where doc_id=#{docId} and deleted = 0 " + |
| | | "<if test='keepRoomId != null and keepBedNo != null'>" + |
| | | " and not (room_id = #{keepRoomId} and bed_no = #{keepBedNo}) " + |
| | | "</if>" + |
| | | "</script>") |
| | | Integer releaseOtherBedsOfDoc(@Param("docId")Long docId, @Param("keepRoomId")Long keepRoomId, |
| | | @Param("keepBedNo")String keepBedNo, @Param("newStatus") BedStatusEnum newStatus); |
| | | |
| | | @Update("<script> " + |
| | | "update lihu.clinic_room set status=#{newStatus.status}, doc_id=null, doc_name=null " + |
| | | "where room_id=#{roomId} and bed_no=#{bedNo} " + |
| | | "where room_id=#{roomId} and bed_no=#{bedNo} and doc_id=#{docId} " + |
| | | "and status in ( " + |
| | | " <foreach collection='curStatusList' separator=',' item='curStatus'>" + |
| | | " #{curStatus.status} " + |
| | | " </foreach> );" + |
| | | "</script>") |
| | | Integer setBedDoctorOff(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("docId")Long docId, @Param("newStatus") BedStatusEnum newStatus, @Param("curStatusList") List<BedStatusEnum> curStatusList); |
| | | |
| | | /** |
| | | * 【本次需求】闭诊时清空**所有被医生占用**的工位(doc_id 非空,且状态为「医生在岗 / 暂停」)。 |
| | | * <p> |
| | | * 背景:工位不再因「空闲超时 / 令牌失效 / 刷新页面」被释放(避免医生离开一会儿就丢工位), |
| | | * 因此需要一个兜底,防止医生下班忘离座导致工位长期被占用 —— 闭诊时统一清空当班工位。 |
| | | * |
| | | * @param newStatus 清空后置为的状态(空闲 / 已开通) |
| | | * @param curStatusList 允许被清空的当前状态集合 |
| | | */ |
| | | @Update("<script> " + |
| | | "update lihu.clinic_room set status=#{newStatus.status}, doc_id=null, doc_name=null, update_time=NOW() " + |
| | | "where deleted = 0 and doc_id is not null " + |
| | | "and status in ( " + |
| | | " <foreach collection='curStatusList' separator=',' item='curStatus'>" + |
| | | " #{curStatus.status} " + |
| | | " </foreach> )" + |
| | | "</script>") |
| | | Integer clearAllBedDoctors(@Param("newStatus") BedStatusEnum newStatus, @Param("curStatusList") List<BedStatusEnum> curStatusList); |
| | | |
| | | /** |
| | | * 【本次需求】管理员强制清空某个工位。 |
| | | * <p> |
| | | * 与 {@link #setBedDoctorOff} 的唯一区别:**不带 `doc_id = ?` 条件**, |
| | | * 因此可以把"别人占用中"的工位清掉(医生下班忘离座、换人使用同一工位时用)。 |
| | | * 仍然要求当前状态是「医生在岗 / 暂停」且 doc_id 非空,避免误清空闲工位。 |
| | | */ |
| | | @Update("<script> " + |
| | | "update lihu.clinic_room set status=#{newStatus.status}, doc_id=null, doc_name=null, update_time=NOW() " + |
| | | "where room_id=#{roomId} and bed_no=#{bedNo} and doc_id is not null " + |
| | | "and status in ( " + |
| | | " <foreach collection='curStatusList' separator=',' item='curStatus'>" + |
| | | " #{curStatus.status} " + |
| | | " </foreach> )" + |
| | | "</script>") |
| | | Integer setBedDoctorOffAdmin(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, |
| | | @Param("newStatus") BedStatusEnum newStatus, @Param("curStatusList") List<BedStatusEnum> curStatusList); |
| | | } |