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

---
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java |  674 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 639 insertions(+), 35 deletions(-)

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 fe54ef3..6df4631 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
@@ -37,6 +37,7 @@
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -104,6 +105,79 @@
 
         // 杩斿洖
         return appointment.getId();
+    }
+
+    /** 骞跺彂鍐茬獊鍚庣殑閲嶈瘯娆℃暟涓庣瓑寰呴棿闅旓紙浠呯敤浜�"鎻掑叆鎾炲敮涓�绱㈠紩"杩欎竴绉嶆儏鍐碉級 */
+    private static final int APPLY_NO_CONFLICT_RETRY = 3;
+    private static final long APPLY_NO_CONFLICT_WAIT_MS = 150L;
+
+    /**
+     * 鎸� {@code apply_no} 鍘熷瓙钀藉簱锛氬凡瀛樺湪鍒欐洿鏂帮紝涓嶅瓨鍦ㄥ垯鎻掑叆锛涘苟鍙戦噸澶嶆彃鍏ユ椂涓嶄細鐣欓噸澶嶈銆�
+     *
+     * <h3>涓轰粈涔堥渶瑕佸畠</h3>
+     * 鍘熷疄鐜版槸銆寋@code getByApplyNo} 鏌ヤ竴涓� 鈫� 娌℃湁灏� insert銆嶏紝鏌ヤ笌鎻掍箣闂存病鏈夊師瀛愭�с��
+     * 瀹炴祴 2026-10-04 12:16锛欻IS 鍦� 423ms 鍐呮妸鍚屼竴寮犵敵璇峰崟鎺ㄤ簡涓ら亶锛屼袱涓嚎绋嬮兘璇诲埌 0 琛屻��
+     * 閮芥墽琛屼簡 insert锛屼簬鏄悓涓� {@code apply_no} 钀戒笅涓ゆ潯锛坕d 211740 / 211741锛夈��
+     * 琛ㄤ笂鍘熸湁鐨勫敮涓�绱㈠紩 {@code uniq-pat-book(pat_id, book_date, book_check_type)}
+     * 鍦� book_date / book_check_type 涓� NULL 鏃朵笉鐢熸晥锛屾嫤涓嶄綇銆�
+     *
+     * <h3>鐜板湪鐨勫仛娉�</h3>
+     * 鏁版嵁搴撲晶宸插姞鍞竴绱㈠紩 {@code uk_appointment_apply_no_active}锛堝彧绾︽潫鏈垹闄よ锛夈��
+     * 杩欓噷鏀规垚銆屽厛灏濊瘯鎻掑叆锛屾挒鍞竴閿氨鍥炶骞舵敼涓烘洿鏂般�嶏細
+     * <ul>
+     *   <li>涓茶鍦烘櫙锛氭彃鍏ユ垚鍔燂紝琛屼负涓庡師鏉ヤ竴鑷达紱</li>
+     *   <li>骞跺彂鍦烘櫙锛氬叾涓竴涓彃鍏ュ繀鐒跺け璐ワ紙DuplicateKeyException锛夛紝澶辫触鏂硅蛋鏇存柊锛屼笉鍐嶄骇鐢熼噸澶嶈锛�</li>
+     *   <li>瀵规柟浜嬪姟灏氭湭鎻愪氦瀵艰嚧鍥炶涓嶅埌鏃讹紝鐭殏绛夊緟鍚庨噸璇曪紙鏈�澶� {@value #APPLY_NO_CONFLICT_RETRY} 娆★級銆�</li>
+     * </ul>
+     *
+     * @return 钀藉簱璁板綍鐨� id
+     */
+    private Long atomicSaveByApplyNo(AppointmentSaveReqVO saveReqVO) {
+        String applyNo = saveReqVO.getApplyNo();
+        // 鈶� 鍏堟寜鐢宠鍗曞彿璧�"鏇存柊"鍒嗘敮锛堜笌鏀归�犲墠鐨勮涔変竴鑷达細鍛戒腑宸插瓨鍦ㄥ垯浠ユ湰娆℃姤鏂囧唴瀹规洿鏂帮級
+        AppointmentDO exists = (applyNo == null) ? null : appointmentMapper.getByApplyNo(applyNo);
+        if (exists != null) {
+            saveReqVO.setId(exists.getId());
+            updateAppointment(saveReqVO);
+            return exists.getId();
+        }
+
+        // 鈶� 涓嶅瓨鍦� 鈫� 灏濊瘯鎻掑叆锛涙挒鍞竴绱㈠紩璇存槑鏈夊苟鍙戞彃鍏ワ紝杞洿鏂伴噸璇�
+        for (int attempt = 0; attempt <= APPLY_NO_CONFLICT_RETRY; attempt++) {
+            try {
+                AppointmentDO toInsert = BeanUtils.toBean(saveReqVO, AppointmentDO.class);
+                toInsert.setId(null);
+                appointmentMapper.insert(toInsert);
+                return toInsert.getId();
+            } catch (DuplicateKeyException e) {
+                AppointmentDO concurrent = (applyNo == null) ? null : appointmentMapper.getByApplyNo(applyNo);
+                if (concurrent != null) {
+                    log.warn("[atomicSaveByApplyNo][骞跺彂閲嶅鎻掑叆宸叉嫤鎴紝鏀逛负鏇存柊宸叉湁璁板綍] applyNo={} existingId={}",
+                            applyNo, concurrent.getId());
+                    saveReqVO.setId(concurrent.getId());
+                    updateAppointment(saveReqVO);
+                    return concurrent.getId();
+                }
+                // 瀵规柟鍙兘杩樻病鎻愪氦锛氱瓑涓�涓嬪啀璇曪紙鏈�鍚庝粛鎷夸笉鍒板氨涓婃姏锛岀敱澶栧眰璁板綍閿欒鏃ュ織锛�
+                if (attempt < APPLY_NO_CONFLICT_RETRY) {
+                    try {
+                        Thread.sleep(APPLY_NO_CONFLICT_WAIT_MS);
+                    } catch (InterruptedException ie) {
+                        Thread.currentThread().interrupt();
+                        throw e;
+                    }
+                    AppointmentDO retry = appointmentMapper.getByApplyNo(applyNo);
+                    if (retry != null) {
+                        saveReqVO.setId(retry.getId());
+                        updateAppointment(saveReqVO);
+                        return retry.getId();
+                    }
+                } else {
+                    throw e;
+                }
+            }
+        }
+        throw exception(APPOINTMENT_CREATE_FAIL);
     }
 
     @Override
