From fce96ef468291fb9a0e6a4d34ab371315e9485d4 Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期六, 03 十月 2026 00:59:44 +0800
Subject: [PATCH] ai优化

---
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/doctor/DoctorController.java                 |  133 ++
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/QueueSequenceController.java   |   33 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/devrent/DevRentServiceImpl.java                       |  161 ++
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/checktype/CheckTypeDO.java                     |   24 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueSaveReqVO.java                 |   22 
 jh-server/src/main/resources/application-local.yaml                                                                               |   22 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/callingscreen/CallingScreenServiceImpl.java           |   76 +
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/room/RoomDO.java                               |   12 
 jh-server/pom.xml                                                                                                                 |   59 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queuesequence/QueueSequenceMapper.java              |  130 +
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentPageReqVO.java     |    4 
 sql/mysql/jh.sql                                                                                                                  |    7 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceRespVO.java    |    8 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceSaveReqVO.java |   29 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/BedBO.java                                      |   16 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceTxFunctions.java                    |  110 +
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java                           |  224 +++
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueRespVO.java                    |   36 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/appointment/AppointmentMapper.java                  |   13 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypePageReqVO.java         |    3 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentRespVO.java        |   43 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/devrent/vo/DevRentRespVO.java                |   56 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queue/QueueMapper.java                              |  138 +
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/devrent/DevRentDO.java                         |   70 +
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceServiceImpl.java           |  292 ++++
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/appointment/AppointmentDO.java                 |   60 
 jh-server/src/main/resources/application.yaml                                                                                     |    4 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/jobrecord/vo/JobRecordPageReqVO.java         |   17 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/jobrecord/JobRecordMapper.java                      |    2 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/AppointmentTypeEnum.java                                |   61 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java               | 1188 ++++++++++++++++-
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeSaveReqVO.java         |    6 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queuesequence/QueueSequenceDO.java             |   11 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentSaveReqVO.java     |   57 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/callingscreen/ScreenQueueRespVO.java         |   55 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/jobrecord/JobRecordDO.java                     |   66 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceService.java               |   20 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/checktype/CheckTypeMapper.java                      |    8 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/external/ExternalController.java             |  109 +
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/jobrecord/JobRecordServiceImpl.java                   |   93 +
 jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/redis/RedisKeyConstants.java                     |   24 
 jh-module-ecg/jh-module-ecg-api/src/main/java/cn/lihu/jh/module/ecg/enums/ErrorCodeConstants.java                                 |   28 
 /dev/null                                                                                                                         |  138 --
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/SimpleCheckTypeRespVO.java      |    3 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queue/QueueDO.java                             |   46 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/devrent/DevRentMapper.java                          |   19 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/room/RoomMapper.java                                |   11 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueService.java                               |   55 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeRespVO.java            |    8 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/ActionTypeEnum.java                                     |  117 +
 50 files changed, 3,504 insertions(+), 423 deletions(-)

diff --git a/jh-module-ecg/jh-module-ecg-api/src/main/java/cn/lihu/jh/module/ecg/enums/ErrorCodeConstants.java b/jh-module-ecg/jh-module-ecg-api/src/main/java/cn/lihu/jh/module/ecg/enums/ErrorCodeConstants.java
index 6aa50e3..afcb65e 100644
--- a/jh-module-ecg/jh-module-ecg-api/src/main/java/cn/lihu/jh/module/ecg/enums/ErrorCodeConstants.java
+++ b/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, "涓嶆敮鎸佺殑鏈嶅姟浠g爜(action)锛岃鏍稿鎺ュ彛鏂囨。浜ゆ槗缂栧彿");
+    ErrorCode HIS_MESSAGE_PARSE_FAIL = new ErrorCode(1_010_001_100, "鎶ユ枃瑙f瀽澶辫触锛岃鏍稿鎶ユ枃缁撴瀯涓庡繀濉瓧娈�");
+    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, "闃熷垪涓湁鎮h��");
     ErrorCode QUEUE_NOT_READY_PATIENT = new ErrorCode(1_010_003_004, "娌℃湁鍑嗗涓殑鎮h��");
     ErrorCode QUEUE_RECALL_INSTALL_NOT_CUR_ROOM = new ErrorCode(1_010_003_005, "涓嶈兘鍙洖鍏朵粬璇婂鐨勫畨瑁呮偅鑰�");
+    /**
+     * 銆屽仠姝㈠�欒瘖銆嶅姛鑳芥湭灏辩华銆�
+     * <p>
+     * 瑙﹀彂鏉′欢锛氭暟鎹簱灏氭湭鎵ц `_prep/11_闇�姹傚崌绾姹囨�籗QL.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, "鎮h�呬笉瀛樺湪");
 
@@ -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, "鏈椂娈礦IP搴忓彿宸叉弧");
     ErrorCode QUEUE_SEQUENCE_TIMESLOT_VIP_EXCEPTION = new ErrorCode(1_010_010_003, "鏈椂娈礦IP搴忓彿寮傚父");
+
+    /**
+     * 棰勭害鏃舵閲嶅锛氬悓涓�妫�鏌ョ被鍨嬩笅鍚屼竴涓椂娈靛彧鑳芥湁涓�鏉¤鍒欍��
+     * <p>
+     * 琛ㄤ笂**娌℃湁** (check_type, time_slot) 鍞竴绾︽潫锛堝巻鍙查仐鐣欙級锛岃�屽彇鍙� SQL
+     * {@code select queue_no ... where check_type=? and time_slot=? ... for update}
+     * 鏈熸湜鍙懡涓竴琛岋紱鑻ュ瓨鍦ㄩ噸澶嶈锛屽彇鍙疯涓轰笉鍙鏈熴�傛晠鍦ㄧ淮鎶ゅ叆鍙e鎷︽埅銆�
+     */
+    ErrorCode QUEUE_SEQUENCE_TIMESLOT_DUPLICATE = new ErrorCode(1_010_010_004,
+            "璇ユ鏌ョ被鍨嬬殑姝ゆ椂娈佃鍒欏凡瀛樺湪锛岃鍕块噸澶嶆坊鍔�");
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentPageReqVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentPageReqVO.java
index 439895a..23c018f 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentPageReqVO.java
+++ b/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.*;
 
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentRespVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentRespVO.java
index c14ace3..5fabb13 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentRespVO.java
+++ b/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=甯歌锛孞=鍔犳��
+     */
+    @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;
+
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentSaveReqVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentSaveReqVO.java
index 596a58d..3b5b6fc 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentSaveReqVO.java
+++ b/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>
+ * 杩欎袱涓瓧娈靛師鍏堝0鏄庝负 {@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=甯歌锛孞=鍔犳�ワ紙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;
+
+    /**
+     * 娉ㄦ剰浜嬮」锛圚IS 鎶ユ枃 ZDY.remark锛�
+     */
+    private String remark;
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/callingscreen/ScreenQueueRespVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/callingscreen/ScreenQueueRespVO.java
index 91d487a..55818e9 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/callingscreen/ScreenQueueRespVO.java
+++ b/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锛坬ueue 琛ㄦ棤姝ゅ垪锛夛紝鐢� 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 = "鎮h�呯數璇濓紙鎵嬫満浼樺厛锛屽洖閫�鍥鸿瘽锛�")
+    @ExcelProperty("鎮h�呯數璇�")
+    private String patMobile;
+
+    @Schema(description = "鐥呭尯鍚嶇О")
+    @ExcelProperty("鐥呭尯鍚嶇О")
+    private String patWardDesc;
+
+    @Schema(description = "鐥呭簥鍙凤紙娉ㄦ剰涓嶆槸鏈被鐨� bedNo锛屽悗鑰呮槸璇婄枟搴�/宸ヤ綅鍙凤級")
+    @ExcelProperty("鐥呭簥鍙�")
+    private String patBedNo;
+
+    @Schema(description = "鎮h�呮潵婧愶細1闂ㄨ瘖 2鎬ヨ瘖 3浣忛櫌 4浣撴")
+    @ExcelProperty("鎮h�呮潵婧�")
+    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;
 }
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypePageReqVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypePageReqVO.java
index e6ecaf1..9012d06 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypePageReqVO.java
+++ b/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;
 }
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeRespVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeRespVO.java
index 16e4f45..2a970e5 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeRespVO.java
+++ b/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;
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeSaveReqVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeSaveReqVO.java
index be6da5e..9fb216c 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/CheckTypeSaveReqVO.java
+++ b/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;
 }
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/SimpleCheckTypeRespVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/SimpleCheckTypeRespVO.java
index 384d999..dc5f6d4 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/checktype/vo/SimpleCheckTypeRespVO.java
+++ b/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;
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/devrent/vo/DevRentRespVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/devrent/vo/DevRentRespVO.java
index 016d8b8..6478333 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/devrent/vo/DevRentRespVO.java
+++ b/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锛坉ev_rent 琛ㄦ棤姝ゅ垪锛夛紝鐢� DevRentServiceImpl 鎸� applyNo 鍥炲~銆�
+    // 琛ラ綈杩欎簺瀛楁鍚庯紝棰嗙敤/瑁呮満/鎷嗘満/鏁版嵁褰曞叆/妫�鏌ヨ褰� 5 涓晫闈㈡墠鑳藉睍绀哄畬鏁存偅鑰呬俊鎭��
+
+    @Schema(description = "鎮h�呮�у埆")
+    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 = "鎮h�呮潵婧愶細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 = "灏辫瘖鍗″彿锛坢edical_card锛屽簱涓涓虹┖锛�")
+    private String medicalCard;
+
+    @Schema(description = "闂ㄨ瘖鍙凤紙瀹炴祴閮ㄥ垎鏁版嵁瀛樼殑鏄韩浠借瘉鍙凤紝闈炵湡姝e崱鍙凤級")
+    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;
 }
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/doctor/DoctorController.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/doctor/DoctorController.java
index 142830f..6359151 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/doctor/DoctorController.java
+++ b/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 = "鎮h�呯紪鍙�", 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 绮剧‘瀹氫綅锛岄伩鍏嶈鎾ら攢鍏朵粬鎮h�咃紙鏃㈡湁缂洪櫡瑙� DevRentServiceImpl锛�
+        Integer result = queueService.undoFinishPatient(roomId, bedNo, patId, checkType);
+        if (null == result || 0 == result) {
+            return error(APPOINTMENT_NOT_EXISTS);
+        }
+        return success("宸叉挙閿�妫�鏌ュ畬鎴愶紝鎮h�呭凡杩斿洖鍊欒瘖鍖�");
+    }
+
+    @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 = "鍙栨湰宸ヤ綅浠婃棩鏈�杩戜竴浣嶅凡瀹屾垚鎮h�咃紙渚涙挙閿�鎻愮ず锛�")
+    @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 = "鍋滄鍊欒瘖锛氫笉鍐嶆柊澧炲�欒瘖鎮h�咃紙宸叉湁鍊欒瘖浠嶅彲鍙彿锛�")
+    @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 = "鎭㈠鍊欒瘖锛氶噸鏂板紑濮嬫帴鏀跺�欒瘖鎮h��")
+    @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);
+    }
+
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/external/ExternalController.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/external/ExternalController.java
index 82a4bb2..c743e03 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/external/ExternalController.java
+++ b/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.*;
 
+/**
+ * 渚涚涓夋柟锛圚IS / 闆嗘垚骞冲彴锛夎皟鐢ㄧ殑閫氱敤鎺ュ彛銆�
+ *
+ * <h3>璺敱鏂瑰紡</h3>
+ * 閫氳繃璇锋眰澶� {@code action} 鍖哄垎鏈嶅姟锛屽彇鍊艰 {@link ActionTypeEnum}銆�
+ *
+ * <h3>鏈鏀瑰姩瑕佺偣</h3>
+ * <ol>
+ *   <li><b>琛ユ敞鍐� ECG 涓撳睘 action</b>锛氭帴鍙f枃妗� 6.4/6.5 瀹氫箟
+ *       {@code S050402}锛圗CG 妫�鏌ラ绾︾姸鎬佹柊澧烇級銆亄@code S050502}锛圗CG 妫�鏌ラ绾︾姸鎬佹洿鏂帮級锛�
+ *       涓� pacs 鐨� {@code S050401}/{@code S050501} 骞跺垪銆傚疄娴嬫棩蹇椾腑杩欎袱涓紪鍙�
+ *       灏氭湭鍑虹幇锛�0 娆★級锛屾澶�**涓诲姩鍏煎**锛岄伩鍏嶉櫌鏂瑰垏鎹㈢紪鍙锋椂娑堟伅琚嫆銆�</li>
+ *   <li><b>鍏煎鏃犲悗缂�鍐欐硶</b>锛氭枃妗e畾涔� {@code S0201}/{@code S0202}锛�
+ *       鑰屽疄娴嬫姤鏂囦负 {@code S0201ECG}/{@code S0202ECG}锛屼袱鑰呭潎鎺ユ敹銆�</li>
+ *   <li><b>缁嗗寲閿欒鐮�</b>锛氬師瀹炵幇鎶婃墍鏈夊紓甯哥粺涓�鍘嬫垚
+ *       {@code APPOINTMENT_CREATE_FAIL}锛�"鐢宠鍗曞垱寤哄け璐�"锛夛紝
+ *       瀵艰嚧鎺掗殰鍥伴毦锛堟湰娆¢棶棰樻帓鏌ユ垚鏈嵆鏉ヨ嚜姝わ級銆傜幇鎸�
+ *       銆屾湭鐭� action / 鎶ユ枃瑙f瀽澶辫触 / 璁板綍涓嶅瓨鍦� / 鍏朵粬銆嶅尯鍒嗚繑鍥炪��</li>
+ * </ol>
+ *
+ * <h3>鍏充簬 S0405</h3>
+ * {@code S0405}锛堢敵璇峰崟鐘舵�佹洿鏂帮級鏄�**鍏ㄩ櫌閫氱敤**鏈嶅姟锛屽尰闄細鎶婃墍鏈夋鏌ョ瀹�
+ * 锛圕T/MRI/DR/瓒呭0鈥︼級鐨勭姸鎬佷竴骞舵帹閫併�備笟鍔″眰宸叉寜蹇冪數鑼冨洿杩囨护锛�
+ * 闈炲績鐢靛崟鍙鏃ュ織銆佷笉澶勭悊锛堣瑙� {@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 璇锋眰鏁版嵁锛圚L7 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][鏈煡鐨刟ction绫诲瀷 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 {
-            // 浣跨敤绛栫暐妯″紡澶勭悊涓嶅悓鐨刟ction
-            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);
+            // 鏈鏈熷紓甯革細鎶ユ枃瑙f瀽澶辫触銆佸瓧娈电己澶卞鑷寸殑 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);
         }
     }
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/jobrecord/vo/JobRecordPageReqVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/jobrecord/vo/JobRecordPageReqVO.java
index 386dcf9..f1eeedb 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/jobrecord/vo/JobRecordPageReqVO.java
+++ b/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>瑙e喅锛氬墠绔妸**褰撳墠璇婂鐨� checkTypes** 浼犱笂鏉ワ紝杩欓噷鎸� `check_type in (...)` 杩囨护锛�
+     * 浣垮垪琛ㄥ彧鏄剧ず"鏈瘖瀹ゅ紑灞曠殑妫�鏌ラ」鐩�"涓嬨�佷笖鐢辫嚜宸卞畬鎴愮殑璁板綍銆�
+     *
+     * <p>涓虹┖鏃朵笉鍔犳杩囨护锛屼繚鎸佹棦鏈夎涓猴紙鍚戝悗鍏煎锛夈��
+     */
+    @Schema(description = "妫�鏌ラ」鐩紙鎸夎瘖瀹ら殧绂昏褰曠敤锛�", example = "[100,1100]")
+    private Integer[] checkTypes;
+
 }
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueRespVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueRespVO.java
index 57ce465..08a2428 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueRespVO.java
+++ b/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锛坬ueue 琛ㄦ棤姝ゅ垪锛夛紝鐢� QueueServiceImpl#fillAppointmentInfo 鍥炲~銆�
+
+    @Schema(description = "鎮h�呮潵婧愶細1闂ㄨ瘖 2鎬ヨ瘖 3浣忛櫌 4浣撴")
+    private Integer patSrc;
+
+    @Schema(description = "鎮h�呮墜鏈哄彿")
+    private String patMobile;
+
+    @Schema(description = "鎮h�呯數璇�")
+    private String patPhone;
+
+    @Schema(description = "鐥呭尯鍚嶇О")
+    private String patWardDesc;
+
+    @Schema(description = "鐥呭簥鍙凤紙娉ㄦ剰锛氫笉鏄湰绫荤殑 bedNo锛屽悗鑰呮槸璇婄枟搴�/宸ヤ綅鍙凤級")
+    private String patBedNo;
+
+    @Schema(description = "灏辫瘖鍗″彿锛坢edical_card锛屽簱涓涓虹┖锛�")
+    private String medicalCard;
+
+    @Schema(description = "闂ㄨ瘖鍙凤紙瀹炴祴閮ㄥ垎鏁版嵁瀛樼殑鏄韩浠借瘉鍙凤紝闈炵湡姝e崱鍙凤級")
+    private String outpatientNo;
+
+    @Schema(description = "韬唤璇佸彿")
+    private String patIdentityId;
+
+    /**
+     * 鍖诲槺鍙凤紙HIS 鎶ユ枃 observationRequest.id.item[root=2.16.156.10011.1.28].extension锛夈��
+     * 涓庛�岀敵璇峰崟鍙� applyNo銆嶄笉鍚岋細鍓嶈�呮槸鍖诲槺鏍囪瘑锛屽悗鑰呮槸鐢宠鍗曟爣璇嗐�傝鑺傜偣鍦ㄨ鑼冧腑闈炲繀椤婚」锛屽簱涓彲涓虹┖銆�
+     */
+    private String doctorAdviceNo;
+
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueSaveReqVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueSaveReqVO.java
index ba5d055..4f691fd 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queue/vo/QueueSaveReqVO.java
+++ b/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>
+     * 鏉ユ簮锛欻IS 鎶ユ枃 {@code observationRequest.zdy.jjbz}锛圢=甯歌锛孞=鍔犳�ワ級
+     * 鈫� 棰勭害璁板綍 {@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;
 }
 
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/QueueSequenceController.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/QueueSequenceController.java
index 3aee1e2..f401eb5 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/QueueSequenceController.java
+++ b/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 = "鑾峰緱褰撳ぉ鏈弧鐨刅IP鏃堕棿娈�")
-    @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
+    @Operation(summary = "鑾峰緱鎸囧畾妫�鏌ョ被鍨嬬殑鍏ㄩ儴棰勭害鏃舵")
+    @Parameter(name = "checkType", description = "妫�鏌ョ被鍨嬪��", required = true)
+    // 鈿狅笍 鏈帴鍙f湁涓や釜璋冪敤鏂癸細鈶犮�岄绾︽椂娈电淮鎶ゃ�嶇晫闈紙check-type 鏉冮檺锛�
+    //                      鈶� 棰勭害娴佺▼ appointment/CheckItemPanel.vue锛坅ppointment 鏉冮檺锛�
+    // 鏁呭繀椤诲悓鏃跺厑璁歌繖涓夌被鏉冮檺锛屽惁鍒欎細鐮村潖鍏朵腑涓�鏉′笟鍔℃祦銆�
+    @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 {
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceRespVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceRespVO.java
index 46806a3..028219b 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceRespVO.java
+++ b/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;
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceSaveReqVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceSaveReqVO.java
index 7d62e6f..53990ad 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/queuesequence/vo/QueueSequenceSaveReqVO.java
+++ b/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 = "鏃舵锛圚HMMHHMM 褰㈠紡锛屽 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;
 
 }
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/appointment/AppointmentDO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/appointment/AppointmentDO.java
index 7831314..b2bcea1 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/appointment/AppointmentDO.java
+++ b/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}锛歂=甯歌锛孞=鍔犳�ャ��
+     */
+    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 鐢宠鍗曟柊澧炴湇鍔$殑绀轰緥涓鑺傜偣娉ㄩ噴涓恒�屽尰鍢盜D銆嶏紝
+     * 6.4/6.5 妫�鏌ラ绾︾姸鎬佹湇鍔′腑娉ㄩ噴涓恒�屽尰鍢卞彿銆嶃��
+     * 瀹炴祴 S0201ECG 220 鏉°�丼0202ECG 29 鏉″潎鎼哄甫璇ュ�硷紙褰㈠ {@code 112663505}锛夈��
+     * <p>
+     * 娉ㄦ剰锛�<b>涓嶆槸</b> {@code apply_no}锛堢敵璇峰崟鍙凤紝root {@code 2.16.156.10011.1.24}锛夛紝浜岃�呬笉鍚屻��
+     */
+    private String doctorAdviceNo;
+
+    /**
+     * 妫�鏌ユ埧闂村悕绉般�傛潵婧� HIS 鎶ユ枃 {@code ZDY.roomname}锛圫050401/S050402锛夈��
+     */
+    private String roomName;
+
+    /**
+     * 娉ㄦ剰浜嬮」銆傛潵婧� HIS 鎶ユ枃 {@code ZDY.remark}锛圫050401/S050402锛夈��
+     */
+    private String remark;
 
     private String status;
     /**
@@ -143,10 +187,24 @@
 
     /**
      * 鑰愯嵂鎬э細 鏄惁澶氳��1浠h〃鏄紝0浠h〃涓嶆槸
+     * <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} 鍚嶇О鏄�"搴婅竟蹇冪數鍥�(甯歌+棰戣氨)"锛�
+     * 閭f槸**涓�涓鏌ラ」鐩�**锛涜�屾湰瀛楁琛ㄨ揪鐨勬槸**鍚屼竴椤圭洰銆佹偅鑰呴渶鍒板簥杈瑰仛**锛屼袱鑰呰涔変笉鍚屻��
+     */
+    private String isBedside;
+
+    /**
      * 浣忛櫌鍙�
      */
     private String hospitalNo;
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/checktype/CheckTypeDO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/checktype/CheckTypeDO.java
index 61af12c..efe9daf 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/checktype/CheckTypeDO.java
+++ b/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;
+
+    /**
+     * 鎺掗槦搴忓彿瑙勫垯锛堥渶姹傦細绛惧埌鏃跺浣曠粰鎮h�呮帓闃熷簭鍙凤級
+     *
+     * <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;
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/devrent/DevRentDO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/devrent/DevRentDO.java
index 5270773..2e28d35 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/devrent/DevRentDO.java
+++ b/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锛坉ev_rent 琛ㄦ棤瀵瑰簲鍒楋級锛岀敱 DevRentServiceImpl
+    // 鏌ヨ鍚庢寜 applyNo 鍥炴煡鍥炲~銆�
+    //
+    // 銆愰噸瑕併�戝繀椤绘爣璁� @TableField(exist = false)锛�
+    //   DevRentDO 浼氱敤浜� updateById / insert锛岃嫢涓嶅姞璇ユ敞瑙o紝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;
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/jobrecord/JobRecordDO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/jobrecord/JobRecordDO.java
index 44c339d..c4d4c75 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/jobrecord/JobRecordDO.java
+++ b/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 琛ㄣ��
+    // 鍥炲~閾捐矾锛歫ob_record.rentId 鈫� dev_rent.applyNo 鈫� appointment
+    // 鐢� JobRecordServiceImpl#fillPatientInfo 鎸� rentId 鎵归噺鍥炲~锛堥伩鍏� N+1锛夈��
+    //
+    // 銆愰噸瑕併�戝繀椤绘爣 @TableField(exist = false)锛氭湰 DO 浼氱敤浜� insert/updateById锛�
+    // 鑻ヤ笉鍔犳敞瑙o紝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;
 }
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queue/QueueDO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queue/QueueDO.java
index 3d13aa9..b9a2c92 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queue/QueueDO.java
+++ b/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锛宷ueue 琛ㄦ棤瀵瑰簲鍒楋紝鐢� 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;
+
+    /** 灏辫瘖鍗″彿锛坢edical_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;
 }
 
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queuesequence/QueueSequenceDO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queuesequence/QueueSequenceDO.java
index e1eab6a..b824290 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/queuesequence/QueueSequenceDO.java
+++ b/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;
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/room/RoomDO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/room/RoomDO.java
index 0ae5e35..988ed89 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/room/RoomDO.java
+++ b/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=姝e父鎺ユ敹鍊欒瘖鎮h�咃紱1=鍋滄鏂板鍊欒瘖鎮h�呫��
+     * <p>
+     * 寮�鍚悗**宸叉湁鍊欒瘖鐥呬汉缁х画鍙彿锛屼絾涓嶅啀鏂板鍊欒瘖鐥呬汉**銆�
+     * 璇ュ瓧娈典細鐢� {@code bedReload} 閫氳繃 BeanUtils 鑷姩鏄犲皠鍒�
+     * {@link cn.lihu.jh.module.ecg.service.queue.BedBO#stopReady}銆�
+     * <p>
+     * 娉ㄦ剰锛氫笌鍖荤敓"鏆傚仠"锛坽@code status=DOCTOR_PAUSE}锛夋槸**涓や釜鐙珛姒傚康**锛�
+     * 鍚庤�呯粡 {@code updateStop} 浼氬己鍒跺畬鎴愬氨璇婁腑鎮h�呭苟韪㈣蛋鍊欒瘖涓偅鑰呫��
+     */
+    private Boolean stopReady;
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/appointment/AppointmentMapper.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/appointment/AppointmentMapper.java
index 8bd4466..d61a930 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/appointment/AppointmentMapper.java
+++ b/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 鐢宠鍙峰垪琛紙璋冪敤鏂归渶淇濊瘉闈炵┖锛孧ySQL 鐨� 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);
 }
 
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/checktype/CheckTypeMapper.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/checktype/CheckTypeMapper.java
index 3a3b54f..393ff71 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/checktype/CheckTypeMapper.java
+++ b/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;")
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/devrent/DevRentMapper.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/devrent/DevRentMapper.java
index 4c4c1fc..017ba7c 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/devrent/DevRentMapper.java
+++ b/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 鎵归噺鍙栥�宨d + apply_no銆嶃��
+     * <p>
+     * 鐢ㄩ�旓細浣滀笟璁板綍鍒楄〃椤靛洖濉偅鑰呬俊鎭椂闇�瑕� `job_record.rentId 鈫� dev_rent.applyNo`銆�
+     * 鍘熷厛鐢� {@code selectById} 閫愭潯鍙栵紙N 娆℃煡璇級锛屾湰鏂规硶鏀逛负涓�娆� IN 鏌ヨ銆�
+     * <p>
+     * 鍒绘剰**鍙彇涓ゅ垪**鑰岄潪 `SELECT *`锛歞ev_rent 鍚� `pat_details` 绛� JSON 澶у瓧娈碉紝
+     * 鍥炲~鍙渶 applyNo锛屾病蹇呰鎶婃暣涓� DO 鎷夊洖鏉ャ��
+     *
+     * @param rentIdList 绉熻祦 id 鍒楄〃锛堣皟鐢ㄦ柟闇�淇濊瘉闈炵┖锛孧ySQL 鐨� 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);
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/jobrecord/JobRecordMapper.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/jobrecord/JobRecordMapper.java
index bc3d90b..dd978bb 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/jobrecord/JobRecordMapper.java
+++ b/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));
     }
 
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queue/QueueMapper.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queue/QueueMapper.java
index a9c331c..485c620 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queue/QueueMapper.java
+++ b/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 鐩稿叧缂洪櫡淇銆戞寜銆屽伐浣� + 鎮h�� + 妫�鏌ョ被鍨� + 鐘舵�併��**绮剧‘**瀹氫綅闃熷垪琛屻��
+     * <p>
+     * 鐢ㄤ簬鏇夸唬 {@link #getBedFirstQueueItemByStatus}锛氬悗鑰呭彧鎸�"宸ヤ綅 + 鐘舵�佸彇 seq_num 鏈�灏忕殑涓�鏉�"锛�
+     * 褰撳尰鐢熷厛鐐�"鏀惧純妫�鏌�"锛堜細鎶婅鎮h�呯疆涓� 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>
+     * 姣斻�宻eq_num 鏈�灏忋�嶆洿璐村悎"褰撳墠姝e湪灏辫瘖/瑁呮満鐨勯偅浣嶆偅鑰�"锛歴eq_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锛氳鐐广�屽彨鍙� / 妫�鏌ュ畬鎴愩�嶇殑鎾ら攢 ====================
+
+    /**
+     * 鎾ら攢銆屾鏌ュ畬鎴愩�嶏細鎶婃湰宸ヤ綅浠婃棩鐨�**鎸囧畾鎮h��**浠� 宸插氨璇�(40) 閫�鍥� 鍊欒瘖涓�(20)銆�
+     * <p>
+     * 蹇呴』鎸� {@code pat_id + book_check_type + 浠婃棩} 绮剧‘瀹氫綅锛�**涓嶈兘**鍙寜
+     * "宸ヤ綅 + status=40 鍙栫涓�鏉�"鈥斺�旈偅浼氬湪鏈熼棿宸插彨涓嬩竴浣嶆偅鑰呮椂璇敼浠栦汉锛堣
+     * {@code DevRentServiceImpl.routineFinishOperation} 鐨勬棦鏈夌己闄凤級銆�
+     * <p>
+     * {@code passed = 0} 鏄负浜嗚鎮h�呴噸鏂板洖鍒版甯稿�欒瘖搴忓垪锛堥潪"杩囧彿"鎬侊級銆�
+     */
+    @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>
+     * 浠呮寜宸ヤ綅+鐘舵�佸畾浣嶏紙"褰撳墠姝e湪灏辫瘖鐨勯偅涓�浣�"锛夛紝涓嶄娇鐢� 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();
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queuesequence/QueueSequenceMapper.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queuesequence/QueueSequenceMapper.java
index 2a5e34e..9ccf2a5 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/queuesequence/QueueSequenceMapper.java
+++ b/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 鎮h�呯敤锛�
+     * @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);
+
+    // =========================================================================
+    // 銆愰渶姹傦細鎺掗槦搴忓彿瑙勫垯 = 绛惧埌搴忓彿銆戣鏁板櫒锛坰eq_counter 琛級
+    //
+    // 璁捐瑕佺偣锛堜袱娆″疄娴嬭俯鍧戝悗纭畾锛屽嬁鏀瑰洖锛夛細
+    //   鈶� 鏅�氬彿涓庨鐣欏彿鐢�**涓や釜鐙珛璁℃暟鍣�** 鈥斺�� 鍗曚釜璁℃暟鍣�"杩愮畻鍚庤烦杩�"蹇呯劧閲嶅彿锛�
+    //      鏅�氭偅鑰� candidate=10 鈫� 璺宠繃棰勭暀寰� 11锛涗笅涓�涓� candidate=11 鈫� 涔熷緱 11銆�
+    //   鈶� 鎺ㄨ繘鐢ㄥ崟鏉� INSERT..ON DUPLICATE KEY UPDATE锛堝師瀛愶級锛�
+    //      璇诲洖蹇呴』涓庢帹杩涘浜�**鍚屼竴浜嬪姟**锛屽惁鍒� REPEATABLE READ 浼氳鍒版棫蹇収銆�
+    //      瀹炴祴锛歛utoCommit=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} 姝f槸"璺宠繃棰勭暀鍙锋椂棰濆 +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锛�
+    //
+    // 鍘熷洜锛歁yBatis-Plus 鐨� DataPermissionInterceptor 浼氱敤 JSqlParser 瑙f瀽姣忔潯 SQL锛�
+    //   鑰� JSqlParser 鐨� processInsert **涓嶆敮鎸� MySQL 鐨� `INSERT ... ON DUPLICATE KEY UPDATE`**
+    //   璇硶锛岀洿鎺ユ姏 UnsupportedOperationException锛涜寮傚父绌块�忓埌涓氬姟灞傦紝瀵艰嚧绛惧埌澶辫触銆�
+    //   鈥斺�� 杩欐槸銆屾鏋舵嫤鎴櫒銆嶄笌銆孧ySQL 涓撴湁璇硶銆嶇殑鍐茬獊锛屼笌 SQL 鏈韩鏄惁姝g‘鏃犲叧銆�
+    //
+    // 涓轰粈涔堝彲浠ャ�佷篃搴旇蹇界暐鏁版嵁鏉冮檺锛�
+    //   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>鏄惧紡浜嬪姟锛圔EGIN 鈫� 鎺ㄨ繘 鈫� 璇诲洖 鈫� 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);
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/room/RoomMapper.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/room/RoomMapper.java
index ae94fac..cb951c8 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/room/RoomMapper.java
+++ b/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=姝e父鎺ユ敹鍊欒瘖鎮h�咃紱1=鍋滄鏂板鍊欒瘖鎮h��
+     * @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)" +
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/ActionTypeEnum.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/ActionTypeEnum.java
index ea4424c..5943f62 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/ActionTypeEnum.java
+++ b/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锛坧acs锛� / S050402锛圗CG锛�
+ *   6.5 妫�鏌ラ绾︾姸鎬佹洿鏂帮細S050501锛坧acs锛� / S050502锛圗CG锛�
+ * </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 缂栧彿锛孍CG 涓撳睘缂栧彿灏氭湭鍚敤銆�
+ *
+ * <p>涓轰簡鍦ㄩ櫌鏂瑰垏鎹㈢紪鍙锋椂涓嶄涪娑堟伅锛岃繖閲�**鍚屾椂娉ㄥ唽涓ょ缂栧彿**锛堜富鍔ㄥ吋瀹癸級锛�
+ * 骞堕澶栧吋瀹圭敵璇峰崟鏂板/鏇存柊鐨勬棤鍚庣紑鍐欐硶 {@code S0201} / {@code S0202}
+ * 锛堟枃妗e彧瀹氫箟浜嗘棤鍚庣紑褰㈠紡锛岃�屽疄娴嬫姤鏂囧甫 {@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锛堟枃妗e畾涔夛紝褰撳墠鏈惎鐢紝涓诲姩鍏煎锛�
+
+    // ---------- 6.5 妫�鏌ラ绾︾姸鎬佹洿鏂帮紙pacs / ECG 涓ょ缂栧彿閮芥帴鏀讹級 ----------
+    S050501("S050501", "妫�鏌ラ绾︾姸鎬佷慨鏀�"),   // pacs
+    S050502("S050502", "妫�鏌ラ绾︾姸鎬佷慨鏀�");   // ECG锛堟枃妗e畾涔夛紝褰撳墠鏈惎鐢紝涓诲姩鍏煎锛�
 
     /**
      * 绫诲瀷
@@ -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锛坧acs + ECG锛� */
+    public static final List<ActionTypeEnum> APPOINTMENT_STATUS_CREATE_ACTIONS =
+            Arrays.asList(S050401, S050402);
+
+    /** 妫�鏌ラ绾︾姸鎬佹洿鏂扮被 action锛坧acs + 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);
+    }
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/AppointmentTypeEnum.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/AppointmentTypeEnum.java
index a46587a..b6e062b 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/AppointmentTypeEnum.java
+++ b/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>
+ * 鍘熷疄鐜板瓨鍦ㄤ袱澶勯棶棰橈紝宸蹭慨姝o細
+ * <ol>
+ *   <li><b>瀛楅潰鍊煎惈绌虹櫧姹℃煋</b>锛氬師瀹氫箟涓� {@code SQDKL("   1", ...)}銆�
+ *       {@code JCDJ("  3\t", ...)}锛宼ype 鍊煎墠鏈夌┖鏍笺�侀儴鍒嗗惈鍒惰〃绗︼紝
+ *       瀵艰嚧 {@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 "} 鍧囧彲姝g‘鍖归厤銆�
      *
-     * @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;
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java
index 9fe1dfb..fe54ef3 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java
+++ b/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 {
 
+    /**
+     * 鎮h�呮�у埆銆屾湭鐭ャ�嶇殑鍏滃簳鍊笺��
+     * <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 琛ㄧ亴鍏ユ斁灏�/瓒呭0绛夊叾浠栫瀹ょ殑鏁版嵁銆�
+     */
+    @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锛欼SCB銆屾槸鍚﹀簥杈广�嶉殢闃熷垪涓�璧疯惤搴擄紝渚涘睆骞�/椤甸潰灞曠ず
+            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 涓級銆�
+            // 瑙f瀽閫昏緫鎶藉埌 findBedsideFlag锛屼究浜庡崟鍏冩祴璇曘��
+            String bedsideFlag = findBedsideFlag(dataMap);
+            if (bedsideFlag != null) {
+                appointment.setIsBedside(bedsideFlag);
+            }
+
+            // 浼樺厛绾�/鍔犳�ユ爣璁帮紙zdy.jjbz锛歂=甯歌锛孞=鍔犳�ワ級
+            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
+            // 绫诲瀷瀹夊叏锛歮ethodCode 鐨� 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
+                //
+                // 渚濇嵁锛圚IS銆婁氦浜掓湇鍔¢�氱敤鎺ュ彛鏂囨。銆嬶級锛�
+                //   路 6.1 鐢宠鍗曟柊澧炴湇鍔★紙鏈」鐩墍鐢� S0201ECG锛夌殑绀轰緥涓鑺傜偣娉ㄩ噴鍗充负銆屽尰鍢盜D銆嶏細
+                //       <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 鏉°�丼0202ECG 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 浠g爜鍙兘鏄犲皠涓嶅埌锛岀洿鎺� 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][浣撴鎮h�呮鏌ラ」鐩悕绉版棤娉曟槧灏刔 checkName={}", checkName);
+                }
+            } else {
+                Integer value = resolveBookCheckTypeFromComponent2(dataMap);
+                if (value != null) {
+                    appointment.setBookCheckType(value);
+                } else {
+                    log.warn("[handleAppointmentCreate][HIS 妫�鏌ヤ唬鐮佹棤娉曟槧灏勫埌鏈湴妫�鏌ョ被鍨媇 checkType={}", checkType);
                 }
             }
 
