jh-module-ecg/jh-module-ecg-api/src/main/java/cn/lihu/jh/module/ecg/enums/ErrorCodeConstants.java
@@ -22,6 +22,16 @@ ErrorCode APPOINTMENT_STATUS_UPDATE_FAIL = new ErrorCode(1_010_001_070, "ç³è¯·åç¶ææ´æ°å¤±è´¥"); ErrorCode APPOINTMENT_STATUS_REGISTER_UPDATE_FAIL = new ErrorCode(1_010_001_080, "ç³è¯·åç»è®°ç¶ææ´æ°å¤±è´¥"); // ========== HIS éç¨æ¥å£ï¼/ecg/external/generalInterfaceï¼æ°å¢é误ç ========== // ç®çï¼åå®ç°æææå¼å¸¸ç»ä¸åæ APPOINTMENT_CREATE_FAILï¼ // å¯¼è´ HIS ä¾§æ æ³åºåé®é¢ç±»åï¼æ¬æ¬¡æéææ¬å³æ¥èªæ¤ï¼ãä»¥ä¸ææ¶æ®µç»åã ErrorCode HIS_ACTION_NOT_SUPPORTED = new ErrorCode(1_010_001_090, "䏿¯æçæå¡ä»£ç (action)ï¼è¯·æ ¸å¯¹æ¥å£ææ¡£äº¤æç¼å·"); ErrorCode HIS_MESSAGE_PARSE_FAIL = new ErrorCode(1_010_001_100, "æ¥æè§£æå¤±è´¥ï¼è¯·æ ¸å¯¹æ¥æç»æä¸å¿ å¡«åæ®µ"); ErrorCode HIS_APPLY_NO_MISSING = new ErrorCode(1_010_001_110, "æ¥æç¼ºå°ç³è¯·åå·"); ErrorCode HIS_APPOINTMENT_NOT_FOUND = new ErrorCode(1_010_001_120, "æªæ¾å°å¯¹åºçé¢çº¦è®°å½"); ErrorCode HIS_STATUS_INVALID = new ErrorCode(1_010_001_130, "æ£æ¥ç¶æç¼ç ä¸å¨ç¼ç 表èå´å "); ErrorCode HIS_NOT_ECG_ORDER = new ErrorCode(1_010_001_140, "éå¿çµä¸å¡åï¼å·²è·³è¿å¤ç"); ErrorCode ROOM_NOT_EXISTS = new ErrorCode(1_010_002_000, "è¯å®¤åè¯çåºä¸åå¨"); ErrorCode ROOM_NOT_SIT = new ErrorCode(1_010_002_001, "è¯·éæ°å°±åº§"); ErrorCode ROOM_INVALID_STATUS = new ErrorCode(1_010_002_001, "è¯å®¤åè¯çåºç¶æå¼å¸¸"); @@ -32,6 +42,14 @@ ErrorCode QUEUE_HAVE_PATIENT = new ErrorCode(1_010_003_003, "éå䏿æ£è "); ErrorCode QUEUE_NOT_READY_PATIENT = new ErrorCode(1_010_003_004, "没æåå¤ä¸çæ£è "); ErrorCode QUEUE_RECALL_INSTALL_NOT_CUR_ROOM = new ErrorCode(1_010_003_005, "ä¸è½å¬åå ¶ä»è¯å®¤çå®è£ æ£è "); /** * ã忢åè¯ãåè½æªå°±ç»ªã * <p> * è§¦åæ¡ä»¶ï¼æ°æ®åºå°æªæ§è¡ `_prep/11_éæ±å级_æ±æ»SQL.sql`ï¼ç¼º `clinic_room.stop_ready` åï¼ã * ç¨ç¬ç«é误ç èéæåå§ SQL å¼å¸¸æç»å端ï¼ä¾¿äºç°åºå¿«éå®ä½é¨ç½²éæ¼ã */ ErrorCode QUEUE_STOP_READY_NOT_CONFIGURED = new ErrorCode(1_010_003_006, "忢åè¯åè½æªé ç½®ï¼è¯·å æ§è¡æ°æ®åºåçº§èæ¬ï¼clinic_room.stop_readyï¼"); ErrorCode PATIENT_NOT_EXISTS = new ErrorCode(1_010_004_000, "æ£è ä¸åå¨"); @@ -66,4 +84,14 @@ ErrorCode QUEUE_SEQUENCE_TIMESLOT_EXCEPTION = new ErrorCode(1_010_010_002, "æ¬æ¶æ®µåºå·å¼å¸¸"); ErrorCode QUEUE_SEQUENCE_TIMESLOT_VIP_FULL = new ErrorCode(1_010_010_003, "æ¬æ¶æ®µVIPåºå·å·²æ»¡"); ErrorCode QUEUE_SEQUENCE_TIMESLOT_VIP_EXCEPTION = new ErrorCode(1_010_010_003, "æ¬æ¶æ®µVIPåºå·å¼å¸¸"); /** * é¢çº¦æ¶æ®µéå¤ï¼å䏿£æ¥ç±»åä¸åä¸ä¸ªæ¶æ®µåªè½æä¸æ¡è§åã * <p> * 表ä¸**没æ** (check_type, time_slot) å¯ä¸çº¦æï¼åå²éçï¼ï¼èåå· SQL * {@code select queue_no ... where check_type=? and time_slot=? ... for update} * ææåªå½ä¸ä¸è¡ï¼è¥åå¨éå¤è¡ï¼åå·è¡ä¸ºä¸å¯é¢æãæ å¨ç»´æ¤å ¥å£å¤æ¦æªã */ ErrorCode QUEUE_SEQUENCE_TIMESLOT_DUPLICATE = new ErrorCode(1_010_010_004, "è¯¥æ£æ¥ç±»åçæ¤æ¶æ®µè§åå·²åå¨ï¼è¯·å¿é夿·»å "); } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentPageReqVO.java
@@ -4,7 +4,9 @@ import com.fasterxml.jackson.annotation.JsonFormat; import lombok.*; import java.sql.Date; // 注æï¼å为 java.sql.Dateï¼åªè¡¨ç¤ºæ¥æï¼ï¼ä¼è®© registerDate/doctorTime 丢失æ¶åç§ã // 2026-09-30 ä¸ AppointmentSaveReqVO/AppointmentDO ç»ä¸ä¸º java.util.Dateã import java.util.Date; import java.time.LocalDate; import java.util.*; jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentRespVO.java
@@ -3,7 +3,9 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import java.sql.Date; // 注æï¼å为 java.sql.Dateï¼åªè¡¨ç¤ºæ¥æï¼ï¼ä¼è®© registerDate/doctorTime 丢失æ¶åç§ã // 2026-09-30 ä¸ AppointmentSaveReqVO/AppointmentDO ç»ä¸ä¸º java.util.Dateã import java.util.Date; import java.time.LocalDate; import java.util.*; @@ -136,6 +138,10 @@ */ private String tolerance; @Schema(description = "æ¯å¦åºè¾¹ 0=å¦ 1=æ¯", example = "0") @ExcelProperty("æ¯å¦åºè¾¹") private String isBedside; /** * ä½é¢å· */ @@ -169,4 +175,39 @@ @ExcelProperty("å¼åæ¶é´") private Date doctorTime; // ==================== HIS æ¥å ¥è¡¥å åæ®µï¼2026-09-27 é表æ°å¢åä¸èµ·å å ¥ï¼ ==================== // 注ï¼bookSeqNum å·²å¨ä¸æ¹å£°æï¼æ¤å¤ä¸éå¤å®ä¹ /** * ä¼å 级 / å æ¥æ è®°ï¼N=常è§ï¼J=å æ¥ */ @ExcelProperty("å æ¥æ è®°") private String jjbz; /** * æ£æ¥æ¹å¼ç¼ç */ private String methodCode; /** * æ£æ¥é¨ä½ç¼ç */ private String targetSiteCode; /** * å»å±å·ï¼HIS æ¥æ component2.observationRequest.id.item[root=2.16.156.10011.1.28].extensionï¼ã * ä¸ãç³è¯·åå· applyNoãä¸åï¼åè æ¯å»å±æ è¯ï¼åè æ¯ç³è¯·åæ è¯ã */ private String doctorAdviceNo; /** * æ£æ¥æ¿é´åç§° */ private String roomName; /** * 注æäºé¡¹ */ private String remark; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentSaveReqVO.java
@@ -7,10 +7,27 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.sql.Date; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Date; /** * 管çåå° - é¢çº¦æ°å¢/ä¿®æ¹ Request VO * * <h3>â ï¸ å ³äº {@code registerDate} / {@code doctorTime} çç±»åï¼2026-09-30 ä¿®æ£ï¼</h3> * è¿ä¸¤ä¸ªå段åå 声æä¸º {@code java.sql.Date}ï¼ç» {@code import java.sql.Date;} * éé å°æ¬ç±»ç {@code Date}ï¼ï¼è对åºç {@code AppointmentDO} æ¯ {@code java.util.Date}ã * * <p>{@code java.sql.Date} æ¯**åªè¡¨ç¤ºæ¥æ**ç JDBC ç±»åã宿µï¼åå ¥ datetime åï¼ï¼ * <pre> * setObject(java.util.Date) â 2026-09-26 16:58:53 ä¿çæ¶åç§ * setObject(java.sql.Date) â 2026-09-26 00:00:00 æ¶é´è¢«ä¸¢å¼ * </pre> * è¿æ£æ¯ {@code appointment.register_date} åºç° {@code yyyy-MM-dd 00:00:00} * çæå ç±»å ââ 塿¯ä»æ¬ VO åå¼è½åºçè·¯å¾é½ä¼ææ¶é´æªæã * * <p>ç°ç»ä¸ä¸º {@code java.util.Date}ï¼ä¸ DO åååå ¥è·¯å¾ï¼{@code new Date()}ï¼ä¿æä¸è´ã */ @Schema(description = "管çåå° - é¢çº¦æ°å¢/ä¿®æ¹ Request VO") @Data public class AppointmentSaveReqVO { @@ -132,4 +149,42 @@ * å¼åæ¶é´ */ private Date doctorTime; // ==================== HIS æ¥å ¥è¡¥å åæ®µï¼2026-09-27 é表æ°å¢åä¸èµ·å å ¥ï¼ ==================== /** * é¢çº¦æåºå·ï¼HIS æ¥æ patient.id.item[4]ï¼ */ private Integer bookSeqNum; /** * ä¼å 级 / å æ¥æ è®°ï¼N=常è§ï¼J=å æ¥ï¼HIS æ¥æ zdy.jjbzï¼ */ private String jjbz; /** * æ£æ¥æ¹å¼ç¼ç ï¼HIS æ¥æ methodCode.item[].codeï¼ */ private String methodCode; /** * æ£æ¥é¨ä½ç¼ç ï¼HIS æ¥æ targetSiteCode.item.codeï¼ */ private String targetSiteCode; /** * å»å±å·ï¼HIS æ¥æ observationRequest.id.item[root=2.16.156.10011.1.28].extensionï¼ã * ä¸ãç³è¯·åå· applyNoãä¸åã */ private String doctorAdviceNo; /** * æ£æ¥æ¿é´åç§°ï¼HIS æ¥æ ZDY.roomnameï¼ */ private String roomName; /** * 注æäºé¡¹ï¼HIS æ¥æ ZDY.remarkï¼ */ private String remark; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/callingscreen/ScreenQueueRespVO.java
@@ -68,4 +68,59 @@ @Schema(description = "è¯çåºç¼å·") @ExcelProperty("è¯çåºç¼å·") private String bedNo; // ==================== éæ±1ï¼æ£è ä¿¡æ¯ 18 项 ==================== // 忥èªé¢çº¦å appointmentï¼queue è¡¨æ æ¤åï¼ï¼ç± CallingScreenServiceImpl // è°ç¨ QueueService#fillAppointmentInfo åå¡«ååç» BeanUtils.toBean æ å°å°è¿éã // è¡¥é½å大å±/è¯é´å±æè½å±ç¤ºå®æ´æ£è ä¿¡æ¯ã @Schema(description = "å°±è¯æµæ°´å·") @ExcelProperty("å°±è¯æµæ°´å·") private String episodeId; @Schema(description = "ç³è¯·ç¼å·") @ExcelProperty("ç³è¯·ç¼å·") private String applyNo; @Schema(description = "åºçæ¥æ") @ExcelProperty("åºçæ¥æ") private java.time.LocalDate patBirthday; @Schema(description = "æ£è çµè¯ï¼ææºä¼å ï¼åéåºè¯ï¼") @ExcelProperty("æ£è çµè¯") private String patMobile; @Schema(description = "ç åºåç§°") @ExcelProperty("ç åºåç§°") private String patWardDesc; @Schema(description = "ç åºå·ï¼æ³¨æä¸æ¯æ¬ç±»ç bedNoï¼åè æ¯è¯çåº/å·¥ä½å·ï¼") @ExcelProperty("ç åºå·") private String patBedNo; @Schema(description = "æ£è æ¥æºï¼1é¨è¯ 2æ¥è¯ 3ä½é¢ 4使£") @ExcelProperty("æ£è æ¥æº") private Integer patSrc; @Schema(description = "å¼åå»å¸") @ExcelProperty("å¼åå»å¸") private String doctor; @Schema(description = "å¼åæ¥æ") @ExcelProperty("å¼åæ¥æ") private java.util.Date doctorTime; @Schema(description = "ç»è®°æ¶é´") @ExcelProperty("ç»è®°æ¶é´") private java.util.Date registerDate; @Schema(description = "å¤èè¯ï¼0æ 1å¤è 2å¤éèè¯") @ExcelProperty("å¤èè¯") private String tolerance; private String isBedside; @Schema(description = "å»å±å·ï¼HIS observationRequest.id.item[root=2.16.156.10011.1.28]ï¼ä¸ç³è¯·å· applyNo ä¸åï¼") @ExcelProperty("å»å±å·") private String doctorAdviceNo; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypePageReqVO.java
@@ -54,4 +54,7 @@ @Schema(description = "é¢çº¦åºå·æ¾ç¤ºåç¼") private String seqPrefix; @Schema(description = "æåºåºå·") private Integer sort; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeRespVO.java
@@ -70,4 +70,12 @@ @Schema(description = "é¢çº¦åºå·æ¾ç¤ºåç¼") @ExcelProperty("é¢çº¦åºå·æ¾ç¤ºåç¼") private String seqPrefix; @Schema(description = "æéåºå·è§åï¼0=é¢çº¦å·, 1=ç¾å°åºå·, 2=æ¶æ®µå·ï¼é»è®¤ï¼", example = "2") @ExcelProperty("æéåºå·è§å") private Integer seqRule; @Schema(description = "æåºåºå·ï¼è¶å°è¶é åï¼æ£æ¥é¡¹ç®æ¾ç¤ºé¡ºåºï¼", example = "100") @ExcelProperty("æåºåºå·") private Integer sort; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeSaveReqVO.java
@@ -47,4 +47,10 @@ @Schema(description = "é¢çº¦åºå·æ¾ç¤ºåç¼") private String seqPrefix; @Schema(description = "æéåºå·è§åï¼0=é¢çº¦å·, 1=ç¾å°åºå·, 2=æ¶æ®µå·ï¼é»è®¤ï¼", example = "2") private Integer seqRule; @Schema(description = "æåºåºå·ï¼è¶å°è¶é åï¼æ£æ¥é¡¹ç®æ¾ç¤ºé¡ºåºï¼", example = "100") private Integer sort; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/SimpleCheckTypeRespVO.java
@@ -28,4 +28,7 @@ @Schema(description = "æ¯å¦éè¦ç¡®è´¹") private Integer expenseRecognition; @Schema(description = "æ¯å¦éè¦è®¾å¤é¢ç¨ï¼0-ä¸éè¦ï¼1-éè¦", example = "1") private Integer needDevReady; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/devrent/vo/DevRentRespVO.java
@@ -5,6 +5,7 @@ import lombok.*; import java.util.*; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDate; import java.time.LocalDateTime; import com.alibaba.excel.annotation.*; @@ -97,4 +98,59 @@ @Schema(description = "设å¤ç¶æ") private Integer devState; // ==================== éæ±1ï¼æ£è ä¿¡æ¯ 18 项 ==================== // 忥èªé¢çº¦å appointmentï¼dev_rent è¡¨æ æ¤åï¼ï¼ç± DevRentServiceImpl æ applyNo åå¡«ã // è¡¥é½è¿äºå段åï¼é¢ç¨/è£ æº/ææº/æ°æ®å½å ¥/æ£æ¥è®°å½ 5 个ç颿è½å±ç¤ºå®æ´æ£è ä¿¡æ¯ã @Schema(description = "æ£è æ§å«") private Byte patGender; @Schema(description = "åºçæ¥æ") private LocalDate patBirthday; @Schema(description = "ç»è®°æ¶é´") private Date registerDate; @Schema(description = "å¼åå»å¸") private String doctor; @Schema(description = "å¼åæ¥æï¼å¼åæ¶é´ï¼") private Date doctorTime; @Schema(description = "æ£è æ¥æºï¼1é¨è¯ 2æ¥è¯ 3ä½é¢ 4使£") private Integer patSrc; @Schema(description = "ææºå·") private String patMobile; @Schema(description = "çµè¯") private String patPhone; @Schema(description = "ç åºåç§°") private String patWardDesc; @Schema(description = "ç åºå·") private String patBedNo; @Schema(description = "å°±è¯å¡å·ï¼medical_cardï¼åºä¸å¤ä¸ºç©ºï¼") private String medicalCard; @Schema(description = "é¨è¯å·ï¼å®æµé¨åæ°æ®åçæ¯èº«ä»½è¯å·ï¼éçæ£å¡å·ï¼") private String outpatientNo; @Schema(description = "身份è¯å·") private String patIdentityId; /** * å»å±å·ï¼HIS æ¥æ observationRequest.id.item[root=2.16.156.10011.1.28].extensionï¼ã * ä¸ãç³è¯·åå· applyNoãä¸åï¼åè æ¯å»å±æ è¯ï¼åè æ¯ç³è¯·åæ è¯ã该èç¹å¨è§èä¸éå¿ é¡»é¡¹ï¼åºä¸å¯ä¸ºç©ºã */ private String doctorAdviceNo; @Schema(description = "å¤èè¯ï¼0æ 1å¤è 2å¤éèè¯") private String tolerance; @Schema(description = "æ¯å¦åºè¾¹ 0=å¦ 1=æ¯", example = "0") private String isBedside; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/doctor/DoctorController.java
@@ -10,6 +10,7 @@ import cn.lihu.jh.module.ecg.controller.admin.queue.vo.QueueSaveReqVO; import cn.lihu.jh.module.ecg.controller.admin.room.vo.RoomRespVO; import cn.lihu.jh.module.ecg.dal.dataobject.queue.QueueDO; import cn.lihu.jh.module.ecg.dal.dataobject.room.RoomDO; import cn.lihu.jh.module.ecg.enums.QueueStatusEnum; import cn.lihu.jh.module.ecg.service.call.CallService; import cn.lihu.jh.module.ecg.service.queue.QueueService; @@ -112,6 +113,45 @@ return success(SUCCESS.getCode()); return error(result); } /** * éæ¾**å½åç»å½ç¨æ·**å ç¨çå ¨é¨è¯çåºä½ï¼éåºç³»ç»æ¶èªå¨ç¦»åº§ï¼ã * * <p>èæ¯ï¼å»çå¨ãè¯å®¤éæ©ã页é好åºä½åå³å ç¨è¯¥åºä½ï¼{@code clinic_room.doc_id}ï¼ï¼ * è¥ä¸ç´ä¸ç¹ã离座ãå°±éåºç³»ç»ï¼åºä½ä¼ä¸ç´æ¾ç¤ºè¢«å ç¨ï¼å ¶ä»å»çæ æ³ä½¿ç¨ã * * <p>ä¸ {@link #bedDoctorOff} çåºå«ï¼ * <ul> * <li>{@code /bed-doctor-off} éè¦åç«¯ä¼ roomId + bedNoï¼ç¦»å¼æä¸ª**æå®**åºä½ï¼ï¼</li> * <li>æ¬æ¥å£**ä¸éè¦ä»»ä½åæ°**ï¼æå½åç»å½ç¨æ·åæ¥å ¶å ç¨ç**ææ**åºä½å¹¶éä¸éæ¾ã</li> * </ul> * 乿以åæ"æ å"ï¼éåºç»å½ / 空é²è¶ æ¶ / 令ç失æçåºæ¯ä¸ï¼å端å¯è½å·²ç»æ¿ä¸å° * åºä½ç roomId/bedNoï¼æ¬å°ç¼åå·²è¢«æ¸ çï¼ï¼æ¤æ¶åªè½ç±æå¡ç«¯æ userId 忥ã * æå¡ç«¯åæ¥ä¹æ´å¯é ââ å端ç¼åçåºä½è¥è¢«ç®¡çåæ¹å¨è¿ï¼å°±ä¼åºç°"鿾䏿"ã * * <p>å¹çï¼æªå ç¨ä»»ä½åºä½æ¶ç´æ¥è¿åæåã */ @PostMapping("/release-my-beds") @Operation(summary = "éæ¾å½åç»å½ç¨æ·å ç¨çå ¨é¨åºä½ï¼éåºç³»ç»æ¶èªå¨ç¦»åº§ï¼") public CommonResult<Boolean> releaseMyBeds() { Long userId = SecurityFrameworkUtils.getLoginUserId(); if (userId == null) { // æªç»å½ï¼æä»¤ç已失æï¼æ¶æ åºä½å¯éæ¾ï¼ææåè¿åï¼é¿å å端æ¥é return success(true); } String userNickname = SecurityFrameworkUtils.getLoginUserNickname(); List<RoomDO> occupiedBeds = queueService.getDocRoomInfo(userId); if (occupiedBeds == null || occupiedBeds.isEmpty()) { return success(true); // æªå ç¨åºä½ï¼æ éå¤ç } log.info("[releaseMyBeds] éåºç³»ç»èªå¨ç¦»åº§. userId={} nickname={} å ç¨åºä½æ°={}", userId, userNickname, occupiedBeds.size()); for (RoomDO bed : occupiedBeds) { // éä¸ªéæ¾ï¼å个失败ä¸å½±åå ¶å®åºä½ queueService.startBedDoctorOff(bed.getRoomId(), bed.getBedNo(), userId, userNickname); } return success(true); } @GetMapping("/bed-doctor-get") @@ -460,4 +500,97 @@ return success("æä½æå"); } // ==================== éæ±2ï¼æ¤éãå«å· / æ£æ¥å®æã ==================== @GetMapping("/undo-finish-patient") @Operation(summary = "æ¤éæ£æ¥å®æï¼å·²å°±è¯(40) â åè¯ä¸(20)") @Parameter(name = "roomId", description = "è¯å®¤ç¼å·", required = true, example = "116") @Parameter(name = "bedNo", description = "å·¥ä½ç¼å·", required = true, example = "A1") @Parameter(name = "patId", description = "æ£è ç¼å·", required = true, example = "913639423") @Parameter(name = "checkType", description = "æ£æ¥ç±»å", required = true, example = "100") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") public CommonResult<String> undoFinishPatient( @RequestParam("roomId") Long roomId, @RequestParam("bedNo") String bedNo, @RequestParam("patId") String patId, @RequestParam("checkType") Integer checkType) { // 说æï¼å¿ é¡»æ patId + checkType 精确å®ä½ï¼é¿å 误æ¤éå ¶ä»æ£è ï¼æ¢æç¼ºé·è§ DevRentServiceImplï¼ Integer result = queueService.undoFinishPatient(roomId, bedNo, patId, checkType); if (null == result || 0 == result) { return error(APPOINTMENT_NOT_EXISTS); } return success("å·²æ¤éæ£æ¥å®æï¼æ£è å·²è¿ååè¯åº"); } @GetMapping("/undo-call-patient") @Operation(summary = "æ¤éå«å·ï¼å°±è¯ä¸(30) â åè¯ä¸(20)") @Parameter(name = "roomId", description = "è¯å®¤ç¼å·", required = true, example = "116") @Parameter(name = "bedNo", description = "å·¥ä½ç¼å·", required = true, example = "A1") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") public CommonResult<String> undoCallPatient( @RequestParam("roomId") Long roomId, @RequestParam("bedNo") String bedNo) { Integer result = queueService.undoCallPatient(roomId, bedNo); if (null == result || 0 == result) { return error(QUEUE_NOT_EXISTS); } return success("å·²æ¤éå«å·ï¼æ£è å·²è¿ååè¯åº"); } @GetMapping("/last-finished-patient") @Operation(summary = "忬工ä½ä»æ¥æè¿ä¸ä½å·²å®ææ£è ï¼ä¾æ¤éæç¤ºï¼") @Parameter(name = "roomId", description = "è¯å®¤ç¼å·", required = true, example = "116") @Parameter(name = "bedNo", description = "å·¥ä½ç¼å·", required = true, example = "A1") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") public CommonResult<QueueRespVO> lastFinishedPatient( @RequestParam("roomId") Long roomId, @RequestParam("bedNo") String bedNo) { QueueDO queueDO = queueService.getBedLastFinishedQueueItem(roomId, bedNo); return success(BeanUtils.toBean(queueDO, QueueRespVO.class)); } // ==================== éæ±3ï¼åæ¢åè¯å¼å ³ ==================== @GetMapping("/stop-ready") @Operation(summary = "忢åè¯ï¼ä¸åæ°å¢åè¯æ£è ï¼å·²æåè¯ä»å¯å«å·ï¼") @Parameter(name = "roomId", description = "è¯å®¤ç¼å·", required = true, example = "116") @Parameter(name = "bedNo", description = "å·¥ä½ç¼å·", required = true, example = "A1") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") public CommonResult<Boolean> stopReady( @RequestParam("roomId") Long roomId, @RequestParam("bedNo") String bedNo) { ErrorCode ec = queueService.setStopReady(roomId, bedNo, true); if (!SUCCESS.getCode().equals(ec.getCode())) { return error(ec); } return success(true); } @GetMapping("/resume-ready") @Operation(summary = "æ¢å¤åè¯ï¼éæ°å¼å§æ¥æ¶åè¯æ£è ") @Parameter(name = "roomId", description = "è¯å®¤ç¼å·", required = true, example = "116") @Parameter(name = "bedNo", description = "å·¥ä½ç¼å·", required = true, example = "A1") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") public CommonResult<Boolean> resumeReady( @RequestParam("roomId") Long roomId, @RequestParam("bedNo") String bedNo) { ErrorCode ec = queueService.setStopReady(roomId, bedNo, false); if (!SUCCESS.getCode().equals(ec.getCode())) { return error(ec); } return success(true); } @GetMapping("/get-stop-ready") @Operation(summary = "æ¥è¯¢åæ¢åè¯ç¶æ") @Parameter(name = "roomId", description = "è¯å®¤ç¼å·", required = true, example = "116") @Parameter(name = "bedNo", description = "å·¥ä½ç¼å·", required = true, example = "A1") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") public CommonResult<Boolean> getStopReady( @RequestParam("roomId") Long roomId, @RequestParam("bedNo") String bedNo) { Boolean stop = queueService.getStopReady(roomId, bedNo); return success(stop != null && stop); } } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/external/ExternalController.java
@@ -14,12 +14,38 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.util.Map; import java.util.function.Consumer; import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.lihu.jh.framework.common.pojo.CommonResult.success; import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.APPOINTMENT_CREATE_FAIL; import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.*; /** * ä¾ç¬¬ä¸æ¹ï¼HIS / éæå¹³å°ï¼è°ç¨çéç¨æ¥å£ã * * <h3>è·¯ç±æ¹å¼</h3> * éè¿è¯·æ±å¤´ {@code action} åºåæå¡ï¼åå¼è§ {@link ActionTypeEnum}ã * * <h3>æ¬æ¬¡æ¹å¨è¦ç¹</h3> * <ol> * <li><b>补注å ECG ä¸å± action</b>ï¼æ¥å£ææ¡£ 6.4/6.5 å®ä¹ * {@code S050402}ï¼ECG æ£æ¥é¢çº¦ç¶ææ°å¢ï¼ã{@code S050502}ï¼ECG æ£æ¥é¢çº¦ç¶ææ´æ°ï¼ï¼ * ä¸ pacs ç {@code S050401}/{@code S050501} å¹¶åã宿µæ¥å¿ä¸è¿ä¸¤ä¸ªç¼å· * å°æªåºç°ï¼0 次ï¼ï¼æ¤å¤**主å¨å ¼å®¹**ï¼é¿å 颿¹åæ¢ç¼å·æ¶æ¶æ¯è¢«æã</li> * <li><b>å ¼å®¹æ åç¼åæ³</b>ï¼ææ¡£å®ä¹ {@code S0201}/{@code S0202}ï¼ * è宿µæ¥æä¸º {@code S0201ECG}/{@code S0202ECG}ï¼ä¸¤è 忥æ¶ã</li> * <li><b>ç»åé误ç </b>ï¼åå®ç°æææå¼å¸¸ç»ä¸åæ * {@code APPOINTMENT_CREATE_FAIL}ï¼"ç³è¯·åå建失败"ï¼ï¼ * å¯¼è´æéå°é¾ï¼æ¬æ¬¡é®é¢ææ¥ææ¬å³æ¥èªæ¤ï¼ãç°æ * ãæªç¥ action / æ¥æè§£æå¤±è´¥ / è®°å½ä¸åå¨ / å ¶ä»ãåºåè¿åã</li> * </ol> * * <h3>å ³äº S0405</h3> * {@code S0405}ï¼ç³è¯·åç¶ææ´æ°ï¼æ¯**å ¨é¢éç¨**æå¡ï¼å»é¢ä¼ææææ£æ¥ç§å®¤ * ï¼CT/MRI/DR/è¶ å£°â¦ï¼çç¶æä¸å¹¶æ¨éãä¸å¡å±å·²æå¿çµèå´è¿æ»¤ï¼ * éå¿çµååªè®°æ¥å¿ãä¸å¤çï¼è¯¦è§ {@code HisEcgFilter}ï¼ã * * @author å¿çµæéè£ æºç³»ç» */ @Tag(name = "ä¾ç¬¬ä¸æ¹è°ç¨æ¥å£") @RestController @RequestMapping("/ecg/external") @@ -27,18 +53,20 @@ @Slf4j public class ExternalController { /** 请æ±å¤´ä¸ç action é®å */ private static final String HEADER_ACTION = "action"; @Resource private AppointmentService appointmentService; /** * éç¨æ¥å£ * <p> * æ¯æä»¥ä¸actionç±»åï¼ * - S0201ECG: é¢çº¦å建 * - S0202ECG: é¢çº¦æ´æ° * éç¨æ¥å£ã * * @param dataMap è¯·æ±æ°æ® * @param headers 请æ±å¤´ï¼å¿ é¡»å å«actionåæ®µ * <p>æ¯æç action è§ {@link ActionTypeEnum}ï¼å æ¬ï¼ * ç³è¯·åæ°å¢/æ´æ°ãç³è¯·åç¶ææ´æ°ãæ£æ¥é¢çº¦ç¶ææ°å¢/æ´æ°ã * * @param dataMap è¯·æ±æ°æ®ï¼HL7 V3 转æ¢åç Mapï¼ * @param headers 请æ±å¤´ï¼å¿ é¡»å å« {@code action} * @return å¤çç»æ */ @PermitAll @@ -47,35 +75,54 @@ public CommonResult<Boolean> generalInterface( @RequestBody @NotNull(message = "è¯·æ±æ°æ®ä¸è½ä¸ºç©º") Map<String, Object> dataMap, @RequestHeader @NotEmpty(message = "请æ±å¤´ä¸è½ä¸ºç©º") Map<String, String> headers) { log.info("[generalInterface][å¼å§å¤çè¯·æ± action({}) dataMap({})]", headers.get("action"), dataMap); String actionType = headers.get("action"); ActionTypeEnum action = ActionTypeEnum.getByType(actionType); String rawAction = headers.get(HEADER_ACTION); ActionTypeEnum action = ActionTypeEnum.getByType(rawAction); if (action == null) { log.warn("[generalInterface][æªç¥çactionç±»å action({})]", actionType); throw exception(APPOINTMENT_CREATE_FAIL); // ä¸ååæ"ç³è¯·åå建失败"ï¼æç¡®åç¥ action ä¸åæ¯æ log.warn("[generalInterface][䏿¯æç action({})ï¼è¯·æ ¸å¯¹æ¥å£ææ¡£ 6.x 交æç¼å·]", rawAction); throw exception(HIS_ACTION_NOT_SUPPORTED); } log.info("[generalInterface][å¼å§å¤çè¯·æ± action({}) dataMap({})]", rawAction, dataMap); try { // 使ç¨çç¥æ¨¡å¼å¤çä¸åçaction Map<ActionTypeEnum, Consumer<Map<String, Object>>> actionHandlers = Map.of( ActionTypeEnum.S0201ECG, appointmentService::handleAppointmentCreate, ActionTypeEnum.S0202ECG, appointmentService::handleAppointmentUpdate, ActionTypeEnum.S040501HIS, appointmentService::handleAppointmentStateUpdate, ActionTypeEnum.S050401, appointmentService::handleCheckAppointmentUpdate, ActionTypeEnum.S0405, appointmentService::handleAppointmentStatusUpdate, ActionTypeEnum.S050501, appointmentService::handleCheckAppointmentUpdate ); Consumer<Map<String, Object>> handler = actionHandlers.get(action); if (handler == null) { throw exception(APPOINTMENT_CREATE_FAIL); } handler.accept(dataMap); dispatch(action, dataMap); return success(true); } catch (cn.lihu.jh.framework.common.exception.ServiceException e) { // ä¸å¡å¼å¸¸ï¼ä¿çåå§é误ç ä¸ä¿¡æ¯ï¼ä¾¿äº HIS ä¾§å®ä½ log.error("[generalInterface][ä¸å¡å¤ç失败 action({}) code({}) msg({})]", rawAction, e.getCode(), e.getMessage()); throw e; } catch (Exception e) { throw exception(APPOINTMENT_CREATE_FAIL); // æªé¢æå¼å¸¸ï¼æ¥æè§£æå¤±è´¥ãåæ®µç¼ºå¤±å¯¼è´ç NPE/ç±»å转æ¢å¼å¸¸ç log.error("[generalInterface][æ¥æå¤çå¼å¸¸ action({}) dataMap({})]", rawAction, dataMap, e); throw exception(HIS_MESSAGE_PARSE_FAIL); } } /** * æ action åæ´¾å°å¯¹åºå¤çå¨ã * <p> * ä½¿ç¨ {@link ActionTypeEnum} çåç»æ¹æ³èé Map æ å°ï¼æ¯ä¸ºäºè®© * ãå䏿å¡çå¤ç§ç¼å·ãï¼pacs / ECGãæåç¼ / æ åç¼ï¼èµ°åä¸å¤çå¨ï¼ * é¿å æ°å¢ç¼å·æ¶æ¼é ã */ private void dispatch(ActionTypeEnum action, Map<String, Object> dataMap) { if (action.isApplyCreate()) { appointmentService.handleAppointmentCreate(dataMap); } else if (action.isApplyUpdate()) { appointmentService.handleAppointmentUpdate(dataMap); } else if (action.isApplyStatusUpdate()) { appointmentService.handleAppointmentStateUpdate(dataMap); } else if (action.isAppointmentStatusCreate() || action.isAppointmentStatusUpdate()) { // æ£æ¥é¢çº¦ç¶æï¼æ°å¢(S050401/S050402) ä¸ æ´æ°(S050501/S050502) // æ¥æç»æç¸åï¼èµ°åä¸å¤çå¨ appointmentService.handleCheckAppointmentUpdate(dataMap); } else { // æä¸¾æ°å¢ä½æªæ¥å ¥åæ´¾é»è¾æ¶çå åºï¼é¿å éé»å¿½ç¥ throw exception(HIS_ACTION_NOT_SUPPORTED); } } } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/jobrecord/vo/JobRecordPageReqVO.java
@@ -51,4 +51,21 @@ @Schema(description = "对åºç§èµç¼å·", example = "19472") private Long rentId; /** * æ£æ¥é¡¹ç®è¿æ»¤ï¼**æè¯å®¤/å·¥ä½éç¦»å·²å®æè®°å½**ï¼ã * * <p>èæ¯ï¼`job_record` 表**åªæ doc_id + check_typeï¼æ²¡æ room_id**ï¼ * è `/ecg/job-record/doctor-page` å¼ºå¶æç»å½å»çæ¥èªå·±çè®°å½ã * è¥åä¸å»çå¨å¤ä¸ªè¯å®¤åè¯ï¼ä¾å¦ 1å·é¨è¯ check_types=[100,1100]ã * 6å·é¨è¯ check_types=[400] å¹³æ¿è¿å¨å¿çµï¼ï¼å·²å®æè®°å½åè¡¨ä¼æ**å¤ä¸ªè¯å®¤çè®°å½æ··å¨ä¸èµ·**ï¼ * 表ç°ä¸º"1å·é¨è¯çå«å·æ£æ¥é¡µåºç°äºå¹³æ¿è¿å¨å¿çµçè®°å½"ã * * <p>è§£å³ï¼å端æ**å½åè¯å®¤ç checkTypes** ä¼ ä¸æ¥ï¼è¿éæ `check_type in (...)` è¿æ»¤ï¼ * 使åè¡¨åªæ¾ç¤º"æ¬è¯å®¤å¼å±çæ£æ¥é¡¹ç®"ä¸ãä¸ç±èªå·±å®æçè®°å½ã * * <p>为空æ¶ä¸å æ¤è¿æ»¤ï¼ä¿ææ¢æè¡ä¸ºï¼ååå ¼å®¹ï¼ã */ @Schema(description = "æ£æ¥é¡¹ç®ï¼æè¯å®¤é离记å½ç¨ï¼", example = "[100,1100]") private Integer[] checkTypes; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueRespVO.java
@@ -104,6 +104,9 @@ @TableField(exist = false) private String tolerance; @Schema(description = "æ¯å¦åºè¾¹ 0=å¦ 1=æ¯", example = "0") private String isBedside; /** * 以ä¸å段æ¥èªé¢çº¦åï¼appointmentï¼ï¼ç± QueueServiceImpl#fillAppointmentInfo å¡«å */ @@ -119,4 +122,37 @@ @Schema(description = "å¼åæ¥æï¼å¼åæ¶é´ï¼") private Date doctorTime; // ==================== éæ±1ï¼æ£è ä¿¡æ¯ 18 项æéçå¹³éºå段 ==================== // 忥èªé¢çº¦å appointmentï¼queue è¡¨æ æ¤åï¼ï¼ç± QueueServiceImpl#fillAppointmentInfo åå¡«ã @Schema(description = "æ£è æ¥æºï¼1é¨è¯ 2æ¥è¯ 3ä½é¢ 4使£") private Integer patSrc; @Schema(description = "æ£è ææºå·") private String patMobile; @Schema(description = "æ£è çµè¯") private String patPhone; @Schema(description = "ç åºåç§°") private String patWardDesc; @Schema(description = "ç åºå·ï¼æ³¨æï¼ä¸æ¯æ¬ç±»ç bedNoï¼åè æ¯è¯çåº/å·¥ä½å·ï¼") private String patBedNo; @Schema(description = "å°±è¯å¡å·ï¼medical_cardï¼åºä¸å¤ä¸ºç©ºï¼") private String medicalCard; @Schema(description = "é¨è¯å·ï¼å®æµé¨åæ°æ®åçæ¯èº«ä»½è¯å·ï¼éçæ£å¡å·ï¼") private String outpatientNo; @Schema(description = "身份è¯å·") private String patIdentityId; /** * å»å±å·ï¼HIS æ¥æ observationRequest.id.item[root=2.16.156.10011.1.28].extensionï¼ã * ä¸ãç³è¯·åå· applyNoãä¸åï¼åè æ¯å»å±æ è¯ï¼åè æ¯ç³è¯·åæ è¯ã该èç¹å¨è§èä¸éå¿ é¡»é¡¹ï¼åºä¸å¯ä¸ºç©ºã */ private String doctorAdviceNo; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueSaveReqVO.java
@@ -89,5 +89,27 @@ @Schema(description = "è¯çåºç¼å·") private String bedNo; /** * å æ¥/æéæ è®°ï¼1=å æ¥ï¼æéæ¶ä¼å ï¼ï¼å ¶ä½/空=常è§ã * <p> * æ¥æºï¼HIS æ¥æ {@code observationRequest.zdy.jjbz}ï¼N=常è§ï¼J=å æ¥ï¼ * â é¢çº¦è®°å½ {@code appointment.jjbz} â é¢çº¦ç¡®è®¤æ¶å¸¦å ¥æéã * ä¸äººå·¥æéï¼{@code QueueServiceImpl#patientJump}ï¼å ±ç¨è¯¥åæ®µï¼ * {@code queue} 表æ {@code order by jump_flag desc, book_timeslot, create_time} åå·ï¼ * å æ¤ç½® 1 å³å®ç°"å æ¥ä¼å "ã */ @Schema(description = "å æ¥æ è®° 1=å æ¥") private Byte jumpFlag; /** * æ¯å¦åºè¾¹ï¼éæ±2ï¼ãæ¥æº HIS æ¥æ {@code observationRequest.zdy.ISCB}ï¼0=å¦ï¼1=æ¯ï¼ * â é¢çº¦è®°å½ {@code appointment.is_bedside} â é¢çº¦ç¡®è®¤æ¶å¸¦å ¥æéã * <p> * ä¸ãæ£æ¥ç±»åãçåºå«ï¼{@code check_type.value=1000} æ¯"åºè¾¹å¿çµå¾"è¿ä¸ª**项ç®**ï¼ * èæ¬åæ®µè¡¨è¾¾**åä¸é¡¹ç®ãæ£è éå°åºè¾¹å**è¿ä¸å±æ§ã */ @Schema(description = "æ¯å¦åºè¾¹ 0=å¦ 1=æ¯", example = "0") private String isBedside; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/QueueSequenceController.java
@@ -39,58 +39,61 @@ private QueueSequenceService queueSequenceService; @PostMapping("/create") @Operation(summary = "å建å½å¤©åºå·") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") @Operation(summary = "å建é¢çº¦æ¶æ®µè§å") @PreAuthorize("@ss.hasAnyPermissions('ecg:check-type:create', 'ecg:doctor:task')") public CommonResult<Integer> createQueueSequence(@Valid @RequestBody QueueSequenceSaveReqVO createReqVO) { return success(queueSequenceService.createQueueSequence(createReqVO)); } @PutMapping("/update") @Operation(summary = "æ´æ°å½å¤©åºå·") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") @Operation(summary = "æ´æ°é¢çº¦æ¶æ®µè§å") @PreAuthorize("@ss.hasAnyPermissions('ecg:check-type:update', 'ecg:doctor:task')") public CommonResult<Boolean> updateQueueSequence(@Valid @RequestBody QueueSequenceSaveReqVO updateReqVO) { queueSequenceService.updateQueueSequence(updateReqVO); return success(true); } @DeleteMapping("/delete") @Operation(summary = "å é¤å½å¤©åºå·") @Operation(summary = "å é¤é¢çº¦æ¶æ®µè§å") @Parameter(name = "id", description = "ç¼å·", required = true) @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") @PreAuthorize("@ss.hasAnyPermissions('ecg:check-type:delete', 'ecg:doctor:task')") public CommonResult<Boolean> deleteQueueSequence(@RequestParam("id") Integer id) { queueSequenceService.deleteQueueSequence(id); return success(true); } @GetMapping("/get") @Operation(summary = "è·å¾å½å¤©åºå·") @Operation(summary = "è·å¾é¢çº¦æ¶æ®µè§å") @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") @PreAuthorize("@ss.hasAnyPermissions('ecg:check-type:query', 'ecg:doctor:task')") public CommonResult<QueueSequenceRespVO> getQueueSequence(@RequestParam("id") Integer id) { QueueSequenceDO queueSequence = queueSequenceService.getQueueSequence(id); return success(BeanUtils.toBean(queueSequence, QueueSequenceRespVO.class)); } @GetMapping("/get-timeslot-by-checktype") @Operation(summary = "è·å¾å½å¤©æªæ»¡çVIPæ¶é´æ®µ") @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") @Operation(summary = "è·å¾æå®æ£æ¥ç±»åçå ¨é¨é¢çº¦æ¶æ®µ") @Parameter(name = "checkType", description = "æ£æ¥ç±»åå¼", required = true) // â ï¸ æ¬æ¥å£æä¸¤ä¸ªè°ç¨æ¹ï¼â ãé¢çº¦æ¶æ®µç»´æ¤ãçé¢ï¼check-type æéï¼ // â¡ é¢çº¦æµç¨ appointment/CheckItemPanel.vueï¼appointment æéï¼ // æ å¿ é¡»åæ¶å 许è¿ä¸ç±»æéï¼å¦åä¼ç ´åå ¶ä¸ä¸æ¡ä¸å¡æµã @PreAuthorize("@ss.hasAnyPermissions('ecg:check-type:query', 'ecg:appointment:query', 'ecg:doctor:task')") public CommonResult<List<QueueSequenceRespVO>> getTimeslotByCheckType(@RequestParam("checkType") Integer checkType) { List<QueueSequenceDO> queueSequenceList = queueSequenceService.selectGivenCheckTypeTimeslot(checkType); return success(BeanUtils.toBean(queueSequenceList, QueueSequenceRespVO.class)); } @GetMapping("/page") @Operation(summary = "è·å¾å½å¤©åºå·å页") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") @Operation(summary = "è·å¾é¢çº¦æ¶æ®µè§åå页") @PreAuthorize("@ss.hasAnyPermissions('ecg:check-type:query', 'ecg:doctor:task')") public CommonResult<PageResult<QueueSequenceRespVO>> getQueueSequencePage(@Valid QueueSequencePageReqVO pageReqVO) { PageResult<QueueSequenceDO> pageResult = queueSequenceService.getQueueSequencePage(pageReqVO); return success(BeanUtils.toBean(pageResult, QueueSequenceRespVO.class)); } @GetMapping("/export-excel") @Operation(summary = "导åºå½å¤©åºå· Excel") @PreAuthorize("@ss.hasPermission('ecg:doctor:task')") @Operation(summary = "导åºé¢çº¦æ¶æ®µè§å Excel") @PreAuthorize("@ss.hasAnyPermissions('ecg:check-type:export', 'ecg:doctor:task')") @ApiAccessLog(operateType = EXPORT) public void exportQueueSequenceExcel(@Valid QueueSequencePageReqVO pageReqVO, HttpServletResponse response) throws IOException { jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceRespVO.java
@@ -28,10 +28,18 @@ @ExcelProperty("è¯¥æ¶æ®µ æ®éæ£è åºå·") private Integer queueNo; @Schema(description = "è¯¥æ¶æ®µ æ®éæ£è èµ·å§åºå·ï¼æ¯æ¥éç½®åå°æ¤å¼ï¼") @ExcelProperty("æ®éèµ·å§åºå·") private Integer queueSet; @Schema(description = "è¯¥æ¶æ®µ vip åºå·") @ExcelProperty("è¯¥æ¶æ®µ vip åºå·") private Integer queueVipNo; @Schema(description = "è¯¥æ¶æ®µ vip èµ·å§åºå·ï¼æ¯æ¥éç½®åå°æ¤å¼ï¼") @ExcelProperty("vipèµ·å§åºå·") private Integer queueVipSet; @Schema(description = "è¯¥æ¶æ®µ æ®éæ£è åºå·æ»¡") @ExcelProperty("è¯¥æ¶æ®µ æ®éæ£è åºå·æ»¡") private Integer queueFull; jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceSaveReqVO.java
@@ -2,31 +2,44 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import javax.validation.constraints.NotNull; import java.util.*; @Schema(description = "管çåå° - å½å¤©åºå·æ°å¢/ä¿®æ¹ Request VO") @Schema(description = "管çåå° - é¢çº¦æ¶æ®µè§å æ°å¢/ä¿®æ¹ Request VO") @Data public class QueueSequenceSaveReqVO { @Schema(description = "DB 主é®", requiredMode = Schema.RequiredMode.REQUIRED, example = "11958") @Schema(description = "DB 主é®ï¼æ°å¢æ¶ç空ï¼", example = "11958") private Integer id; @Schema(description = "æ£æ¥ç±»å", example = "2") @Schema(description = "æ£æ¥ç±»åï¼å弿¥èª check_type.valueï¼", example = "100", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "æ£æ¥ç±»åä¸è½ä¸ºç©º") private Integer checkType; @Schema(description = "æ¶æ®µ") @Schema(description = "æ¶æ®µï¼HHMMHHMM å½¢å¼ï¼å¦ 8000830 表示 08:00-08:30ï¼", example = "8000830", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "æ¶æ®µä¸è½ä¸ºç©º") private Integer timeSlot; @Schema(description = "è¯¥æ¶æ®µ æ®éæ£è åºå·") @Schema(description = "è¯¥æ¶æ®µ æ®éæ£è å½ååºå·ï¼åå·æ¶ä»æ¤å¼å¾ååï¼å¯ä¸èµ·å§åºå·ä¸åï¼") private Integer queueNo; @Schema(description = "è¯¥æ¶æ®µ vip åºå·") @Schema(description = "è¯¥æ¶æ®µ æ®éæ£è èµ·å§åºå·ï¼æ¯æ¥éç½®åå°æ¤å¼ï¼") private Integer queueSet; @Schema(description = "è¯¥æ¶æ®µ vip å½ååºå·") private Integer queueVipNo; @Schema(description = "è¯¥æ¶æ®µ æ®éæ£è åºå·æ»¡") @Schema(description = "è¯¥æ¶æ®µ vip èµ·å§åºå·ï¼æ¯æ¥éç½®åå°æ¤å¼ï¼") private Integer queueVipSet; @Schema(description = "è¯¥æ¶æ®µ æ®éæ£è åºå·ä¸éï¼è¾¾å°å³è¯¥æ¶æ®µæ»¡ï¼", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "æ®éåºå·ä¸éä¸è½ä¸ºç©º") private Integer queueFull; @Schema(description = "è¯¥æ¶æ®µ vip åºå·æ»¡") @Schema(description = "è¯¥æ¶æ®µ vip åºå·ä¸é") private Integer queueVipFull; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/appointment/AppointmentDO.java
@@ -132,8 +132,52 @@ private LocalDateTime syncTime; @TableField(exist = false) /** * é¢çº¦æåºå·ã * <p> * æ¥æº HIS æ¥æ {@code actAppointment.subject.patient.id.item[]} ä¸ * {@code root=2.16.156.10011.2.5.1.11} ç项ï¼<b>æ root å¹é ï¼éæä½ç½®</b>ï¼ * ææ¡£ç¤ºä¾æ å¨ item[4]ï¼ä½å®é æ¥æ item[4] ç root æ¯ 2.5.1.8ãå°±è¯æ¬¡æ°ãï¼ * æåºå·å®é ä½äº item[6]ï¼ã */ private Integer bookSeqNum; /** * ä¼å 级 / å æ¥æ è®°ãæ¥æº HIS æ¥æ {@code observationRequest.zdy.jjbz}ï¼N=常è§ï¼J=å æ¥ã */ private String jjbz; /** * æ£æ¥æ¹å¼ç¼ç ãæ¥æº HIS æ¥æ {@code component2.observationRequest.methodCode.item[].code}ã */ private String methodCode; /** * æ£æ¥é¨ä½ç¼ç ãæ¥æº HIS æ¥æ {@code component2.observationRequest.targetSiteCode.item.code}ã */ private String targetSiteCode; /** * å»å±å·ï¼å»å±IDï¼ãæ¥æº HIS æ¥æ * {@code component2.observationRequest.id.item[root=2.16.156.10011.1.28].extension}ã * <p> * 便®ãäº¤äºæå¡éç¨æ¥å£ææ¡£ãï¼6.1 ç³è¯·åæ°å¢æå¡ç示ä¾ä¸è¯¥èç¹æ³¨é为ãå»å±IDãï¼ * 6.4/6.5 æ£æ¥é¢çº¦ç¶ææå¡ä¸æ³¨é为ãå»å±å·ãã * 宿µ S0201ECG 220 æ¡ãS0202ECG 29 æ¡åæºå¸¦è¯¥å¼ï¼å½¢å¦ {@code 112663505}ï¼ã * <p> * 注æï¼<b>䏿¯</b> {@code apply_no}ï¼ç³è¯·åå·ï¼root {@code 2.16.156.10011.1.24}ï¼ï¼äºè ä¸åã */ private String doctorAdviceNo; /** * æ£æ¥æ¿é´åç§°ãæ¥æº HIS æ¥æ {@code ZDY.roomname}ï¼S050401/S050402ï¼ã */ private String roomName; /** * 注æäºé¡¹ãæ¥æº HIS æ¥æ {@code ZDY.remark}ï¼S050401/S050402ï¼ã */ private String remark; private String status; /** @@ -143,10 +187,24 @@ /** * èè¯æ§ï¼ æ¯å¦å¤è1代表æ¯ï¼0ä»£è¡¨ä¸æ¯ * <p> * æ¥æº HIS æ¥æ {@code observationRequest.zdy.ISDN}ï¼èªå®ä¹å段åºï¼å®æ¹ææ¡£æªå®ä¹ï¼ * 宿µç宿¥æå å«è¯¥å段ï¼åå¼æä¸º 0ï¼ã */ private String tolerance; /** * æ¯å¦åºè¾¹ï¼0å¦ 1æ¯ï¼ * <p> * æ¥æº HIS æ¥æ {@code observationRequest.zdy.ISCB}ï¼èªå®ä¹å段åºï¼å®æ¹ææ¡£æªå®ä¹ï¼ * 宿µç宿¥æå å«è¯¥å段ï¼åå¼æä¸º 0ï¼ã * <p> * ä¸ãæ£æ¥ç±»åãçåºå«ï¼{@code check_type.value=1000} åç§°æ¯"åºè¾¹å¿çµå¾(常è§+é¢è°±)"ï¼ * 飿¯**ä¸ä¸ªæ£æ¥é¡¹ç®**ï¼èæ¬åæ®µè¡¨è¾¾çæ¯**åä¸é¡¹ç®ãæ£è éå°åºè¾¹å**ï¼ä¸¤è è¯ä¹ä¸åã */ private String isBedside; /** * ä½é¢å· */ private String hospitalNo; jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/checktype/CheckTypeDO.java
@@ -78,4 +78,28 @@ private String notes; private String seqPrefix; /** * æéåºå·è§åï¼éæ±ï¼ç¾å°æ¶å¦ä½ç»æ£è æéåºå·ï¼ * * <p>åå¼è§ {@link cn.lihu.jh.module.ecg.enums.SeqRuleEnum}ï¼ * <ul> * <li>0 = é¢çº¦å·ï¼ç¨é¢çº¦ç³»ç»ä¸åçå·ï¼ä¸ååé æ°å·ï¼</li> * <li>1 = ç¾å°åºå·ï¼å½å¤©åæ£æ¥ç±»åå è¿ç»éå¢ï¼æ¯ 9 个é¢ç 1 个ç»å æ¥ï¼</li> * <li>2 = æ¶æ®µå·ï¼æé¢çº¦æ¶é´æ®µç»å·ï¼ç°ç¶è§åï¼</li> * </ul> * * <p>â ï¸ åéæ°æ®è¯¥å为 null æ¶ï¼{@code SeqRuleEnum.parse()} ä¼åé为 * {@code TIMESLOT(2)} ââ å³**ä¿ææ¹é åçè¡ä¸º**ï¼ä¸ä¼å æªé ç½®èæ¹ååå·é»è¾ã */ private Integer seqRule; /** * æåºåºå·ï¼è¶å°è¶é åï¼æ£æ¥é¡¹ç®çæ¾ç¤ºé¡ºåºï¼ * * <p>éæ±ï¼æ£æ¥ç±»å管çåè¡¨éææ¤å段æåºï¼å¹¶å¯å¨çº¿ç¼è¾ã * <p>åéæ°æ®ç± {@code _prep/23_add_check_type_sort.sql} æ {@code value} ååºåå§åï¼ * ä¿è¯å级åå表顺åºä¸å级åä¸è´ã */ private Integer sort; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/devrent/DevRentDO.java
@@ -5,9 +5,7 @@ import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; import java.util.*; import java.time.LocalDateTime; import java.time.LocalDateTime; import java.time.LocalDateTime; import java.time.LocalDate; import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.*; import cn.lihu.jh.framework.mybatis.core.dataobject.BaseDO; @@ -97,4 +95,70 @@ private Integer state; private Integer paid; // ==================== éæ±1ï¼æ£è ä¿¡æ¯ 18 项æéçå¹³éºå段 ==================== // 以ä¸åæ¥èªé¢çº¦å appointmentï¼dev_rent 表æ 对åºåï¼ï¼ç± DevRentServiceImpl // æ¥è¯¢åæ applyNo 忥åå¡«ã // // ãéè¦ãå¿ é¡»æ è®° @TableField(exist = false)ï¼ // DevRentDO ä¼ç¨äº updateById / insertï¼è¥ä¸å 该注解ï¼MyBatis-Plus 伿è¿äº // ä¸åå¨çåæ¼è¿ SQLï¼å¯¼è´ "Unknown column" æ¥éã // // 乿以平éºèä¸è®©å端读 patDetails JSONï¼ // patDetails æ¯ç¡®è®¤é¢çº¦æ¶åå ¥çå¿«ç §ï¼å¯è½æ»åäº appointment çææ°å¼ï¼ // ä¸å端读 patDetails?.xxx æ TS ç±»åæç¤ºï¼å®¹æåéã @TableField(exist = false) private Byte patGender; @TableField(exist = false) private LocalDate patBirthday; @TableField(exist = false) private Date registerDate; @TableField(exist = false) private String doctor; @TableField(exist = false) private Date doctorTime; @TableField(exist = false) private Integer patSrc; @TableField(exist = false) private String patMobile; @TableField(exist = false) private String patPhone; @TableField(exist = false) private String patWardDesc; @TableField(exist = false) private String patBedNo; @TableField(exist = false) private String medicalCard; @TableField(exist = false) private String outpatientNo; @TableField(exist = false) private String patIdentityId; /** * å»å±å·ï¼HIS æ¥æ observationRequest.id.item[root=2.16.156.10011.1.28].extensionï¼ã * ä¸ãç³è¯·åå· applyNoãä¸åï¼åè æ¯å»å±æ è¯ï¼åè æ¯ç³è¯·åæ è¯ã该èç¹å¨è§èä¸éå¿ é¡»é¡¹ï¼åºä¸å¯ä¸ºç©ºã */ private String doctorAdviceNo; /** å¤èè¯ï¼0 æ / 1 å¤è / 2 å¤éèè¯ */ @TableField(exist = false) private String tolerance; /** * æ¯å¦åºè¾¹ï¼0å¦ 1æ¯ï¼ââ éæ±2ï¼æ¥æº HIS zdy.ISCB */ private String isBedside; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/jobrecord/JobRecordDO.java
@@ -2,8 +2,7 @@ import lombok.*; import java.util.*; import java.time.LocalDateTime; import java.time.LocalDateTime; import java.time.LocalDate; import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.*; import cn.lihu.jh.framework.mybatis.core.dataobject.BaseDO; @@ -77,4 +76,67 @@ @TableField(exist = false) private Integer paid; // ==================== éæ±1ï¼æ£è ä¿¡æ¯ 18 项 ==================== // job_record åªåäº patId / patNameï¼å ¶ä½æ£è ä¿¡æ¯å¨ appointment 表ã // åå¡«é¾è·¯ï¼job_record.rentId â dev_rent.applyNo â appointment // ç± JobRecordServiceImpl#fillPatientInfo æ rentId æ¹éåå¡«ï¼é¿å N+1ï¼ã // // ãéè¦ãå¿ é¡»æ @TableField(exist = false)ï¼æ¬ DO ä¼ç¨äº insert/updateByIdï¼ // è¥ä¸å 注解ï¼MyBatis-Plus 伿è¿äºä¸åå¨çåæ¼è¿ SQL â Unknown column æ¥éã @TableField(exist = false) private String applyNo; @TableField(exist = false) private String episodeId; @TableField(exist = false) private Byte patGender; @TableField(exist = false) private LocalDate patBirthday; @TableField(exist = false) private Date registerDate; @TableField(exist = false) private String doctor; @TableField(exist = false) private Date doctorTime; @TableField(exist = false) private Integer patSrc; @TableField(exist = false) private String patMobile; @TableField(exist = false) private String patPhone; @TableField(exist = false) private String patWardDesc; @TableField(exist = false) private String patBedNo; @TableField(exist = false) private String medicalCard; @TableField(exist = false) private String outpatientNo; @TableField(exist = false) private String patIdentityId; /** * å»å±å·ï¼HIS æ¥æ observationRequest.id.item[root=2.16.156.10011.1.28].extensionï¼ã * ä¸ãç³è¯·åå· applyNoãä¸åï¼åè æ¯å»å±æ è¯ï¼åè æ¯ç³è¯·åæ è¯ã该èç¹å¨è§èä¸éå¿ é¡»é¡¹ï¼åºä¸å¯ä¸ºç©ºã */ private String doctorAdviceNo; /** å¤èè¯ï¼0æ 1å¤è 2å¤éèè¯ */ @TableField(exist = false) private String tolerance; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queue/QueueDO.java
@@ -121,6 +121,15 @@ private String tolerance; /** * æ¯å¦åºè¾¹ï¼0å¦ 1æ¯ï¼ââ éæ±2ã * <p> * queue 表已æè¯¥åï¼è§ _prep/22_add_seq_rule_and_bedside.sqlï¼ï¼ * é¢çº¦ç¡®è®¤æ¶ç± appointment.is_bedside å¸¦å ¥ï¼å¯¹å·²åå¨çéåè¡ï¼ * ä¹å¯ç± {@code fillAppointmentInfo} åæ¥è¡¥å¡«ã */ private String isBedside; /** * 以ä¸å段æ¥èªé¢çº¦åï¼appointmentï¼ï¼queue 表ä¸ä¸åå¨ï¼ * ç± QueueServiceImpl#fillAppointmentInfo 卿¥è¯¢åæ applyNo 忥填å ã */ @@ -135,5 +144,42 @@ @TableField(exist = false) private Date doctorTime; // ==================== éæ±1ï¼æ£è ä¿¡æ¯ 18 项æéçå¹³éºå段 ==================== // 以ä¸åæ¥èª appointmentï¼queue 表æ 对åºåï¼ç± fillAppointmentInfo åå¡«ã // 乿以"å¹³éº"è䏿¯è®©å端读 patDetails JSONï¼ // 1) patDetails æ¯ç¡®è®¤é¢çº¦æ¶åå ¥çå¿«ç §ï¼å¯è½æ»åäº appointment çææ°å¼ï¼ // 2) å端模æ¿è¯» `row.patDetails?.xxx` æ æ³äº«å TS ç±»åæç¤ºï¼æåéã @TableField(exist = false) private Integer patSrc; @TableField(exist = false) private String patMobile; @TableField(exist = false) private String patPhone; @TableField(exist = false) private String patWardDesc; @TableField(exist = false) private String patBedNo; /** å°±è¯å¡å·ï¼medical_cardï¼åºä¸å¤ä¸ºç©ºï¼å端èªè¡åéå° outpatient_noï¼ */ @TableField(exist = false) private String medicalCard; @TableField(exist = false) private String outpatientNo; @TableField(exist = false) private String patIdentityId; /** * å»å±å·ï¼HIS æ¥æ observationRequest.id.item[root=2.16.156.10011.1.28].extensionï¼ã * ä¸ãç³è¯·åå· applyNoãä¸åï¼åè æ¯å»å±æ è¯ï¼åè æ¯ç³è¯·åæ è¯ã该èç¹å¨è§èä¸éå¿ é¡»é¡¹ï¼åºä¸å¯ä¸ºç©ºã */ private String doctorAdviceNo; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queuesequence/QueueSequenceDO.java
@@ -40,10 +40,21 @@ */ private Integer queueNo; /** * è¯¥æ¶æ®µ æ®éæ£è åºå·åå§å¼ï¼æ¯æ¥éç½®æ¶çèµ·å§å·ï¼è§ {@code QueueSequenceMapper#initNumber}ï¼ * <p> * â ï¸ åå æ¬ DO æªæ å°è¯¥åãæå·¥ç»´æ¤æ¶æ®µè§åæ¶å¿ é¡»è½è®¾ç½®å® ââ * å¦åãé¢çº¦æ¶æ®µãç»´æ¤ç颿 æ³æå®æ¯ä¸ªæ¶æ®µä»å å·å¼å§ã */ private Integer queueSet; /** * è¯¥æ¶æ®µ vip åºå· */ private Integer queueVipNo; /** * è¯¥æ¶æ®µ vip åºå·åå§å¼ï¼æ¯æ¥éç½®æ¶çèµ·å§å·ï¼ */ private Integer queueVipSet; /** * è¯¥æ¶æ®µ æ®éæ£è åºå·æ»¡ */ private Integer queueFull; jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/room/RoomDO.java
@@ -68,4 +68,16 @@ * @see cn.lihu.jh.module.ecg.enums.BedOpTypeEnum */ private Integer opType; /** * ãéæ±3ã忢åè¯å¼å ³ï¼0=æ£å¸¸æ¥æ¶åè¯æ£è ï¼1=忢æ°å¢åè¯æ£è ã * <p> * å¼å¯å**å·²æåè¯ç 人继ç»å«å·ï¼ä½ä¸åæ°å¢åè¯ç 人**ã * è¯¥åæ®µä¼ç± {@code bedReload} éè¿ BeanUtils èªå¨æ å°å° * {@link cn.lihu.jh.module.ecg.service.queue.BedBO#stopReady}ã * <p> * 注æï¼ä¸å»ç"æå"ï¼{@code status=DOCTOR_PAUSE}ï¼æ¯**两个ç¬ç«æ¦å¿µ**ï¼ * åè ç» {@code updateStop} ä¼å¼ºå¶å®æå°±è¯ä¸æ£è 并踢走åè¯ä¸æ£è ã */ private Boolean stopReady; } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/appointment/AppointmentMapper.java
@@ -52,5 +52,18 @@ @Select("select * from lihu.appointment where apply_no = #{applyNo} limit 1") AppointmentDO getByApplyNo(@Param("applyNo") String applyNo); /** * ãéæ±1ãæç³è¯·å·æ¹éæ¥è¯¢ï¼ä¾åè¡¨é¡µä¸æ¬¡æ§åå¡«æ£è ä¿¡æ¯ï¼é¿å N+1 æ¥è¯¢ã * * @param applyNoList ç³è¯·å·å表ï¼è°ç¨æ¹éä¿è¯é空ï¼MySQL ç IN () ä¼è¯æ³éè¯¯ï¼ */ @Select("<script>" + "select * from lihu.appointment where deleted = 0 and apply_no in (" + " <foreach collection='applyNoList' separator=',' item='_applyNo'>" + " #{_applyNo} " + " </foreach> )" + "</script>") List<AppointmentDO> getByApplyNoList(@Param("applyNoList") List<String> applyNoList); } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/checktype/CheckTypeMapper.java
@@ -30,7 +30,9 @@ .eqIfPresent(CheckTypeDO::getTimeslotBookNum, reqVO.getTimeslotBookNum()) .eqIfPresent(CheckTypeDO::getTimeslotReservedNum, reqVO.getTimeslotReservedNum()) .eqIfPresent(CheckTypeDO::getAffinityCheckTypes, reqVO.getAffinityCheckTypes()) .orderByDesc(CheckTypeDO::getId)); // éæ±9ï¼æãæåºåºå·ãååºå±ç¤ºï¼åå æ id ååºï¼ä¸ä¸å¡æåºæ å ³ï¼ .orderByAsc(CheckTypeDO::getSort) .orderByAsc(CheckTypeDO::getValue)); } default PageResult<CheckTypeDO> selectPageForCallingScreen(CheckTypePageReqVO reqVO) { @@ -46,7 +48,9 @@ .eqIfPresent(CheckTypeDO::getTimeslotBookNum, reqVO.getTimeslotBookNum()) .eqIfPresent(CheckTypeDO::getTimeslotReservedNum, reqVO.getTimeslotReservedNum()) .eqIfPresent(CheckTypeDO::getAffinityCheckTypes, reqVO.getAffinityCheckTypes()) .orderByDesc(CheckTypeDO::getId)); // éæ±9ï¼æãæåºåºå·ãååºå±ç¤ºï¼åå æ id ååºï¼ä¸ä¸å¡æåºæ å ³ï¼ .orderByAsc(CheckTypeDO::getSort) .orderByAsc(CheckTypeDO::getValue)); } @Select("SELECT * FROM lihu.check_type;") jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/devrent/DevRentMapper.java
@@ -74,4 +74,23 @@ @Update("update lihu.dev_rent set paid = #{paid} where id = #{rentId};") Integer setPaid(@Param("rentId") Long rentId, @Param("paid") Integer paid); /** * ãéæ±1ãæ id æ¹éåãid + apply_noãã * <p> * ç¨éï¼ä½ä¸è®°å½å表页åå¡«æ£è ä¿¡æ¯æ¶éè¦ `job_record.rentId â dev_rent.applyNo`ã * åå ç¨ {@code selectById} éæ¡åï¼N 次æ¥è¯¢ï¼ï¼æ¬æ¹æ³æ¹ä¸ºä¸æ¬¡ IN æ¥è¯¢ã * <p> * 廿**åªå两å**èé `SELECT *`ï¼dev_rent å« `pat_details` ç JSON 大忮µï¼ * åå¡«åªé applyNoï¼æ²¡å¿ è¦ææ´ä¸ª DO æåæ¥ã * * @param rentIdList ç§èµ id å表ï¼è°ç¨æ¹éä¿è¯é空ï¼MySQL ç IN () ä¼è¯æ³éè¯¯ï¼ */ @Select("<script>" + "SELECT id, apply_no FROM lihu.dev_rent WHERE id IN (" + " <foreach collection='rentIdList' separator=',' item='rentId'>" + " #{rentId} " + " </foreach> )" + "</script>") List<DevRentDO> getApplyNoByIdList(@Param("rentIdList") List<Long> rentIdList); } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/jobrecord/JobRecordMapper.java
@@ -35,6 +35,8 @@ .eqIfPresent(JobRecordDO::getRemark, reqVO.getRemark()) .betweenIfPresent(JobRecordDO::getCreateTime, reqVO.getCreateTime()) .eqIfPresent(JobRecordDO::getRentId, reqVO.getRentId()) // æè¯å®¤çæ£æ¥é¡¹ç®éç¦»å·²å®æè®°å½ï¼è¯¦è§ JobRecordPageReqVO#checkTypes 注éï¼ .inIfPresent(JobRecordDO::getCheckType, reqVO.getCheckTypes()) .orderByDesc(JobRecordDO::getId)); } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queue/QueueMapper.java
@@ -54,11 +54,16 @@ @Select(""" <script> SELECT * FROM lihu.queue where room_id = #{roomId} and status in ( where room_id = #{roomId} and deleted = 0 and status in ( <foreach collection='statusList' separator=',' item='status'> #{status} </foreach> ) order by status desc, seq_num, book_timeslot order by case when status = 30 then 0 when status in (3, 5) then 1 else 2 end, seq_num, book_timeslot </script> """) @Results({ @@ -66,14 +71,31 @@ }) List<QueueDO> getRoomQueueByStatus(@Param("roomId")Long roomId, @Param("statusList")List<Integer> statusList); @Select("<script>" + "SELECT * FROM lihu.queue " + "where status in (" + " <foreach collection='statusList' separator=',' item='status'>" + " #{status} " + " </foreach> )" + " order by status desc, seq_num, book_timeslot" + "</script>") /** * 大å±åæ°ã * <p> * æåºè§åï¼éæ±8ï¼ï¼**å°±è¯ä¸(30) 置顶 â è¿å·(3/5) ä¸çå(10/15/20/12) ææéåºå· seq_num ååºæ··æ**ã * åå ç¨ {@code order by status desc}ï¼ä¼æè¿å·(3/5)æå°æ¯ä¸åæåºé¨ï¼ * å¨ {@code overflow-y:auto} çåéæ»ä¸å°ï¼çåäº"è¿å·ä¸æ¾ç¤º"ã * <p> * åæ¶è¡¥ä¸ {@code deleted = 0}ï¼æ¬æ¹æ³æ¯èªå®ä¹ {@code @Select}ï¼ * ä¼ç»è¿ MyBatis-Plus ç {@code @TableLogic} é»è¾å é¤è¿æ»¤ã */ @Select(""" <script> SELECT * FROM lihu.queue where deleted = 0 and status in ( <foreach collection='statusList' separator=',' item='status'> #{status} </foreach> ) order by case when status = 30 then 0 when status in (3, 5) then 1 else 2 end, seq_num, book_timeslot </script> """) @Results({ @Result(property = "patDetails", column = "pat_details", typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class) }) @@ -150,6 +172,7 @@ @Select("<script>" + "SELECT count(1) as total_in_status FROM lihu.queue where " + " deleted = 0 and book_date = CURDATE() and " + " status in ( " + " <foreach collection='statusList' separator=',' item='status'>" + " #{status} " + @@ -172,6 +195,7 @@ @Select("<script>" + "SELECT status, count(1) as total_in_status FROM lihu.queue where " + " deleted = 0 and book_date = CURDATE() and " + " room_id = #{roomId} and bed_no = #{bedNo} " + " group by status " + "</script>") @@ -179,6 +203,7 @@ @Select("<script>" + "SELECT status, count(1) as total_in_status FROM lihu.queue where " + " deleted = 0 and book_date = CURDATE() and " + " room_id = #{roomId} " + " group by status " + "</script>") @@ -186,7 +211,8 @@ @Select("<script>" + "SELECT count(1) FROM lihu.queue " + "where room_id = #{roomId} and bed_no = #{bedNo} and status in (" + "where deleted = 0 and book_date = CURDATE() and " + " room_id = #{roomId} and bed_no = #{bedNo} and status in (" + " <foreach collection='statusList' separator=',' item='status'>" + " #{status} " + " </foreach> )" + @@ -196,7 +222,7 @@ @Select(""" <script> SELECT * FROM lihu.queue where room_id = #{roomId} and bed_no = #{bedNo} and status in ( where deleted = 0 and room_id = #{roomId} and bed_no = #{bedNo} and status in ( <foreach collection='statusList' separator=',' item='status'> #{status} </foreach> ) @@ -213,6 +239,48 @@ and status = #{curStatus} order by seq_num, book_timeslot limit 1 """) QueueDO getBedFirstQueueItemByStatus(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("curStatus")Integer curStatus); /** * ãéæ±2 ç¸å ³ç¼ºé·ä¿®å¤ãæãå·¥ä½ + æ£è + æ£æ¥ç±»å + ç¶æã**精确**å®ä½éåè¡ã * <p> * ç¨äºæ¿ä»£ {@link #getBedFirstQueueItemByStatus}ï¼åè åªæ"å·¥ä½ + ç¶æå seq_num æå°ç䏿¡"ï¼ * å½å»çå ç¹"æ¾å¼æ£æ¥"ï¼ä¼æè¯¥æ£è 置为 40ï¼ååç¹"æ£æ¥å®æ"æ¶ï¼ * ä¼åå°**ä¸ä¸ä½æ£è **å¹¶æä»è¯¯ç½®ä¸ºå·²å®æï¼è¯¦è§ DevRentServiceImpl.routineFinishOperationï¼ã */ @Select(""" SELECT * from lihu.queue where room_id = #{roomId} and bed_no = #{bedNo} and status = #{curStatus} and pat_id = #{patId} and book_check_type = #{checkType} and TO_DAYS(book_date) = TO_DAYS(NOW()) order by seq_num limit 1 """) @Results({ @Result(property = "patDetails", column = "pat_details", typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class) }) QueueDO getBedQueueItemByPatAndStatus(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("patId")String patId, @Param("checkType")Integer checkType, @Param("curStatus")Integer curStatus); /** * æå·¥ä½ + ç¶æ + 仿¥å**æè¿æ´æ°**ç䏿¡ã * <p> * æ¯ãseq_num æå°ãæ´è´´å"å½åæ£å¨å°±è¯/è£ æºçé£ä½æ£è "ï¼seq_num æå°æ¯æ¬æ¶æ®µææ©æéçï¼ * è update_time ææ°ææ¯å被å«å·æ¨è¿å°è¯¥ç¶æçã */ @Select(""" SELECT * from lihu.queue where room_id = #{roomId} and bed_no = #{bedNo} and status = #{curStatus} and TO_DAYS(book_date) = TO_DAYS(NOW()) order by update_time desc, seq_num limit 1 """) @Results({ @Result(property = "patDetails", column = "pat_details", typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class) }) QueueDO getBedLatestQueueItemByStatus(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("curStatus")Integer curStatus); @Select(""" SELECT * from lihu.queue where apply_no = #{applyNo} and status = #{curStatus} order by seq_num, book_timeslot limit 1 @@ -326,6 +394,52 @@ Integer queueJump(@Param("patId")String patId, @Param("bookCheckType")Integer bookCheckType, @Param("curStatus")Integer curStatus, @Param("jumped")Byte jumped ); // ==================== éæ±2ï¼è¯¯ç¹ãå«å· / æ£æ¥å®æãçæ¤é ==================== /** * æ¤éãæ£æ¥å®æãï¼ææ¬å·¥ä½ä»æ¥ç**æå®æ£è **ä» å·²å°±è¯(40) éå åè¯ä¸(20)ã * <p> * å¿ é¡»æ {@code pat_id + book_check_type + 仿¥} 精确å®ä½ï¼**ä¸è½**åªæ * "å·¥ä½ + status=40 åç¬¬ä¸æ¡"ââé£ä¼å¨æé´å·²å«ä¸ä¸ä½æ£è æ¶è¯¯æ¹ä»äººï¼è§ * {@code DevRentServiceImpl.routineFinishOperation} çæ¢æç¼ºé·ï¼ã * <p> * {@code passed = 0} æ¯ä¸ºäºè®©æ£è éæ°åå°æ£å¸¸åè¯åºåï¼é"è¿å·"æï¼ã */ @Update("update lihu.queue set status = #{newStatus}, passed = 0 " + " where room_id = #{roomId} and bed_no = #{bedNo} and status = #{curStatus} " + " and pat_id = #{patId} and book_check_type = #{checkType} " + " and TO_DAYS(book_date) = TO_DAYS(NOW())") Integer undoFinishPatient(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("patId")String patId, @Param("checkType")Integer checkType, @Param("curStatus")Integer curStatus, @Param("newStatus")Integer newStatus); /** * æ¤éã误ç¹å«å·ãï¼ææ¬å·¥ä½å½å å°±è¯ä¸(30) çæ£è éå åè¯ä¸(20)ã * <p> * ä» æå·¥ä½+ç¶æå®ä½ï¼"å½åæ£å¨å°±è¯çé£ä¸ä½"ï¼ï¼ä¸ä½¿ç¨ seq_num åæ¥è¯¢ï¼ * é¿å ä¸ {@code updateBedQueueStatus} çåæ³æ··æ·ã */ @Update("update lihu.queue set status = #{newStatus} " + " where id = " + " (select a.id from " + " (select id from lihu.queue where room_id = #{roomId} and bed_no = #{bedNo} " + " and status = #{curStatus} and TO_DAYS(book_date) = TO_DAYS(NOW()) " + " order by seq_num, book_timeslot limit 1) a)") Integer undoCallPatient(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("curStatus")Integer curStatus, @Param("newStatus")Integer newStatus); /** * 忬工ä½ä»æ¥**æè¿ä¸ä½å·²å®æ**çæ£è ï¼ç¨äºçé¢æç¤º"坿¤éçæ¯è°"ï¼ã */ @Select("SELECT * FROM lihu.queue where room_id = #{roomId} and bed_no = #{bedNo} " + " and status = #{status} and TO_DAYS(book_date) = TO_DAYS(NOW()) " + " order by update_time desc, seq_num desc limit 1") @Results({ @Result(property = "patDetails", column = "pat_details", typeHandler=com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class) }) QueueDO getBedLastFinishedQueueItem(@Param("roomId")Long roomId, @Param("bedNo")String bedNo, @Param("status")Integer status); //@Update("TRUNCATE TABLE lihu.queue") @Delete("delete from lihu.queue where TO_DAYS(book_date) != TO_DAYS(NOW())") void clearQueue(); jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queuesequence/QueueSequenceMapper.java
@@ -6,6 +6,8 @@ import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.lihu.jh.framework.mybatis.core.mapper.BaseMapperX; import cn.lihu.jh.module.ecg.dal.dataobject.queuesequence.QueueSequenceDO; import cn.lihu.jh.module.ecg.dal.dataobject.queuesequence.SeqCounterDO; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import org.apache.ibatis.annotations.*; import cn.lihu.jh.module.ecg.controller.admin.queuesequence.vo.*; @@ -26,7 +28,10 @@ .eqIfPresent(QueueSequenceDO::getQueueFull, reqVO.getQueueFull()) .eqIfPresent(QueueSequenceDO::getQueueVipFull, reqVO.getQueueVipFull()) .betweenIfPresent(QueueSequenceDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(QueueSequenceDO::getId)); // ãé¢çº¦æ¶æ®µç»´æ¤çé¢ãæãæ£æ¥ç±»å â æ¶æ®µãååºæåï¼ // 便äºå¨åä¸é¡¹ç®ä¸é¡ºåºæ¥ç/ç¼è¾åæ¶æ®µï¼åå®ç°æ id ååºï¼ç»´æ¤æ¶é¾ä»¥é è¯»ï¼ .orderByAsc(QueueSequenceDO::getCheckType) .orderByAsc(QueueSequenceDO::getTimeSlot)); } @Select(" select * from lihu.queue_sequence where check_type=#{checkType}; ") @@ -55,4 +60,127 @@ @Update("UPDATE lihu.queue_sequence SET queue_no=queue_set,queue_vip_no=queue_vip_set WHERE deleted=0; ") Integer initNumber(); /** * ãä¿®å¤ãæ¶æ®µä¸å ¨/å·²æ»¡å¯¼è´æ²¡æ³ç¾å°ãã夿æå® (æ£æ¥ç±»å, æ¶æ®µ) æ¯å¦**è¿æå¯åå·**ã * <p> * 注æï¼ä¸ {@link #selectQueueNoForUpdate} ä¸åï¼æ¬æ¹æ³**ä¸å for update**ã * ä¹ä¸è¿åå ·ä½å·å¼ ââ å®åªç¨äºãåå寻æ¾ä¸ä¸ªå¯ç¨æ¶æ®µãæ¶çæ¢æµï¼ä¸åä¸å¹¶ååå·ï¼ * çæ£åå·ä»ç± {@code selectQueueNoForUpdate} å¨äºå¡å 宿ã * * @param includeVip true æ¶åæ¶è¦æ± VIP å·ä¹æä½éï¼VIP æ£è ç¨ï¼ * @return 1 = æä½éï¼0 = è¯¥æ¶æ®µä¸åå¨æå·²æ»¡ */ @Select("select count(1) from lihu.queue_sequence " + " where check_type = #{checkType} and time_slot = #{timeslot} " + " and queue_no < queue_full " + " and (#{includeVip} = 0 or queue_vip_no < queue_vip_full)") Integer countAvailableTimeslot(@Param("checkType") Integer checkType, @Param("timeslot") Integer timeslot, @Param("includeVip") Integer includeVip); // ========================================================================= // ãéæ±ï¼æéåºå·è§å = ç¾å°åºå·ã计æ°å¨ï¼seq_counter è¡¨ï¼ // // 设计è¦ç¹ï¼ä¸¤æ¬¡å®æµè¸©ååç¡®å®ï¼å¿æ¹åï¼ï¼ // â æ®éå·ä¸é¢çå·ç¨**两个ç¬ç«è®¡æ°å¨** ââ å个计æ°å¨"è¿ç®åè·³è¿"å¿ ç¶éå·ï¼ // æ®éæ£è candidate=10 â è·³è¿é¢çå¾ 11ï¼ä¸ä¸ä¸ª candidate=11 â ä¹å¾ 11ã // â¡ æ¨è¿ç¨åæ¡ INSERT..ON DUPLICATE KEY UPDATEï¼ååï¼ï¼ // 读åå¿ é¡»ä¸æ¨è¿å¤äº**åä¸äºå¡**ï¼å¦å REPEATABLE READ ä¼è¯»å°æ§å¿«ç §ã // 宿µï¼autoCommit=true æ¶ 160 次åå·ä» 75 个å¯ä¸å¼ï¼å äºå¡å 160/160ã // ========================================================================= /** * å忍è¿ãæ®éå·ã计æ°å¨ï¼å¹¶è¿ååé å°çæ®éå·ã * * <h4>计æ°å¨è¯ä¹ï¼å ³é®ï¼å¿æ¹ï¼</h4> * {@code normal_next} åçæ¯**ä¸ä¸æ¬¡å·²åé åºå»çæ®éå·**ï¼é¦æ¬¡ä¸º 0ï¼ã * æ¬æ¬¡åé {@code = normal_next + 1}ï¼è¥è¯¥å¼æ°æ¯é¢çå·ï¼10 çåæ°ï¼ï¼ * åæ¬æ¬¡åé å®é ä¸è¦è·³å° {@code +2}ï¼å¹¶æè®¡æ°å¨ä¸å¹¶æ¨è¿å° {@code +2}ã * * <pre> * normal_next: 0 â åé 1 â 1 â åé 2 â ⦠â 9 â åé 11(è·³è¿10) â 11 â åé 12 â ⦠* â 计æ°å¨ +2ï¼å æ¤ä¸ä¼å¨ä¸ä¸æ¬¡åäº§åº 11 * </pre> * * <h4>为ä»ä¹ä¸è½åª +1</h4> * è¥è®¡æ°å¨åª +1ï¼{@code normal_next=10} æ¶åé {@code nextNormalSeq(11)=11}ï¼ * è {@code normal_next=11} æ¶ååé 11 ââ **åä¸ä¸ªå·å两次**ã * åå æµè¯ {@code SeqRuleEnumTest#testNextNormalSeq_shouldSkipMultiplesOfTen} æ¾æè·æ¤é®é¢ã * <p> * æ¬ SQL ä¸ç {@code IF} æ£æ¯"è·³è¿é¢çå·æ¶é¢å¤ +1"ï¼çä»·äº Java ç * {@code nextNormalSeq(normal_next + 1)}ï¼ä¸**å¨ä¸æ¡è¯å¥å åå宿**ã * * @return æ¬æ¬¡åé å°çæ®éå· */ // ========================================================================== // â ï¸ å¿ é¡»å @InterceptorIgnore(dataPermission = "true")ï¼å¦åãé¢çº¦ç¡®è®¤ç´æ¥ 500ã // // 宿µæ éï¼2026-10-01 çº¿ä¸æ¥å¿ï¼ï¼ // org.mybatis.spring.MyBatisSystemException: ... UnsupportedOperationException // at JsqlParserSupport.processInsert(JsqlParserSupport.java:107) // at DataPermissionInterceptor.beforePrepare(DataPermissionInterceptor.java:86) // ### The error may involve QueueSequenceMapper.advanceNormalSeq // ï¼è°ç¨é¾ appointment/confirm â distributeSeqNoByRule â nextCheckInSeqNo â advanceNormalSeqï¼ // // åå ï¼MyBatis-Plus ç DataPermissionInterceptor ä¼ç¨ JSqlParser è§£ææ¯æ¡ SQLï¼ // è JSqlParser ç processInsert **䏿¯æ MySQL ç `INSERT ... ON DUPLICATE KEY UPDATE`** // è¯æ³ï¼ç´æ¥æ UnsupportedOperationExceptionï¼è¯¥å¼å¸¸ç©¿éå°ä¸å¡å±ï¼å¯¼è´ç¾å°å¤±è´¥ã // ââ è¿æ¯ãæ¡æ¶æ¦æªå¨ãä¸ãMySQL ä¸æè¯æ³ãçå²çªï¼ä¸ SQL æ¬èº«æ¯å¦æ£ç¡®æ å ³ã // // 为ä»ä¹å¯ä»¥ãä¹åºè¯¥å¿½ç¥æ°æ®æéï¼ // 1) seq_counter 表**æ¢æ²¡æ dept_id 乿²¡æ user_id**ï¼æ°æ®æéè§å坹宿¬å°±æ æä¹ï¼ // 2) æ¬è¯å¥æ¯çº¯ç²¹çåå计æ°å¨æ¨è¿ï¼ä¸æ¶åä»»ä½éè¦æé¨é¨/ç¨æ·éç¦»çæ°æ®ã // ========================================================================== @InterceptorIgnore(dataPermission = "true") @Update("INSERT INTO lihu.seq_counter (check_type, seq_date, normal_next, reserved_next) " + "VALUES (#{checkType}, #{seqDate}, 1, 10) " + "ON DUPLICATE KEY UPDATE normal_next = normal_next + 1 " + " + IF((normal_next + 1) % 10 = 0, 1, 0)") int advanceNormalSeq(@Param("checkType") Integer checkType, @Param("seqDate") java.time.LocalDate seqDate); /** * å忍è¿ãé¢çå·ã计æ°å¨ï¼å¹¶è¿ååé å°çé¢çå·ï¼å æ¥æ£è ç¨ï¼ã * <p> * é¢çå·åºåï¼10ã20ã30â¦ï¼åºå®ä¸º 10 çåæ°ï¼ã * <p> * åæ ·éè¦ {@code @InterceptorIgnore(dataPermission = "true")}ï¼åå è§ * {@link #advanceNormalSeq} 䏿¹ç详ç»è¯´æï¼JSqlParser 䏿¯ææ¬è¯æ³ï¼ã * * @return æ¬æ¬¡åé å°çé¢çå· */ @InterceptorIgnore(dataPermission = "true") @Update("INSERT INTO lihu.seq_counter (check_type, seq_date, normal_next, reserved_next) " + "VALUES (#{checkType}, #{seqDate}, 1, 10) " + "ON DUPLICATE KEY UPDATE reserved_next = reserved_next + 10") int advanceReservedSeq(@Param("checkType") Integer checkType, @Param("seqDate") java.time.LocalDate seqDate); /** * 读å两个计æ°å¨çå½åå¼ï¼å³æ¬æ¬¡è¦åé çå·ï¼ã * * <h4>â ï¸ å¿ é¡»ä¸ advance* å¤äºãåä¸äºå¡ãå </h4> * MySQL é»è®¤ REPEATABLE READï¼è¥ SELECT å¨ç¬ç«äºå¡ä¸ï¼ä¼è¯»å°äºå¡å¼å§æ¶çå¿«ç §æ§å¼ï¼ * ä»èæå·²è¢«å«äººç¨æçå·éå¤ååºå»ã * <p> * 宿µå¯¹æ¯ï¼8 çº¿ç¨ Ã 20 次 = 160 次åå·ï¼ï¼ * <table border="1"> * <tr><th>æ¹å¼</th><th>å¯ä¸å¼</th><th>ç»è®º</th></tr> * <tr><td>autoCommit=trueï¼æ¨è¿ä¸è¯»ååèªç¬ç«äºå¡ï¼</td><td>75 / 160</td><td>ð´ 大ééå·</td></tr> * <tr><td>æ¾å¼äºå¡ï¼BEGIN â æ¨è¿ â 读å â COMMITï¼</td><td><b>160 / 160</b></td><td>â å·å¼ 1~160 è¿ç»æ é</td></tr> * </table> * è°ç¨æ¹ {@code QueueSequenceServiceImpl#distributeSeqNoByRule} å·²æ æ³¨ {@code @Transactional}ï¼ * è¿æ¯**å¿ é¡»ä¿æ**çåæï¼è¯·å¿ææ¬æ¹æ³æªå°æ äºå¡çä¸ä¸æä¸åç¬è°ç¨ã * * @return {@code [0]=normal_next, [1]=reserved_next} */ @Select("SELECT normal_next, reserved_next FROM lihu.seq_counter " + " WHERE check_type = #{checkType} AND seq_date = #{seqDate}") @Results({ @Result(property = "normalNext", column = "normal_next"), @Result(property = "reservedNext", column = "reserved_next") }) SeqCounterDO getSeqCounter(@Param("checkType") Integer checkType, @Param("seqDate") java.time.LocalDate seqDate); } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/room/RoomMapper.java
@@ -92,6 +92,17 @@ "</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); @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)" + jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/ActionTypeEnum.java
@@ -3,20 +3,55 @@ import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Arrays; import java.util.List; /** * Actionç±»åæä¸¾ * HIS æ¥æ header ä¸ action çå弿䏾ã * * <h3>å ³äº PACS / ECG ç action åºå</h3> * 颿¹ãäº¤äºæå¡éç¨æ¥å£ææ¡£ãä¸ï¼å䏿å¡å¨ä¸åç³»ç»ä¸ä½¿ç¨**ä¸åç交æç¼å·**ï¼ * <pre> * 6.4 æ£æ¥é¢çº¦ç¶ææ°å¢ï¼S050401ï¼pacsï¼ / S050402ï¼ECGï¼ * 6.5 æ£æ¥é¢çº¦ç¶ææ´æ°ï¼S050501ï¼pacsï¼ / S050502ï¼ECGï¼ * </pre> * * <p><b>宿µç»è®ºï¼2026-09-17 æ¥å¿ï¼å ± 1753 æ¡è¯·æ±ï¼</b>ï¼å®é å°è¾¾ç action åªæ * {@code S0405}ã{@code S050401}ã{@code S0201ECG}ã{@code S0202ECG}ã * {@code S050501}ã{@code S040501HIS} å ç§ï¼å ¶ä¸ * <b>{@code S050402} ä¸ {@code S050502} åºç° 0 次</b>ã * å³é¢æ¹å½åèµ°çæ¯ pacs ç¼å·ï¼ECG ä¸å±ç¼å·å°æªå¯ç¨ã * * <p>为äºå¨é¢æ¹åæ¢ç¼å·æ¶ä¸ä¸¢æ¶æ¯ï¼è¿é**åæ¶æ³¨å两ç§ç¼å·**ï¼ä¸»å¨å ¼å®¹ï¼ï¼ * å¹¶é¢å¤å ¼å®¹ç³è¯·åæ°å¢/æ´æ°çæ åç¼åæ³ {@code S0201} / {@code S0202} * ï¼ææ¡£åªå®ä¹äºæ åç¼å½¢å¼ï¼è宿µæ¥æå¸¦ {@code ECG} åç¼ï¼ã * * @author å¿çµæéè£ æºç³»ç» */ @Getter @AllArgsConstructor public enum ActionTypeEnum { // ---------- 6.1 ç³è¯·åæ°å¢ï¼ææ¡£ä¸º S0201ï¼å®æµæ¥æä¸º S0201ECGï¼ä¸¤ç§é½å ¼å®¹ï¼ ---------- S0201ECG("S0201ECG", "ç³è¯·åå建"), S0202ECG("S0202ECG", "ç³è¯·åæ´æ°"), S040501HIS("S040501HIS", "é¢çº¦æ´æ°"), S050401("S050401", "æ£æ¥é¢çº¦ç¶ææ°å¢"), S0405("S0405", "ç³è¯·åç»è®°ç¶ææ´æ°"), S050501("S050501", "æ£æ¥é¢çº¦ç¶æä¿®æ¹"); S0201("S0201", "ç³è¯·åå建"), // ---------- 6.2 ç³è¯·åæ´æ°ï¼ææ¡£ä¸º S0202ï¼å®æµæ¥æä¸º S0202ECGï¼ ---------- S0202ECG("S0202ECG", "ç³è¯·åæ´æ°"), S0202("S0202", "ç³è¯·åæ´æ°"), // ---------- 6.3 ç³è¯·åç¶ææ´æ°ï¼å ¨é¢éç¨ï¼ä¸åºåç§å®¤ï¼ ---------- S040501HIS("S040501HIS", "é¢çº¦æ´æ°"), S0405HIS("S0405HIS", "ç³è¯·åç¶ææ´æ°"), S0405("S0405", "ç³è¯·åç»è®°ç¶ææ´æ°"), // ---------- 6.4 æ£æ¥é¢çº¦ç¶ææ°å¢ï¼pacs / ECG 两ç§ç¼å·é½æ¥æ¶ï¼ ---------- S050401("S050401", "æ£æ¥é¢çº¦ç¶ææ°å¢"), // pacs S050402("S050402", "æ£æ¥é¢çº¦ç¶ææ°å¢"), // ECGï¼ææ¡£å®ä¹ï¼å½åæªå¯ç¨ï¼ä¸»å¨å ¼å®¹ï¼ // ---------- 6.5 æ£æ¥é¢çº¦ç¶ææ´æ°ï¼pacs / ECG 两ç§ç¼å·é½æ¥æ¶ï¼ ---------- S050501("S050501", "æ£æ¥é¢çº¦ç¶æä¿®æ¹"), // pacs S050502("S050502", "æ£æ¥é¢çº¦ç¶æä¿®æ¹"); // ECGï¼ææ¡£å®ä¹ï¼å½åæªå¯ç¨ï¼ä¸»å¨å ¼å®¹ï¼ /** * ç±»å @@ -28,17 +63,79 @@ private final String description; /** * æ ¹æ®ç±»åè·åæä¸¾ * æ ¹æ®ç±»åè·åæä¸¾ã * <p> * å ¼å®¹å¤çï¼å ¥åå å»é¤é¦å°¾ç©ºç½ï¼è¥æªå½ä¸ï¼åå°è¯å¿½ç¥å¤§å°åå¹é ï¼ * é¿å å HIS 侧大å°åä¸ä¸è´ï¼å¦ {@code s0201ecg}ï¼å¯¼è´æ´æ¡æ¶æ¯è¢«æã * * @param type ç±»å * @return æä¸¾ * @param type action å¼ * @return æä¸¾ï¼æ æ³è¯å«æ¶è¿å null */ public static ActionTypeEnum getByType(String type) { if (type == null) { return null; } String trimmed = type.trim(); if (trimmed.isEmpty()) { return null; } // 1. 精确å¹é for (ActionTypeEnum value : values()) { if (value.getType().equals(type)) { if (value.type.equals(trimmed)) { return value; } } // 2. 忽ç¥å¤§å°åå åº for (ActionTypeEnum value : values()) { if (value.type.equalsIgnoreCase(trimmed)) { return value; } } return null; } /** ç³è¯·åæ°å¢ç±» actionï¼å«æ åç¼å ¼å®¹åæ³ï¼ */ public static final List<ActionTypeEnum> APPLY_CREATE_ACTIONS = Arrays.asList(S0201ECG, S0201); /** ç³è¯·åæ´æ°ç±» actionï¼å«æ åç¼å ¼å®¹åæ³ï¼ */ public static final List<ActionTypeEnum> APPLY_UPDATE_ACTIONS = Arrays.asList(S0202ECG, S0202); /** ç³è¯·åç¶ææ´æ°ç±» actionï¼å ¨é¢éç¨ï¼ */ public static final List<ActionTypeEnum> APPLY_STATUS_ACTIONS = Arrays.asList(S040501HIS, S0405HIS, S0405); /** æ£æ¥é¢çº¦ç¶ææ°å¢ç±» actionï¼pacs + ECGï¼ */ public static final List<ActionTypeEnum> APPOINTMENT_STATUS_CREATE_ACTIONS = Arrays.asList(S050401, S050402); /** æ£æ¥é¢çº¦ç¶ææ´æ°ç±» actionï¼pacs + ECGï¼ */ public static final List<ActionTypeEnum> APPOINTMENT_STATUS_UPDATE_ACTIONS = Arrays.asList(S050501, S050502); /** æ¯å¦ä¸ºç³è¯·åæ°å¢ */ public boolean isApplyCreate() { return APPLY_CREATE_ACTIONS.contains(this); } /** æ¯å¦ä¸ºç³è¯·åæ´æ° */ public boolean isApplyUpdate() { return APPLY_UPDATE_ACTIONS.contains(this); } /** æ¯å¦ä¸ºç³è¯·åç¶ææ´æ°ï¼å ¨é¢éç¨æµï¼éè¦æå¿çµä¸å¡è¿æ»¤ï¼ */ public boolean isApplyStatusUpdate() { return APPLY_STATUS_ACTIONS.contains(this); } /** æ¯å¦ä¸ºæ£æ¥é¢çº¦ç¶ææ°å¢ */ public boolean isAppointmentStatusCreate() { return APPOINTMENT_STATUS_CREATE_ACTIONS.contains(this); } /** æ¯å¦ä¸ºæ£æ¥é¢çº¦ç¶ææ´æ° */ public boolean isAppointmentStatusUpdate() { return APPOINTMENT_STATUS_UPDATE_ACTIONS.contains(this); } } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/AppointmentTypeEnum.java
@@ -4,41 +4,66 @@ import lombok.Getter; /** * Actionç±»åæä¸¾ * æ£æ¥ç¶æç¼ç æä¸¾ã * * <h3>ä¿®æ£è¯´æ</h3> * åå®ç°åå¨ä¸¤å¤é®é¢ï¼å·²ä¿®æ£ï¼ * <ol> * <li><b>åé¢å¼å«ç©ºç½æ±¡æ</b>ï¼åå®ä¹ä¸º {@code SQDKL(" 1", ...)}ã * {@code JCDJ(" 3\t", ...)}ï¼type å¼åæç©ºæ ¼ãé¨åå«å¶è¡¨ç¬¦ï¼ * å¯¼è´ {@link #getByType(String)} 对æ£å¸¸ä¼ å ¥ç {@code "1"}ã{@code "3"} * å¹é 失败ï¼è¿å nullï¼ãç°å·²å»é¤å ¨é¨ç©ºç½ã</li> * <li><b>å å«ç çä¸ç¨ç¶æ</b>ï¼åè¡¨å« 21 æ æ¬éæ£ã22 åæ¶æ æ¬éæ£ã23 å·²ç¼´è´¹ï¼ * è¿äºå±ç çç§ä¸å¡ï¼å¿çµç³»ç»ä¸æ¶åï¼å·²ç§»é¤ã</li> * </ol> * * <p>ç¼ç å¼ä¸ãæ£æ¥ç¶æç¼ç 表ãä¸è´ãç¶æç**å½ä¸å**ï¼å»å导é¶ãæ ¡éªåæ³æ§ï¼ * è¯·ä½¿ç¨ {@link HisCheckStatusEnum#normalize(String)}ï¼æ¬æä¸¾åªè´è´£ * ç±»åå¼å°åç§°çå±ç¤ºæ å°ã * * @author å¿çµæéè£ æºç³»ç» */ @Getter @AllArgsConstructor public enum AppointmentTypeEnum { SQDKL(" 1", " ç³è¯·åå¼ç«"), SQDCX(" 2", "ç³è¯·åæ¤é"), JCDJ(" 3 ", "æ£æ¥ç»è®°"), QXJC(" 4", " åæ¶æ£æ¥"), JCKS(" 5", " æ£æ¥å¼å§"), GZYJ(" 6", " ç»é å½±å"), JCJS(" 7", " æ£æ¥ç»æ"), BGSC(" 8", " æ¥åçæ"), BGCX(" 9", " æ¥åæ¤é"), BGSH(" 10", " æ¥åå®¡æ ¸"); SQDKL("1", "ç³è¯·åå¼ç«"), SQDCX("2", "ç³è¯·åæ¤é"), JCDJ("3", "æ£æ¥ç»è®°"), QXJC("4", "åæ¶æ£æ¥"), JCKS("5", "æ£æ¥å¼å§"), GZYJ("6", "ç»é å½±å"), JCJS("7", "æ£æ¥ç»æ"), BGSC("8", "æ¥åçæ"), BGCX("9", "æ¥åæ¤é"), BGSH("10", "æ¥åå®¡æ ¸"); /** * ç±»å * ç¶æç¼ç ï¼æ åå¼ï¼æ 空ç½ãæ å导é¶ï¼ */ private final String type; /** * æè¿° * ç¶æåç§° */ private final String description; /** * æ ¹æ®ç±»åè·åæä¸¾ * æ ¹æ®ç¶æç¼ç è·ååç§°ã * <p> * å ¥åä¼å åå½ä¸åå¤çï¼å»ç©ºç½ãå»å导é¶ï¼ï¼å æ¤ä¼ å ¥ * {@code "3"}ã{@code "03"}ã{@code " 3 "} å坿£ç¡®å¹é ã * * @param type ç±»å * @return æä¸¾ * @param type ç¶æç¼ç * @return ç¶æåç§°ï¼æ æ³è¯å«æ¶è¿å null */ public static String getByType(String type) { String normalized = HisCheckStatusEnum.normalize(type); if (normalized == null) { return null; } for (AppointmentTypeEnum value : values()) { if (value.getType().equals(type)) { return value.getDescription(); if (value.type.equals(normalized)) { return value.description; } } return null; jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java
@@ -14,9 +14,11 @@ import cn.lihu.jh.module.ecg.enums.AppointmentTypeEnum; import cn.lihu.jh.module.ecg.enums.HisCheckCodeEnum; import cn.lihu.jh.module.ecg.enums.HisCheckNameEnum; import cn.lihu.jh.module.ecg.enums.HisCheckStatusEnum; import cn.lihu.jh.module.ecg.feign.RemoteDataService; import cn.lihu.jh.module.ecg.service.config.EcgConfigService; import cn.lihu.jh.module.ecg.service.devrent.ApplicationTemplate; import cn.lihu.jh.module.ecg.service.his.HisEcgFilter; import cn.lihu.jh.module.ecg.service.queue.QueueService; import cn.lihu.jh.module.ecg.service.queuesequence.QueueSequenceService; import cn.lihu.jh.module.ecg.webservice.WebServiceClient; @@ -52,6 +54,16 @@ @Slf4j public class AppointmentServiceImpl implements AppointmentService { /** * æ£è æ§å«ãæªç¥ãçå åºå¼ã * <p> * {@code appointment.pat_gender} 卿°æ®åºä¸ä¸º NOT NULL 䏿 é»è®¤å¼ * ï¼å®æµï¼{@code Field 'pat_gender' doesn't have a default value}ï¼ã * è {@code S0405} çæ¥æçæ§å«å段路å¾ä¸ {@code S0201ECG} ä¸åãä¸å¯è½ç¼ºå¤±ï¼ * 容鿰墿¶è¥åä¸å°ï¼æ 0ï¼æªç¥ï¼åå ¥ï¼é¿å æå ¥å¤±è´¥ã */ private static final Byte UNKNOWN_GENDER = (byte) 0; @Resource private EcgConfigService ecgConfigService; @@ -66,6 +78,15 @@ @Resource private AppointmentMapper appointmentMapper; /** * å¿çµä¸å¡åå¤å®å¨ã * <p> * ç¨äº {@code S0405}ï¼å ¨é¢éç¨ç¶ææµï¼çè¿æ»¤ï¼éå¿çµååªè®°æ¥å¿ãä¸è½åºï¼ * é¿å å appointment 表çå ¥æ¾å°/è¶ å£°çå ¶ä»ç§å®¤çæ°æ®ã */ @Resource private HisEcgFilter hisEcgFilter; @Autowired private WebServiceClient webServiceClient; @@ -302,12 +323,19 @@ if (!DateUtils.isToday(appointment.getBookDate())) throw exception(APPOINTMENT_NOT_TODAY); Integer newSeqNo = null; if (confirmReqVO.getIsVip() == 0) { newSeqNo = queueSequenceService.distributeSeqNo(confirmReqVO.getBookCheckType(), confirmReqVO.getBookTimeslot()); } else { newSeqNo = queueSequenceService.distributeVipSeqNo(confirmReqVO.getBookCheckType(), confirmReqVO.getBookTimeslot()); } // ãéæ±ï¼æéåºå·è§åãæ check_type.seq_rule å³å®åå·æ¹å¼ï¼ // 0=é¢çº¦å·ï¼ç¨é¢çº¦ç³»ç»å·²ä¸åçå·ï¼å½å HIS æªä¸åï¼ä¼èªå¨åéå°ç¾å°åºå·ï¼ // 1=ç¾å°åºå·ï¼å½å¤©åæ£æ¥ç±»åè¿ç»éå¢ï¼æ¯ 9 个é¢ç 1 个ç»å æ¥ï¼ // 2=æ¶æ®µå·ï¼æ bookTimeslot ä»å·æ± åå· ââ æ¹é åçåæè¡ä¸ºï¼ä¹æ¯æªé ç½®æ¶çé»è®¤ï¼ boolean urgent = isHisUrgent(appointment); Integer newSeqNo = queueSequenceService.distributeSeqNoByRule( confirmReqVO.getBookCheckType(), confirmReqVO.getBookTimeslot(), appointment.getBookSeqNum(), urgent); log.info("[appoitmentConfirm][åé æéåºå·] appointmentId={} checkType={} timeslot={} è§ååå·={} å æ¥={}", appointment.getId(), confirmReqVO.getBookCheckType(), confirmReqVO.getBookTimeslot(), newSeqNo, urgent); try { QueueSaveReqVO queueSaveReqVO = new QueueSaveReqVO(); @@ -324,6 +352,15 @@ queueSaveReqVO.setIsVip(confirmReqVO.getIsVip()); queueSaveReqVO.setPassed((byte) 0); queueSaveReqVO.setExpired((byte) 0); // éæ±2ï¼ISCBãæ¯å¦åºè¾¹ãééåä¸èµ·è½åºï¼ä¾å±å¹/页é¢å±ç¤º queueSaveReqVO.setIsBedside(appointment.getIsBedside()); // HIS å æ¥æ è®°ï¼jjbz=Jï¼â æéå æ¥ï¼ä¸äººå·¥æéå ±ç¨ jump_flagã // queue 表æ "order by jump_flag desc, book_timeslot, create_time" åå·ï¼ç½® 1 å³ä¼å ã if (urgent) { queueSaveReqVO.setJumpFlag((byte) 1); log.info("[appoitmentConfirm][HIS å æ¥æ£è ï¼æéæ è®°ä¸ºå æ¥] applyNo={} patId={}", appointment.getApplyNo(), appointment.getPatId()); } queueSaveReqVO.setPatDetails(getPatDetails(appointment)); queueService.queue(queueSaveReqVO); } catch (DuplicateKeyException duplicateKeyException) { @@ -333,8 +370,27 @@ return newSeqNo; } private PatDetails getPatDetails(AppointmentDO appointment) { PatDetails patDetails = new PatDetails(); /** * å¤æè¯¥é¢çº¦æ¯å¦ä¸º HIS æ è®°çå æ¥åã * <p> * 便® {@code appointment.jjbz}ï¼æ¥æº HIS æ¥æ {@code zdy.jjbz}ï¼ï¼ * {@code J} / {@code 1} / {@code Y} è§ä¸ºå æ¥ï¼å ¶ä½ï¼å¦ {@code N}ï¼ä¸ºå¸¸è§ã * <p> * <b>注æ</b>ï¼å®æµ 2026-09-17 æ¥å¿ä¸ 60 æ¡ S0201ECG ç {@code jjbz} **å ¨ä¸º N**ï¼ * æªåå¾ {@code J} çç宿 ·ä¾ï¼å æ¤è¯¥åæ¯å°æªç»è¿ç宿¥æéªè¯ã * * @param appointment é¢çº¦è®°å½ï¼å¯ä¸º null * @return true=å æ¥ */ private boolean isHisUrgent(AppointmentDO appointment) { if (appointment == null || StringUtils.isEmpty(appointment.getJjbz())) { return false; } String flag = appointment.getJjbz().trim(); return "J".equalsIgnoreCase(flag) || "1".equals(flag) || "Y".equalsIgnoreCase(flag); } private PatDetails getPatDetails(AppointmentDO appointment) { PatDetails patDetails = new PatDetails(); patDetails.setAppointmentId(appointment.getId()); patDetails.setId(appointment.getPatId()); patDetails.setName(appointment.getPatName()); @@ -376,6 +432,64 @@ } return null; }).ifPresent(appointment::setTolerance); // æ¯å¦åºè¾¹ï¼éæ±2ï¼ï¼zdy.ISCBã0=å¦ï¼1=æ¯ã // // ä¸ ISDN åå¨ zdy èªå®ä¹å段åºï¼ä¸**åå±å®æ¹ææ¡£æªå®ä¹ç 7 个æ©å±å段** // ï¼å®æµç宿¥æ 26 ä¸ªåæ®µï¼ææ¡£åªå®ä¹äº 19 个ï¼ã // è§£æé»è¾æ½å° findBedsideFlagï¼ä¾¿äºåå æµè¯ã String bedsideFlag = findBedsideFlag(dataMap); if (bedsideFlag != null) { appointment.setIsBedside(bedsideFlag); } // ä¼å 级/å æ¥æ è®°ï¼zdy.jjbzï¼N=常è§ï¼J=å æ¥ï¼ Map<String, Object> zdyNode = dig(dataMap, "controlActProcess", "subject", "observationRequest", "zdy"); if (zdyNode != null) { Object jjbz = zdyNode.get("jjbz"); if (jjbz != null && StringUtils.isNotEmpty(jjbz.toString().trim())) { appointment.setJjbz(jjbz.toString().trim()); } } // æ£æ¥æ¹å¼ç¼ç ï¼methodCode.item[0].code // ç±»åå®å ¨ï¼methodCode ç item å¯è½ä¸åå¨ï¼å¯è½æ¯å个 Mapï¼ä¹å¯è½æ¯ List Map<String, Object> c2 = dig(dataMap, "controlActProcess", "subject", "observationRequest", "component2", "observationRequest"); if (c2 != null) { String methodCode = digText(c2, "methodCode", "item", "code"); if (StringUtils.isEmpty(methodCode)) { // ä¼ List æ¶ digText ä¼èªå¨åé¦å ç´ åä¸é»ï¼è¿éåå 䏿¬¡ code methodCode = digText(c2, "methodCode", "item", "part", "value"); } if (StringUtils.isNotEmpty(methodCode)) { appointment.setMethodCode(methodCode); } String targetSite = digText(c2, "targetSiteCode", "item", "code"); if (StringUtils.isNotEmpty(targetSite)) { appointment.setTargetSiteCode(targetSite); } // å»å±å·ï¼component2.observationRequest.id.item[root=2.16.156.10011.1.28].extension // // 便®ï¼HISãäº¤äºæå¡éç¨æ¥å£ææ¡£ãï¼ï¼ // · 6.1 ç³è¯·åæ°å¢æå¡ï¼æ¬é¡¹ç®æç¨ S0201ECGï¼ç示ä¾ä¸è¯¥èç¹æ³¨éå³ä¸ºãå»å±IDãï¼ // <id><!--å»å±ID--><item root="2.16.156.10011.1.28" extension=""/></id> // · 6.4/6.5 æ£æ¥é¢çº¦ç¶ææå¡ç示ä¾ä¸åæ ·æ³¨é为ãå»å±å·ãï¼ // <!-- å»å±å· --> ... <id root="2.16.156.10011.1.28" extension="11"/> // 宿µ S0201ECG 220 æ¡ãS0202ECG 29 æ¡**åæºå¸¦è¯¥å¼ä¸æ 空å¼** // ï¼å½¢å¦ 112663505 / 112663700ï¼ä¸åä¸å»å±å¨æ°å¢ä¸æ´æ°æ¥æä¸åå¼ä¸è´ï¼ã // // ã为ä»ä¹ä¸ç¨ digText ç´æ¥å item.extensionã // digText éå° List **åªåé¦å ç´ **ï¼è id.item å¨é¨åæå¡ä¸æ¯æ°ç» // ï¼å¦ 6.4 åæ¶å« 1.24 ç³è¯·åå·ä¸ 1.28 å»å±å·ï¼ãæ å¿ é¡»**æ root å¹é **ï¼ // å¦åå¯è½æç³è¯·åå·å½æå»å±å·ã String doctorAdviceNo = findExtensionByRoot(c2.get("id"), ORDER_NO_ROOT); if (StringUtils.isNotEmpty(doctorAdviceNo)) { appointment.setDoctorAdviceNo(doctorAdviceNo); } } // å»çå¼åæ¶é´ Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("author")).map(author -> (Map<String, Object>) author.get("time")).map(time -> (String) time.get("value")).map(str -> { @@ -453,13 +567,29 @@ // String checkType = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("code")).map(code -> (String) code.get("code")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL)); String checkType = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("code")).map(code -> (String) code.get("code")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL)); String checkName = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("code")).map(code -> (Map<String, Object>) code.get("displayName")).map(displayName -> (String) displayName.get("value")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL)); if (appointment.getPatSrc() != null && appointment.getPatSrc() != 4) { if (checkType != null || checkType != "") appointment.setBookCheckType(Integer.valueOf(HisCheckCodeEnum.getByCode(checkType.substring(1)))); } else if (appointment.getPatSrc() != null && appointment.getPatSrc() == 4) { if (StringUtils.isNotEmpty(checkName)) { checkName = checkName.replaceAll("\\s+", ""); appointment.setBookCheckType(Integer.valueOf(HisCheckNameEnum.getByName(checkName))); // 便®æ£æ¥ç±»åè§£ææ¬å° book_check_typeã // ä¿®æ£ç¹ï¼åå®ç°æç¼ºé·ï¼ï¼ // 1. å¤æåæ `checkType != null || checkType != ""`ï¼æä¸º trueï¼ // 2. patSrc 为 Integerï¼`!= 4` å¨è¶ åº Integer ç¼åèå´æ¶ä¼å¤±æï¼æ¹ç¨ Objects.equalsï¼ // 3. HIS 代ç å¯è½æ å°ä¸å°ï¼ç´æ¥ Integer.valueOf(null) 伿 // NumberFormatExceptionï¼å®æµæ¥å¿ä¸æ "Cannot parse null string"ï¼ã if (Objects.equals(appointment.getPatSrc(), 4)) { String normalizedName = StringUtils.isNotEmpty(checkName) ? checkName.replaceAll("\\s+", "") : null; String mapped = StringUtils.isNotEmpty(normalizedName) ? HisCheckNameEnum.getByName(normalizedName) : null; Integer value = parseIntegerQuietly(mapped); if (value != null) { appointment.setBookCheckType(value); } else { log.warn("[handleAppointmentCreate][使£æ£è æ£æ¥é¡¹ç®åç§°æ æ³æ å°] checkName={}", checkName); } } else { Integer value = resolveBookCheckTypeFromComponent2(dataMap); if (value != null) { appointment.setBookCheckType(value); } else { log.warn("[handleAppointmentCreate][HIS æ£æ¥ä»£ç æ æ³æ å°å°æ¬å°æ£æ¥ç±»å] checkType={}", checkType); } } @@ -487,16 +617,84 @@ // å°AppointmentDO转æ¢ä¸ºAppointmentSaveReqVOå¹¶ä¿å AppointmentSaveReqVO saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class); //æ ¹æ®ç³è¯·ç¼å·å æ¥è¯¢ä¸ä¸æ¯å¦åå¨ï¼å¦æåå¨ï¼å°±ä¸æ°å¢äº // æç³è¯·åå·æ£æ¥æ¯å¦å·²åå¨ã // ãæ¬æ¬¡æ¹å¨ Q5ãåå®ç°å½ä¸å·²å卿¶ç´æ¥ returnï¼ä¸æ´æ°ï¼ï¼ // ä¸ S0202ECG / S0405 ä¸¤æ¡æ´æ°æµç"æ¾ä¸å°åå åºæ°å¢"æ¹åç¸åï¼è¯ä¹ä¸ç»ä¸ã // ç°æ¹ä¸ºï¼å½ä¸å·²åå¨åä»¥æ¬æ¬¡æ¥æå 容æ§è¡æ´æ°ï¼é¿å HIS é夿¨éæ¶æ§æ°æ®ä¸è¢«ä¿®æ£ã AppointmentDO appointmentDO = appointmentMapper.getByApplyNo(saveReqVO.getApplyNo()); log.info("=======æ¯å¦æ°å¢è¿äºï¼{}", ObjectUtils.isNotEmpty(appointmentDO) ? appointmentDO.getId() : null); if (ObjectUtils.isNotEmpty(appointmentDO)) return appointmentDO.getId(); log.info("[handleAppointmentCreate][æ¯å¦å·²åå¨] applyNo={} existingId={}", saveReqVO.getApplyNo(), appointmentDO == null ? null : appointmentDO.getId()); if (appointmentDO != null) { // ä¿çåè®°å½ä¸æ¬æ¬¡æ¥ææªæä¾çåæ®µï¼é¿å 被空å¼è¦ç mergeUnsetFields(appointment, appointmentDO); saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class); saveReqVO.setId(appointmentDO.getId()); updateAppointment(saveReqVO); return appointmentDO.getId(); } return createAppointment(saveReqVO); } catch (Exception e) { log.error("[handleAppointmentCreate][å¤çé¢çº¦å建失败 dataMap({})]", dataMap, e); throw exception(APPOINTMENT_CREATE_FAIL); } } /** * æ´æ°ååå¹¶ï¼æ¬æ¬¡æ¥ææªæä¾ï¼ä¸º nullï¼çåæ®µï¼æ²¿ç¨æ°æ®åºä¸çåå¼ã * <p> * ç®çï¼{@code S0201ECG} çæäºå段å¨é¨ååºæ¯ä¸ä¼ç¼ºå¤±ï¼ä¾å¦ä½æ£æ£è æ é¢çº¦æ¶é´ã * åºå¤´å±æ¶æ¯æ ç§å®¤ä¿¡æ¯ï¼ãè¥ç´æ¥ä»¥æ¥æå 容æ´ä½è¦çï¼ä¼æå·²ææ°æ®æ¸ 空ã * è¿æ¯"é¨åæ´æ°"è¯ä¹ï¼ä¸æ´æ°æµç {@code ifPresent} éåæ®µèµå¼ä¿æä¸è´ã * <p> * 注æï¼å¨ {@link AppointmentDO} å±åå¹¶ï¼èé VO å±ï¼ï¼å 为 * {@code AppointmentSaveReqVO} ä¸ DO çåæ®µç±»åå¹¶ä¸ä¸è´ * ï¼VO ç {@code bookDate/patBirthday} 为 {@code LocalDateTime}ã * {@code registerDate/doctorTime} 为 {@code java.sql.Date}ï¼ * DO 对åºä¸º {@code LocalDate} / {@code java.util.Date}ï¼ã * * @param target æ¬æ¬¡æ¥æè§£æåºç对象ï¼ä¼è¢«å°±å°è¡¥å ¨ï¼ * @param source æ°æ®åºä¸å·²æçè®°å½ */ private void mergeUnsetFields(AppointmentDO target, AppointmentDO source) { if (target.getApplyNo() == null) target.setApplyNo(source.getApplyNo()); if (target.getEpisodeId() == null) target.setEpisodeId(source.getEpisodeId()); if (target.getPatSrc() == null) target.setPatSrc(source.getPatSrc()); if (target.getPatId() == null) target.setPatId(source.getPatId()); if (target.getPatName() == null) target.setPatName(source.getPatName()); if (target.getPatGender() == null) target.setPatGender(source.getPatGender()); if (target.getPatBirthday() == null) target.setPatBirthday(source.getPatBirthday()); if (target.getPatMobile() == null) target.setPatMobile(source.getPatMobile()); if (target.getPatPhone() == null) target.setPatPhone(source.getPatPhone()); if (target.getPatIdentityId() == null) target.setPatIdentityId(source.getPatIdentityId()); if (target.getPatAddr() == null) target.setPatAddr(source.getPatAddr()); if (target.getPatDeptCode() == null) target.setPatDeptCode(source.getPatDeptCode()); if (target.getPatDeptDesc() == null) target.setPatDeptDesc(source.getPatDeptDesc()); if (target.getPatWardCode() == null) target.setPatWardCode(source.getPatWardCode()); if (target.getPatWardDesc() == null) target.setPatWardDesc(source.getPatWardDesc()); if (target.getPatBedNo() == null) target.setPatBedNo(source.getPatBedNo()); if (target.getBookDate() == null) target.setBookDate(source.getBookDate()); if (target.getBookTimeslot() == null) target.setBookTimeslot(source.getBookTimeslot()); if (target.getBookTime() == null) target.setBookTime(source.getBookTime()); if (target.getBookCheckType() == null) target.setBookCheckType(source.getBookCheckType()); if (target.getBookSrc() == null) target.setBookSrc(source.getBookSrc()); if (target.getPaid() == null) target.setPaid(source.getPaid()); if (target.getStatus() == null) target.setStatus(source.getStatus()); if (target.getRegisterDate() == null) target.setRegisterDate(source.getRegisterDate()); if (target.getTolerance() == null) target.setTolerance(source.getTolerance()); if (target.getHospitalNo() == null) target.setHospitalNo(source.getHospitalNo()); if (target.getMedicalCard() == null) target.setMedicalCard(source.getMedicalCard()); if (target.getOutpatientNo() == null) target.setOutpatientNo(source.getOutpatientNo()); if (target.getDoctor() == null) target.setDoctor(source.getDoctor()); if (target.getDoctorCode() == null) target.setDoctorCode(source.getDoctorCode()); if (target.getDoctorTime() == null) target.setDoctorTime(source.getDoctorTime()); // ââ HIS è¡¥å åæ®µï¼é表æ°å¢åä¸èµ·å å ¥ï¼ä¿æ"é¨åæ´æ°ä¸æ¸ 空"è¯ä¹ï¼ââ if (target.getJjbz() == null) target.setJjbz(source.getJjbz()); if (target.getMethodCode() == null) target.setMethodCode(source.getMethodCode()); if (target.getTargetSiteCode() == null) target.setTargetSiteCode(source.getTargetSiteCode()); if (target.getRoomName() == null) target.setRoomName(source.getRoomName()); if (target.getRemark() == null) target.setRemark(source.getRemark()); if (target.getBookSeqNum() == null) target.setBookSeqNum(source.getBookSeqNum()); } @Override @@ -589,10 +787,13 @@ } return null; }).ifPresent(existingAppointment::setPaid); //è®¾ç½®æ£æ¥ç±»å String checkType = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("code")).map(code -> (String) code.get("code")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL)); if (checkType != null || checkType != "") existingAppointment.setBookCheckType(Integer.valueOf(HisCheckCodeEnum.getByCode(checkType.substring(1)))); // è®¾ç½®æ£æ¥ç±»å Integer checkTypeValue = resolveBookCheckTypeFromComponent2(dataMap); if (checkTypeValue != null) { existingAppointment.setBookCheckType(checkTypeValue); } else { log.warn("[handleAppointmentUpdate][æªè½è§£ææ£æ¥ç±»åï¼ä¿çåå¼] applyNo={}", applyNo); } // å°AppointmentDO转æ¢ä¸ºAppointmentSaveReqVOå¹¶æ´æ° AppointmentSaveReqVO updateReqVO = BeanUtils.toBean(existingAppointment, AppointmentSaveReqVO.class); @@ -603,111 +804,892 @@ } } /** * 仿¥æ {@code component2.observationRequest.code.code} è§£ææ¬å°æ£æ¥ç±»åå¼ã * * <h3>ä¿®æ£ç缺é·</h3> * åå®ç°ä¸ºï¼ * <pre> * if (checkType != null || checkType != "") // æä¸º trueï¼ä¸é»è¾åºä¸º && * setBookCheckType(Integer.valueOf( * HisCheckCodeEnum.getByCode(checkType.substring(1)))); // æ é¿åº¦æ ¡éª * </pre> * åå¨ä¸å¤é®é¢ï¼ * <ol> * <li>{@code ||} ä½¿å¤ææçï¼</li> * <li>{@code substring(1)} ç´æ¥æªæï¼æ¥æå¼é¿åº¦ä¸è¶³æ¶æ * {@code StringIndexOutOfBoundsException}ï¼å®æµæ¥å¿ä¸æç±»ä¼¼å¼å¸¸ï¼ï¼</li> * <li>{@code HisCheckCodeEnum.getByCode()} å¯è½è¿å nullï¼ * éå {@code Integer.valueOf(null)} æ {@code NumberFormatException} * ï¼å®æµæ¥å¿ä¸ç¡®æ {@code Cannot parse null string}ï¼ã</li> * </ol> * ç°æ¹ä¸ºï¼HIS 代ç å ¼å®¹å¸¦/ä¸å¸¦ {@code Y} åç¼ï¼å¯¹åºå substring(1) è¯ä¹ï¼ï¼ * ä¸ä» å¨è½æ å°å°æ¬å° {@code check_type} 弿¶æè¿åï¼å¦åè¿å null ç±è°ç¨æ¹ä¿çåå¼ã * * @return æ¬å°æ£æ¥ç±»åå¼ï¼å¦ 1000ï¼ï¼æ æ³è§£ææ¶è¿å null */ private Integer resolveBookCheckTypeFromComponent2(Map<String, Object> dataMap) { // ç±»åå®å ¨ï¼observationRequest.code å¯è½æ¯ Mapï¼ä¹å¯è½æ¯ç©ºå符串 String hisCode = digText(dataMap, "controlActProcess", "subject", "observationRequest", "component2", "observationRequest", "code", "code"); if (StringUtils.isEmpty(hisCode)) { return null; } String raw = hisCode.trim().replaceAll("\\s+", ""); // å ¼å®¹ï¼HIS æ¥æå¼å½¢å¦ "Y1202065"ï¼èæä¸¾ code ä¸ºå»æé¦å符åç "1202065"ï¼ // åæ¶ä¹å®¹å¿æ¥ææ¬èº«ä¸å¸¦åç¼ String[] candidates = raw.length() > 1 ? new String[]{raw, raw.substring(1)} : new String[]{raw}; for (String candidate : candidates) { String mapped = HisCheckCodeEnum.getByCode(candidate); if (StringUtils.isNotEmpty(mapped)) { return parseIntegerQuietly(mapped); } } log.warn("[resolveBookCheckTypeFromComponent2][HIS æ£æ¥ä»£ç æ æ³æ å°å°æ¬å°æ£æ¥ç±»å] hisCode={}", hisCode); return null; } /** * ç³è¯·åç¶ææ´æ°ï¼action: {@code S0405} / {@code S0405HIS} / {@code S040501HIS}ï¼ã * * <h3>â ï¸ è¯¥æå¡æ¯å ¨é¢éç¨ç</h3> * æ¥å£ææ¡£ 6.3 å®ä¹å ¶ action 为 {@code S0405|S0405HIS|S040501HIS}ï¼**ä¸åºåç§å®¤**ã * å»é¢ä¼ææææ£æ¥ç§å®¤ï¼CTãMRIãDRãè¶ å£°ã骨å¯åº¦â¦ï¼çæ£æ¥ç¶æä¸å¹¶æ¨éã * 宿µ 2026-09-17ï¼æ¬æå¡æ¶å° 1225 次请æ±ï¼å ¶ä¸ä» 3.5% çç³è¯·åå·å±å¿çµä¸å¡ï¼ * å ¶ä½ä¸ºæ¾å°/è¶ å£°çç§å®¤çåï¼å¦ {@code 2126091700001} è¸é¨CTå¹³æ« / æ¥è¯CT室ï¼ã * * <h3>å¤ççç¥</h3> * <ol> * <li>æåç³è¯·åå·ä¸æ£æ¥ç¶æç ï¼å¹¶å¯¹ç¶æç å**å½ä¸å**ï¼å»å导é¶ãæ ¡éªåæ³æ§ï¼</li> * <li>æ¥æ¬å°é¢çº¦è®°å½ï¼ * <ul> * <li><b>åå¨</b> â æ´æ°ç¶æï¼ç¶æä¸º 3ï¼æ£æ¥ç»è®°ï¼æ¶åæ¶åå ¥ç»è®°æ¶é´</li> * <li><b>ä¸åå¨ + æ¯å¿çµå</b> â è®° WARN å¹¶**æå ¥æ°è®°å½**ï¼Q4 è¦æ±å®¹éæ°å¢ï¼</li> * <li><b>ä¸åå¨ + éå¿çµå</b> â ä» è®° DEBUG æ¥å¿ï¼**ä¸æå ¥**ï¼é¿å çå ¥æ å ³æ°æ®ï¼</li> * </ul> * </li> * </ol> */ @Override @Transactional(rollbackFor = Exception.class) public void handleAppointmentStateUpdate(Map<String, Object> dataMap) { if (dataMap == null) { throw exception(APPOINTMENT_STATUS_UPDATE_FAIL); } // ä»dataMap䏿åç³è¯·åå· String applyNo = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("placerGroup")).map(placerGroup -> (Map<String, Object>) placerGroup.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("id")).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL)); // æ¥è¯¢ç°æé¢çº¦è®°å½ // 1. æåç³è¯·åå·ï¼ç±»åå®å ¨å¯¼èªï¼ String applyNo = digText(dataMap, "controlActProcess", "subject", "placerGroup", "component2", "observationRequest", "id", "item", "extension"); if (StringUtils.isEmpty(applyNo)) { log.warn("[handleAppointmentStateUpdate][æ¥æç¼ºå°ç³è¯·åå·ï¼å¿½ç¥] dataMap={}", dataMap); throw exception(HIS_APPLY_NO_MISSING); } // 2. æåå¹¶å½ä¸åæ£æ¥ç¶æç // ç±»åå®å ¨ï¼processStep.code å¨é¨åæ¥æä¸æ¯ Mapï¼code={code=7,...}ï¼ï¼ // å¨å¦ä¸äºæ¥æä¸å¯è½æ¯ç©ºå符串ï¼ç´æ¥ç¨é¾å¼å¼ºè½¬ä¼æ ClassCastException String rawStatus = digText(dataMap, "controlActProcess", "subject", "placerGroup", "component2", "observationRequest", "component1", "processStep", "code", "code"); String status = HisCheckStatusEnum.normalize(rawStatus); if (status == null) { // 宿µæ¥æä¸è¯¥å¼åå¨ "3" / "03" / "7" / "08" / "10" çä¸ååæ³ï¼ // å½ä¸åå仿 æ³è¯å«è¯´æä¸æ¯ç¼ç 表å çç¶æï¼å¦ç çä¸ç¨ 21/22/23ï¼ log.warn("[handleAppointmentStateUpdate][æ£æ¥ç¶æç¼ç éæ³æä¸å¨ç¼ç 表å ï¼å¿½ç¥] applyNo={} rawStatus={}", applyNo, rawStatus); throw exception(HIS_STATUS_INVALID); } // 3. æ¬å°è®°å½å¹é AppointmentDO existingAppointment = appointmentMapper.getByApplyNo(applyNo); // å¦æè®°å½ä¸åå¨ï¼åè°ç¨handleAppointmentCreateè¿è¡æ°å¢ if (existingAppointment == null) { handleAppointmentCreate(dataMap); if (existingAppointment != null) { existingAppointment.setStatus(status); if (HisCheckStatusEnum.REGISTERED.getCode().toString().equals(status)) { existingAppointment.setRegisterDate(new Date()); } AppointmentSaveReqVO updateReqVO = BeanUtils.toBean(existingAppointment, AppointmentSaveReqVO.class); updateAppointment(updateReqVO); return; } // ä»dataMap䏿åç³è¯·åå· // String status = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("placerGroup")).map(placerGroup -> (Map<String, Object>) placerGroup.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("component1")).map(component1 -> (Map<String, Object>) component1.get("processStep")).map(processStep -> (Map<String, Object>) processStep.get("code")).map(code -> (Map<String, Object>) code.get("displayName")).map(displayName -> (String) displayName.get("value")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL)); String status = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("placerGroup")).map(placerGroup -> (Map<String, Object>) placerGroup.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("component1")).map(component1 -> (Map<String, Object>) component1.get("processStep")).map(processStep -> (Map<String, Object>) processStep.get("code")).map(code -> (String) code.get("code")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL)); existingAppointment.setStatus(status); if ("3".equals(status)) { existingAppointment.setRegisterDate(new Date()); // 4. è®°å½ä¸åå¨ï¼å å¤å®æ¯å¦å¿çµä¸å¡åï¼éå¿çµååªè®°æ¥å¿ãä¸æå ¥ // // S0405 æ¯å ¨é¢éç¨æµãå¯ç¨çå¿çµå¤å®ä¾æ®ï¼æå®æµæ¥æï¼ï¼ // A. apply_no åç¼ï¼1101/6401ï¼ // B. component2.observationRequest.component1.processStep.code.ZDY // ä¸ç jcxmcode / jcxmnameï¼å®æµ 1138/1225 æ¡å¸¦è¯¥åæ®µï¼ // å½¢å¦ jcxmname=è¸é¨CTå¹³æ«,ä¸è ¹é¨CTå¹³æ« / roomname=æ¥è¯CTå®¤ï¼ // C. æ§è¡ç§å®¤ï¼éé ç½®ç½ååï¼ Map<String, Object> zdyFromS0405 = extractZdyFromStateMessage(dataMap); String s0405CheckCode = extractZdyValueFromMap(zdyFromS0405, "jcxmcode"); String s0405CheckName = extractZdyValueFromMap(zdyFromS0405, "jcxmname"); String hisDeptCode = extractDeptCodeFromComponent2(dataMap); if (!hisEcgFilter.isEcgOrder("S0405", applyNo, s0405CheckCode, s0405CheckName, hisDeptCode)) { // å ¨é¢æµä¸çå ¶ä»ç§å®¤åæ®ï¼éé»è·³è¿ï¼DEBUG æ¥å¿ç± filter è¾åºï¼ return; } // å°AppointmentDO转æ¢ä¸ºAppointmentSaveReqVOå¹¶æ´æ° AppointmentSaveReqVO updateReqVO = BeanUtils.toBean(existingAppointment, AppointmentSaveReqVO.class); updateAppointment(updateReqVO); } // 5. æ¯å¿çµå使¬å°æ è®°å½ â 容鿰å¢ï¼Q4 è¦æ±ï¼ log.warn("[handleAppointmentStateUpdate][å¿çµä¸å¡å使¬å°æ è®°å½ï¼æ§è¡å®¹éæ°å¢] applyNo={} status={} dept={}", applyNo, status, hisDeptCode); insertAppointmentFromStateMessage(applyNo, status, dataMap); } /** * ä»dataMap䏿åencounteræ°æ® * ä» S0405 æ¥æä¸æé å¹¶æå ¥ä¸æ¡é¢çº¦è®°å½ã * * <h3>â ï¸ å·²ç¥çæ°æ®ç¼ºå¤±</h3> * {@code S0405} æ¥æ**ä¸å 嫿£æ¥é¡¹ç®ä¿¡æ¯**ï¼æ {@code component2.observationRequest.code}ï¼ï¼ * å æ¤æ æ³ç¡®å® {@code book_check_type}ï¼æ£æ¥ç±»åï¼ã宿µç¡®è®¤ï¼ç³è¯·åå·åç¼ * 䏿£æ¥ç±»å**æ 对åºå ³ç³»**ï¼å为 {@code ...1101} åç¼çè®°å½åå¨ 1000/100/1100 çå¤ç§ç±»åï¼ï¼ * æ ä¸åçæµï¼ä¿æä¸ºç©ºå¹¶è¾åº WARNï¼å¾ åç» {@code S0202ECG}ï¼ç³è¯·åæ´æ°ï¼ * æäººå·¥è¡¥å½ä¿®æ£ã * <p> * åç {@code book_date}ï¼é¢çº¦æ¥æï¼ä¹ä¸å¨æ¥æä¸ï¼ä¿æä¸ºç©º ââ è¿ä¸ç°ææ°æ®ä¸è´ * ï¼åºä¸çº¦ 48% è®°å½ {@code book_date} 为空ï¼é¢çº¦æ¥æç± S050401/S040501HIS åç»è¡¥å ¥ï¼ã */ private Map<String, Object> extractEncounter(Map<String, Object> dataMap) { return Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("componentOf1")).map(componentOf1 -> (Map<String, Object>) componentOf1.get("encounter")).orElse(null); private void insertAppointmentFromStateMessage(String applyNo, String status, Map<String, Object> dataMap) { AppointmentDO appointment = new AppointmentDO(); appointment.setApplyNo(applyNo); appointment.setStatus(status); if (HisCheckStatusEnum.REGISTERED.getCode().toString().equals(status)) { appointment.setRegisterDate(new Date()); } // æ£è ä¿¡æ¯ï¼S0405 ç patient.id.item 为å表ï¼åID/æ£è ID/é¨è¯å·/ä½é¢å·/å°±è¯æ¬¡æ°/å°±è¯æµæ°´å·ï¼ // ç¨ç±»åå®å ¨å¯¼èªï¼é¿å æä¸çº§ä¸æ¯ Map æ¶æ ClassCastException Map<String, Object> encounter = dig(dataMap, "controlActProcess", "subject", "placerGroup", "componentOf1", "encounter"); if (encounter != null) { // å°±è¯æµæ°´å·ï¼id.item[1] List<?> encIdItems = asList(dig(encounter, "id"), "item"); if (encIdItems.size() > 1 && encIdItems.get(1) instanceof Map) { appointment.setEpisodeId(str(((Map<String, Object>) encIdItems.get(1)).get("extension"))); } // æ£è ä¿¡æ¯ Map<String, Object> patient = dig(encounter, "subject", "patient"); if (patient != null) { List<?> patIdItems = asList(patient, "id", "item"); // æ£è ID item[1]ï¼é¨è¯å· item[2]ï¼ä½é¢å· item[3] if (patIdItems.size() > 1 && patIdItems.get(1) instanceof Map) { appointment.setPatId(str(((Map<String, Object>) patIdItems.get(1)).get("extension"))); } if (patIdItems.size() > 2 && patIdItems.get(2) instanceof Map) { appointment.setOutpatientNo(str(((Map<String, Object>) patIdItems.get(2)).get("extension"))); } if (patIdItems.size() > 3 && patIdItems.get(3) instanceof Map) { appointment.setHospitalNo(str(((Map<String, Object>) patIdItems.get(3)).get("extension"))); } // å§å String patName = digText(patient, "patientPerson", "name", "item", "part", "value"); if (StringUtils.isNotEmpty(patName)) { appointment.setPatName(patName); } // æ§å«ï¼pat_gender 为 NOT NULLï¼å°½éåï¼åä¸å°æ¶ç±ä¸æ¹å åºä¸º 0 String gender = digText(patient, "patientPerson", "administrativeGenderCode", "code"); Byte genderByte = parseByteQuietly(gender); if (genderByte != null) { appointment.setPatGender(genderByte); } } } // æ§è¡ç§å®¤ï¼åå ¥ pat_dept_code / pat_dept_descï¼ Map<String, Object> org = dig(dataMap, "controlActProcess", "subject", "placerGroup", "component2", "observationRequest", "location", "serviceDeliveryLocation", "serviceProviderOrganization"); if (org != null) { String deptCode = digText(org, "id", "item", "extension"); if (StringUtils.isNotEmpty(deptCode)) { appointment.setPatDeptCode(deptCode); } String deptDesc = digText(org, "name", "item", "part", "value"); if (StringUtils.isNotEmpty(deptDesc)) { appointment.setPatDeptDesc(deptDesc); } } if (StringUtils.isEmpty(appointment.getPatName())) { log.warn("[insertAppointmentFromStateMessage][容鿰å¢çè®°å½ç¼ºå°æ£è å§å] applyNo={}", applyNo); } log.warn("[insertAppointmentFromStateMessage][注æï¼S0405 æ¥æä¸å«æ£æ¥é¡¹ç®ï¼" + "book_check_type å°ä¸ºç©ºï¼éåç» S0202ECG æäººå·¥è¡¥å½] applyNo={}", applyNo); // pat_id / pat_name / pat_gender 卿°æ®åºä¸å为 NOT NULLï¼ç¼ºå¼æ¶æåæ¥éï¼ // é¿å SQL å¼å¸¸å¯¼è´äºå¡åæ»ï¼å®æµæ¥éï¼Field 'pat_gender' doesn't have a default valueï¼ if (StringUtils.isEmpty(appointment.getPatId())) { log.error("[insertAppointmentFromStateMessage][æ¥æç¼ºæ£è ç¼å·(pat_id)ï¼æ æ³æ°å¢] applyNo={}", applyNo); throw exception(PATIENT_NOT_EXISTS); } if (appointment.getPatGender() == null) { log.warn("[insertAppointmentFromStateMessage][æ¥ææªæä¾æ£è æ§å«ï¼ææªç¥(0)åå ¥] applyNo={}", applyNo); appointment.setPatGender(UNKNOWN_GENDER); } AppointmentSaveReqVO saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class); createAppointment(saveReqVO); } @Override public void handleCheckAppointmentUpdate(Map<String, Object> dataMap) { // ä»dataMapä¸è·åcontrolActProcess Map<String, Object> controlActProcess = (Map<String, Object>) dataMap.get("controlActProcess"); Map<String, Object> subject = (Map<String, Object>) controlActProcess.get("subject"); Map<String, Object> actAppointment = (Map<String, Object>) subject.get("actAppointment"); /** * å S0405 æ¥æä¸ç {@code ZDY} èç¹ã * <p> * 宿µè·¯å¾ï¼{@code controlActProcess.subject.placerGroup.component2.observationRequest * .component1.processStep.code.ZDY}ï¼å 容形å¦ï¼ * <pre> * ZDY={roomcode=111, roomname=æ¥è¯CT室, jcxmcode=1080,3016,3014, * jcxmname=è¸é¨CTå¹³æ«,ä¸è ¹é¨CTå¹³æ«,ä¸è ¹é¨CTå¹³æ«, * pdh=000336, yysd=00:00-01:00, isjj=1} * </pre> * 注æï¼{@code observationRequest.code} 卿¥æä¸**å¯è½æ¯ç©ºå符串èé Map**ï¼ * æ å¿ é¡»ç¨ {@link #dig(Object, String...)} åç±»åå®å ¨å¯¼èªã */ private Map<String, Object> extractZdyFromStateMessage(Map<String, Object> dataMap) { return dig(dataMap, "controlActProcess", "subject", "placerGroup", "component2", "observationRequest", "component1", "processStep", "code", "ZDY"); } // è·åç³è¯·ç¼å· List<Map<String, Object>> referencedOrders = (List<Map<String, Object>>) actAppointment.get("referencedOrder"); String applyNo = null; if (!CollectionUtils.isEmpty(referencedOrders)) { Map<String, Object> actOrder = (Map<String, Object>) referencedOrders.get(0).get("actOrder"); Map<String, Object> id = (Map<String, Object>) actOrder.get("id"); applyNo = (String) id.get("extension"); /** ä» Map ä¸ååç¬¦ä¸²åæ®µï¼å¯ä¸ºç©ºï¼ */ private String extractZdyValueFromMap(Map<String, Object> map, String key) { if (map == null) { return null; } Object v = map.get(key); return v == null ? null : v.toString(); } /** å®å ¨è½¬å符串ï¼null è¿å nullï¼å ¶ä½ toString() */ private static String str(Object o) { return o == null ? null : o.toString(); } /** {@code appointment.remark} å宽ä¸éï¼è§ 08_fix_remark_length.sqlï¼å½å varchar(2000)ï¼ */ private static final int REMARK_MAX_LEN = 2000; /** {@code appointment.room_name} å宽ä¸é */ private static final int ROOM_NAME_MAX_LEN = 200; /** * æåå®½æªæææ¬ï¼é²æ¢ {@code Data too long for column} 导è´**æ´ä¸ªäºå¡åæ»**ã * * <p><b>è¡æ³ªæè®</b>ï¼2026-09-28 ç产ç¯å¢è¯¥é误åºç° 52 次ãå¿çµå¾è¿å¨è¯éªç * 注æäºé¡¹é¿è¾¾ 474 å符ï¼è {@code remark} åå为 {@code varchar(255)}ï¼ * 溢åºåæ {@code MysqlDataTruncation}ï¼ä½¿æ´æ¡ UPDATE åæ» ââ * è¿å¸¦åä¸äºå¡ä¸ç {@code book_time}ã{@code room_name} ä¸èµ·ä¸¢å¤±ï¼ * 表ç°ä¸º"é¢çº¦æ¶é´æ®µæ²¡åè¿æ°æ®åº"ã * * @param value åå§ææ¬ * @param maxLen ç®æ å宽 * @return æªæåçææ¬ï¼null åæ ·è¿åï¼ */ private static String truncate(String value, int maxLen) { if (value == null) { return null; } if (value.length() <= maxLen) { return value; } log.warn("[truncate][ææ¬è¶ é¿å·²æªæ] åé¿åº¦={} æªæè³={} å 容å 60 å={}", value.length(), maxLen, value.substring(0, Math.min(60, value.length()))); return value.substring(0, maxLen); } /** * å±çº§å¯¼èªååãå表ãèç¹ï¼{@code dig(root, path...)} å¾å°çå¼è¥æ¯ List åè¿åï¼ * å¦åè¿å空å表ï¼**䏿å¼å¸¸**ï¼ã */ @SuppressWarnings("unchecked") private static List<?> asList(Map<String, Object> root, String... path) { Object cur = root; for (String key : path) { if (!(cur instanceof Map)) { return Collections.emptyList(); } cur = ((Map<String, Object>) cur).get(key); } return cur instanceof List ? (List<?>) cur : Collections.emptyList(); } /** * ç±»åå®å ¨çå±çº§å¯¼èªï¼é级å Map åèç¹ã * * <p><b>为ä»ä¹éè¦å®</b>ï¼HIS æ¥æç» Jackson ååºåååï¼åä¸å段çç±»å**å¹¶ä¸ç¨³å®**ã * ä¾å¦ {@code observationRequest.code} å¨é¨åæ¥æä¸æ¯ {@code Map}ï¼{@code code={code=7,...}}ï¼ï¼ * å¨å¦ä¸äºæ¥æä¸æ¯**空å符串**ï¼{@code code=}ï¼ãè¥ç¨ * {@code .map(m -> (Map<String,Object>) m.get("code"))} è¿ç§é¾å¼å¼ºå¶è½¬æ¢ï¼ * éå°åç¬¦ä¸²ä¼æ {@code ClassCastException}ï¼**å¯¼è´æ´æ¡æ¶æ¯å¤ç䏿**ã * * <p>宿µç产æ¥å¿ 2026-09-28 ä¸è¯¥ç±»å¼å¸¸åºç° **287 次**ï¼æ£æ¯ç±æ¤åæ³å¼èµ· * ï¼{@code AppointmentServiceImpl.lambda$extractCheckCodeFromComponent2}ï¼ã * * @param root èµ·å§èç¹ * @param path 便¬¡è¦åçé® * @return æ«ç«¯èç¹ï¼ä»»ä¸ç¯è䏿¯ Map æç¼ºå¤±æ¶è¿å nullï¼**䏿å¼å¸¸**ï¼ */ @SuppressWarnings("unchecked") private static Map<String, Object> dig(Map<String, Object> root, String... path) { Object cur = root; for (String key : path) { if (!(cur instanceof Map)) { return null; } cur = ((Map<String, Object>) cur).get(key); } return cur instanceof Map ? (Map<String, Object>) cur : null; } /** HIS æ¥æä¸ãå»å±å·/å»å±IDãç id rootï¼è§ãäº¤äºæå¡éç¨æ¥å£ææ¡£ã6.1 / 6.4 / 6.5ï¼ */ private static final String ORDER_NO_ROOT = "2.16.156.10011.1.28"; /** * å¨ HL7 ç {@code id} èç¹ä¸ï¼æ {@code root} å¹é å¹¶ååº {@code extension}ã * <p> * å ¼å®¹ä¸ç§çå®å½¢æï¼å已卿¥æ/ææ¡£ä¸åºç°ï¼ï¼ * <pre> * id={item={root=..., extension=...}} // å个 Map * id={item=[{root=..., extension=...}, {...}]} // Listï¼å¤æ è¯ï¼é¡»æ root åºåï¼ * {root=..., extension=...} // ç´æ¥å°±æ¯æ è¯æ¬èº« * </pre> * <p> * <b>为ä»ä¹ä¸å¤ç¨ {@link #digText}</b>ï¼{@code digText} éå° List åªåé¦å ç´ ï¼ * è {@code id.item} 为æ°ç»æ¶å¯è½é¦å ç´ æ¯ãç³è¯·åå·(root 1.24)ãèéãå»å±å·(root 1.28)ãï¼ * ä¼åéå¼ãæ è¿éæ¾å¼éåå¹¶æ root å¹é ã * * @param idNode {@code id} èç¹ï¼Map æ Listï¼å¯ä¸º nullï¼ * @param root ç®æ root å¼ * @return å¹é 项ç extensionï¼æªå¹é /为空æ¶è¿å null */ private static String findExtensionByRoot(Object idNode, String root) { if (idNode == null) { return null; } Object item = (idNode instanceof Map) ? ((Map<String, Object>) idNode).get("item") : idNode; if (item == null) { return null; } List<Object> candidates = new ArrayList<>(); if (item instanceof List) { candidates.addAll((List<Object>) item); } else { candidates.add(item); } for (Object cand : candidates) { if (!(cand instanceof Map)) { continue; } Map<String, Object> m = (Map<String, Object>) cand; Object r = m.get("root"); if (r != null && root.equals(r.toString().trim())) { Object ext = m.get("extension"); if (ext != null && StringUtils.isNotEmpty(ext.toString().trim())) { return ext.toString().trim(); } } } return null; } /** * ä» HIS æ¥æä¸å {@code zdy} èªå®ä¹å段åºçãæ¯å¦åºè¾¹ãæ è®°ï¼éæ±2ï¼ã * * <h4>åæ®µæ¥æº</h4> * {@code controlActProcess.subject.observationRequest.zdy.ISCB}ï¼ * åå¼ {@code 0=å¦ 1=æ¯}ã * * <p>è¯¥åæ®µ**å¨ HIS 宿¹ãäº¤äºæå¡éç¨æ¥å£ææ¡£ã䏿ªå®ä¹** ââ ææ¡£é 25 个 * {@code zdy} åå ± 19 ä¸ªåæ®µï¼å®æµç宿¥æå´æ 26 个ï¼{@code ISCB} å±å ¶ä¸ * 7 个æªå ¬å¼æ©å±å段ä¹ä¸ï¼{@code ISCB/ISDN/BLLSH/SWCJBS/KDYSSJH/KLX/VTEGWBZ}ï¼ã * 宿µæ ·æ¬ä¸ {@code ISCB} æä¸º 0ã * * <h4>ä¸ãåºè¾¹æ£æ¥ç±»åãçåºå«</h4> * {@code check_type.value=1000} çåç§°æ¯"åºè¾¹å¿çµå¾(常è§+é¢è°±)"ï¼é£æ¯**ä¸ä¸ªæ£æ¥é¡¹ç®**ï¼ * æ¬æ è®°è¡¨è¾¾çæ¯**åä¸é¡¹ç®ãæ£è éå°åºè¾¹å**ï¼ä¸¤è è¯ä¹ä¸åï¼ä¸å¯äºç¸æ¿ä»£ã * * <p>æ½æéææ¹æ³æ¯ä¸ºäºå¯åå æµè¯ï¼è§ {@code HisParseSafetyTest}ï¼ã * * @param dataMap HIS æ¥ææ ¹èç¹ * @return {@code "0"}/{@code "1"}ï¼å段缺失æä¸ºç©ºæ¶è¿å null */ static String findBedsideFlag(Map<String, Object> dataMap) { if (dataMap == null) { return null; } Object cap = dataMap.get("controlActProcess"); if (!(cap instanceof Map)) { return null; } Object subject = ((Map<String, Object>) cap).get("subject"); if (!(subject instanceof Map)) { return null; } Object obs = ((Map<String, Object>) subject).get("observationRequest"); if (!(obs instanceof Map)) { return null; } Object zdy = ((Map<String, Object>) obs).get("zdy"); if (!(zdy instanceof Map)) { return null; } Object iscb = ((Map<String, Object>) zdy).get("ISCB"); if (iscb == null) { return null; } String v = iscb.toString().trim(); return v.isEmpty() ? null : v; } /** * åæ«ç«¯èç¹çæ éå¼ï¼ç¨äº {@code code} å¯è½æ¯ Map ä¹å¯è½æ¯å符串çåºæ¯ï¼ã * * @return æ éææ¬ï¼æ«ç«¯ä¸º Map æ¶åå ¶ä¸ç {@code value}/{@code code}ï¼åä¸å°è¿å null */ private static String digText(Map<String, Object> root, String... path) { Object cur = root; for (int i = 0; i < path.length; i++) { if (cur instanceof Map) { cur = ((Map<String, Object>) cur).get(path[i]); } else if (cur instanceof List) { // å表形æï¼å¦ item=[{...}]ï¼å第ä¸ä¸ªå ç´ ç»§ç» List<?> list = (List<?>) cur; if (list.isEmpty() || !(list.get(0) instanceof Map)) { return null; } cur = ((Map<String, Object>) list.get(0)).get(path[i]); } else { return null; } } if (cur == null) { return null; } if (cur instanceof Map) { Map<String, Object> m = (Map<String, Object>) cur; Object v = m.get("value"); if (v == null) { v = m.get("code"); } return v == null ? null : v.toString(); } if (cur instanceof String) { String s = (String) cur; return s.trim().isEmpty() ? null : s; } return cur.toString(); } /** 仿¥æç {@code component2.observationRequest.code.code} 忣æ¥é¡¹ç®ä»£ç ï¼å¯ä¸ºç©ºï¼ */ private String extractCheckCodeFromComponent2(Map<String, Object> dataMap) { // ç±»åå®å ¨ï¼code å¯è½æ¯ Mapï¼ä¹å¯è½æ¯ç©ºå符串 return digText(dataMap, "controlActProcess", "subject", "placerGroup", "component2", "observationRequest", "code", "code"); } /** 仿¥æç {@code component2.observationRequest.location...} åæ§è¡ç§å®¤ç¼ç ï¼å¯ä¸ºç©ºï¼ */ private String extractDeptCodeFromComponent2(Map<String, Object> dataMap) { return digText(dataMap, "controlActProcess", "subject", "placerGroup", "component2", "observationRequest", "location", "serviceDeliveryLocation", "serviceProviderOrganization", "id", "item", "extension"); } /** * ä» dataMap 䏿å encounter æ°æ®ã * * <p>æ¥æè·¯å¾ï¼{@code controlActProcess.subject.observationRequest.componentOf1.encounter}ã * * <p><b>注æ</b>ï¼{@code componentOf1} ä½äº {@code observationRequest} ä¹ä¸ï¼ * ä¸ {@code id}ã{@code code}ã{@code component2} å级ï¼**䏿¯** {@code subject} çç´æ¥åèç¹ã * æé æµè¯æ¥ææè§£ææ¥å¿æ¶å®¹ææéå±çº§ï¼æ¤å¤é级å¤ç©ºä»¥ä¾¿å®ä½ã */ @SuppressWarnings("unchecked") private Map<String, Object> extractEncounter(Map<String, Object> dataMap) { Map<String, Object> cap = (Map<String, Object>) dataMap.get("controlActProcess"); if (cap == null) { return null; } Map<String, Object> subject = (Map<String, Object>) cap.get("subject"); if (subject == null) { return null; } Map<String, Object> observationRequest = (Map<String, Object>) subject.get("observationRequest"); if (observationRequest == null) { return null; } Object componentOf1 = observationRequest.get("componentOf1"); if (componentOf1 == null) { return null; } return (Map<String, Object>) ((Map<String, Object>) componentOf1).get("encounter"); } /** * æ£æ¥é¢çº¦ç¶ææ°å¢/æ´æ° * ï¼action: {@code S050401}/{@code S050402} æ°å¢ã{@code S050501}/{@code S050502} æ´æ°ï¼ã * * <h3>æ¬æ¬¡æ¹å¨</h3> * <ol> * <li><b>å 餿»ä»£ç </b>ï¼åå®ç°å¨è®°å½ä¸å卿¶è°ç¨ {@code handleAppointmentCreate(dataMap)}ï¼ * 使¬æå¡çæ¥æç»ææ¯ {@code subject.actAppointment}ï¼è create ææ * {@code subject.observationRequest} ââ 两è å®å ¨ä¸å ¼å®¹ï¼{@code extractEncounter} * å¿ ç¶è¿å null å¹¶æå¼å¸¸ï¼åç´§éå ¶åç {@code log.warn("æªæ¾å°é¢çº¦è®°å½")} * å æ¤**æ°¸è¿ä¸ä¼æ§è¡**ãç°æ¹ä¸ºæç¡®è®°æ¥å¿ + 容鿰å¢ã</li> * <li><b>ç¶æå½ä¸å</b>ï¼{@code ZDY.statusCode} æ¯**é¢çº¦ç¶æ**ï¼å¦ 1=å·²é¢çº¦ï¼ï¼ * ä¸ {@code S0405} ç**æ£æ¥ç¶æç¼ç **è¯ä¹ä¸åï¼ä½ååå ¥ {@code status} åã * è¿éç»ä¸èµ° {@link HisCheckStatusEnum#normalize(String)} æ ¡éªã</li> * <li><b>容鿰å¢</b>ï¼Q4 è¦æ±ï¼ï¼è®°å½ä¸å卿¶è®° WARN 并便®æ¬æ¥ææå ¥æ°è®°å½ã</li> * <li><b>å¯ç¨æªä½¿ç¨å段</b>ï¼Q7 è¦æ±ï¼ï¼{@code ZDY.remark}ï¼æ³¨æäºé¡¹ï¼ã * {@code ZDY.area}ï¼ä½ç½®ï¼ã{@code ZDY.roomcode}/{@code roomname}ï¼æ¿é´ï¼ã * {@code patient.id.item[4]}ï¼é¢çº¦æåºå·ï¼ã</li> * <li><b>空å¼é²å¾¡</b>ï¼åå®ç°ç´æ¥ {@code LocalDateTime.parse(bookTimeStr)} * ä¸ {@code Integer.parseInt(bookSrc)}ï¼æ¥æç¼ºå段æ¶ä¼æå¼å¸¸å¯¼è´æ´æ¡æ¶æ¯å¤±è´¥ã</li> * </ol> */ @Override @Transactional(rollbackFor = Exception.class) public void handleCheckAppointmentUpdate(Map<String, Object> dataMap) { Map<String, Object> controlActProcess = (Map<String, Object>) dataMap.get("controlActProcess"); if (controlActProcess == null) { throw exception(HIS_MESSAGE_PARSE_FAIL); } Map<String, Object> subject = (Map<String, Object>) controlActProcess.get("subject"); Map<String, Object> actAppointment = subject == null ? null : (Map<String, Object>) subject.get("actAppointment"); if (actAppointment == null) { throw exception(HIS_MESSAGE_PARSE_FAIL); } if (applyNo == null) { // 1. è·åç³è¯·ç¼å·ã // 注æï¼æ¥å£ææ¡£å®ä¹é¢çº¦å·å¨ actAppointment.id.extensionï¼å¦ 3360270ï¼ï¼ // èå®é æ¥æåæ¶æä¾äº referencedOrder[].actOrder.id.extensionï¼å¦ 2126091700001ï¼ // ä¸ S0201ECG å建çç³è¯·åå·ä¸è´ï¼ãæ¬å° appointment.apply_no åçæ¯åè ï¼ // å æ¤**ä¼å å referencedOrder**ï¼åä¸å°ååéå° actAppointment.idã String applyNo = extractApplyNoFromCheckAppointment(actAppointment); if (StringUtils.isEmpty(applyNo)) { log.warn("[handleCheckAppointmentUpdate][æªæ¾å°ç³è¯·ç¼å·ï¼å¿½ç¥] dataMap={}", dataMap); throw exception(HIS_APPLY_NO_MISSING); } log.warn("[handleCheckAppointmentUpdate][æªæ¾å°ç³è¯·ç¼å·]"); // 1.1 ãå¿ åè¿æ»¤ãS050401/S050501 åæ ·æ¯**å ¨é¢éç¨**æå¡ï¼ä¼æ¨éæ¾å°/è¶ å£°ç // éå¿çµç§å®¤çé¢çº¦åï¼å®æµ 2026-09-17ï¼S050401 109/256ãS050501 4/19 为éå¿çµï¼ // æ£æ¥é¡¹ç®å¦"å³èæ£ä¾§ä½/2å·æºæ¿(DR)"ã"å½©è¶ å³ä¸è¢å¨è/5å·è¯å®¤"ï¼ã // æ¤å该å¤çå¨**没æä»»ä½è¿æ»¤**ï¼å¯¼è´è¿äºå被å½ä½å¿çµç³è¯·åééå ¥åºã // éå¿çµåç´æ¥è·³è¿ï¼åªè®°æ¥å¿ãä¸è½åºãä¸è¿åé误ï¼é¿å HIS åå¤éæ¨ï¼ã Map<String, Object> zdyNode = (Map<String, Object>) actAppointment.get("ZDY"); String checkDeptCode = extractDeptCodeFromCheckAppointment(actAppointment); if (!hisEcgFilter.isEcgOrderWithZdy("S050401/S050501", applyNo, checkDeptCode, zdyNode)) { return; } // æ ¹æ®applyNoæ¥è¯¢é¢çº¦è®°å½ // 2. è§£æé¢çº¦æ¶é´ï¼å¯è½ä¸ºç©ºï¼åå®ç°ä¼ç´æ¥æå¼å¸¸ï¼ Map<String, Object> zdy = zdyNode; Map<String, Object> effectiveTime = (Map<String, Object>) actAppointment.get("effectiveTime"); Map<String, Object> anyTime = effectiveTime == null ? null : (Map<String, Object>) effectiveTime.get("any"); String bookTimeStr = anyTime == null ? null : (String) anyTime.get("value"); LocalDateTime bookTime = parseDateTime(bookTimeStr); LocalDate bookDate = bookTime == null ? null : bookTime.toLocalDate(); // 3. æ¶é´æ®µï¼ZDY.timeï¼å½¢å¦ "2026-09-17 08:30-09:00"ï¼ï¼è§£æå¤±è´¥ä¸å½±åå ¶ä»å段 Integer bookTimeslot = parseBookTimeslot(zdy == null ? null : (String) zdy.get("time")); // 4. å°±è¯ç±»å« â bookSrcï¼ææ¡£ï¼actAppointment.code.codeï¼ä½é¢/é¨è¯/æ¥è¯ä»£ç ï¼ Map<String, Object> code = (Map<String, Object>) actAppointment.get("code"); String bookSrc = code == null ? null : (String) code.get("code"); Integer bookSrcValue = parseIntegerQuietly(bookSrc); // 5. é¢çº¦ç¶æå½ä¸åï¼ZDY.statusCodeï¼ String rawStatus = zdy == null || zdy.get("statusCode") == null ? null : zdy.get("statusCode").toString(); String status = HisCheckStatusEnum.normalize(rawStatus); if (status == null && rawStatus != null) { log.warn("[handleCheckAppointmentUpdate][é¢çº¦ç¶æç¼ç ä¸å¨ç¼ç 表å ï¼å°ä¸æ´æ°ç¶æ] applyNo={} rawStatus={}", applyNo, rawStatus); } // 6. å¹é æ¬å°è®°å½ AppointmentDO appointment = appointmentMapper.getByApplyNo(applyNo); if (appointment == null) { handleAppointmentCreate(dataMap); log.warn("[handleCheckAppointmentUpdate][æªæ¾å°é¢çº¦è®°å½ applyNo({})]", applyNo); log.warn("[handleCheckAppointmentUpdate][æªæ¾å°é¢çº¦è®°å½ï¼æ§è¡å®¹éæ°å¢] applyNo={} status={}", applyNo, status); insertAppointmentFromCheckAppointment(applyNo, actAppointment, bookDate, bookTime, bookTimeslot, bookSrcValue, status); return; } // è·åé¢çº¦æ¶é´ Map<String, Object> effectiveTime = (Map<String, Object>) actAppointment.get("effectiveTime"); Map<String, Object> any = (Map<String, Object>) effectiveTime.get("any"); String bookTimeStr = (String) any.get("value"); // è·åé¢çº¦æ¥æº Map<String, Object> code = (Map<String, Object>) actAppointment.get("code"); String bookSrc = (String) code.get("code"); // è§£æé¢çº¦æ¶é´ LocalDateTime bookTime = LocalDateTime.parse(bookTimeStr, DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); LocalDate bookDate = bookTime.toLocalDate(); Integer bookTimeslot = null; // è·åæ¶é´æ®µ try { // String timeRange = (String) ((Map<String, Object>) actAppointment.get("ZDY")).get("time");è¿è¡å¦ææ¯æ´æ°æä½çæ¶åï¼æå¯è½æ¥ç©ºæé(ä½ä¸å½±åï¼å¯ä»¥ä¸ç¨ç®¡) String timeRange = (String) ((Map<String, Object>) actAppointment.get("ZDY")).get("time"); String[] time1 = timeRange.split(" "); String[] times = time1[1].split("-"); String startTime = times[0].trim(); String endTime = times[1].trim(); // è½¬æ¢æ¶é´æ®µæ ¼å¼ä¸ºhhmmhhmm bookTimeslot = Integer.parseInt(startTime.replace(":", "")) * 10000 + Integer.parseInt(endTime.replace(":", "")); } catch (Exception e) { e.printStackTrace(); // 7. æ´æ°å·²æè®°å½ if (bookDate != null) { appointment.setBookDate(bookDate); } // æ´æ°é¢çº¦ä¿¡æ¯ appointment.setBookDate(bookDate); appointment.setBookTimeslot(bookTimeslot); appointment.setBookTime(bookTime); appointment.setBookSrc(Integer.parseInt(bookSrc)); appointment.setStatus((String) ((Map<String, Object>) actAppointment.get("ZDY")).get("statusCode")); // ä¿åæ´æ° if (bookTime != null) { appointment.setBookTime(bookTime); } if (bookTimeslot != null) { appointment.setBookTimeslot(bookTimeslot); } if (bookSrcValue != null) { appointment.setBookSrc(bookSrcValue); } if (status != null) { appointment.setStatus(status); } // ââ HIS è¡¥å åæ®µï¼é表æ°å¢åä¸èµ·å¯ç¨ï¼ââ // 注æï¼remark å¯è½é¿è¾¾æ°ç¾å符ï¼å¦å®æµå¿çµå¾è¿å¨è¯éªæ³¨æäºé¡¹ 474 åï¼ï¼ // å¿ é¡»æåå®½æªæï¼å¦å Data too long ä¼å¯¼è´æ´ä¸ªäºå¡åæ»ï¼è§ truncate æ¹æ³è¯´æï¼ if (zdy != null) { Object remark = zdy.get("remark"); if (remark != null && StringUtils.isNotEmpty(remark.toString())) { appointment.setRemark(truncate(remark.toString(), REMARK_MAX_LEN)); } Object roomName = zdy.get("roomname"); if (roomName != null && StringUtils.isNotEmpty(roomName.toString())) { appointment.setRoomName(truncate(roomName.toString(), ROOM_NAME_MAX_LEN)); } } // é¢çº¦æåºå·ï¼patient.id.item[4]ï¼ Integer seqNum = extractBookSeqNum(actAppointment); if (seqNum != null) { appointment.setBookSeqNum(seqNum); } appointmentMapper.updateById(appointment); } /** * 忣æ¥é¢çº¦æ¥æä¸çæ§è¡/ç³è¯·ç§å®¤ç¼ç ã * <p> * æ¥æè·¯å¾ï¼{@code actAppointment.subject.patient.providerOrganization.id.item.extension} * ï¼å®æµæ ·ä¾ {@code ZY012}ï¼ãä» ç¨äºå¿çµå¤å®ç"便® C"ï¼éé ç½®ç½ååæçæï¼ã */ private String extractDeptCodeFromCheckAppointment(Map<String, Object> actAppointment) { return digText(actAppointment, "subject", "patient", "providerOrganization", "id", "item", "extension"); } /** * é¢çº¦æåºå·å¨æ¥æä¸ç root æ è¯ã * <p> * æ¥å£ææ¡£ 6.4 ç示ä¾éæãé¢çº¦æåºå·ãæ³¨å¨ {@code item[4]} ä½ç½®ï¼ * ä½**å®é æ¥æç root ä¸ä½ç½®ä¸ä¸è´**ï¼ç宿¥æï¼2026-09-17 æ¥å¿ï¼ä¸º * <pre> * item[0] root=2.16.156.10011.2.5.1.5 åID * item[1] root=2.16.156.10011.2.5.1.4 æ£è ID * item[2] root=2.16.156.10011.1.10 é¨ï¼æ¥ï¼è¯å· * item[3] root=2.16.156.10011.1.12 ä½é¢å· * item[4] root=2.16.156.10011.2.5.1.8 å°±è¯æ¬¡æ° â 䏿¯æåºå· * item[5] root=2.16.156.10011.2.5.1.9 å°±è¯æµæ°´å· * item[6] root=2.16.156.10011.2.5.1.11 é¢çº¦æåºå· â å®é 卿¤ * </pre> * å æ¤**æ root å¹é **èéæä½ç½®åå¼ï¼é¿å ä½ç½®æ¼ç§»å¯¼è´åéåæ®µã */ private static final String ROOT_BOOK_SEQ_NUM = "2.16.156.10011.2.5.1.11"; /** * åãé¢çº¦æåºå·ãã * <p> * æ¥æè·¯å¾ï¼{@code actAppointment.subject.patient.id.item[]} ä¸ * {@code root=2.16.156.10011.2.5.1.11} çé£ä¸é¡¹ç {@code extension}ã * * @return æåºå·ï¼åä¸å°æ¶è¿å null */ @SuppressWarnings("unchecked") private Integer extractBookSeqNum(Map<String, Object> actAppointment) { List<?> items = asList(actAppointment, "subject", "patient", "id", "item"); for (Object it : items) { if (!(it instanceof Map)) { continue; } Map<String, Object> item = (Map<String, Object>) it; Object root = item.get("root"); if (root != null && ROOT_BOOK_SEQ_NUM.equals(root.toString().trim())) { Object ext = item.get("extension"); return ext == null ? null : parseIntegerQuietly(ext.toString()); } } return null; } /** * 忣æ¥é¢çº¦æ¥æçç³è¯·åå·ã * <p> * ä¼å {@code referencedOrder[0].actOrder.id.extension}ï¼ä¸ S0201ECG å建çç³è¯·åå·ä¸è´ï¼ * 宿µ {@code 2126091700001}ï¼ï¼åä¸å°æ¶åéå° {@code actAppointment.id.extension} * ï¼æ¥å£ææ¡£å®ä¹çé¢çº¦å·ï¼å®æµ {@code 3360270}ï¼ã */ @SuppressWarnings("unchecked") private String extractApplyNoFromCheckAppointment(Map<String, Object> actAppointment) { Object referencedOrders = actAppointment.get("referencedOrder"); if (referencedOrders instanceof List) { List<?> list = (List<?>) referencedOrders; if (!list.isEmpty() && list.get(0) instanceof Map) { Map<String, Object> first = (Map<String, Object>) list.get(0); Map<String, Object> actOrder = (Map<String, Object>) first.get("actOrder"); if (actOrder != null) { Map<String, Object> id = (Map<String, Object>) actOrder.get("id"); if (id != null && id.get("extension") != null) { return id.get("extension").toString(); } } } } Map<String, Object> id = (Map<String, Object>) actAppointment.get("id"); if (id != null && id.get("extension") != null) { return id.get("extension").toString(); } return null; } /** 便®æ£æ¥é¢çº¦æ¥ææå ¥æ°è®°å½ï¼Q4 容鿰å¢ï¼ */ @SuppressWarnings("unchecked") private void insertAppointmentFromCheckAppointment(String applyNo, Map<String, Object> actAppointment, LocalDate bookDate, LocalDateTime bookTime, Integer bookTimeslot, Integer bookSrcValue, String status) { AppointmentDO appointment = new AppointmentDO(); appointment.setApplyNo(applyNo); appointment.setBookDate(bookDate); appointment.setBookTime(bookTime); appointment.setBookTimeslot(bookTimeslot); appointment.setBookSrc(bookSrcValue); appointment.setStatus(status); Map<String, Object> zdy = (Map<String, Object>) actAppointment.get("ZDY"); // ZDY ä¸ç remarkï¼æ³¨æäºé¡¹ï¼ä¸ roomnameï¼æ¿é´åç§°ï¼å·²é表æ°å¢åè½åºï¼ // areaï¼ä½ç½®ï¼ä¸ roomcodeï¼æ¿é´ç¼ç ï¼ç®å仿 对åºåï¼æä¸ä¿åã if (zdy != null) { Object remark = zdy.get("remark"); if (remark != null && StringUtils.isNotEmpty(remark.toString())) { appointment.setRemark(truncate(remark.toString(), REMARK_MAX_LEN)); } Object roomName = zdy.get("roomname"); if (roomName != null && StringUtils.isNotEmpty(roomName.toString())) { appointment.setRoomName(truncate(roomName.toString(), ROOM_NAME_MAX_LEN)); } } // é¢çº¦æåºå·ï¼patient.id.item[4]ï¼ Integer bookSeqNum = extractBookSeqNum(actAppointment); if (bookSeqNum != null) { appointment.setBookSeqNum(bookSeqNum); } // æ£è ä¿¡æ¯ Map<String, Object> subjectNode = (Map<String, Object>) actAppointment.get("subject"); if (subjectNode != null) { Map<String, Object> patient = (Map<String, Object>) subjectNode.get("patient"); if (patient != null) { List<?> patIdItems = Optional.ofNullable(patient.get("id")) .map(id -> (Map<String, Object>) id).map(id -> id.get("item")) .filter(it -> it instanceof List).map(it -> (List<?>) it) .orElse(Collections.emptyList()); if (patIdItems.size() > 1) { appointment.setPatId((String) ((Map<String, Object>) patIdItems.get(1)).get("extension")); } if (patIdItems.size() > 2) { appointment.setOutpatientNo((String) ((Map<String, Object>) patIdItems.get(2)).get("extension")); } if (patIdItems.size() > 3) { appointment.setHospitalNo((String) ((Map<String, Object>) patIdItems.get(3)).get("extension")); } // é¢çº¦æåºå·å·²å¨ä¸æ¹éè¿ extractBookSeqNum ç»ä¸èµå¼ï¼æ¤å¤ä¸åéå¤å¤ç // æ£è å§å Optional.ofNullable(patient.get("patientPerson")) .map(p -> (Map<String, Object>) p) .map(p -> (Map<String, Object>) p.get("name")) .map(n -> (Map<String, Object>) n.get("item")) .map(i -> (Map<String, Object>) i.get("part")) .map(part -> (String) part.get("value")) .ifPresent(appointment::setPatName); // ç 人ç§å®¤ï¼providerOrganizationï¼ââ Q7 å¯ç¨ Optional.ofNullable(patient.get("providerOrganization")) .map(org -> (Map<String, Object>) org) .ifPresent(org -> { Optional.ofNullable(org.get("id")) .map(id -> (Map<String, Object>) id) .map(id -> (Map<String, Object>) id.get("item")) .map(item -> (Map<String, Object>) item) .map(item -> (String) item.get("extension")) .ifPresent(appointment::setPatDeptCode); Optional.ofNullable(org.get("name")) .map(n -> (Map<String, Object>) n) .map(n -> (Map<String, Object>) n.get("item")) .map(i -> (Map<String, Object>) i.get("part")) .map(part -> (String) part.get("value")) .ifPresent(appointment::setPatDeptDesc); }); } } if (StringUtils.isEmpty(appointment.getPatName())) { log.warn("[insertAppointmentFromCheckAppointment][容鿰å¢çè®°å½ç¼ºå°æ£è å§å] applyNo={}", applyNo); } // appointment.pat_id / pat_name 卿°æ®åºä¸ä¸º NOT NULLï¼ // ç¼ºå¼æ¶è¥ç´æ¥ insert 伿 SQL å¼å¸¸å¹¶å¯¼è´æ´ä¸ªäºå¡åæ»ã // è¿éæåç»åºæç¡®é误ï¼ä¾¿äº HIS ä¾§å®ä½æ¥æé®é¢ã if (StringUtils.isEmpty(appointment.getPatId())) { log.error("[insertAppointmentFromCheckAppointment][æ¥æç¼ºæ£è ç¼å·(pat_id)ï¼æ æ³æ°å¢] applyNo={}", applyNo); throw exception(PATIENT_NOT_EXISTS); } if (appointment.getPatGender() == null) { log.warn("[insertAppointmentFromCheckAppointment][æ¥ææªæä¾æ£è æ§å«ï¼ææªç¥(0)åå ¥] applyNo={}", applyNo); appointment.setPatGender(UNKNOWN_GENDER); } AppointmentSaveReqVO saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class); createAppointment(saveReqVO); } /** è§£æ {@code yyyyMMddHHmmss} æ¶é´ï¼å¤±è´¥æä¸ºç©ºè¿å nullï¼ä¸æå¼å¸¸ï¼ */ private LocalDateTime parseDateTime(String value) { if (StringUtils.isEmpty(value)) { return null; } try { return LocalDateTime.parse(value.trim(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); } catch (Exception e) { log.warn("[parseDateTime][æ¶é´æ ¼å¼éæ³ï¼å¿½ç¥] value={}", value); return null; } } /** è§£æ ZDY.timeï¼å½¢å¦ "2026-09-17 08:30-09:00"ï¼ä¸º hhmmhhmm æ´æ°ï¼å¤±è´¥è¿å null */ private Integer parseBookTimeslot(String timeRange) { if (StringUtils.isEmpty(timeRange)) { return null; } try { String[] parts = timeRange.trim().split("\\s+"); if (parts.length < 2) { return null; } String[] times = parts[1].split("-"); if (times.length < 2) { return null; } String startTime = times[0].trim().replace(":", ""); String endTime = times[1].trim().replace(":", ""); return Integer.parseInt(startTime) * 10000 + Integer.parseInt(endTime); } catch (Exception e) { log.warn("[parseBookTimeslot][æ¶é´æ®µè§£æå¤±è´¥ï¼å¿½ç¥] timeRange={}", timeRange); return null; } } /** å®½æ¾æ´æ°è§£æï¼éæ°åæç©ºè¿å nullï¼é¿å Integer.parseInt(null) æå¼å¸¸ï¼ */ private Integer parseIntegerQuietly(String value) { if (StringUtils.isEmpty(value) || !value.trim().matches("-?\\d+")) { return null; } try { return Integer.parseInt(value.trim()); } catch (NumberFormatException e) { return null; } } /** å®½æ¾ Byte è§£æï¼éæ°åæç©ºè¿å nullï¼ç¨äºæ£è æ§å«ç tinyint åæ®µï¼ */ private Byte parseByteQuietly(String value) { if (StringUtils.isEmpty(value) || !value.trim().matches("-?\\d+")) { return null; } try { return Byte.parseByte(value.trim()); } catch (NumberFormatException e) { return null; } } @Override @@ -735,6 +1717,20 @@ //è®°å½ç»è®°æ¶é´ date = new Date(); } // ãè¯ææ¥å¿ãç»è®°æ¶é´åå ¥åå带类åä¿¡æ¯ï¼ç¨äºå¿«éå®ä½ã00:00:00 æªæãç±»é®é¢ã // // èæ¯ï¼2026-09-27 èµ· appointment.register_date åºç°å¤§é yyyy-MM-dd 00:00:00ï¼ // ç»å®éªç¡®è®¤æå æ¯ãåå ¥å¼æ¯ DATE è¯ä¹çå¼ãèé驱å¨é®é¢ï¼ // · java.util.Date + DATETIME å â ä¿çæ¶åç§ // · java.sql.Date / DATE å â å¿ ç¶åæ 00:00:00 // æ¬æ¥å¿æå° date çå®é ç±»åä¸å¼ï¼è¥æ¥å¿éåºç° java.sql.Date æé 3 ç¶æå´è¢«åï¼ // å³å¯ç´æ¥å®ä½åå ¥æ¹ã if (date != null) { log.info("[handleAppointmentStatusUpdate][ç»è®°æ¶é´åå ¥] applyNo={} status={} " + "æ¥æå¯¹è±¡ç±»å={} å¼={}ï¼æ¶é´é¨ååºä¸ºå½åæ¶å»ï¼è¥ä¸º 00:00:00 说æè¢«æªæï¼", applyNo, status, date.getClass().getName(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date)); } //ç¶ææ´æ° Integer i = appointmentMapper.updateStatusByApplyNo(applyNo, status, date); log.info("ç³è¯·åç»è®°applyNo:{},ç¶æstatus:{},æ´æ°ç»æï¼{}", applyNo, status, i); jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/callingscreen/CallingScreenServiceImpl.java
@@ -34,6 +34,15 @@ @Resource private RoomMapper roomMapper; /** * éæ±1ï¼ç¨äºåå¡«æ£è ä¿¡æ¯ï¼æ§å«/åºçæ¥æ/ç åº/åºå·/çµè¯/æ¥æº/å¼åå»å¸çï¼ã * <p> * ä¸åå±å¹æ¥è¯¢æ¯**ç´æ¥æ¥ queueMapper** çï¼ä¸ç»è¿ QueueService çæ¥è¯¢æ¹æ³ï¼ * å æ¤å¿ é¡»æ¾å¼è°ç¨ fillAppointmentInfo è¡¥é½ï¼å¦å大å±/è¯é´å±åªæå§åã */ @Resource private cn.lihu.jh.module.ecg.service.queue.QueueService queueService; @Resource private CheckTypeMapper checkTypeMapper; @@ -88,13 +97,38 @@ @Override public Map<Integer, List<QueueDO>> getBigScreenPatient() { Map<Integer, List<QueueDO>> mapDisplayColQueue = new HashMap<>(); int displayColCnt = (int) mapCheckTypeVsDisplayColumn.values().stream().distinct().count(); for (int dispCol=0; dispCol<displayColCnt; dispCol++) { List<QueueDO> columnQueueData = new ArrayList<>(); mapDisplayColQueue.put(dispCol, columnQueueData); } mapDisplayColQueue.values().forEach(List::clear); // ãä¿®å¤ NPEãæ**çå® calling_column å¼**建é®ï¼è䏿¯ 0..count-1ã // // åå®ç°ï¼ // int displayColCnt = distinct().count(); // ä¾å¦ = 5 // for (i = 0; i < displayColCnt; i++) put(i, ...); // å»ºé® 0,1,2,3,4 // ä½ä¸é¢åå¼ç¨çæ¯**çå® calling_column**ï¼å¦ 0,1,3,4,-1ï¼ï¼ // å ¶ä¸ -1ï¼è¡¨ç¤º"ä¸å¨å¤§å±æ¾ç¤º"ï¼æ°¸è¿ä¸ä¼è¢«å»ºé® â get(-1) è¿å null â NPEï¼ // 导è´**æ´ä¸ªå¤§å±æ¥å£ 500ãæ´å±ç©ºç½**ã宿µ check_type 䏿 7 个类åç // calling_column = -1ï¼700/800/900/1200/1300/1400/1500ï¼ï¼åªè¦è¿äºç±»åææ£è // 卿éï¼å°±ä¼è§¦åï¼å¤§å± SQL æ check_type è¿æ»¤ï¼å¿ ç¶è¢«æåºï¼ã // // ä¿®å¤åï¼åªä¸º**ææçæ¾ç¤ºå**ï¼>=0ï¼å»ºé®ï¼-1 çç±»åå¨å¤§å±ä¸æ¾ç¤ºï¼ // ç±ä¸æ¹ col å¤å®è·³è¿ï¼ä¸å产ç NPEã // // ãå¥å£®æ§ãmapCheckTypeVsDisplayColumn ä» å¨ getDisplayColInfo() ä¸èµå¼ // ï¼å£°æå¤ä¸º nullï¼ãæ£å¸¸å¯å¨æµç¨ç± MySpringEventListener è°ç¨è¯¥æ¹æ³åå§åï¼ // ä½è¥å¯å¨é¶æ®µè¯¥è°ç¨æªæåï¼ä¾å¦ CheckTypeMapper æ¥è¯¢å¼å¸¸ï¼ï¼ // è¿éä¼ç´æ¥ NPE â 大å±å次 500ãæ å å¤ç©ºå¹¶æ°æ§åå§åã if (null == mapCheckTypeVsDisplayColumn) { log.warn("[getBigScreenPatient] æ¾ç¤ºåæ å°å°æªåå§åï¼å°è¯æ°æ§åå§å"); try { getDisplayColInfo(); } catch (Exception e) { log.error("[getBigScreenPatient] æ¾ç¤ºåæ å°åå§å失败ï¼è¿åç©ºç»æ", e); return mapDisplayColQueue; // è¿å空 mapï¼å端å±ç¤ºç©ºå±èé 500 } } mapCheckTypeVsDisplayColumn.values().stream() .filter(col -> col != null && col >= 0) .distinct() .forEach(col -> mapDisplayColQueue.put(col, new ArrayList<>())); List<Integer> queueStatusList = new ArrayList<>(); queueStatusList.add(QueueStatusEnum.READY.getStatus()); @@ -105,8 +139,20 @@ queueStatusList.add(QueueStatusEnum.PASSED_WAITING.getStatus()); queueStatusList.add(QueueStatusEnum.AFFINITY.getStatus()); List<QueueDO> queueDOList = queueMapper.getBigScreenQueueByStatus( queueStatusList ); // éæ±1ï¼åå¡«æ£è ä¿¡æ¯ï¼æ§å«/åºçæ¥æ/ç åº/åºå·/çµè¯/æ¥æº/å¼åå»å¸çï¼ queueService.fillAppointmentInfo(queueDOList); queueDOList.forEach(queueDO -> { List<QueueDO> columnQueueData = mapDisplayColQueue.get(mapCheckTypeVsDisplayColumn.get(queueDO.getBookCheckType())); Integer col = mapCheckTypeVsDisplayColumn.get(queueDO.getBookCheckType()); // åéé²å¾¡ï¼æ å°ç¼ºå¤±æå为 -1ï¼ä¸æ¾ç¤ºï¼æ¶è·³è¿ï¼é¿å NPE if (col == null || col < 0) { return; } List<QueueDO> columnQueueData = mapDisplayColQueue.get(col); if (columnQueueData == null) { log.warn("[getBigScreenPatient][æ¾ç¤ºåæªåå§åï¼å·²è·³è¿] checkType={} callingColumn={}", queueDO.getBookCheckType(), col); return; } columnQueueData.add( queueDO ); }); @@ -150,8 +196,22 @@ queueStatusList.add(QueueStatusEnum.READY.getStatus()); queueStatusList.add(QueueStatusEnum.ONSTAGE.getStatus()); queueStatusList.add(QueueStatusEnum.PASSED.getStatus()); // ãéæ±8 ä¿®å¤ãè¡¥ä¸ãå·²è¿å·-æéã(3)ã // // éæ±åæï¼ãè¿å·æ£è åºåºç°å¨**大å±åè¯é´å±**ãï¼ä¸ãè¿å·ä¸çå¾ ä¸æå¨ä¸èµ·ãæåºå·ååºãã // 大å±ç getBigScreenPatient å·²å« PASSED_WAITING(3)ï¼ä½æ¬æ¹æ³ï¼è¯é´å±ï¼**æ¼äº**ï¼ // å¯¼è´ status=3 çæ£è å¨å¤§å±å¯è§ãå¨è¯é´å±ä¸å¯è§ã // // 宿µå¤ç°ï¼æé seq 1~5 å ± 5 使£è ï¼å« status=3 ä¸ 5ï¼ï¼ // 大å±è¿å 5 ä½ â ï¼è¯é´å±è¿å 4 ä½ï¼ç¼º status=3 é£ä½ï¼ð´ // // æåºæ éé¢å¤å¤çï¼getRoomQueueByStatus ç order by å·²æ status in (3,5) å½ä¸ºåä¸ç» // ï¼æå¨å°±è¯ä¸ä¹åãåè¯ä¹åï¼ï¼ç»å åæ seq_numãbook_timeslot ååº ââ æ£åéæ±ã queueStatusList.add(QueueStatusEnum.PASSED_WAITING.getStatus()); queueStatusList.add(QueueStatusEnum.AFFINITY.getStatus()); List<QueueDO> queueDOList = queueMapper.getRoomQueueByStatus(roomId, queueStatusList); // éæ±1ï¼åå¡«æ£è ä¿¡æ¯ï¼è¯é´å±-æ£æ¥éåï¼ queueService.fillAppointmentInfo(queueDOList); //æ [亲åç] æªå°ä¸»é¡¹åé¢ List<QueueDO> affinityWaitingList = new ArrayList<>(); @@ -197,6 +257,8 @@ queueStatusList.add(QueueStatusEnum.INSTALLING.getStatus()); queueStatusList.add(QueueStatusEnum.RECALLED_INSTALL.getStatus()); List<QueueDO> queueDOList = queueMapper.getRoomQueueByStatus(roomId, queueStatusList); // éæ±1ï¼åå¡«æ£è ä¿¡æ¯ï¼è¯é´å±-è£ æºéåï¼ queueService.fillAppointmentInfo(queueDOList); //æ [亲åç] æªå°ä¸»é¡¹åé¢ List<QueueDO> affinityReceivedList = new ArrayList<>(); jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/devrent/DevRentServiceImpl.java
@@ -154,15 +154,63 @@ //queueMapper.updateBedQueueStatus(createReqVO.getRoomId(), createReqVO.getBedNo(), // QueueStatusEnum.ONSTAGE.getStatus(), QueueStatusEnum.FINISH.getStatus()); QueueDO firstOnStageQueueItem = queueMapper.getBedFirstQueueItemByStatus(createReqVO.getRoomId(), createReqVO.getBedNo(), QueueStatusEnum.ONSTAGE.getStatus()); // QueueStatusEnum.ONSTAGE => QueueStatusEnum.FINISH firstOnStageQueueItem.setStatus(QueueStatusEnum.FINISH.getStatus()); // é»è®¤ç¶æ 设置 queueMapper.updateById(firstOnStageQueueItem); // ã缺é·ä¿®å¤ãåå®ç°ï¼ // QueueDO firstOnStageQueueItem = queueMapper.getBedFirstQueueItemByStatus( // roomId, bedNo, ONSTAGE); // firstOnStageQueueItem.setStatus(FINISH); // â åä¸å°æ¶ä¸º nullï¼ç´æ¥ NPE // // 两个é®é¢ï¼ // 1) NPEï¼è¯¥å·¥ä½å½å没æ"å°±è¯ä¸(30)"æ£è æ¶è¿å nullï¼ä¾å¦å»çå ç¹äº"æ¾å¼æ£æ¥"ï¼ // cancelRoutineOperation å·²æè¯¥æ£è 置为 40ï¼ï¼ç¬¬ 159 è¡ç©ºæé â æ´ä¸ªäºå¡åæ»ã // 2) 误伤ï¼åªæ"å·¥ä½ + ç¶æå seq_num æå°ç䏿¡"ï¼è¥æé´å·²å«äºä¸ä¸ä½æ£è ï¼ // 伿**ä¸ä¸ä½æ£è **误置为"已就è¯(40)"ã // // ä¿®å¤çç¥ï¼æå¯é æ§ä»é«å°ä½ï¼ï¼ // â ä¼å æ patId + checkType 精确å¹é ï¼å端 submitForm ä¼ ç formData å«è¿ä¸¤ä¸ªå段ï¼ï¼ // â¡ éåå°"å·¥ä½ + ç¶æ + 仿¥"å update_time ææ°ç䏿¡ï¼æ¯ seq_num æå°æ´è´´åå½åæ£è ï¼ï¼ // ⢠ä»åä¸å° â è®°è¦åå¹¶**è·³è¿éåæ´æ°**ï¼è䏿¯æ NPE 让æ´ä¸ª"æ£æ¥å®æ"失败ã // æ¤æ¶è®¾å¤å½è¿ãä½ä¸è®°å½çä»ä¼æ£å¸¸ä¿åï¼æ°æ®ä¸ä¸¢ï¼ï¼ä» éåç¶ææªåã QueueDO onStageQueueItem = null; // æ£æ¥é¡¹ç®.äº²åæ§ å¤çé»è¾ CheckTypeDO checkTypeDO = queueServiceTxFunctions.getCheckTypeItem(firstOnStageQueueItem.getBookCheckType()); if (checkTypeDO.getAffinityCheckTypes().length > 0) { procAffinityWhenRoutineFinish(firstOnStageQueueItem.getPatId(), checkTypeDO.getAffinityCheckTypes()); // â 精确å®ä½ï¼ç¨ Spring ç StringUtilsï¼é¿å é¢å¤ä¾èµï¼ // æ¬æ¨¡åæªå¼å ¥ commons-lang3ï¼å¿ç¨ org.apache.commons.lang3.StringUtilsï¼ if (org.springframework.util.StringUtils.hasText(createReqVO.getPatId()) && null != createReqVO.getCheckType()) { onStageQueueItem = queueMapper.getBedQueueItemByPatAndStatus( createReqVO.getRoomId(), createReqVO.getBedNo(), createReqVO.getPatId(), createReqVO.getCheckType(), QueueStatusEnum.ONSTAGE.getStatus()); } // â¡ éåï¼å该工ä½ä»æ¥æè¿æ´æ°ç䏿¡"å°±è¯ä¸" if (null == onStageQueueItem) { onStageQueueItem = queueMapper.getBedLatestQueueItemByStatus( createReqVO.getRoomId(), createReqVO.getBedNo(), QueueStatusEnum.ONSTAGE.getStatus()); if (null != onStageQueueItem) { log.warn("[routineFinish] æªæ patId å½ä¸ï¼éå为æå·¥ä½åæè¿å°±è¯ä¸æ£è . " + "roomId={} bedNo={} reqPatId={} reqCheckType={} å®é patId={} checkType={}", createReqVO.getRoomId(), createReqVO.getBedNo(), createReqVO.getPatId(), createReqVO.getCheckType(), onStageQueueItem.getPatId(), onStageQueueItem.getBookCheckType()); } } // ⢠ä»åä¸å°ï¼è·³è¿éåæ´æ°ï¼ä¸æå¼å¸¸ï¼ä¿è¯"æ£æ¥å®æ"æ¬èº«å¯ç¨ï¼ if (null == onStageQueueItem) { log.warn("[routineFinish] è¯¥å·¥ä½æ [å°±è¯ä¸]æ£è ï¼è·³è¿éåç¶ææ´æ°. roomId={} bedNo={} patId={} applyNo={}", createReqVO.getRoomId(), createReqVO.getBedNo(), createReqVO.getPatId(), createReqVO.getApplyNo()); } else { // QueueStatusEnum.ONSTAGE => QueueStatusEnum.FINISH onStageQueueItem.setStatus(QueueStatusEnum.FINISH.getStatus()); queueMapper.updateById(onStageQueueItem); // æ£æ¥é¡¹ç®.äº²åæ§ å¤çé»è¾ CheckTypeDO checkTypeDO = queueServiceTxFunctions.getCheckTypeItem(onStageQueueItem.getBookCheckType()); if (null != checkTypeDO && null != checkTypeDO.getAffinityCheckTypes() && checkTypeDO.getAffinityCheckTypes().length > 0) { procAffinityWhenRoutineFinish(onStageQueueItem.getPatId(), checkTypeDO.getAffinityCheckTypes()); } } //æ£æ¥å®æåï¼æ¤æ¶æ£æ¥ç»è®°åæäºï¼éè¦å°è¿ä¸ªååç»éæå¹³å°(线ä¸ç¯å¢æåå) @@ -177,7 +225,13 @@ log.info("routineFinishWebServiceClientçè¿åå¼ä¸ºï¼{}", s); if (s.contains("æ´æ°æå")) { //éè¦æ ¹æ®applyNo,å°appiontment表éçstatusæ¹æ3 appointmentMapper.updateStatusByApplyNo(createReqVO.getApplyNo(), "3", new Date()); // ãè¯ææ¥å¿ãå AppointmentServiceImpl#handleAppointmentStatusUpdateï¼ // æå°æ¥æå¯¹è±¡ç±»åä¸å¼ï¼ä¾¿äºå®ä½ register_date è¢«åæ 00:00:00 çåå ¥æ¹ã java.util.Date regNow = new Date(); log.info("[devRentCreate][ç»è®°æ¶é´åå ¥] applyNo={} æ¥æå¯¹è±¡ç±»å={} å¼={}", createReqVO.getApplyNo(), regNow.getClass().getName(), new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(regNow)); appointmentMapper.updateStatusByApplyNo(createReqVO.getApplyNo(), "3", regNow); } } else { //æ£æ¥ç±»åæ¯åºè¾¹çæå¸¸è§çï¼éè¦æ ¹æ®applyNo,å°appiontment表éçstatusæ¹æ7 @@ -220,7 +274,12 @@ log.info("webserviceçè¿åå¼ä¸ºï¼{}", s); if (s.contains("æ´æ°æå")) { //éè¦æ ¹æ®applyNo,å°appiontment表éçstatusæ¹æ3 appointmentMapper.updateStatusByApplyNo(createReqVO.getApplyNo(), "3", new Date()); // ãè¯ææ¥å¿ãåä¸ï¼æå°æ¥æå¯¹è±¡ç±»åä¸å¼ java.util.Date regNow2 = new Date(); log.info("[devRentOther][ç»è®°æ¶é´åå ¥] applyNo={} æ¥æå¯¹è±¡ç±»å={} å¼={}", createReqVO.getApplyNo(), regNow2.getClass().getName(), new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(regNow2)); appointmentMapper.updateStatusByApplyNo(createReqVO.getApplyNo(), "3", regNow2); } } List<Integer> jobTypeList = new ArrayList<Integer>(); @@ -771,13 +830,17 @@ @Override public DevRentDO getDevRent(Long id) { return devRentMapper.selectById(id); DevRentDO devRentDO = devRentMapper.selectById(id); fillPatientInfo(devRentDO); return devRentDO; } @Override public PageResult<DevRentDO> getDevRentPage(DevRentPageReqVO pageReqVO) { pageReqVO.setState(0); return devRentMapper.selectPage(pageReqVO); PageResult<DevRentDO> pageResult = devRentMapper.selectPage(pageReqVO); fillPatientInfo(pageResult.getList()); return pageResult; } @Override @@ -786,7 +849,9 @@ stateList.add(DevRentStateEnum.INSTALLED.getState()); stateList.add(DevRentStateEnum.RECEIVED.getState()); searchReqVO.setStateList(stateList); return devRentMapper.getRentByState(searchReqVO); DevRentDO devRentDO = devRentMapper.getRentByState(searchReqVO); fillPatientInfo(devRentDO); return devRentDO; } @Override @@ -794,7 +859,9 @@ List<Integer> stateList = new ArrayList<>(); stateList.add(DevRentStateEnum.FREE.getState()); searchReqVO.setStateList(stateList); return devRentMapper.getRentByState(searchReqVO); DevRentDO devRentDO = devRentMapper.getRentByState(searchReqVO); fillPatientInfo(devRentDO); return devRentDO; } @Override @@ -803,7 +870,9 @@ stateList.add(DevRentStateEnum.RECEIVED.getState()); stateList.add(DevRentStateEnum.RECEIVED_CANCELLED.getState()); searchReqVO.setStateList(stateList); return devRentMapper.getRentByState(searchReqVO); DevRentDO devRentDO = devRentMapper.getRentByState(searchReqVO); fillPatientInfo(devRentDO); return devRentDO; } @Override @@ -811,7 +880,67 @@ List<Integer> stateList = new ArrayList<>(); stateList.add(DevRentStateEnum.DISMANTLED.getState()); searchReqVO.setStateList(stateList); return devRentMapper.getRentByState(searchReqVO); DevRentDO devRentDO = devRentMapper.getRentByState(searchReqVO); fillPatientInfo(devRentDO); return devRentDO; } // ==================== éæ±1ï¼åå¡«æ£è ä¿¡æ¯ 18 项 ==================== // dev_rent 表åªåäº applyNo / patName / patDetailsï¼ // å ¶ä½æ£è ä¿¡æ¯ï¼æ§å«ãåºçæ¥æãç åºãåºå·ãçµè¯ãæ¥æºãå°±è¯å¡å·ã // ç»è®°æ¶é´ãå¼åå»å¸ãå¼åæ¥æãå¤èè¯ï¼é½å¨ appointment 表ã // // åç § QueueServiceImpl#fillAppointmentInfo çåæ³ï¼æ¥è¯¢åæ applyNo 忥é¢çº¦åè¡¥é½ã // è¿æ ·é¢ç¨/è£ æº/ææº/æ°æ®å½å ¥/æ£æ¥è®°å½ 5 个ç颿è½å±ç¤ºå®æ´æ£è ä¿¡æ¯ã /** * åå¡«åä¸ªå¯¹è±¡çæ£è ä¿¡æ¯ï¼å¯¹è±¡ä¸º null æ applyNo 为空æ¶å®å ¨è·³è¿ï¼ã */ private void fillPatientInfo(DevRentDO devRentDO) { if (null == devRentDO || !org.springframework.util.StringUtils.hasText(devRentDO.getApplyNo())) { return; } AppointmentDO appointment = appointmentMapper.getByApplyNo(devRentDO.getApplyNo()); if (null == appointment) { return; } applyAppointmentToDevRent(devRentDO, appointment); } /** * æ¹éåå¡«ï¼é¿å N+1 ä¹å¤çé¢å¤å¼éç±è°ç¨æ¹æ§å¶ï¼æ¤å¤éæ¡åæ¥ï¼ * ä¸ QueueServiceImpl#fillAppointmentInfo ä¿æä¸è´çåæ³ï¼ã */ private void fillPatientInfo(List<DevRentDO> devRentDOList) { if (null == devRentDOList || devRentDOList.isEmpty()) { return; } devRentDOList.forEach(this::fillPatientInfo); } /** * æé¢çº¦åä¸çæ£è ä¿¡æ¯å¤å¶å° dev_rent 对象ã * <p> * 注æï¼åªè¦ç**为空ç**å¹³éºå段ï¼ââä¸ï¼è¿éç´æ¥è¦çï¼ * è¿äºåæ®µåæ è®°ä¸º {@code @TableField(exist=false)}ï¼ä¸åä¸ååºï¼ * æ¬æ¬¡æ¥è¯¢è¿åçå°±æ¯ææ°æ°æ®ï¼ä¸åå¨"è¦çæç¨æ·åå½å ¥çå¼"çé£é©ã */ private void applyAppointmentToDevRent(DevRentDO target, AppointmentDO source) { target.setPatGender(source.getPatGender()); target.setPatBirthday(source.getPatBirthday()); target.setRegisterDate(source.getRegisterDate()); target.setDoctor(source.getDoctor()); target.setDoctorTime(source.getDoctorTime()); target.setPatSrc(source.getPatSrc()); target.setPatMobile(source.getPatMobile()); target.setPatPhone(source.getPatPhone()); target.setPatWardDesc(source.getPatWardDesc()); target.setPatBedNo(source.getPatBedNo()); target.setMedicalCard(source.getMedicalCard()); if (target.getDoctorAdviceNo() == null) target.setDoctorAdviceNo(source.getDoctorAdviceNo()); target.setOutpatientNo(source.getOutpatientNo()); target.setPatIdentityId(source.getPatIdentityId()); target.setTolerance(source.getTolerance()); } // 确费å¤ç jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/jobrecord/JobRecordServiceImpl.java
@@ -1,7 +1,10 @@ package cn.lihu.jh.module.ecg.service.jobrecord; import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.AppointmentRespVO; import cn.lihu.jh.module.ecg.dal.dataobject.appointment.AppointmentDO; import cn.lihu.jh.module.ecg.dal.dataobject.devrent.DevRentDO; import cn.lihu.jh.module.ecg.dal.dataobject.jobrecord.JobRecordStatisticDO; import cn.lihu.jh.module.ecg.dal.mysql.appointment.AppointmentMapper; import cn.lihu.jh.module.ecg.dal.mysql.devrent.DevRentMapper; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -38,6 +41,9 @@ @Resource private DevRentMapper devRentMapper; @Resource private AppointmentMapper appointmentMapper; @Override public Long createJobRecord(JobRecordSaveReqVO createReqVO) { // æå ¥ @@ -72,7 +78,11 @@ @Override public JobRecordDO getJobRecord(Long id) { return jobRecordMapper.selectById(id); JobRecordDO jobRecordDO = jobRecordMapper.selectById(id); if (null != jobRecordDO) { fillPatientInfo(java.util.Collections.singletonList(jobRecordDO)); } return jobRecordDO; } @Override @@ -86,11 +96,92 @@ for (int i = 0; i < jobRecordDOList.size(); i++) { jobRecordDOList.get(i).setPaid(paidInfoList.get(i)); } // éæ±1ï¼åå¡«æ£è ä¿¡æ¯ï¼æ¹éï¼é¿å N+1ï¼ fillPatientInfo(jobRecordDOList); } return pageResult; } // ==================== éæ±1ï¼åå¡«æ£è ä¿¡æ¯ 18 项 ==================== // åå¡«é¾è·¯ï¼ä¸çº§ï¼ï¼ // job_record.rentId â dev_rent.applyNo â appointment // 乿以ä¸ç¨éæ¡ getByApplyNoï¼job_record åè¡¨é¡µä¸æ¬¡å¯è½è¿åå åæ¡ï¼ // éæ¡æ¥ä¼å½¢æ N+1ãè¿éæ¹ä¸ºãæ¹éå dev_rentã+ãæ¹éå appointmentãã private void fillPatientInfo(List<JobRecordDO> jobRecordDOList) { if (null == jobRecordDOList || jobRecordDOList.isEmpty()) { return; } // 1) æ¹éå dev_rentï¼æ¿å° applyNo List<Long> rentIdList = jobRecordDOList.stream() .map(JobRecordDO::getRentId) .filter(java.util.Objects::nonNull) .distinct() .toList(); if (rentIdList.isEmpty()) { return; } Map<Long, String> applyNoByRentId = new HashMap<>(); // 䏿¬¡ IN æ¥è¯¢åå ¨é¨ applyNoï¼åå éæ¡ selectById â N 次æ¥è¯¢ï¼ List<DevRentDO> devRentDOList = devRentMapper.getApplyNoByIdList(rentIdList); if (null != devRentDOList) { devRentDOList.forEach(d -> { if (null != d && null != d.getId() && org.springframework.util.StringUtils.hasText(d.getApplyNo())) { applyNoByRentId.put(d.getId(), d.getApplyNo()); } }); } if (applyNoByRentId.isEmpty()) { return; } // 2) æ¹éå appointmentï¼ä¸æ¬¡ IN æ¥è¯¢ï¼ List<String> applyNoList = applyNoByRentId.values().stream().distinct().toList(); Map<String, AppointmentDO> appointmentByApplyNo = new HashMap<>(); List<AppointmentDO> appointmentDOList = appointmentMapper.getByApplyNoList(applyNoList); if (null != appointmentDOList) { appointmentDOList.forEach(a -> { if (null != a && org.springframework.util.StringUtils.hasText(a.getApplyNo())) { appointmentByApplyNo.put(a.getApplyNo(), a); } }); } // 3) åå¡« jobRecordDOList.forEach(jobRecordDO -> { if (null == jobRecordDO || null == jobRecordDO.getRentId()) { return; } String applyNo = applyNoByRentId.get(jobRecordDO.getRentId()); if (null == applyNo) { return; } AppointmentDO appointment = appointmentByApplyNo.get(applyNo); if (null == appointment) { return; } jobRecordDO.setApplyNo(applyNo); jobRecordDO.setEpisodeId(appointment.getEpisodeId()); jobRecordDO.setPatGender(appointment.getPatGender()); jobRecordDO.setPatBirthday(appointment.getPatBirthday()); jobRecordDO.setRegisterDate(appointment.getRegisterDate()); jobRecordDO.setDoctor(appointment.getDoctor()); jobRecordDO.setDoctorTime(appointment.getDoctorTime()); jobRecordDO.setPatSrc(appointment.getPatSrc()); jobRecordDO.setPatMobile(appointment.getPatMobile()); jobRecordDO.setPatPhone(appointment.getPatPhone()); jobRecordDO.setPatWardDesc(appointment.getPatWardDesc()); jobRecordDO.setPatBedNo(appointment.getPatBedNo()); jobRecordDO.setMedicalCard(appointment.getMedicalCard()); jobRecordDO.setDoctorAdviceNo(appointment.getDoctorAdviceNo()); jobRecordDO.setOutpatientNo(appointment.getOutpatientNo()); jobRecordDO.setPatIdentityId(appointment.getPatIdentityId()); jobRecordDO.setTolerance(appointment.getTolerance()); }); } @Override public List<JobRecordStatisticDO> getJobStatistic(LocalDateTime jobTimeFrom, LocalDateTime jobTimeTo) { jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/BedBO.java
@@ -29,6 +29,22 @@ Integer readyPatNum = 0; Integer maxReadyPatNum = 0; /** * ãéæ±3ã忢åè¯å¼å ³ã * <p> * true = è¯¥å·¥ä½æåæ¥æ¶**æ°ç**åè¯æ£è ï¼å·²æçåè¯æ£è ä»å¯æ£å¸¸å«å·ï¼ï¼ * false = æ£å¸¸æ¥æ¶ã * <p> * ä¸ {@code BedStatusEnum.DOCTOR_PAUSE} çåºå«ï¼å»ç"æå"èµ°çæ¯ * {@code updateStop}ï¼ä¼é¡ºææå°±è¯ä¸(30)强å¶å®æãå¹¶æåè¯ä¸(20)çè¡ * {@code room_id=0/bed_no=' '} è¸¢èµ°ï¼æ£è å空æ¶å¤±ï¼ï¼ä¸æ»¡è¶³ * "å·²æåè¯ç 人继ç»å«å·"çè¦æ±ï¼æ æ¬å¼å ³**ç¬ç«å®ç°**ï¼åªæ¦æªæ°å¢ã * <p> * è¯¥åæ®µé**è½åº**ï¼{@code clinic_room.stop_ready}ï¼ï¼å¦åæ¯æ¬¡ * {@code bedReload}ï¼å¼è¯/éå¯ï¼é½ä¼ä¸¢å¤±ã */ Boolean stopReady = false; @Override public int compareTo(@NotNull BedBO o) { return Integer.compare(this.readyPatNum, o.readyPatNum); jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueService.java
@@ -144,6 +144,45 @@ Integer recallInstallPatient(Long roomId, String bedNo, String patId, Integer checkType, Long roomId_operator, String bedNo_operator); // ==================== éæ±2ï¼æ¤éãå«å· / æ£æ¥å®æã ==================== /** * æ¤éãæ£æ¥å®æãï¼ææ¬å·¥ä½ä»æ¥çæå®æ£è ä» å·²å°±è¯(40) éå åè¯ä¸(20)ã * <p> * å¿ é¡»æä¾ patId + checkType å精确å®ä½ï¼é¿å 误æ¹å ¶ä»æ£è ã * * @return åå½±åè¡æ°ï¼0 è¡¨ç¤ºæªæ¾å°è¯¥æ£è 仿¥çå·²å®æè®°å½ */ Integer undoFinishPatient(Long roomId, String bedNo, String patId, Integer checkType); /** * æ¤éã误ç¹å«å·ãï¼ææ¬å·¥ä½å½å å°±è¯ä¸(30) çæ£è éå åè¯ä¸(20)ã * * @return åå½±åè¡æ°ï¼0 表示å½åæ å°±è¯ä¸æ£è */ Integer undoCallPatient(Long roomId, String bedNo); /** * 忬工ä½ä»æ¥**æè¿ä¸ä½å·²å®æ**çæ£è ï¼ä¾çé¢æç¤ºå¯æ¤é对象ï¼ã */ QueueDO getBedLastFinishedQueueItem(Long roomId, String bedNo); // ==================== éæ±3ï¼åæ¢åè¯å¼å ³ ==================== /** * 设置ã忢åè¯ãå¼å ³ï¼æä¹ åå° {@code clinic_room.stop_ready}ï¼ã * <p> * å¼å¯åï¼**å·²æåè¯ç 人继ç»å«å·ï¼ä½ä¸åæ°å¢åè¯ç 人**ï¼ * å ³é忢夿£å¸¸æ¥æ¶ã * * @param stop true=忢åè¯ï¼false=æ¢å¤ * @return æåè¿å SUCCESS */ ErrorCode setStopReady(Long roomId, String bedNo, boolean stop); /** æ¥è¯¢ã忢åè¯ãç¶æï¼å·¥ä½ä¸åå¨è¿å null */ Boolean getStopReady(Long roomId, String bedNo); Integer patientJump(String patId, Integer bookCheckType, Byte jumped ); List<RoomDO> getDocRoomInfo(Long docId); @@ -151,4 +190,20 @@ List<QueueDO> getCheckRelatedPatient(Long roomId, String bedNo); List<QueueDO> getInstallRelatedPatient(Long roomId, String bedNo); // ==================== éæ±1ï¼æ£è ä¿¡æ¯åå¡« ==================== /** * æ {@code applyNo} ä»é¢çº¦åï¼appointmentï¼åå¡«éåå¯¹è±¡çæ£è ä¿¡æ¯ã * <p> * queue 表åªåäºæ£è ç¼å·/å§åï¼å ¶ä½ï¼æ§å«ãåºçæ¥æãç åºãåºå·ãçµè¯ãæ¥æºã * å°±è¯å¡å·ãç»è®°æ¶é´ãå¼åå»å¸ãå¼åæ¥æãå¤èè¯ï¼é½å¨ appointment 表ã * <p> * 乿以坹夿´é²ï¼å¤§å±/è¯é´å±ï¼{@code CallingScreenServiceImpl}ï¼ç´æ¥æ¥ * {@code queueMapper}ï¼ä¸ç»è¿æ¬ Service çæ¥è¯¢æ¹æ³ï¼éè¦æ¾å¼è°ç¨æ¬æ¹æ³è¡¥é½ã * ä¸è¡¥é½å大å±/è¯é´å±çæ£è ä¿¡æ¯åªæå§åï¼æ§å«/ç åº/åºå·çå ¨ä¸ºç©ºï¼ã * * @param queueDOList éå对象å表ï¼ç©º/null å®å ¨ï¼ */ void fillAppointmentInfo(List<QueueDO> queueDOList); } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java
@@ -10,7 +10,9 @@ import cn.lihu.jh.module.ecg.dal.dataobject.checktype.CheckTypeDO; import cn.lihu.jh.module.ecg.dal.dataobject.devrent.DevRentDO; import cn.lihu.jh.module.ecg.dal.mysql.appointment.AppointmentMapper; import cn.lihu.jh.module.ecg.dal.mysql.checktype.CheckTypeMapper; import cn.lihu.jh.module.ecg.dal.mysql.devrent.DevRentMapper; import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.lihu.jh.module.ecg.enums.DevRentStateEnum; import cn.lihu.jh.module.system.api.oauth2.OAuth2TokenApi; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; @@ -66,6 +68,13 @@ @Resource private DevRentMapper devRentMapper; /** * ç¨äºã设å¤é¢ç¨/è£ æºãåæ°æ¶è¿æ»¤åº {@code need_dev_ready = 1} çæ£æ¥é¡¹ç® * ï¼è§ {@link #filterNeedDevReady}ï¼ã */ @Resource private CheckTypeMapper checkTypeMapper; ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); @@ -433,7 +442,8 @@ * queue 表ä¸åè¿äºå段ï¼ä½å»ç端å表æ¥å£éè¦å±ç¤ºï¼æä»¥æ¥è¯¢åæ applyNo 忥é¢çº¦åå¡«å ï¼ * å¤èè¯ãæ§å«ãåºçæ¥æãç»è®°æ¶é´ãå¼åå»å¸ãå¼åæ¥æã */ private void fillAppointmentInfo(List<QueueDO> queueDOList) { @Override public void fillAppointmentInfo(List<QueueDO> queueDOList) { if (CollectionUtils.isEmpty(queueDOList)) { return; } @@ -446,11 +456,26 @@ return; } queueDO.setTolerance(appointment.getTolerance()); // éæ±2ï¼åºè¾¹æ è®°ï¼HIS zdy.ISCBï¼ãqueue 表已æè¯¥åï¼ // ä½å¯¹ã22_* èæ¬æ§è¡åå°±å·²å ¥éãçè¡ï¼é è¿éåæ¥è¡¥å¡«ï¼ä¿è¯å±å¹/页é¢è½çå°ã if (queueDO.getIsBedside() == null) { queueDO.setIsBedside(appointment.getIsBedside()); } queueDO.setPatGender(appointment.getPatGender()); queueDO.setPatBirthday(appointment.getPatBirthday()); queueDO.setRegisterDate(appointment.getRegisterDate()); queueDO.setDoctor(appointment.getDoctor()); queueDO.setDoctorTime(appointment.getDoctorTime()); // éæ±1ï¼è¡¥å¹³éºçæ£è ä¿¡æ¯æ¥æºå段ï¼ç ååº/åºå·/çµè¯/æ¥æº/å°±è¯å¡å·çï¼ queueDO.setPatSrc(appointment.getPatSrc()); queueDO.setPatMobile(appointment.getPatMobile()); queueDO.setPatPhone(appointment.getPatPhone()); queueDO.setPatWardDesc(appointment.getPatWardDesc()); queueDO.setPatBedNo(appointment.getPatBedNo()); queueDO.setMedicalCard(appointment.getMedicalCard()); queueDO.setDoctorAdviceNo(appointment.getDoctorAdviceNo()); queueDO.setOutpatientNo(appointment.getOutpatientNo()); queueDO.setPatIdentityId(appointment.getPatIdentityId()); }); } @@ -471,18 +496,33 @@ patientStatisticVO.setReadyNum(item.getTotalInStatus()); } else if (QueueStatusEnum.FINISH.getStatus() == item.getStatus()) { patientStatisticVO.setFinishedNum(item.getTotalInStatus()); } else if (QueueStatusEnum.PASSED.getStatus() == item.getStatus()) { patientStatisticVO.setPassedNum(item.getTotalInStatus()); } else if (QueueStatusEnum.PASSED.getStatus() == item.getStatus() || QueueStatusEnum.PASSED_WAITING.getStatus() == item.getStatus()) { // ãéæ±4 å£å¾ç»ä¸ãè¿å· = å·²è¿å·(5) + å·²è¿å·-æé(3)ã // åå åªç® 5ï¼èå表ä¸å±å¹é½å« 3ï¼å¯¼è´"è¿å·"æ°åæ¯å®é å°ã int cur = patientStatisticVO.getPassedNum() == null ? 0 : patientStatisticVO.getPassedNum(); patientStatisticVO.setPassedNum(cur + item.getTotalInStatus()); } }); // ç»è®¡ 该工ä½ç±»åçãæéä¸ãäººåæ°é // ãQ7 ç¡®è®¤ãæ¤å¤å»æç»è®¡**å ¨é¡¹ç®**ï¼è¯¥å·¥ä½æå«æ£æ¥ç±»åï¼ç"æéä¸"æ»æ°ï¼ // è¯ä¹ä¸º"å ¨é¢è¿æå¤å°äººççåè¿ç±»æ£æ¥"ï¼ä¸"æ¬å·¥ä½ä¸ç¼å¯è§çåè¯äººæ°"äºè¡¥ã // ä¸å·²è¡¥ deleted=0 / book_date=仿¥ï¼è§ QueueMapper.checkTypeAndStatusStatisticï¼ã RoomDO roomDO = getRoomDO(roomId, bedNo); Integer[] checkTypes = roomDO.getCheckTypes(); List<Integer> statusList = new ArrayList<>(); statusList.add(QueueStatusEnum.WAITING.getStatus()); Integer num = queueMapper.checkTypeAndStatusStatistic(checkTypes, statusList); patientStatisticVO.setQueuingNum(num); int queuingNum = 0; // ãé²å¾¡ãcheckTypes 为空æ¶ä¸è½æ¼ `book_check_type in ()`ï¼MySQL è¯æ³é误ï¼ã // 宿µè¯¥åºæ¯ä¼è®©ç»è®¡æ¥å£ 500ï¼è¿è导è´å»ç端顶é¨ç»è®¡æ´åæ¥éã if (checkTypes != null && checkTypes.length > 0) { List<Integer> statusList = new ArrayList<>(); statusList.add(QueueStatusEnum.WAITING.getStatus()); Integer num = queueMapper.checkTypeAndStatusStatistic(checkTypes, statusList); queuingNum = num == null ? 0 : num; } else { log.warn("[getPatientStatistic][工使ªé ç½®æ£æ¥ç±»åï¼æé䏿 0 计] roomId={} bedNo={}", roomId, bedNo); } patientStatisticVO.setQueuingNum(queuingNum); return patientStatisticVO; } @@ -524,8 +564,19 @@ bedQueueStatisticDOList.forEach(item -> { if (QueueStatusEnum.READY.getStatus() == item.getStatus()) { patientStatisticVO.setReadyNum(item.getTotalInStatus()); } else if (QueueStatusEnum.PASSED.getStatus() == item.getStatus()) { patientStatisticVO.setPassedNum(item.getTotalInStatus()); } else if (QueueStatusEnum.PASSED.getStatus() == item.getStatus() || QueueStatusEnum.PASSED_WAITING.getStatus() == item.getStatus()) { // ãéæ±4 å£å¾ç»ä¸ãè¿å· = å·²è¿å·(5) + å·²è¿å·-æé(3)ã // // ä¸ getPatientStatistic ä¿æåä¸å£å¾ãåå®ç°åªå¤ PASSED(5)ï¼ // èé¢ç¨çé¢çå表/å±å¹é½å« status=3ï¼å¯¼è´ãè¿å·ãæ°åæ¯å®é å° // ââ è¿æ£æ¯ç¨æ·åé¦çãç»è®¡ä¸å®é ä¸ç¬¦ãã // // å¦ï¼åå®ç°ç¨ setPassedNum(item.getTotalInStatus())ï¼**è¦ç**èéç´¯å ï¼ï¼ // å SQL æ¯ group by statusï¼status=3 ä¸ status=5 æ¯ä¸¤è¡ï¼ // è¦çä¼åªä¿çæåä¸è¡ â æ¹ä¸ºç´¯å ã int cur = patientStatisticVO.getPassedNum() == null ? 0 : patientStatisticVO.getPassedNum(); patientStatisticVO.setPassedNum(cur + item.getTotalInStatus()); } }); @@ -545,10 +596,17 @@ // ç»è®¡ 该工ä½ç±»åçãæéä¸ãäººåæ°é RoomDO roomDO = getRoomDO(roomId, bedNo); Integer[] checkTypes = roomDO.getCheckTypes(); List<Integer> statusList = new ArrayList<>(); statusList.add(QueueStatusEnum.WAITING.getStatus()); Integer num = queueMapper.checkTypeAndStatusStatistic(checkTypes, statusList); patientStatisticVO.setQueuingNum(num); Integer num = 0; // ãé²å¾¡ãcheckTypes 为空æ¶ä¸è½æ¼ `book_check_type in ()`ï¼MySQL è¯æ³é误ï¼ï¼ // 宿µè¯¥åºæ¯ä¼è®©ç»è®¡æ¥å£ 500ãå»ç端顶é¨ç»è®¡æ´åæ¥éãä¸ getPatientStatistic ä¿æä¸è´ã if (checkTypes != null && checkTypes.length > 0) { List<Integer> statusList = new ArrayList<>(); statusList.add(QueueStatusEnum.WAITING.getStatus()); num = queueMapper.checkTypeAndStatusStatistic(checkTypes, statusList); } else { log.warn("[getBedDevReadyStatistic][工使ªé ç½®æ£æ¥ç±»åï¼æé䏿 0 计] roomId={} bedNo={}", roomId, bedNo); } patientStatisticVO.setQueuingNum(num == null ? 0 : num); return patientStatisticVO; } @@ -578,6 +636,73 @@ startHurryUpOneBed(roomId, bedNo); return updateNum; } // ==================== éæ±2ï¼æ¤éãå«å· / æ£æ¥å®æã ==================== /** * æ¤éãæ£æ¥å®æãï¼ææ¬å·¥ä½ä»æ¥çæå®æ£è ä» å·²å°±è¯(40) éå **åè¯ä¸(20)**ã * <p> * <b>Q9 确认</b>ï¼æ¤éååå°**åè¯åº**ï¼èé"å°±è¯ä¸"ï¼ï¼ä¾¿äºå»çéæ°å«å·ã * <p> * æ¶å°¾å¿ é¡»è° {@link #startHurryUpOneBed}ï¼å®ä¼éæ°è®¡ç®è¯¥å·¥ä½ç * {@code readyPatNum} å¹¶å·æ°åæµéåä¼å 级ãè¥ä¸åæ¥å å计æ°ï¼ * {@code hurryupOneCheckType} ä¼æåº {@code exceed max queue number}ã * * @return åå½±åè¡æ°ï¼0 表示没æ¾å°è¯¥æ£è 仿¥çå·²å®æè®°å½ï¼ */ @Override public Integer undoFinishPatient(Long roomId, String bedNo, String patId, Integer checkType) { Integer updateNum = queueMapper.undoFinishPatient(roomId, bedNo, patId, checkType, QueueStatusEnum.FINISH.getStatus(), QueueStatusEnum.READY.getStatus()); if (null != updateNum && updateNum > 0) { startHurryUpOneBed(roomId, bedNo); } return updateNum; } /** * æ¤éã误ç¹å«å·ãï¼ææ¬å·¥ä½å½å å°±è¯ä¸(30) çæ£è éå **åè¯ä¸(20)**ã * * @return åå½±åè¡æ°ï¼0 表示å½å没æå°±è¯ä¸çæ£è ï¼ */ @Override public Integer undoCallPatient(Long roomId, String bedNo) { Integer updateNum = queueMapper.undoCallPatient(roomId, bedNo, QueueStatusEnum.ONSTAGE.getStatus(), QueueStatusEnum.READY.getStatus()); if (null != updateNum && updateNum > 0) { startHurryUpOneBed(roomId, bedNo); } return updateNum; } @Override public QueueDO getBedLastFinishedQueueItem(Long roomId, String bedNo) { return queueMapper.getBedLastFinishedQueueItem(roomId, bedNo, QueueStatusEnum.FINISH.getStatus()); } // ==================== éæ±3ï¼åæ¢åè¯å¼å ³ ==================== @Override public ErrorCode setStopReady(Long roomId, String bedNo, boolean stop) { // èµ°åçº¿ç¨æ§è¡å¨ï¼ä¸ bedDoctorPause/Resume ä¿æä¸è´ç串è¡åå¤çï¼ // é¿å ä¸åæµéåçå¹¶åä¿®æ¹å²çªã Future<ErrorCode> future = singleThreadExecutor.submit( () -> queueServiceTxFunctions.setStopReady(roomId, bedNo, stop)); try { return future.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error("[setStopReady] è¢«ä¸æ roomId={} bedNo={}", roomId, bedNo, e); } catch (ExecutionException e) { log.error("[setStopReady] æ§è¡å¼å¸¸ roomId={} bedNo={}", roomId, bedNo, e); } return ECG_INNER_ERROR; } @Override public Boolean getStopReady(Long roomId, String bedNo) { return queueServiceTxFunctions.getStopReady(roomId, bedNo); } @Override @@ -632,6 +757,10 @@ queueStatusList.add(QueueStatusEnum.READY.getStatus()); queueStatusList.add(QueueStatusEnum.ONSTAGE.getStatus()); queueStatusList.add(QueueStatusEnum.PASSED.getStatus()); // ãéæ±4 å£å¾ç»ä¸ãè¡¥ä¸ PASSED_WAITING(3)ãå·²è¿å·-æéãã // åå å表åªå« 5ï¼è大å±/è¯é´å±æ¥è¯¢å« 3ï¼å¯¼è´å䏿£è å¨ä¸åçé¢åºç°ä¸å¦ä¸ä¸è´ï¼ // ç»è®¡ä¾§ä¹å° 3 è®¡å ¥"è¿å·"ï¼è§ getPatientStatistic / getBedDevReadyStatisticï¼ã queueStatusList.add(QueueStatusEnum.PASSED_WAITING.getStatus()); queueStatusList.add(QueueStatusEnum.AFFINITY.getStatus()); List<QueueDO> queueDOList = getBedQueueByStatus(roomId, bedNo, queueStatusList); @@ -677,9 +806,31 @@ queueStatusList.add(QueueStatusEnum.INSTALLING.getStatus()); queueDOList.addAll(0, getBedQueueByStatus(roomId, bedNo, queueStatusList)); // å½åå·¥ä½ç // ====================================================================== // ãä¿®å¤ãåªä¿çãéè¦è®¾å¤é¢ç¨ãçæ£æ¥é¡¹ç®ã // // èæ¯ï¼ä¸é¢ä¸¤å¤æ¥è¯¢çæ¡ä»¶æ¯ `room_id = ? AND status IN (...)` // ï¼getRoomQueueByStatus çè³**ä¸å« bed_no**ï¼ï¼**å®å ¨ä¸ç book_check_type**ã // èèªå¨åæµï¼preemptWaitingPatientWithBedCheckTypesï¼æ¯**æå·¥ä½ checkTypes è¿æ»¤**çï¼ // æä»¥åªæ"äººå·¥ææ£è æè¿æ¥"è¿æ¡è·¯å¾ä¼æ¼ ââ 表ç°ä¸º // ã设å¤é¢ç¨ã页é误åºç°å¸¸è§å¿çµå¾(100)ãå¹³æ¿è¿å¨å¿çµ(400)ç**ä¸éé¢ç¨è®¾å¤**çæ£è ã // // å¤å®ä¾æ®ç¨é ç½® `check_type.need_dev_ready`ï¼ // 1 = éè¦è®¾å¤é¢ç¨ï¼å¦ 卿å¿çµ 200ã卿è¡å 300ï¼ // 0 = ä¸éè¦ï¼å¸¸è§å¿çµå¾ãå¹³æ¿è¿å¨å¿çµ â¦ï¼ // // æ¾å¨æå¡å±è䏿¯æ¹ SQLï¼ä¸æ¬¡æ¥è¯¢å¾å°éååå¨å åè¿æ»¤ï¼é»è¾éä¸ãæè¯»ï¼ // ä¸ä¸éè¦ä¸ºå¤æ°æ®æº/å¨æè¡¨åé¢å¤è°æ´ SQLãæ¬è¯å®¤å¾ å®è£ æ£è é级å¾å°ï¼å åè¡ï¼ã // ====================================================================== queueDOList = filterNeedDevReady(queueDOList); // 注æï¼ä¸é¢ç¨ lambdaï¼æè·çåéå¿ é¡»æ¯ effectively finalï¼ // æ è¿éå¦èµ·ä¸ä¸ª final åéï¼è䏿¯å¤ç¨ä¸é¢ç queueDOListï¼å®å·²è¢«éæ°èµå¼ï¼ã final List<QueueDO> installQueueList = queueDOList; //æ [亲åç] æªå°ä¸»é¡¹åé¢ List<QueueDO> affinityReceivedList = new ArrayList<>(); ListIterator<QueueDO> iterator = queueDOList.listIterator(); ListIterator<QueueDO> iterator = installQueueList.listIterator(); while (iterator.hasNext()) { QueueDO item = iterator.next(); if (item.getStatus() == QueueStatusEnum.AFFINITY_INSTALL.getStatus()) { @@ -688,15 +839,52 @@ } } affinityReceivedList.forEach(affinityReceivedItem -> { for (int i = queueDOList.size() - 1; i >= 0; i--) { if (affinityReceivedItem.getSeqNum() == queueDOList.get(i).getSeqNum()) { queueDOList.add(i + 1, affinityReceivedItem); for (int i = installQueueList.size() - 1; i >= 0; i--) { if (affinityReceivedItem.getSeqNum() == installQueueList.get(i).getSeqNum()) { installQueueList.add(i + 1, affinityReceivedItem); break; } } }); return queueDOList; return installQueueList; } /** * åªä¿çãéè¦è®¾å¤é¢ç¨ãï¼{@code check_type.need_dev_ready = 1}ï¼çæ£æ¥é¡¹ç®çæ£è ã * * <p>ç¨äºã设å¤é¢ç¨ / è£ æºãåæ°ï¼è¿äºå·¥ä½åªåºå¤çéè¦é¢ç¨è®¾å¤çæ£æ¥é¡¹ç®ï¼ * å¦åä¼åºç°å¸¸è§å¿çµå¾çæ£è æ··å ¥è®¾å¤æµç¨ã * * <p>é ç½®å¼å¸¸ï¼æ¥ä¸å°æ£æ¥é¡¹ç®ï¼æ¶**è¿ååå表**ï¼å®å¯å¤æ¾ç¤ºä¹ä¸è¦ææ£è "èèµ·æ¥"ã */ private List<QueueDO> filterNeedDevReady(List<QueueDO> queueDOList) { if (null == queueDOList || queueDOList.isEmpty()) { return queueDOList; } List<CheckTypeDO> needDevList = checkTypeMapper.selectList( new LambdaQueryWrapperX<CheckTypeDO>().eq(CheckTypeDO::getNeedDevReady, 1)); if (null == needDevList || needDevList.isEmpty()) { log.warn("[filterNeedDevReady] æªé 置任ä½[éè¦è®¾å¤é¢ç¨]çæ£æ¥é¡¹ç®ï¼è·³è¿è¿æ»¤ä»¥å æ£è å ¨é¨ä¸å¯è§"); return queueDOList; } Set<Integer> needDevCheckTypes = new HashSet<>(); needDevList.forEach(ct -> { if (null != ct.getValue()) { needDevCheckTypes.add(ct.getValue()); } }); List<QueueDO> filtered = new ArrayList<>(); for (QueueDO item : queueDOList) { if (needDevCheckTypes.contains(item.getBookCheckType())) { filtered.add(item); } else { log.info("[filterNeedDevReady] è¿æ»¤æä¸éè¦è®¾å¤é¢ç¨çæ£è . patId={} æ£æ¥é¡¹ç®={} ç¶æ={}", item.getPatId(), item.getBookCheckType(), item.getStatus()); } } return filtered; } private RoomDO getRoomDO(Long roomId, String bedNo) { jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceTxFunctions.java
@@ -194,6 +194,67 @@ return GlobalErrorCodeConstants.SUCCESS; } // ==================== éæ±3ï¼åæ¢åè¯å¼å ³ ==================== /** * 设置ã忢åè¯ãå¼å ³ã * <p> * {@code stop=true}ï¼è¯¥å·¥ä½**ä¸åæ°å¢**åè¯æ£è ï¼ç§»åºåæµéåï¼ï¼ * ä½**å·²æåè¯æ£è ä»å¯æ£å¸¸å«å·**ï¼{@code nextPatient} 䏿£æ¥æ¤å¼å ³ï¼ã * <p> * {@code stop=false}ï¼æ¢å¤æ£å¸¸ï¼éæ°å å ¥åæµéåå¼å§æ¥æ¶æ£è * ï¼åææ¯å·¥ä½ç¶æä¸º"å»çå¨åº§"ï¼ä¸ {@code bedReload} çå¤å®ä¸è´ï¼ã * <p> * ç¶æåå ¥ {@code clinic_room.stop_ready}ï¼ä»¥å¨ {@code bedReload} åä¿æã * * @return æåè¿å SUCCESSï¼å·¥ä½ä¸åå¨è¿å {@link #QUEUE_BED_NOT_EXIST} */ public ErrorCode setStopReady(Long roomId, String bedNo, boolean stop) { BedBO bedBO = mapOpeningBed.get( Utils.formatRoomBed(roomId, bedNo) ); if (null == bedBO) { log.error("[setStopReady] å·¥ä½ä¸åå¨. roomId={} bedNo={}", roomId, bedNo); return QUEUE_BED_NOT_EXIST; } // å è½åºï¼å¤±è´¥å䏿¹å åï¼é¿å ç¶æä¸ä¸è´ï¼ // // ãé¨ç½²ä¿æ¤ãè¥æ°æ®åºå°æªæ§è¡åçº§èæ¬ï¼ç¼º clinic_room.stop_ready åï¼ï¼ // roomMapper.setBedStopReady(...) ä¼å¨ Mapper å±ç´æ¥æ SQL å¼å¸¸ // ï¼@Update æ³¨è§£æ¹æ³æ²¡æè¿åå¼å¯å¤æï¼å¼å¸¸ç´æ¥å泡ï¼ã // è¿éæ¾å¼æè·å¹¶è½¬ææç¡®çä¸å¡é误ç ï¼é¿å æåå§ SQL é误æ´é²ç»åç«¯ï¼ // 便äºç°åºä¸ç¼çåºæ¯"é¨ç½²éæ¼"è䏿¯"åè½åäº"ã Integer updateNum; try { updateNum = roomMapper.setBedStopReady(roomId, bedNo, stop ? 1 : 0); } catch (Exception e) { log.error("[setStopReady] ååºå¤±è´¥ï¼è¯·ç¡®è®¤å·²æ§è¡ _prep/11_éæ±å级_æ±æ»SQL.sql" + "ï¼clinic_room.stop_readyï¼. roomId={} bedNo={}", roomId, bedNo, e); return QUEUE_STOP_READY_NOT_CONFIGURED; } if (null == updateNum || 0 == updateNum) { // å·¥ä½å¯è½å°æªå¨ clinic_room ç»è®°ï¼ä» åè¦ä½ä»å 许æ¹å åï¼ // 以å å DB è®°å½ç¼ºå¤±å¯¼è´å»çå®å ¨æ æ³ä½¿ç¨è¯¥åè½ã log.warn("[setStopReady] DB æªæ´æ°å°è¡ï¼ä» æ´æ°å å. roomId={} bedNo={} stop={}", roomId, bedNo, stop); } bedBO.setStopReady(stop); // 忥念éåï¼åæ¢ â ç§»åºï¼æ¢å¤ â å å ¥ï¼ä» å¨å»çå¨åº§æ¶ï¼ if (stop) { removeBedFromRoutingQueue(bedBO); } else if (BedStatusEnum.DOCTOR_ON.getStatus().equals(bedBO.getStatus())) { addBedToRoutingQueue(bedBO); } log.info("[setStopReady] roomId={} bedNo={} stopReady={}", roomId, bedNo, stop); return GlobalErrorCodeConstants.SUCCESS; } /** æ¥è¯¢å½åã忢åè¯ãç¶æï¼å·¥ä½ä¸åå¨è¿å nullï¼ */ public Boolean getStopReady(Long roomId, String bedNo) { BedBO bedBO = mapOpeningBed.get( Utils.formatRoomBed(roomId, bedNo) ); return null == bedBO ? null : Boolean.TRUE.equals(bedBO.getStopReady()); } public ErrorCode bedDoctorOn(Long roomId, String bedNo, Long docId, String docName) { BedBO bedBO = mapOpeningBed.get( Utils.formatRoomBed(roomId, bedNo) ); if (null == bedBO) { @@ -325,7 +386,12 @@ bedBOList.forEach(item -> { mapOpeningBed.put( Utils.formatRoomBed(item.roomId, item.bedNo), item); if (BedStatusEnum.DOCTOR_ON.getStatus() == item.getStatus()) { // ãéæ±3ãã忢åè¯ãçå·¥ä½ä¸å å ¥åæµéå ââ ä¸å»çå¨åº§(status=DOCTOR_ON)åæ ·å¤å®ï¼ // å¦åæ¯æ¬¡ bedReloadï¼å¼è¯/éå¯/è¯å®¤éç½®ï¼åå¼å ³ä¼å¤±æãåå¼å§æ¶ç 人ã // 注æï¼stopReady ä» é»æ¢**æ°å¢**åè¯æ£è ï¼å·²æåè¯æ£è ä»å¯æ£å¸¸å«å· // ï¼nextPatient 䏿£æ¥è¯¥å¼å ³ï¼ã if (BedStatusEnum.DOCTOR_ON.getStatus() == item.getStatus() && !Boolean.TRUE.equals(item.getStopReady())) { addBedToRoutingQueue(item); } }); @@ -367,8 +433,13 @@ BedBO bedBO = getBedQueueBO(roomId, bedNo); // ãéæ±3ãã忢åè¯ãæ¶ä¸åæãå·²å¬åãæ£è æ¾å ¥åè¯åºã // 注æï¼è¿**ä¸å½±å**å·²æåè¯æ£è 被æ£å¸¸å«å·ï¼nextPatient 䏿£æ¥æ¬å¼å ³ï¼ï¼ // ä¹ä¸å½±åå»çå¯¹å ·ä½æ£è ç"å¬å"æä½æ¬èº«ï¼åªå½±åå ¶èªå¨è¿å ¥åè¯çè¡¥ä½ï¼ã boolean stopReady = Boolean.TRUE.equals(bedBO.getStopReady()); // å¤ç è¿å·-忥 ç人 while (bedBO.getReadyPatNum() < bedBO.getMaxReadyPatNum()) { while (!stopReady && bedBO.getReadyPatNum() < bedBO.getMaxReadyPatNum()) { // æ¥ç å½åå·¥ä½ æ¯å¦æè¿å·-åæ¥çæ£è Integer updateNum = queueMapper.queueRecalledPatient( bedBO.getRoomId(), @@ -410,6 +481,12 @@ */ public void hurryupOneCheckType(Integer checkType) { // ãä¿®å¤æ¢æç¼ºé·ãè¡¥ä¸å¼è¯é¨é¸ãåå®ç°**å¯ç¬è¿éæ¼äº** openingFlag æ£æ¥ // ï¼hurryupAllBed ä¸ hurryupOneBed 齿ï¼ï¼å¯¼è´æå¨"éè¯"åï¼ // åªè¦æäººé¢çº¦ç¡®è®¤ / å æ¥ï¼æ£è ä»ä¼è¢«æ¨è¿åè¯åºã if (0 == openingFlag.get()) return; PriorityBlockingQueue<BedBO> routingQueue = mapCheckTypeRoutingQueue.get(checkType); if (null == routingQueue) return; @@ -418,6 +495,18 @@ BedBO bedBO = routingQueue.peek(); if (null == bedBO) return; // ãéæ±3ãè·³è¿å¤äºã忢åè¯ãçå·¥ä½ã // ä¸è½ç´æ¥ return ââ 该éåæ readyPatNum ååº peekï¼ // ç´æ¥ return ä¼è®©å ¶ä½å·¥ä½ä¹æ¶ä¸å°æ£è ï¼é¥¿æ»ï¼ã // è¿é poll åºæ¥åè¥å½ä¸åæ¢æï¼ä» å°å ¶ä»éåç§»é¤ï¼ä¸å offer åå»ï¼ï¼ // ç¶å continue å¤çä¸ä¸ä¸ªå·¥ä½ã if (Boolean.TRUE.equals(bedBO.getStopReady())) { routingQueue.poll(); log.info("[hurryupOneCheckType] å·¥ä½[忢åè¯]ï¼ç§»åºåæµéå. roomId={} bedNo={}", bedBO.getRoomId(), bedBO.getBedNo()); continue; } int curQueueNum = bedBO.getReadyPatNum(); if (curQueueNum > bedBO.getMaxReadyPatNum()) @@ -495,6 +584,11 @@ } private void hurryupOneBedCheckTypeList(BedBO bedBO) { // ãéæ±3ãã忢åè¯ãçå·¥ä½ä¸åæ°å¢åè¯æ£è ã // å·²æåè¯æ£è ä»å¯æ£å¸¸å«å·ï¼æ¬æ¹æ³åªè´è´£"è¡¥é½åè¯"ï¼ä¸åä¸å«å·ï¼ã if (Boolean.TRUE.equals(bedBO.getStopReady())) { return; } while (bedBO.getReadyPatNum() < bedBO.getMaxReadyPatNum()) { // æ¢å æ¯å¦ææéä¸çæ£è Integer updateNum = queueMapper.preemptWaitingPatientWithBedCheckTypes( @@ -575,6 +669,18 @@ if (Objects.equals(BedOpTypeEnum.OP_INSTALL.getOpType(), bedBO.getOpType())) return; // ãéæ±3ãã忢åè¯ãçå·¥ä½ä¸è¿åæµéåã // è¿æ¯**å¯ä¸å ¥å£**çç»ä¸é¨é¸ï¼åªè¦å·¥ä½è¢«æ è®°ä¸ºåæ¢åè¯ï¼ // æ 论ä»åªæ¡è·¯å¾ï¼å¼è¯ addBedToRoutingQueueãå»çæ¢å¤ãbedReloadã // ææå¨æ¢å¤å¼å ³ï¼è¯å¾å å ¥ï¼é½ä¼è¢«æç»ï¼ä»èä¿è¯ï¼ // · å·²æåè¯æ£è ä»å¯æ£å¸¸å«å·ï¼nextPatient 䏿£æ¥è¯¥å¼å ³ï¼ // · ä½ä¸ä¼å被åé ãæéä¸ãçæ°æ£è if (Boolean.TRUE.equals(bedBO.getStopReady())) { log.info("[addBedToRoutingQueue] å·¥ä½å¤äº[忢åè¯]ï¼è·³è¿å å ¥åæµéå. roomId={} bedNo={}", bedBO.getRoomId(), bedBO.getBedNo()); return; } // 忥DB, 设置工ä½çåæµæ§å¶ä¿¡æ¯ List<Integer> queueStatusList = new ArrayList<>(); queueStatusList.add(QueueStatusEnum.READY.getStatus()); //[åè¯ä¸] jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceService.java
@@ -66,5 +66,25 @@ Integer distributeSeqNo(Integer checkType, Integer timeslot); Integer distributeVipSeqNo(Integer checkType, Integer timeslot); /** * æãæ£æ¥ç±»åé ç½®çè§åãåé æéåºå·ï¼ç¾å°æ¶è°ç¨ï¼ã * * <p>è§åæ¥èª {@code check_type.seq_rule}ï¼åå¼è§ * {@link cn.lihu.jh.module.ecg.enums.SeqRuleEnum}ï¼ * <ul> * <li>{@code 0=é¢çº¦å·} ââ ç´æ¥ç¨é¢çº¦ç³»ç»å·²ä¸åçå·ï¼{@code existingSeqNo}ï¼ï¼ä¸ååé ï¼</li> * <li>{@code 1=ç¾å°åºå·} ââ å½å¤©åæ£æ¥ç±»åå è¿ç»éå¢ï¼æ¯ 9 个å·é¢ç 1 个ç»å æ¥ï¼</li> * <li>{@code 2=æ¶æ®µå·} ââ æé¢çº¦æ¶æ®µä»å·æ± åå·ï¼æ¹é åçåæè¡ä¸ºï¼ä¹æ¯æªé ç½®æ¶çé»è®¤ï¼ã</li> * </ul> * * @param checkType æ£æ¥ç±»åå¼ï¼{@code check_type.value}ï¼ * @param timeslot HIS ä¸åçé¢çº¦æ¶æ®µï¼ä» è§å 2 使ç¨ï¼ * @param existingSeqNo é¢çº¦ç³»ç»å·²ä¸åçå·ï¼ä» è§å 0 使ç¨ï¼ä¸º null æ¶åéå°ç¾å°åºå·è§åï¼ * @param urgent æ¯å¦å æ¥ï¼{@code jjbz=J}ï¼ââ ä» è§å 1 使ç¨ï¼å æ¥å¯å ç¨é¢çå· * @return åé ç»è¯¥æ£è çæéåºå·ï¼ä» 1 å¼å§ï¼ */ Integer distributeSeqNoByRule(Integer checkType, Integer timeslot, Integer existingSeqNo, boolean urgent); void initNumber(); } jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceServiceImpl.java
@@ -2,14 +2,18 @@ import cn.lihu.jh.module.ecg.Utils; import cn.lihu.jh.module.ecg.dal.dataobject.checktype.CheckTypeDO; import cn.lihu.jh.module.ecg.dal.dataobject.queuesequence.SeqCounterDO; import cn.lihu.jh.module.ecg.dal.mysql.checktype.CheckTypeMapper; import cn.lihu.jh.module.ecg.enums.SeqRuleEnum; import cn.lihu.jh.module.infra.api.config.ConfigApi; import cn.lihu.jh.module.system.api.dict.DictDataApi; import cn.lihu.jh.module.system.api.dict.dto.DictDataRespDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.time.LocalTime; import java.util.*; import cn.lihu.jh.module.ecg.controller.admin.queuesequence.vo.*; @@ -17,6 +21,7 @@ import cn.lihu.jh.framework.common.pojo.PageResult; import cn.lihu.jh.framework.common.pojo.PageParam; import cn.lihu.jh.framework.common.util.object.BeanUtils; import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.lihu.jh.module.ecg.dal.mysql.queuesequence.QueueSequenceMapper; @@ -33,7 +38,16 @@ */ @Service @Validated @Slf4j public class QueueSequenceServiceImpl implements QueueSequenceService { /** * å忥æ¾å¯ç¨æ¶æ®µçæå¤§æ¥æ°ï¼çº¦ 3 å°æ¶ï¼ã * <p> * å 6 çåå ï¼åå ¸æ¶æ®µä¸º 30 åéç²åº¦ï¼6 个约 3 å°æ¶ï¼ * æ¢è½è·¨è¿"å°æ°æ¶æ®µç¼ºå¤±/已满"çæ åµï¼åä¸ä¼æä¸åçæ£è æå°ä¸åé æä½éªé®é¢ã */ private static final int MAX_TIMESLOT_LOOKAHEAD = 6; @Resource private ConfigApi configApi; @@ -47,6 +61,23 @@ @Resource private CheckTypeMapper checkTypeMapper; /** * ç¨äºæã计æ°å¨æ¨è¿ + 读åãæ¾å¼å è¿**åä¸ä¸ªäºå¡**ã * * <h4>为ä»ä¹å¿ é¡»ç¨ TransactionTemplate è䏿¯ @Transactionalï¼éè¦ï¼</h4> * è¿ä¸¤æ¥å¨ {@link #nextCheckInSeqNo} è¿ä¸ª **private æ¹æ³**éï¼ä¸ç±**åç±»å é¨è°ç¨** * ï¼{@code distributeSeqNoByRule} â {@code nextCheckInSeqNo}ï¼ã * Spring ç {@code @Transactional} åºäºä»£çï¼**åç±»èªè°ç¨ä¸ä¼èµ°ä»£ç â æ³¨è§£å®å ¨ä¸çæ**ã * äºæ¯"æ¨è¿"ä¸"读å"ä¼åèªç¬ç«æäº¤ï¼å¨ REPEATABLE READ ä¸è¯»å°çå¯è½æ¯æ§å¿«ç § * â **å¹¶åéå·**ï¼æ©å 宿µï¼ç¬ç«äºå¡åªæ 75/160 个å¯ä¸å¼ï¼åäºå¡ä¸º 160/160ï¼ã * * æ è¿éç¨ {@link TransactionTemplate} **æ¾å¼**å¼å¯äºå¡ï¼ä¸ä¾èµ AOP 代çï¼å¿ ç¶çæã * ä¼ æè¡ä¸ºç¨é»è®¤ç REQUIREDï¼å¤å±å·²æäºå¡ï¼å¦ {@code distributeSeqNoByRule} * æ æ³¨äº {@code @Transactional}ï¼æ¶å¹¶å ¥ï¼æ²¡ææ¶æ°å»ºã */ @Resource private org.springframework.transaction.support.TransactionTemplate counterTransactionTemplate; @Override public void initQueueSequenceTable() { queueSequenceMapper.clearQueueSequenceTableNotCurrent(); @@ -56,8 +87,17 @@ } } /** * æ°å¢é¢çº¦æ¶æ®µè§åã * * <p>æ ¡éªãå䏿£æ¥ç±»å + å䏿¶æ®µãä¸éå¤ ââ è¡¨ä¸æ²¡æè¯¥å¯ä¸çº¦æï¼åå²éçï¼ï¼ * èåå· SQL {@code select queue_no ... where check_type=? and time_slot=? for update} * ææåªå½ä¸ä¸è¡ï¼ä¸æ¦åºç°éå¤è¡ï¼åå·ä¼å½ä¸ä¸ç¡®å®çä¸è¡ã * è¿éå¨ç»´æ¤å ¥å£å¤æ¦æªï¼ç»åºæç¡®æç¤ºè䏿¯è®©é®é¢è¿å ¥åå·é¶æ®µã */ @Override public Integer createQueueSequence(QueueSequenceSaveReqVO createReqVO) { validateTimeslotNotDuplicated(createReqVO.getCheckType(), createReqVO.getTimeSlot(), null); // æå ¥ QueueSequenceDO queueSequence = BeanUtils.toBean(createReqVO, QueueSequenceDO.class); queueSequenceMapper.insert(queueSequence); @@ -69,9 +109,32 @@ public void updateQueueSequence(QueueSequenceSaveReqVO updateReqVO) { // æ ¡éªåå¨ validateQueueSequenceExists(updateReqVO.getId()); // ãæ ¡éªãæ¹äº checkType æ timeSlot æ¶ä¸è½ä¸å ¶å®è¡æè½¦ï¼æé¤èªèº«ï¼ validateTimeslotNotDuplicated(updateReqVO.getCheckType(), updateReqVO.getTimeSlot(), updateReqVO.getId()); // æ´æ° QueueSequenceDO updateObj = BeanUtils.toBean(updateReqVO, QueueSequenceDO.class); queueSequenceMapper.updateById(updateObj); } /** * æ ¡éªãæ£æ¥ç±»å + æ¶æ®µãå¨è¡¨ä¸å¯ä¸ã * * @param excludeId éæé¤çè¡ idï¼æ´æ°æ¶ä¼ èªèº« idï¼æ°å¢æ¶ä¼ nullï¼ */ private void validateTimeslotNotDuplicated(Integer checkType, Integer timeSlot, Integer excludeId) { if (null == checkType || null == timeSlot) { return; // ç± VO ä¸ç @NotNull å åºï¼è¿éä¸é夿¥é } QueueSequenceDO exist = queueSequenceMapper.selectOne( new LambdaQueryWrapperX<QueueSequenceDO>() .eq(QueueSequenceDO::getCheckType, checkType) .eq(QueueSequenceDO::getTimeSlot, timeSlot)); if (null != exist && !exist.getId().equals(excludeId)) { log.warn("[validateTimeslotNotDuplicated] æ¶æ®µè§åéå¤. checkType={} timeSlot={} " + "å·²åå¨id={} æ¬æ¬¡id={}", checkType, timeSlot, exist.getId(), excludeId); throw exception(QUEUE_SEQUENCE_TIMESLOT_DUPLICATE); } } @Override @@ -138,14 +201,30 @@ public Integer distributeSeqNo(Integer checkType, Integer timeslot) { Integer curSeqNo = queueSequenceMapper.selectQueueNoForUpdate(checkType, timeslot); if (null == curSeqNo) { // ä»ä¸ä¸ä¸ªæ¶æ®µ è·ååºå·ãåå ç³»ç»ç¨30åéçé´éååé¢çº¦æ¶é´æ®µï¼HISçé¢çº¦æ¶é´æ®µå¯è½æ¯30åéæ60åé Integer nextTimeslot = getNextTimeSlot(timeslot, checkType); // ãä¿®å¤ãæ¶æ®µä¸å ¨/å·²æ»¡å¯¼è´æ²¡æ³ç¾å°ãã // åé»è¾ï¼åªå"åå ¸éçç´§é»ä¸ä¸ä¸ªæ¶æ®µ"ï¼ä¸è¦æ±è¯¥æ¶æ®µå¨ queue_sequence ä¸åå¨ã // ç°å®é®é¢ï¼å®æµï¼ï¼ // · åå ¸ ecg_book_timeslot æ 21 ä¸ªæ¶æ®µï¼ä½ queue_sequence ä¸ checkType=400 // åªæ 13 个ãcheckType=100 åªæ 17 个 ââ é¨åæ¶æ®µæ ¹æ¬æ²¡æå·æ± è¡ï¼ // · HIS ä¼ä¸å 60 åéç²åº¦ç bookTimeslotï¼å¦ 10001100ï¼ï¼åå ¸éæ²¡æè¯¥å¼ï¼ // getNextTimeSlot ç´æ¥ return nullï¼ // · ä¸ªå«æ¶æ®µå®¹éå¾å°ï¼å¹³æ¿è¿å¨ timeslot_book_num=3ï¼ï¼å¾å¿«éå®ã // ä¸è ä»»ä¸å½ä¸ â æ QUEUE_SEQUENCE_TIMESLOT_FULL â **æ£è 没æ³ç¾å°**ã // // ç°å¨æ¹ä¸ºï¼**ååæå¤æ¾ N ä¸ªæ¶æ®µï¼å第ä¸ä¸ªä»æä½éç**ï¼ä¸é¢ findAvailableTimeslot å å®ç°ï¼ï¼ // å¤§å¹ éä½"å ä¸ªå«æ¶æ®µç¼ºå¤±/已满就ç¾å°å¤±è´¥"çæ¦çï¼ç¡®å®é½æ»¡äºææéã Integer nextTimeslot = findAvailableTimeslot(checkType, timeslot, false); if (null == nextTimeslot) { log.error("[distributeSeqNo] è¯¥æ£æ¥ç±»ååå {} ä¸ªæ¶æ®µå åæ å¯åå·æ¶æ®µ. checkType={} timeslot={}", MAX_TIMESLOT_LOOKAHEAD, checkType, timeslot); throw exception(QUEUE_SEQUENCE_TIMESLOT_FULL); } curSeqNo = queueSequenceMapper.selectQueueNoForUpdate(checkType, nextTimeslot); if (null == curSeqNo) { // æ¢æµä¸åå·ä¹é´è¢«å¹¶åæ¢ç©ºï¼ä¿å®æ¥éï¼ç±å端æç¤ºéæ°ç¾å°ï¼ log.warn("[distributeSeqNo] æ¢æµå°çæ¶æ®µéå³è¢«å 满. checkType={} timeslot={}", checkType, nextTimeslot); throw exception(QUEUE_SEQUENCE_TIMESLOT_FULL); } @@ -180,6 +259,215 @@ return curVipSeqNo + 1; } /** * æãæ£æ¥ç±»åé ç½®çè§åãåé æéåºå·ã * * <h3>ä¸ç§è§å</h3> * <ol> * <li><b>é¢çº¦å·(0)</b>ï¼ç´æ¥ç¨é¢çº¦ç³»ç»å·²ä¸åçå·ï¼ä¸ååé ã * 注æ {@code existingSeqNo} 为空æ¶**åéå°ç¾å°åºå·è§å** ââ å 为è¥ç´æ¥è¿å * nullï¼è°ç¨æ¹ä¼æ null åå ¥ {@code book_seq_num}ï¼æ£è å°æ¿ä¸å°å·ã</li> * <li><b>ç¾å°åºå·(1)</b>ï¼å½å¤©åæ£æ¥ç±»åå è¿ç»éå¢ï¼ç¬¬ 1 个ç¾å° = 1 å·ï¼ï¼ * å¹¶æãæ¯ 9 个å·é¢ç 1 个ãè·³è¿é¢çå·ç»å æ¥æ£è ã * **ä¸è®¾å½æ¥ä¸é**ï¼ä¸è§å 2 çæ¶æ®µå®¹éä¸åï¼ã</li> * <li><b>æ¶æ®µå·(2)</b>ï¼è°ç¨åæç {@link #distributeSeqNo}ï¼æ {@code time_slot} ä»å·æ± åå·ï¼ï¼ * ä¿çæ¶æ®µå®¹éæ§å¶ãè¿ä¹æ¯ {@code seq_rule} æªé ç½®æ¶çé»è®¤å¼ã</li> * </ol> * * <h3>为ä»ä¹è§å 1 éè¦ç¬ç«è®¡æ°å¨</h3> * ä¸è½ç¨ {@code MAX(book_seq_num)+1} 计ç®ï¼é¢çå·ï¼10ã20â¦ï¼è¥æ 人使ç¨å°±ä¸ä¼åºç°å¨ * æ°æ®éï¼ä¸ä¸ä¸ªæ®éå·æ MAX+1 ä¼å次ç®åºåä¸ä¸ªé¢çå·ï¼é æå²çªã * å æ¤ç¨ {@code seq_counter} 表**å¿ é¡»è¢«æ¶è**å°éå¢ï¼è§ Mapper ç LAST_INSERT_ID åæ³ï¼ã */ @Override @Transactional public Integer distributeSeqNoByRule(Integer checkType, Integer timeslot, Integer existingSeqNo, boolean urgent) { SeqRuleEnum rule = resolveRule(checkType); switch (rule) { case APPOINT: // â é¢çº¦å·ï¼é¢çº¦ç³»ç»å·²ç»å·åç´æ¥ç¨ï¼å¦ååéå°ç¾å°åºå·ï¼é¿å æ£è æ¿ä¸å°å·ï¼ if (null != existingSeqNo && existingSeqNo > 0) { log.info("[distributeSeqNoByRule] è§å=é¢çº¦å·ï¼ç´æ¥ä½¿ç¨é¢çº¦ç³»ç»å·. checkType={} seqNo={}", checkType, existingSeqNo); return existingSeqNo; } log.warn("[distributeSeqNoByRule] è§å=é¢çº¦å·ï¼ä½é¢çº¦ç³»ç»æªä¸åå·ï¼åéå°ç¾å°åºå·. checkType={}", checkType); return nextCheckInSeqNo(checkType, urgent); case CHECKIN: // â¡ ç¾å°åºå·ï¼å½å¤©åæ£æ¥ç±»åè¿ç»éå¢ï¼æ¯ 9 个é¢ç 1 个 return nextCheckInSeqNo(checkType, urgent); case TIMESLOT: default: // â¢ æ¶æ®µå·ï¼ä¿ææ¹é åçè¡ä¸ºï¼å«æ¶æ®µå®¹éæ§å¶ï¼ return distributeSeqNo(checkType, timeslot); } } /** * è§£æææ£æ¥ç±»åé ç½®çæéåºå·è§åï¼æ¥ä¸å°é ç½®ææªé ç½®æ¶è¿åé»è®¤ï¼æ¶æ®µå·ï¼ã */ private SeqRuleEnum resolveRule(Integer checkType) { if (null == checkType) { return SeqRuleEnum.DEFAULT; } CheckTypeDO checkTypeDO = checkTypeMapper.getCheckTypeByValue(checkType); if (null == checkTypeDO) { log.warn("[resolveRule] æªæ¾å°æ£æ¥ç±»åé ç½®ï¼ä½¿ç¨é»è®¤è§å(æ¶æ®µå·). checkType={}", checkType); return SeqRuleEnum.DEFAULT; } return SeqRuleEnum.parse(checkTypeDO.getSeqRule()); } /** * 计ç®ä¸ä¸ä¸ªãç¾å°åºå·ãã * * <h4>两个ç¬ç«è®¡æ°å¨ï¼è¿æ¯è¸©ååçç»è®ºï¼</h4> * {@code seq_counter} ç»´æ¤ä¸¤ä¸ªäºä¸å¹²æ°ç计æ°å¨ï¼ * <ul> * <li>{@code normal_next} ââ æ®éå·ï¼åºå 1..9ã11..19ã21..29â¦ï¼è·³è¿ 10 çåæ°ï¼ï¼</li> * <li>{@code reserved_next} ââ é¢çå·ï¼å æ¥ç¨ï¼ï¼åºå 10ã20ã30â¦ã</li> * </ul> * <b>为ä»ä¹ä¸è½åªç¨ä¸ä¸ªè®¡æ°å¨</b>ï¼è¥ç¨å个 {@code candidate} éå¢åå"è·³è¿é¢çå·"ï¼ * å¿ ç¶æè½¦ ââ æ®éæ£è æ¿å° candidate=10 â è·³è¿å¾ 11ï¼ä¸ä¸ä¸ªæ®éæ£è æ¿å° candidate=11 * â ä¹å¾ 11ã宿µ 20 次åå·ä¸ç¬¬ 10ã11 次åé å·ç¸åã * 两个计æ°å¨ç©çé离åï¼äºè åå¼åä¸ç¸äº¤ï¼**ä¸å¯è½éå·**ã * * <h4>å¹¶åï¼ä¸¤å¤åï¼å已修å¤ï¼</h4> * <ol> * <li><b>æ¨è¿å¿ é¡»åå</b>ï¼ç¨åæ¡ {@code INSERT .. ON DUPLICATE KEY UPDATE} * 卿°æ®åºç«¯å®æ"读-æ¹-å"ï¼é¿å å æ¥åæ¹é æéå·ã * 注æè¯¥è¯å¥å¿ é¡»å {@code @InterceptorIgnore(dataPermission="true")}ï¼ * å¦å MyBatis-Plus ç DataPermissionInterceptor ä¼ç¨ JSqlParser è§£æå®å¹¶ * **æ UnsupportedOperationException**ï¼JSqlParser 䏿¯æè¯¥ MySQL ä¸æè¯æ³ï¼ï¼ * 表ç°ä¸º**é¢çº¦ç¡®è®¤ç´æ¥ 500** ââ è¯¦è§ Mapper ä¸ç注éã</li> * <li><b>æ¨è¿ä¸è¯»åå¿ é¡»åäºå¡</b>ï¼MySQL é»è®¤ REPEATABLE READï¼ * è¥è¯»åå¨å¦ä¸ä¸ªäºå¡éï¼ä¼è¯»å°æ§å¿«ç § â éå·ã * æ¬æ¹æ³æ¯ private ä¸è¢«**åç±»å é¨è°ç¨**ï¼{@code @Transactional} å ä¸èµ°ä»£çè**失æ**ï¼ * æ æ¹ç¨ {@link org.springframework.transaction.support.TransactionTemplate} æ¾å¼å¼å¯äºå¡ã</li> * </ol> * 宿µ 8 çº¿ç¨ Ã 20 次 = 160 次åå·ï¼åäºå¡ 160/160 å¯ä¸ãå·å¼è¿ç»ï¼ * ç¬ç«äºå¡åªæ 75/160 ââ è¯¦è§ Mapper 注éã */ private Integer nextCheckInSeqNo(Integer checkType, boolean urgent) { final LocalDate today = LocalDate.now(); // ç¨æ¾å¼äºå¡æãæ¨è¿ãä¸ã读åãå å¨ä¸èµ·ï¼@Transactional 卿¤å¤ä¸çæï¼è§æ¹æ³æ³¨éï¼ Integer assigned = counterTransactionTemplate.execute(status -> { if (urgent) { queueSequenceMapper.advanceReservedSeq(checkType, today); } else { queueSequenceMapper.advanceNormalSeq(checkType, today); } SeqCounterDO counter = queueSequenceMapper.getSeqCounter(checkType, today); if (null == counter) { return null; } return urgent ? counter.getReservedNext() : counter.getNormalNext(); }); if (null == assigned) { // ç论ä¸ä¸ä¼åçï¼åæ¨è¿è¿ï¼ï¼ä¿å®åéï¼é¿å æé黿ç¾å° assigned = urgent ? SeqRuleEnum.ROUND_SIZE : 1; log.error("[nextCheckInSeqNo] 计æ°å¨è¯»å失败ï¼åé为é»è®¤å·. checkType={} å æ¥={} åéå·={}", checkType, urgent, assigned); } log.info("[nextCheckInSeqNo] è§å=ç¾å°åºå·. checkType={} å æ¥={} æ¬æ¬¡åé ={}", checkType, urgent, assigned); return assigned; } /** * å忥æ¾ä¸ä¸ª**仿ä½é**çé¢çº¦æ¶æ®µã * <p> * 䏿§ç {@code getNextTimeSlot} çåºå«ï¼ * <ol> * <li>æ§å®ç°åªç"ç´§é»çä¸ä¸ä¸ª"åå ¸é¡¹ï¼ä¸**䏿£æ¥è¯¥æ¶æ®µå¨ queue_sequence 䏿¯å¦åå¨** * ââ è¥ä¸ä¸ä¸ªæ¶æ®µæ°å¥½ç¼ºå¤±ï¼å·æ± 没æè¿ä¸è¡ï¼ï¼ä¼ç´æ¥è¿åå®ï¼éå * {@code selectQueueNoForUpdate} åä¸å°å¼ â æ TIMESLOT_FULLã * è¿ä¹æ¯"è¿å¨è¯éªæ²¡æ³ç¾å°"çç´æ¥åå ä¹ä¸ã</li> * <li>æ§å®ç°å¨ {@code timeslot} ä¸å¨åå ¸ä¸æ¶ï¼HIS ä¼ä¸å 60 åéç²åº¦å¼ï¼ * å¦ 10001100ï¼èåå ¸åªæ 30 åéç²åº¦ï¼ç´æ¥ {@code return null}ã * æ¬å®ç°æ¹ä¸º**ååå ¸ä¸ç¬¬ä¸ä¸ªæäº {@code timeslot} çæ¶æ®µ**ç»§ç»ååæ¾ï¼ * ä»èä»è½ä¸ºè¿ç±»æ£è åé å·ã</li> * <li>æå¤ååæ¾ {@link #MAX_TIMESLOT_LOOKAHEAD} ä¸ªæ¶æ®µï¼çº¦ 3 å°æ¶ï¼ï¼ * é¿å "å½åæ¯æåä¸ä¸ªæ¶æ®µ"æ¶æ å¤å¯å»ï¼å ¨é½æ»¡æè¿å nullã</li> * </ol> * * @param checkType æ£æ¥ç±»å * @param timeslot HIS ä¼ å ¥çé¢çº¦æ¶æ®µï¼å¯è½æ¯åå ¸å¤ç 60 åéç²åº¦å¼ï¼ * @param includeVip true æ¶è¦æ± VIP å·ä¹æä½é * @return å¯ç¨çæ¶æ®µå¼ï¼æ å¯ç¨æ¶æ®µè¿å null */ private Integer findAvailableTimeslot(Integer checkType, Integer timeslot, boolean includeVip) { List<DictDataRespDTO> dictBookTimeslotList = dictDataApi.getDictDataList(ECG_BOOK_TIMESLOT); if (dictBookTimeslotList == null || dictBookTimeslotList.isEmpty()) { log.error("[findAvailableTimeslot] åå ¸ {} ä¸ºç©ºï¼æ æ³åé æ¶æ®µå·", ECG_BOOK_TIMESLOT); return null; } // èµ·ç¹ï¼ä¸¥æ ¼æäº timeslot ç第ä¸ä¸ªåå ¸é¡¹ã // è¿æ ·å³ä½¿ timeslot ä¸å¨åå ¸å ï¼60 åéç²åº¦å¼ï¼ï¼ä¹è½è½å°å ¶åçæ¶æ®µç»§ç»æ¾ã int startIdx = -1; for (int i = 0; i < dictBookTimeslotList.size(); i++) { Integer v = parseSlotValue(dictBookTimeslotList.get(i).getValue()); if (null != v && v > timeslot) { startIdx = i; break; } } if (startIdx < 0) { // timeslot å·²æ¯æåä¸ä¸ªæ¶æ®µï¼æå ¨é¨æ¶æ®µé½æ©äºå®ï¼ log.warn("[findAvailableTimeslot] å·²æ¯æåä¸ä¸ªæ¶æ®µææ æ´ææ¶æ®µ. checkType={} timeslot={}", checkType, timeslot); return null; } int end = Math.min(dictBookTimeslotList.size(), startIdx + MAX_TIMESLOT_LOOKAHEAD); for (int i = startIdx; i < end; i++) { Integer candidate = parseSlotValue(dictBookTimeslotList.get(i).getValue()); if (null == candidate) { continue; } Integer avail = queueSequenceMapper.countAvailableTimeslot( checkType, candidate, includeVip ? 1 : 0); if (null != avail && avail > 0) { log.info("[findAvailableTimeslot] checkType={} åæ¶æ®µ={} â æ¹ç¨æ¶æ®µ={}ï¼ç¬¬ {} 个åéï¼", checkType, timeslot, candidate, i - startIdx + 1); return candidate; } } log.warn("[findAvailableTimeslot] åå {} ä¸ªæ¶æ®µå åæ ä½é. checkType={} timeslot={}", MAX_TIMESLOT_LOOKAHEAD, checkType, timeslot); return null; } /** å®å ¨è§£æåå ¸å¼ï¼å½¢å¦ "9301000"ï¼ä¸º Integerï¼å¿½ç¥èæ°æ® */ private Integer parseSlotValue(String value) { if (null == value || value.isEmpty()) { return null; } try { return Integer.valueOf(value.trim()); } catch (NumberFormatException e) { log.warn("[parseSlotValue] åå ¸æ¶æ®µå¼éæ³ï¼å·²å¿½ç¥: {}", value); return null; } } /** * æ§ç"åç´§é»ä¸ä¸ä¸ªæ¶æ®µ"ãä¿çä¾åè/å ¼å®¹ï¼æ°é»è¾è¯·ç¨ * {@link #findAvailableTimeslot(Integer, Integer, boolean)}ã * * @deprecated åªçä¸ä¸ä¸ªæ¶æ®µä¸ä¸æ ¡éªå·æ± æ¯å¦åå¨ï¼ä¼å¯¼è´ç¾å°å¤±è´¥ */ @Deprecated private Integer getNextTimeSlot(Integer timeslot, Integer checkType) { List<DictDataRespDTO> dictBookTimeslotList = dictDataApi.getDictDataList(ECG_BOOK_TIMESLOT); Optional<Integer> index = dictBookTimeslotList.stream() jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/mail/MailSendApi.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/NotifyMessageSendApi.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/dto/NotifySendSingleToUserReqDTO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/dto/NotifyTemplateReqDTO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/enums/mail/MailSendStatusEnum.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/enums/notify/NotifyTemplateTypeEnum.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/api/mail/MailSendApiImpl.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/api/notify/NotifyMessageSendApiImpl.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailAccountController.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailLogController.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailTemplateController.http
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailTemplateController.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/log/MailLogPageReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/log/MailLogRespVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateRespVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/NotifyMessageController.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/NotifyTemplateController.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailAccountDO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailLogDO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailTemplateDO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/notify/NotifyMessageDO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/notify/NotifyTemplateDO.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailAccountMapper.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailLogMapper.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailTemplateMapper.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/notify/NotifyMessageMapper.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/notify/NotifyTemplateMapper.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/redis/RedisKeyConstants.java
@@ -68,30 +68,6 @@ String OAUTH2_ACCESS_TOKEN = "oauth2_access_token:%s"; /** * ç«å 信模ççç¼å * <p> * KEY æ ¼å¼ï¼notify_template:{code} * VALUE æ°æ®æ ¼å¼ï¼String 模çä¿¡æ¯ */ String NOTIFY_TEMPLATE = "notify_template"; /** * é®ä»¶è´¦å·çç¼å * <p> * KEY æ ¼å¼ï¼mail_account:{id} * VALUE æ°æ®æ ¼å¼ï¼String è´¦å·ä¿¡æ¯ */ String MAIL_ACCOUNT = "mail_account"; /** * é®ä»¶æ¨¡ççç¼å * <p> * KEY æ ¼å¼ï¼mail_template:{code} * VALUE æ°æ®æ ¼å¼ï¼String 模çä¿¡æ¯ */ String MAIL_TEMPLATE = "mail_template"; /** * ç信模ççç¼å * <p> * KEY æ ¼å¼ï¼sms_template:{id} jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/consumer/mail/MailSendConsumer.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/message/mail/MailSendMessage.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/producer/mail/MailProducer.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailAccountService.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailAccountServiceImpl.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailLogService.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailLogServiceImpl.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailSendService.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailSendServiceImpl.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailTemplateService.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailTemplateServiceImpl.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyMessageService.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyMessageServiceImpl.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifySendService.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifySendServiceImpl.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyTemplateService.java
ÎļþÒÑɾ³ý jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyTemplateServiceImpl.java
ÎļþÒÑɾ³ý jh-server/pom.xml
@@ -148,6 +148,38 @@ <build> <!-- 设置æå»ºç jar å å --> <finalName>${project.artifactId}</finalName> <!-- åå¹¶é¨ç½²ï¼æ ecg_web çå端æå»ºäº§ç©æè¿ jarã · ç®æ ç®å½é META-INF/resources/frontend èé staticï¼ META-INF/resources æ¯ Servlet 3.0 æ åéæèµæºç®å½ï¼Spring Boot é»è®¤ä¼æ«æï¼é¢å¤å ä¸å± frontend/ åç¼ï¼ä¾¿äºåç«¯ç¨ addResourceHandlers 精确æ§å¶"åªäº URL 交ç»å端"ï¼ ä¸å½±åå端已æç /doc.htmlã/druid/**ã/profile/** çè·¯å¾ã è§ cn.lihu.jh.server.ecg.FrontendResourceConfigã · 产ç©ç®å½ç± profile æ³¨å ¥ç env.VITE_OUT_DIR å³å®ï¼ é»è®¤ dist-mergedï¼å¯¹åº ecg_web ç `pnpm build:merged`ï¼ã · 注æï¼æ¬æ¨¡åãä¸ãå¼å ¥ frontend-maven-pluginã å端æå»ºè¯·å¨é¨ç½²ååç¬æ§è¡ï¼cd ecg_web && pnpm build:mergedï¼ï¼ é¿å å端æå»ºå¼ºä¾èµ node/pnpmï¼ä¹é¿å æå»ºæºéè¦å¤ç½ä¸è½½ nodeã --> <resources> <!-- ä¿çåæçåç«¯èµæºï¼application*.yamlãlogback-spring.xml çï¼ --> <resource> <directory>src/main/resources</directory> <filtering>false</filtering> </resource> <!-- æ°å¢ï¼åç«¯äº§ç© --> <resource> <directory>${project.basedir}/../../ecg_web/${env.VITE_OUT_DIR}</directory> <targetPath>META-INF/resources/frontend</targetPath> <filtering>false</filtering> </resource> </resources> <plugins> <!-- æå --> <plugin> @@ -165,4 +197,31 @@ </plugins> </build> <!-- å端产ç©ç®å½çéæ©ãenv.VITE_OUT_DIR ä¼è¢«ä¸é¢ <resources> å¼ç¨ã · frontend-mergedï¼é»è®¤ï¼ï¼ä½¿ç¨ ecg_web æ§è¡ `pnpm build:merged` 产åºç dist-mergedï¼å¯¹åº"å端æè¿ jarãä¸åç«¯åæº"çåå¹¶é¨ç½²æ¨¡å¼ã · frontend-prodï¼åéå°åæç dist-prodãè¥å端ä»ç± nginx ç¬ç«æç®¡ ï¼å³ä¸ååå¹¶é¨ç½²ï¼ï¼ç¨ -P frontend-prod æ¿æ´»æ¤ profile å³å¯ï¼ æ¤æ¶ jar å ä¸å«å端ï¼è¡ä¸ºä¸æ¹é åä¸è´ã --> <profiles> <profile> <id>frontend-merged</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <env.VITE_OUT_DIR>dist-merged</env.VITE_OUT_DIR> </properties> </profile> <profile> <id>frontend-prod</id> <properties> <env.VITE_OUT_DIR>dist-prod</env.VITE_OUT_DIR> </properties> </profile> </profiles> </project> jh-server/src/main/resources/application-local.yaml
@@ -1,5 +1,5 @@ server: host: 192.168.2.100 host: localhost port: 48080 --- #################### å»é¢å¹³å°æå¡å°å #################### @@ -51,16 +51,16 @@ primary: master datasource: master: url: jdbc:mysql://192.168.2.200:3306/lihu?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X è¿æ¥çç¤ºä¾ # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X è¿æ¥çç¤ºä¾ url: jdbc:mysql://47.93.127.38:3308/lihu?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X è¿æ¥çç¤ºä¾ # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X è¿æ¥çç¤ºä¾ # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL è¿æ¥çç¤ºä¾ # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle è¿æ¥çç¤ºä¾ # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer è¿æ¥çç¤ºä¾ # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM è¿æ¥çç¤ºä¾ # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大éä» KingbaseES è¿æ¥çç¤ºä¾ # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss è¿æ¥çç¤ºä¾ username: root password: Smartor.2023 username: smartor password: Smartor.2016 # username: sa # SQL Server è¿æ¥çç¤ºä¾ # password: Jh@2024 # SQL Server è¿æ¥çç¤ºä¾ # username: SYSDBA # DM è¿æ¥çç¤ºä¾ @@ -69,16 +69,16 @@ # password: Jh@2024 # OpenGauss è¿æ¥çç¤ºä¾ slave: # 模æä»åºï¼å¯æ ¹æ®èªå·±éè¦ä¿®æ¹ lazy: true # å¼å¯æå è½½ï¼ä¿è¯å¯å¨é度 url: jdbc:mysql://192.168.2.200:3306/lihu?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X è¿æ¥çç¤ºä¾ username: root password: Smartor.2023 url: jdbc:mysql://47.93.127.38:3308/lihu?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X è¿æ¥çç¤ºä¾ username: smartor password: Smartor.2016 # Redis é ç½®ãRedisson é»è®¤çé 置足å¤ä½¿ç¨ï¼ä¸è¬ä¸éè¦è¿è¡è°ä¼ redis: host: 192.168.2.200 #r-bp1zyjl0g07e1ry08rpd.redis.rds.aliyuncs.com # å°å port: 6379 #ç«¯å£ 6379 host: 127.0.0.1 #r-bp1zyjl0g07e1ry08rpd.redis.rds.aliyuncs.com # å°å port: 6020 #ç«¯å£ 6379 database: 15 # æ°æ®åºç´¢å¼ password: Smartor.2023 #Root@yinyu # å¯ç ï¼å»ºè®®ç产ç¯å¢å¼å¯ password: Smartor #Root@yinyu # å¯ç ï¼å»ºè®®ç产ç¯å¢å¼å¯ --- #################### 宿¶ä»»å¡ç¸å ³é ç½® #################### jh-server/src/main/resources/application.yaml
@@ -3,8 +3,8 @@ name: jh-server profiles: active: stage # active: stage # active: local active: prod main: allow-circular-references: true # å 许循ç¯ä¾èµï¼å ä¸ºé¡¹ç®æ¯ä¸å±æ¶æï¼æ æ³é¿å è¿ä¸ªæ åµã sql/mysql/jh.sql
@@ -34,6 +34,13 @@ `updater` varchar(10) DEFAULT '' COMMENT 'æ´æ°è ', `update_time` datetime NOT NULL COMMENT 'æ´æ°æ¶é´', `deleted` bit(1) DEFAULT b'0' COMMENT 'å 餿 è®°', -- ä»¥ä¸ 6 åç± _prep/06_add_his_columns.sql æ·»å ï¼HIS æ¥å ¥è¡¥å åæ®µï¼2026-09-27ï¼ `jjbz` varchar(4) DEFAULT NULL COMMENT 'ä¼å 级æ è®° Nå¸¸è§ Jå æ¥', `method_code` varchar(64) DEFAULT NULL COMMENT 'æ£æ¥æ¹å¼ç¼ç ', `target_site_code` varchar(64) DEFAULT NULL COMMENT 'æ£æ¥é¨ä½ç¼ç ', `room_name` varchar(64) DEFAULT NULL COMMENT 'æ£æ¥æ¿é´åç§°', `remark` varchar(255) DEFAULT NULL COMMENT '注æäºé¡¹', `book_seq_num` int DEFAULT NULL COMMENT 'é¢çº¦æåºå·', PRIMARY KEY (`id`), KEY `idx-pat` (`pat_id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='é¢çº¦è¡¨';