@@ -183,6 +257,12 @@
     @Override
     public List<AppointmentDO> queryAndCreateAppointmentByPatId(String patCode) {
         // 浠庡尰闄㈠钩鍙版煡璇�
+        //
+        // 銆愭湰闇�姹傘�戝尮閰嶅彛寰勪粠銆岀敵璇峰崟鍙� / 灏辫瘖娴佹按鍙� / 浣忛櫌鍙� / 韬唤璇佸彿銆嶆墿灞曚负**鍐嶅姞涓� pat_id**
+        // 锛堣 AppointmentMapper.getCurrentCode 鐨� SQL锛夈�傚師鍥狅細
+        //   鎵嬪姩鏂板缓鐨勯绾︼紙/ecg/appointment/create锛夊彧鏈� pat_id锛�
+        //   apply_no / episode_id / hospital_no / pat_identity_id 鍏ㄤ负绌猴紝
+        //   绛惧埌椤垫寜鎮h�呯紪鍙锋煡璇㈡椂**姘歌繙鏌ヤ笉鍒�** 鈫� 椤甸潰鎻愮ず銆岃鍏堥绾︺�嶁啋 鏃犳硶绛惧埌銆�
         List<AppointmentDO> appointmentExtermalList = appointmentMapper.getCurrentCode(patCode);
 
         for (int appointmentIndex = 0; appointmentIndex < appointmentExtermalList.size(); appointmentIndex++) {
@@ -190,26 +270,47 @@
             if (null == appointmentExtermal) continue;
 
             // 浠嶥B鏌ヨ棰勭害锛屾槸鍚﹀凡缁忓瓨鍦�
-            AppointmentDO appointmentDO = appointmentMapper.getByEpisodeIdAndApplyNo(appointmentExtermal.getEpisodeId(), appointmentExtermal.getApplyNo());
+            //
+            // 銆愭湰闇�姹傘�戜紭鍏堟寜**涓婚敭 id** 鍒ゆ柇銆屾槸鍚﹀凡瀛樺湪銆嶏細
+            //   getCurrentCode 鏄湰鍦板簱鏌ヨ锛坰elect * 浼氭妸 id 甯﹀洖鏉ワ級锛�
+            //   鑰屽師閫昏緫鐢� getByEpisodeIdAndApplyNo(episodeId, applyNo) 鍒ゆ柇锛�
+            //   鎵嬪姩鏂板缓鐨勮杩欎袱涓瓧娈垫槸 NULL/绌� 鈬� `= NULL` 姘歌繙涓嶅尮閰� 鈬� 姣忔墦寮�涓�娆$鍒伴〉灏�**閲嶅鎻掑叆**涓�鏉°��
+            AppointmentDO appointmentDO = null;
+            if (null != appointmentExtermal.getId()) {
+                appointmentDO = appointmentMapper.selectById(appointmentExtermal.getId());
+            }
+            if (null == appointmentDO) {
+                appointmentDO = appointmentMapper.getByEpisodeIdAndApplyNo(
+                        appointmentExtermal.getEpisodeId(), appointmentExtermal.getApplyNo());
+            }
             if (null == appointmentDO) {
                 appointmentMapper.insert(appointmentExtermal);
             } else {
                 appointmentExtermal.setId(appointmentDO.getId()); // 纭繚 杩斿洖鍊煎寘鍚� appointment id
 
                 // 澶勭悊绗竴娆$‘璁ゆ椂杩樻病鏈夐绾︽椂闂达紝鍐嶆潵纭鏃跺凡鏈夐绾︽椂闂寸殑鎯呭喌
-                if (appointmentDO.getBookDate() != appointmentExtermal.getBookDate()) {
+                // 銆愭湰娆′慨澶嶃�戝師鍐欐硶 `appointmentDO.getBookDate() != appointmentExtermal.getBookDate()`
+                // 鏄�**寮曠敤姣旇緝**锛圠ocalDate 涓や釜涓嶅悓瀹炰緥鍗充娇鍊肩浉鍚屼篃浼氬垽涓轰笉绛夛級锛�
+                // 浼氬鑷存瘡娆¢兘鐧借窇涓�娆� updateById锛堟棤璋撴敼鍐� update_time锛夈�傛敼涓哄�兼瘮杈冦��
+                if (!java.util.Objects.equals(appointmentDO.getBookDate(), appointmentExtermal.getBookDate())) {
                     appointmentMapper.updateById(appointmentExtermal);
                 }
             }
         }
 
-        // 鏌ヨ[queue琛╙琛ュ厖 book_seq_num 鍒拌繑鍥炲�间腑
+        // 鏌ヨ[queue琛╙琛ュ厖銆屾帓闃熷彿銆嶅埌杩斿洖鍊间腑
+        //
+        // 銆愬彿缁熶竴锛堟湰闇�姹傦級銆戞帓闃熷彿鏀逛负鍦ㄧ鍒版椂涓�娆℃�у啓杩� queue.seq_num锛屼笉鍐嶅啓 book_seq_num銆�
+        // 鍥犳杩欓噷鍙� seq_num锛涘澶栧瓧娈靛悕浠嶅彨 bookSeqNum锛堥渶姹傝姹傛帴鍙e瓧娈典繚鐣欎笉鍔級銆�
+        // 杩囨护 null锛氬瓨閲忚锛堟敼閫犲墠绛惧埌鐨勶級seq_num 鍙兘涓虹┖锛岃�� toMap 鐨� value 涓� null 浼氭姏 NPE銆�
         if (!appointmentExtermalList.isEmpty()) {
             List<Long> appointIdlist = appointmentExtermalList.stream().map(appointmentDO -> appointmentDO.getId()).toList();
-            List<QueueDO> simpleQueueDOList = queueService.selectBookSeqNumByAppointIdList(appointIdlist);
+            List<QueueDO> simpleQueueDOList = queueService.selectQueueByAppointIdList(appointIdlist);
             if (!simpleQueueDOList.isEmpty()) {
-                Map<Long, Integer> mapAppointIdVsBookSeqNo = simpleQueueDOList.stream().collect(Collectors.toMap(QueueDO::getAppointId, QueueDO::getBookSeqNum));
-                appointmentExtermalList.forEach(appointmentExterma -> appointmentExterma.setBookSeqNum(mapAppointIdVsBookSeqNo.get(appointmentExterma.getId())));
+                Map<Long, Integer> mapAppointIdVsSeqNo = simpleQueueDOList.stream()
+                        .filter(queueDO -> null != queueDO.getAppointId() && null != queueDO.getSeqNum())
+                        .collect(Collectors.toMap(QueueDO::getAppointId, QueueDO::getSeqNum, (a, b) -> a));
+                appointmentExtermalList.forEach(appointmentExterma -> appointmentExterma.setBookSeqNum(mapAppointIdVsSeqNo.get(appointmentExterma.getId())));
             }
         }
 
@@ -315,27 +416,52 @@
         AppointmentDO appointment = getAppointment(confirmReqVO.getId());
         if (null == appointment) throw exception(PATIENT_NOT_EXISTS);
 
-        // 鎵嬪姩棰勭害锛岀洿鎺ヨ缃绾︽棩鏈熶负褰撳ぉ
-        if (confirmReqVO.getIsVip() == 1) {
+        boolean isVipFlag = (null != confirmReqVO.getIsVip() && 1 == confirmReqVO.getIsVip());
+        boolean forceCheckIn = Boolean.TRUE.equals(confirmReqVO.getForceCheckIn());
+        // 娉ㄦ剰锛氳繖閲岀殑"鏄惁褰撳ぉ"蹇呴』鍦ㄦ敼鍐� bookDate 涔嬪墠鍒ゆ柇锛堜笅闈細鎶婇潪褰撳ぉ鏀逛负褰撳ぉ锛�
+        boolean bookDateIsToday = DateUtils.isToday(appointment.getBookDate());
+
+        // 鎵嬪姩棰勭害 / VIP 鍔犲彿锛氶绾︽棩鏈熺洿鎺ユ寜褰撳ぉ绛惧埌
+        if (isVipFlag) {
             appointment.setBookDate(LocalDate.now());
+            bookDateIsToday = true;
         }
 
-        if (!DateUtils.isToday(appointment.getBookDate())) throw exception(APPOINTMENT_NOT_TODAY);
-
+        // 銆愭湰闇�姹傘�戦潪褰撳ぉ棰勭害鐨勭鍒帮細鍏堟彁閱掋�佺‘璁ゅ悗鍏佽绛惧叆锛堝墠绔脊绐楃‘璁ゅ悗甯� forceCheckIn=true锛�
+        //   鈶� 鏈‘璁わ紙鍓嶇杩樻病璁╃敤鎴风‘璁わ級鈫� 浠嶈繑鍥� APPOINTMENT_NOT_TODAY锛屽墠绔嵁姝ゅ脊銆岄潪褰撳ぉ锛屾槸鍚︾鍒般�嶏紱
+        //   鈶� 宸茬‘璁� 鈫� 鍏佽绛惧叆锛屽苟涓�**寮哄埗璧伴鐣欏彿閫氶亾**锛岄伩鍏嶅崰鐢ㄥ綋澶╁悓鏃舵鐨勬甯搁绾﹀彿锛�
+        //   鈶� 棰勭害鏃ユ湡鏀瑰啓涓哄綋澶╋細闃熷垪/澶у睆/宸ヤ綔鍙伴兘鎸� book_date = 浠婂ぉ 杩囨护锛�
+        //      鑻ヤ繚鐣欏師鏃ユ湡锛屾偅鑰呯鍏ュ悗涓嶄細鍑虹幇鍦ㄤ换浣曞垪琛ㄩ噷銆�
+        if (!bookDateIsToday) {
+            if (!forceCheckIn) {
+                throw exception(APPOINTMENT_NOT_TODAY);
+            }
+            log.info("[appoitmentConfirm] 闈炲綋澶╅绾︾鍏ワ紙鏀圭敤棰勭暀鍙凤紝棰勭害鏃ユ湡鏀逛粖澶╋級. appointmentId={} 鍘熼绾︽棩鏈�={} checkType={} timeslot={}",
+                    appointment.getId(), appointment.getBookDate(), confirmReqVO.getBookCheckType(),
+                    confirmReqVO.getBookTimeslot());
+            appointment.setBookDate(LocalDate.now());
+        }
 
         // 銆愰渶姹傦細鎺掗槦搴忓彿瑙勫垯銆戞寜 check_type.seq_rule 鍐冲畾鍙栧彿鏂瑰紡锛�
         //   0=棰勭害鍙凤紙鐢ㄩ绾︾郴缁熷凡涓嬪彂鐨勫彿锛涘綋鍓� HIS 鏈笅鍙戯紝浼氳嚜鍔ㄥ洖閫�鍒扮鍒板簭鍙凤級
         //   1=绛惧埌搴忓彿锛堝綋澶╁悓妫�鏌ョ被鍨嬭繛缁�掑锛屾瘡 9 涓鐣� 1 涓粰鍔犳�ワ級
         //   2=鏃舵鍙凤紙鎸� bookTimeslot 浠庡彿姹犲彇鍙� 鈥斺�� 鏀归�犲墠鐨勫師鏈夎涓猴紝涔熸槸鏈厤缃椂鐨勯粯璁わ級
+        //
+        // 銆愭湰闇�姹傦細鎸夋椂娈甸绾︺�戝鍔� VIP/鍔犲彿鏍囪锛�
+        //   路 VIP/鍔犲彿/闈炲綋澶╃鍏� 鈫� 鏈棰勭暀鍙� 鈫� 鎬婚鐣欐睜锛坱ime_slot=0锛�
+        //   路 鏅��               鈫� 鏈鏅�氬彿 鈫� 鏈棰勭暀鍙� 鈫� 鎬婚鐣欐睜
+        //   娌℃湁棰勭害鏃舵锛坆ookTimeslot 涓虹┖/0/瀛楀吀澶栵級鏃朵篃鑳界鍒帮細鐩存帴钀藉埌鎬婚鐣欐睜銆�
         boolean urgent = isHisUrgent(appointment);
+        boolean vip = isVipFlag || urgent || !bookDateIsToday;
         Integer newSeqNo = queueSequenceService.distributeSeqNoByRule(
                 confirmReqVO.getBookCheckType(),
                 confirmReqVO.getBookTimeslot(),
                 appointment.getBookSeqNum(),
-                urgent);
-        log.info("[appoitmentConfirm][鍒嗛厤鎺掗槦搴忓彿] appointmentId={} checkType={} timeslot={} 瑙勫垯鍙栧彿={} 鍔犳��={}",
+                urgent,
+                vip);
+        log.info("[appoitmentConfirm][鍒嗛厤鎺掗槦搴忓彿] appointmentId={} checkType={} timeslot={} 瑙勫垯鍙栧彿={} 鍔犳��={} VIP/鍔犲彿={}",
                 appointment.getId(), confirmReqVO.getBookCheckType(), confirmReqVO.getBookTimeslot(),
-                newSeqNo, urgent);
+                newSeqNo, urgent, vip);
 
         try {
             QueueSaveReqVO queueSaveReqVO = new QueueSaveReqVO();
@@ -348,14 +474,19 @@
             queueSaveReqVO.setBookDate(appointment.getBookDate());
             queueSaveReqVO.setBookTimeslot(confirmReqVO.getBookTimeslot()); /*appointment.getBookTimeslot()*/
             queueSaveReqVO.setBookCheckType(appointment.getBookCheckType());
-            queueSaveReqVO.setBookSeqNum(newSeqNo);
+            // 銆愬彿缁熶竴锛堟湰闇�姹傦級銆戠鍒版椂鍙栫殑鍙�**鐩存帴鍐欏叆 seq_num**锛堜笉鍐嶅啓 book_seq_num锛夈��
+            // 涔嬪悗浠讳綍鐜妭閮戒笉鍐嶆敼杩欎釜鍙凤細鍒嗘祦銆佽繃鍙枫�佸彫鍥炪�佸姞鎬ャ�佽鏈哄潎鍙敼鐘舵��/宸ヤ綅銆�
+            // 鍙栧彿瑙勫垯浠嶇敱 check_type.seq_rule 鍐冲畾锛堥绾﹀彿 / 绛惧埌搴忓彿 / 鏃舵鍙凤級锛岃 distributeSeqNoByRule銆�
+            queueSaveReqVO.setSeqNum(newSeqNo);
             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 鍗充紭鍏堛��
+            // 銆愬彿缁熶竴鍚庛�戝姞鎬�**涓嶆敼鎺掗槦鍙�**锛堝彿鍦ㄤ笅闈� setSeqNum 鏃跺凡缁忓畾姝伙級锛�
+            // 鑰屾槸闈犳帓搴忎綋鐜帮細鍒嗘祦鍙栦汉銆佸彨鍙峰彇浜恒�佸伐浣滃彴/璇婇棿灞�/澶у睆鍒楄〃閮芥槸
+            // "jump_flag desc 浼樺厛 鈫� seq_num 鍗囧簭"锛岀疆 1 鍗虫帓鍒版渶鍓嶃��
             if (urgent) {
                 queueSaveReqVO.setJumpFlag((byte) 1);
                 log.info("[appoitmentConfirm][HIS 鍔犳�ユ偅鑰咃紝鎺掗槦鏍囪涓哄姞鎬 applyNo={} patId={}",
@@ -471,6 +602,40 @@
                     appointment.setTargetSiteCode(targetSite);
                 }
 
+                // 棰勭害鏃堕棿/鏃堕棿娈�/璇婂锛圫0201ECG 鎶ユ枃鐨� component2.observationRequest.ZDY锛屽疄娴嬪舰濡傦細
+                //   ZDY={time=2026-10-06 08:00-08:30, area=..., roomname=6鍙疯瘖瀹�(鍘呭彸渚�), roomcode=, jcxmcode=201652, jcxmname=骞虫澘杩愬姩璇曢獙}
+                // 鍘熷疄鐜板彧鎶婂畠褰�"妫�鏌ョ被鍨�"鐢紝娌¤В鏋愰绾︿俊鎭紝瀵艰嚧杩欐潯娴佸缓鍑烘潵鐨勮褰�
+                // book_date / book_timeslot / book_time / room_name 鍏ㄤ负绌猴紙瀹炴祴 211741銆�211962 灏辨槸杩欑鍗婃潯鏁版嵁锛夈��
+                Object zdyRaw = c2.get("ZDY");
+                if (zdyRaw == null) {
+                    zdyRaw = c2.get("zdy");
+                }
+                if (zdyRaw instanceof Map) {
+                    Map<String, Object> zdyMap = (Map<String, Object>) zdyRaw;
+                    Object timeObj = zdyMap.get("time");
+                    String timeRange = timeObj == null ? null : timeObj.toString();
+                    Integer timeslot = parseBookTimeslot(timeRange);
+                    if (timeslot != null) {
+                        appointment.setBookTimeslot(timeslot);
+                        // 鐢辨椂闂存璧峰鎺ㄧ畻棰勭害鏃跺埢锛堝 8000830 鈫� 08:00锛夛紱book_date 瑙佷笅鏂� 鈶� 鐨勭粺涓�鎺ㄥ
+                        LocalTime startTime = timeOfTimeslot(timeslot);
+                        if (startTime != null) {
+                            appointment.setBookTime(LocalDateTime.of(LocalDate.now(), startTime));
+                        }
+                    } else {
+                        // 鏃堕棿娈佃В鏋愪笉鍑烘潵鏃讹紝閫�鍥炵敤 effectiveTime锛堟姤鏂囬噷鍙︿竴涓绾︽椂鍒诲瓧娈碉級
+                        LocalDateTime bookTime = parseDateTime(digText(c2, "effectiveTime", "any", "value"));
+                        if (bookTime != null) {
+                            appointment.setBookTime(bookTime);
+                            appointment.setBookDate(bookTime.toLocalDate());
+                        }
+                    }
+                    Object roomName = zdyMap.get("roomname");
+                    if (roomName != null && StringUtils.isNotEmpty(roomName.toString())) {
+                        appointment.setRoomName(truncate(roomName.toString(), ROOM_NAME_MAX_LEN));
+                    }
+                }
+
                 // 鍖诲槺鍙凤細component2.observationRequest.id.item[root=2.16.156.10011.1.28].extension
                 //
                 // 渚濇嵁锛圚IS銆婁氦浜掓湇鍔¢�氱敤鎺ュ彛鏂囨。銆嬶級锛�
@@ -491,15 +656,29 @@
                 }
             }
 
-            // 鍖荤敓寮�鍗曟椂闂�
-            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 -> {
-                try {
-                    return new SimpleDateFormat("yyyyMMddHHmmss").parse(str);
-                } catch (Exception e) {
-                    e.printStackTrace();
-                    return null;
+            // 鍖荤敓寮�鍗曟椂闂达紙鎶ユ枃璺緞锛歝ontrolActProcess.subject.observationRequest.author.time.value锛�
+            //
+            // 銆愪负浠�涔堜笉鐢ㄤ竴琛� Optional 閾剧洿鎺� parse銆�
+            // 鍘熷疄鐜板啓姝� `SimpleDateFormat("yyyyMMddHHmmss")`锛屾牸寮忎笉绗﹀彧浼� **闈欓粯涓㈠純**
+            // 锛坈atch 閲屼粎 printStackTrace锛屼笉钀芥棩蹇楀瓧娈碉級鈥斺�旂嚎涓婂嚭鐜伴棶棰樻椂鏃犱粠瀹氫綅銆�
+            // 鐜版敼涓烘樉寮忓垎鏀� + 缁撴瀯鍖� WARN 鏃ュ織锛岃嚦灏戞妸銆屾姤鏂囧師鍊� / 鐢宠鍗曞彿銆嶈涓嬫潵銆�
+            String doctorTimeRaw = digText(dataMap, "controlActProcess", "subject",
+                    "observationRequest", "author", "time", "value");
+            // 璇ュ灏氭湭鎵ц鍒颁笅鏂圭殑 setApplyNo锛堝師 L575锛夛紝鏁呭崟鐙彇涓�娆$敵璇峰崟鍙凤紝浠呯敤浜庢棩蹇楀畾浣�
+            String applyNoForLog = digText(dataMap, "controlActProcess", "subject",
+                    "observationRequest", "id", "item", "extension");
+            if (StringUtils.isNotEmpty(doctorTimeRaw)) {
+                // 鍘熸牱閲囩撼 HIS 鎵�鍙戠殑鍊硷紙涓嶅仛鍙栬垗锛岄伩鍏嶈鍒ゅ弽鑰屽啓鍧忔暟鎹級銆�
+                // 鑻ヤ负銆屾棩鏈熷�笺�嶏紙鏃跺垎绉�=000000锛屽疄娴嬬害 61%锛夛紝parseHisDoctorTime 浼氭墦 WARN
+                // 璁板綍鍘熷鎶ユ枃鍊� + 鐢宠鍗曞彿锛屼究浜庡悜 HIS 渚у弽棣堬紱鍐欏叆琛屼负涓庢敼鍔ㄥ墠涓�鑷淬��
+                java.util.Date parsedDoctorTime = parseHisDoctorTime(doctorTimeRaw, applyNoForLog);
+                if (parsedDoctorTime != null) {
+                    appointment.setDoctorTime(parsedDoctorTime);
                 }
-            }).filter(Objects::nonNull).ifPresent(appointment::setDoctorTime);
+            } else {
+                log.warn("[handleAppointmentCreate][鎶ユ枃缂哄皯寮�鍗曟椂闂� author/time/value锛宒octor_time 灏嗕负绌篯 applyNo={}",
+                        applyNoForLog);
+            }
 
             //璁剧疆寮�鍗曞尰鐢熷鍚�
             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("assignedEntity")).map(assignedEntity -> (Map<String, Object>) assignedEntity.get("assignedPerson")).map(assignedPerson -> (Map<String, Object>) assignedPerson.get("name")).map(name -> (Map<String, Object>) name.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(appointment::setDoctor);
@@ -563,6 +742,33 @@
             // 璁剧疆鐢宠鍗曞彿
             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("id")).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).ifPresent(appointment::setApplyNo);
 