@@ -487,16 +617,84 @@
             // 灏咥ppointmentDO杞崲涓篈ppointmentSaveReqVO骞朵繚瀛�
             AppointmentSaveReqVO saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class);
 
-            //鏍规嵁鐢宠缂栧彿鍏堟煡璇竴涓嬫槸鍚﹀瓨鍦紝濡傛灉瀛樺湪锛屽氨涓嶆柊澧炰簡
+            // 鎸夌敵璇峰崟鍙锋鏌ユ槸鍚﹀凡瀛樺湪銆�
+            // 銆愭湰娆℃敼鍔� Q5銆戝師瀹炵幇鍛戒腑宸插瓨鍦ㄦ椂鐩存帴 return锛堜笉鏇存柊锛夛紝
+            // 涓� S0202ECG / S0405 涓ゆ潯鏇存柊娴佺殑"鎵句笉鍒板垯鍏滃簳鏂板"鏂瑰悜鐩稿弽锛岃涔変笉缁熶竴銆�
+            // 鐜版敼涓猴細鍛戒腑宸插瓨鍦ㄥ垯浠ユ湰娆℃姤鏂囧唴瀹规墽琛屾洿鏂帮紝閬垮厤 HIS 閲嶅鎺ㄩ�佹椂鏃ф暟鎹笉琚慨姝c��
             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} 鐨勬煇浜涘瓧娈靛湪閮ㄥ垎鍦烘櫙涓嬩細缂哄け锛堜緥濡備綋妫�鎮h�呮棤棰勭害鏃堕棿銆�
+     * 搴婂ご灞忔秷鎭棤绉戝淇℃伅锛夈�傝嫢鐩存帴浠ユ姤鏂囧唴瀹规暣浣撹鐩栵紝浼氭妸宸叉湁鏁版嵁娓呯┖銆�
+     * 杩欐槸"閮ㄥ垎鏇存柊"璇箟锛屼笌鏇存柊娴佺殑 {@code ifPresent} 閫愬瓧娈佃祴鍊间繚鎸佷竴鑷淬��
+     * <p>
+     * 娉ㄦ剰锛氬湪 {@link AppointmentDO} 灞傚悎骞讹紙鑰岄潪 VO 灞傦級锛屽洜涓�
+     * {@code AppointmentSaveReqVO} 涓� DO 鐨勫瓧娈电被鍨嬪苟涓嶄竴鑷�
+     * 锛圴O 鐨� {@code bookDate/patBirthday} 涓� {@code LocalDateTime}銆�
+     * {@code registerDate/doctorTime} 涓� {@code java.sql.Date}锛�
+     * DO 瀵瑰簲涓� {@code LocalDate} / {@code java.util.Date}锛夈��
+     *
+     * @param target 鏈鎶ユ枃瑙f瀽鍑虹殑瀵硅薄锛堜細琚氨鍦拌ˉ鍏級
+     * @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][鏈兘瑙f瀽妫�鏌ョ被鍨嬶紝淇濈暀鍘熷�糫 applyNo={}", applyNo);
+            }
 
             // 灏咥ppointmentDO杞崲涓篈ppointmentSaveReqVO骞舵洿鏂�
             AppointmentSaveReqVO updateReqVO = BeanUtils.toBean(existingAppointment, AppointmentSaveReqVO.class);
@@ -603,111 +804,892 @@
         }
     }
 
+    /**
+     * 浠庢姤鏂� {@code component2.observationRequest.code.code} 瑙f瀽鏈湴妫�鏌ョ被鍨嬪�笺��
+     *
+     * <h3>淇鐨勭己闄�</h3>
+     * 鍘熷疄鐜颁负锛�
+     * <pre>
+     *   if (checkType != null || checkType != "")            // 鎭掍负 true锛屼笖閫昏緫搴斾负 &amp;&amp;
+     *       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 浠g爜鍏煎甯�/涓嶅甫 {@code Y} 鍓嶇紑锛堝搴斿師 substring(1) 璇箟锛夛紝
+     * 涓斾粎鍦ㄨ兘鏄犲皠鍒版湰鍦� {@code check_type} 鍊兼椂鎵嶈繑鍥烇紝鍚﹀垯杩斿洖 null 鐢辫皟鐢ㄦ柟淇濈暀鍘熷�笺��
+     *
+     * @return 鏈湴妫�鏌ョ被鍨嬪�硷紙濡� 1000锛夛紱鏃犳硶瑙f瀽鏃惰繑鍥� null
+     */
+    private Integer resolveBookCheckTypeFromComponent2(Map<String, Object> dataMap) {
+        // 绫诲瀷瀹夊叏锛歰bservationRequest.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+", "");
+        // 鍏煎锛欻IS 鎶ユ枃鍊煎舰濡� "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銆丮RI銆丏R銆佽秴澹般�侀瀵嗗害鈥︼級鐨勬鏌ョ姸鎬佷竴骞舵帹閫併��
+     * 瀹炴祴 2026-09-17锛氭湰鏈嶅姟鏀跺埌 1225 娆¤姹傦紝鍏朵腑浠� 3.5% 鐨勭敵璇峰崟鍙峰睘蹇冪數涓氬姟锛�
+     * 鍏朵綑涓烘斁灏�/瓒呭0绛夌瀹ょ殑鍗曪紙濡� {@code 2126091700001} 鑳搁儴CT骞虫壂 / 鎬ヨ瘖CT瀹わ級銆�
+     *
+     * <h3>澶勭悊绛栫暐</h3>
+     * <ol>
+     *   <li>鎻愬彇鐢宠鍗曞彿涓庢鏌ョ姸鎬佺爜锛屽苟瀵圭姸鎬佺爜鍋�**褰掍竴鍖�**锛堝幓鍓嶅闆躲�佹牎楠屽悎娉曟�э級</li>
+     *   <li>鏌ユ湰鍦伴绾﹁褰曪細
+     *     <ul>
+     *       <li><b>瀛樺湪</b> 鈫� 鏇存柊鐘舵�侊紱鐘舵�佷负 3锛堟鏌ョ櫥璁帮級鏃跺悓鏃跺啓鍏ョ櫥璁版椂闂�</li>
+     *       <li><b>涓嶅瓨鍦� + 鏄績鐢靛崟</b> 鈫� 璁� WARN 骞�**鎻掑叆鏂拌褰�**锛圦4 瑕佹眰瀹归敊鏂板锛�</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);
         }
-        // 浠巇ataMap涓彁鍙栫敵璇峰崟鍙�
-        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. 鎻愬彇骞跺綊涓�鍖栨鏌ョ姸鎬佺爜
+        //    绫诲瀷瀹夊叏锛歱rocessStep.code 鍦ㄩ儴鍒嗘姤鏂囦腑鏄� Map锛坈ode={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);
-
-        // 濡傛灉璁板綍涓嶅瓨鍦紝鍒欒皟鐢╤andleAppointmentCreate杩涜鏂板
-        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;
         }
 
-
-        // 浠巇ataMap涓彁鍙栫敵璇峰崟鍙�
-//        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骞虫壂,涓婅吂閮–T骞虫壂 / 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)) {
+            // 鍏ㄩ櫌娴佷腑鐨勫叾浠栫瀹ゅ崟鎹紝闈欓粯璺宠繃锛圖EBUG 鏃ュ織鐢� filter 杈撳嚭锛�
+            return;
         }
-        // 灏咥ppointmentDO杞崲涓篈ppointmentSaveReqVO骞舵洿鏂�
-        AppointmentSaveReqVO updateReqVO = BeanUtils.toBean(existingAppointment, AppointmentSaveReqVO.class);
-        updateAppointment(updateReqVO);
-    }
 
