package cn.lihu.jh.module.ecg.dal.mysql.room;
|
|
import java.util.*;
|
|
import cn.lihu.jh.framework.common.pojo.PageResult;
|
import cn.lihu.jh.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.lihu.jh.module.ecg.dal.dataobject.room.RoomDO;
|
import org.apache.ibatis.annotations.*;
|
|
import cn.lihu.jh.module.ecg.controller.admin.room.vo.RoomPageReqVO;
|
import cn.lihu.jh.module.ecg.enums.BedStatusEnum;
|
|
/**
|
* 诊室和诊疗床 Mapper
|
*
|
* @author 芋道源码
|
*/
|
@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())
|
.orderByAsc(RoomDO::getRoomId)
|
.orderByAsc(RoomDO::getBedNo));
|
}
|
|
/**
|
* 按 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 " +
|
" where deleted = 0 " +
|
"</script>")
|
Integer resetRoom(@Param("newStatus") Integer newStatus);
|
|
@Select("<script> " +
|
"SELECT * FROM lihu.clinic_room " +
|
"where status in ( " +
|
" <foreach collection='curStatusList' separator=',' item='curStatus'>" +
|
" #{curStatus.status} " +
|
" </foreach> )" +
|
" and deleted = 0" +
|
" order by room_id;" +
|
"</script>")
|
@Results({
|
@Result(property = "checkTypes", column = "check_types", typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class)
|
})
|
List<RoomDO> simpleRoomList(@Param("curStatusList") List<BedStatusEnum> curStatusList);
|
|
@Select("SELECT * FROM lihu.clinic_room where room_id=#{roomId} and bed_no=#{bedNo}")
|
@Results({
|
@Result(property = "checkTypes", column = "check_types", typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class)
|
})
|
RoomDO getRoom(@Param("roomId")Long roomId, @Param("bedNo")String bedNo);
|
|
@Select("SELECT * FROM lihu.clinic_room where room_id=#{roomId} and bed_no=#{bedNo} and doc_id=#{docId}")
|
RoomDO getRoomByRoomBedDoc(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("docId")Long docId);
|
|
@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} " +
|
" where room_id=#{roomId} and bed_no=#{bedNo} and isNull(doc_id) " +
|
" and status in ( " +
|
" <foreach collection='curStatusList' separator=',' item='curStatus'>" +
|
" #{curStatus.status} " +
|
" </foreach> );" +
|
"</script>")
|
Integer setBedOpeningOpening(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("newStatus") BedStatusEnum newStatus, @Param("curStatusList") List<BedStatusEnum> curStatusList);
|
|
@Update("<script> " +
|
"update lihu.clinic_room set status=#{newStatus.status}, doc_id=null, doc_name=null " +
|
" where room_id=#{roomId} and bed_no=#{bedNo} and isNull(doc_id) " +
|
" and status in ( " +
|
" <foreach collection='curStatusList' separator=',' item='curStatus'>" +
|
" #{curStatus.status} " +
|
" </foreach> );" +
|
"</script>")
|
Integer setBedOpeningClosed(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("newStatus") BedStatusEnum newStatus, @Param("curStatusList") List<BedStatusEnum> curStatusList);
|
|
@Update("<script> " +
|
"update lihu.clinic_room set status=#{newStatus.status} " +
|
"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 setBedDoctorStatus(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("docId")Long docId, @Param("newStatus") BedStatusEnum newStatus, @Param("curStatusList") List<BedStatusEnum> curStatusList);
|
|
/**
|
* 【需求3】设置工位的「停止候诊」开关(持久化,供 bedReload 后恢复)。
|
*
|
* @param stopReady 0=正常接收候诊患者;1=停止新增候诊患者
|
* @return 受影响行数
|
*/
|
@Update("update lihu.clinic_room set stop_ready = #{stopReady}, update_time = NOW() "
|
+ "where room_id = #{roomId} and bed_no = #{bedNo} and deleted = 0")
|
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}, 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("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} 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);
|
}
|