+            // 棰勭害鏃ユ湡锛氭姤鏂囬噷鐨勯绾︽椂闂存 ZDY.time 褰㈠ "2026-10-06 08:00-08:30"銆�
+            // 涓婇潰瑙f瀽鏃堕棿娈垫椂鍙嬁鍒颁簡鏃跺垎锛堢敤浜� book_timeslot/book_time锛夛紝杩欓噷琛ユ棩鏈燂細
+            // 鑻ュ彧鎷垮埌鏃堕棿娈佃�屾棩鏈熶负绌猴紝灏变粠 ZDY.time 鐨勬棩鏈熼儴鍒嗚ˉ涓婏紝骞舵嵁姝や慨姝� book_time 鐨勬棩鏈熴��
+            String zdyTimeRange = digText(dataMap, "controlActProcess", "subject", "observationRequest",
+                    "component2", "observationRequest", "ZDY", "time");
+            if (StringUtils.isEmpty(zdyTimeRange)) {
+                zdyTimeRange = digText(dataMap, "controlActProcess", "subject", "observationRequest",
+                        "component2", "observationRequest", "zdy", "time");
+            }
+            if (StringUtils.isNotEmpty(zdyTimeRange)) {
+                String[] parts = zdyTimeRange.trim().split("\\s+");
+                if (parts.length >= 1) {
+                    LocalDateTime parsedDate = parseDateTime(parts[0] + " 00:00");
+                    if (parsedDate != null) {
+                        LocalDate zdyBookDate = parsedDate.toLocalDate();
+                        if (appointment.getBookDate() == null) {
+                            appointment.setBookDate(zdyBookDate);
+                        }
+                        // book_time 涔嬪墠鍙槸鐢�"浠婂ぉ"鍗犱綅锛岃繖閲屾崲鎴愮湡瀹為绾︽棩鏈�
+                        if (appointment.getBookTime() != null) {
+                            appointment.setBookTime(appointment.getBookTime().withYear(zdyBookDate.getYear())
+                                    .withMonth(zdyBookDate.getMonthValue()).withDayOfMonth(zdyBookDate.getDayOfMonth()));
+                        }
+                    }
+                }
+            }
+
             //璁剧疆妫�鏌ョ被鍨�
 //            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));