+        // 5. 鏄績鐢靛崟浣嗘湰鍦版棤璁板綍 鈫� 瀹归敊鏂板锛圦4 瑕佹眰锛�
+        log.warn("[handleAppointmentStateUpdate][蹇冪數涓氬姟鍗曚絾鏈湴鏃犺褰曪紝鎵ц瀹归敊鏂板] applyNo={} status={} dept={}",
+                applyNo, status, hisDeptCode);
+        insertAppointmentFromStateMessage(applyNo, status, dataMap);
+    }
 
     /**
-     * 浠巇ataMap涓彁鍙杄ncounter鏁版嵁
+     * 浠� S0405 鎶ユ枃涓瀯閫犲苟鎻掑叆涓�鏉¢绾﹁褰曘��
+     *
+     * <h3>鈿狅笍 宸茬煡鐨勬暟鎹己澶�</h3>
+     * {@code S0405} 鎶ユ枃**涓嶅寘鍚鏌ラ」鐩俊鎭�**锛堟棤 {@code component2.observationRequest.code}锛夛紝
+     * 鍥犳鏃犳硶纭畾 {@code book_check_type}锛堟鏌ョ被鍨嬶級銆傚疄娴嬬‘璁わ細鐢宠鍗曞彿鍚庣紑
+     * 涓庢鏌ョ被鍨�**鏃犲搴斿叧绯�**锛堝悓涓� {@code ...1101} 鍚庣紑鐨勮褰曞瓨鍦� 1000/100/1100 绛夊绉嶇被鍨嬶級锛�
+     * 鏁呬笉鍋氱寽娴嬶紝淇濇寔涓虹┖骞惰緭鍑� WARN锛屽緟鍚庣画 {@code S0202ECG}锛堢敵璇峰崟鏇存柊锛�
+     * 鎴栦汉宸ヨˉ褰曚慨姝c��
+     * <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());
+        }
+
+        // 鎮h�呬俊鎭紙S0405 鐨� patient.id.item 涓哄垪琛細鍩烮D/鎮h�匢D/闂ㄨ瘖鍙�/浣忛櫌鍙�/灏辫瘖娆℃暟/灏辫瘖娴佹按鍙凤級
+        // 鐢ㄧ被鍨嬪畨鍏ㄥ鑸紝閬垮厤鏌愪竴绾т笉鏄� 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")));
+            }
+            // 鎮h�呬俊鎭�
+            Map<String, Object> patient = dig(encounter, "subject", "patient");
+            if (patient != null) {
+                List<?> patIdItems = asList(patient, "id", "item");
+                // 鎮h�匢D 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);
+                }
+                // 鎬у埆锛歱at_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][娉ㄦ剰锛歋0405 鎶ユ枃涓嶅惈妫�鏌ラ」鐩紝" +
+                "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) {
-        // 浠巇ataMap涓幏鍙朿ontrolActProcess
-        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骞虫壂,涓婅吂閮–T骞虫壂,涓嬭吂閮–T骞虫壂,
+     *        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();
+    }
+
+    /** 瀹夊叏杞瓧绗︿覆锛歯ull 杩斿洖 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 鎴柇鍚庣殑鏂囨湰锛坣ull 鍘熸牱杩斿洖锛�
+     */
+    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>锛欻IS 鎶ユ枃缁� 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} 鑺傜偣锛圡ap 鎴� 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) {
+        // 绫诲瀷瀹夊叏锛歝ode 鍙兘鏄� 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} 鐨勭洿鎺ュ瓙鑺傜偣銆�
+     * 鏋勯�犳祴璇曟姤鏂囨垨瑙f瀽鏃ュ織鏃跺鏄撴悶閿欏眰绾э紝姝ゅ閫愮骇鍒ょ┖浠ヤ究瀹氫綅銆�
+     */
+    @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");
+    }
+
+    /**
+     * 妫�鏌ラ绾︾姸鎬佹柊澧�/鏇存柊
+     * 锛坅ction: {@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>锛圦4 瑕佹眰锛夛細璁板綍涓嶅瓨鍦ㄦ椂璁� WARN 骞朵緷鎹湰鎶ユ枃鎻掑叆鏂拌褰曘��</li>
+     *   <li><b>鍚敤鏈娇鐢ㄥ瓧娈�</b>锛圦7 瑕佹眰锛夛細{@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. 鑾峰彇鐢宠缂栧彿銆�
+        //    娉ㄦ剰锛氭帴鍙f枃妗e畾涔夐绾﹀彿鍦� 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 銆愬繀鍋氳繃婊ゃ�慡050401/S050501 鍚屾牱鏄�**鍏ㄩ櫌閫氱敤**鏈嶅姟锛屼細鎺ㄩ�佹斁灏�/瓒呭0绛�
+        //     闈炲績鐢电瀹ょ殑棰勭害鍗曪紙瀹炴祴 2026-09-17锛歋050401 109/256銆丼050501 4/19 涓洪潪蹇冪數锛�
+        //     妫�鏌ラ」鐩"鍙宠倶姝d晶浣�/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. 瑙f瀽棰勭害鏃堕棿锛堝彲鑳戒负绌猴紝鍘熷疄鐜颁細鐩存帴鎶涘紓甯革級
+        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"锛夛紝瑙f瀽澶辫触涓嶅奖鍝嶅叾浠栧瓧娈�
+        Integer bookTimeslot = parseBookTimeslot(zdy == null ? null : (String) zdy.get("time"));
+
+        // 4. 灏辫瘖绫诲埆 鈫� bookSrc锛堟枃妗o細actAppointment.code.code锛屼綇闄�/闂ㄨ瘖/鎬ヨ瘖浠g爜锛�
+        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");
-
-        // 瑙f瀽棰勭害鏃堕棿
-        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 琛ュ厖瀛楁锛堥殢琛ㄦ柊澧炲垪涓�璧峰惎鐢級鈥斺��
+        // 娉ㄦ剰锛歳emark 鍙兘闀胯揪鏁扮櫨瀛楃锛堝瀹炴祴蹇冪數鍥捐繍鍔ㄨ瘯楠屾敞鎰忎簨椤� 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    鍩烮D
+     *   item[1] root=2.16.156.10011.2.5.1.4    鎮h�匢D
+     *   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}
+     * 锛堟帴鍙f枃妗e畾涔夌殑棰勭害鍙凤紝瀹炴祴 {@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;
+    }
+
+    /** 渚濇嵁妫�鏌ラ绾︽姤鏂囨彃鍏ユ柊璁板綍锛圦4 瀹归敊鏂板锛� */
+    @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);
+        }
+
+        // 鎮h�呬俊鎭�
+        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 缁熶竴璧嬪�硷紝姝ゅ涓嶅啀閲嶅澶勭悊
+                // 鎮h�呭鍚�
+                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);
+                // 鐥呬汉绉戝锛坧roviderOrganization锛夆�斺�� 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);
+    }
+
+    /** 瑙f瀽 {@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;
+        }
+    }
+
+    /** 瑙f瀽 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;
+        }
+    }
+
+    /** 瀹芥澗鏁存暟瑙f瀽锛氶潪鏁板瓧鎴栫┖杩斿洖 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 瑙f瀽锛氶潪鏁板瓧鎴栫┖杩斿洖 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("鐢宠鍗曠櫥璁癮pplyNo:{},鐘舵�乻tatus:{},鏇存柊缁撴灉锛歿}", applyNo, status, i);
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/callingscreen/CallingScreenServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/callingscreen/CallingScreenServiceImpl.java
index 8a53348..0f8a490 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/callingscreen/CallingScreenServiceImpl.java
+++ b/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銆�
+        //
+        // 銆愬仴澹�с�憁apCheckTypeVsDisplayColumn 浠呭湪 getDisplayColInfo() 涓祴鍊�
+        // 锛堝0鏄庡涓� 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 閭d綅锛夝煍�
+        //
+        // 鎺掑簭鏃犻渶棰濆澶勭悊锛歡etRoomQueueByStatus 鐨� order by 宸叉妸 status in (3,5) 褰掍负鍚屼竴缁�
+        // 锛堟帓鍦ㄥ氨璇婁腑涔嬪悗銆佸�欒瘖涔嬪墠锛夛紝缁勫唴鍐嶆寜 seq_num銆乥ook_timeslot 鍗囧簭 鈥斺�� 姝e悎闇�姹傘��
+        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<>();
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/devrent/DevRentServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/devrent/DevRentServiceImpl.java
index 36557dd..c987e9d 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/devrent/DevRentServiceImpl.java
+++ b/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)"鎮h�呮椂杩斿洖 null锛堜緥濡傚尰鐢熷厛鐐逛簡"鏀惧純妫�鏌�"锛�
+        //      cancelRoutineOperation 宸叉妸璇ユ偅鑰呯疆涓� 40锛夛紝绗� 159 琛岀┖鎸囬拡 鈫� 鏁翠釜浜嬪姟鍥炴粴銆�
+        //   2) 璇激锛氬彧鎸�"宸ヤ綅 + 鐘舵�佸彇 seq_num 鏈�灏忕殑涓�鏉�"锛岃嫢鏈熼棿宸插彨浜嗕笅涓�浣嶆偅鑰咃紝
+        //      浼氭妸**涓嬩竴浣嶆偅鑰�**璇疆涓�"宸插氨璇�(40)"銆�
+        //
+        // 淇绛栫暐锛堟寜鍙潬鎬т粠楂樺埌浣庯級锛�
+        //   鈶� 浼樺厛鎸� patId + checkType 绮剧‘鍖归厤锛堝墠绔� submitForm 浼犵殑 formData 鍚繖涓や釜瀛楁锛夛紱
+        //   鈶� 閫�鍖栧埌"宸ヤ綅 + 鐘舵�� + 浠婃棩"鍙� update_time 鏈�鏂扮殑涓�鏉★紙姣� seq_num 鏈�灏忔洿璐村悎褰撳墠鎮h�咃級锛�
+        //   鈶� 浠嶅彇涓嶅埌 鈫� 璁拌鍛婂苟**璺宠繃闃熷垪鏇存柊**锛岃�屼笉鏄姏 NPE 璁╂暣涓�"妫�鏌ュ畬鎴�"澶辫触銆�
+        //      姝ゆ椂璁惧褰掕繕銆佷綔涓氳褰曠瓑浠嶄細姝e父淇濆瓨锛堟暟鎹笉涓級锛屼粎闃熷垪鐘舵�佹湭鍙樸��
+        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 鍛戒腑锛岄��鍖栦负鎸夊伐浣嶅彇鏈�杩戝氨璇婁腑鎮h��. "
+                                + "roomId={} bedNo={} reqPatId={} reqCheckType={} 瀹為檯patId={} checkType={}",
+                        createReqVO.getRoomId(), createReqVO.getBedNo(), createReqVO.getPatId(),
+                        createReqVO.getCheckType(), onStageQueueItem.getPatId(),
+                        onStageQueueItem.getBookCheckType());
+            }
+        }
+
+        // 鈶� 浠嶅彇涓嶅埌锛氳烦杩囬槦鍒楁洿鏂帮紝涓嶆姏寮傚父锛堜繚璇�"妫�鏌ュ畬鎴�"鏈韩鍙敤锛�
+        if (null == onStageQueueItem) {
+            log.warn("[routineFinish] 璇ュ伐浣嶆棤[灏辫瘖涓璢鎮h�咃紝璺宠繃闃熷垪鐘舵�佹洿鏂�. 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("鏇存柊鎴愬姛")) {
                     //闇�瑕佹牴鎹產pplyNo,灏哸ppiontment琛ㄩ噷鐨剆tatus鏀规垚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 {
                 //妫�鏌ョ被鍨嬫槸搴婅竟鐨勬垨甯歌鐨勶紝闇�瑕佹牴鎹產pplyNo,灏哸ppiontment琛ㄩ噷鐨剆tatus鏀规垚7
@@ -220,7 +274,12 @@
             log.info("webservice鐨勮繑鍥炲�间负锛歿}", s);
             if (s.contains("鏇存柊鎴愬姛")) {
                 //闇�瑕佹牴鎹產pplyNo,灏哸ppiontment琛ㄩ噷鐨剆tatus鏀规垚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锛�
+    // 鍏朵綑鎮h�呬俊鎭紙鎬у埆銆佸嚭鐢熸棩鏈熴�佺梾鍖恒�佸簥鍙枫�佺數璇濄�佹潵婧愩�佸氨璇婂崱鍙枫��
+    // 鐧昏鏃堕棿銆佸紑鍗曞尰甯堛�佸紑鍗曟棩鏈熴�佸鑰愯嵂锛夐兘鍦� 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);
+    }
+
+    /**
+     * 鎶婇绾﹀崟涓殑鎮h�呬俊鎭鍒跺埌 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());
     }
 
     // 纭垂澶勭悊
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/jobrecord/JobRecordServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/jobrecord/JobRecordServiceImpl.java
index 17b5515..a5f0ae4 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/jobrecord/JobRecordServiceImpl.java
+++ b/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锛歫ob_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) {
 
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/BedBO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/BedBO.java
index 1789de9..4b5ac39 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/BedBO.java
+++ b/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 = 璇ュ伐浣嶆殏鍋滄帴鏀�**鏂扮殑**鍊欒瘖鎮h�咃紙宸叉湁鐨勫�欒瘖鎮h�呬粛鍙甯稿彨鍙凤級锛�
+     * false = 姝e父鎺ユ敹銆�
+     * <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);
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueService.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueService.java
index 83f7e59..3fd8f0c 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueService.java
+++ b/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 鍋氱簿纭畾浣嶏紝閬垮厤璇敼鍏朵粬鎮h�呫��
+     *
+     * @return 鍙楀奖鍝嶈鏁帮紱0 琛ㄧず鏈壘鍒拌鎮h�呬粖鏃ョ殑宸插畬鎴愯褰�
+     */
+    Integer undoFinishPatient(Long roomId, String bedNo, String patId, Integer checkType);
+
+    /**
+     * 鎾ら攢銆岃鐐瑰彨鍙枫�嶏細鎶婃湰宸ヤ綅褰撳墠 灏辫瘖涓�(30) 鐨勬偅鑰呴��鍥� 鍊欒瘖涓�(20)銆�
+     *
+     * @return 鍙楀奖鍝嶈鏁帮紱0 琛ㄧず褰撳墠鏃犲氨璇婁腑鎮h��
+     */
+    Integer undoCallPatient(Long roomId, String bedNo);
+
+    /**
+     * 鍙栨湰宸ヤ綅浠婃棩**鏈�杩戜竴浣嶅凡瀹屾垚**鐨勬偅鑰咃紙渚涚晫闈㈡彁绀哄彲鎾ら攢瀵硅薄锛夈��
+     */
+    QueueDO getBedLastFinishedQueueItem(Long roomId, String bedNo);
+
+    // ==================== 闇�姹�3锛氬仠姝㈠�欒瘖寮�鍏� ====================
+
+    /**
+     * 璁剧疆銆屽仠姝㈠�欒瘖銆嶅紑鍏筹紙鎸佷箙鍖栧埌 {@code clinic_room.stop_ready}锛夈��
+     * <p>
+     * 寮�鍚悗锛�**宸叉湁鍊欒瘖鐥呬汉缁х画鍙彿锛屼絾涓嶅啀鏂板鍊欒瘖鐥呬汉**锛�
+     * 鍏抽棴鍚庢仮澶嶆甯告帴鏀躲��
+     *
+     * @param stop true=鍋滄鍊欒瘖锛沠alse=鎭㈠
+     * @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} 浠庨绾﹀崟锛坅ppointment锛夊洖濉槦鍒楀璞$殑鎮h�呬俊鎭��
+     * <p>
+     * queue 琛ㄥ彧瀛樹簡鎮h�呯紪鍙�/濮撳悕锛屽叾浣欙紙鎬у埆銆佸嚭鐢熸棩鏈熴�佺梾鍖恒�佸簥鍙枫�佺數璇濄�佹潵婧愩��
+     * 灏辫瘖鍗″彿銆佺櫥璁版椂闂淬�佸紑鍗曞尰甯堛�佸紑鍗曟棩鏈熴�佸鑰愯嵂锛夐兘鍦� appointment 琛ㄣ��
+     * <p>
+     * 涔嬫墍浠ュ澶栨毚闇诧細澶у睆/璇婇棿灞忥紙{@code CallingScreenServiceImpl}锛夌洿鎺ユ煡
+     * {@code queueMapper}锛屼笉缁忚繃鏈� Service 鐨勬煡璇㈡柟娉曪紝闇�瑕佹樉寮忚皟鐢ㄦ湰鏂规硶琛ラ綈銆�
+     * 涓嶈ˉ榻愬垯澶у睆/璇婇棿灞忕殑鎮h�呬俊鎭彧鏈夊鍚嶏紙鎬у埆/鐥呭尯/搴婂彿绛夊叏涓虹┖锛夈��
+     *
+     * @param queueDOList 闃熷垪瀵硅薄鍒楄〃锛堢┖/null 瀹夊叏锛�
+     */
+    void fillAppointmentInfo(List<QueueDO> queueDOList);
 }
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java
index 3c99e02..4b6f9e4 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java
+++ b/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锛夈�俼ueue 琛ㄥ凡鏈夎鍒楋紝
+            // 浣嗗銆�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 鍙e緞缁熶竴銆戣繃鍙� = 宸茶繃鍙�(5) + 宸茶繃鍙�-鎺掗槦(3)銆�
+                // 鍘熷厛鍙畻 5锛岃�屽垪琛ㄤ笌灞忓箷閮藉惈 3锛屽鑷�"杩囧彿"鏁板瓧姣斿疄闄呭皯銆�
+                int cur = patientStatisticVO.getPassedNum() == null ? 0 : patientStatisticVO.getPassedNum();
+                patientStatisticVO.setPassedNum(cur + item.getTotalInStatus());
             }
         });
 
         // 缁熻 璇ュ伐浣嶇被鍨嬬殑銆愭帓闃熶腑銆戜汉鍛樻暟閲�
+        // 銆怮7 纭銆戞澶勫埢鎰忕粺璁�**鍏ㄩ」鐩�**锛堣宸ヤ綅鎵�鍚鏌ョ被鍨嬶級鐨�"鎺掗槦涓�"鎬绘暟锛�
+        // 璇箟涓�"鍏ㄩ櫌杩樻湁澶氬皯浜虹瓑鐫�鍋氳繖绫绘鏌�"锛屼笌"鏈伐浣嶄竴鐪煎彲瑙佺殑鍊欒瘖浜烘暟"浜掕ˉ銆�
+        // 涓斿凡琛� 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;
+        // 銆愰槻寰°�慶heckTypes 涓虹┖鏃朵笉鑳芥嫾 `book_check_type in ()`锛圡ySQL 璇硶閿欒锛夈��
+        // 瀹炴祴璇ュ満鏅細璁╃粺璁℃帴鍙� 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 鍙e緞缁熶竴銆戣繃鍙� = 宸茶繃鍙�(5) + 宸茶繃鍙�-鎺掗槦(3)銆�
+                //
+                // 涓� getPatientStatistic 淇濇寔鍚屼竴鍙e緞銆傚師瀹炵幇鍙垽 PASSED(5)锛�
+                // 鑰岄鐢ㄧ晫闈㈢殑鍒楄〃/灞忓箷閮藉惈 status=3锛屽鑷淬�岃繃鍙枫�嶆暟瀛楁瘮瀹為檯灏�
+                // 鈥斺�� 杩欐鏄敤鎴峰弽棣堢殑銆岀粺璁′笌瀹為檯涓嶇銆嶃��
+                //
+                // 鍙︼細鍘熷疄鐜扮敤 setPassedNum(item.getTotalInStatus())锛�**瑕嗙洊**鑰岄潪绱姞锛夛紝
+                // 鍥� SQL 鏄� group by status锛宻tatus=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;
+        // 銆愰槻寰°�慶heckTypes 涓虹┖鏃朵笉鑳芥嫾 `book_check_type in ()`锛圡ySQL 璇硶閿欒锛夛紝
+        // 瀹炴祴璇ュ満鏅細璁╃粺璁℃帴鍙� 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 琛ㄧず娌℃壘鍒拌鎮h�呬粖鏃ョ殑宸插畬鎴愯褰曪級
+     */
+    @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 琛ㄧず褰撳墠娌℃湁灏辫瘖涓殑鎮h�咃級
+     */
+    @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 鍙e緞缁熶竴銆戣ˉ涓� PASSED_WAITING(3)銆屽凡杩囧彿-鎺掗槦銆嶃��
+        // 鍘熷厛鍒楄〃鍙惈 5锛岃�屽ぇ灞�/璇婇棿灞忔煡璇㈠惈 3锛屽鑷村悓涓�鎮h�呭湪涓嶅悓鐣岄潰鍑虹幇涓庡惁涓嶄竴鑷达紱
+        // 缁熻渚т篃灏� 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 (...)`
+        // 锛坓etRoomQueueByStatus 鐢氳嚦**涓嶅惈 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}锛夌殑妫�鏌ラ」鐩殑鎮h�呫��
+     *
+     * <p>鐢ㄤ簬銆岃澶囬鐢� / 瑁呮満銆嶅彇鏁帮細杩欎簺宸ヤ綅鍙簲澶勭悊闇�瑕侀鐢ㄨ澶囩殑妫�鏌ラ」鐩紝
+     * 鍚﹀垯浼氬嚭鐜板父瑙勫績鐢靛浘绛夋偅鑰呮贩鍏ヨ澶囨祦绋嬨��
+     *
+     * <p>閰嶇疆寮傚父锛堟煡涓嶅埌妫�鏌ラ」鐩級鏃�**杩斿洖鍘熷垪琛�**锛屽畞鍙鏄剧ず涔熶笉瑕佹妸鎮h��"钘忚捣鏉�"銆�
+     */
+    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] 鏈厤缃换浣昜闇�瑕佽澶囬鐢╙鐨勬鏌ラ」鐩紝璺宠繃杩囨护浠ュ厤鎮h�呭叏閮ㄤ笉鍙");
+            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] 杩囨护鎺変笉闇�瑕佽澶囬鐢ㄧ殑鎮h��. patId={} 妫�鏌ラ」鐩�={} 鐘舵��={}",
+                        item.getPatId(), item.getBookCheckType(), item.getStatus());
+            }
+        }
+        return filtered;
     }
 
     private RoomDO getRoomDO(Long roomId, String bedNo) {
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceTxFunctions.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceTxFunctions.java
index da8629e..7acf662 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceTxFunctions.java
+++ b/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}锛氳宸ヤ綅**涓嶅啀鏂板**鍊欒瘖鎮h�咃紙绉诲嚭鍒嗘祦闃熷垪锛夛紝
+     * 浣�**宸叉湁鍊欒瘖鎮h�呬粛鍙甯稿彨鍙�**锛坽@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_闇�姹傚崌绾姹囨�籗QL.sql"
+                    + "锛坈linic_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锛堝紑璇�/閲嶅惎/璇婂閲嶇疆锛夊悗寮�鍏充細澶辨晥銆佸張寮�濮嬫敹鐥呬汉銆�
+            // 娉ㄦ剰锛歴topReady 浠呴樆姝�**鏂板**鍊欒瘖鎮h�咃紝宸叉湁鍊欒瘖鎮h�呬粛鍙甯稿彨鍙�
+            // 锛坣extPatient 涓嶆鏌ヨ寮�鍏筹級銆�
+            if (BedStatusEnum.DOCTOR_ON.getStatus() == item.getStatus()
+                    && !Boolean.TRUE.equals(item.getStopReady())) {
                 addBedToRoutingQueue(item);
             }
         });
@@ -367,8 +433,13 @@
 
         BedBO bedBO = getBedQueueBO(roomId, bedNo);
 
+        // 銆愰渶姹�3銆戙�屽仠姝㈠�欒瘖銆嶆椂涓嶅啀鎶娿�愬凡鍙洖銆戞偅鑰呮斁鍏ュ�欒瘖鍖恒��
+        // 娉ㄦ剰锛氳繖**涓嶅奖鍝�**宸叉湁鍊欒瘖鎮h�呰姝e父鍙彿锛坣extPatient 涓嶆鏌ユ湰寮�鍏筹級锛�
+        // 涔熶笉褰卞搷鍖荤敓瀵瑰叿浣撴偅鑰呯殑"鍙洖"鎿嶄綔鏈韩锛堝彧褰卞搷鍏惰嚜鍔ㄨ繘鍏ュ�欒瘖鐨勮ˉ浣嶏級銆�
+        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 妫�鏌�
+        // 锛坔urryupAllBed 涓� hurryupOneBed 閮芥湁锛夛紝瀵艰嚧鎵嬪姩"闂瘖"鍚庯紝
+        // 鍙鏈変汉棰勭害纭 / 鍔犳�ワ紝鎮h�呬粛浼氳鎺ㄨ繘鍊欒瘖鍖恒��
+        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 浼氳鍏朵綑宸ヤ綅涔熸敹涓嶅埌鎮h�咃紙楗挎锛夈��
+            // 杩欓噷 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銆戙�屽仠姝㈠�欒瘖銆嶇殑宸ヤ綅涓嶅啀鏂板鍊欒瘖鎮h�呫��
+        // 宸叉湁鍊欒瘖鎮h�呬粛鍙甯稿彨鍙凤紙鏈柟娉曞彧璐熻矗"琛ラ綈鍊欒瘖"锛屼笉鍙備笌鍙彿锛夈��
+        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銆佸尰鐢熸仮澶嶃�乥edReload銆�
+        // 鎴栨墜鍔ㄦ仮澶嶅紑鍏筹級璇曞浘鍔犲叆锛岄兘浼氳鎷掔粷锛屼粠鑰屼繚璇侊細
+        //   路 宸叉湁鍊欒瘖鎮h�呬粛鍙甯稿彨鍙凤紙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()); //[鍊欒瘖涓璢
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceService.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceService.java
index a8ff0ff..366e5d5 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceService.java
+++ b/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 鍒嗛厤缁欒鎮h�呯殑鎺掗槦搴忓彿锛堜粠 1 寮�濮嬶級
+     */
+    Integer distributeSeqNoByRule(Integer checkType, Integer timeslot,
+                                 Integer existingSeqNo, boolean urgent);
+
     void initNumber();
 }
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceServiceImpl.java
index d86afda..ebfc4db 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queuesequence/QueueSequenceServiceImpl.java
+++ b/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} 鍩轰簬浠g悊锛�**鍚岀被鑷皟鐢ㄤ笉浼氳蛋浠g悊 鈬� 娉ㄨВ瀹屽叏涓嶇敓鏁�**銆�
+     * 浜庢槸"鎺ㄨ繘"涓�"璇诲洖"浼氬悇鑷嫭绔嬫彁浜わ紝鍦� REPEATABLE READ 涓嬭鍒扮殑鍙兘鏄棫蹇収
+     * 鈬� **骞跺彂閲嶅彿**锛堟棭鍏堝疄娴嬶細鐙珛浜嬪姟鍙湁 75/160 涓敮涓�鍊硷紱鍚屼簨鍔′负 160/160锛夈��
+     *
+     * 鏁呰繖閲岀敤 {@link TransactionTemplate} **鏄惧紡**寮�鍚簨鍔★紝涓嶄緷璧� AOP 浠g悊锛屽繀鐒剁敓鏁堛��
+     * 浼犳挱琛屼负鐢ㄩ粯璁ょ殑 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}
+     * 鏈熸湜鍙懡涓竴琛岋紱涓�鏃﹀嚭鐜伴噸澶嶈锛屽彇鍙蜂細鍛戒腑涓嶇‘瀹氱殑涓�琛屻��
+     * 杩欓噷鍦ㄧ淮鎶ゅ叆鍙e鎷︽埅锛岀粰鍑烘槑纭彁绀鸿�屼笉鏄闂杩涘叆鍙栧彿闃舵銆�
+     */
     @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={} "
