From 0afac42fb2e9d6e5291304dd0044ce3042b45d2b Mon Sep 17 00:00:00 2001
From: liusheng <337615773@qq.com>
Date: 星期六, 10 十月 2026 15:09:14 +0800
Subject: [PATCH] 短信模块提交

---
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java | 1320 ++++++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 880 insertions(+), 440 deletions(-)

diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
index 0422675..2b0a141 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
@@ -6,25 +6,35 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.gson.Gson;
+import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.dx.MessageSend;
-import com.ruoyi.common.enums.MsgLSEnum;
+import com.ruoyi.common.core.service.IDingTalkService;
 import com.ruoyi.common.enums.ServiceFromEnum;
-import com.ruoyi.common.enums.WxGZHEnum;
 import com.ruoyi.common.utils.*;
 import com.ruoyi.common.utils.http.HttpUtils;
-import com.ruoyi.common.utils.sms.smsUtils;
+import com.ruoyi.message.SendResult;
+import com.ruoyi.message.sms.SmsSendRequest;
+import com.ruoyi.message.sms.SmsSenderFactory;
+import com.ruoyi.message.sms.provider.xh.XinHuaSmsSender;
+import com.ruoyi.message.wechat.WechatSendRequest;
+import com.ruoyi.message.wechat.WechatSenderFactory;
+import com.ruoyi.quartz.constant.MzGatherConstant;
+import com.ruoyi.quartz.enums.MzGatherParamEnum;
+import com.ruoyi.quartz.enums.MzGatherSlotEnum;
+import com.ruoyi.quartz.enums.MzGatherStatusEnum;
 import com.ruoyi.quartz.service.ICollectHISService;
 import com.ruoyi.quartz.util.CreateDataTable;
 import com.ruoyi.system.domain.SysConfig;
 import com.ruoyi.system.mapper.SysConfigMapper;
 import com.ruoyi.system.service.ISysConfigService;
 import com.ruoyi.system.service.ISysDeptService;
-import com.smartor.common.LSHospTokenUtil;
-import com.smartor.common.MtSubmitSmUtil;
+import com.ruoyi.system.service.ISysUserService;
+import com.ruoyi.message.sms.provider.sltd.ws.MessageSend;
 import com.smartor.common.QwenLLMUtil;
 import com.smartor.domain.*;
+import com.smartor.domain.VO.ServiceSubtaskDetailTraceVO;
 import com.smartor.domain.entity.ServiceSubtaskEntity;
 import com.smartor.mapper.*;
 import com.smartor.service.*;
@@ -40,17 +50,15 @@
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.security.MessageDigest;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
-
-import static cn.hutool.core.convert.Convert.toHex;
 
 /**
  * 瀹氭椂浠诲姟璋冨害娴嬭瘯
@@ -102,21 +110,15 @@
     @Autowired
     private ISysConfigService configService;
 
+    @Autowired
+    private IDingTalkService dingTalkService;
+
+    @Autowired
+    private ISysUserService userService;
+
 
     @Value("${localIP}")
     private String localIP;
-
-    @Value("${xhsmsPath}")
-    private String xhsmsPath;
-
-    @Value("${xhsmsAccount}")
-    private String xhsmsAccount;
-
-    @Value("${xhsmsPwd}")
-    private String xhsmsPwd;
-    // 铏氭嫙鎺ュ叆鐮�
-    @Value("${xhsmsjrm}")
-    private String xhsmsjrm;
 
     @Value("${pub_key}")
     private String pub_key;
@@ -146,6 +148,9 @@
     ISysDeptService sysDeptService;
 
     @Autowired
+    IServiceSubtaskDetailTraceService serviceSubtaskDetailTraceService;
+
+    @Autowired
     IPatMedOuthospService patMedOuthospService;
 
     @Autowired
@@ -173,13 +178,25 @@
     @Value("${server.port}")
     private String port;
 
+    /**
+     * 娑堟伅鍙戦�佹柟宸ュ巶锛堢煭淇�/寰俊鍏紬鍙凤級銆�
+     * <p>
+     * 鍘熸潵鐭俊涓庡叕浼楀彿鐨勫彂閫侀�昏緫鍦ㄦ湰绫婚噷鐢� {@code if (active.equals("xx"))} 纭垎鏀簡绾� 300 琛岋紝
+     * 鐜板凡鏀跺彛鍒� {@code ruoyi-message} 妯″潡锛岃繖閲屽彧璐熻矗鎸� {@code active} 璺敱銆�
+     */
     @Autowired
-    private MtSubmitSmUtil mtSubmitSmUtil;
+    private SmsSenderFactory smsSenderFactory;
+
+    @Autowired
+    private WechatSenderFactory wechatSenderFactory;
 
     @Value("${spring.profiles.active}")
     private String active;
     @Autowired
     private SysConfigMapper sysConfigMapper;