@@ -582,7 +788,17 @@
                 if (value != null) {
                     appointment.setBookCheckType(value);
                 } else {
-                    log.warn("[handleAppointmentCreate][浣撴鎮h�呮鏌ラ」鐩悕绉版棤娉曟槧灏刔 checkName={}", checkName);
+                    // 鍚嶇О鏄犲皠涓嶅埌灏遍��鍥炪�屾寜 HIS 妫�鏌ヤ唬鐮佹槧灏勩�嶏細
+                    // 瀹炴祴杩愬姩璇曢獙鍦� HIS 渚ф敼杩囧悕锛堝钩鏉胯繍鍔ㄥ績鐢� 鈫� 骞虫澘杩愬姩璇曢獙锛夛紝
+                    // 鍙鍚嶇О浼氳 book_check_type 钀界┖锛涜�屾姤鏂囬噷鐨� code锛堝 201652锛夋槸绋冲畾鐨勩��
+                    Integer fallback = resolveBookCheckTypeFromComponent2(dataMap);
+                    if (fallback != null) {
+                        appointment.setBookCheckType(fallback);
+                        log.info("[handleAppointmentCreate][浣撴鎮h�呭悕绉版湭鏄犲皠锛屽凡鎸夋鏌ヤ唬鐮佸厹搴昡 checkName={} bookCheckType={}",
+                                checkName, fallback);
+                    } else {
+                        log.warn("[handleAppointmentCreate][浣撴鎮h�呮鏌ラ」鐩悕绉颁笌浠g爜鍧囨棤娉曟槧灏刔 checkName={}", checkName);
+                    }
                 }
             } else {
                 Integer value = resolveBookCheckTypeFromComponent2(dataMap);
@@ -627,13 +843,12 @@
             if (appointmentDO != null) {
                 // 淇濈暀鍘熻褰曚腑鏈鎶ユ枃鏈彁渚涚殑瀛楁锛岄伩鍏嶈绌哄�艰鐩�
                 mergeUnsetFields(appointment, appointmentDO);
+                // 鍚堝苟缁撴灉瑕佸洖鍒� saveReqVO 涓婏紝鍚﹀垯鏇存柊/鎻掑叆鐢ㄧ殑杩樻槸"鏈悎骞�"鐨勬姤鏂囧��
                 saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class);
-                saveReqVO.setId(appointmentDO.getId());
-                updateAppointment(saveReqVO);
-                return appointmentDO.getId();
             }
-
-            return createAppointment(saveReqVO);
+            // 浜ょ粰鍘熷瓙钀藉簱锛氫笉瀛樺湪鍒欐彃鍏ワ紝宸插瓨鍦ㄥ垯鏇存柊锛涘苟鍙戦噸澶嶆彃鍏ヤ細琚敮涓�绱㈠紩鎷︿笅骞惰浆涓烘洿鏂帮紝
+            // 涓嶄細鍐嶅嚭鐜�"鍚屼竴 apply_no 涓ゆ潯璁板綍"锛堝師瀹炵幇鍦ㄨ繖閲�"鏌ヤ竴娆″啀鎻�"锛屽苟鍙戜笅蹇呯劧婕忥級銆�
+            return atomicSaveByApplyNo(saveReqVO);
         } catch (Exception e) {
             log.error("[handleAppointmentCreate][澶勭悊棰勭害鍒涘缓澶辫触 dataMap({})]", dataMap, e);
             throw exception(APPOINTMENT_CREATE_FAIL);
@@ -904,12 +1119,18 @@
         // 3. 鏈湴璁板綍鍖归厤
         AppointmentDO existingAppointment = appointmentMapper.getByApplyNo(applyNo);
         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);
+            // 鐘舵�佹祦鍙厑璁告敼 status / register_date锛�
+            // 鍘熷疄鐜版妸鏌ュ嚭鏉ョ殑鏁磋瀵硅薄鍐� updateById 鍐欏洖锛堣-鏀�-鍐欙級锛屼細鎶� book_date / book_check_type
+            // 绛夊瓧娈垫寜鏃у揩鐓ц鐩栥�傚疄娴� 2026-10-05 07:58锛屼竴绗旈绾﹀垰琚� S050401 鍐欏ソ棰勭害鏃堕棿涓庢鏌ョ被鍨嬶紝
+            // 3.6 绉掑悗 S0405 鐘舵�佹祦鍙堟妸鏁磋鍐欏洖涓�娆★紝check_type 琚啓鎴愪簡绌恒��
+            // 杩欓噷鏀规垚鍙洿鏂扮姸鎬侊紙register_date 浠呭湪鐘舵��=鐧昏鏃跺啓鍏ワ紝鐢� updateStatusByApplyNo 澶勭悊锛夈��
+            Date registerDate = HisCheckStatusEnum.REGISTERED.getCode().toString().equals(status)
+                    ? new Date() : null;
+            Integer updated = registerDate != null
+                    ? appointmentMapper.updateStatusByApplyNo(applyNo, status, registerDate)
+                    : appointmentMapper.updateStatusOnlyByApplyNo(applyNo, status);
+            log.info("[handleAppointmentStateUpdate][浠呮洿鏂扮姸鎬乚 applyNo={} status={} 褰卞搷琛屾暟={}",
+                    applyNo, status, updated);
             return;
         }
 