+                            + "宸插瓨鍦╥d={} 鏈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鍒嗛挓鐨勯棿闅斿垝鍒嗛绾︽椂闂存锛孒IS鐨勯绾︽椂闂存鍙兘鏄�30鍒嗛挓鎴�60鍒嗛挓
-            Integer nextTimeslot = getNextTimeSlot(timeslot, checkType);
+            // 銆愪慨澶嶃�屾椂娈典笉鍏�/宸叉弧瀵艰嚧娌℃硶绛惧埌銆嶃��
+            // 鍘熼�昏緫锛氬彧鍙�"瀛楀吀閲岀殑绱ч偦涓嬩竴涓椂娈�"锛屼笖瑕佹眰璇ユ椂娈靛湪 queue_sequence 涓瓨鍦ㄣ��
+            // 鐜板疄闂锛堝疄娴嬶級锛�
+            //   路 瀛楀吀 ecg_book_timeslot 鏈� 21 涓椂娈碉紝浣� queue_sequence 涓� checkType=400
+            //     鍙湁 13 涓�乧heckType=100 鍙湁 17 涓� 鈥斺�� 閮ㄥ垎鏃舵鏍规湰娌℃湁鍙锋睜琛岋紱
+            //   路 HIS 浼氫笅鍙� 60 鍒嗛挓绮掑害鐨� bookTimeslot锛堝 10001100锛夛紝瀛楀吀閲屾病鏈夎鍊硷紝
+            //     getNextTimeSlot 鐩存帴 return null锛�
+            //   路 涓埆鏃舵瀹归噺寰堝皬锛堝钩鏉胯繍鍔� timeslot_book_num=3锛夛紝寰堝揩閿�瀹屻��
+            // 涓夎�呬换涓�鍛戒腑 鈫� 鎶� QUEUE_SEQUENCE_TIMESLOT_FULL 鈫� **鎮h�呮病娉曠鍒�**銆�
+            //
+            // 鐜板湪鏀逛负锛�**鍚戝悗鏈�澶氭壘 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:
+                // 鈶� 棰勭害鍙凤細棰勭害绯荤粺宸茬粰鍙峰垯鐩存帴鐢紱鍚﹀垯鍥為��鍒扮鍒板簭鍙凤紙閬垮厤鎮h�呮嬁涓嶅埌鍙凤級
+                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);
+        }
+    }
+
+    /**
+     * 瑙f瀽鏌愭鏌ョ被鍨嬮厤缃殑鎺掗槦搴忓彿瑙勫垯锛涙煡涓嶅埌閰嶇疆鎴栨湭閰嶇疆鏃惰繑鍥為粯璁わ紙鏃舵鍙凤級銆�
+     */
+    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 瑙f瀽瀹冨苟
+     *       **鎶� UnsupportedOperationException**锛圝SqlParser 涓嶆敮鎸佽 MySQL 涓撴湁璇硶锛夛紝
+     *       琛ㄧ幇涓�**棰勭害纭鐩存帴 500** 鈥斺�� 璇﹁ Mapper 涓婄殑娉ㄩ噴銆�</li>
+     *   <li><b>鎺ㄨ繘涓庤鍥炲繀椤诲悓浜嬪姟</b>锛歁ySQL 榛樿 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} 涓嶅湪瀛楀吀涓椂锛圚IS 浼氫笅鍙� 60 鍒嗛挓绮掑害鍊硷紝
+     *       濡� 10001100锛岃�屽瓧鍏稿彧鏈� 30 鍒嗛挓绮掑害锛夌洿鎺� {@code return null}銆�
+     *       鏈疄鐜版敼涓�**鍙栧瓧鍏镐腑绗竴涓櫄浜� {@code timeslot} 鐨勬椂娈�**缁х画鍚戝悗鎵撅紝
+     *       浠庤�屼粛鑳戒负杩欑被鎮h�呭垎閰嶅彿銆�</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;
+    }
+
+    /** 瀹夊叏瑙f瀽瀛楀吀鍊硷紙褰㈠ "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()
diff --git a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/mail/MailSendApi.java b/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/mail/MailSendApi.java
deleted file mode 100644
index 4097405..0000000
--- a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/mail/MailSendApi.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package cn.lihu.jh.module.system.api.mail;
-
-import cn.lihu.jh.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
-
-import javax.validation.Valid;
-
-/**
- * 閭鍙戦�� API 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MailSendApi {
-
-    /**
-     * 鍙戦�佸崟鏉¢偖绠辩粰 Admin 鐢ㄦ埛
-     *
-     * 鍦� mail 涓虹┖鏃讹紝浣跨敤 userId 鍔犺浇瀵瑰簲 Admin 鐨勯偖绠�
-     *
-     * @param reqDTO 鍙戦�佽姹�
-     * @return 鍙戦�佹棩蹇楃紪鍙�
-     */
-    Long sendSingleMailToAdmin(@Valid MailSendSingleToUserReqDTO reqDTO);
-
-    /**
-     * 鍙戦�佸崟鏉¢偖绠辩粰 Member 鐢ㄦ埛
-     *
-     * 鍦� mail 涓虹┖鏃讹紝浣跨敤 userId 鍔犺浇瀵瑰簲 Member 鐨勯偖绠�
-     *
-     * @param reqDTO 鍙戦�佽姹�
-     * @return 鍙戦�佹棩蹇楃紪鍙�
-     */
-    Long sendSingleMailToMember(@Valid MailSendSingleToUserReqDTO reqDTO);
-
-}
diff --git a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java b/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java
deleted file mode 100644
index dd45bab..0000000
--- a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package cn.lihu.jh.module.system.api.mail.dto;
-
-import lombok.Data;
-
-import javax.validation.constraints.Email;
-import javax.validation.constraints.NotNull;
-import java.util.Map;
-
-/**
- * 閭欢鍙戦�� Request DTO
- *
- * @author wangjingqi
- */
-@Data
-public class MailSendSingleToUserReqDTO {
-
-    /**
-     * 鐢ㄦ埛缂栧彿
-     */
-    private Long userId;
-    /**
-     * 閭
-     */
-    @Email
-    private String mail;
-
-    /**
-     * 閭欢妯℃澘缂栧彿
-     */
-    @NotNull(message = "閭欢妯℃澘缂栧彿涓嶈兘涓虹┖")
-    private String templateCode;
-    /**
-     * 閭欢妯℃澘鍙傛暟
-     */
-    private Map<String, Object> templateParams;
-
-}
diff --git a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/NotifyMessageSendApi.java b/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/NotifyMessageSendApi.java
deleted file mode 100644
index 87ba41b..0000000
--- a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/NotifyMessageSendApi.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package cn.lihu.jh.module.system.api.notify;
-
-import cn.lihu.jh.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
-
-import javax.validation.Valid;
-
-/**
- * 绔欏唴淇″彂閫� API 鎺ュ彛
- *
- * @author xrcoder
- */
-public interface NotifyMessageSendApi {
-
-    /**
-     * 鍙戦�佸崟鏉$珯鍐呬俊缁� Admin 鐢ㄦ埛
-     *
-     * @param reqDTO 鍙戦�佽姹�
-     * @return 鍙戦�佹秷鎭� ID
-     */
-    Long sendSingleMessageToAdmin(@Valid NotifySendSingleToUserReqDTO reqDTO);
-
-    /**
-     * 鍙戦�佸崟鏉$珯鍐呬俊缁� Member 鐢ㄦ埛
-     *
-     * @param reqDTO 鍙戦�佽姹�
-     * @return 鍙戦�佹秷鎭� ID
-     */
-    Long sendSingleMessageToMember(@Valid NotifySendSingleToUserReqDTO reqDTO);
-
-}
diff --git a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/dto/NotifySendSingleToUserReqDTO.java b/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/dto/NotifySendSingleToUserReqDTO.java
deleted file mode 100644
index 122d94a..0000000
--- a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/dto/NotifySendSingleToUserReqDTO.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package cn.lihu.jh.module.system.api.notify.dto;
-
-import lombok.Data;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-import java.util.Map;
-
-/**
- * 绔欏唴淇″彂閫佺粰 Admin 鎴栬�� Member 鐢ㄦ埛
- *
- * @author xrcoder
- */
-@Data
-public class NotifySendSingleToUserReqDTO {
-
-    /**
-     * 鐢ㄦ埛缂栧彿
-     */
-    @NotNull(message = "鐢ㄦ埛缂栧彿涓嶈兘涓虹┖")
-    private Long userId;
-
-    /**
-     * 绔欏唴淇℃ā鏉跨紪鍙�
-     */
-    @NotEmpty(message = "绔欏唴淇℃ā鏉跨紪鍙蜂笉鑳戒负绌�")
-    private String templateCode;
-
-    /**
-     * 绔欏唴淇℃ā鏉垮弬鏁�
-     */
-    private Map<String, Object> templateParams;
-}
diff --git a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/dto/NotifyTemplateReqDTO.java b/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/dto/NotifyTemplateReqDTO.java
deleted file mode 100644
index dd65e08..0000000
--- a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/api/notify/dto/NotifyTemplateReqDTO.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package cn.lihu.jh.module.system.api.notify.dto;
-
-import cn.lihu.jh.framework.common.enums.CommonStatusEnum;
-import cn.lihu.jh.framework.common.validation.InEnum;
-import lombok.Data;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-
-@Data
-public class NotifyTemplateReqDTO {
-
-    @NotEmpty(message = "妯$増鍚嶇О涓嶈兘涓虹┖")
-    private String name;
-
-    @NotNull(message = "妯$増缂栫爜涓嶈兘涓虹┖")
-    private String code;
-
-    @NotNull(message = "妯$増绫诲瀷涓嶈兘涓虹┖")
-    private Integer type;
-
-    @NotEmpty(message = "鍙戦�佷汉鍚嶇О涓嶈兘涓虹┖")
-    private String nickname;
-
-    @NotEmpty(message = "妯$増鍐呭涓嶈兘涓虹┖")
-    private String content;
-
-    @NotNull(message = "鐘舵�佷笉鑳戒负绌�")
-    @InEnum(value = CommonStatusEnum.class, message = "鐘舵�佸繀椤绘槸 {value}")
-    private Integer status;
-
-    private String remark;
-
-}
diff --git a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/enums/mail/MailSendStatusEnum.java b/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/enums/mail/MailSendStatusEnum.java
deleted file mode 100644
index 301e6b6..0000000
--- a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/enums/mail/MailSendStatusEnum.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package cn.lihu.jh.module.system.enums.mail;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * 閭欢鐨勫彂閫佺姸鎬佹灇涓�
- *
- * @author wangjingyi
- * @since 2022/4/10 13:39
- */
-@Getter
-@AllArgsConstructor
-public enum MailSendStatusEnum {
-
-    INIT(0), // 鍒濆鍖�
-    SUCCESS(10), // 鍙戦�佹垚鍔�
-    FAILURE(20), // 鍙戦�佸け璐�
-    IGNORE(30), // 蹇界暐锛屽嵆涓嶅彂閫�
-    ;
-
-    private final int status;
-
-}
diff --git a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/enums/notify/NotifyTemplateTypeEnum.java b/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/enums/notify/NotifyTemplateTypeEnum.java
deleted file mode 100644
index 49cd395..0000000
--- a/jh-module-system/jh-module-system-api/src/main/java/cn/lihu/jh/module/system/enums/notify/NotifyTemplateTypeEnum.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package cn.lihu.jh.module.system.enums.notify;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * 閫氱煡妯℃澘绫诲瀷鏋氫妇
- *
- * @author HUIHUI
- */
-@Getter
-@AllArgsConstructor
-public enum NotifyTemplateTypeEnum {
-
-    /**
-     * 绯荤粺娑堟伅
-     */
-    SYSTEM_MESSAGE(2),
-    /**
-     * 閫氱煡娑堟伅
-     */
-    NOTIFICATION_MESSAGE(1);
-
-    private final Integer type;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/api/mail/MailSendApiImpl.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/api/mail/MailSendApiImpl.java
deleted file mode 100644
index 82058e2..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/api/mail/MailSendApiImpl.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package cn.lihu.jh.module.system.api.mail;
-
-import cn.lihu.jh.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
-import cn.lihu.jh.module.system.service.mail.MailSendService;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import javax.annotation.Resource;
-
-/**
- * 閭欢鍙戦�� API 瀹炵幇绫�
- *
- * @author wangjingyi
- */
-@Service
-@Validated
-public class MailSendApiImpl implements MailSendApi {
-
-    @Resource
-    private MailSendService mailSendService;
-
-    @Override
-    public Long sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) {
-        return mailSendService.sendSingleMailToAdmin(reqDTO.getMail(), reqDTO.getUserId(),
-                reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
-    }
-
-    @Override
-    public Long sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) {
-        return mailSendService.sendSingleMailToMember(reqDTO.getMail(), reqDTO.getUserId(),
-                reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/api/notify/NotifyMessageSendApiImpl.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/api/notify/NotifyMessageSendApiImpl.java
deleted file mode 100644
index af01051..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/api/notify/NotifyMessageSendApiImpl.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package cn.lihu.jh.module.system.api.notify;
-
-import cn.lihu.jh.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
-import cn.lihu.jh.module.system.service.notify.NotifySendService;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-
-/**
- * 绔欏唴淇″彂閫� API 瀹炵幇绫�
- *
- * @author xrcoder
- */
-@Service
-public class NotifyMessageSendApiImpl implements NotifyMessageSendApi {
-
-    @Resource
-    private NotifySendService notifySendService;
-
-    @Override
-    public Long sendSingleMessageToAdmin(NotifySendSingleToUserReqDTO reqDTO) {
-        return notifySendService.sendSingleNotifyToAdmin(reqDTO.getUserId(),
-                reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
-    }
-
-    @Override
-    public Long sendSingleMessageToMember(NotifySendSingleToUserReqDTO reqDTO) {
-        return notifySendService.sendSingleNotifyToMember(reqDTO.getUserId(),
-                reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailAccountController.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailAccountController.java
deleted file mode 100644
index 6c31137..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailAccountController.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail;
-
-
-import cn.lihu.jh.framework.common.pojo.CommonResult;
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.common.util.object.BeanUtils;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.account.MailAccountRespVO;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.account.MailAccountSaveReqVO;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.account.MailAccountSimpleRespVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailAccountDO;
-import cn.lihu.jh.module.system.service.mail.MailAccountService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-import java.util.List;
-
-import static cn.lihu.jh.framework.common.pojo.CommonResult.success;
-
-@Tag(name = "绠$悊鍚庡彴 - 閭璐﹀彿")
-@RestController
-@RequestMapping("/system/mail-account")
-public class MailAccountController {
-
-    @Resource
-    private MailAccountService mailAccountService;
-
-    @PostMapping("/create")
-    @Operation(summary = "鍒涘缓閭璐﹀彿")
-    @PreAuthorize("@ss.hasPermission('system:mail-account:create')")
-    public CommonResult<Long> createMailAccount(@Valid @RequestBody MailAccountSaveReqVO createReqVO) {
-        return success(mailAccountService.createMailAccount(createReqVO));
-    }
-
-    @PutMapping("/update")
-    @Operation(summary = "淇敼閭璐﹀彿")
-    @PreAuthorize("@ss.hasPermission('system:mail-account:update')")
-    public CommonResult<Boolean> updateMailAccount(@Valid @RequestBody MailAccountSaveReqVO updateReqVO) {
-        mailAccountService.updateMailAccount(updateReqVO);
-        return success(true);
-    }
-
-    @DeleteMapping("/delete")
-    @Operation(summary = "鍒犻櫎閭璐﹀彿")
-    @Parameter(name = "id", description = "缂栧彿", required = true)
-    @PreAuthorize("@ss.hasPermission('system:mail-account:delete')")
-    public CommonResult<Boolean> deleteMailAccount(@RequestParam Long id) {
-        mailAccountService.deleteMailAccount(id);
-        return success(true);
-    }
-
-    @GetMapping("/get")
-    @Operation(summary = "鑾峰緱閭璐﹀彿")
-    @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('system:mail-account:query')")
-    public CommonResult<MailAccountRespVO> getMailAccount(@RequestParam("id") Long id) {
-        MailAccountDO account = mailAccountService.getMailAccount(id);
-        return success(BeanUtils.toBean(account, MailAccountRespVO.class));
-    }
-
-    @GetMapping("/page")
-    @Operation(summary = "鑾峰緱閭璐﹀彿鍒嗛〉")
-    @PreAuthorize("@ss.hasPermission('system:mail-account:query')")
-    public CommonResult<PageResult<MailAccountRespVO>> getMailAccountPage(@Valid MailAccountPageReqVO pageReqVO) {
-        PageResult<MailAccountDO> pageResult = mailAccountService.getMailAccountPage(pageReqVO);
-        return success(BeanUtils.toBean(pageResult, MailAccountRespVO.class));
-    }
-
-    @GetMapping({"/list-all-simple", "simple-list"})
-    @Operation(summary = "鑾峰緱閭璐﹀彿绮剧畝鍒楄〃")
-    public CommonResult<List<MailAccountSimpleRespVO>> getSimpleMailAccountList() {
-        List<MailAccountDO> list = mailAccountService.getMailAccountList();
-        return success(BeanUtils.toBean(list, MailAccountSimpleRespVO.class));
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailLogController.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailLogController.java
deleted file mode 100644
index 75b703f..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailLogController.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail;
-
-import cn.lihu.jh.framework.common.pojo.CommonResult;
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.common.util.object.BeanUtils;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.log.MailLogRespVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailLogDO;
-import cn.lihu.jh.module.system.service.mail.MailLogService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-import static cn.lihu.jh.framework.common.pojo.CommonResult.success;
-
-@Tag(name = "绠$悊鍚庡彴 - 閭欢鏃ュ織")
-@RestController
-@RequestMapping("/system/mail-log")
-public class MailLogController {
-
-    @Resource
-    private MailLogService mailLogService;
-
-    @GetMapping("/page")
-    @Operation(summary = "鑾峰緱閭鏃ュ織鍒嗛〉")
-    @PreAuthorize("@ss.hasPermission('system:mail-log:query')")
-    public CommonResult<PageResult<MailLogRespVO>> getMailLogPage(@Valid MailLogPageReqVO pageVO) {
-        PageResult<MailLogDO> pageResult = mailLogService.getMailLogPage(pageVO);
-        return success(BeanUtils.toBean(pageResult, MailLogRespVO.class));
-    }
-
-    @GetMapping("/get")
-    @Operation(summary = "鑾峰緱閭鏃ュ織")
-    @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('system:mail-log:query')")
-    public CommonResult<MailLogRespVO> getMailTemplate(@RequestParam("id") Long id) {
-        MailLogDO log = mailLogService.getMailLog(id);
-        return success(BeanUtils.toBean(log, MailLogRespVO.class));
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailTemplateController.http b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailTemplateController.http
deleted file mode 100644
index f3c47f5..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailTemplateController.http
+++ /dev/null
@@ -1,14 +0,0 @@
-### 璇锋眰 /system/mail-template/send-mail 鎺ュ彛 => 鎴愬姛
-POST {{baseUrl}}/system/mail-template/send-mail
-Authorization: Bearer {{token}}
-Content-Type: application/json
-tenant-id: {{adminTenentId}}
-
-{
-  "templateCode": "test_01",
-  "mail": "7685413@qq.com",
-  "templateParams": {
-    "key01": "value01",
-    "key02": "value02"
-  }
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailTemplateController.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailTemplateController.java
deleted file mode 100644
index 087d513..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/MailTemplateController.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail;
-
-import cn.lihu.jh.framework.common.pojo.CommonResult;
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.common.util.object.BeanUtils;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.template.*;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailTemplateDO;
-import cn.lihu.jh.module.system.service.mail.MailSendService;
-import cn.lihu.jh.module.system.service.mail.MailTemplateService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-import java.util.List;
-
-import static cn.lihu.jh.framework.common.pojo.CommonResult.success;
-import static cn.lihu.jh.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
-
-@Tag(name = "绠$悊鍚庡彴 - 閭欢妯$増")
-@RestController
-@RequestMapping("/system/mail-template")
-public class MailTemplateController {
-
-    @Resource
-    private MailTemplateService mailTempleService;
-    @Resource
-    private MailSendService mailSendService;
-
-    @PostMapping("/create")
-    @Operation(summary = "鍒涘缓閭欢妯$増")
-    @PreAuthorize("@ss.hasPermission('system:mail-template:create')")
-    public CommonResult<Long> createMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO createReqVO){
-        return success(mailTempleService.createMailTemplate(createReqVO));
-    }
-
-    @PutMapping("/update")
-    @Operation(summary = "淇敼閭欢妯$増")
-    @PreAuthorize("@ss.hasPermission('system:mail-template:update')")
-    public CommonResult<Boolean> updateMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO updateReqVO){
-        mailTempleService.updateMailTemplate(updateReqVO);
-        return success(true);
-    }
-
-    @DeleteMapping("/delete")
-    @Operation(summary = "鍒犻櫎閭欢妯$増")
-    @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('system:mail-template:delete')")
-    public CommonResult<Boolean> deleteMailTemplate(@RequestParam("id") Long id) {
-        mailTempleService.deleteMailTemplate(id);
-        return success(true);
-    }
-
-    @GetMapping("/get")
-    @Operation(summary = "鑾峰緱閭欢妯$増")
-    @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('system:mail-template:query')")
-    public CommonResult<MailTemplateRespVO> getMailTemplate(@RequestParam("id") Long id) {
-        MailTemplateDO template = mailTempleService.getMailTemplate(id);
-        return success(BeanUtils.toBean(template, MailTemplateRespVO.class));
-    }
-
-    @GetMapping("/page")
-    @Operation(summary = "鑾峰緱閭欢妯$増鍒嗛〉")
-    @PreAuthorize("@ss.hasPermission('system:mail-template:query')")
-    public CommonResult<PageResult<MailTemplateRespVO>> getMailTemplatePage(@Valid MailTemplatePageReqVO pageReqVO) {
-        PageResult<MailTemplateDO> pageResult = mailTempleService.getMailTemplatePage(pageReqVO);
-        return success(BeanUtils.toBean(pageResult, MailTemplateRespVO.class));
-    }
-
-    @GetMapping({"/list-all-simple", "simple-list"})
-    @Operation(summary = "鑾峰緱閭欢妯$増绮剧畝鍒楄〃")
-    public CommonResult<List<MailTemplateSimpleRespVO>> getSimpleTemplateList() {
-        List<MailTemplateDO> list = mailTempleService.getMailTemplateList();
-        return success(BeanUtils.toBean(list, MailTemplateSimpleRespVO.class));
-    }
-
-    @PostMapping("/send-mail")
-    @Operation(summary = "鍙戦�佺煭淇�")
-    @PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')")
-    public CommonResult<Long> sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) {
-        return success(mailSendService.sendSingleMailToAdmin(sendReqVO.getMail(), getLoginUserId(),
-                sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java
deleted file mode 100644
index f8c0706..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.account;
-
-import cn.lihu.jh.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭璐﹀彿鍒嗛〉 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class MailAccountPageReqVO extends PageParam {
-
-    @Schema(description = "閭", requiredMode = Schema.RequiredMode.REQUIRED, example = "jhyuanma@123.com")
-    private String mail;
-
-    @Schema(description = "鐢ㄦ埛鍚�" , requiredMode = Schema.RequiredMode.REQUIRED , example = "jh")
-    private String username;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java
deleted file mode 100644
index 2fd423f..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.account;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭璐﹀彿 Response VO")
-@Data
-public class MailAccountRespVO {
-
-    @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    private Long id;
-
-    @Schema(description = "閭", requiredMode = Schema.RequiredMode.REQUIRED, example = "jhyuanma@123.com")
-    private String mail;
-
-    @Schema(description = "鐢ㄦ埛鍚�", requiredMode = Schema.RequiredMode.REQUIRED, example = "jh")
-    private String username;
-
-    @Schema(description = "瀵嗙爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
-    private String password;
-
-    @Schema(description = "SMTP 鏈嶅姟鍣ㄥ煙鍚�", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn")
-    private String host;
-
-    @Schema(description = "SMTP 鏈嶅姟鍣ㄧ鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
-    private Integer port;
-
-    @Schema(description = "鏄惁寮�鍚� ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
-    private Boolean sslEnable;
-
-    @Schema(description = "鏄惁寮�鍚� starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
-    private Boolean starttlsEnable;
-
-    @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
-    private LocalDateTime createTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java
deleted file mode 100644
index 160017b..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.account;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import javax.validation.constraints.Email;
-import javax.validation.constraints.NotNull;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭璐﹀彿鍒涘缓/淇敼 Request VO")
-@Data
-public class MailAccountSaveReqVO {
-
-    @Schema(description = "缂栧彿", example = "1024")
-    private Long id;
-
-    @Schema(description = "閭", requiredMode = Schema.RequiredMode.REQUIRED, example = "jhyuanma@123.com")
-    @NotNull(message = "閭涓嶈兘涓虹┖")
-    @Email(message = "蹇呴』鏄� Email 鏍煎紡")
-    private String mail;
-
-    @Schema(description = "鐢ㄦ埛鍚�", requiredMode = Schema.RequiredMode.REQUIRED, example = "jh")
-    @NotNull(message = "鐢ㄦ埛鍚嶄笉鑳戒负绌�")
-    private String username;
-
-    @Schema(description = "瀵嗙爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
-    @NotNull(message = "瀵嗙爜蹇呭~")
-    private String password;
-
-    @Schema(description = "SMTP 鏈嶅姟鍣ㄥ煙鍚�", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn")
-    @NotNull(message = "SMTP 鏈嶅姟鍣ㄥ煙鍚嶄笉鑳戒负绌�")
-    private String host;
-
-    @Schema(description = "SMTP 鏈嶅姟鍣ㄧ鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
-    @NotNull(message = "SMTP 鏈嶅姟鍣ㄧ鍙d笉鑳戒负绌�")
-    private Integer port;
-
-    @Schema(description = "鏄惁寮�鍚� ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
-    @NotNull(message = "鏄惁寮�鍚� ssl 蹇呭~")
-    private Boolean sslEnable;
-
-    @Schema(description = "鏄惁寮�鍚� starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
-    @NotNull(message = "鏄惁寮�鍚� starttls 蹇呭~")
-    private Boolean starttlsEnable;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java
deleted file mode 100644
index 9bbc2d8..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.account;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭璐﹀彿鐨勭簿绠� Response VO")
-@Data
-public class MailAccountSimpleRespVO {
-
-    @Schema(description = "閭缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    private Long id;
-
-    @Schema(description = "閭", requiredMode = Schema.RequiredMode.REQUIRED, example = "768541388@qq.com")
-    private String mail;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/log/MailLogPageReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/log/MailLogPageReqVO.java
deleted file mode 100644
index eeb154f..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/log/MailLogPageReqVO.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.log;
-
-import cn.lihu.jh.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-
-import static cn.lihu.jh.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭鏃ュ織鍒嗛〉 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class MailLogPageReqVO extends PageParam {
-
-    @Schema(description = "鐢ㄦ埛缂栧彿", example = "30883")
-    private Long userId;
-
-    @Schema(description = "鐢ㄦ埛绫诲瀷锛屽弬瑙� UserTypeEnum 鏋氫妇", example = "2")
-    private Integer userType;
-
-    @Schema(description = "鎺ユ敹閭鍦板潃锛屾ā绯婂尮閰�", example = "76854@qq.com")
-    private String toMail;
-
-    @Schema(description = "閭璐﹀彿缂栧彿", example = "18107")
-    private Long accountId;
-
-    @Schema(description = "妯℃澘缂栧彿", example = "5678")
-    private Long templateId;
-
-    @Schema(description = "鍙戦�佺姸鎬侊紝鍙傝 MailSendStatusEnum 鏋氫妇", example = "1")
-    private Integer sendStatus;
-
-    @Schema(description = "鍙戦�佹椂闂�")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] sendTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/log/MailLogRespVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/log/MailLogRespVO.java
deleted file mode 100644
index a35d57d..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/log/MailLogRespVO.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.log;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-import java.util.Map;
-
-import static cn.lihu.jh.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭欢鏃ュ織 Response VO")
-@Data
-public class MailLogRespVO {
-
-    @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "31020")
-    private Long id;
-
-    @Schema(description = "鐢ㄦ埛缂栧彿", example = "30883")
-    private Long userId;
-
-    @Schema(description = "鐢ㄦ埛绫诲瀷锛屽弬瑙� UserTypeEnum 鏋氫妇", example = "2")
-    private Byte userType;
-
-    @Schema(description = "鎺ユ敹閭鍦板潃", requiredMode = Schema.RequiredMode.REQUIRED, example = "76854@qq.com")
-    private String toMail;
-
-    @Schema(description = "閭璐﹀彿缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "18107")
-    private Long accountId;
-
-    @Schema(description = "鍙戦�侀偖绠卞湴鍧�", requiredMode = Schema.RequiredMode.REQUIRED, example = "85757@qq.com")
-    private String fromMail;
-
-    @Schema(description = "妯℃澘缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "5678")
-    private Long templateId;
-
-    @Schema(description = "妯℃澘缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
-    private String templateCode;
-
-    @Schema(description = "妯$増鍙戦�佷汉鍚嶇О", example = "鏉庡洓")
-    private String templateNickname;
-
-    @Schema(description = "閭欢鏍囬", requiredMode = Schema.RequiredMode.REQUIRED, example = "娴嬭瘯鏍囬")
-    private String templateTitle;
-
-    @Schema(description = "閭欢鍐呭", requiredMode = Schema.RequiredMode.REQUIRED, example = "娴嬭瘯鍐呭")
-    private String templateContent;
-
-    @Schema(description = "閭欢鍙傛暟", requiredMode = Schema.RequiredMode.REQUIRED)
-    private Map<String, Object> templateParams;
-
-    @Schema(description = "鍙戦�佺姸鎬侊紝鍙傝 MailSendStatusEnum 鏋氫妇", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    private Byte sendStatus;
-
-    @Schema(description = "鍙戦�佹椂闂�")
-    private LocalDateTime sendTime;
-
-    @Schema(description = "鍙戦�佽繑鍥炵殑娑堟伅 ID", example = "28568")
-    private String sendMessageId;
-
-    @Schema(description = "鍙戦�佸紓甯�")
-    private String sendException;
-
-    @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
-    private LocalDateTime createTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java
deleted file mode 100644
index deb9fbe..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.template;
-
-import cn.lihu.jh.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-
-import static cn.lihu.jh.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭欢妯$増鍒嗛〉 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class MailTemplatePageReqVO extends PageParam {
-
-    @Schema(description = "鐘舵�侊紝鍙傝 CommonStatusEnum 鏋氫妇", example = "1")
-    private Integer status;
-
-    @Schema(description = "鏍囪瘑锛屾ā绯婂尮閰�", example = "code_1024")
-    private String code;
-
-    @Schema(description = "鍚嶇О锛屾ā绯婂尮閰�", example = "鑺嬪ご")
-    private String name;
-
-    @Schema(description = "璐﹀彿缂栧彿", example = "2048")
-    private Long accountId;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] createTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateRespVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateRespVO.java
deleted file mode 100644
index f6eb305..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateRespVO.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.template;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-import java.time.LocalDateTime;
-import java.util.List;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭欢鏈彮 Response VO")
-@Data
-public class MailTemplateRespVO {
-
-    @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    private Long id;
-
-    @Schema(description = "妯$増鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "娴嬭瘯鍚嶅瓧")
-    private String name;
-
-    @Schema(description = "妯$増缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "test")
-    private String code;
-
-    @Schema(description = "鍙戦�佺殑閭璐﹀彿缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    private Long accountId;
-
-    @Schema(description = "鍙戦�佷汉鍚嶇О", example = "鑺嬪ご")
-    private String nickname;
-
-    @Schema(description = "鏍囬", requiredMode = Schema.RequiredMode.REQUIRED, example = "娉ㄥ唽鎴愬姛")
-    private String title;
-
-    @Schema(description = "鍐呭", requiredMode = Schema.RequiredMode.REQUIRED, example = "浣犲ソ锛屾敞鍐屾垚鍔熷暒")
-    private String content;
-
-    @Schema(description = "鍙傛暟鏁扮粍", example = "name,code")
-    private List<String> params;
-
-    @Schema(description = "鐘舵�侊紝鍙傝 CommonStatusEnum 鏋氫妇", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    private Integer status;
-
-    @Schema(description = "澶囨敞", example = "濂ョ壒鏇�")
-    private String remark;
-
-    @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
-    private LocalDateTime createTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java
deleted file mode 100644
index f0649e9..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.template;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭欢妯$増鍒涘缓/淇敼 Request VO")
-@Data
-public class MailTemplateSaveReqVO {
-
-    @Schema(description = "缂栧彿", example = "1024")
-    private Long id;
-
-    @Schema(description = "妯$増鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "娴嬭瘯鍚嶅瓧")
-    @NotNull(message = "鍚嶇О涓嶈兘涓虹┖")
-    private String name;
-
-    @Schema(description = "妯$増缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "test")
-    @NotNull(message = "妯$増缂栧彿涓嶈兘涓虹┖")
-    private String code;
-
-    @Schema(description = "鍙戦�佺殑閭璐﹀彿缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "鍙戦�佺殑閭璐﹀彿缂栧彿涓嶈兘涓虹┖")
-    private Long accountId;
-
-    @Schema(description = "鍙戦�佷汉鍚嶇О", example = "鑺嬪ご")
-    private String nickname;
-
-    @Schema(description = "鏍囬", requiredMode = Schema.RequiredMode.REQUIRED, example = "娉ㄥ唽鎴愬姛")
-    @NotEmpty(message = "鏍囬涓嶈兘涓虹┖")
-    private String title;
-
-    @Schema(description = "鍐呭", requiredMode = Schema.RequiredMode.REQUIRED, example = "浣犲ソ锛屾敞鍐屾垚鍔熷暒")
-    @NotEmpty(message = "鍐呭涓嶈兘涓虹┖")
-    private String content;
-
-    @Schema(description = "鐘舵�侊紝鍙傝 CommonStatusEnum 鏋氫妇", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "鐘舵�佷笉鑳戒负绌�")
-    private Integer status;
-
-    @Schema(description = "澶囨敞", example = "濂ョ壒鏇�")
-    private String remark;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java
deleted file mode 100644
index 67e251c..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.template;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-import java.util.Map;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭欢鍙戦�� Req VO")
-@Data
-public class MailTemplateSendReqVO {
-
-    @Schema(description = "鎺ユ敹閭", requiredMode = Schema.RequiredMode.REQUIRED, example = "7685413@qq.com")
-    @NotEmpty(message = "鎺ユ敹閭涓嶈兘涓虹┖")
-    private String mail;
-
-    @Schema(description = "妯℃澘缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
-    @NotNull(message = "妯℃澘缂栫爜涓嶈兘涓虹┖")
-    private String templateCode;
-
-    @Schema(description = "妯℃澘鍙傛暟")
-    private Map<String, Object> templateParams;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java
deleted file mode 100644
index f414967..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.mail.vo.template;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-@Schema(description = "绠$悊鍚庡彴 - 閭欢妯$増鐨勭簿绠� Response VO")
-@Data
-public class MailTemplateSimpleRespVO {
-
-    @Schema(description = "妯$増缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    private Long id;
-
-    @Schema(description = "妯$増鍚嶅瓧", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍝掑搾鍝�")
-    private String name;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/NotifyMessageController.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/NotifyMessageController.java
deleted file mode 100644
index 79c2b1a..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/NotifyMessageController.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.notify;
-
-import cn.lihu.jh.framework.apilog.core.annotation.ApiAccessLog;
-import cn.lihu.jh.framework.common.enums.UserTypeEnum;
-import cn.lihu.jh.framework.common.pojo.CommonResult;
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.common.util.object.BeanUtils;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyMessageDO;
-import cn.lihu.jh.module.system.service.notify.NotifyMessageService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-import java.util.List;
-
-import static cn.lihu.jh.framework.common.pojo.CommonResult.success;
-import static cn.lihu.jh.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
-
-@Tag(name = "绠$悊鍚庡彴 - 鎴戠殑绔欏唴淇�")
-@RestController
-@RequestMapping("/system/notify-message")
-@Validated
-public class NotifyMessageController {
-
-    @Resource
-    private NotifyMessageService notifyMessageService;
-
-    // ========== 绠$悊鎵�鏈夌殑绔欏唴淇� ==========
-
-    @GetMapping("/get")
-    @Operation(summary = "鑾峰緱绔欏唴淇�")
-    @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('system:notify-message:query')")
-    public CommonResult<NotifyMessageRespVO> getNotifyMessage(@RequestParam("id") Long id) {
-        NotifyMessageDO message = notifyMessageService.getNotifyMessage(id);
-        return success(BeanUtils.toBean(message, NotifyMessageRespVO.class));
-    }
-
-    @GetMapping("/page")
-    @Operation(summary = "鑾峰緱绔欏唴淇″垎椤�")
-    @PreAuthorize("@ss.hasPermission('system:notify-message:query')")
-    public CommonResult<PageResult<NotifyMessageRespVO>> getNotifyMessagePage(@Valid NotifyMessagePageReqVO pageVO) {
-        PageResult<NotifyMessageDO> pageResult = notifyMessageService.getNotifyMessagePage(pageVO);
-        return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class));
-    }
-
-    // ========== 鏌ョ湅鑷繁鐨勭珯鍐呬俊 ==========
-
-    @GetMapping("/my-page")
-    @Operation(summary = "鑾峰緱鎴戠殑绔欏唴淇″垎椤�")
-    public CommonResult<PageResult<NotifyMessageRespVO>> getMyMyNotifyMessagePage(@Valid NotifyMessageMyPageReqVO pageVO) {
-        PageResult<NotifyMessageDO> pageResult = notifyMessageService.getMyMyNotifyMessagePage(pageVO,
-                getLoginUserId(), UserTypeEnum.ADMIN.getValue());
-        return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class));
-    }
-
-    @PutMapping("/update-read")
-    @Operation(summary = "鏍囪绔欏唴淇′负宸茶")
-    @Parameter(name = "ids", description = "缂栧彿鍒楄〃", required = true, example = "1024,2048")
-    public CommonResult<Boolean> updateNotifyMessageRead(@RequestParam("ids") List<Long> ids) {
-        notifyMessageService.updateNotifyMessageRead(ids, getLoginUserId(), UserTypeEnum.ADMIN.getValue());
-        return success(Boolean.TRUE);
-    }
-
-    @PutMapping("/update-all-read")
-    @Operation(summary = "鏍囪鎵�鏈夌珯鍐呬俊涓哄凡璇�")
-    public CommonResult<Boolean> updateAllNotifyMessageRead() {
-        notifyMessageService.updateAllNotifyMessageRead(getLoginUserId(), UserTypeEnum.ADMIN.getValue());
-        return success(Boolean.TRUE);
-    }
-
-    @GetMapping("/get-unread-list")
-    @Operation(summary = "鑾峰彇褰撳墠鐢ㄦ埛鐨勬渶鏂扮珯鍐呬俊鍒楄〃锛岄粯璁� 10 鏉�")
-    @Parameter(name = "size", description = "10")
-    public CommonResult<List<NotifyMessageRespVO>> getUnreadNotifyMessageList(
-            @RequestParam(name = "size", defaultValue = "10") Integer size) {
-        List<NotifyMessageDO> list = notifyMessageService.getUnreadNotifyMessageList(
-                getLoginUserId(), UserTypeEnum.ADMIN.getValue(), size);
-        return success(BeanUtils.toBean(list, NotifyMessageRespVO.class));
-    }
-
-    @GetMapping("/get-unread-count")
-    @Operation(summary = "鑾峰緱褰撳墠鐢ㄦ埛鐨勬湭璇荤珯鍐呬俊鏁伴噺")
-    @ApiAccessLog(enable = false) // 鐢变簬鍓嶇浼氫笉鏂疆璇㈣鎺ュ彛锛岃褰曟棩蹇楁病鏈夋剰涔�
-    public CommonResult<Long> getUnreadNotifyMessageCount() {
-        return success(notifyMessageService.getUnreadNotifyMessageCount(
-                getLoginUserId(), UserTypeEnum.ADMIN.getValue()));
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/NotifyTemplateController.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/NotifyTemplateController.java
deleted file mode 100644
index dc6f3e1..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/NotifyTemplateController.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.notify;
-
-import cn.lihu.jh.framework.common.enums.UserTypeEnum;
-import cn.lihu.jh.framework.common.pojo.CommonResult;
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.common.util.object.BeanUtils;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.template.*;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyTemplateDO;
-import cn.lihu.jh.module.system.service.notify.NotifySendService;
-import cn.lihu.jh.module.system.service.notify.NotifyTemplateService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-
-import static cn.lihu.jh.framework.common.pojo.CommonResult.success;
-
-@Tag(name = "绠$悊鍚庡彴 - 绔欏唴淇℃ā鐗�")
-@RestController
-@RequestMapping("/system/notify-template")
-@Validated
-public class NotifyTemplateController {
-
-    @Resource
-    private NotifyTemplateService notifyTemplateService;
-
-    @Resource
-    private NotifySendService notifySendService;
-
-    @PostMapping("/create")
-    @Operation(summary = "鍒涘缓绔欏唴淇℃ā鐗�")
-    @PreAuthorize("@ss.hasPermission('system:notify-template:create')")
-    public CommonResult<Long> createNotifyTemplate(@Valid @RequestBody NotifyTemplateSaveReqVO createReqVO) {
-        return success(notifyTemplateService.createNotifyTemplate(createReqVO));
-    }
-
-    @PutMapping("/update")
-    @Operation(summary = "鏇存柊绔欏唴淇℃ā鐗�")
-    @PreAuthorize("@ss.hasPermission('system:notify-template:update')")
-    public CommonResult<Boolean> updateNotifyTemplate(@Valid @RequestBody NotifyTemplateSaveReqVO updateReqVO) {
-        notifyTemplateService.updateNotifyTemplate(updateReqVO);
-        return success(true);
-    }
-
-    @DeleteMapping("/delete")
-    @Operation(summary = "鍒犻櫎绔欏唴淇℃ā鐗�")
-    @Parameter(name = "id", description = "缂栧彿", required = true)
-    @PreAuthorize("@ss.hasPermission('system:notify-template:delete')")
-    public CommonResult<Boolean> deleteNotifyTemplate(@RequestParam("id") Long id) {
-        notifyTemplateService.deleteNotifyTemplate(id);
-        return success(true);
-    }
-
-    @GetMapping("/get")
-    @Operation(summary = "鑾峰緱绔欏唴淇℃ā鐗�")
-    @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
-    @PreAuthorize("@ss.hasPermission('system:notify-template:query')")
-    public CommonResult<NotifyTemplateRespVO> getNotifyTemplate(@RequestParam("id") Long id) {
-        NotifyTemplateDO template = notifyTemplateService.getNotifyTemplate(id);
-        return success(BeanUtils.toBean(template, NotifyTemplateRespVO.class));
-    }
-
-    @GetMapping("/page")
-    @Operation(summary = "鑾峰緱绔欏唴淇℃ā鐗堝垎椤�")
-    @PreAuthorize("@ss.hasPermission('system:notify-template:query')")
-    public CommonResult<PageResult<NotifyTemplateRespVO>> getNotifyTemplatePage(@Valid NotifyTemplatePageReqVO pageVO) {
-        PageResult<NotifyTemplateDO> pageResult = notifyTemplateService.getNotifyTemplatePage(pageVO);
-        return success(BeanUtils.toBean(pageResult, NotifyTemplateRespVO.class));
-    }
-
-    @PostMapping("/send-notify")
-    @Operation(summary = "鍙戦�佺珯鍐呬俊")
-    @PreAuthorize("@ss.hasPermission('system:notify-template:send-notify')")
-    public CommonResult<Long> sendNotify(@Valid @RequestBody NotifyTemplateSendReqVO sendReqVO) {
-        if (UserTypeEnum.MEMBER.getValue().equals(sendReqVO.getUserType())) {
-            return success(notifySendService.sendSingleNotifyToMember(sendReqVO.getUserId(),
-                    sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
-        } else {
-            return success(notifySendService.sendSingleNotifyToAdmin(sendReqVO.getUserId(),
-                    sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
-        }
-    }
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java
deleted file mode 100644
index 91b61e7..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.notify.vo.message;
-
-import cn.lihu.jh.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-
-import static cn.lihu.jh.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
-@Schema(description = "绠$悊鍚庡彴 - 绔欏唴淇″垎椤� Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class NotifyMessageMyPageReqVO extends PageParam {
-
-    @Schema(description = "鏄惁宸茶", example = "true")
-    private Boolean readStatus;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] createTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java
deleted file mode 100644
index 84827f7..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.notify.vo.message;
-
-import cn.lihu.jh.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-
-import static cn.lihu.jh.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
-@Schema(description = "绠$悊鍚庡彴 - 绔欏唴淇″垎椤� Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class NotifyMessagePageReqVO extends PageParam {
-
-    @Schema(description = "鐢ㄦ埛缂栧彿", example = "25025")
-    private Long userId;
-
-    @Schema(description = "鐢ㄦ埛绫诲瀷", example = "1")
-    private Integer userType;
-
-    @Schema(description = "妯℃澘缂栫爜", example = "test_01")
-    private String templateCode;
-
-    @Schema(description = "妯$増绫诲瀷", example = "2")
-    private Integer templateType;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] createTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java
deleted file mode 100644
index d99bfb0..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.notify.vo.message;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-import java.util.Map;
-
-@Schema(description = "绠$悊鍚庡彴 - 绔欏唴淇� Response VO")
-@Data
-public class NotifyMessageRespVO {
-
-    @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    private Long id;
-
-    @Schema(description = "鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "25025")
-    private Long userId;
-
-    @Schema(description = "鐢ㄦ埛绫诲瀷锛屽弬瑙� UserTypeEnum 鏋氫妇", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    private Byte userType;
-
-    @Schema(description = "妯$増缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "13013")
-    private Long templateId;
-
-    @Schema(description = "妯℃澘缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
-    private String templateCode;
-
-    @Schema(description = "妯$増鍙戦�佷汉鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鑺嬭壙")
-    private String templateNickname;
-
-    @Schema(description = "妯$増鍐呭", requiredMode = Schema.RequiredMode.REQUIRED, example = "娴嬭瘯鍐呭")
-    private String templateContent;
-
-    @Schema(description = "妯$増绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
-    private Integer templateType;
-
-    @Schema(description = "妯$増鍙傛暟", requiredMode = Schema.RequiredMode.REQUIRED)
-    private Map<String, Object> templateParams;
-
-    @Schema(description = "鏄惁宸茶", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
-    private Boolean readStatus;
-
-    @Schema(description = "闃呰鏃堕棿")
-    private LocalDateTime readTime;
-
-    @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
-    private LocalDateTime createTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java
deleted file mode 100644
index d7a8d6d..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.notify.vo.template;
-
-import cn.lihu.jh.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-
-import static cn.lihu.jh.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
-@Schema(description = "绠$悊鍚庡彴 - 绔欏唴淇℃ā鐗堝垎椤� Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class NotifyTemplatePageReqVO extends PageParam {
-
-    @Schema(description = "妯$増缂栫爜", example = "test_01")
-    private String code;
-
-    @Schema(description = "妯$増鍚嶇О", example = "鎴戞槸鍚嶇О")
-    private String name;
-
-    @Schema(description = "鐘舵�侊紝鍙傝 CommonStatusEnum 鏋氫妇绫�", example = "1")
-    private Integer status;
-
-    @Schema(description = "鍒涘缓鏃堕棿")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] createTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java
deleted file mode 100644
index f3c7e3e..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.notify.vo.template;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-import java.util.List;
-
-@Schema(description = "绠$悊鍚庡彴 - 绔欏唴淇℃ā鐗� Response VO")
-@Data
-public class NotifyTemplateRespVO {
-
-    @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    private Long id;
-
-    @Schema(description = "妯$増鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "娴嬭瘯妯$増")
-    private String name;
-
-    @Schema(description = "妯$増缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "SEND_TEST")
-    private String code;
-
-    @Schema(description = "妯$増绫诲瀷锛屽搴� system_notify_template_type 瀛楀吀", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    private Integer type;
-
-    @Schema(description = "鍙戦�佷汉鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍦熻眴")
-    private String nickname;
-
-    @Schema(description = "妯$増鍐呭", requiredMode = Schema.RequiredMode.REQUIRED, example = "鎴戞槸妯$増鍐呭")
-    private String content;
-
-    @Schema(description = "鍙傛暟鏁扮粍", example = "name,code")
-    private List<String> params;
-
-    @Schema(description = "鐘舵�侊紝鍙傝 CommonStatusEnum 鏋氫妇", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    private Integer status;
-
-    @Schema(description = "澶囨敞", example = "鎴戞槸澶囨敞")
-    private String remark;
-
-    @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
-    private LocalDateTime createTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java
deleted file mode 100644
index 9893d0f..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.notify.vo.template;
-
-import cn.lihu.jh.framework.common.enums.CommonStatusEnum;
-import cn.lihu.jh.framework.common.validation.InEnum;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.*;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-
-@Schema(description = "绠$悊鍚庡彴 - 绔欏唴淇℃ā鐗堝垱寤�/淇敼 Request VO")
-@Data
-public class NotifyTemplateSaveReqVO {
-
-    @Schema(description = "ID", example = "1024")
-    private Long id;
-
-    @Schema(description = "妯$増鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "娴嬭瘯妯$増")
-    @NotEmpty(message = "妯$増鍚嶇О涓嶈兘涓虹┖")
-    private String name;
-
-    @Schema(description = "妯$増缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "SEND_TEST")
-    @NotNull(message = "妯$増缂栫爜涓嶈兘涓虹┖")
-    private String code;
-
-    @Schema(description = "妯$増绫诲瀷锛屽搴� system_notify_template_type 瀛楀吀", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "妯$増绫诲瀷涓嶈兘涓虹┖")
-    private Integer type;
-
-    @Schema(description = "鍙戦�佷汉鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍦熻眴")
-    @NotEmpty(message = "鍙戦�佷汉鍚嶇О涓嶈兘涓虹┖")
-    private String nickname;
-
-    @Schema(description = "妯$増鍐呭", requiredMode = Schema.RequiredMode.REQUIRED, example = "鎴戞槸妯$増鍐呭")
-    @NotEmpty(message = "妯$増鍐呭涓嶈兘涓虹┖")
-    private String content;
-
-    @Schema(description = "鐘舵�侊紝鍙傝 CommonStatusEnum 鏋氫妇", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "鐘舵�佷笉鑳戒负绌�")
-    @InEnum(value = CommonStatusEnum.class, message = "鐘舵�佸繀椤绘槸 {value}")
-    private Integer status;
-
-    @Schema(description = "澶囨敞", example = "鎴戞槸澶囨敞")
-    private String remark;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java
deleted file mode 100644
index 54e6d52..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package cn.lihu.jh.module.system.controller.admin.notify.vo.template;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-import java.util.Map;
-
-@Schema(description = "绠$悊鍚庡彴 - 绔欏唴淇℃ā鏉跨殑鍙戦�� Request VO")
-@Data
-public class NotifyTemplateSendReqVO {
-
-    @Schema(description = "鐢ㄦ埛id", requiredMode = Schema.RequiredMode.REQUIRED, example = "01")
-    @NotNull(message = "鐢ㄦ埛id涓嶈兘涓虹┖")
-    private Long userId;
-
-    @Schema(description = "鐢ㄦ埛绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "鐢ㄦ埛绫诲瀷涓嶈兘涓虹┖")
-    private Integer userType;
-
-    @Schema(description = "妯℃澘缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "01")
-    @NotEmpty(message = "妯℃澘缂栫爜涓嶈兘涓虹┖")
-    private String templateCode;
-
-    @Schema(description = "妯℃澘鍙傛暟")
-    private Map<String, Object> templateParams;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailAccountDO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailAccountDO.java
deleted file mode 100644
index ad056b4..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailAccountDO.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package cn.lihu.jh.module.system.dal.dataobject.mail;
-
-import cn.lihu.jh.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * 閭璐﹀彿 DO
- *
- * 鐢ㄩ�旓細閰嶇疆鍙戦�侀偖绠辩殑璐﹀彿
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-@TableName(value = "system_mail_account", autoResultMap = true)
-@Data
-@EqualsAndHashCode(callSuper = true)
-public class MailAccountDO extends BaseDO {
-
-    /**
-     * 涓婚敭
-     */
-    @TableId
-    private Long id;
-    /**
-     * 閭
-     */
-    private String mail;
-
-    /**
-     * 鐢ㄦ埛鍚�
-     */
-    private String username;
-    /**
-     * 瀵嗙爜
-     */
-    private String password;
-    /**
-     * SMTP 鏈嶅姟鍣ㄥ煙鍚�
-     */
-    private String host;
-    /**
-     * SMTP 鏈嶅姟鍣ㄧ鍙�
-     */
-    private Integer port;
-    /**
-     * 鏄惁寮�鍚� SSL
-     */
-    private Boolean sslEnable;
-    /**
-     * 鏄惁寮�鍚� STARTTLS
-     */
-    private Boolean starttlsEnable;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailLogDO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailLogDO.java
deleted file mode 100644
index e516fbc..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailLogDO.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package cn.lihu.jh.module.system.dal.dataobject.mail;
-
-import cn.lihu.jh.framework.common.enums.UserTypeEnum;
-import cn.lihu.jh.framework.mybatis.core.dataobject.BaseDO;
-import cn.lihu.jh.module.system.enums.mail.MailSendStatusEnum;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
-import lombok.*;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-import java.util.Map;
-
-/**
- * 閭鏃ュ織 DO
- * 璁板綍姣忎竴娆¢偖浠剁殑鍙戦��
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-@TableName(value = "system_mail_log", autoResultMap = true)
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@AllArgsConstructor
-@NoArgsConstructor
-public class MailLogDO extends BaseDO implements Serializable {
-
-    /**
-     * 鏃ュ織缂栧彿锛岃嚜澧�
-     */
-    private Long id;
-
-    /**
-     * 鐢ㄦ埛缂栫爜
-     */
-    private Long userId;
-    /**
-     * 鐢ㄦ埛绫诲瀷
-     *
-     * 鏋氫妇 {@link UserTypeEnum}
-     */
-    private Integer userType;
-    /**
-     * 鎺ユ敹閭鍦板潃
-     */
-    private String toMail;
-
-    /**
-     * 閭璐﹀彿缂栧彿
-     *
-     * 鍏宠仈 {@link MailAccountDO#getId()}
-     */
-    private Long accountId;
-    /**
-     * 鍙戦�侀偖绠卞湴鍧�
-     *
-     * 鍐椾綑 {@link MailAccountDO#getMail()}
-     */
-    private String fromMail;
-
-    // ========= 妯℃澘鐩稿叧瀛楁 =========
-    /**
-     * 妯$増缂栧彿
-     *
-     * 鍏宠仈 {@link MailTemplateDO#getId()}
-     */
-    private Long templateId;
-    /**
-     * 妯$増缂栫爜
-     *
-     * 鍐椾綑 {@link MailTemplateDO#getCode()}
-     */
-    private String templateCode;
-    /**
-     * 妯$増鍙戦�佷汉鍚嶇О
-     *
-     * 鍐椾綑 {@link MailTemplateDO#getNickname()}
-     */
-    private String templateNickname;
-    /**
-     * 妯$増鏍囬
-     */
-    private String templateTitle;
-    /**
-     * 妯$増鍐呭
-     *
-     * 鍩轰簬 {@link MailTemplateDO#getContent()} 鏍煎紡鍖栧悗鐨勫唴瀹�
-     */
-    private String templateContent;
-    /**
-     * 妯$増鍙傛暟
-     *
-     * 鍩轰簬 {@link MailTemplateDO#getParams()} 杈撳叆鍚庣殑鍙傛暟
-     */
-    @TableField(typeHandler = JacksonTypeHandler.class)
-    private Map<String, Object> templateParams;
-
-    // ========= 鍙戦�佺浉鍏冲瓧娈� =========
-    /**
-     * 鍙戦�佺姸鎬�
-     *
-     * 鏋氫妇 {@link MailSendStatusEnum}
-     */
-    private Integer sendStatus;
-    /**
-     * 鍙戦�佹椂闂�
-     */
-    private LocalDateTime sendTime;
-    /**
-     * 鍙戦�佽繑鍥炵殑娑堟伅 ID
-     */
-    private String sendMessageId;
-    /**
-     * 鍙戦�佸紓甯�
-     */
-    private String sendException;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailTemplateDO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailTemplateDO.java
deleted file mode 100644
index b7ca534..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/mail/MailTemplateDO.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package cn.lihu.jh.module.system.dal.dataobject.mail;
-
-import cn.lihu.jh.framework.common.enums.CommonStatusEnum;
-import cn.lihu.jh.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.util.List;
-
-/**
- * 閭欢妯$増 DO
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-@TableName(value = "system_mail_template", autoResultMap = true)
-@Data
-@EqualsAndHashCode(callSuper = true)
-public class MailTemplateDO extends BaseDO {
-
-    /**
-     * 涓婚敭
-     */
-    private Long id;
-    /**
-     * 妯$増鍚嶇О
-     */
-    private String name;
-    /**
-     * 妯$増缂栧彿
-     */
-    private String code;
-    /**
-     * 鍙戦�佺殑閭璐﹀彿缂栧彿
-     *
-     * 鍏宠仈 {@link MailAccountDO#getId()}
-     */
-    private Long accountId;
-
-    /**
-     * 鍙戦�佷汉鍚嶇О
-     */
-    private String nickname;
-    /**
-     * 鏍囬
-     */
-    private String title;
-    /**
-     * 鍐呭
-     */
-    private String content;
-    /**
-     * 鍙傛暟鏁扮粍(鑷姩鏍规嵁鍐呭鐢熸垚)
-     */
-    @TableField(typeHandler = JacksonTypeHandler.class)
-    private List<String> params;
-    /**
-     * 鐘舵��
-     *
-     * 鏋氫妇 {@link CommonStatusEnum}
-     */
-    private Integer status;
-    /**
-     * 澶囨敞
-     */
-    private String remark;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/notify/NotifyMessageDO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/notify/NotifyMessageDO.java
deleted file mode 100644
index 2a9cf6d..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/notify/NotifyMessageDO.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package cn.lihu.jh.module.system.dal.dataobject.notify;
-
-import cn.lihu.jh.framework.common.enums.UserTypeEnum;
-import cn.lihu.jh.framework.mybatis.core.dataobject.BaseDO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailTemplateDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
-import lombok.*;
-
-import java.time.LocalDateTime;
-import java.util.Date;
-import java.util.Map;
-
-/**
- * 绔欏唴淇� DO
- *
- * @author xrcoder
- */
-@TableName(value = "system_notify_message", autoResultMap = true)
-@KeySequence("system_notify_message_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷銆傚鏋滄槸 MySQL 绛夋暟鎹簱锛屽彲涓嶅啓銆�
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class NotifyMessageDO extends BaseDO {
-
-    /**
-     * 绔欏唴淇$紪鍙凤紝鑷
-     */
-    @TableId
-    private Long id;
-    /**
-     * 鐢ㄦ埛缂栧彿
-     *
-     * 鍏宠仈 MemberUserDO 鐨� id 瀛楁銆佹垨鑰� AdminUserDO 鐨� id 瀛楁
-     */
-    private Long userId;
-    /**
-     * 鐢ㄦ埛绫诲瀷
-     *
-     * 鏋氫妇 {@link UserTypeEnum}
-     */
-    private Integer userType;
-
-    // ========= 妯℃澘鐩稿叧瀛楁 =========
-
-    /**
-     * 妯$増缂栧彿
-     *
-     * 鍏宠仈 {@link NotifyTemplateDO#getId()}
-     */
-    private Long templateId;
-    /**
-     * 妯$増缂栫爜
-     *
-     * 鍏宠仈 {@link NotifyTemplateDO#getCode()}
-     */
-    private String templateCode;
-    /**
-     * 妯$増绫诲瀷
-     *
-     * 鍐椾綑 {@link NotifyTemplateDO#getType()}
-     */
-    private Integer templateType;
-    /**
-     * 妯$増鍙戦�佷汉鍚嶇О
-     *
-     * 鍐椾綑 {@link NotifyTemplateDO#getNickname()}
-     */
-    private String templateNickname;
-    /**
-     * 妯$増鍐呭
-     *
-     * 鍩轰簬 {@link NotifyTemplateDO#getContent()} 鏍煎紡鍖栧悗鐨勫唴瀹�
-     */
-    private String templateContent;
-    /**
-     * 妯$増鍙傛暟
-     *
-     * 鍩轰簬 {@link NotifyTemplateDO#getParams()} 杈撳叆鍚庣殑鍙傛暟
-     */
-    @TableField(typeHandler = JacksonTypeHandler.class)
-    private Map<String, Object> templateParams;
-
-    // ========= 璇诲彇鐩稿叧瀛楁 =========
-
-    /**
-     * 鏄惁宸茶
-     */
-    private Boolean readStatus;
-    /**
-     * 闃呰鏃堕棿
-     */
-    private LocalDateTime readTime;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/notify/NotifyTemplateDO.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/notify/NotifyTemplateDO.java
deleted file mode 100644
index fb85609..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/dataobject/notify/NotifyTemplateDO.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package cn.lihu.jh.module.system.dal.dataobject.notify;
-
-import cn.lihu.jh.framework.common.enums.CommonStatusEnum;
-import cn.lihu.jh.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
-import lombok.*;
-
-import java.util.List;
-
-/**
- * 绔欏唴淇℃ā鐗� DO
- *
- * @author xrcoder
- */
-@TableName(value = "system_notify_template", autoResultMap = true)
-@KeySequence("system_notify_template_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷銆傚鏋滄槸 MySQL 绛夋暟鎹簱锛屽彲涓嶅啓銆�
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class NotifyTemplateDO extends BaseDO {
-
-    /**
-     * ID
-     */
-    @TableId
-    private Long id;
-    /**
-     * 妯$増鍚嶇О
-     */
-    private String name;
-    /**
-     * 妯$増缂栫爜
-     */
-    private String code;
-    /**
-     * 妯$増绫诲瀷
-     *
-     * 瀵瑰簲 system_notify_template_type 瀛楀吀
-     */
-    private Integer type;
-    /**
-     * 鍙戦�佷汉鍚嶇О
-     */
-    private String nickname;
-    /**
-     * 妯$増鍐呭
-     */
-    private String content;
-    /**
-     * 鍙傛暟鏁扮粍
-     */
-    @TableField(typeHandler = JacksonTypeHandler.class)
-    private List<String> params;
-    /**
-     * 鐘舵��
-     *
-     * 鏋氫妇 {@link CommonStatusEnum}
-     */
-    private Integer status;
-    /**
-     * 澶囨敞
-     */
-    private String remark;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailAccountMapper.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailAccountMapper.java
deleted file mode 100644
index 673a4ca..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailAccountMapper.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package cn.lihu.jh.module.system.dal.mysql.mail;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.mybatis.core.mapper.BaseMapperX;
-import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.lihu.jh.framework.mybatis.core.query.QueryWrapperX;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailAccountDO;
-import org.apache.ibatis.annotations.Mapper;
-
-@Mapper
-public interface MailAccountMapper extends BaseMapperX<MailAccountDO> {
-
-    default PageResult<MailAccountDO> selectPage(MailAccountPageReqVO pageReqVO) {
-        return selectPage(pageReqVO, new LambdaQueryWrapperX<MailAccountDO>()
-                .likeIfPresent(MailAccountDO::getMail, pageReqVO.getMail())
-                .likeIfPresent(MailAccountDO::getUsername , pageReqVO.getUsername()));
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailLogMapper.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailLogMapper.java
deleted file mode 100644
index 7ac7e56..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailLogMapper.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package cn.lihu.jh.module.system.dal.mysql.mail;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.mybatis.core.mapper.BaseMapperX;
-import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailLogDO;
-import org.apache.ibatis.annotations.Mapper;
-
-@Mapper
-public interface MailLogMapper extends BaseMapperX<MailLogDO> {
-
-    default PageResult<MailLogDO> selectPage(MailLogPageReqVO reqVO) {
-        return selectPage(reqVO, new LambdaQueryWrapperX<MailLogDO>()
-                .eqIfPresent(MailLogDO::getUserId, reqVO.getUserId())
-                .eqIfPresent(MailLogDO::getUserType, reqVO.getUserType())
-                .likeIfPresent(MailLogDO::getToMail, reqVO.getToMail())
-                .eqIfPresent(MailLogDO::getAccountId, reqVO.getAccountId())
-                .eqIfPresent(MailLogDO::getTemplateId, reqVO.getTemplateId())
-                .eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus())
-                .betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime())
-                .orderByDesc(MailLogDO::getId));
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailTemplateMapper.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailTemplateMapper.java
deleted file mode 100644
index bcd4fb6..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/mail/MailTemplateMapper.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package cn.lihu.jh.module.system.dal.mysql.mail;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.mybatis.core.mapper.BaseMapperX;
-import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.lihu.jh.framework.mybatis.core.query.QueryWrapperX;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailTemplateDO;
-import cn.lihu.jh.module.system.dal.dataobject.sms.SmsTemplateDO;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Select;
-
-import java.util.Date;
-
-@Mapper
-public interface MailTemplateMapper extends BaseMapperX<MailTemplateDO> {
-
-    default PageResult<MailTemplateDO> selectPage(MailTemplatePageReqVO pageReqVO){
-        return selectPage(pageReqVO , new LambdaQueryWrapperX<MailTemplateDO>()
-                .eqIfPresent(MailTemplateDO::getStatus, pageReqVO.getStatus())
-                .likeIfPresent(MailTemplateDO::getCode, pageReqVO.getCode())
-                .likeIfPresent(MailTemplateDO::getName, pageReqVO.getName())
-                .eqIfPresent(MailTemplateDO::getAccountId, pageReqVO.getAccountId())
-                .betweenIfPresent(MailTemplateDO::getCreateTime, pageReqVO.getCreateTime()));
-    }
-
-    default Long selectCountByAccountId(Long accountId) {
-        return selectCount(MailTemplateDO::getAccountId, accountId);
-    }
-
-    default MailTemplateDO selectByCode(String code) {
-        return selectOne(MailTemplateDO::getCode, code);
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/notify/NotifyMessageMapper.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/notify/NotifyMessageMapper.java
deleted file mode 100644
index 8cc90c4..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/notify/NotifyMessageMapper.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package cn.lihu.jh.module.system.dal.mysql.notify;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.mybatis.core.mapper.BaseMapperX;
-import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.lihu.jh.framework.mybatis.core.query.QueryWrapperX;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyMessageDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.time.LocalDateTime;
-import java.util.Collection;
-import java.util.List;
-
-@Mapper
-public interface NotifyMessageMapper extends BaseMapperX<NotifyMessageDO> {
-
-    default PageResult<NotifyMessageDO> selectPage(NotifyMessagePageReqVO reqVO) {
-        return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>()
-                .eqIfPresent(NotifyMessageDO::getUserId, reqVO.getUserId())
-                .eqIfPresent(NotifyMessageDO::getUserType, reqVO.getUserType())
-                .likeIfPresent(NotifyMessageDO::getTemplateCode, reqVO.getTemplateCode())
-                .eqIfPresent(NotifyMessageDO::getTemplateType, reqVO.getTemplateType())
-                .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())
-                .orderByDesc(NotifyMessageDO::getId));
-    }
-
-    default PageResult<NotifyMessageDO> selectPage(NotifyMessageMyPageReqVO reqVO, Long userId, Integer userType) {
-        return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>()
-                .eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus())
-                .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())
-                .eq(NotifyMessageDO::getUserId, userId)
-                .eq(NotifyMessageDO::getUserType, userType)
-                .orderByDesc(NotifyMessageDO::getId));
-    }
-
-    default int updateListRead(Collection<Long> ids, Long userId, Integer userType) {
-        return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()),
-                new LambdaQueryWrapperX<NotifyMessageDO>()
-                        .in(NotifyMessageDO::getId, ids)
-                        .eq(NotifyMessageDO::getUserId, userId)
-                        .eq(NotifyMessageDO::getUserType, userType)
-                        .eq(NotifyMessageDO::getReadStatus, false));
-    }
-
-    default int updateListRead(Long userId, Integer userType) {
-        return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()),
-                new LambdaQueryWrapperX<NotifyMessageDO>()
-                        .eq(NotifyMessageDO::getUserId, userId)
-                        .eq(NotifyMessageDO::getUserType, userType)
-                        .eq(NotifyMessageDO::getReadStatus, false));
-    }
-
-    default List<NotifyMessageDO> selectUnreadListByUserIdAndUserType(Long userId, Integer userType, Integer size) {
-        return selectList(new QueryWrapperX<NotifyMessageDO>() // 鐢变簬瑕佷娇鐢� limitN 璇彞锛屾墍浠ュ彧鑳界敤 QueryWrapperX
-                .eq("user_id", userId)
-                .eq("user_type", userType)
-                .eq("read_status", false)
-                .orderByDesc("id").limitN(size));
-    }
-
-    default Long selectUnreadCountByUserIdAndUserType(Long userId, Integer userType) {
-        return selectCount(new LambdaQueryWrapperX<NotifyMessageDO>()
-                .eq(NotifyMessageDO::getReadStatus, false)
-                .eq(NotifyMessageDO::getUserId, userId)
-                .eq(NotifyMessageDO::getUserType, userType));
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/notify/NotifyTemplateMapper.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/notify/NotifyTemplateMapper.java
deleted file mode 100644
index 9d9c523..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/mysql/notify/NotifyTemplateMapper.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package cn.lihu.jh.module.system.dal.mysql.notify;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.mybatis.core.mapper.BaseMapperX;
-import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyTemplateDO;
-import org.apache.ibatis.annotations.Mapper;
-
-@Mapper
-public interface NotifyTemplateMapper extends BaseMapperX<NotifyTemplateDO> {
-
-    default NotifyTemplateDO selectByCode(String code) {
-        return selectOne(NotifyTemplateDO::getCode, code);
-    }
-
-    default PageResult<NotifyTemplateDO> selectPage(NotifyTemplatePageReqVO reqVO) {
-        return selectPage(reqVO, new LambdaQueryWrapperX<NotifyTemplateDO>()
-                .likeIfPresent(NotifyTemplateDO::getCode, reqVO.getCode())
-                .likeIfPresent(NotifyTemplateDO::getName, reqVO.getName())
-                .eqIfPresent(NotifyTemplateDO::getStatus, reqVO.getStatus())
-                .betweenIfPresent(NotifyTemplateDO::getCreateTime, reqVO.getCreateTime())
-                .orderByDesc(NotifyTemplateDO::getId));
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/redis/RedisKeyConstants.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/redis/RedisKeyConstants.java
index ff34ada..21c8d44 100644
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/dal/redis/RedisKeyConstants.java
+++ b/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 鏍煎紡锛歯otify_template:{code}
-     * VALUE 鏁版嵁鏍煎紡锛歋tring 妯$増淇℃伅
-     */
-    String NOTIFY_TEMPLATE = "notify_template";
-
-    /**
-     * 閭欢璐﹀彿鐨勭紦瀛�
-     * <p>
-     * KEY 鏍煎紡锛歮ail_account:{id}
-     * VALUE 鏁版嵁鏍煎紡锛歋tring 璐﹀彿淇℃伅
-     */
-    String MAIL_ACCOUNT = "mail_account";
-
-    /**
-     * 閭欢妯$増鐨勭紦瀛�
-     * <p>
-     * KEY 鏍煎紡锛歮ail_template:{code}
-     * VALUE 鏁版嵁鏍煎紡锛歋tring 妯$増淇℃伅
-     */
-    String MAIL_TEMPLATE = "mail_template";
-
-    /**
      * 鐭俊妯$増鐨勭紦瀛�
      * <p>
      * KEY 鏍煎紡锛歴ms_template:{id}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/consumer/mail/MailSendConsumer.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/consumer/mail/MailSendConsumer.java
deleted file mode 100644
index 451a76c..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/consumer/mail/MailSendConsumer.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package cn.lihu.jh.module.system.mq.consumer.mail;
-
-import cn.lihu.jh.module.system.mq.message.mail.MailSendMessage;
-import cn.lihu.jh.module.system.service.mail.MailSendService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.event.EventListener;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 閽堝 {@link MailSendMessage} 鐨勬秷璐硅��
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Component
-@Slf4j
-public class MailSendConsumer {
-
-    @Resource
-    private MailSendService mailSendService;
-
-    @EventListener
-    @Async // Spring Event 榛樿鍦� Producer 鍙戦�佺殑绾跨▼锛岄�氳繃 @Async 瀹炵幇寮傛
-    public void onMessage(MailSendMessage message) {
-        log.info("[onMessage][娑堟伅鍐呭({})]", message);
-        mailSendService.doSendMail(message);
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/message/mail/MailSendMessage.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/message/mail/MailSendMessage.java
deleted file mode 100644
index d211cb2..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/message/mail/MailSendMessage.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package cn.lihu.jh.module.system.mq.message.mail;
-
-import lombok.Data;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-
-/**
- * 閭鍙戦�佹秷鎭�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-public class MailSendMessage {
-
-    /**
-     * 閭欢鏃ュ織缂栧彿
-     */
-    @NotNull(message = "閭欢鏃ュ織缂栧彿涓嶈兘涓虹┖")
-    private Long logId;
-    /**
-     * 鎺ユ敹閭欢鍦板潃
-     */
-    @NotNull(message = "鎺ユ敹閭欢鍦板潃涓嶈兘涓虹┖")
-    private String mail;
-    /**
-     * 閭欢璐﹀彿缂栧彿
-     */
-    @NotNull(message = "閭欢璐﹀彿缂栧彿涓嶈兘涓虹┖")
-    private Long accountId;
-
-    /**
-     * 閭欢鍙戜欢浜�
-     */
-    private String nickname;
-    /**
-     * 閭欢鏍囬
-     */
-    @NotEmpty(message = "閭欢鏍囬涓嶈兘涓虹┖")
-    private String title;
-    /**
-     * 閭欢鍐呭
-     */
-    @NotEmpty(message = "閭欢鍐呭涓嶈兘涓虹┖")
-    private String content;
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/producer/mail/MailProducer.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/producer/mail/MailProducer.java
deleted file mode 100644
index 5aba4ce..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/mq/producer/mail/MailProducer.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package cn.lihu.jh.module.system.mq.producer.mail;
-
-import cn.lihu.jh.module.system.mq.message.mail.MailSendMessage;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.ApplicationContext;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * Mail 閭欢鐩稿叧娑堟伅鐨� Producer
- *
- * @author wangjingyi
- * @since 2021/4/19 13:33
- */
-@Slf4j
-@Component
-public class MailProducer {
-
-    @Resource
-    private ApplicationContext applicationContext;
-
-    /**
-     * 鍙戦�� {@link MailSendMessage} 娑堟伅
-     *
-     * @param sendLogId 鍙戦�佹棩蹇楃紪鐮�
-     * @param mail 鎺ユ敹閭欢鍦板潃
-     * @param accountId 閭欢璐﹀彿缂栧彿
-     * @param nickname 閭欢鍙戜欢浜�
-     * @param title 閭欢鏍囬
-     * @param content 閭欢鍐呭
-     */
-    public void sendMailSendMessage(Long sendLogId, String mail, Long accountId,
-                                    String nickname, String title, String content) {
-        MailSendMessage message = new MailSendMessage()
-                .setLogId(sendLogId).setMail(mail).setAccountId(accountId)
-                .setNickname(nickname).setTitle(title).setContent(content);
-        applicationContext.publishEvent(message);
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailAccountService.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailAccountService.java
deleted file mode 100644
index 9145fd0..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailAccountService.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package cn.lihu.jh.module.system.service.mail;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.account.MailAccountSaveReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailAccountDO;
-
-import javax.validation.Valid;
-import java.util.List;
-
-/**
- * 閭璐﹀彿 Service 鎺ュ彛
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-public interface MailAccountService {
-
-    /**
-     * 鍒涘缓閭璐﹀彿
-     *
-     * @param createReqVO 閭璐﹀彿淇℃伅
-     * @return 缂栧彿
-     */
-    Long createMailAccount(@Valid MailAccountSaveReqVO createReqVO);
-
-    /**
-     * 淇敼閭璐﹀彿
-     *
-     * @param updateReqVO 閭璐﹀彿淇℃伅
-     */
-    void updateMailAccount(@Valid MailAccountSaveReqVO updateReqVO);
-
-    /**
-     * 鍒犻櫎閭璐﹀彿
-     *
-     * @param id 缂栧彿
-     */
-    void deleteMailAccount(Long id);
-
-    /**
-     * 鑾峰彇閭璐﹀彿淇℃伅
-     *
-     * @param id 缂栧彿
-     * @return 閭璐﹀彿淇℃伅
-     */
-    MailAccountDO getMailAccount(Long id);
-
-    /**
-     * 浠庣紦瀛樹腑鑾峰彇閭璐﹀彿
-     *
-     * @param id 缂栧彿
-     * @return 閭璐﹀彿
-     */
-    MailAccountDO getMailAccountFromCache(Long id);
-
-    /**
-     * 鑾峰彇閭璐﹀彿鍒嗛〉淇℃伅
-     *
-     * @param pageReqVO 閭璐﹀彿鍒嗛〉鍙傛暟
-     * @return 閭璐﹀彿鍒嗛〉淇℃伅
-     */
-    PageResult<MailAccountDO> getMailAccountPage(MailAccountPageReqVO pageReqVO);
-
-    /**
-     * 鑾峰彇閭鏁扮粍淇℃伅
-     *
-     * @return 閭璐﹀彿淇℃伅鏁扮粍
-     */
-    List<MailAccountDO> getMailAccountList();
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailAccountServiceImpl.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailAccountServiceImpl.java
deleted file mode 100644
index 9bc3d87..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailAccountServiceImpl.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package cn.lihu.jh.module.system.service.mail;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.common.util.object.BeanUtils;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.account.MailAccountSaveReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailAccountDO;
-import cn.lihu.jh.module.system.dal.mysql.mail.MailAccountMapper;
-import cn.lihu.jh.module.system.dal.redis.RedisKeyConstants;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import javax.annotation.Resource;
-import java.util.List;
-
-import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.lihu.jh.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS;
-import static cn.lihu.jh.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS;
-
-/**
- * 閭璐﹀彿 Service 瀹炵幇绫�
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-@Service
-@Validated
-@Slf4j
-public class MailAccountServiceImpl implements MailAccountService {
-
-    @Resource
-    private MailAccountMapper mailAccountMapper;
-
-    @Resource
-    private MailTemplateService mailTemplateService;
-
-    @Override
-    public Long createMailAccount(MailAccountSaveReqVO createReqVO) {
-        MailAccountDO account = BeanUtils.toBean(createReqVO, MailAccountDO.class);
-        mailAccountMapper.insert(account);
-        return account.getId();
-    }
-
-    @Override
-    @CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#updateReqVO.id")
-    public void updateMailAccount(MailAccountSaveReqVO updateReqVO) {
-        // 鏍¢獙鏄惁瀛樺湪
-        validateMailAccountExists(updateReqVO.getId());
-
-        // 鏇存柊
-        MailAccountDO updateObj = BeanUtils.toBean(updateReqVO, MailAccountDO.class);
-        mailAccountMapper.updateById(updateObj);
-    }
-
-    @Override
-    @CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id")
-    public void deleteMailAccount(Long id) {
-        // 鏍¢獙鏄惁瀛樺湪璐﹀彿
-        validateMailAccountExists(id);
-        // 鏍¢獙鏄惁瀛樺湪鍏宠仈妯$増
-        if (mailTemplateService.getMailTemplateCountByAccountId(id) > 0) {
-            throw exception(MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS);
-        }
-
-        // 鍒犻櫎
-        mailAccountMapper.deleteById(id);
-    }
-
-    private void validateMailAccountExists(Long id) {
-        if (mailAccountMapper.selectById(id) == null) {
-            throw exception(MAIL_ACCOUNT_NOT_EXISTS);
-        }
-    }
-
-    @Override
-    public MailAccountDO getMailAccount(Long id) {
-        return mailAccountMapper.selectById(id);
-    }
-
-    @Override
-    @Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id", unless = "#result == null")
-    public MailAccountDO getMailAccountFromCache(Long id) {
-        return getMailAccount(id);
-    }
-
-    @Override
-    public PageResult<MailAccountDO> getMailAccountPage(MailAccountPageReqVO pageReqVO) {
-        return mailAccountMapper.selectPage(pageReqVO);
-    }
-
-    @Override
-    public List<MailAccountDO> getMailAccountList() {
-        return mailAccountMapper.selectList();
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailLogService.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailLogService.java
deleted file mode 100644
index 7b295b1..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailLogService.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package cn.lihu.jh.module.system.service.mail;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailAccountDO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailLogDO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailTemplateDO;
-
-import java.util.Map;
-
-/**
- * 閭欢鏃ュ織 Service 鎺ュ彛
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-public interface MailLogService {
-
-    /**
-     * 閭欢鏃ュ織鍒嗛〉
-     *
-     * @param pageVO 鍒嗛〉鍙傛暟
-     * @return 鍒嗛〉缁撴灉
-     */
-    PageResult<MailLogDO> getMailLogPage(MailLogPageReqVO pageVO);
-
-    /**
-     * 鑾峰緱鎸囧畾缂栧彿鐨勯偖浠舵棩蹇�
-     *
-     * @param id 鏃ュ織缂栧彿
-     * @return 閭欢鏃ュ織
-     */
-    MailLogDO getMailLog(Long id);
-
-    /**
-     * 鍒涘缓閭欢鏃ュ織
-     *
-     * @param userId 鐢ㄦ埛缂栫爜
-     * @param userType 鐢ㄦ埛绫诲瀷
-     * @param toMail 鏀朵欢浜洪偖浠�
-     * @param account 閭欢璐﹀彿淇℃伅
-     * @param template      妯$増淇℃伅
-     * @param templateContent 妯$増鍐呭
-     * @param templateParams 妯$増鍙傛暟
-     * @param isSend        鏄惁鍙戦�佹垚鍔�
-     * @return 鏃ュ織缂栧彿
-     */
-    Long createMailLog(Long userId, Integer userType, String toMail,
-                       MailAccountDO account, MailTemplateDO template ,
-                       String templateContent, Map<String, Object> templateParams, Boolean isSend);
-
-    /**
-     * 鏇存柊閭欢鍙戦�佺粨鏋�
-     *
-     * @param logId  鏃ュ織缂栧彿
-     * @param messageId 鍙戦�佸悗鐨勬秷鎭紪鍙�
-     * @param exception 鍙戦�佸紓甯�
-     */
-    void updateMailSendResult(Long logId, String messageId, Exception exception);
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailLogServiceImpl.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailLogServiceImpl.java
deleted file mode 100644
index ff9d607..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailLogServiceImpl.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package cn.lihu.jh.module.system.service.mail;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailAccountDO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailLogDO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailTemplateDO;
-import cn.lihu.jh.module.system.dal.mysql.mail.MailLogMapper;
-import cn.lihu.jh.module.system.enums.mail.MailSendStatusEnum;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import javax.annotation.Resource;
-import java.time.LocalDateTime;
-import java.util.Map;
-import java.util.Objects;
-
-import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage;
-
-/**
- * 閭欢鏃ュ織 Service 瀹炵幇绫�
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-@Service
-@Validated
-public class MailLogServiceImpl implements MailLogService {
-
-    @Resource
-    private MailLogMapper mailLogMapper;
-
-    @Override
-    public PageResult<MailLogDO> getMailLogPage(MailLogPageReqVO pageVO) {
-        return mailLogMapper.selectPage(pageVO);
-    }
-
-    @Override
-    public MailLogDO getMailLog(Long id) {
-        return mailLogMapper.selectById(id);
-    }
-
-    @Override
-    public Long createMailLog(Long userId, Integer userType, String toMail,
-                              MailAccountDO account, MailTemplateDO template,
-                              String templateContent, Map<String, Object> templateParams, Boolean isSend) {
-        MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
-        // 鏍规嵁鏄惁瑕佸彂閫侊紝璁剧疆鐘舵��
-        logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus()
-                : MailSendStatusEnum.IGNORE.getStatus())
-                // 鐢ㄦ埛淇℃伅
-                .userId(userId).userType(userType).toMail(toMail)
-                .accountId(account.getId()).fromMail(account.getMail())
-                // 妯℃澘鐩稿叧瀛楁
-                .templateId(template.getId()).templateCode(template.getCode()).templateNickname(template.getNickname())
-                .templateTitle(template.getTitle()).templateContent(templateContent).templateParams(templateParams);
-
-        // 鎻掑叆鏁版嵁搴�
-        MailLogDO logDO = logDOBuilder.build();
-        mailLogMapper.insert(logDO);
-        return logDO.getId();
-    }
-
-    @Override
-    public void updateMailSendResult(Long logId, String messageId, Exception exception) {
-        // 1. 鎴愬姛
-        if (exception == null) {
-            mailLogMapper.updateById(new MailLogDO().setId(logId).setSendTime(LocalDateTime.now())
-                    .setSendStatus(MailSendStatusEnum.SUCCESS.getStatus()).setSendMessageId(messageId));
-            return;
-        }
-        // 2. 澶辫触
-        mailLogMapper.updateById(new MailLogDO().setId(logId).setSendTime(LocalDateTime.now())
-                .setSendStatus(MailSendStatusEnum.FAILURE.getStatus()).setSendException(getRootCauseMessage(exception)));
-
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailSendService.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailSendService.java
deleted file mode 100644
index 5ef836c..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailSendService.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package cn.lihu.jh.module.system.service.mail;
-
-import cn.lihu.jh.module.system.mq.message.mail.MailSendMessage;
-
-import java.util.Map;
-
-/**
- * 閭欢鍙戦�� Service 鎺ュ彛
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-public interface MailSendService {
-
-    /**
-     * 鍙戦�佸崟鏉¢偖浠剁粰绠$悊鍚庡彴鐨勭敤鎴�
-     *
-     * @param mail 閭
-     * @param userId 鐢ㄦ埛缂栫爜
-     * @param templateCode 閭欢妯$増缂栫爜
-     * @param templateParams 閭欢妯$増鍙傛暟
-     * @return 鍙戦�佹棩蹇楃紪鍙�
-     */
-    Long sendSingleMailToAdmin(String mail, Long userId,
-                               String templateCode, Map<String, Object> templateParams);
-
-    /**
-     * 鍙戦�佸崟鏉¢偖浠剁粰鐢ㄦ埛 APP 鐨勭敤鎴�
-     *
-     * @param mail 閭
-     * @param userId 鐢ㄦ埛缂栫爜
-     * @param templateCode 閭欢妯$増缂栫爜
-     * @param templateParams 閭欢妯$増鍙傛暟
-     * @return 鍙戦�佹棩蹇楃紪鍙�
-     */
-    Long sendSingleMailToMember(String mail, Long userId,
-                                String templateCode, Map<String, Object> templateParams);
-
-    /**
-     * 鍙戦�佸崟鏉¢偖浠剁粰鐢ㄦ埛
-     *
-     * @param mail 閭
-     * @param userId 鐢ㄦ埛缂栫爜
-     * @param userType 鐢ㄦ埛绫诲瀷
-     * @param templateCode 閭欢妯$増缂栫爜
-     * @param templateParams 閭欢妯$増鍙傛暟
-     * @return 鍙戦�佹棩蹇楃紪鍙�
-     */
-    Long sendSingleMail(String mail, Long userId, Integer userType,
-                        String templateCode, Map<String, Object> templateParams);
-
-    /**
-     * 鎵ц鐪熸鐨勯偖浠跺彂閫�
-     * 娉ㄦ剰锛岃鏂规硶浠呬粎鎻愪緵缁� MQ Consumer 浣跨敤
-     *
-     * @param message 閭欢
-     */
-    void doSendMail(MailSendMessage message);
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailSendServiceImpl.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailSendServiceImpl.java
deleted file mode 100644
index 03df8ac..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailSendServiceImpl.java
+++ /dev/null
@@ -1,174 +0,0 @@
-package cn.lihu.jh.module.system.service.mail;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.mail.MailAccount;
-import cn.hutool.extra.mail.MailUtil;
-import cn.lihu.jh.framework.common.enums.CommonStatusEnum;
-import cn.lihu.jh.framework.common.enums.UserTypeEnum;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailAccountDO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailTemplateDO;
-import cn.lihu.jh.module.system.dal.dataobject.user.AdminUserDO;
-import cn.lihu.jh.module.system.mq.message.mail.MailSendMessage;
-import cn.lihu.jh.module.system.mq.producer.mail.MailProducer;
-import cn.lihu.jh.module.system.service.member.MemberService;
-import cn.lihu.jh.module.system.service.user.AdminUserService;
-import com.google.common.annotations.VisibleForTesting;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import javax.annotation.Resource;
-import java.util.Map;
-
-import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.lihu.jh.module.system.enums.ErrorCodeConstants.*;
-
-/**
- * 閭鍙戦�� Service 瀹炵幇绫�
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-@Service
-@Validated
-@Slf4j
-public class MailSendServiceImpl implements MailSendService {
-
-    @Resource
-    private AdminUserService adminUserService;
-    @Resource
-    private MemberService memberService;
-
-    @Resource
-    private MailAccountService mailAccountService;
-    @Resource
-    private MailTemplateService mailTemplateService;
-
-    @Resource
-    private MailLogService mailLogService;
-    @Resource
-    private MailProducer mailProducer;
-
-    @Override
-    public Long sendSingleMailToAdmin(String mail, Long userId,
-                                      String templateCode, Map<String, Object> templateParams) {
-        // 濡傛灉 mail 涓虹┖锛屽垯鍔犺浇鐢ㄦ埛缂栧彿瀵瑰簲鐨勯偖绠�
-        if (StrUtil.isEmpty(mail)) {
-            AdminUserDO user = adminUserService.getUser(userId);
-            if (user != null) {
-                mail = user.getEmail();
-            }
-        }
-        // 鎵ц鍙戦��
-        return sendSingleMail(mail, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
-    }
-
-    @Override
-    public Long sendSingleMailToMember(String mail, Long userId,
-                                       String templateCode, Map<String, Object> templateParams) {
-        // 濡傛灉 mail 涓虹┖锛屽垯鍔犺浇鐢ㄦ埛缂栧彿瀵瑰簲鐨勯偖绠�
-        if (StrUtil.isEmpty(mail)) {
-            mail = memberService.getMemberUserEmail(userId);
-        }
-        // 鎵ц鍙戦��
-        return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
-    }
-
-    @Override
-    public Long sendSingleMail(String mail, Long userId, Integer userType,
-                               String templateCode, Map<String, Object> templateParams) {
-        // 鏍¢獙閭妯$増鏄惁鍚堟硶
-        MailTemplateDO template = validateMailTemplate(templateCode);
-        // 鏍¢獙閭璐﹀彿鏄惁鍚堟硶
-        MailAccountDO account = validateMailAccount(template.getAccountId());
-
-        // 鏍¢獙閭鏄惁瀛樺湪
-        mail = validateMail(mail);
-        validateTemplateParams(template, templateParams);
-
-        // 鍒涘缓鍙戦�佹棩蹇椼�傚鏋滄ā鏉胯绂佺敤锛屽垯涓嶅彂閫佺煭淇★紝鍙褰曟棩蹇�
-        Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
-        String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams);
-        String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams);
-        Long sendLogId = mailLogService.createMailLog(userId, userType, mail,
-                account, template, content, templateParams, isSend);
-        // 鍙戦�� MQ 娑堟伅锛屽紓姝ユ墽琛屽彂閫佺煭淇�
-        if (isSend) {
-            mailProducer.sendMailSendMessage(sendLogId, mail, account.getId(),
-                    template.getNickname(), title, content);
-        }
-        return sendLogId;
-    }
-
-    @Override
-    public void doSendMail(MailSendMessage message) {
-        // 1. 鍒涘缓鍙戦�佽处鍙�
-        MailAccountDO account = validateMailAccount(message.getAccountId());
-        MailAccount mailAccount  = buildMailAccount(account, message.getNickname());
-        // 2. 鍙戦�侀偖浠�
-        try {
-            String messageId = MailUtil.send(mailAccount, message.getMail(),
-                    message.getTitle(), message.getContent(), true);
-            // 3. 鏇存柊缁撴灉锛堟垚鍔燂級
-            mailLogService.updateMailSendResult(message.getLogId(), messageId, null);
-        } catch (Exception e) {
-            // 3. 鏇存柊缁撴灉锛堝紓甯革級
-            mailLogService.updateMailSendResult(message.getLogId(), null, e);
-        }
-    }
-
-    private MailAccount buildMailAccount(MailAccountDO account, String nickname) {
-        String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail();
-        return new MailAccount().setFrom(from).setAuth(true)
-                .setUser(account.getUsername()).setPass(account.getPassword())
-                .setHost(account.getHost()).setPort(account.getPort())
-                .setSslEnable(account.getSslEnable()).setStarttlsEnable(account.getStarttlsEnable());
-    }
-
-    @VisibleForTesting
-    MailTemplateDO validateMailTemplate(String templateCode) {
-        // 鑾峰緱閭欢妯℃澘銆傝�冭檻鍒版晥鐜囷紝浠庣紦瀛樹腑鑾峰彇
-        MailTemplateDO template = mailTemplateService.getMailTemplateByCodeFromCache(templateCode);
-        // 閭欢妯℃澘涓嶅瓨鍦�
-        if (template == null) {
-            throw exception(MAIL_TEMPLATE_NOT_EXISTS);
-        }
-        return template;
-    }
-
-    @VisibleForTesting
-    MailAccountDO validateMailAccount(Long accountId) {
-        // 鑾峰緱閭璐﹀彿銆傝�冭檻鍒版晥鐜囷紝浠庣紦瀛樹腑鑾峰彇
-        MailAccountDO account = mailAccountService.getMailAccountFromCache(accountId);
-        // 閭璐﹀彿涓嶅瓨鍦�
-        if (account == null) {
-            throw exception(MAIL_ACCOUNT_NOT_EXISTS);
-        }
-        return account;
-    }
-
-    @VisibleForTesting
-    String validateMail(String mail) {
-        if (StrUtil.isEmpty(mail)) {
-            throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
-        }
-        return mail;
-    }
-
-    /**
-     * 鏍¢獙閭欢鍙傛暟鏄惁纭疄
-     *
-     * @param template 閭妯℃澘
-     * @param templateParams 鍙傛暟鍒楄〃
-     */
-    @VisibleForTesting
-    void validateTemplateParams(MailTemplateDO template, Map<String, Object> templateParams) {
-        template.getParams().forEach(key -> {
-            Object value = templateParams.get(key);
-            if (value == null) {
-                throw exception(MAIL_SEND_TEMPLATE_PARAM_MISS, key);
-            }
-        });
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailTemplateService.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailTemplateService.java
deleted file mode 100644
index df59ddf..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailTemplateService.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package cn.lihu.jh.module.system.service.mail;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailTemplateDO;
-
-import javax.validation.Valid;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 閭欢妯$増 Service 鎺ュ彛
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-public interface MailTemplateService {
-
-    /**
-     * 閭欢妯$増鍒涘缓
-     *
-     * @param createReqVO 閭欢淇℃伅
-     * @return 缂栧彿
-     */
-    Long createMailTemplate(@Valid MailTemplateSaveReqVO createReqVO);
-
-    /**
-     * 閭欢妯$増淇敼
-     *
-     * @param updateReqVO 閭欢淇℃伅
-     */
-    void updateMailTemplate(@Valid MailTemplateSaveReqVO updateReqVO);
-
-    /**
-     * 閭欢妯$増鍒犻櫎
-     *
-     * @param id 缂栧彿
-     */
-    void deleteMailTemplate(Long id);
-
-    /**
-     * 鑾峰彇閭欢妯$増
-     *
-     * @param id 缂栧彿
-     * @return 閭欢妯$増
-     */
-    MailTemplateDO getMailTemplate(Long id);
-
-    /**
-     * 鑾峰彇閭欢妯$増鍒嗛〉
-     *
-     * @param pageReqVO 妯$増淇℃伅
-     * @return 閭欢妯$増鍒嗛〉淇℃伅
-     */
-    PageResult<MailTemplateDO> getMailTemplatePage(MailTemplatePageReqVO pageReqVO);
-
-    /**
-     * 鑾峰彇閭欢妯℃澘鏁扮粍
-     *
-     * @return 妯$増鏁扮粍
-     */
-    List<MailTemplateDO> getMailTemplateList();
-
-    /**
-     * 浠庣紦瀛樹腑鑾峰彇閭欢妯$増
-     *
-     * @param code 妯℃澘缂栫爜
-     * @return 閭欢妯℃澘
-     */
-    MailTemplateDO getMailTemplateByCodeFromCache(String code);
-
-    /**
-     * 閭欢妯$増鍐呭鍚堟垚
-     *
-     * @param content 閭欢妯$増
-     * @param params 鍚堟垚鍙傛暟
-     * @return 鏍煎紡鍖栧悗鐨勫唴瀹�
-     */
-    String formatMailTemplateContent(String content, Map<String, Object> params);
-
-    /**
-     * 鑾峰緱鎸囧畾閭欢璐﹀彿涓嬬殑閭欢妯℃澘鏁伴噺
-     *
-     * @param accountId 璐﹀彿缂栧彿
-     * @return 鏁伴噺
-     */
-    long getMailTemplateCountByAccountId(Long accountId);
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailTemplateServiceImpl.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailTemplateServiceImpl.java
deleted file mode 100644
index 0f087ff..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/mail/MailTemplateServiceImpl.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package cn.lihu.jh.module.system.service.mail;
-
-import cn.hutool.core.util.ObjUtil;
-import cn.hutool.core.util.ReUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.common.util.object.BeanUtils;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;
-import cn.lihu.jh.module.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.mail.MailTemplateDO;
-import cn.lihu.jh.module.system.dal.mysql.mail.MailTemplateMapper;
-import cn.lihu.jh.module.system.dal.redis.RedisKeyConstants;
-import com.google.common.annotations.VisibleForTesting;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import javax.annotation.Resource;
-import javax.validation.Valid;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.lihu.jh.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_CODE_EXISTS;
-import static cn.lihu.jh.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS;
-
-/**
- * 閭妯$増 Service 瀹炵幇绫�
- *
- * @author wangjingyi
- * @since 2022-03-21
- */
-@Service
-@Validated
-@Slf4j
-public class MailTemplateServiceImpl implements MailTemplateService {
-
-    /**
-     * 姝e垯琛ㄨ揪寮忥紝鍖归厤 {} 涓殑鍙橀噺
-     */
-    private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}");
-
-    @Resource
-    private MailTemplateMapper mailTemplateMapper;
-
-    @Override
-    public Long createMailTemplate(MailTemplateSaveReqVO createReqVO) {
-        // 鏍¢獙 code 鏄惁鍞竴
-        validateCodeUnique(null, createReqVO.getCode());
-
-        // 鎻掑叆
-        MailTemplateDO template = BeanUtils.toBean(createReqVO, MailTemplateDO.class)
-                .setParams(parseTemplateContentParams(createReqVO.getContent()));
-        mailTemplateMapper.insert(template);
-        return template.getId();
-    }
-
-    @Override
-    @CacheEvict(cacheNames = RedisKeyConstants.MAIL_TEMPLATE,
-            allEntries = true) // allEntries 娓呯┖鎵�鏈夌紦瀛橈紝鍥犱负鍙兘淇敼鍒� code 瀛楁锛屼笉濂芥竻鐞�
-    public void updateMailTemplate(@Valid MailTemplateSaveReqVO updateReqVO) {
-        // 鏍¢獙鏄惁瀛樺湪
-        validateMailTemplateExists(updateReqVO.getId());
-        // 鏍¢獙 code 鏄惁鍞竴
-        validateCodeUnique(updateReqVO.getId(),updateReqVO.getCode());
-
-        // 鏇存柊
-        MailTemplateDO updateObj = BeanUtils.toBean(updateReqVO, MailTemplateDO.class)
-                .setParams(parseTemplateContentParams(updateReqVO.getContent()));
-        mailTemplateMapper.updateById(updateObj);
-    }
-
-    @VisibleForTesting
-    void validateCodeUnique(Long id, String code) {
-        MailTemplateDO template = mailTemplateMapper.selectByCode(code);
-        if (template == null) {
-            return;
-        }
-        // 瀛樺湪 template 璁板綍鐨勬儏鍐典笅
-        if (id == null // 鏂板鏃讹紝璇存槑閲嶅
-                || ObjUtil.notEqual(id, template.getId())) { // 鏇存柊鏃讹紝濡傛灉 id 涓嶄竴鑷达紝璇存槑閲嶅
-            throw exception(MAIL_TEMPLATE_CODE_EXISTS);
-        }
-    }
-
-    @Override
-    @CacheEvict(cacheNames = RedisKeyConstants.MAIL_TEMPLATE,
-            allEntries = true) // allEntries 娓呯┖鎵�鏈夌紦瀛橈紝鍥犱负 id 涓嶆槸鐩存帴鐨勭紦瀛� code锛屼笉濂芥竻鐞�
-    public void deleteMailTemplate(Long id) {
-        // 鏍¢獙鏄惁瀛樺湪
-        validateMailTemplateExists(id);
-
-        // 鍒犻櫎
-        mailTemplateMapper.deleteById(id);
-    }
-
-    private void validateMailTemplateExists(Long id) {
-        if (mailTemplateMapper.selectById(id) == null) {
-            throw exception(MAIL_TEMPLATE_NOT_EXISTS);
-        }
-    }
-
-    @Override
-    public MailTemplateDO getMailTemplate(Long id) {return mailTemplateMapper.selectById(id);}
-
-    @Override
-    @Cacheable(value = RedisKeyConstants.MAIL_TEMPLATE, key = "#code", unless = "#result == null")
-    public MailTemplateDO getMailTemplateByCodeFromCache(String code) {
-        return mailTemplateMapper.selectByCode(code);
-    }
-
-    @Override
-    public PageResult<MailTemplateDO> getMailTemplatePage(MailTemplatePageReqVO pageReqVO) {
-        return mailTemplateMapper.selectPage(pageReqVO);
-    }
-
-    @Override
-    public List<MailTemplateDO> getMailTemplateList() {return mailTemplateMapper.selectList();}
-
-    @Override
-    public String formatMailTemplateContent(String content, Map<String, Object> params) {
-        return StrUtil.format(content, params);
-    }
-
-    @VisibleForTesting
-    public List<String> parseTemplateContentParams(String content) {
-        return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
-    }
-
-    @Override
-    public long getMailTemplateCountByAccountId(Long accountId) {
-        return mailTemplateMapper.selectCountByAccountId(accountId);
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyMessageService.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyMessageService.java
deleted file mode 100644
index c31bfb0..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyMessageService.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package cn.lihu.jh.module.system.service.notify;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyMessageDO;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyTemplateDO;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 绔欏唴淇� Service 鎺ュ彛
- *
- * @author xrcoder
- */
-public interface NotifyMessageService {
-
-    /**
-     * 鍒涘缓绔欏唴淇�
-     *
-     * @param userId 鐢ㄦ埛缂栧彿
-     * @param userType 鐢ㄦ埛绫诲瀷
-     * @param template 妯$増淇℃伅
-     * @param templateContent 妯$増鍐呭
-     * @param templateParams 妯$増鍙傛暟
-     * @return 绔欏唴淇$紪鍙�
-     */
-    Long createNotifyMessage(Long userId, Integer userType,
-                             NotifyTemplateDO template, String templateContent, Map<String, Object> templateParams);
-
-    /**
-     * 鑾峰緱绔欏唴淇″垎椤�
-     *
-     * @param pageReqVO 鍒嗛〉鏌ヨ
-     * @return 绔欏唴淇″垎椤�
-     */
-    PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO);
-
-    /**
-     * 鑾峰緱銆愭垜鐨勩�戠珯鍐呬俊鍒嗛〉
-     *
-     * @param pageReqVO 鍒嗛〉鏌ヨ
-     * @param userId 鐢ㄦ埛缂栧彿
-     * @param userType 鐢ㄦ埛绫诲瀷
-     * @return 绔欏唴淇″垎椤�
-     */
-    PageResult<NotifyMessageDO> getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType);
-
-    /**
-     * 鑾峰緱绔欏唴淇�
-     *
-     * @param id 缂栧彿
-     * @return 绔欏唴淇�
-     */
-    NotifyMessageDO getNotifyMessage(Long id);
-
-    /**
-     * 鑾峰緱銆愭垜鐨勩�戞湭璇荤珯鍐呬俊鍒楄〃
-     *
-     * @param userId   鐢ㄦ埛缂栧彿
-     * @param userType 鐢ㄦ埛绫诲瀷
-     * @param size     鏁伴噺
-     * @return 绔欏唴淇″垪琛�
-     */
-    List<NotifyMessageDO> getUnreadNotifyMessageList(Long userId, Integer userType, Integer size);
-
-    /**
-     * 缁熻鐢ㄦ埛鏈绔欏唴淇℃潯鏁�
-     *
-     * @param userId   鐢ㄦ埛缂栧彿
-     * @param userType 鐢ㄦ埛绫诲瀷
-     * @return 杩斿洖鏈绔欏唴淇℃潯鏁�
-     */
-    Long getUnreadNotifyMessageCount(Long userId, Integer userType);
-
-    /**
-     * 鏍囪绔欏唴淇′负宸茶
-     *
-     * @param ids    绔欏唴淇$紪鍙烽泦鍚�
-     * @param userId 鐢ㄦ埛缂栧彿
-     * @param userType 鐢ㄦ埛绫诲瀷
-     * @return 鏇存柊鍒扮殑鏉℃暟
-     */
-    int updateNotifyMessageRead(Collection<Long> ids, Long userId, Integer userType);
-
-    /**
-     * 鏍囪鎵�鏈夌珯鍐呬俊涓哄凡璇�
-     *
-     * @param userId   鐢ㄦ埛缂栧彿
-     * @param userType 鐢ㄦ埛绫诲瀷
-     * @return 鏇存柊鍒扮殑鏉℃暟
-     */
-    int updateAllNotifyMessageRead(Long userId, Integer userType);
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyMessageServiceImpl.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyMessageServiceImpl.java
deleted file mode 100644
index 8d40813..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyMessageServiceImpl.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package cn.lihu.jh.module.system.service.notify;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyMessageDO;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyTemplateDO;
-import cn.lihu.jh.module.system.dal.mysql.notify.NotifyMessageMapper;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 绔欏唴淇� Service 瀹炵幇绫�
- *
- * @author xrcoder
- */
-@Service
-@Validated
-public class NotifyMessageServiceImpl implements NotifyMessageService {
-
-    @Resource
-    private NotifyMessageMapper notifyMessageMapper;
-
-    @Override
-    public Long createNotifyMessage(Long userId, Integer userType,
-                                    NotifyTemplateDO template, String templateContent, Map<String, Object> templateParams) {
-        NotifyMessageDO message = new NotifyMessageDO().setUserId(userId).setUserType(userType)
-                .setTemplateId(template.getId()).setTemplateCode(template.getCode())
-                .setTemplateType(template.getType()).setTemplateNickname(template.getNickname())
-                .setTemplateContent(templateContent).setTemplateParams(templateParams).setReadStatus(false);
-        notifyMessageMapper.insert(message);
-        return message.getId();
-    }
-
-    @Override
-    public PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO) {
-        return notifyMessageMapper.selectPage(pageReqVO);
-    }
-
-    @Override
-    public PageResult<NotifyMessageDO> getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType) {
-        return notifyMessageMapper.selectPage(pageReqVO, userId, userType);
-    }
-
-    @Override
-    public NotifyMessageDO getNotifyMessage(Long id) {
-        return notifyMessageMapper.selectById(id);
-    }
-
-    @Override
-    public List<NotifyMessageDO> getUnreadNotifyMessageList(Long userId, Integer userType, Integer size) {
-        return notifyMessageMapper.selectUnreadListByUserIdAndUserType(userId, userType, size);
-    }
-
-    @Override
-    public Long getUnreadNotifyMessageCount(Long userId, Integer userType) {
-        return notifyMessageMapper.selectUnreadCountByUserIdAndUserType(userId, userType);
-    }
-
-    @Override
-    public int updateNotifyMessageRead(Collection<Long> ids, Long userId, Integer userType) {
-        return notifyMessageMapper.updateListRead(ids, userId, userType);
-    }
-
-    @Override
-    public int updateAllNotifyMessageRead(Long userId, Integer userType) {
-        return notifyMessageMapper.updateListRead(userId, userType);
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifySendService.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifySendService.java
deleted file mode 100644
index db833cc..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifySendService.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package cn.lihu.jh.module.system.service.notify;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * 绔欏唴淇″彂閫� Service 鎺ュ彛
- *
- * @author xrcoder
- */
-public interface NotifySendService {
-
-    /**
-     * 鍙戦�佸崟鏉$珯鍐呬俊缁欑鐞嗗悗鍙扮殑鐢ㄦ埛
-     *
-     * 鍦� mobile 涓虹┖鏃讹紝浣跨敤 userId 鍔犺浇瀵瑰簲绠$悊鍛樼殑鎵嬫満鍙�
-     *
-     * @param userId 鐢ㄦ埛缂栧彿
-     * @param templateCode 鐭俊妯℃澘缂栧彿
-     * @param templateParams 鐭俊妯℃澘鍙傛暟
-     * @return 鍙戦�佹棩蹇楃紪鍙�
-     */
-    Long sendSingleNotifyToAdmin(Long userId,
-                                 String templateCode, Map<String, Object> templateParams);
-    /**
-     * 鍙戦�佸崟鏉$珯鍐呬俊缁欑敤鎴� APP 鐨勭敤鎴�
-     *
-     * 鍦� mobile 涓虹┖鏃讹紝浣跨敤 userId 鍔犺浇瀵瑰簲浼氬憳鐨勬墜鏈哄彿
-     *
-     * @param userId 鐢ㄦ埛缂栧彿
-     * @param templateCode 绔欏唴淇℃ā鏉跨紪鍙�
-     * @param templateParams 绔欏唴淇℃ā鏉垮弬鏁�
-     * @return 鍙戦�佹棩蹇楃紪鍙�
-     */
-    Long sendSingleNotifyToMember(Long userId,
-                                  String templateCode, Map<String, Object> templateParams);
-
-    /**
-     * 鍙戦�佸崟鏉$珯鍐呬俊缁欑敤鎴�
-     *
-     * @param userId 鐢ㄦ埛缂栧彿
-     * @param userType 鐢ㄦ埛绫诲瀷
-     * @param templateCode 绔欏唴淇℃ā鏉跨紪鍙�
-     * @param templateParams 绔欏唴淇℃ā鏉垮弬鏁�
-     * @return 鍙戦�佹棩蹇楃紪鍙�
-     */
-    Long sendSingleNotify( Long userId, Integer userType,
-                           String templateCode, Map<String, Object> templateParams);
-
-    default void sendBatchNotify(List<String> mobiles, List<Long> userIds, Integer userType,
-                                 String templateCode, Map<String, Object> templateParams) {
-        throw new UnsupportedOperationException("鏆傛椂涓嶆敮鎸佽鎿嶄綔锛屾劅鍏磋叮鍙互瀹炵幇璇ュ姛鑳藉摕锛�");
-    }
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifySendServiceImpl.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifySendServiceImpl.java
deleted file mode 100644
index 77f7836..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifySendServiceImpl.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package cn.lihu.jh.module.system.service.notify;
-
-import cn.lihu.jh.framework.common.enums.CommonStatusEnum;
-import cn.lihu.jh.framework.common.enums.UserTypeEnum;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyTemplateDO;
-import com.google.common.annotations.VisibleForTesting;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import javax.annotation.Resource;
-import java.util.Map;
-import java.util.Objects;
-
-import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.lihu.jh.module.system.enums.ErrorCodeConstants.*;
-
-/**
- * 绔欏唴淇″彂閫� Service 瀹炵幇绫�
- *
- * @author xrcoder
- */
-@Service
-@Validated
-@Slf4j
-public class NotifySendServiceImpl implements NotifySendService {
-
-    @Resource
-    private NotifyTemplateService notifyTemplateService;
-
-    @Resource
-    private NotifyMessageService notifyMessageService;
-
-    @Override
-    public Long sendSingleNotifyToAdmin(Long userId, String templateCode, Map<String, Object> templateParams) {
-        return sendSingleNotify(userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
-    }
-
-    @Override
-    public Long sendSingleNotifyToMember(Long userId, String templateCode, Map<String, Object> templateParams) {
-        return sendSingleNotify(userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
-    }
-
-    @Override
-    public Long sendSingleNotify(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams) {
-        // 鏍¢獙妯$増
-        NotifyTemplateDO template = validateNotifyTemplate(templateCode);
-        if (Objects.equals(template.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
-            log.info("[sendSingleNotify][妯$増({})宸茬粡鍏抽棴锛屾棤娉曠粰鐢ㄦ埛({}/{})鍙戦�乚", templateCode, userId, userType);
-            return null;
-        }
-        // 鏍¢獙鍙傛暟
-        validateTemplateParams(template, templateParams);
-
-        // 鍙戦�佺珯鍐呬俊
-        String content = notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams);
-        return notifyMessageService.createNotifyMessage(userId, userType, template, content, templateParams);
-    }
-
-    @VisibleForTesting
-    public NotifyTemplateDO validateNotifyTemplate(String templateCode) {
-        // 鑾峰緱绔欏唴淇℃ā鏉裤�傝�冭檻鍒版晥鐜囷紝浠庣紦瀛樹腑鑾峰彇
-        NotifyTemplateDO template = notifyTemplateService.getNotifyTemplateByCodeFromCache(templateCode);
-        // 绔欏唴淇℃ā鏉夸笉瀛樺湪
-        if (template == null) {
-            throw exception(NOTICE_NOT_FOUND);
-        }
-        return template;
-    }
-
-    /**
-     * 鏍¢獙绔欏唴淇℃ā鐗堝弬鏁版槸鍚︾‘瀹�
-     *
-     * @param template 閭妯℃澘
-     * @param templateParams 鍙傛暟鍒楄〃
-     */
-    @VisibleForTesting
-    public void validateTemplateParams(NotifyTemplateDO template, Map<String, Object> templateParams) {
-        template.getParams().forEach(key -> {
-            Object value = templateParams.get(key);
-            if (value == null) {
-                throw exception(NOTIFY_SEND_TEMPLATE_PARAM_MISS, key);
-            }
-        });
-    }
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyTemplateService.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyTemplateService.java
deleted file mode 100644
index ac07d05..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyTemplateService.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package cn.lihu.jh.module.system.service.notify;
-
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyTemplateDO;
-
-import javax.validation.Valid;
-import java.util.Map;
-
-/**
- * 绔欏唴淇℃ā鐗� Service 鎺ュ彛
- *
- * @author xrcoder
- */
-public interface NotifyTemplateService {
-
-    /**
-     * 鍒涘缓绔欏唴淇℃ā鐗�
-     *
-     * @param createReqVO 鍒涘缓淇℃伅
-     * @return 缂栧彿
-     */
-    Long createNotifyTemplate(@Valid NotifyTemplateSaveReqVO createReqVO);
-
-    /**
-     * 鏇存柊绔欏唴淇℃ā鐗�
-     *
-     * @param updateReqVO 鏇存柊淇℃伅
-     */
-    void updateNotifyTemplate(@Valid NotifyTemplateSaveReqVO updateReqVO);
-
-    /**
-     * 鍒犻櫎绔欏唴淇℃ā鐗�
-     *
-     * @param id 缂栧彿
-     */
-    void deleteNotifyTemplate(Long id);
-
-    /**
-     * 鑾峰緱绔欏唴淇℃ā鐗�
-     *
-     * @param id 缂栧彿
-     * @return 绔欏唴淇℃ā鐗�
-     */
-    NotifyTemplateDO getNotifyTemplate(Long id);
-
-    /**
-     * 鑾峰緱绔欏唴淇℃ā鏉匡紝浠庣紦瀛樹腑
-     *
-     * @param code 妯℃澘缂栫爜
-     * @return 绔欏唴淇℃ā鏉�
-     */
-    NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code);
-
-    /**
-     * 鑾峰緱绔欏唴淇℃ā鐗堝垎椤�
-     *
-     * @param pageReqVO 鍒嗛〉鏌ヨ
-     * @return 绔欏唴淇℃ā鐗堝垎椤�
-     */
-    PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO);
-
-    /**
-     * 鏍煎紡鍖栫珯鍐呬俊鍐呭
-     *
-     * @param content 绔欏唴淇℃ā鏉跨殑鍐呭
-     * @param params 绔欏唴淇″唴瀹圭殑鍙傛暟
-     * @return 鏍煎紡鍖栧悗鐨勫唴瀹�
-     */
-    String formatNotifyTemplateContent(String content, Map<String, Object> params);
-
-}
diff --git a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyTemplateServiceImpl.java b/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyTemplateServiceImpl.java
deleted file mode 100644
index 70683b5..0000000
--- a/jh-module-system/jh-module-system-biz/src/main/java/cn/lihu/jh/module/system/service/notify/NotifyTemplateServiceImpl.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package cn.lihu.jh.module.system.service.notify;
-
-import cn.hutool.core.util.ReUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.common.util.object.BeanUtils;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
-import cn.lihu.jh.module.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO;
-import cn.lihu.jh.module.system.dal.dataobject.notify.NotifyTemplateDO;
-import cn.lihu.jh.module.system.dal.mysql.notify.NotifyTemplateMapper;
-import cn.lihu.jh.module.system.dal.redis.RedisKeyConstants;
-import com.google.common.annotations.VisibleForTesting;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import javax.annotation.Resource;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.lihu.jh.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_CODE_DUPLICATE;
-import static cn.lihu.jh.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS;
-
-/**
- * 绔欏唴淇℃ā鐗� Service 瀹炵幇绫�
- *
- * @author xrcoder
- */
-@Service
-@Validated
-@Slf4j
-public class NotifyTemplateServiceImpl implements NotifyTemplateService {
-
-    /**
-     * 姝e垯琛ㄨ揪寮忥紝鍖归厤 {} 涓殑鍙橀噺
-     */
-    private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}");
-
-    @Resource
-    private NotifyTemplateMapper notifyTemplateMapper;
-
-    @Override
-    public Long createNotifyTemplate(NotifyTemplateSaveReqVO createReqVO) {
-        // 鏍¢獙绔欏唴淇$紪鐮佹槸鍚﹂噸澶�
-        validateNotifyTemplateCodeDuplicate(null, createReqVO.getCode());
-
-        // 鎻掑叆
-        NotifyTemplateDO notifyTemplate = BeanUtils.toBean(createReqVO, NotifyTemplateDO.class);
-        notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent()));
-        notifyTemplateMapper.insert(notifyTemplate);
-        return notifyTemplate.getId();
-    }
-
-    @Override
-    @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE,
-            allEntries = true) // allEntries 娓呯┖鎵�鏈夌紦瀛橈紝鍥犱负鍙兘淇敼鍒� code 瀛楁锛屼笉濂芥竻鐞�
-    public void updateNotifyTemplate(NotifyTemplateSaveReqVO updateReqVO) {
-        // 鏍¢獙瀛樺湪
-        validateNotifyTemplateExists(updateReqVO.getId());
-        // 鏍¢獙绔欏唴淇$紪鐮佹槸鍚﹂噸澶�
-        validateNotifyTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode());
-
-        // 鏇存柊
-        NotifyTemplateDO updateObj = BeanUtils.toBean(updateReqVO, NotifyTemplateDO.class);
-        updateObj.setParams(parseTemplateContentParams(updateObj.getContent()));
-        notifyTemplateMapper.updateById(updateObj);
-    }
-
-    @VisibleForTesting
-    public List<String> parseTemplateContentParams(String content) {
-        return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
-    }
-
-    @Override
-    @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE,
-            allEntries = true) // allEntries 娓呯┖鎵�鏈夌紦瀛橈紝鍥犱负 id 涓嶆槸鐩存帴鐨勭紦瀛� code锛屼笉濂芥竻鐞�
-    public void deleteNotifyTemplate(Long id) {
-        // 鏍¢獙瀛樺湪
-        validateNotifyTemplateExists(id);
-        // 鍒犻櫎
-        notifyTemplateMapper.deleteById(id);
-    }
-
-    private void validateNotifyTemplateExists(Long id) {
-        if (notifyTemplateMapper.selectById(id) == null) {
-            throw exception(NOTIFY_TEMPLATE_NOT_EXISTS);
-        }
-    }
-
-    @Override
-    public NotifyTemplateDO getNotifyTemplate(Long id) {
-        return notifyTemplateMapper.selectById(id);
-    }
-
-    @Override
-    @Cacheable(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, key = "#code",
-            unless = "#result == null")
-    public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) {
-        return notifyTemplateMapper.selectByCode(code);
-    }
-
-    @Override
-    public PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) {
-        return notifyTemplateMapper.selectPage(pageReqVO);
-    }
-
-    @VisibleForTesting
-    void validateNotifyTemplateCodeDuplicate(Long id, String code) {
-        NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code);
-        if (template == null) {
-            return;
-        }
-        // 濡傛灉 id 涓虹┖锛岃鏄庝笉鐢ㄦ瘮杈冩槸鍚︿负鐩稿悓 id 鐨勫瓧鍏哥被鍨�
-        if (id == null) {
-            throw exception(NOTIFY_TEMPLATE_CODE_DUPLICATE, code);
-        }
-        if (!template.getId().equals(id)) {
-            throw exception(NOTIFY_TEMPLATE_CODE_DUPLICATE, code);
-        }
-    }
-
-    /**
-     * 鏍煎紡鍖栫珯鍐呬俊鍐呭
-     *
-     * @param content 绔欏唴淇℃ā鏉跨殑鍐呭
-     * @param params  绔欏唴淇″唴瀹圭殑鍙傛暟
-     * @return 鏍煎紡鍖栧悗鐨勫唴瀹�
-     */
-    @Override
-    public String formatNotifyTemplateContent(String content, Map<String, Object> params) {
-        return StrUtil.format(content, params);
-    }
-
-}
diff --git a/jh-server/pom.xml b/jh-server/pom.xml
index 7b2ab01..1cb4e5d 100644
--- a/jh-server/pom.xml
+++ b/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銆乴ogback-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>
 
+    <!--
+        鍓嶇浜х墿鐩綍鐨勯�夋嫨銆俥nv.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>
diff --git a/jh-server/src/main/resources/application-local.yaml b/jh-server/src/main/resources/application-local.yaml
index e2deb52..7fd5b9e 100644
--- a/jh-server/src/main/resources/application-local.yaml
+++ b/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 閰嶇疆銆俁edisson 榛樿鐨勯厤缃冻澶熶娇鐢紝涓�鑸笉闇�瑕佽繘琛岃皟浼�
   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 # 瀵嗙爜锛屽缓璁敓浜х幆澧冨紑鍚�
 
 --- #################### 瀹氭椂浠诲姟鐩稿叧閰嶇疆 ####################
 
diff --git a/jh-server/src/main/resources/application.yaml b/jh-server/src/main/resources/application.yaml
index e01dff2..d216a8a 100644
--- a/jh-server/src/main/resources/application.yaml
+++ b/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 # 鍏佽寰幆渚濊禆锛屽洜涓洪」鐩槸涓夊眰鏋舵瀯锛屾棤娉曢伩鍏嶈繖涓儏鍐点��
diff --git a/sql/mysql/jh.sql b/sql/mysql/jh.sql
index b45e033..390b8f7 100644
--- a/sql/mysql/jh.sql
+++ b/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 娣诲姞锛圚IS 鎺ュ叆琛ュ厖瀛楁锛�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='棰勭害琛�';

--
Gitblit v1.9.3