+
+    @Autowired
+    private IServiceTaskScheduleService serviceTaskScheduleService;
 
     public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) {
         System.out.println(StringUtils.format("鎵ц澶氬弬鏂规硶锛� 瀛楃涓茬被鍨媨}锛屽竷灏旂被鍨媨}锛岄暱鏁村瀷{}锛屾诞鐐瑰瀷{}锛屾暣褰}", s, b, l, d, i));
@@ -231,6 +248,112 @@
     }
 
     /**
+     * 瀹氭椂鍙戦�丼LTD婊℃剰搴﹀紓甯镐俊鎭�
+     */
+    public void sendSLTDMYDExceptInfo() {
+        //1.鑾峰彇鍙戦�佷汉宸ュ彿
+        ServiceSubtaskDetailTraceVO subtaskDetailTraceVO = new ServiceSubtaskDetailTraceVO();
+        subtaskDetailTraceVO.setHandleFlag("0");
+        List<ServiceSubtaskDetailTrace> serviceSubtaskDetailTraces = serviceSubtaskDetailTraceService.selectServiceSubtaskDetailTtraceList(subtaskDetailTraceVO);
+        // 鎶� dutyDeptPersonCode 鏁寸悊鍒� list 涓紙濡傛灉澶氫釜浜虹敤閫楀彿鍒嗗壊锛屽垯灞曞紑骞跺幓閲嶏級
+        List<String> dutyDeptPersonCodeList = serviceSubtaskDetailTraces.stream().map(ServiceSubtaskDetailTrace::getDutyDeptPersonCode).filter(StringUtils::isNotBlank).flatMap(code -> Arrays.stream(code.split(","))).map(String::trim).filter(StringUtils::isNotBlank).distinct()  // 鍘婚噸
+                .collect(Collectors.toList());
+        // 鑾峰彇鈥滅渷绔嬪悓寰锋弧鎰忓害寮傚父鍐呭鎻愰啋"
+        SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("sltd.myd.send.except.contont");
+        String exceptContent = sysConfig.getConfigValue();
+
+        // 鑾峰彇鈥滅渷绔嬪悓寰锋弧鎰忓害寮傚父鍐呭鎻愰啋娴嬭瘯浜哄伐鍙封��
+        String testPerson = sysConfigMapper.checkConfigKeyUnique("sltd.myd.send.test.person").getConfigValue();
+        if (StringUtils.isNotBlank(testPerson)) {
+            String[] split = testPerson.split(",");
+            if (CollectionUtils.isEmpty(dutyDeptPersonCodeList)) dutyDeptPersonCodeList = Arrays.asList(split);
+            else dutyDeptPersonCodeList.addAll(Arrays.asList(split));
+        }
+
+        if (CollectionUtils.isNotEmpty(dutyDeptPersonCodeList)) {
+            for (String dutyDeptPersonCode : dutyDeptPersonCodeList) {
+                log.info("銆恠endSLTDMYDExceptInfo銆戝彂閫佷汉宸ュ彿锛歿}", dutyDeptPersonCode);
+                String data = MessageSend.sendMsg(exceptContent, "7", dutyDeptPersonCode, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
+            }
+        }
+    }
+
+    /**
+     * 瀹氭椂鍙戦�佸紓甯镐俊鎭�-鏅畞
+     */
+    public void sendExceptInfo() throws Exception {
+        //1.鑾峰彇鍙戦�佷汉宸ュ彿
+        ServiceSubtaskDetailTraceVO subtaskDetailTraceVO = new ServiceSubtaskDetailTraceVO();
+        subtaskDetailTraceVO.setHandleFlag("0");
+        List<ServiceSubtaskDetailTrace> serviceSubtaskDetailTraces =
+                serviceSubtaskDetailTraceService.selectServiceSubtaskDetailTtraceList(subtaskDetailTraceVO);
+        // 鑾峰彇鈥滃紓甯稿唴瀹规彁閱�"
+        SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("send.except.content");
+        String exceptContent = sysConfig.getConfigValue();
+
+        // 鑾峰彇鈥滃唴瀹规彁閱掓祴璇曚汉宸ュ彿鈥�
+        SysConfig testPersonConfig = sysConfigMapper.checkConfigKeyUnique("send.test.person");
+        String testPerson = ObjectUtils.isNotEmpty(testPersonConfig) ? testPersonConfig.getConfigValue() : "";
+        if(CollectionUtils.isNotEmpty(serviceSubtaskDetailTraces)){
+            for (ServiceSubtaskDetailTrace serviceSubtaskDetailTrace : serviceSubtaskDetailTraces) {
+                List<String> dutyDeptPersonCodeList = new ArrayList<>();
+                        // 鎶� dutyDeptPersonCode 鏁寸悊鍒� list 涓紙濡傛灉澶氫釜浜虹敤閫楀彿鍒嗗壊锛屽垯灞曞紑骞跺幓閲嶏級
+                String dutyDeptPersonCodeStr = serviceSubtaskDetailTrace.getDutyDeptPersonCode();
+                if(StringUtils.isNotEmpty(dutyDeptPersonCodeStr)){
+                    String[] dutyDeptPersonCodeSplit = dutyDeptPersonCodeStr.split(",");
+                    if (CollectionUtils.isEmpty(dutyDeptPersonCodeList)) {
+                        dutyDeptPersonCodeList = new ArrayList<>(Arrays.asList(dutyDeptPersonCodeSplit));
+                    } else {
+                        dutyDeptPersonCodeList.addAll(Arrays.asList(dutyDeptPersonCodeSplit));
+                    }
+
+                }
+
+                if (StringUtils.isNotBlank(testPerson)) {
+                    String[] split = testPerson.split(",");
+                    if (CollectionUtils.isEmpty(dutyDeptPersonCodeList)) {
+                        dutyDeptPersonCodeList = new ArrayList<>(Arrays.asList(split));
+                    } else {
+                        dutyDeptPersonCodeList.addAll(Arrays.asList(split));
+                    }
+                }
+
+                if (CollectionUtils.isNotEmpty(dutyDeptPersonCodeList)) {
+                    for (String dutyDeptPersonCode : dutyDeptPersonCodeList) {
+                        log.info("銆恠endExceptInfo銆戝彂閫佷汉宸ュ彿锛歿}", dutyDeptPersonCode);
+                        SysUser sysUser = new SysUser();
+                        SysUser sysUserVo = new SysUser();
+                        sysUserVo.setUserName(dutyDeptPersonCode);
+                        sysUserVo.setOrgid(serviceSubtaskDetailTrace.getOrgid());
+                        List<SysUser> users = userService.getUserList(sysUserVo);
+                        String phoneNumber = "";
+                        if(ObjectUtils.isNotEmpty(users)){
+                            sysUser = users.get(0);
+                            phoneNumber = sysUser.getPhonenumber();
+                        }else {
+                            continue;
+                        }
+
+                        if(StringUtils.isEmpty(phoneNumber)){
+                            continue;
+                        }
+                        String dutyDeptPerson = dingTalkService.getDingTalkUserByMobile(phoneNumber);
+                        if(StringUtils.isNotBlank(dutyDeptPerson)){
+                            String context = TemplateUtils.render(exceptContent, serviceSubtaskDetailTrace);
+                            dingTalkService.sendDingTalkText(context, dutyDeptPerson);
+                            //鏇存柊鐘舵��
+                            serviceSubtaskDetailTrace.setHandleFlag("1");
+                            serviceSubtaskDetailTrace.setUpdateTime(new Date());
+                            serviceSubtaskDetailTraceService.updateServiceSubtaskDetailTtrace(serviceSubtaskDetailTrace);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
      * 瀹氭椂澶勭悊澶栭摼鐨勬暟鎹�
      */
     public void runServiceSubTaskAnswer() {
@@ -246,6 +369,17 @@
         LocalDateTime tomorrowEnd = tomorrowStart.plusDays(1).minusSeconds(1);     // 鏄庡ぉ 23:59:59
         ixhGatherPatArchiveService.getAppointRecordInfo("2", tomorrowStart, tomorrowEnd);
     }
+
+    /**
+     * 姣忔湀15鍙峰拰鏈堝簳锛屾煡璇㈠苟澶勭悊 HIS 鏁版嵁锛堝悓寰凤紝鍗楀崕锛�
+     */
+    public void dealHisDataHalfMonth() {
+        LocalDateTime now = LocalDateTime.now();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        String formattedNow = now.format(formatter);
+        dealHisData(formattedNow);
+    }
+
 
     /**
      * HIS鏁版嵁閲囬泦
@@ -343,7 +477,7 @@
                     iIcd10Service.queryAddIcd10();
                 }
 
-                // nhfy/sltd鍥炴函30澶╁垎娈甸噰闆嗗垽鏂紙姣忔鏈�澶�7澶╋級
+                // nhfy/sltd鍥炴函30澶╁垎娈甸噰闆嗗垽鏂紙姣忔鏈�澶�4澶╋級
                 boolean isBackfill = (active.trim().equals("nhfy") || active.trim().equals("sltd")) && StringUtils.isNotBlank(todayZeroStr);
                 if (isBackfill) {
                     DateTimeFormatter dateFmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@@ -351,7 +485,7 @@
                     LocalDate segEndDate = todayZero.toLocalDate();
                     int segCount = 0;
                     while (!segStart.isAfter(segEndDate)) {
-                        LocalDate segEnd = segStart.plusDays(6);
+                        LocalDate segEnd = segStart.plusDays(3);
                         if (segEnd.isAfter(segEndDate)) {
                             segEnd = segEndDate;
                         }
@@ -384,7 +518,7 @@
                         list.add("FH0109.23");
                         list.add("FH0109.53");
                         serviceSLTDInhospReqVO.setStatusList(list);
-                        log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滈鍏ラ櫌鈥濋噰闆嗘暟鎹叆鍙傦細{}", serviceSLTDInhospReqVO);
+//                        log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滈鍏ラ櫌鈥濋噰闆嗘暟鎹叆鍙傦細{}", serviceSLTDInhospReqVO);
                         serviceSLTDHealthcareRecordService.queryHealthcareRecordList(serviceSLTDInhospReqVO);
                         log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滈鍏ラ櫌鈥濈祼鏉熼噰闆嗘暟鎹紝闄㈠尯锛歿}", cid);
 
@@ -402,7 +536,7 @@
                         List<String> listStr = new ArrayList<>();
                         listStr.add("FH0109.24");
                         serviceSLTDInhospReqVO.setStatusList(listStr);
-                        log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滃叆闄⑩�濋噰闆嗘暟鎹叆鍙傦細{}", serviceSLTDInhospReqVO);
+//                        log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滃叆闄⑩�濋噰闆嗘暟鎹叆鍙傦細{}", serviceSLTDInhospReqVO);
                         serviceSLTDHealthcareRecordService.queryHealthcareRecordList(serviceSLTDInhospReqVO);
                         log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滃叆闄⑩�濈祼鏉熼噰闆嗘暟鎹紝闄㈠尯锛歿}", cid);
 
@@ -425,7 +559,7 @@
                         //棰勫嚭闄�
                         list2.add("FH0109.25");
                         serviceSLTDInhospReqVO.setStatusList(list2);
-                        log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滃嚭闄⑩�濋噰闆嗘暟鎹叆鍙傦細{}", serviceSLTDInhospReqVO);
+//                        log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滃嚭闄⑩�濋噰闆嗘暟鎹叆鍙傦細{}", serviceSLTDInhospReqVO);
                         serviceSLTDHealthcareRecordService.queryHealthcareRecordList(serviceSLTDInhospReqVO);
                         log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滃嚭闄⑩�濇潫閲囬泦鏁版嵁锛岄櫌鍖猴細{}", cid);
                     }
@@ -446,7 +580,7 @@
      * @param endDateStr   鏃ユ湡缁撴潫 yyyy-MM-dd
      */
     private void collectSegmentData(Long cid, String startDateStr, String endDateStr) {
-        // 棰勫叆闄�
+//        // 棰勫叆闄�
         log.info("銆恉ealHisData銆戦鍏ラ櫌寮�濮嬮噰闆嗘暟鎹紝闄㈠尯锛歿}锛屾椂闂存锛歿} ~ {}", cid, startDateStr, endDateStr);
         ServiceSLTDInhospReqVO reqVO = new ServiceSLTDInhospReqVO();
         reqVO.setOrgId("20001001");
@@ -459,7 +593,12 @@
         preAdmitStatus.add("FH0109.53");
         reqVO.setStatusList(preAdmitStatus);
         log.info("銆恉ealHisData銆戦鍏ラ櫌閲囬泦鏁版嵁鍏ュ弬锛歿}", reqVO);
-        serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
+        try {
+            serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
+        } catch (Exception e) {
+            // 鍗曠被鏁版嵁澶辫触涓嶅啀鍚戜笂鎶涳細鍚﹀垯涓�娈靛け璐ヤ細璁╂湰娆″洖婧悗闈㈢殑鎵�鏈夋閮戒笉鎵ц
+            log.error("銆恉ealHisData銆戦鍏ラ櫌閲囬泦澶辫触锛岃烦杩囪绫荤户缁�傞櫌鍖猴細{}锛屾椂闂存锛歿} ~ {}", cid, startDateStr, endDateStr, e);
+        }
         log.info("銆恉ealHisData銆戦鍏ラ櫌绲備簡閲囬泦鏁版嵁锛岄櫌鍖猴細{}", cid);
 
         // 鍏ラ櫌
@@ -473,7 +612,12 @@
         admitStatus.add("FH0109.24");
         reqVO.setStatusList(admitStatus);
         log.info("銆恉ealHisData銆戝叆闄㈤噰闆嗘暟鎹叆鍙傦細{}", reqVO);
-        serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
+        try {
+            serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
+        } catch (Exception e) {
+            // 鍗曠被鏁版嵁澶辫触涓嶅啀鍚戜笂鎶涳細鍚﹀垯涓�娈靛け璐ヤ細璁╂湰娆″洖婧悗闈㈢殑鎵�鏈夋閮戒笉鎵ц
+            log.error("銆恉ealHisData銆戝叆闄㈤噰闆嗗け璐ワ紝璺宠繃璇ョ被缁х画銆傞櫌鍖猴細{}锛屾椂闂存锛歿} ~ {}", cid, startDateStr, endDateStr, e);
+        }
         log.info("銆恉ealHisData銆戝叆闄㈢祩浜嗛噰闆嗘暟鎹紝闄㈠尯锛歿}", cid);
 
         // 鍑洪櫌
@@ -490,101 +634,405 @@
         dischargeStatus.add("FH0109.25");
         reqVO.setStatusList(dischargeStatus);
         log.info("銆恉ealHisData銆戝嚭闄㈤噰闆嗘暟鎹叆鍙傦細{}", reqVO);
-        serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
+        try {
+            serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
+        } catch (Exception e) {
+            // 鍗曠被鏁版嵁澶辫触涓嶅啀鍚戜笂鎶涳細鍚﹀垯涓�娈靛け璐ヤ細璁╂湰娆″洖婧悗闈㈢殑鎵�鏈夋閮戒笉鎵ц
+            log.error("銆恉ealHisData銆戝嚭闄㈤噰闆嗗け璐ワ紝璺宠繃璇ョ被缁х画銆傞櫌鍖猴細{}锛屾椂闂存锛歿} ~ {}", cid, startDateStr, endDateStr, e);
+        }
         log.info("銆恉ealHisData銆戝嚭闄㈢粨鏉熼噰闆嗘暟鎹紝闄㈠尯锛歿}", cid);
     }
 
     /**
-     * HIS鐪佺珛鍚屽痉闂ㄦ�ヨ瘖鏁版嵁閲囬泦锛堣繖涓彧鑳戒竴澶╂墽琛屼竴娆★紝涓嶈兘鍗婁釜灏忔椂鎵ц涓�涓紝鏁版嵁閲忓お澶э紝褰卞搷鎬ц兘锛�
-     * 瀹氭椂浠诲姟锛氶棬璇婃暟鎹�
-     * todayZeroStr  褰撳墠鐨勬椂闂�   渚嬪锛�2026-05-06 00:00:00
+     * HIS鐪佺珛鍚屽痉闂ㄦ�ヨ瘖鏁版嵁閲囬泦锛堟瘡鍗婂皬鏃朵竴杞紝鎸夊ぉ鍏ㄩ噺鍒锋柊 + 鍒嗛〉鏂偣缁噰锛�
+     * <p>
+     * HIS 渚ч棬鎬ヨ瘖鏁版嵁鍙兘鎸夊ぉ鏌ワ紝姣忚疆鎷夊埌鐨勯兘鏄綋澶╁叏閲忥紙鍒版櫄涓婁竴涓囧鏉★級锛岃繖涓彇鏁版垚鏈敼涓嶄簡锛�
+     * 鑳芥敼鐨勬槸澶勭悊鎴愭湰锛氬綋澶╂暟鎹噷缁濆ぇ澶氭暟涓婁竴杞凡缁忓叆搴擄紝闈�"鏁撮〉鎵归噺鏌ラ噸 + 宸插叆搴撶洿鎺ヨ烦杩�"锛�
+     * 姣忚疆鐪熸闇�瑕佸仛妗f澶勭悊鍜屽叆搴撶殑鍙湁鏂板嚭鐜扮殑閭e嚑鐧炬潯锛屼竴涓囧鏉′篃鑳藉湪寰堢煭鏃堕棿鍐呰窇瀹屻��
+     * <p>
+     * 姣忎竴杞仛涓変欢浜嬶細
+     * <ol>
+     *   <li>浠婂ぉ鐨勬暣杞埛鏂帮細绗� 1 椤电炕鍒版渶鍚庝竴椤碉紝鍙鐞嗘柊璁板綍锛�</li>
+     *   <li>鏄ㄥぉ鐨勬敹灏鹃噰闆嗭細姣忓ぉ鍙仛涓�娆★紝鍏滀綇 23:xx 涔嬪悗鎵嶅啓鍏� HIS 鐨勮褰曞拰璺ㄩ浂鐐圭殑鏁版嵁锛�</li>
+     *   <li>鎵嬪伐鍥炴函锛氫换鍔″叆鍙傜粰浜嗘棩鏈熸椂锛屾妸閭eぉ琛ラ噰涓�娆★紙鍚屼竴澶╁彧琛ヤ竴娆★紝涓嶄細姣忚疆閲嶅琛ワ級銆�</li>
+     * </ol>
+     * 姣忚疆鏈�澶氳窇 {@link MzGatherParamEnum#BUDGET_MINUTES}锛堥粯璁� 20 鍒嗛挓锛夛紝鍒扮偣淇濆瓨椤电爜鏂偣姝e父閫�鍑猴紝涓嬩竴杞粠璇ラ〉缁х画锛�
+     * 姣忛噰瀹屼竴椤甸兘浼氳惤涓�娆℃柇鐐癸紝杩涚▼琚潃涔熶笉浼氫粠澶撮噸鎵��
+     * <p>
+     * 澶辫触涓�寰嬩笉闃绘柇閲囬泦杩涘害锛�
+     * <ul>
+     *   <li>鏁版嵁灞傚け璐ワ紙杞崲/妗f/鍏ュ簱锛夎惤 pat_med_outhosp_error 琛ㄤ氦浜哄伐澶勭悊锛�</li>
+     *   <li>鎺ュ彛灞傚け璐ワ紙缃戠粶瓒呮椂銆佹潵鏈潵杩斿洖闈� 200锛夋病鏈夋暟鎹彲钀借〃锛屽彧鍐� error 鏃ュ織锛堝惈闄㈠尯銆佹棩鏈熴�侀〉鐮併�佹帴鍙e叆鍙傦級锛�
+     *       璺宠繃璇ラ〉缁х画寰�鍚庨噰锛屾湰杞粨鏉熸椂鎶婃柇鐐圭暀鍦ㄧ涓�涓け璐ラ〉锛涘洜涓烘瘡杞兘鏄暣澶╀粠澶村叏閲忓埛鏂帮紝
+     *       琚烦杩囩殑椤典笅涓�杞繀鐒堕噸鏂伴噰鍒帮紝涓嶄細婕忥紱</li>
+     *   <li>杩炵画 {@link MzGatherConstant#MAX_CONSECUTIVE_PAGE_FAIL} 椤垫帴鍙eけ璐ュ垽瀹氫负鎺ュ彛鏁翠綋涓嶅彲鐢紝鏈疆鎻愬墠缁撴潫锛堥伩鍏嶇┖杞嚑鍗侀〉锛夛紝
+     *       鏂偣鐣欏湪绗竴涓け璐ラ〉锛屼笅涓�杞啀璇曘��</li>
+     * </ul>
+     *
+     * @param todayZeroStr 鍙�夛紝鎵嬪伐鎸囧畾瑕佷竴娆℃�у洖婧殑鏃ユ湡锛屾敮鎸� yyyy-MM-dd HH:mm:ss 鎴� yyyy-MM-dd锛涗负绌烘椂鍙埛鏂颁粖澶�+鏀跺熬鏄ㄥぉ
      */
     public void dealHisDataMZ(String todayZeroStr) {
-        log.info("銆恉ealHisData銆戦棬鎬ヨ瘖鏁版嵁寮�濮嬫墽琛孒IS鏁版嵁閲囬泦浠诲姟");
-        // 鑾峰彇鏄ㄥぉ0鐐瑰埌浠婂ぉ0鐐圭殑鏃堕棿鑼冨洿
-        LocalDateTime todayZero = LocalDateTime.now().with(LocalTime.MIN);
-        if (StringUtils.isNotBlank(todayZeroStr)) {
-            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-            todayZero = LocalDateTime.parse(todayZeroStr, formatter);
+        log.info("銆恉ealHisDataMZ銆戦棬鎬ヨ瘖鏁版嵁閲囬泦寮�濮嬶紝鍏ュ弬锛歿}", todayZeroStr);
+        // 鍗楀崕闄勪竴鐨勫厛涓嶉噰闂ㄦ�ヨ瘖鏁版嵁
+        if (!"sltd".equals(active.trim())) {
+            log.info("銆恉ealHisDataMZ銆戝綋鍓嶇幆澧� {} 涓嶉噰闆嗛棬鎬ヨ瘖鏁版嵁锛岃烦杩�", active.trim());
+            return;
         }
-        LocalDateTime tomorrowdayZero = todayZero.plusDays(1);
 
-        if (active.trim().equals("sltd") || active.trim().equals("nhfy")) {
-            //鐪佺珛鍚屽痉涓庡崕鍗楅檮涓�鐢ㄥ悓涓�濂楅噰闆嗘柟娉曪紙閮芥槸鏉ユ湭鏉ユ彁渚涳級
+        long budgetMinutes = getMzConfigLong(MzGatherParamEnum.BUDGET_MINUTES);
+        long pageSize = getMzConfigLong(MzGatherParamEnum.PAGE_SIZE);
+        long maxPage = getMzConfigLong(MzGatherParamEnum.MAX_PAGE);
+
+        LocalDateTime now = LocalDateTime.now().withNano(0);
+        LocalDateTime deadline = now.plusMinutes(budgetMinutes);
+
+        // 鑾峰彇鐪佺珛鍚屽痉瑕侀噰闆嗙殑闄㈠尯
+        SysConfig cf = new SysConfig();
+        cf.setConfigKey("sltd.gather.campusid");
+        cf.setOrgid(MzGatherConstant.ORG_ID);
+        List<SysConfig> sysConfigcampusids = configService.selectConfigList(cf);
+        if (CollectionUtils.isEmpty(sysConfigcampusids) || StringUtils.isBlank(sysConfigcampusids.get(0).getConfigValue())) {
+            log.error("銆恉ealHisDataMZ銆慡ysConfig涓殑闄㈠尯ID涓虹┖锛�");
+            return;
+        }
+        List<Long> campusidList = Arrays.stream(sysConfigcampusids.get(0).getConfigValue().split(","))
+                .map(String::trim).filter(StringUtils::isNotBlank).map(Long::valueOf).collect(Collectors.toList());
+        log.info("銆恉ealHisDataMZ銆戦櫌鍖猴細{}锛屽崟杞绠楋細{}鍒嗛挓锛屾瘡椤碉細{}鏉�", campusidList, budgetMinutes, pageSize);
+
+        for (Long cid : campusidList) {
+            if (LocalDateTime.now().isAfter(deadline)) {
+                log.warn("銆恉ealHisDataMZ銆戞湰杞椂闂撮绠楀凡鐢ㄥ敖锛屽墿浣欓櫌鍖虹暀鍒颁笅涓�杞户缁紝闄㈠尯锛歿}", cid);
+                break;
+            }
+            // 闃叉涓婁竴杞繕娌¤窇瀹屽氨琚笅涓�杞彔鐫�璺戯紙棰勭畻閰嶇疆杩囧ぇ銆佹垨鎵嬪伐瑙﹀彂鏃跺厹搴曪級
+            String lockKey = "mzRunning:" + cid;
+            if (Boolean.TRUE.equals(redisCache.hasKey(lockKey))) {
+                log.warn("銆恉ealHisDataMZ銆戣闄㈠尯涓婁竴杞噰闆嗗皻鏈粨鏉燂紝鏈疆璺宠繃锛岄櫌鍖猴細{}锛堟柇鐐瑰凡淇濈暀锛屼笅涓�杞户缁級", cid);
+                continue;
+            }
+            redisCache.setCacheObject(lockKey, MzGatherConstant.MINUTE_FMT.format(now), budgetMinutes * 2, TimeUnit.MINUTES);
             try {
-                //鑾峰彇鐪佺珛鍚屽痉瑕侀噰闆嗙殑闄㈠尯
-                SysConfig cf = new SysConfig();
-                cf.setConfigKey("sltd.gather.campusid");
-                cf.setOrgid("20001001");
-                List<SysConfig> sysConfigcampusids = configService.selectConfigList(cf);
-
-                List<Long> campusidList = new ArrayList<>();
-                if (CollectionUtils.isNotEmpty(sysConfigcampusids)) {
-                    String[] split = sysConfigcampusids.get(0).getConfigValue().split(",");
-                    campusidList = Arrays.stream(split).map(Long::valueOf).collect(Collectors.toList());
-                } else {
-                    log.error("SysConfig涓殑闄㈠尯ID涓虹┖锛�");
-                    return;
-                }
-
-                // 鐪佺珛鍚屽痉鏁版嵁閲囬泦
-                log.info("--campusidList鐨勫�间负锛歿}", campusidList);
-                for (Long cid : campusidList) {
-                    String nowTime = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                    ServiceSLTDInhospReqVO serviceSLTDInhospReqVO = new ServiceSLTDInhospReqVO();
-                    serviceSLTDInhospReqVO.setOrgId("20001001");
-                    serviceSLTDInhospReqVO.setCampusId(cid);
-                    serviceSLTDInhospReqVO.setEncounterTimeStart(nowTime);
-                    serviceSLTDInhospReqVO.setEncounterTimeEnd(nowTime);
-
-                    // 闂ㄦ�ヨ瘖鍒嗛〉閲囬泦锛氭瘡椤�40鏉★紝鐩村埌鏃犳暟鎹负姝�(鍗楀崕闄勪竴鐨勫厛涓嶉噰闂ㄦ�ヨ瘖鏁版嵁)
-                    if (active.trim().equals("sltd")) {
-                        log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滈棬鎬ヨ瘖鈥濆紑濮嬪垎椤甸噰闆嗘暟鎹紝闄㈠尯锛歿}", cid);
-                        serviceSLTDInhospReqVO.setStartHeadTime(null);
-                        serviceSLTDInhospReqVO.setStartTailTime(null);
-                        //鏌ヨ褰撳ぉ鐨勬暟鎹�
-                        serviceSLTDInhospReqVO.setEncounterTimeEnd(tomorrowdayZero.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
-                        serviceSLTDInhospReqVO.setEncounterTimeStart(todayZero.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
-                        serviceSLTDInhospReqVO.setStatusList(null);
-                        List<String> list1 = new ArrayList<>();
-                        list1.add("FH0108.01");
-                        list1.add("FH0108.03");
-                        serviceSLTDInhospReqVO.setHealthcareRecordTypeList(list1);
-                        //浠庣紦瀛橀噷鑾峰彇璧峰椤碉紙闆剁偣鍓�10鍒嗛挓鍐呯敤鏄ㄥぉ鐨勬棩鏈燂紝閬垮厤璺ㄥぉ婕忛噰锛�
-                        LocalDateTime now = LocalDateTime.now();
-                        String mzCacheDate = (now.getHour() == 0 && now.getMinute() < 10) ? now.minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) : now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                        Long outpPage = redisCache.getCacheObject("mzCurrent" + cid + mzCacheDate);
-                        if (outpPage == null) outpPage = 1L;
-                        //閭h竟鏆傛椂鍙兘璁剧疆40
-                        final long OUTP_PAGE_SIZE = 500L;
-                        while (true) {
-                            serviceSLTDInhospReqVO.setCurrent(outpPage);
-                            serviceSLTDInhospReqVO.setSize(OUTP_PAGE_SIZE);
-                            log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滈棬鎬ヨ瘖鈥濋噰闆嗙{}椤垫暟鎹紝闄㈠尯锛歿}", outpPage, cid);
-                            List<ServiceSLTDInhospResDTO> outpResult = serviceSLTDHealthcareRecordService.queryHealthcareRecordList(serviceSLTDInhospReqVO);
-                            if (CollectionUtils.isEmpty(outpResult)) {
-                                log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滈棬鎬ヨ瘖鈥濈{}椤垫棤鏁版嵁锛岄噰闆嗙粨鏉燂紝闄㈠尯锛歿}", outpPage, cid);
-                                break;
-                            }
-                            log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滈棬鎬ヨ瘖鈥濈{}椤甸噰闆唟}鏉★紝闄㈠尯锛歿}", outpPage, outpResult.size(), cid);
-                            if (outpResult.size() < OUTP_PAGE_SIZE) {
-                                //璁剧疆涓�涓紦瀛橈紝鐢ㄦ潵瀛樺湪涓嬫鐨勮捣濮嬮〉
-                                redisCache.setCacheObject("mzCurrent" + cid + mzCacheDate, outpPage, 24, TimeUnit.HOURS);
-                                log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滈棬鎬ヨ瘖鈥濈殑缂撳瓨key:{}涓嬫鐨勮捣濮嬮〉{}锛岄櫌鍖猴細{}", "mzCurrent" + cid + mzCacheDate, outpPage, cid);
-                                break;
-                            }
-                            outpPage++;
-                        }
-                        // 娓呴櫎鍒嗛〉鍙傛暟锛岄伩鍏嶅奖鍝嶅悗缁嚭鍏ラ櫌鏌ヨ
-                        serviceSLTDInhospReqVO.setCurrent(null);
-                        serviceSLTDInhospReqVO.setSize(null);
-                        log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滈棬鎬ヨ瘖鈥濆垎椤甸噰闆嗗畬鎴愶紝闄㈠尯锛歿}", cid);
-                    }
-                }
+                collectOutpatientDaily(cid, todayZeroStr, pageSize, maxPage, deadline);
             } catch (Exception e) {
-                log.error("銆恉ealHisData銆戠渷绔嬪悓寰锋暟鎹棬鎬ヨ瘖閲囬泦寮傚父", e);
+                log.error("銆恉ealHisDataMZ銆戦棬鎬ヨ瘖閲囬泦寮傚父锛岄櫌鍖猴細{}锛屾柇鐐瑰凡淇濈暀锛屼笅涓�杞粠鏂偣缁х画", cid, e);
+            } finally {
+                redisCache.deleteObject(lockKey);
             }
         }
+        log.info("銆恉ealHisDataMZ銆戦棬鎬ヨ瘖閲囬泦鏈疆缁撴潫锛岃�楁椂锛歿}绉�",
+                java.time.Duration.between(now, LocalDateTime.now()).getSeconds());
+    }
+
+    /**
+     * 閲囬泦鏌愪釜闄㈠尯锛氬厛琛ヤ竴娆℃�у洖婧棩鏈燂紝鍐嶅仛鏄ㄥぉ鐨勬敹灏鹃噰闆嗭紝鏈�鍚庢暣杞埛鏂颁粖澶�
+     */
+    private void collectOutpatientDaily(Long cid, String backfillParam, long pageSize, long maxPage,
+                                        LocalDateTime deadline) {
+        String cursorKey = "mzDayCursor:" + cid;
+        MzDayCursor cursor = loadMzDayCursor(cursorKey);
+        LocalDate today = LocalDate.now();
+        LocalDate yesterday = today.minusDays(1);
+
+        // 鎵嬪伐鍏ュ弬鎸囧畾鐨勪竴娆℃�у洖婧細鍚屼竴涓棩鏈熷彧琛ヤ竴娆★紝閬垮厤瀹氭椂浠诲姟姣忚疆閲嶅琛�
+        LocalDateTime backfillTime = parseMzStartTime(backfillParam);
+        if (backfillTime != null) {
+            LocalDate backfillDay = backfillTime.toLocalDate();
+            if (backfillDay.toString().equals(cursor.backfillDone)) {
+                log.info("銆恉ealHisDataMZ銆戝叆鍙傛棩鏈� {} 宸插畬鎴愬洖婧紝璺宠繃锛岄櫌鍖猴細{}", backfillDay, cid);
+            } else if (backfillDay.equals(today)) {
+                // 鍏ュ弬灏辨槸浠婂ぉ锛屼氦缁欎笅闈㈢殑鏁磋疆鍒锋柊澶勭悊鍗冲彲
+                cursor.backfillDone = backfillDay.toString();
+                saveMzDayCursor(cursorKey, cursor);
+            } else {
+                cursor.backfillDay = backfillDay.toString();
+                cursor.backfillPage = 1L;
+                saveMzDayCursor(cursorKey, cursor);
+                log.info("銆恉ealHisDataMZ銆戝緟鍥炴函鏃ユ湡锛歿}锛岄櫌鍖猴細{}", backfillDay, cid);
+            }
+        }
+
+        // 1) 涓�娆℃�у洖婧�
+        if (cursor.backfillDay != null) {
+            LocalDate day = LocalDate.parse(cursor.backfillDay);
+            MzGatherStatusEnum status = runDayPass(cid, cursorKey, cursor, MzGatherSlotEnum.BACKFILL, day,
+                    cursor.backfillPage, pageSize, maxPage, deadline);
+            if (status != MzGatherStatusEnum.DONE) {
+                log.warn("銆恉ealHisDataMZ銆戝洖婧棩鏈� {} 鏈疆鏈畬鎴愶紙{}锛夛紝鏂偣宸蹭繚鐣欙紝闄㈠尯锛歿}", day, status.getDesc(), cid);
+                return;
+            }
+            cursor.backfillDone = cursor.backfillDay;
+            cursor.backfillDay = null;
+            cursor.backfillPage = 1L;
+            saveMzDayCursor(cursorKey, cursor);
+        }
+
+        // 2) 鏄ㄥぉ鏀跺熬閲囬泦锛氭瘡澶╀竴娆★紝鍏滀綇 23:xx 涔嬪悗鎵嶅啓杩� HIS 鐨勮褰曞拰璺ㄩ浂鐐圭殑鏁版嵁
+        if (!yesterday.toString().equals(cursor.finalDay)) {
+            MzGatherStatusEnum status = runDayPass(cid, cursorKey, cursor, MzGatherSlotEnum.FINAL, yesterday,
+                    cursor.finalPage, pageSize, maxPage, deadline);
+            if (status != MzGatherStatusEnum.DONE) {
+                log.warn("銆恉ealHisDataMZ銆戞槰鏃ユ敹灏鹃噰闆� {} 鏈疆鏈畬鎴愶紙{}锛夛紝鏂偣宸蹭繚鐣欙紝闄㈠尯锛歿}", yesterday, status.getDesc(), cid);
+                return;
+            }
+            cursor.finalDay = yesterday.toString();
+            cursor.finalPage = 1L;
+            saveMzDayCursor(cursorKey, cursor);
+        }
+
+        // 3) 浠婂ぉ鐨勬暣杞埛鏂�
+        if (!today.toString().equals(cursor.day)) {
+            cursor.day = today.toString();
+            cursor.page = 1L;
+            saveMzDayCursor(cursorKey, cursor);
+        }
+        MzGatherStatusEnum status = runDayPass(cid, cursorKey, cursor, MzGatherSlotEnum.TODAY, today,
+                cursor.page, pageSize, maxPage, deadline);
+        if (status == MzGatherStatusEnum.DONE) {
+            // 鏁磋疆鍒锋柊瀹屾垚锛岄〉鐮佸綊浣嶏紝涓嬩竴杞噸鏂颁粠绗竴椤垫暣杞埛鏂�
+            cursor.page = 1L;
+            saveMzDayCursor(cursorKey, cursor);
+            log.info("銆恉ealHisDataMZ銆憑} 闂ㄦ�ヨ瘖鏁磋疆鍒锋柊瀹屾垚锛岄櫌鍖猴細{}", today, cid);
+        }
+    }
+
+    /**
+     * 鍏ㄩ噺閲囬泦鏌愪竴澶╋紙鍒嗛〉鐩村埌閲囧畬锛夛紝姣忛噰瀹屼竴椤电珛鍗宠惤涓�娆℃柇鐐�
+     *
+     * @param slot 鏂偣妲戒綅锛堜粖澶╂暣杞埛鏂� / 鏄ㄦ棩鏀跺熬 / 鎵嬪伐鍥炴函锛夛紝鍐冲畾涓柇椤电爜璁板埌鍝釜瀛楁
+     * @return {@link MzGatherStatusEnum} 閲囬泦瀹屾垚 / 棰勭畻鐢ㄥ敖 / 鎺ュ彛杩炵画澶辫触鎻愬墠缁撴潫
+     */
+    private MzGatherStatusEnum runDayPass(Long cid, String cursorKey, MzDayCursor cursor, MzGatherSlotEnum slot,
+                                          LocalDate day, long startPage, long pageSize, long maxPage,
+                                          LocalDateTime deadline) {
+        String startStr = day.format(MzGatherConstant.DAY_FMT);
+        String endStr = day.plusDays(1).format(MzGatherConstant.DAY_FMT);
+
+        ServiceSLTDInhospReqVO reqVO = new ServiceSLTDInhospReqVO();
+        reqVO.setOrgId(MzGatherConstant.ORG_ID);
+        reqVO.setCampusId(cid);
+        reqVO.setStartHeadTime(null);
+        reqVO.setStartTailTime(null);
+        reqVO.setStatusList(null);
+        // 鎺ュ彛鍙敮鎸佹寜澶╂煡锛岃捣姝㈤兘浼犳棩鏈�
+        reqVO.setEncounterTimeStart(startStr);
+        reqVO.setEncounterTimeEnd(endStr);
+        List<String> typeList = new ArrayList<>();
+        typeList.add("FH0108.01"); // 闂ㄨ瘖
+        typeList.add("FH0108.03"); // 鎬ヨ瘖
+        reqVO.setHealthcareRecordTypeList(typeList);
+        reqVO.setSize(pageSize);
+
+        long page = startPage < 1L ? 1L : startPage;
+        long total = 0L;
+        long pageCount = 0L;
+        // 鎺ュ彛灞傚け璐ヨ烦杩囩殑椤垫暟銆佺涓�涓け璐ラ〉銆佽繛缁け璐ラ〉鏁�
+        long skippedPages = 0L;
+        long firstFailPage = -1L;
+        int consecutiveFail = 0;
+        while (true) {
+            if (LocalDateTime.now().isAfter(deadline)) {
+                // 鏈疆鏈夎烦杩囩殑椤垫椂锛屾柇鐐瑰洖鍒扮涓�涓け璐ラ〉锛屼繚璇佷笅涓�杞厛鎶婅繖浜涢〉琛ュ洖鏉�
+                long resumePage = (skippedPages > 0 && firstFailPage > 0) ? firstFailPage : page;
+                saveMzDayPage(cursorKey, cursor, slot, resumePage);
+                log.warn("銆恉ealHisDataMZ銆戞湰杞椂闂撮绠楃敤灏斤紝{} 鏈疆宸查噰{}椤祘}鏉}锛屼笅娆′粠绗瑊}椤电户缁紝闄㈠尯锛歿}",
+                        day, pageCount, total, skippedLog(skippedPages), resumePage, cid);
+                return MzGatherStatusEnum.BUDGET_UP;
+            }
+            reqVO.setCurrent(page);
+            log.info("銆恉ealHisDataMZ銆戦噰闆嗛棬鎬ヨ瘖鏁版嵁锛岄櫌鍖猴細{}锛屾棩鏈燂細{}锛岀{}椤�", cid, day, page);
+
+            List<ServiceSLTDInhospResDTO> pageData = null;
+            Exception lastError = null;
+            for (int attempt = 1; attempt <= MzGatherConstant.PAGE_RETRY_TIMES; attempt++) {
+                try {
+                    pageData = serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
+                    lastError = null;
+                    break;
+                } catch (Exception e) {
+                    lastError = e;
+                    log.error("銆恉ealHisDataMZ銆戦棬鎬ヨ瘖绗瑊}椤电{}娆¢噰闆嗗け璐ワ紝闄㈠尯锛歿}锛屾棩鏈燂細{}", page, attempt, cid, day, e);
+                    if (attempt < MzGatherConstant.PAGE_RETRY_TIMES) {
+                        try {
+                            Thread.sleep(MzGatherConstant.PAGE_RETRY_SLEEP_MS);
+                        } catch (InterruptedException ie) {
+                            Thread.currentThread().interrupt();
+                            break;
+                        }
+                    }
+                }
+            }
+            if (lastError != null) {
+                // 鎺ュ彛灞傚け璐ワ紙缃戠粶瓒呮椂 / 鏉ユ湭鏉ヨ繑鍥為潪200锛夋病鏈夋暟鎹彲浠ヨ惤琛紝鍙啓 error 鏃ュ織锛岀劧鍚庤烦杩囪椤电户缁線鍚庨噰锛屼笉闃绘柇杩涘害銆�
+                // 姣忚疆閮芥槸鏁村ぉ浠庡ご鍏ㄩ噺鍒锋柊锛岃璺宠繃鐨勯〉涓嬩竴杞繀鐒堕噸鏂伴噰鍒帮紝鎵�浠ヤ笉浼氭紡鏁版嵁銆�
+                skippedPages++;
+                if (firstFailPage < 0) {
+                    firstFailPage = page;
+                }
+                consecutiveFail++;
+                log.error("銆恉ealHisDataMZ銆戞帴鍙e眰閲囬泦澶辫触锛屽凡璁� error 鏃ュ織骞惰烦杩囪椤碉紝鏈疆缁х画寰�鍚庨噰锛�"
+                                + "闄㈠尯锛歿}锛屾棩鏈燂細{}锛岀{}椤碉紝鎺ュ彛鍏ュ弬锛歿}锛屽紓甯革細{}",
+                        cid, day, page, new Gson().toJson(reqVO), lastError.getMessage(), lastError);
+                if (consecutiveFail >= MzGatherConstant.MAX_CONSECUTIVE_PAGE_FAIL) {
+                    // 杩炵画澶氶〉鎺ュ彛澶辫触锛屽垽瀹氭潵鏈潵鎺ュ彛鏁翠綋涓嶅彲鐢紝鏈疆鎻愬墠缁撴潫锛堜笉鍐嶇┖杞悗闈㈠嚑鍗侀〉锛夛紝鏂偣鐣欏湪绗竴涓け璐ラ〉
+                    log.error("銆恉ealHisDataMZ銆戣繛缁瓄}椤垫帴鍙eけ璐ワ紝鍒ゅ畾鏉ユ湭鏉ユ帴鍙d笉鍙敤锛屾湰杞彁鍓嶇粨鏉燂紱闄㈠尯锛歿}锛屾棩鏈燂細{}锛屾柇鐐逛繚鐣欏湪绗瑊}椤�",
+                            consecutiveFail, cid, day, firstFailPage);
+                    saveMzDayPage(cursorKey, cursor, slot, firstFailPage);
+                    return MzGatherStatusEnum.FAILED;
+                }
+                page++;
+                continue;
+            }
+            consecutiveFail = 0;
+
+            if (CollectionUtils.isEmpty(pageData)) {
+                log.info("銆恉ealHisDataMZ銆憑} 绗瑊}椤垫棤鏁版嵁锛岄噰闆嗙粨鏉燂紝闄㈠尯锛歿}锛屾湰杞畕}椤靛叡{}鏉}",
+                        day, page, cid, pageCount, total, skippedLog(skippedPages));
+                return MzGatherStatusEnum.DONE;
+            }
+            pageCount++;
+            total += pageData.size();
+            log.info("銆恉ealHisDataMZ銆憑} 绗瑊}椤甸噰闆唟}鏉★紝闄㈠尯锛歿}", day, page, pageData.size(), cid);
+            if (pageData.size() < pageSize) {
+                log.info("銆恉ealHisDataMZ銆憑} 閲囬泦缁撴潫锛岄櫌鍖猴細{}锛屾湰杞畕}椤靛叡{}鏉}", day, cid, pageCount, total, skippedLog(skippedPages));
+                return MzGatherStatusEnum.DONE;
+            }
+            page++;
+            if (page > maxPage) {
+                log.error("銆恉ealHisDataMZ銆憑} 宸茬炕鍒扮{}椤碉紝瓒呰繃鍗曟棩涓婇檺{}椤碉紝鎸夐噰瀹屽鐞嗭紝闄㈠尯锛歿}", day, page, maxPage, cid);
+                return MzGatherStatusEnum.DONE;
+            }
+            // 姣忛噰瀹屼竴椤电珛鍗宠惤鏂偣锛氳繘绋嬭閲嶅惎/寮烘潃涔熻兘浠庤繖涓�椤电户缁紝涓嶄粠澶撮噸鎵紝涔熶笉浼氭紡
+            saveMzDayPage(cursorKey, cursor, slot, page);
+        }
+    }
+
+    /** 鎸夋Ы浣嶄繚瀛樹腑鏂〉鐮� */
+    private void saveMzDayPage(String cursorKey, MzDayCursor cursor, MzGatherSlotEnum slot, long page) {
+        if (slot == MzGatherSlotEnum.FINAL) {
+            cursor.finalPage = page;
+        } else if (slot == MzGatherSlotEnum.BACKFILL) {
+            cursor.backfillPage = page;
+        } else {
+            cursor.page = page;
+        }
+        saveMzDayCursor(cursorKey, cursor);
+    }
+
+    /** 鏃ュ織閲屾彁绀烘帴鍙e眰澶辫触璺宠繃浜嗗嚑椤碉紙涓嬩竴杞暣杞埛鏂颁細閲嶆柊閲囧埌锛� */
+    private String skippedLog(long skippedPages) {
+        return skippedPages > 0L ? "锛屾帴鍙eけ璐ヨ烦杩�" + skippedPages + "椤碉紙涓嬩竴杞暣杞埛鏂颁細閲嶆柊閲囧埌锛�" : "";
+    }
+
+    /** 璇诲彇 sys_config 閲岀殑闂ㄦ�ヨ瘖閲囬泦鍙傛暟锛堟満鏋� orgid=20001001锛夛紝鍙栦笉鍒版垨瓒呰寖鍥存椂鐢ㄦ灇涓鹃噷鐨勯粯璁ゅ�� */
+    private long getMzConfigLong(MzGatherParamEnum param) {
+        try {
+            SysConfig config = new SysConfig();
+            config.setConfigKey(param.getKey());
+            config.setOrgid(MzGatherConstant.ORG_ID);
+            List<SysConfig> configs = configService.selectConfigList(config);
+            if (CollectionUtils.isNotEmpty(configs) && StringUtils.isNotBlank(configs.get(0).getConfigValue())) {
+                long value = Long.parseLong(configs.get(0).getConfigValue().trim());
+                if (value >= param.getMin() && value <= param.getMax()) {
+                    return value;
+                }
+                log.warn("銆恉ealHisDataMZ銆戦厤缃畕}鐨勫�納}瓒呭嚭鑼冨洿[{},{}]锛屼娇鐢ㄩ粯璁ゅ�納}",
+                        param.getKey(), value, param.getMin(), param.getMax(), param.getDefaultValue());
+            }
+        } catch (Exception e) {
+            log.warn("銆恉ealHisDataMZ銆戣鍙栭厤缃畕}澶辫触锛屼娇鐢ㄩ粯璁ゅ�納}", param.getKey(), param.getDefaultValue(), e);
+        }
+        return param.getDefaultValue();
+    }
+
+    /** 瑙f瀽浠诲姟鍏ュ弬锛堣涓�娆℃�у洖婧殑鏃ユ湡锛夛紝鏀寔 yyyy-MM-dd HH:mm:ss 涓� yyyy-MM-dd */
+    private LocalDateTime parseMzStartTime(String text) {
+        LocalDateTime time = parseMzTimeQuiet(text);
+        if (time == null && StringUtils.isNotBlank(text)) {
+            log.warn("銆恉ealHisDataMZ銆戝叆鍙� {} 鏃犳硶瑙f瀽涓烘棩鏈燂紝鎸夋湭鎸囧畾澶勭悊", text);
+        }
+        return time;
+    }
+
+    /** 闈欓粯瑙f瀽鏃ユ湡锛屾敮鎸� yyyy-MM-dd HH:mm:ss 涓� yyyy-MM-dd锛屾牸寮忎笉绗﹁繑鍥� null锛堜笉鍒锋棩蹇楋級 */
+    private LocalDateTime parseMzTimeQuiet(String text) {
+        if (StringUtils.isBlank(text)) {
+            return null;
+        }
+        String value = text.trim();
+        try {
+            return LocalDateTime.parse(value, MzGatherConstant.MINUTE_FMT);
+        } catch (Exception ignore) {
+            // 鍏煎鍙紶鏃ユ湡鐨勬儏鍐碉紝钀藉埌涓嬮潰鎸夋棩鏈熻В鏋�
+        }
+        try {
+            return LocalDate.parse(value).atStartOfDay();
+        } catch (Exception ignore) {
+            return null;
+        }
+    }
+
+    /** 淇濆瓨闂ㄦ�ヨ瘖閲囬泦鏂偣锛堝悇杞涓柇鐨勯〉鐮侊級 */
+    private void saveMzDayCursor(String cursorKey, MzDayCursor cursor) {
+        JSONObject json = new JSONObject();
+        json.put("day", cursor.day);
+        json.put("page", cursor.page);
+        json.put("finalDay", cursor.finalDay);
+        json.put("finalPage", cursor.finalPage);
+        json.put("backfillDay", cursor.backfillDay);
+        json.put("backfillPage", cursor.backfillPage);
+        json.put("backfillDone", cursor.backfillDone);
+        json.put("updateTime", MzGatherConstant.MINUTE_FMT.format(LocalDateTime.now().withNano(0)));
+        redisCache.setCacheObject(cursorKey, json.toJSONString(), MzGatherConstant.CACHE_TTL_HOURS, TimeUnit.HOURS);
+    }
+
+    /** 璇诲彇闂ㄦ�ヨ瘖閲囬泦鏂偣锛岃涓嶅埌鎴栬В鏋愬け璐ユ椂杩斿洖绌烘柇鐐癸紙绛変环浜庝粠绗竴椤靛紑濮嬫暣杞埛鏂帮級 */
+    private MzDayCursor loadMzDayCursor(String cursorKey) {
+        MzDayCursor cursor = new MzDayCursor();
+        try {
+            String json = redisCache.getCacheObject(cursorKey);
+            if (StringUtils.isBlank(json)) {
+                return cursor;
+            }
+            JSONObject obj = JSONObject.parseObject(json);
+            cursor.day = obj.getString("day");
+            cursor.page = obj.getLongValue("page");
+            cursor.finalDay = obj.getString("finalDay");
+            cursor.finalPage = obj.getLongValue("finalPage");
+            cursor.backfillDay = obj.getString("backfillDay");
+            cursor.backfillPage = obj.getLongValue("backfillPage");
+            cursor.backfillDone = obj.getString("backfillDone");
+            if (cursor.page < 1L) {
+                cursor.page = 1L;
+            }
+            if (cursor.finalPage < 1L) {
+                cursor.finalPage = 1L;
+            }
+            if (cursor.backfillPage < 1L) {
+                cursor.backfillPage = 1L;
+            }
+            return cursor;
+        } catch (Exception e) {
+            log.warn("銆恉ealHisDataMZ銆戣鍙栨柇鐐箋}澶辫触锛屾寜绌烘柇鐐瑰鐞�", cursorKey, e);
+            return new MzDayCursor();
+        }
+    }
+
+    /**
+     * 闂ㄦ�ヨ瘖閲囬泦鏂偣锛氭瘡澶╀竴杞叏閲忓埛鏂帮紝杩欓噷鍒嗗埆璁板綍涓変釜杞涓柇鍦ㄧ鍑犻〉
+     * 锛堥〉鐮佷负 1 琛ㄧず璇ヨ疆娆′笅涓�杞粠绗竴椤垫暣杞紑濮嬶級
+     */
+    private static class MzDayCursor {
+        /** 浠婂ぉ鐨勬暣杞埛鏂� */
+        private String day;
+        private long page = 1L;
+        /** 鏄ㄥぉ鐨勬敹灏鹃噰闆� */
+        private String finalDay;
+        private long finalPage = 1L;
+        /** 寰呭仛鐨勪竴娆℃�у洖婧� */
+        private String backfillDay;
+        private long backfillPage = 1L;
+        /** 宸茬粡琛ヨ繃鐨勫洖婧棩鏈燂紝閬垮厤瀹氭椂浠诲姟姣忚疆閲嶅琛ュ悓涓�澶� */
+        private String backfillDone;
     }
 
     /**
@@ -596,13 +1044,31 @@
         ServiceSLTDInhospReqVO serviceSLTDInhospReqVO = new ServiceSLTDInhospReqVO();
         serviceSLTDInhospReqVO.setOrgId("20001001");
         Long outpPage = 1L;
+        int totalCount = 0;  // 缁熻鎬诲叡閲囬泦鐨勮嵂鍝佹暟閲�
+
         while (true) {
             serviceSLTDInhospReqVO.setCurrent(outpPage);
             serviceSLTDInhospReqVO.setSize(OUTP_PAGE_SIZE);
-            log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滆嵂鍝佹暟鎹�濋噰闆嗙{}椤垫暟鎹�", outpPage);
-           Boolean b = serviceSLTDHealthcareRecordService.queryMedicationItemList(serviceSLTDInhospReqVO);
-            log.info("銆恉ealHisData銆戠渷绔嬪悓寰封�滆嵂鍝佹暟鎹�濋噰闆嗙粨鏋滐細{}", b);
-            outpPage++;
+            log.info("銆恉ealHisData銆戠渷绔嬪悓寰穃"鑽搧鏁版嵁\"閲囬泦绗瑊}椤垫暟鎹�", outpPage);
+
+            try {
+                Integer fetchedCount = serviceSLTDHealthcareRecordService.queryMedicationItemList(serviceSLTDInhospReqVO);
+                log.info("銆恉ealHisData銆戠渷绔嬪悓寰穃"鑽搧鏁版嵁\"绗瑊}椤甸噰闆嗗埌{}鏉¤褰�", outpPage, fetchedCount);
+
+                totalCount += fetchedCount != null ? fetchedCount : 0;
+
+                // 濡傛灉杩斿洖鐨勬暟鎹噺灏忎簬 pageSize锛岃鏄庡凡缁忔槸鏈�鍚庝竴椤典簡锛岄��鍑哄惊鐜�
+                if (fetchedCount == null || fetchedCount < OUTP_PAGE_SIZE) {
+                    log.info("銆恉ealHisData銆戠渷绔嬪悓寰穃"鑽搧鏁版嵁\"閲囬泦瀹屾垚锛屾�婚〉鏁�:{}, 鎬昏{}鏉¤褰�", outpPage, totalCount);
+                    break;
+                }
+
+                outpPage++;
+            } catch (Exception e) {
+                log.error("銆恉ealHisData銆戠渷绔嬪悓寰穃"鑽搧鏁版嵁\"绗瑊}椤甸噰闆嗗け璐�", outpPage, e);
+                // 鍑洪敊鏃朵篃鍙互閫夋嫨閫�鍑烘垨缁х画锛岃繖閲岄�夋嫨閫�鍑洪伩鍏嶆棤闄愰噸璇�
+                break;
+            }
         }
     }
 
@@ -647,7 +1113,7 @@
     public void dealHisData2() {
         //灏嗘偅鑰呬俊鎭�佸嚭鍏ラ櫌鏁版嵁鍏ㄩ儴閲囬泦
         // 鎸囧畾鐨勫紑濮嬫棩鏈�
-        LocalDate endDate = LocalDate.of(2025, 3, 3);
+        LocalDate endDate = LocalDate.of(2026, 7, 6);
         // 褰撳墠鏃ユ湡
         LocalDate currentDate = LocalDate.now();
         // 瀹氫箟鏃ユ湡鏍煎紡
@@ -678,17 +1144,17 @@
     }
 
     /**
-     * 澶勭悊鎮h�呬俊鎭紝杩涘叆瀛愪换鍔¤〃
+     * 澶勭悊鎮h�呬俊鎭紝杩涘叆瀛愪换鍔¤〃(浠诲姟缁�)
      */
-    public void dealOutHospInfoByDimension() {
+    public void dealOutHospInfoBySchedule() {
         String config = configService.selectConfigByKey("visit.early.day");
         if (port.equals("8095")) {
             //鍑洪櫌琛�
-            iPatMedInhospService.dealOutHospInfoByDimension(config);
+            iPatMedInhospService.dealOutHospInfoBySchedule(config);
             //闂ㄨ瘖琛�(鏂板崕鐨勬殏鏃朵笉鍋氶棬璇婇殢璁�)
-            if (!active.equals("xh")) {
-                //iPatMedOuthospService.dealOutpatientInfo();
-            }
+//            if (!active.equals("xh")) {
+//                //iPatMedOuthospService.dealOutpatientInfo();
+//            }
         }
     }
 
@@ -759,91 +1225,16 @@
      * 澶勭悊琛ュ伩浠诲姟
      */
     public void compensateTask() {
-        //鑾峰彇鍒皊endstate=3 骞朵笖 visit_time涓哄皬浜庣瓑浜庝粖澶╃殑subtask
+        //鑾峰彇鍒皊endstate=3銆�1 骞朵笖 visit_time涓哄皬浜庣瓑浜庝粖澶╃殑subtask
+        List<Long> list = Arrays.asList(3L, 1L);
         ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
-        serviceSubtaskVO.setSendstate(3L);
-        serviceSubtaskVO.setVisitTime(new Date());
-        List<ServiceSubtask> serviceSubtaskList = serviceSubtaskMapper.getCompensateServiceSubtaskList(serviceSubtaskVO);
-        for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
-            //鏍规嵁褰撳墠鐨勬墽琛屾柟寮忥紝鑾峰彇涓嬩竴绉嶆墽琛屾柟寮�
-            ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
-            serviceSubtaskPreachform.setTaskid(serviceSubtask.getTaskid());
-            serviceSubtaskPreachform.setSubid(serviceSubtask.getId());
-            serviceSubtaskPreachform.setOrgid(serviceSubtask.getOrgid());
-            List<ServiceSubtaskPreachform> serviceSubtaskPreachforms = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(serviceSubtaskPreachform);
-            //鑾峰彇褰撳墠鎵ц鏂瑰紡鐨勫簭鍙�
-            Optional<Long> currentSort = serviceSubtaskPreachforms.stream().filter(item -> serviceSubtask.getCurrentPreachform().equals(item.getPreachform())).map(ServiceSubtaskPreachform::getSort).findFirst();
-            Optional<Long> id = serviceSubtaskPreachforms.stream().filter(item -> serviceSubtask.getCurrentPreachform().equals(item.getPreachform())).map(ServiceSubtaskPreachform::getId).findFirst();
-            if (currentSort.isPresent()) {
-                //1鍏堟鏌ヤ竴涓嬶紝鏄笉鏄湁鎵ц鐘舵�佹槸瀹屾垚鐨勶紙鎬曚箣鍓嶅凡缁忔湁瀹岀殑浜嗭紝娌℃湁灏唖ervuce_subtask鐨勭姸鎬佹敼鎴愬姛锛岃繖閲屽啀妫�鏌ヤ竴涓嬶級
-                boolean finishState = serviceSubtaskPreachforms.stream().allMatch(item -> item.getSendstate().equals("9"));
-                if (finishState) {
-                    serviceSubtask.setSendstate(6L);
-                    serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
-                    continue;
-                }
-
-                //2鍒ゆ柇涓�涓嬶紝褰撳墠鐨剆ort鏄笉鏄瓑浜庨渶瑕佹墽琛岀殑鎬讳釜鏁帮紝濡傛灉绛変簬鐨勮瘽锛岃鏄庢槸鏈�鍚庝竴涓紝鐩存帴灏唖ervuce_subtask鐨勭姸鎬佹敼鎴�5锛屾墽琛屽け璐ュ氨琛屼簡
-                Long cs = currentSort.get();
-                if (cs.equals(serviceSubtaskPreachforms.size())) {
-                    serviceSubtask.setSendstate(7L);
-                    serviceSubtask.setRemark("澶勭悊琛ュ伩浠诲姟,褰撳墠澶勭悊鏈�鍚庤ˉ鍋匡紝鍏ㄩ儴鎵ц澶辫触锛堣秴鏃讹級");
-
-                    serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
-                    //淇敼鍙戦�佹柟寮忕殑鐘舵�佷负澶辫触
-                    serviceSubtaskPreachform.setSendstate("5");
-                    serviceSubtaskPreachform.setId(id.get());
-
-                    serviceSubtaskPreachformMapper.updateServiceSubtaskPreachform(serviceSubtaskPreachform);
-                    continue;
-                }
-
-                //3.涓嶆槸鏈�鍚庝竴涓紝鑾峰彇鍒颁笅涓�涓墽琛屾柟寮�(鍥犱负閮芥槸鍦ㄤ粖澶╂墽琛岋紝閭e氨鐩存帴鍙戝嚭鍘诲氨瀹屼簡)
-                sfHandlle(serviceSubtask);
-            }
-        }
-    }
-
-    /**
-     * 闀挎湡浠诲姟鍙戦��
-     */
-    public void longTaskSendTest(Long subId) {
-        //鑾峰彇浠诲姟淇℃伅
-        ServiceTask st = new ServiceTask();
-        st.setDelFlag("0");
-        st.setLongTask(1);
-        List<ServiceTask> serviceTasks = serviceTaskMapper.selectServiceTaskList(st);
-        log.info("銆恖ongTaskSend銆戣幏鍙栧埌{}涓暱鏈熶换鍔�", serviceTasks.size());
-        for (ServiceTask serviceTask : serviceTasks) {
-            CommonTaskcallMQ commonTaskcallMQ = new CommonTaskcallMQ();
-            commonTaskcallMQ.setTaskid(serviceTask.getTaskid());
-            commonTaskcallMQ.setPreachform(serviceTask.getPreachform());
-            commonTaskcallMQ.setSendType("2");
-
-            //閫氳繃浠诲姟ID鎷垮埌鎮h�呬俊鎭�,骞朵笖闅忚鏃堕棿寰楁槸浠婂ぉ涔嬪墠鐨�
-            ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
-            serviceSubtaskVO.setTaskid(commonTaskcallMQ.getTaskid());
-            serviceSubtaskVO.setSendstate(2L);
-            serviceSubtaskVO.setIsVisitAgain(1);
-            serviceSubtaskVO.setSubId(subId);
+        List<ServiceSubtask> serviceSubtaskList = new ArrayList<>();
+        for (Long sendstate : list) {
+            serviceSubtaskVO.setSendstate(sendstate);
             serviceSubtaskVO.setVisitTime(new Date());
-            List<ServiceSubtask> selectServiceSubtaskList = serviceSubtaskMapper.queryServiceSubtaskList(serviceSubtaskVO);
-            for (ServiceSubtask serviceSubtask : selectServiceSubtaskList) {
-                sfHandlle(serviceSubtask);
-            }
+            List<ServiceSubtask> compensateServiceSubtaskList = serviceSubtaskMapper.getCompensateServiceSubtaskList(serviceSubtaskVO);
+            serviceSubtaskList.addAll(compensateServiceSubtaskList);
         }
-    }
-
-    /**
-     * 澶勭悊琛ュ伩浠诲姟
-     */
-    public void compensateTaskTest(Long subId) {
-        //鑾峰彇鍒皊endstate=3 骞朵笖 visit_time涓哄皬浜庣瓑浜庝粖澶╃殑subtask
-        ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
-        serviceSubtaskVO.setSendstate(3L);
-        serviceSubtaskVO.setSubId(subId);
-        serviceSubtaskVO.setVisitTime(new Date());
-        List<ServiceSubtask> serviceSubtaskList = serviceSubtaskMapper.getCompensateServiceSubtaskList(serviceSubtaskVO);
         for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
             //鏍规嵁褰撳墠鐨勬墽琛屾柟寮忥紝鑾峰彇涓嬩竴绉嶆墽琛屾柟寮�
             ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
@@ -865,7 +1256,9 @@
 
                 //2鍒ゆ柇涓�涓嬶紝褰撳墠鐨剆ort鏄笉鏄瓑浜庨渶瑕佹墽琛岀殑鎬讳釜鏁帮紝濡傛灉绛変簬鐨勮瘽锛岃鏄庢槸鏈�鍚庝竴涓紝鐩存帴灏唖ervuce_subtask鐨勭姸鎬佹敼鎴�5锛屾墽琛屽け璐ュ氨琛屼簡
                 Long cs = currentSort.get();
-                if (cs.equals(serviceSubtaskPreachforms.size())) {
+
+                if (cs.equals(serviceSubtaskPreachforms.size())
+                        && isSubtaskDeadline(serviceSubtask, serviceSubtaskPreachforms)) {
                     serviceSubtask.setSendstate(7L);
                     serviceSubtask.setRemark("澶勭悊琛ュ伩浠诲姟,褰撳墠澶勭悊鏈�鍚庤ˉ鍋匡紝鍏ㄩ儴鎵ц澶辫触锛堣秴鏃讹級");
 
@@ -1030,18 +1423,17 @@
                     serviceOutPath.setCreateTime(new Date());
                     serviceOutPath.setOrgid(serviceSubtask.getOrgid());
                     iServiceOutPathService.insertServiceOutPath(serviceOutPath);
+                    String url = "";
                     String format = String.format("%03X", serviceOutPath.getId());
-                    serviceOutPath.setRadix(format);
-                    serviceOutPath.setUpdateTime(new Date());
-                    iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                     //鍏堝垽鏂竴涓嬪彂鐨勬槸涓嶆槸瀹f暀
                     if (!"3".equals(serviceSubtask.getType())) {
                         sendMagParam.setPhone(serviceSubtask.getPhone());
-
-                        sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format);
+                        url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format;
+                        sendMagParam.setUrl(url);
                         //濡傛灉type鏄闊抽殢璁跨殑璇濓紙璇存槑琛ュ伩鍙戦�佹柟寮忎腑鏈夌數璇濋殢璁跨殑鏂瑰紡锛岃繖閲岀殑澶栭摼灏卞湴鍧�鍙兘鐢�/sf锛�
                         if (serviceSubtask.getType().equals("1"))
-                            sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/sf?p=" + format : localIP + "/sf?p=" + format);
+                            url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/sf?p=" + format : localIP + "/sf?p=" + format;
+                            sendMagParam.setUrl(url);
 
 //                        SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("wj.sms.template");
                         SysConfig sysConfig = new SysConfig();
@@ -1061,7 +1453,9 @@
                         HeLibrary heLibrary = heLibraryMapper.selectHeLibraryById(serviceSubtask.getLibtemplateid());
                         if (heLibrary.getHetype().equals("1")) {
                             sendMagParam.setPhone(serviceSubtask.getPhone());
-                            sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/xj?p=" + format : localIP + "/xj?p=" + format);
+                            url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/xj?p=" + format : localIP + "/xj?p=" + format;
+
+                            sendMagParam.setUrl(url);
 
                             SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("xj.sms.template");
                             if (!Objects.isNull(sysConfig)) {
@@ -1079,116 +1473,16 @@
                         }
 
                     }
-                    String isSuccess = null;
+
+                    serviceOutPath.setRadix(format);
+                    serviceOutPath.setUpdateTime(new Date());
+                    serviceOutPath.setUrl(url);
+                    iServiceOutPathService.updateServiceOutPath(serviceOutPath);
+                    //鐭俊鍙戦�侊細鍚勭珯鐐瑰鎺ユ柟寮忓樊寮傝緝澶э紙鎶ユ枃/绛惧悕/token/杩斿洖鍒ゅ畾閮戒笉鍚岋級锛�
+                    //宸叉敹鍙e埌 ruoyi-message 妯″潡锛岃繖閲屽彧璐熻矗缁勮鍏ュ弬骞惰矾鐢�
                     log.info("active鐨勫�间负锛歿}", active);
-                    if (active.equals("xh")) {
-                        Map<String, String> req = new HashMap<>();
-//                        req.put("phone", sendMagParam.getPhone());
-//                        req.put("content", sendMagParam.getContent());
-                        Map<String, String> map2 = new HashMap<String, String>();
-                        map2.put("action", "send");
-                        map2.put("account", xhsmsAccount);
-                        map2.put("password", xhsmsPwd);
-                        map2.put("mobile", sendMagParam.getPhone());
-                        map2.put("content", sendMagParam.getContent());
-                        map2.put("extno", xhsmsjrm);
-                        map2.put("rt", "json");
-                        StringBuilder encodedParams = new StringBuilder();
-
-                        for (Map.Entry<String, String> entry : map2.entrySet()) {
-                            if (encodedParams.length() > 0) {
-                                encodedParams.append("&");
-                            }
-                            // 瀵归敭鍜屽�艰繘琛孶RL缂栫爜
-                            String encodedKey = URLEncoder.encode(entry.getKey(), "UTF-8");
-                            String encodedValue = URLEncoder.encode(entry.getValue(), "UTF-8");
-                            encodedParams.append(encodedKey).append("=").append(encodedValue);
-                        }
-                        Boolean result = HttpUtils.sendPost(xhsmsPath, new Gson().toJson(req));
-                        if (result) isSuccess = "true";
-                    } else if (active.equals("ls")) {
-//                        String url = configService.selectConfigByKey("token.360", serviceSubtask.getOrgid());
-//                        //涓芥按鐨勭煭淇″彂閫佹柟寮�
-//                        Map<String, String> map = MsgLSEnum.getAddressByCode(serviceSubtask.getOrgid());
-                        SysConfig config = new SysConfig();
-                        config.setConfigKey("ls.msg.info");
-                        config.setOrgid(serviceSubtask.getOrgid());
-                        List<SysConfig> sysConfigs = configService.selectConfigList(config);
-                        Map<String, String> msgInfo = new HashMap<>();
-                        if (CollectionUtils.isNotEmpty(sysConfigs)) {
-                            String configValue = sysConfigs.get(0).getConfigValue();
-                            ObjectMapper objectMapper = new ObjectMapper();
-                            if (StringUtils.isNotEmpty(configValue)) {
-                                msgInfo = objectMapper.readValue(configValue, Map.class);
-                            }
-                        }
-                        log.info("-----------map鐨勫�间负锛歿}", msgInfo);
-                        String token = LSHospTokenUtil.getToken(serviceSubtask.getOrgid(), msgInfo.get("tokenUrl"));
-                        if (ObjectUtils.isNotEmpty(msgInfo) && StringUtils.isEmpty(msgInfo.get("address"))) {
-                            setSuccessPreachForm(serviceSubtask, sendPreachform, "鐭俊鍙戦�佸け璐�,璇ユ満鏋勬病鏈夐厤缃煭淇″湴鍧�, 鏃堕棿:" + now, "5");
-                            return;
-                        }
-                        log.info("銆恠fHandlle銆戜附姘寸煭淇″彂閫侊紝鍦板潃锛歿}锛屽弬鏁帮細{}锛屾満鏋処D锛歿}", msgInfo.get("address"), sendMagParam, serviceSubtask.getOrgid());
-                        String dxCode = getDXCode(msgInfo.get("address"), sendMagParam.getPhone(), sendMagParam.getContent(), msgInfo.get("sendPersonId"), msgInfo.get("sendPersonName"), MsgLSEnum.getHeaderByCode(msgInfo), token);
-                        log.info("銆恠fHandlle銆戜附姘寸煭淇″彂閫佺粨鏋滐細{}", dxCode);
-                        ObjectMapper objectMapper = new ObjectMapper();
-                        Map<String, Object> textParam = objectMapper.readValue(dxCode, Map.class);
-                        String code = textParam.get("Code").toString();
-                        if (code.equals("0")) {
-                            isSuccess = "true";
-                        }
-                    } else if (active.equals("sltd") || active.equals("nhfy")) {
-                        log.info("sltd杩涙潵浜嗗悧锛焮}   ,---sendMagParam.getContent()鐨勫弬鏁颁负锛歿}", active, sendMagParam.getContent());
-                        if (active.equals("sltd")) {
-                            //鐪佺珛鍚屽痉鐨勭煭淇″彂閫佹柟寮�
-                            String data = MessageSend.sendMsg(sendMagParam.getContent(), "6", sendMagParam.getPhone(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
-                            if (StringUtils.isNotEmpty(data)) {
-                                ObjectMapper mapper = new ObjectMapper();
-                                JsonNode root = mapper.readTree(data);
-                                String status = root.get("result").get(0).get("status").asText();
-                                if (status.equals("00000")) {
-                                    isSuccess = "true";
-                                }
-                            }
-                        } else if (active.equals("nhfy")) {
-                            Map<String, Object> smsResult = mtSubmitSmUtil.submitSm(sendMagParam.getPhone(), sendMagParam.getContent());
-                            if (smsResult != null && smsResult.get("result") != null && smsResult.get("result").toString().equals("0")) {
-                                isSuccess = "true";
-                            }
-                        }
-                    } else if (active.equals("hzszlyy")) {//甯備竴鍖婚櫌
-                        String content = sendMagParam.getContent().replace("銆愭柊鍗庡尰闄€��", "");
-
-                        SysDept sysDeptVo = new SysDept();
-                        List<SysDept> sysDepts = new ArrayList<>();
-                        if (ObjectUtils.isNotEmpty(serviceSubtask.getDeptcode())) {
-                            sysDeptVo.setDeptType("1");
-                            sysDeptVo.setOrgid(serviceSubtask.getOrgid());
-                            sysDeptVo.setDeptCode(serviceSubtask.getDeptcode());
-                            sysDeptService.selectDeptList(sysDeptVo);
-                        } else if (ObjectUtils.isNotEmpty(serviceSubtask.getLeavehospitaldistrictcode())) {
-                            sysDeptVo.setDeptType("2");
-                            sysDeptVo.setOrgid(serviceSubtask.getOrgid());
-                            sysDeptVo.setDeptCode(serviceSubtask.getLeavehospitaldistrictcode());
-                            sysDeptService.selectDeptList(sysDeptVo);
-                        }
-                        SysDept sysDept = CollectionUtils.isNotEmpty(sysDepts) ? sysDepts.get(0) : new SysDept();
-                        String campusid = ObjectUtils.isNotEmpty(sysDept) ? sysDept.getCampusid() : "2";
-                        //婀栨花鍗曠嫭鍙戦�佹柟寮�
-                        if ("1".equals(campusid)) {
-                            String result = smsUtils.sendSms1(xhsmsPath, xhsmsAccount, xhsmsPwd, sendMagParam.getPhone(), content);
-                            //杩欓噷闇�瑕佹牴鎹畆esult杩斿洖鐨勫�煎幓鍒ゆ柇锛屾槸鍚︽垚鍔燂紝鐒跺悗灏嗗�艰祴鍊肩粰isSuccess
-                            if (StringUtils.isNotEmpty(result) && result.contains("澶勭悊鎴愬姛")) {
-                                isSuccess = "true";
-                            }
-                        } else {
-                            String result = smsUtils.sendSms(xhsmsPath, xhsmsAccount, xhsmsPwd, sendMagParam.getPhone(), content);
-                            //杩欓噷闇�瑕佹牴鎹畆esult杩斿洖鐨勫�煎幓鍒ゆ柇锛屾槸鍚︽垚鍔燂紝鐒跺悗灏嗗�艰祴鍊肩粰isSuccess
-                            if (StringUtils.isNotEmpty(result) && result.contains("澶勭悊鎴愬姛")) {
-                                isSuccess = "true";
-                            }
-                        }
-                    }
+                    SendResult smsSendResult = sendSmsByActive(serviceSubtask, sendMagParam);
+                    String isSuccess = smsSendResult.asLegacyFlag();
                     //浠诲姟鍙戦�佽褰�
                     ServiceSubtaskRecord serviceSubtaskRecord = new ServiceSubtaskRecord();
                     serviceSubtaskRecord.setTaskid(serviceSubtask.getTaskid().toString());
@@ -1231,11 +1525,7 @@
                     String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key);
                     String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key);
                     String url = null;
-                    url = localIP + ":" + req_path + "/outsideChainwt?param1=" + taskId +
-                            "&param2=" +  patid +
-                            "&param3=" + URLEncoder.encode(ivrTask1.getTaskName(), StandardCharsets.UTF_8.toString()) +
-                            "&param5=false" +
-                            "$param6=" + subId;
+                    url = localIP + ":" + req_path + "/outsideChainwt?param1=" + taskId + "&param2=" + patid + "&param3=" + URLEncoder.encode(ivrTask1.getTaskName(), StandardCharsets.UTF_8.toString()) + "&param5=false" + "$param6=" + subId;
 
                     ServiceOutPath serviceOutPath = new ServiceOutPath();
                     serviceOutPath.setParam1(taskId);
@@ -1248,31 +1538,14 @@
                     String format = String.format("%03X", serviceOutPath.getId());
                     serviceOutPath.setRadix(format);
                     serviceOutPath.setUpdateTime(new Date());
+                    serviceOutPath.setUrl(url);
                     iServiceOutPathService.updateServiceOutPath(serviceOutPath);
 
-                    //鑾峰彇寰俊鍏紬鍙疯姹備俊鎭牴鎹満鏋処D
-                    List<String> wxqqxx = WxGZHEnum.getDescByCode(patArchive.getOrgid());
-                    //甯備竴鍖婚櫌 涓嶆牎楠�
+                    //寰俊鍏紬鍙峰彂閫侊細甯備竴涓庢柊鍗庢槸涓ゅ瀹屽叏涓嶅悓鐨勭綉鍏充笌鍒ゅ畾鏍囧噯锛�
+                    //鏈烘瀯閰嶇疆鏍¢獙銆丠IS鎮h�匢D鏍¢獙閮藉凡鏀跺彛鍒� ruoyi-message 鐨勫彂閫佹柟瀹炵幇閲�
+                    SendResult wechatSendResult = sendWechatByActive(serviceSubtask, patArchive, url);
+                    Boolean wxCodeSuccess = wechatSendResult.isOk();
 
-                    if (CollectionUtils.isEmpty(wxqqxx) || wxqqxx.size() < 4) {
-                        setSuccessPreachForm(serviceSubtask, sendPreachform, "銆愬叕浼楀彿銆戣鏈烘瀯鐨勫叕浼楀彿閰嶇疆淇℃伅涓嶅叏锛屾棤娉曢�氳繃鍏紬鍙峰彂閫�", "4");
-                        return;
-                    }
-
-                    if (StringUtils.isEmpty(patArchive.getPatidHis())) {
-                        setSuccessPreachForm(serviceSubtask, sendPreachform, "銆愬叕浼楀彿銆戝叕浼楀彿鍙戦�佸け璐�,his绯荤粺鐨勬偅鑰卛d涓虹┖", "5");
-                        return;
-                    }
-                    String wxCode = "";
-                    //甯備竴鍖婚櫌
-                    if (active.equals("hzszlyy")) {
-                        //澶勭悊涓枃涔辩爜闂
-                        wxCode = smsUtils.sendChat(url, patArchive.getTelcode(), serviceSubtask.getSfzh());
-                    } else {
-                        wxCode = getWXCode(serviceSubtask.getSfzh(), url, serviceSubtask.getTaskName(), serviceSubtask.getTaskDesc(), patArchive.getTelcode(), serviceSubtask.getSendname(), patArchive.getPatidHis(), wxqqxx);
-                    }
-
-                    Map map = JSONObject.parseObject(wxCode, Map.class);
                     //浠诲姟鍙戦�佽褰�
                     ServiceSubtaskRecord serviceSubtaskRecord = new ServiceSubtaskRecord();
                     serviceSubtaskRecord.setTaskid(serviceSubtask.getTaskid().toString());
@@ -1281,22 +1554,7 @@
                     serviceSubtaskRecord.setPreachform("4");
                     serviceSubtaskRecord.setStartTime(System.currentTimeMillis());
                     serviceSubtaskRecord.setResult("success");
-                    Boolean wxCodeSuccess = false;
-                    if (active.equals("hzszlyy")) {
-                        if (!map.isEmpty() && map.get("success") != null) {
-                            Integer wxCodeSuccessShiyi = (Integer) map.get("success");
-                            if (ObjectUtils.isNotEmpty(wxCodeSuccessShiyi) && wxCodeSuccessShiyi == 1) {
-                                wxCodeSuccess = true;
-                            } else {
-                                wxCodeSuccess = false;
-                            }
-                        }
-                    } else {
-                        if (!map.isEmpty() && map.get("succ") != null) {
-                            wxCodeSuccess = (boolean) map.get("succ");
-                        }
-                    }
-                    if (!map.isEmpty() && !wxCodeSuccess) serviceSubtaskRecord.setResult("error");
+                    if (!wxCodeSuccess) serviceSubtaskRecord.setResult("error");
                     serviceSubtaskRecordService.insertServiceSubtaskRecord(serviceSubtaskRecord);
 
                     //鍙戦�佸畬鎴愬悗锛屼慨鏀圭姸鎬�
@@ -1305,7 +1563,7 @@
                         serviceSubtask.setResult("success");
                         setSuccessPreachForm(serviceSubtask, sendPreachform, "銆愬叕浼楀彿銆戝叕浼楀彿鍙戦�佹垚鍔�", "2");
                     } else {
-                        log.error("銆恠fHandlle銆戝叕浼楀彿鍙戦�佸け璐ワ紝鎮h�呬俊鎭細{}锛岄敊璇俊鎭細{}", serviceSubtask, map.get("msg"));
+                        log.error("銆恠fHandlle銆戝叕浼楀彿鍙戦�佸け璐ワ紝鎮h�呬俊鎭細{}锛岄敊璇俊鎭細{}", serviceSubtask, wechatSendResult.getMessage());
                         setSuccessPreachForm(serviceSubtask, sendPreachform, "銆愬叕浼楀彿銆戝叕浼楀彿鍙戦�佸け璐�", "5");
                     }
                 } catch (Exception e) {
@@ -1318,6 +1576,72 @@
             setSuccessPreachForm(serviceSubtask, sendPreachform, "浜哄伐鍙戦�佹垚鍔�", "2");
         }
 
+    }
+
+    /**
+     * 鎸� {@code active}锛堢珯鐐癸級璺敱鍒板搴旂殑鐭俊鍙戦�佹柟銆�
+     * <p>
+     * 鍚勭珯鐐瑰樊寮傝 {@code ruoyi-message} 妯″潡鍚勫疄鐜扮被锛涙湰鏂规硶鍙仛銆屽叆鍙傜粍瑁� + 璺敱 + 鏃ュ織銆嶃��
+     * <p>
+     * 鈿狅笍 鏂板崕锛坽@code xh}锛夌珯鐐逛粛璧般�屾棫瀹炵幇锛堝彂閫佺┖鎶ユ枃锛夈�嶏紝涓庡師 {@code RyTask} 琛屼负涓�瀛椾笉宸紝
+     * 纭缃戝叧鎶ユ枃鏍煎紡鍚庡簲鏀逛负 {@code XinHuaSmsSender#sendForm}銆傝瑙佽绫荤殑 TODO 璇存槑銆�
+     */
+    private SendResult sendSmsByActive(ServiceSubtask serviceSubtask, SendMagParam sendMagParam) {
+        SmsSendRequest request = SmsSendRequest.of(sendMagParam.getPhone(), sendMagParam.getContent(), serviceSubtask.getOrgid());
+        //甯備竴鍖哄垎婀栨花/鍚村北涓ゅ鐭俊绛惧悕
+        if ("hzszlyy".equals(active)) {
+            request.setCampus(resolveShiyiCampus(serviceSubtask));
+        }
+        if ("xh".equals(active)) {
+            XinHuaSmsSender xinHuaSmsSender = (XinHuaSmsSender) smsSenderFactory.get(active);
+            return xinHuaSmsSender.sendJsonLegacy(request);
+        }
+        return smsSenderFactory.send(active, request);
+    }
+
+    /**
+     * 鎸� {@code active}锛堢珯鐐癸級璺敱鍒板搴旂殑寰俊鍏紬鍙峰彂閫佹柟銆�
+     * <p>
+     * 鈿狅笍 鏂板崕鍏紬鍙峰繀椤讳紶鎮h�呬俊鎭紙濮撳悕 + HIS 鎮h�匢D锛夛紝涓庡師
+     * {@code getWXCode(...)} 鐨勫叆鍙備繚鎸佷竴涓�瀵瑰簲銆�
+     */
+    private SendResult sendWechatByActive(ServiceSubtask serviceSubtask, PatArchive patArchive, String url) {
+        WechatSendRequest request = new WechatSendRequest();
+        request.setOrgid(patArchive.getOrgid());
+        request.setIdCard(serviceSubtask.getSfzh());
+        request.setUrl(url);
+        request.setTitle(serviceSubtask.getTaskName());
+        request.setContent(serviceSubtask.getTaskDesc());
+        request.setPhone(patArchive.getTelcode());
+        request.setPatientName(serviceSubtask.getSendname());
+        request.setPatidHis(patArchive.getPatidHis());
+        return wechatSenderFactory.send(active, request);
+    }
+
+    /**
+     * 鏌ヨ鎮h�呮墍鍦ㄩ櫌鍖猴紙1=婀栨花锛屽叾浠�=鍚村北锛夈��
+     * <p>
+     * TODO 寰呯‘璁わ細鍘熷疄鐜板苟鏈妸 {@code sysDeptService.selectDeptList(...)} 鐨勮繑鍥炲�艰祴缁�
+     * {@code sysDepts}锛屽洜姝� {@code sysDepts} 鎭掍负绌哄垪琛ㄣ�亄@code campusid} 鎭掍负 {@code "2"}锛�
+     * 婀栨花闄㈠尯瀹為檯涓婃案杩滆蛋涓嶅埌 {@code sendSms1}銆傛湰娆¢噸鏋�<b>淇濇寔璇ヨ涓轰笉鍙�</b>锛�
+     * 璇峰湪涓氬姟纭鍚庡啀鍐冲畾鏄惁淇垚 {@code sysDepts = sysDeptService.selectDeptList(...)}銆�
+     */
+    private String resolveShiyiCampus(ServiceSubtask serviceSubtask) {
+        SysDept sysDeptVo = new SysDept();
+        List<SysDept> sysDepts = new ArrayList<>();
+        if (ObjectUtils.isNotEmpty(serviceSubtask.getDeptcode())) {
+            sysDeptVo.setDeptType("1");
+            sysDeptVo.setOrgid(serviceSubtask.getOrgid());
+            sysDeptVo.setDeptCode(serviceSubtask.getDeptcode());
+            sysDeptService.selectDeptList(sysDeptVo);
+        } else if (ObjectUtils.isNotEmpty(serviceSubtask.getLeavehospitaldistrictcode())) {
+            sysDeptVo.setDeptType("2");
+            sysDeptVo.setOrgid(serviceSubtask.getOrgid());
+            sysDeptVo.setDeptCode(serviceSubtask.getLeavehospitaldistrictcode());
+            sysDeptService.selectDeptList(sysDeptVo);
+        }
+        SysDept sysDept = CollectionUtils.isNotEmpty(sysDepts) ? sysDepts.get(0) : new SysDept();
+        return ObjectUtils.isNotEmpty(sysDept) ? sysDept.getCampusid() : "2";
     }
 
 
@@ -1376,15 +1700,15 @@
                 serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
                 return "-1";
             }
-
             // 褰搒ort绛変簬鍒楄〃size鏃讹紝骞朵笖鎵�鏈塻endstate閮戒笉绛変簬9锛屽垯杩斿洖-1
-            if (currentSort.get().equals((long) serviceSubtaskPreachforms.size())) {
+            if (currentSort.get().equals((long) serviceSubtaskPreachforms.size())
+                    && isSubtaskDeadline(serviceSubtask, serviceSubtaskPreachforms)) {
                 if (allSendStateNot1AndNot9) {
                     //璇存槑鍏ㄥ彂閫佸け璐ヤ簡
                     serviceSubtask.setSendstate(7L);
                     serviceSubtask.setFinishtime(null);
                     log.error("getSendPreachform鏂规硶 妫�鏌ユ槸鍚︽墍鏈塻endstate涓嶇瓑浜�9, 鍏ㄥけ璐ヤ簡");
-                    serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + "," + "鎵�鏈夊彂閫佹柟寮忓潎鏈幏鍙栫粨鏋滐紝浠诲姟澶辫触锛堣秴鏃讹級" : "鎵�鏈夊彂閫佹柟寮忓潎鏈幏鍙栫粨鏋滐紝浠诲姟澶辫触锛堣秴鏃讹級");
+                    serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + "," + "鎵�鏈夋墽琛屾柟寮忓潎鏈幏鍙栫粨鏋滐紝浠诲姟澶辫触锛堣秴鏃讹級" : "鎵�鏈夋墽琛屾柟寮忓潎鏈幏鍙栫粨鏋滐紝浠诲姟澶辫触锛堣秴鏃讹級");
                     serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
                     //淇敼鍙戦�佺姸鎬�
                     setFail(serviceSubtaskPreachforms, serviceSubtask);
@@ -1454,74 +1778,10 @@
         return 0;
     }
 
-    private String getDXCode(String address, String ShouJiHM, String FaSongNR, String FaSongRID, String FaSongRXM, Map<String, Object> headerMap, String token) {
-        Map<String, Object> map = new LinkedHashMap<>();
-
-        Map<String, Object> YeWuXX = new LinkedHashMap<>();
-        Map<String, Object> DuanXinXX = new LinkedHashMap<>();
-        DuanXinXX.put("ShouJiHM", ShouJiHM);
-        DuanXinXX.put("FaSongNR", FaSongNR);
-        DuanXinXX.put("FaSongRID", FaSongRID);
-        DuanXinXX.put("FaSongRXM", FaSongRXM);
-        YeWuXX.put("DuanXinXX", DuanXinXX);
-
-        map.put("XiaoXiTou", headerMap);
-        map.put("YeWuXX", YeWuXX);
-
-        String body = new Gson().toJson(map);
-
-//        String result = HttpUtils.sendPost(address, body);
-        String result = null;
-        try {
-            result = OkHttpExample.sendPostRequest(address, body, token);
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        log.info("銆恎etDXCode銆戠煭淇″彂閫佺粨鏋滐細{}", result);
-
-        JSONObject jsonObject = JSONObject.parseObject(result);
-        String code = (String) jsonObject.toString();
-        return code;
-    }
-
-
-    private String getWXCode(String idcard, String url, String taskName, String taskDesc, String phone, String setPatientname, String setPatientid, List<String> wxqqxx) {
-        XinHuaWXReq xinHuaWXReq = new XinHuaWXReq();
-        xinHuaWXReq.setIdcard(idcard);
-        xinHuaWXReq.setUrl(url);
-        xinHuaWXReq.setPatientid(setPatientid);
-        xinHuaWXReq.setPatientname(setPatientname);
-        xinHuaWXReq.setMobile(phone);
-        xinHuaWXReq.setMedcardno(null);
-        xinHuaWXReq.setTitlename(taskName);
-        xinHuaWXReq.setContent(taskDesc);
-        xinHuaWXReq.setAppid(wxqqxx.get(1));
-        log.info("銆恎etWXCode銆戝井淇″叕浼楀彿璇锋眰鍙傛暟锛歿}", xinHuaWXReq);
-        String body = new Gson().toJson(xinHuaWXReq);
-        String encode = encode(wxqqxx.get(2).concat(body));
-        Map<String, String> headerMap = new HashMap<>();
-        headerMap.put("sign", encode);
-        String result = HttpUtils.sendPostByHeader(wxqqxx.get(3), body, headerMap);
-        log.info("銆恎etWXCode銆戝井淇″叕浼楀彿杩斿洖鍙傛暟锛歿}", result);
-        JSONObject jsonObject = JSONObject.parseObject(result);
-        String code = (String) jsonObject.toString();
-        return code;
-    }
-
-
-    public String encode(String arg) {
-        if (arg == null) {
-            arg = "";
-        }
-        MessageDigest md5 = null;
-        try {
-            md5 = MessageDigest.getInstance("MD5");
-            md5.update(arg.getBytes("UTF-8"));
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return toHex(md5.digest());
-    }
+    // ---------------------------------------------------------------------
+    // 璇存槑锛氬師 getDXCode / getWXCode / encode 涓変釜绉佹湁鏂规硶宸查殢鍙戦�佹柟涓�璧锋敹鍙e埌
+    // ruoyi-message 妯″潡锛圠ishuiSmsSender / XinHuaMpApi锛夛紝姝ゅ宸插垹闄わ紝閬垮厤閲嶅瀹炵幇銆�
+    // ---------------------------------------------------------------------
 
     public void collectHIS() {
         try {
@@ -1531,6 +1791,47 @@
             log.info("銆恉ealHisData銆慔IS缁撴潫閲囬泦鏁版嵁");
         } catch (Exception e) {
             log.error("銆恉ealHisData銆慔IS鏁版嵁閲囬泦寮傚父", e);
+        }
+    }
+
+    public void collectHISYesterday() {
+        try {
+            // 鑾峰彇鏄ㄥぉ0鐐瑰埌浠婂ぉ0鐐圭殑鏃堕棿鑼冨洿
+            LocalDateTime todayZero = LocalDateTime.now().with(LocalTime.MIN);
+            LocalDateTime yesterdayZero = todayZero.minusDays(1);
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+            String startTime = yesterdayZero.format(formatter);
+            String endTime = todayZero.format(formatter);
+            // HIS鏁版嵁閲囬泦
+            log.info("銆恈ollectHISYesterday銆慔IS寮�濮嬮噰闆嗘暟鎹�");
+            // 绔嬪嵆杩斿洖锛屽悗鍙板紓姝ユ墽琛�
+            CompletableFuture.runAsync(() -> {
+                ichService.syncMedInhosp(startTime, endTime);
+            });
+            log.info("銆恈ollectHISYesterday銆慔IS缁撴潫閲囬泦鏁版嵁");
+        } catch (Exception e) {
+            log.error("銆恈ollectHISYesterday銆慔IS鏁版嵁閲囬泦寮傚父", e);
+        }
+    }
+
+    public void collectHISDaysBefore(Long daysBefore) {
+        try {
+            // 鑾峰彇daysBefore 0鐐瑰埌daysBefore-1 0鐐圭殑鏃堕棿鑼冨洿
+            LocalDateTime todayZero = LocalDateTime.now().with(LocalTime.MIN);
+            LocalDateTime daysBeforeZeroStart = todayZero.minusDays(daysBefore);
+            LocalDateTime daysBeforeZeroEnd = todayZero.minusDays(daysBefore-1L);
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+            String startTime = daysBeforeZeroStart.format(formatter);
+            String endTime = daysBeforeZeroEnd.format(formatter);
+            // HIS鏁版嵁閲囬泦
+            log.info("銆恈ollectHISDaysBefore銆慔IS寮�濮嬮噰闆嗘暟鎹�: startTime:{}, endtime:{}",startTime, endTime);
+            // 绔嬪嵆杩斿洖锛屽悗鍙板紓姝ユ墽琛�
+            CompletableFuture.runAsync(() -> {
+                ichService.syncMedInhosp(startTime, endTime);
+            });
+            log.info("銆恈ollectHISDaysBefore銆慔IS缁撴潫閲囬泦鏁版嵁: startTime:{}, endtime:{}",startTime, endTime);
+        } catch (Exception e) {
+            log.error("銆恈ollectHISDaysBefore銆慔IS鏁版嵁閲囬泦寮傚父", e);
         }
     }
 
@@ -1562,7 +1863,7 @@
 //        //浜哄伐鐨勬湭鍙戦�佺姸鎬侊紝闇�瑕佹煡2
 //        if (preachform.equals("1") && StringUtils.isNotEmpty(failSendstate) && Long.valueOf(failSendstate) > 2)
 //            serviceSubtaskPreachform.setSendstate("2");
-
+        log.error("-----serviceSubtaskPreachform鐨勫叆鍙傛槸锛焮}", serviceSubtaskPreachform);
         List<ServiceSubtaskPreachform> serviceSubtaskPreachforms = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(serviceSubtaskPreachform);
         if (CollectionUtils.isNotEmpty(serviceSubtaskPreachforms)) {
             ServiceSubtaskPreachform serviceSubtaskPreachform1 = serviceSubtaskPreachforms.get(0);
@@ -1575,7 +1876,8 @@
             serviceSubtaskPreachformMapper.updateServiceSubtaskPreachform(serviceSubtaskPreachform1);
 
             //濡傛灉褰撳墠鐨刾reachform宸茬粡鏄渶鍚庝竴涓簡锛岄偅鐩存帴灏唖erviceSubtask鐨剆endstate鐘舵�佹敼鎴�7灏辫浜�(鍏ㄨ秴鏃朵簡)
-            if (serviceSubtaskPreachform1.getSort() == sspCount.size()) {
+            if (serviceSubtaskPreachform1.getSort() == sspCount.size()
+                    && isSubtaskDeadline(serviceSubtask, serviceSubtaskPreachforms)) {
                 if (failSendstate.equals("4") || failSendstate.equals("5")) {
                     serviceSubtask.setCurrentPreachform(preachform);
                     serviceSubtask.setSendstate(7L);
@@ -1653,4 +1955,142 @@
         int result = QwenLLMUtil.matchRegex(questionText, voiceText, value, regexText);
         return result;
     }
+
+    /**
+     * 浠诲姟缁勶紙appltype=5锛夐杞撼鍏ワ細鎵弿鏂板嚭闄㈡偅鑰咃紝鎸� schedule 缁戝畾鐨勭淮搴﹀尮閰嶄换鍔$粍锛�
+     * 涓哄懡涓殑鎮h�呮寜璁″垝鏄庣粏涓�娆℃�х敓鎴愮 0 杞� N 鏉� subtask锛屽苟缃� schedulecheck_flag=1銆�
+     * 鍚庣画杞鐢� {@link #rollTaskGroupCycle()} 璐熻矗銆�
+     * <p>
+     * 涓庝富鎵弿 dealOutHospInfo 鍒嗙锛屼簰涓嶅共鎵般�傚缓璁瘡 30 鍒嗛挓鎵ц涓�娆°��
+     */
+    public void dealTaskGroupOutHosp() {
+        log.info("銆恉ealTaskGroupOutHosp銆戝紑濮嬫壂鎻忎换鍔$粍鏂板嚭闄㈡偅鑰�");
+        if (!port.equals("8095")) {
+            return;
+        }
+        try {
+            String config = configService.selectConfigByKey("visit.early.day");
+            iPatMedInhospService.dealOutHospInfoBySchedule(config);
+            log.info("銆恉ealTaskGroupOutHosp銆戜换鍔$粍棣栬疆绾冲叆鎵弿瀹屾垚");
+        } catch (Exception e) {
+            log.error("銆恉ealTaskGroupOutHosp銆戜换鍔$粍鎵弿寮傚父", e);
+        }
+    }
+
+    /**
+     * 浠诲姟缁勶紙appltype=5锛夊惊鐜换鍔℃粴鍔ㄨ皟搴︺��
+     * <p>
+     * 鎵弿鎵�鏈� schedule_style=1 鐨勮鍒掞紝鑻ユ湰杞� subtask 鍏ㄩ儴 finalize锛坰endstate 鈭� 1/2/3锛夛紝
+     * 鍒欏厠闅嗘湰杞偅鑰呭埌涓嬩竴杞紝鎺ㄨ繘 current_loop_count 涓� visit_time銆�
+     * <p>
+     * 寤鸿姣忓皬鏃舵垨姣忓崐灏忔椂鎵ц涓�娆★紝閬垮厤杞绉帇銆�
+     */
+    public void rollTaskGroupCycle() {
+        log.info("銆恟ollTaskGroupCycle銆戝紑濮嬫壂鎻忓惊鐜换鍔$粍");
+        try {
+            int rolled = serviceTaskScheduleService.rollCycleTasks();
+            log.info("銆恟ollTaskGroupCycle銆戞湰娆℃帹杩� {} 涓鍒�", rolled);
+        } catch (Exception e) {
+            log.error("銆恟ollTaskGroupCycle銆戞粴鍔ㄨ皟搴﹀紓甯�", e);
+        }
+    }
+
+    /**
+     * 闅忚浠诲姟鏄惁瓒呮椂
+     * @param serviceSubtask
+     * @param serviceSubtaskPreachforms
+     * @return
+     */
+    public boolean isSubtaskDeadline(ServiceSubtask serviceSubtask, List<ServiceSubtaskPreachform> serviceSubtaskPreachforms){
+        if (ObjectUtils.isNotEmpty(serviceSubtask)) {
+            //鍙湁鍑洪櫌闅忚鍜屼笓鐥呴殢璁挎湁瓒呮椂
+            if(StringUtils.isNotEmpty(serviceSubtask.getServiceType()) &&
+                    !serviceSubtask.getServiceType().equals("2") && !serviceSubtask.getServiceType().equals("13")){
+                return true;
+            }
+        }
+        if (Objects.isNull(serviceSubtask) || CollectionUtils.isEmpty(serviceSubtaskPreachforms)) {
+            return false;
+        }
+        // 鍩哄噯鏃跺埢锛氬嚭闄㈡椂闂� + 鍙戦�佹棩锛坰endDay 缂虹渷鎸� 1锛夛紝骞跺厹搴曢伩鍏� NPE/鑴忔暟鎹�
+        ServiceTask serviceTask = serviceTaskMapper.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
+        int sendDay = serviceTask != null && serviceTask.getSendDay() != null ? serviceTask.getSendDay().intValue() : 1;
+        Date deadline = DateUtils.addDays(serviceSubtask.getEndtime(), sendDay);
+        int sumCompensateTime = CollectionUtils.isEmpty(serviceSubtaskPreachforms) ? 0 : serviceSubtaskPreachforms.stream()
+                .mapToInt(x -> x.getCompensateTime() == null ? 0 : Integer.parseInt(x.getCompensateTime()))
+                .sum();
+        sumCompensateTime = sumCompensateTime + 1;
+        // 鍙ˉ鍋挎渶鍚庝竴姝ヨ嚜韬殑琛ュ伩鏃堕棿锛堝ぉ锛夛紝鑴忓�间竴寰嬫寜 0 鍏滃簳
+        deadline = DateUtils.addDays(deadline, sumCompensateTime);
+        // 鍑洪櫌(鍙戦��)鏃堕棿 + 鏈琛ュ伩鏃堕棿 灏忎簬褰撳墠鏃堕棿 -> 瓒呮椂
+        return deadline.getTime() < new Date().getTime();
+    }
+
+    /**
+     * 澶勭悊瓒呮椂闅忚浠诲姟
+     * @return
+     */
+    public void dealSubtaskDeadline(String orgid, Integer deadlineDay){
+        //鑾峰彇浠诲姟淇℃伅
+        ServiceTask st = new ServiceTask();
+        st.setDelFlag("0");
+        st.setLongTask(1);
+        st.setNexttaskflag("1");
+        st.setOrgid(orgid);
+        List<ServiceTask> serviceTasks = serviceTaskMapper.selectServiceTaskList(st);
+        for (ServiceTask serviceTask : serviceTasks) {
+            deadlineDay = -deadlineDay;
+            Date deadline = DateUtils.addDays(new Date(), deadlineDay);
+            //閫氳繃浠诲姟ID鎷垮埌鎮h�呬俊鎭�,骞朵笖闅忚鏃堕棿寰楁槸浠婂ぉ涔嬪墠鐨�
+            ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
+            serviceSubtaskVO.setOrgid(orgid);
+            serviceSubtaskVO.setSendstate(7L);
+            //鍙壂鎻忛娆¢殢璁跨殑
+            serviceSubtaskVO.setVisitCount(1);
+            serviceSubtaskVO.setTaskid(serviceTask.getTaskid());
+            serviceSubtaskVO.setEndOutHospTime(deadline);
+            List<ServiceSubtask> serviceSubtaskList
+                    = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO);
+            log.info("銆恉ealSubtaskDeadline銆戣幏鍙栧埌{}涓秴鏃朵换鍔�, taskid={}", serviceSubtaskList.size(), serviceTask.getTaskid());
+            for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
+                PatMedInhosp patMedInhospVo = new PatMedInhosp();
+                patMedInhospVo.setOrgid(serviceSubtask.getOrgid());
+                patMedInhospVo.setInhospid(serviceSubtask.getInhospid());
+                List<PatMedInhosp> patMedInhospList = iPatMedInhospService.selectPatMedInhospList(patMedInhospVo);
+                PatMedInhosp patMedInhosp = new PatMedInhosp();
+                if (!patMedInhospList.isEmpty()) {
+                    patMedInhosp = patMedInhospList.get(0);
+                }else {
+                    continue;
+                }
+                if(ObjectUtils.isEmpty(serviceTask.getNexttaskid())){
+                    continue;
+                }
+                ServiceTask nextServiceTask = serviceTaskMapper.selectServiceTaskByTaskid(serviceTask.getNexttaskid());
+                PatArchive patArchive = patArchiveService.selectPatArchiveByPatid(serviceSubtask.getPatid());
+                String config = configService.selectConfigByKey("visit.early.day");
+                Integer type = 1;
+
+                //鏂板鍐嶆闅忚浠诲姟
+                ServiceSubtask serviceSubtaskAgain = iPatMedInhospService.boxedServiceSubtask(nextServiceTask,
+                        patMedInhosp, patArchive, config, type);
+                serviceSubtaskAgain.setId(null);
+                serviceSubtaskAgain.setUpid(serviceSubtask.getId().intValue());
+                serviceSubtaskAgain.setVisitCount(serviceSubtask.getVisitCount() + 1);
+                serviceSubtaskAgain.setSendstate(2L);
+                serviceSubtaskAgain.setCreateTime(new Date());
+                serviceSubtaskAgain.setUpdateTime(new Date());
+                serviceSubtaskAgain.setVisitType(serviceSubtask.getVisitType());
+                serviceSubtaskAgain.setVisitDeptCode(serviceSubtask.getVisitDeptCode());
+                serviceSubtaskAgain.setVisitDeptName(serviceSubtask.getVisitDeptName());
+                int i = serviceSubtaskMapper.insertServiceSubtask(serviceSubtaskAgain);
+                if (i == 1) {
+                    //鍐嶆闅忚浠诲姟鍒涘缓鎴愬姛鍚庯紝鍘熶换鍔℃敼涓哄け璐ョ姸鎬�
+                    serviceSubtask.setSendstate(5L);
+                    serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
+                }
+            }
+        }
+    }
+
 }

--
Gitblit v1.9.3