@@ -1062,6 +1283,121 @@
         return o == null ? null : o.toString();
     }
 
+    /**
+     * 浠� S050401/S050501锛堟鏌ラ绾︼級鎶ユ枃鐨� {@code ZDY} 鑺傜偣瑙f瀽鏈湴 {@code book_check_type}銆�
+     *
+     * <h3>涓轰粈涔堥渶瑕佽繖涓柟娉�</h3>
+     * {@code S050401/S050501} 鎶ユ枃鐨勬鏌ラ」鐩斁鍦� {@code ZDY.jcxmcode / ZDY.jcxmname}
+     * 锛堝舰濡� {@code jcxmcode=201652, jcxmname=骞虫澘杩愬姩璇曢獙}锛夛紝
+     * 涓� {@code S0201ECG} 鐨� {@code component2.observationRequest.code.code} **涓嶆槸鍚屼竴璺緞**銆�
+     * 鍘熷厛鍙湁 S0201ECG 閭f潯璺緞瑙f瀽妫�鏌ョ被鍨嬶紝浜庢槸銆孲050401 鍏堝埌銆丼0201ECG 鏈埌銆嶆椂璧�
+     * {@link #insertAppointmentFromCheckAppointment} 瀹归敊鏂板锛�
+     * {@code book_check_type} 浼�**姘歌繙涓虹┖** 鈥斺�� 瀹炴祴 2026-09-29~10-09 鍏� 279 鏉�
+     * 锛堝 {@code apply_no=8826092420371106}锛屾姤鏂囬噷 {@code jcxmcode=201652} 鏄庢槑瀛樺湪锛夈��
+     *
+     * <h3>瑙f瀽椤哄簭</h3>
+     * <ol>
+     *   <li><b>鍚嶇О浼樺厛</b>锛歿@code jcxmname} 鈫� {@link HisCheckNameEnum#getByName}銆�
+     *       璇ユ灇涓惧凡鍚�屽钩鏉胯繍鍔ㄨ瘯楠屻�嶇瓑 HIS 鏀瑰悕鍒悕锛屼笖鍐呯疆瑙勮寖鍖栧尮閰嶏紱</li>
+     *   <li><b>浠g爜鍏滃簳</b>锛歿@code jcxmcode} 鈫� {@link HisCheckCodeEnum}锛�
+     *       鍏煎甯�/涓嶅甫 {@code Y} 鍓嶇紑銆�</li>
+     * </ol>
+     *
+     * <h3>澶氬�煎鐞�</h3>
+     * 瀹炴祴璇ュ瓧娈靛彲鑳戒负閫楀彿鍒嗛殧澶氬�硷紙濡� S0405 鐨� {@code jcxmcode=1080,3016,3014}锛夈��
+     * 绛栫暐锛�**鎸夐『搴忓彇绗竴涓兘鏄犲皠鎴愬姛鐨勫��**锛涘厛鏁翠綋璇曟帰锛堝崟鍊煎満鏅級锛屽啀閫愭璇曟帰銆�
+     *
+     * @param zdy 鎶ユ枃涓殑 {@code ZDY} 鑺傜偣锛屽彲涓� null
+     * @return 鏈湴妫�鏌ョ被鍨嬪�硷紙濡� 400锛夛紱鏃犳硶瑙f瀽鏃惰繑鍥� null锛堣皟鐢ㄦ柟淇濇寔鍘熷�间笉鍐欙級
+     */
+    private Integer resolveBookCheckTypeFromZdy(Map<String, Object> zdy, String applyNo) {
+        if (zdy == null) {
+            log.warn("[resolveBookCheckTypeFromZdy][鎶ユ枃鏃� ZDY 鑺傜偣锛屾棤娉曡В鏋愭鏌ョ被鍨媇 applyNo={}", applyNo);
+            return null;
+        }
+        String jcxmName = extractZdyValueFromMap(zdy, "jcxmname");
+        String jcxmCode = extractZdyValueFromMap(zdy, "jcxmcode");
+
+        // 鈶� 鍚嶇О鏄犲皠锛堜紭鍏堬細鍙锛屼笖鏋氫妇宸茶鐩� HIS 鏀瑰悕涓庤鑼冨寲宸紓锛�
+        Integer byName = mapCheckNameToType(jcxmName);
+        if (byName != null) {
+            return byName;
+        }
+        // 鈶� 浠g爜鏄犲皠锛堝厹搴曪細瀹炴祴 HIS 渚ф敼杩囧悕锛屼唬鐮佹洿绋冲畾锛�
+        Integer byCode = mapCheckCodeToType(jcxmCode);
+        if (byCode != null) {
+            log.info("[resolveBookCheckTypeFromZdy][鍚嶇О鏈槧灏勶紝宸叉寜妫�鏌ヤ唬鐮佸厹搴昡 "
+                            + "applyNo={} jcxmname={} jcxmcode={} bookCheckType={}",
+                    applyNo, jcxmName, jcxmCode, byCode);
+            return byCode;
+        }
+
+        log.warn("[resolveBookCheckTypeFromZdy][妫�鏌ラ」鐩悕绉颁笌浠g爜鍧囨棤娉曟槧灏勶紝book_check_type 淇濇寔鍘熷�糫 "
+                + "applyNo={} jcxmname={} jcxmcode={}", applyNo, jcxmName, jcxmCode);
+        return null;
+    }
+
+    /** 妫�鏌ラ」鐩悕绉� 鈫� 鏈湴妫�鏌ョ被鍨嬶紙鏀寔閫楀彿鍒嗛殧澶氬�硷紝鍙栫涓�涓彲鏄犲皠鐨勶級 */
+    private Integer mapCheckNameToType(String rawName) {
+        if (StringUtils.isEmpty(rawName)) {
+            return null;
+        }
+        for (String candidate : splitMultiValue(rawName)) {
+            // 鍘荤┖鐧斤細HIS 鎶ユ枃閲屽伓瑙併�屽钩鏉胯繍鍔ㄨ瘯楠� 銆嶈繖绫诲熬闅忕┖鏍�
+            String mapped = HisCheckNameEnum.getByName(candidate.replaceAll("\\s+", ""));
+            Integer value = parseIntegerQuietly(mapped);
+            if (value != null) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    /** HIS 妫�鏌ヤ唬鐮� 鈫� 鏈湴妫�鏌ョ被鍨嬶紙鏀寔閫楀彿鍒嗛殧澶氬�硷紱鍏煎甯�/涓嶅甫 Y 鍓嶇紑锛� */
+    private Integer mapCheckCodeToType(String rawCode) {
+        if (StringUtils.isEmpty(rawCode)) {
+            return null;
+        }
+        for (String candidate : splitMultiValue(rawCode)) {
+            String code = candidate.replaceAll("\\s+", "");
+            if (code.isEmpty()) {
+                continue;
+            }
+            // 鍏煎涓ょ鎶ユ枃褰㈡�侊細甯﹀墠缂�锛圷1202065锛変笌涓嶅甫鍓嶇紑锛�201652锛�
+            String[] tries = code.length() > 1
+                    ? new String[]{code, code.substring(1)}
+                    : new String[]{code};
+            for (String t : tries) {
+                Integer value = parseIntegerQuietly(HisCheckCodeEnum.getByCode(t));
+                if (value != null) {
+                    return value;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 鎷嗗垎銆屽彲鑳界殑澶氬�笺�嶅瓧娈点��
+     * <p>
+     * 鍏堣繑鍥�**鏁翠綋**锛堣鐩栧崟鍊煎満鏅紝涔熼伩鍏嶆妸鍚嶇О閲屾湰灏卞惈閫楀彿鐨勯」鎷嗗潖锛夛紝
+     * 鍐嶈繑鍥炴寜 {@code ,} / {@code 锛寎 鎷嗗嚭鐨勫悇娈点��
+     */
+    private List<String> splitMultiValue(String raw) {
+        List<String> result = new ArrayList<>();
+        if (StringUtils.isEmpty(raw)) {
+            return result;
+        }
+        result.add(raw);
+        for (String part : raw.split("[,锛宂")) {
+            String p = part == null ? "" : part.trim();
+            if (!p.isEmpty() && !p.equals(raw)) {
+                result.add(p);
+            }
+        }
+        return result;
+    }
+
     /** {@code appointment.remark} 鍒楀涓婇檺锛堣 08_fix_remark_length.sql锛屽綋鍓� varchar(2000)锛� */
     private static final int REMARK_MAX_LEN = 2000;
     /** {@code appointment.room_name} 鍒楀涓婇檺 */
@@ -1139,6 +1475,27 @@
 
     /** HIS 鎶ユ枃涓�屽尰鍢卞彿/鍖诲槺ID銆嶇殑 id root锛堣銆婁氦浜掓湇鍔¢�氱敤鎺ュ彛鏂囨。銆�6.1 / 6.4 / 6.5锛� */
     private static final String ORDER_NO_ROOT = "2.16.156.10011.1.28";
+
+    /**
+     * HIS銆屽紑鍗曟椂闂淬��({@code author/time/value}) 鐨勬椂闂存牸寮忋��
+     * 娉ㄦ剰锛歿@link SimpleDateFormat} **涓嶆槸绾跨▼瀹夊叏**鐨勶紝鏁呰繖閲屽彧淇濆瓨 pattern 瀛楃涓诧紝
+     * 姣忔閮芥柊寤哄疄渚嬶紙瑙� {@link #parseHisDoctorTime}锛夈��
+     */
+    private static final String HIS_DOCTOR_TIME_PATTERN = "yyyyMMddHHmmss";
+
+    /**
+     * 鍒ゆ柇 HIS 寮�鍗曟椂闂存槸鍚︿负銆屾棩鏈熷�笺�嶏紙褰㈠ {@code 20261001000000}锛屾椂鍒嗙鍏� 0锛夈��
+     *
+     * <p>鐢� {@code endsWith} 鑰屼笉鏄鍒欙細璇箟鐩寸櫧涓旀棤杞箟鍧�
+     * 锛堟浘鍐欒繃 {@code value.matches("\\d{6}000000")}锛屽洜杞箟灞傜骇鍑洪敊瀵艰嚧姘镐笉鍖归厤锛夈��
+     */
+    private boolean isHisTimeOnlyDate(String value) {
+        if (value == null || value.length() != 14) {
+            return false;
+        }
+        // 鍚� 6 浣嶏紙HHmmss锛夊叏涓� '0' 鍗充负銆屾棩鏈熷�笺�嶅舰鎬�
+        return value.endsWith("000000");
+    }
 
     /**
      * 鍦� HL7 鐨� {@code id} 鑺傜偣涓紝鎸� {@code root} 鍖归厤骞跺彇鍑� {@code extension}銆�
@@ -1442,6 +1799,15 @@
             if (roomName != null && StringUtils.isNotEmpty(roomName.toString())) {
                 appointment.setRoomName(truncate(roomName.toString(), ROOM_NAME_MAX_LEN));
             }
+            // 妫�鏌ョ被鍨嬶細**浠呭湪涓虹┖鏃惰ˉ**
+            //   绛栫暐 (a)锛氫笉瑕嗙洊宸叉湁鍊硷紝閬垮厤鏀瑰潖鏁版嵁锛堜緥濡傝鍗曟浘鐢� S0201ECG 姝g‘鍐欏叆杩囩被鍨嬶級銆�
+            //   涓庡閿欐柊澧炲垎鏀繚鎸佸悓涓�閫昏緫銆�
+            if (appointment.getBookCheckType() == null) {
+                Integer checkTypeValue = resolveBookCheckTypeFromZdy(zdy, applyNo);
+                if (checkTypeValue != null) {
+                    appointment.setBookCheckType(checkTypeValue);
+                }
+            }
         }
         // 棰勭害鎺掑簭鍙凤紙patient.id.item[4]锛�
         Integer seqNum = extractBookSeqNum(actAppointment);
@@ -1548,6 +1914,23 @@
         appointment.setBookSrc(bookSrcValue);
         appointment.setStatus(status);
 
+        // 鎮h�呮潵婧愶紙pat_src锛夛細涓� S0201ECG 淇濇寔鍚屼竴鍋氭硶 鈥斺�� 鐩存帴鍙栨姤鏂囦腑鐨勬偅鑰呯被鍨嬩唬鐮併��
+        //
+        // 鈿狅笍 宸茬煡椋庨櫓锛堜繚鐣欑幇鐘讹紝涓嶅湪鏈鏀瑰姩鑼冨洿鍐咃級锛�
+        //    瀹炴祴 S050401 鎶ユ枃瀵规湰鏉′綋妫�鍗曠粰鍑虹殑鏄� code=3 / displayName=浣撴锛�
+        //    鑰屾湰鍦板瓧鍏革紙ecg_patient_source锛変笌鏁版嵁鍒嗗竷閮借〃鏄庛�屼綋妫� = 4銆佷綇闄� = 3銆嶏細
+        //    鍏ㄥ簱 pat_src=4 鐨� 55,729 鏉$瀹ゅ潎涓恒�屽仴搴风鐞嗕腑蹇冦�嶏紝88 鍓嶇紑锛堜綋妫�锛夊崟 55,874 鏉′负 pat_src=4銆�
+        //    鍗虫姤鏂� code 涓庢湰鍦板瓧鍏哥紪鐮佸苟涓嶄竴鑷淬�傛澶�**鍒绘剰娌跨敤鎶ユ枃鍘熷��**浠ヤ笌 S0201ECG 琛屼负涓�鑷达紝
+        //    濡傞渶鎸夊悕绉扮籂姝o紙浣撴鈫�4锛夛紝搴旂粺涓�鍦ㄤ袱澶勪竴璧锋敼锛岄伩鍏嶄袱鏉℃祦鍐欏嚭涓嶅悓鍊笺��
+        Map<String, Object> codeNode = (Map<String, Object>) actAppointment.get("code");
+        Integer patSrcValue = codeNode == null ? null : parseIntegerQuietly(str(codeNode.get("code")));
+        if (patSrcValue != null) {
+            appointment.setPatSrc(patSrcValue);
+        } else {
+            log.warn("[insertAppointmentFromCheckAppointment][鎶ユ枃缂烘偅鑰呯被鍨�(actAppointment.code.code)锛�"
+                    + "pat_src 灏嗕负绌篯 applyNo={} code={}", applyNo, codeNode);
+        }
+
         Map<String, Object> zdy = (Map<String, Object>) actAppointment.get("ZDY");
         // ZDY 涓殑 remark锛堟敞鎰忎簨椤癸級涓� roomname锛堟埧闂村悕绉帮級宸查殢琛ㄦ柊澧炲垪钀藉簱锛�
         // area锛堜綅缃級涓� roomcode锛堟埧闂寸紪鐮侊級鐩墠浠嶆棤瀵瑰簲鍒楋紝鏆備笉淇濆瓨銆�
@@ -1559,6 +1942,18 @@
             Object roomName = zdy.get("roomname");
             if (roomName != null && StringUtils.isNotEmpty(roomName.toString())) {
                 appointment.setRoomName(truncate(roomName.toString(), ROOM_NAME_MAX_LEN));
+            }
+            // 妫�鏌ョ被鍨嬶細鎶ユ枃閲岀殑 ZDY.jcxmcode / ZDY.jcxmname
+            //
+            // 銆愪慨澶嶃�戝師鍏堟澶�**瀹屽叏娌℃湁**瑙f瀽妫�鏌ョ被鍨嬶紝瀵艰嚧銆孲050401 鍏堝埌銆佷笖灏氭棤 S0201ECG 璁板綍銆�
+            // 鏃跺閿欐柊澧炲嚭鏉ョ殑 appointment.book_check_type 姘歌繙涓虹┖銆�
+            // 瀹炴祴 2026-09-29~10-09 鍏� 279 鏉★紙濡� apply_no=8826092420371106锛�
+            // 鎶ユ枃 ZDY 閲� jcxmcode=201652 / jcxmname=骞虫澘杩愬姩璇曢獙 鏄庢槑瀛樺湪锛夈��
+            if (appointment.getBookCheckType() == null) {
+                Integer checkTypeValue = resolveBookCheckTypeFromZdy(zdy, applyNo);
+                if (checkTypeValue != null) {
+                    appointment.setBookCheckType(checkTypeValue);
+                }
             }
         }
         // 棰勭害鎺掑簭鍙凤紙patient.id.item[4]锛�
@@ -1584,6 +1979,17 @@
                 }
                 if (patIdItems.size() > 3) {
                     appointment.setHospitalNo((String) ((Map<String, Object>) patIdItems.get(3)).get("extension"));
+                }
+                // 灏辫瘖娴佹按鍙凤紙episode_id锛夛細patient.id.item[5]
+                //
+                // 涓� S0201ECG 鍚屾簮锛堥偅杈瑰彇鑷� placerGroup.componentOf1.encounter.id.item[1]锛�
+                // 瀹炴祴涓ゅ鍊肩浉鍚岋細鏈潯鍧囦负 882609242037锛夈��
+                // 銆愪慨澶嶃�戝師鍏堝閿欐柊澧�**瀹屽叏娌℃湁**鍐欏叆灏辫瘖娴佹按鍙凤紝瀵艰嚧璇ュ瓧娈典负绌恒��
+                if (patIdItems.size() > 5) {
+                    String episodeId = (String) ((Map<String, Object>) patIdItems.get(5)).get("extension");
+                    if (StringUtils.isNotEmpty(episodeId)) {
+                        appointment.setEpisodeId(episodeId);
+                    }
                 }
                 // 棰勭害鎺掑簭鍙峰凡鍦ㄤ笂鏂归�氳繃 extractBookSeqNum 缁熶竴璧嬪�硷紝姝ゅ涓嶅啀閲嶅澶勭悊
                 // 鎮h�呭鍚�
@@ -1628,8 +2034,84 @@
             log.warn("[insertAppointmentFromCheckAppointment][鎶ユ枃鏈彁渚涙偅鑰呮�у埆锛屾寜鏈煡(0)鍐欏叆] applyNo={}", applyNo);
             appointment.setPatGender(UNKNOWN_GENDER);
         }
+        // 鎮h�呭浐鏈夊睘鎬у洖濉紙鐢熸棩 / 鐢佃瘽 / 韬唤璇� / 鍦板潃锛�
+        //
+        // 銆愪负浠�涔堥渶瑕併�慡050401 鎶ユ枃鐨� patient.patientPerson **鍙甫濮撳悕**锛�
+        // 涓嶅惈鐢熸棩/鐢佃瘽/韬唤璇侊紙S0201ECG 鏈夈�丼0405 涔熸湁锛屼絾杩欎袱鏉℃姤鏂囧湪鏈満鏅病鏈夊厛鍒帮級锛�
+        // 浜庢槸瀹归敊鏂板鍑烘潵鐨勮褰曡繖浜涘瓧娈靛叏涓虹┖锛屼笌 S0201ECG 寤虹殑鍗曠浉姣�"缂哄瓧娈�"銆�
+        //
+        // 銆愪负浠�涔堣繖鏍疯ˉ鏄噯纭殑銆戣繖浜涙槸**鎮h�呭浐鏈夊睘鎬�**锛堜笉鏄祦姘村睘鎬э級锛�
+        // 鍚屼竴 pat_id 鐨勫巻鍙茶褰曢噷蹇呯劧涓�鑷达紙鍏ㄥ簱濉厖鐜� 99%锛夈��
+        // 娉ㄦ剰锛氬紑鍗曞尰鐢�/寮�鍗曟椂闂村睘娴佹按灞炴�э紝**鍒绘剰涓嶇户鎵�**锛堥偅灞炰簬鎺ㄦ柇锛屽彲鑳藉紶鍐犳潕鎴达級銆�
+        inheritPatientDemographics(appointment, applyNo);
+
         AppointmentSaveReqVO saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class);
         createAppointment(saveReqVO);
+    }
+
+    /**
+     * 瀹归敊鏂板鏃讹紝浠庤鎮h�呮渶杩戜竴鏉¤褰曠户鎵�**鎮h�呭浐鏈夊睘鎬�**銆�
+     *
+     * <p>鍙ˉ銆屾湰娆′负绌恒�嶇殑瀛楁锛岀粷涓嶈鐩栨姤鏂囧凡鎻愪緵鐨勫�笺��
+     * 缁ф壙澶辫触锛堟棤鍘嗗彶璁板綍 / 鏌ヨ寮傚父锛変笉褰卞搷钀藉簱锛屼粎璁版棩蹇椼��</p>
+     *
+     * <p><b>鍒绘剰涓嶇户鎵�</b>鐨勫瓧娈碉細{@code doctor}/{@code doctor_code}/{@code doctor_time}
+     * 锛堝紑鍗曞尰鐢熶笌寮�鍗曟椂闂村睘娴佹按灞炴�э紝鎶ユ枃鏈彁渚涙椂鍙兘鎺ㄦ柇锛屽疄娴嬪悓鎮h�呭悓鏃ヤ竴鑷寸巼 90%锛�
+     * 瀛樺湪寮犲啝鏉庢埓椋庨櫓锛屾晠鎸変笟鍔$‘璁や繚鎸佷负绌猴級銆亄@code register_date}
+     * 锛堝彧搴斿湪 HIS 鎶ャ�屾鏌ョ櫥璁般�嶇姸鎬佹椂鍐欏叆锛夈��</p>
+     *
+     * @param target  鏈瀹归敊鏂板鐨勫璞★紙灏卞湴琛ュ叏锛�
+     * @param applyNo 鐢宠鍗曞彿锛屼粎鐢ㄤ簬鏃ュ織
+     */
+    private void inheritPatientDemographics(AppointmentDO target, String applyNo) {
+        if (StringUtils.isEmpty(target.getPatId())) {
+            return;
+        }
+        // 涓夐」鍏抽敭浜哄彛瀛︿俊鎭姤鏂囬兘缁欎簡灏辨棤闇�缁ф壙锛堟姤鏂囧�间紭鍏堬級
+        if (target.getPatBirthday() != null
+                && StringUtils.isNotEmpty(target.getPatIdentityId())
+                && StringUtils.isNotEmpty(target.getPatMobile())) {
+            return;
+        }
+        AppointmentDO sibling;
+        try {
+            sibling = appointmentMapper.getLatestByPatId(target.getPatId());
+        } catch (Exception e) {
+            log.warn("[inheritPatientDemographics][鏌ヨ鍚屾偅鑰呭巻鍙茶褰曞け璐ワ紝璺宠繃缁ф壙] applyNo={} patId={} err={}",
+                    applyNo, target.getPatId(), e.getMessage());
+            return;
+        }
+        if (sibling == null) {
+            log.warn("[inheritPatientDemographics][璇ユ偅鑰呮棤鍘嗗彶璁板綍鍙户鎵匡紝鎮h�呬俊鎭皢涓嶅畬鏁碷 "
+                    + "applyNo={} patId={}", applyNo, target.getPatId());
+            return;
+        }
+        StringBuilder inherited = new StringBuilder();
+        if (target.getPatBirthday() == null && sibling.getPatBirthday() != null) {
+            target.setPatBirthday(sibling.getPatBirthday());
+            inherited.append("pat_birthday ");
+        }
+        if (StringUtils.isEmpty(target.getPatIdentityId()) && StringUtils.isNotEmpty(sibling.getPatIdentityId())) {
+            target.setPatIdentityId(sibling.getPatIdentityId());
+            inherited.append("pat_identity_id ");
+        }
+        if (StringUtils.isEmpty(target.getPatMobile()) && StringUtils.isNotEmpty(sibling.getPatMobile())) {
+            target.setPatMobile(sibling.getPatMobile());
+            inherited.append("pat_mobile ");
+        }
+        if (StringUtils.isEmpty(target.getPatPhone()) && StringUtils.isNotEmpty(sibling.getPatPhone())) {
+            target.setPatPhone(sibling.getPatPhone());
+            inherited.append("pat_phone ");
+        }
+        if (StringUtils.isEmpty(target.getPatAddr()) && StringUtils.isNotEmpty(sibling.getPatAddr())) {
+            target.setPatAddr(sibling.getPatAddr());
+            inherited.append("pat_addr ");
+        }
+        if (inherited.length() > 0) {
+            log.info("[inheritPatientDemographics][S050401 鎶ユ枃涓嶅惈鎮h�呬汉鍙e淇℃伅锛�"
+                            + "宸蹭粠鍚屾偅鑰呮渶杩戣褰曠户鎵縘 applyNo={} patId={} fromApplyNo={} fields=[{}]",
+                    applyNo, target.getPatId(), sibling.getApplyNo(), inherited.toString().trim());
+        }
     }
 
     /** 瑙f瀽 {@code yyyyMMddHHmmss} 鏃堕棿锛屽け璐ユ垨涓虹┖杩斿洖 null锛堜笉鎶涘紓甯革級 */
@@ -1641,6 +2123,96 @@
             return LocalDateTime.parse(value.trim(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
         } catch (Exception e) {
             log.warn("[parseDateTime][鏃堕棿鏍煎紡闈炴硶锛屽拷鐣 value={}", value);
+            return null;
+        }
+    }
+
+    /**
+     * 瑙f瀽 HIS 鎶ユ枃涓殑銆屽紑鍗曟椂闂淬��({@code author/time/value})銆�
+     *
+     * <h3>鑳屾櫙锛堝疄娴嬬粨璁猴紝2026-10 鎺掓煡锛�</h3>
+     * 搴撲腑绾� <b>61%</b> 鐨� {@code appointment.doctor_time} 涓� {@code yyyy-MM-dd 00:00:00}銆�
+     * 缁忔牳鏌�**涓嶆槸**鏈」鐩殑鏍煎紡鍖栫己闄凤細
+     * <ul>
+     *   <li>鍒楃被鍨嬫槸 {@code datetime}锛屽啓鍏ョ殑鏄� {@code java.util.Date}锛屼繚鐣欐椂鍒嗙锛�</li>
+     *   <li>鐪熷疄鎶ユ枃鏍蜂緥涓瀛楁褰㈠ {@code 20260917005255}锛堝甫鏃跺垎绉掞級锛�</li>
+     *   <li>鏈夌湡瀹炴椂鍒荤殑璁板綍鍛堟甯稿伐浣滄椂娈靛垎甯冿紙06:00鈫�08:00 涓洪珮宄帮級锛�
+     *       鑰岃惤鍦ㄥ紑璇婂墠鐨� 00:00-05:59 鐨勪粎 15 鏉� 鈥斺�� 璇存槑璇ユ椂娈垫湰灏卞嚑涔庝笉寮�鍗曪紱</li>
+     *   <li>鎸夊氨璇婄被鍒湅锛氶棬璇�({@code book_src=1}) 99.6%銆佷綇闄�({@code book_src=2}) 90.5%
+     *       涓� 0 鐐癸紝涓旇鐜拌薄璐┛ 2026 鍏ㄥ勾锛堜笌 2026-09-27 鐨� {@code register_date}
+     *       鎴柇缂洪櫡鏃犲叧锛夈��</li>
+     * </ul>
+     * 鈬� 缁撹锛�**鏄� HIS 渚ф妸璇ュ瓧娈电殑鏃跺垎绉掑彂鎴愪簡 {@code 000000}**锛堝緢鍙兘鏄�屽彧绮剧‘鍒版棩銆�
+     * 鎴栬ˉ褰�/鎵归噺鍥炰紶鐨勫尰鍢憋級銆�
+     *
+     * <h3>鏈柟娉曞仛浠�涔�</h3>
+     * <ul>
+     *   <li>鎸� {@code yyyyMMddHHmmss} 瑙f瀽锛�</li>
+     *   <li>璇嗗埆銆屾椂鍒嗙 = 000000銆嶇殑**鏃ユ湡鍊�**锛屾墦鍑哄甫**鍘熷鎶ユ枃鍊� + 鐢宠鍗曞彿**鐨� WARN
+     *       鈥斺�� 鍘熷疄鐜板彧 {@code printStackTrace()}锛屽嚭闂鏃舵棤浠庡畾浣嶏紱</li>
+     *   <li><b>浠嶇劧鍐欏叆</b>锛堜繚鐣欐棩鏈熼儴鍒嗭級锛氬洜涓恒�岃窛浠婂ぉ鏁般�嶃�屾寜鏃ユ湡鎺掑簭/绛涢�夈�嶉兘鐢ㄦ棩鏈燂紝
+     *       鍐欏叆 NULL 浼氳杩欎簺鍔熻兘閫�鍖栵紝涓旇鍊肩‘涓� HIS 鎵�鍙戙�佸師鏍蜂繚瀛樻洿鍙拷婧��</li>
+     * </ul>
+     *
+     * @param rawValue HIS 鎶ユ枃鍘熷�硷紙褰㈠ {@code 20260917005255}锛�
+     * @param applyNo  鐢宠鍗曞彿锛屼粎鐢ㄤ簬鏃ュ織瀹氫綅
+     * @return 瑙f瀽鍚庣殑鏃堕棿锛涙牸寮忛潪娉曟椂杩斿洖 {@code null}锛堜笉鍐欏簱锛�
+     */
+    private java.util.Date parseHisDoctorTime(String rawValue, String applyNo) {
+        String v = rawValue == null ? null : rawValue.trim();
+        if (StringUtils.isEmpty(v)) {
+            return null;
+        }
+        if (!v.matches("\\d{14}")) {
+            // 瀹炴祴 HIS 鏂囨。鏍蜂緥涓瓨鍦� 12 浣嶏紙yyyyMMddHHmm锛夌敋鑷崇┖鍊硷紝缁熶竴璁� WARN 渚夸簬鍚� HIS 鍙嶉
+            log.warn("[parseHisDoctorTime][寮�鍗曟椂闂存牸寮忛潪 14 浣嶏紝鏃犳硶瑙f瀽锛宒octor_time 灏嗕负绌篯 "
+                    + "applyNo={} raw={} length={}", applyNo, v, v.length());
+            return null;
+        }
+        try {
+            // 鈿狅笍 蹇呴』 setLenient(false)锛歋impleDateFormat 榛樿瀹芥澗锛�
+            // 浼氭妸闈炴硶鏃ユ湡闈欓粯婊氭垚鍚堟硶鍊硷紙濡� 13 鏈� 鈫� 娆″勾 1 鏈堬級锛屽鑷磋剰鏁版嵁鍏ュ簱銆�
+            // 瀹炴祴锛歭enient 涓� "20261301000000" 琚В鏋愭垚 2027-01-01 涓斾笉鎶ラ敊銆�
+            SimpleDateFormat sdf = new SimpleDateFormat(HIS_DOCTOR_TIME_PATTERN);
+            sdf.setLenient(false);
+            java.util.Date parsed = sdf.parse(v);
+            if (isHisTimeOnlyDate(v)) {
+                log.warn("[parseHisDoctorTime][HIS 寮�鍗曟椂闂存椂鍒嗙涓� 000000锛堟棩鏈熷�硷級锛�"
+                        + "doctor_time 灏嗕繚瀛樹负褰撴棩 00:00:00 鈥斺�� 璇ュ�肩敱 HIS 鎶ユ枃鍘熸牱鑰屾潵] "
+                        + "applyNo={} raw={}", applyNo, v);
+            }
+            return parsed;
+        } catch (Exception e) {
+            log.warn("[parseHisDoctorTime][寮�鍗曟椂闂磋В鏋愬け璐ワ紝doctor_time 灏嗕负绌篯 applyNo={} raw={} err={}",
+                    applyNo, v, e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 鐢� {@code book_timeslot}锛坔hmmhhmm锛屽 8000830=08:00-08:30銆�13301400=13:30-14:00锛夊彇棰勭害鏃跺埢锛堝彧鍚椂鍒嗭級銆�
+     * <p>鐢ㄦ潵缁� S0201ECG 杩欐潯娴佽ˉ {@code book_time}锛氬師瀹炵幇鏁存潯娴佷笉鍐欓绾︽椂闂达紝
+     * 寤哄嚭鏉ョ殑璁板綍 book_date/book_timeslot/book_time 鍏ㄧ┖锛堝疄娴� 211741銆�211962锛夈��</p>
+     */
+    private LocalTime timeOfTimeslot(Integer timeslot) {
+        if (timeslot == null) {
+            return null;
+        }
+        try {
+            String s = String.valueOf(timeslot);
+            if (s.length() < 5) {
+                return null;
+            }
+            String start = s.substring(0, s.length() - 4);   // 鍓嶄竴娈� = 寮�濮嬫椂闂� hhmm
+            int hhmm = Integer.parseInt(start);
+            int hour = hhmm / 100;
+            int minute = hhmm % 100;
+            if (hour > 23 || minute > 59) {
+                return null;
+            }
+            return LocalTime.of(hour, minute);
+        } catch (Exception e) {
+            log.warn("[timeOfTimeslot][鏃堕棿娈佃В鏋愬け璐ワ紝蹇界暐] timeslot={}", timeslot);
             return null;
         }
     }
@@ -1680,6 +2252,38 @@
         }
     }
 
+    /**
+     * 銆愭湰闇�姹傦細绱ф�ユ偅鑰呬笉鎺掗槦鐩存帴妫�鏌ャ�戞寜銆岀敵璇峰崟鍙� / 灏辫瘖鍙� / 鎮h�呯紪鍙枫�嶆煡杩戜竴涓湀鐨勯绾﹁褰曘��
+     * <p>
+     * 绐楀彛 [浠婂ぉ-30 澶�, 浠婂ぉ+30 澶锛屾寜鏈獥鍙e紑灞曠殑妫�鏌ラ」鐩繃婊わ紝缁撴灉鎸�**棰勭害鏃堕棿鍊掑簭**銆�
+     */
+    @Override
+    public List<AppointmentDO> getEmergencyCandidates(String code, String checkTypes) {
+        if (StringUtils.isEmpty(code)) {
+            return new ArrayList<>();
+        }
+        List<Integer> checkTypeList = splitToIntList(checkTypes);
+        List<AppointmentDO> list = appointmentMapper.getEmergencyCandidates(code.trim(), checkTypeList);
+        log.info("[getEmergencyCandidates] 绱ф�ュ姞鍋氬�欓�夋煡璇�. code={} checkTypes={} 鍛戒腑={}",
+                code, checkTypes, null == list ? 0 : list.size());
+        return null == list ? new ArrayList<>() : list;
+    }
+
+    /** 鎶� `100,200` 杩欑被閫楀彿鍒嗛殧涓茶В鏋愭垚 List&lt;Integer&gt;锛涢潪娉曢」蹇界暐 */
+    private List<Integer> splitToIntList(String raw) {
+        List<Integer> result = new ArrayList<>();
+        if (StringUtils.isEmpty(raw)) {
+            return result;
+        }
+        for (String part : raw.split("[,锛宂")) {
+            Integer v = parseIntegerQuietly(part);
+            if (null != v && !result.contains(v)) {
+                result.add(v);
+            }
+        }
+        return result;
+    }
+
     /** 瀹芥澗 Byte 瑙f瀽锛氶潪鏁板瓧鎴栫┖杩斿洖 null锛堢敤浜庢偅鑰呮�у埆绛� tinyint 瀛楁锛� */
     private Byte parseByteQuietly(String value) {
         if (StringUtils.isEmpty(value) || !value.trim().matches("-?\\d+")) {

--
Gitblit v1.9.3