From cf8712a9c0816559f50644f15672e7359028c4c4 Mon Sep 17 00:00:00 2001
From: 陈昶聿 <chychen@nbjetron.com>
Date: 星期三, 11 十一月 2026 14:02:58 +0800
Subject: [PATCH] 妇幼-住院完成生成

---
 smartor/src/main/java/com/smartor/domain/PatChildArchiveDetail.java                       |   16 
 smartor/src/main/resources/mapper/smartor/PatChildArchiveDetailMapper.xml                 |   18 +
 ruoyi-task/src/main/java/com/ruoyi/task/api/TaskSubtaskApi.java                           |   13 
 ruoyi-task/src/main/java/com/ruoyi/task/api/contract/TaskSubtaskApiImpl.java              |   14 
 ruoyi-task/src/main/java/com/ruoyi/task/service/impl/ServiceSubtaskServiceImpl.java       |   13 
 smartor/src/main/resources/mapper/smartor/PatChildArchiveMapper.xml                       |   24 +
 ruoyi-task/src/main/resources/mapper/task/ServiceSubtaskMapper.xml                        |   17 +
 smartor/src/main/java/com/smartor/domain/PatChildArchive.java                             |   17 +
 smartor/src/main/java/com/smartor/domain/PatMaternityArchive.java                         |   17 +
 smartor/src/main/resources/mapper/smartor/PatMaternityArchiveDetailMapper.xml             |   18 +
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java                              |   25 +
 ruoyi-admin/src/main/java/com/ruoyi/web/component/RedisMqReceiver.java                    |    7 
 ruoyi-task/src/main/java/com/ruoyi/task/mapper/ServiceSubtaskMapper.java                  |   14 
 smartor/src/main/java/com/smartor/service/IPatSpecificArchiveGenerateService.java         |   18 +
 smartor/src/main/java/com/smartor/domain/PatMaternityArchiveDetail.java                   |   16 
 smartor/src/main/java/com/smartor/service/impl/PatMaternityArchiveServiceImpl.java        |   19 +
 smartor/src/main/java/com/smartor/service/impl/PatChildArchiveServiceImpl.java            |   18 +
 smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java       |    7 
 smartor/src/main/java/com/smartor/service/impl/PatSpecificArchiveGenerateServiceImpl.java |  601 ++++++++++++++++++++++++++++++++++++-
 smartor/src/main/java/com/smartor/common/SpecificArchiveConstants.java                    |   30 +
 smartor/src/main/resources/mapper/smartor/PatMaternityArchiveMapper.xml                   |   24 +
 21 files changed, 912 insertions(+), 34 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/component/RedisMqReceiver.java b/ruoyi-admin/src/main/java/com/ruoyi/web/component/RedisMqReceiver.java
index e889ed6..df9e6b7 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/component/RedisMqReceiver.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/component/RedisMqReceiver.java
@@ -56,6 +56,7 @@
 import com.ruoyi.task.domain.SendMagParam;
 import com.ruoyi.task.service.IServiceSubtaskRecordService;
 import com.ruoyi.task.mapper.ServiceSubtaskPreachformMapper;
+import com.ruoyi.task.event.FollowupCompletedEventPublisher;
 import com.ruoyi.patarchive.mapper.PatArchiveMapper;
 @Slf4j
 @Component//鐩戝惉姝ら槦鍒�
@@ -72,6 +73,9 @@
 
     @Value("${req_path}")
     private String req_path;
+
+    @Autowired
+    private FollowupCompletedEventPublisher followupCompletedEventPublisher;
 
     @Autowired
     private IServiceOutPathService iServiceOutPathService;
@@ -898,6 +902,9 @@
             serviceSubtask.setSendstate(6L);
         }
         serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
+        if (Long.valueOf(6L).equals(serviceSubtask.getSendstate())) {
+            followupCompletedEventPublisher.publish(serviceSubtask.getId());
+        }
 
         // 鏇存柊褰撳墠鍙戦�佹柟寮忔槑缁嗭紱鍙戦�佹垚鍔熸椂鍏佽褰撳墠琛屽凡缁忔槸 sendstate=2銆�
         currentPreachformRow.setSendstate(failSendstate);
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 c1ee902..274ac21 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
@@ -149,6 +149,12 @@
     private ICollectHISService ichService;
 
     @Autowired
+    private IPatSpecificArchiveGenerateService patSpecificArchiveGenerateService;
+
+    @Autowired
+    private com.ruoyi.task.event.FollowupCompletedEventPublisher followupCompletedEventPublisher;
+
+    @Autowired
     private ISysConfigService configService;
 
     @Autowired
@@ -1203,6 +1209,7 @@
                 if (finishState) {
                     serviceSubtask.setSendstate(6L);
                     serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
+                    followupCompletedEventPublisher.publish(serviceSubtask.getId());
                     continue;
                 }
 
@@ -1715,6 +1722,7 @@
                 //璇存槑锛屽湪鏌愮鏂瑰紡鍙戦�佸け璐ュ悗锛屽張鎴愬姛浜嗭紙渚嬪鐭俊鎴栧叕浼楀彿锛屽湪瑙勫畾鏃堕棿澶栨偅鑰呭仛瀹屼簡锛岃繖涓椂鍊欙紝鐘舵�佹敼鎴愪簡9锛�
                 serviceSubtask.setSendstate(6L);
                 serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
+                followupCompletedEventPublisher.publish(serviceSubtask.getId());
                 return "-1";
             }
             // 褰搒ort绛変簬鍒楄〃size鏃讹紝骞朵笖鎵�鏈塻endstate閮戒笉绛変簬9锛屽垯杩斿洖-1
@@ -1942,6 +1950,9 @@
         serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + "," + remark : remark);
         log.info("serviceSubtask鐨勫叆鍙傛槸锛歿}",serviceSubtask);
         serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
+        if (Long.valueOf(6L).equals(serviceSubtask.getSendstate())) {
+            followupCompletedEventPublisher.publish(serviceSubtask.getId());
+        }
         return true;
     }
 
@@ -2197,4 +2208,18 @@
         }
     }
 
+    /**
+     * 浣忛櫌闅忚瀹屾垚鐢熸垚涓撶妗f琛ュ伩浠诲姟銆�
+     *
+     * <p>鎵弿杩� 7 澶╁凡瀹屾垚浣嗘湭鐢熸垚鏃ュ織鐨勪綇闄㈤殢璁匡紝鎸夐厤缃ˉ鐢熸垚濡囩/鍎跨妗f銆�</p>
+     */
+    public void generateInhospFollowupArchive() {
+        try {
+            int generated = patSpecificArchiveGenerateService.compensateInhospFollowups();
+            log.info("銆恎enerateInhospFollowupArchive銆戜綇闄㈤殢璁夸笓绉戞。妗堣ˉ鍋垮畬鎴愶紝鐢熸垚鏁伴噺={}", generated);
+        } catch (Exception e) {
+            log.error("銆恎enerateInhospFollowupArchive銆戜綇闄㈤殢璁夸笓绉戞。妗堣ˉ鍋垮け璐�", e);
+        }
+    }
+
 }
diff --git a/ruoyi-task/src/main/java/com/ruoyi/task/api/TaskSubtaskApi.java b/ruoyi-task/src/main/java/com/ruoyi/task/api/TaskSubtaskApi.java
index d0b9827..2e921e1 100644
--- a/ruoyi-task/src/main/java/com/ruoyi/task/api/TaskSubtaskApi.java
+++ b/ruoyi-task/src/main/java/com/ruoyi/task/api/TaskSubtaskApi.java
@@ -53,6 +53,19 @@
     List<ServiceSubtask> findSubtasks(ServiceSubtaskEntity query);
 
     /**
+     * 鏌ヨ宸插畬鎴愩�佹寚瀹氭満鏋�/鏈嶅姟绫诲瀷銆佸畬鎴愭椂闂村湪 startTime 涔嬪悗鐨勪綇闄㈤殢璁垮瓙浠诲姟銆�
+     * 渚涗綇闄㈤殢璁挎。妗堣ˉ鍋夸换鍔′娇鐢ㄣ��
+     *
+     * @param orgid        鏈烘瀯ID
+     * @param serviceTypes 鏈嶅姟绫诲瀷鐧藉悕鍗�
+     * @param startTime    瀹屾垚鏃堕棿涓嬮檺
+     * @param limit        鏈�澶ф潯鏁�
+     * @return 瀛愪换鍔″垪琛�
+     */
+    List<ServiceSubtask> findCompletedInhospFollowups(String orgid, List<String> serviceTypes,
+                                                      java.util.Date startTime, int limit);
+
+    /**
      * 鏇存柊瀛愪换鍔★紙鍘� {@code ServiceSubtaskMapper#updateServiceSubtask}锛屽姩鎬� SQL 鍙敼闈炵┖瀛楁锛�
      *
      * @param subtask 寰呮洿鏂板璞★紙蹇呴』甯� id锛�
diff --git a/ruoyi-task/src/main/java/com/ruoyi/task/api/contract/TaskSubtaskApiImpl.java b/ruoyi-task/src/main/java/com/ruoyi/task/api/contract/TaskSubtaskApiImpl.java
index dc88006..54a73a8 100644
--- a/ruoyi-task/src/main/java/com/ruoyi/task/api/contract/TaskSubtaskApiImpl.java
+++ b/ruoyi-task/src/main/java/com/ruoyi/task/api/contract/TaskSubtaskApiImpl.java
@@ -12,6 +12,7 @@
 import com.ruoyi.task.mapper.ServiceSubtaskMapper;
 import com.ruoyi.task.service.IServiceSubtaskDetailTraceService;
 import com.ruoyi.task.service.IServiceTaskService;
+import com.ruoyi.task.event.FollowupCompletedEventPublisher;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -49,6 +50,9 @@
     @Autowired
     private IServiceSubtaskDetailTraceService traceService;
 
+    @Autowired
+    private FollowupCompletedEventPublisher followupCompletedEventPublisher;
+
     @Override
     public ServiceSubtask getSubtask(Long subId) {
         return serviceSubtaskMapper.selectServiceSubtaskById(subId);
@@ -60,8 +64,18 @@
     }
 
     @Override
+    public List<ServiceSubtask> findCompletedInhospFollowups(String orgid, List<String> serviceTypes,
+                                                             java.util.Date startTime, int limit) {
+        return serviceSubtaskMapper.selectCompletedInhospFollowups(orgid, serviceTypes, startTime, limit);
+    }
+
+    @Override
     public int updateSubtask(ServiceSubtask subtask) {
         Boolean updated = serviceSubtaskMapper.updateServiceSubtask(subtask);
+        if (Boolean.TRUE.equals(updated) && subtask.getSendstate() != null
+                && subtask.getSendstate() == 6 && subtask.getId() != null) {
+            followupCompletedEventPublisher.publish(subtask.getId());
+        }
         return Boolean.TRUE.equals(updated) ? 1 : 0;
     }
 
diff --git a/ruoyi-task/src/main/java/com/ruoyi/task/mapper/ServiceSubtaskMapper.java b/ruoyi-task/src/main/java/com/ruoyi/task/mapper/ServiceSubtaskMapper.java
index 1bbb207..fa5e26e 100644
--- a/ruoyi-task/src/main/java/com/ruoyi/task/mapper/ServiceSubtaskMapper.java
+++ b/ruoyi-task/src/main/java/com/ruoyi/task/mapper/ServiceSubtaskMapper.java
@@ -48,6 +48,20 @@
     public List<ServiceSubtask> selectServiceSubtaskList(ServiceSubtaskEntity serviceSubtaskVO);
 
     /**
+     * 鏌ヨ宸插畬鎴愩�佷笖灏氭湭琚笓绉戞。妗堢敓鎴愭棩蹇楀鐞嗙殑浣忛櫌闅忚瀛愪换鍔★紙琛ュ伩鎵弿鐢級銆�
+     *
+     * @param orgid        鏈烘瀯ID
+     * @param serviceTypes 鏈嶅姟绫诲瀷鐧藉悕鍗�
+     * @param startTime    瀹屾垚鏃堕棿涓嬮檺
+     * @param limit        鏈�澶ф潯鏁�
+     * @return 瀛愪换鍔¢泦鍚�
+     */
+    public List<ServiceSubtask> selectCompletedInhospFollowups(@Param("orgid") String orgid,
+                                                               @Param("serviceTypes") List<String> serviceTypes,
+                                                               @Param("startTime") Date startTime,
+                                                               @Param("limit") int limit);
+
+    /**
      * 鍒嗛〉绗竴闃舵锛氬彧鍙栧綋鍓嶉〉鐨勫瓙浠诲姟 id銆�
      * <p>
      * where / order 涓� {@link #selectServiceSubtaskList} 鍏辩敤鍚屼竴浠� XML 鐗囨
diff --git a/ruoyi-task/src/main/java/com/ruoyi/task/service/impl/ServiceSubtaskServiceImpl.java b/ruoyi-task/src/main/java/com/ruoyi/task/service/impl/ServiceSubtaskServiceImpl.java
index 9f570dc..3ed3fd6 100644
--- a/ruoyi-task/src/main/java/com/ruoyi/task/service/impl/ServiceSubtaskServiceImpl.java
+++ b/ruoyi-task/src/main/java/com/ruoyi/task/service/impl/ServiceSubtaskServiceImpl.java
@@ -126,6 +126,7 @@
 import com.ruoyi.system.service.ISysDeptService;
 import com.ruoyi.system.mapper.ext.SysDept2Mapper;
 import com.ruoyi.task.api.contract.OperationSubtaskWriter;
+import com.ruoyi.task.event.FollowupCompletedEventPublisher;
 
 /**
  * 鍗曚竴浠诲姟锛堥殢璁匡級Service涓氬姟灞傚鐞�
@@ -145,6 +146,9 @@
      */
     @Autowired
     private OperationSubtaskWriter operationSubtaskWriter;
+
+    @Autowired
+    private FollowupCompletedEventPublisher followupCompletedEventPublisher;
 
     /**
      * 婊℃剰搴︽ā鍧楀澶栭棬闈紙甯搁┗ Bean锛夈��
@@ -1544,7 +1548,12 @@
         if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 6)
             serviceSubtask.setFinishtime(new Date());
 
-        return serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
+        Boolean updated = serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
+        if (Boolean.TRUE.equals(updated) && serviceSubtask.getSendstate() != null
+                && serviceSubtask.getSendstate() == 6 && serviceSubtask.getId() != null) {
+            followupCompletedEventPublisher.publish(serviceSubtask.getId());
+        }
+        return updated;
     }
 
     @Override
@@ -4817,6 +4826,7 @@
             serviceSubtask.setSendstate(6L);
             serviceSubtask.setPreachform("1");
             serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
+            followupCompletedEventPublisher.publish(serviceSubtask.getId());
         }
     }
 
@@ -4961,6 +4971,7 @@
         if (subtaskUpdated == 0) {
             throw new BaseException("寰俊鍏紬鍙烽粯璁ゅ畬鎴愬け璐ワ細瀛愪换鍔$姸鎬佸凡鍙樺寲锛宻ubid=" + current.getId());
         }
+        followupCompletedEventPublisher.publish(current.getId());
 
         log.info("銆愬井淇″叕浼楀彿榛樿瀹屾垚銆憇ubid锛歿}锛屽凡鎸夐粯璁ら�夐」瀹屾垚锛屽~鍏呴鐩暟锛歿}", current.getId(), filled);
         return true;
diff --git a/ruoyi-task/src/main/resources/mapper/task/ServiceSubtaskMapper.xml b/ruoyi-task/src/main/resources/mapper/task/ServiceSubtaskMapper.xml
index 789a25d..f7c7bfb 100644
--- a/ruoyi-task/src/main/resources/mapper/task/ServiceSubtaskMapper.xml
+++ b/ruoyi-task/src/main/resources/mapper/task/ServiceSubtaskMapper.xml
@@ -1100,6 +1100,23 @@
         where id = #{id}
     </select>
 
+    <select id="selectCompletedInhospFollowups" resultMap="ServiceSubtaskResult">
+        <include refid="selectServiceSubtaskVo"/>
+        where del_flag = '0'
+          and sendstate = 6
+          and hosp_type in ('2', '6')
+          and orgid = #{orgid}
+          and finishtime &gt;= #{startTime}
+        <if test="serviceTypes != null and serviceTypes.size() > 0">
+            and service_type in
+            <foreach collection="serviceTypes" item="serviceType" open="(" separator="," close=")">
+                #{serviceType}
+            </foreach>
+        </if>
+        order by id asc
+        limit #{limit}
+    </select>
+
     <select id="selectServiceSubtaskByDiagname" parameterType="com.ruoyi.task.domain.ServiceSubtask"
             resultMap="ServiceSubtaskResult">
         select sendstate,starttime,endtime,nurse_name,phone,sex,task_name,sendname,leavediagname,visit_time FROM
diff --git a/smartor/src/main/java/com/smartor/common/SpecificArchiveConstants.java b/smartor/src/main/java/com/smartor/common/SpecificArchiveConstants.java
index ce0c778..10792bb 100644
--- a/smartor/src/main/java/com/smartor/common/SpecificArchiveConstants.java
+++ b/smartor/src/main/java/com/smartor/common/SpecificArchiveConstants.java
@@ -16,6 +16,36 @@
      */
     public static final String DEFAULT_CAMPUS_ID = "1";
 
+    /** 鏉ユ簮绫诲瀷锛氶棬璇婃帴璇婂畬鎴� */
+    public static final String SOURCE_TYPE_OUTHOSP = "1";
+
+    /** 鏉ユ簮绫诲瀷锛氫綇闄㈤殢璁垮畬鎴� */
+    public static final String SOURCE_TYPE_INHOSP_FOLLOWUP = "2";
+
+    /** 鏉ユ簮绫诲瀷锛氭墜宸ユ柊澧�/鎵嬪伐瀵煎叆 */
+    public static final String SOURCE_TYPE_MANUAL = "3";
+
+    /** 閮ㄩ棬鍒嗙被锛氬绉� */
+    public static final String DEPT_CATEGORY_GYNECOLOGY = "1";
+
+    /** 閮ㄩ棬鍒嗙被锛氬効绉� */
+    public static final String DEPT_CATEGORY_PEDIATRICS = "2";
+
+    /** 鐢熸垚缁撴灉锛氬凡鐢熸垚 */
+    public static final String RESULT_GENERATED = "1";
+
+    /** 鐢熸垚缁撴灉锛氭偅鑰呭凡鏈夊搴旀。妗堬紝璺宠繃 */
+    public static final String RESULT_EXISTS = "2";
+
+    /** 鐢熸垚缁撴灉锛氭湭鍛戒腑閰嶇疆 */
+    public static final String RESULT_NO_MATCH = "3";
+
+    /** 鐢熸垚缁撴灉锛氬け璐� */
+    public static final String RESULT_FAILED = "4";
+
+    /** 浣忛櫌闅忚鏉ユ簮鐨勯粯璁ら厤缃甀D锛堟湭鍛戒腑閰嶇疆鏃跺啓鏃ュ織鐢級 */
+    public static final int NO_CONFIG_ID = 0;
+
     private SpecificArchiveConstants() {
     }
 }
diff --git a/smartor/src/main/java/com/smartor/domain/PatChildArchive.java b/smartor/src/main/java/com/smartor/domain/PatChildArchive.java
index 013137d..c300014 100644
--- a/smartor/src/main/java/com/smartor/domain/PatChildArchive.java
+++ b/smartor/src/main/java/com/smartor/domain/PatChildArchive.java
@@ -30,6 +30,23 @@
     @ApiModelProperty(value = "鍎跨妗f绫诲瀷: 1 钀ュ吇鎬х柧鐥�2 瀛︿範鍥伴毦3 楂樺嵄鍎夸笓妗�")
     private String archiveType;
 
+    /** 鏉ユ簮绫诲瀷锛�1闂ㄨ瘖鎺ヨ瘖 2浣忛櫌闅忚 3鎵嬪伐鏂板 */
+    @Excel(name = "鏉ユ簮绫诲瀷")
+    @ApiModelProperty(value = "鏉ユ簮绫诲瀷锛�1闂ㄨ瘖鎺ヨ瘖 2浣忛櫌闅忚 3鎵嬪伐鏂板")
+    private String sourceType;
+
+    /** 鏉ユ簮涓氬姟ID锛氶棬璇婅褰旾D/浣忛櫌璁板綍ID */
+    @ApiModelProperty(value = "鏉ユ簮涓氬姟ID锛氶棬璇婅褰旾D/浣忛櫌璁板綍ID")
+    private Long sourceBizId;
+
+    /** 鏉ユ簮涓氬姟缂栧彿锛氶棬璇婂彿/浣忛櫌鍙� */
+    @ApiModelProperty(value = "鏉ユ簮涓氬姟缂栧彿锛氶棬璇婂彿/浣忛櫌鍙�")
+    private String sourceBizNo;
+
+    /** 鏉ユ簮闅忚瀛愪换鍔D锛氫綇闄㈤殢璁跨敓鎴愭椂璁板綍瑙﹀彂妗f鐢熸垚鐨� service_subtask.id */
+    @ApiModelProperty(value = "鏉ユ簮闅忚瀛愪换鍔D锛氫綇闄㈤殢璁跨敓鎴愭椂璁板綍瑙﹀彂妗f鐢熸垚鐨� service_subtask.id")
+    private Long sourceSubId;
+
     /** 闂ㄨ瘖缂栧彿 */
     @Excel(name = "闂ㄨ瘖缂栧彿")
     @ApiModelProperty(value = "闂ㄨ瘖缂栧彿")
diff --git a/smartor/src/main/java/com/smartor/domain/PatChildArchiveDetail.java b/smartor/src/main/java/com/smartor/domain/PatChildArchiveDetail.java
index a4fce85..c336e02 100644
--- a/smartor/src/main/java/com/smartor/domain/PatChildArchiveDetail.java
+++ b/smartor/src/main/java/com/smartor/domain/PatChildArchiveDetail.java
@@ -35,11 +35,23 @@
     @ApiModelProperty(value = "妗f绫诲瀷: 1 钀ュ吇鎬х柧鐥�2 瀛︿範鍥伴毦3 楂樺嵄鍎夸笓妗�")
     private String archiveType;
 
-    /** 鏉ユ簮绫诲瀷: 1 闂ㄨ瘖璁板綍 */
+    /** 鏉ユ簮绫诲瀷锛�1闂ㄨ瘖鎺ヨ瘖 2浣忛櫌闅忚 3鎵嬪伐鏂板 */
     @Excel(name = "鏉ユ簮绫诲瀷")
-    @ApiModelProperty(value = "鏉ユ簮绫诲瀷: 1 闂ㄨ瘖璁板綍")
+    @ApiModelProperty(value = "鏉ユ簮绫诲瀷锛�1闂ㄨ瘖鎺ヨ瘖 2浣忛櫌闅忚 3鎵嬪伐鏂板")
     private String sourceType;
 
+    /** 鏉ユ簮涓氬姟ID锛氶棬璇婅褰旾D/浣忛櫌璁板綍ID */
+    @ApiModelProperty(value = "鏉ユ簮涓氬姟ID锛氶棬璇婅褰旾D/浣忛櫌璁板綍ID")
+    private Long sourceBizId;
+
+    /** 鏉ユ簮涓氬姟缂栧彿锛氶棬璇婂彿/浣忛櫌鍙� */
+    @ApiModelProperty(value = "鏉ユ簮涓氬姟缂栧彿锛氶棬璇婂彿/浣忛櫌鍙�")
+    private String sourceBizNo;
+
+    /** 鏉ユ簮闅忚瀛愪换鍔D锛氫綇闄㈤殢璁跨敓鎴愭椂璁板綍瑙﹀彂妗f鐢熸垚鐨� service_subtask.id */
+    @ApiModelProperty(value = "鏉ユ簮闅忚瀛愪换鍔D锛氫綇闄㈤殢璁跨敓鎴愭椂璁板綍瑙﹀彂妗f鐢熸垚鐨� service_subtask.id")
+    private Long sourceSubId;
+
     /** 闂ㄨ瘖缂栧彿 */
     @Excel(name = "闂ㄨ瘖缂栧彿")
     @ApiModelProperty(value = "闂ㄨ瘖缂栧彿")
diff --git a/smartor/src/main/java/com/smartor/domain/PatMaternityArchive.java b/smartor/src/main/java/com/smartor/domain/PatMaternityArchive.java
index 6d48ea4..30a1c29 100644
--- a/smartor/src/main/java/com/smartor/domain/PatMaternityArchive.java
+++ b/smartor/src/main/java/com/smartor/domain/PatMaternityArchive.java
@@ -29,6 +29,23 @@
     @ApiModelProperty(value = "濡囧辜妗f绫诲瀷: 1 鏃╁瓡鍏崇埍2 鍥寸粷缁忔湡MHI")
     private String archiveType;
 
+    /** 鏉ユ簮绫诲瀷锛�1闂ㄨ瘖鎺ヨ瘖 2浣忛櫌闅忚 3鎵嬪伐鏂板 */
+    @Excel(name = "鏉ユ簮绫诲瀷")
+    @ApiModelProperty(value = "鏉ユ簮绫诲瀷锛�1闂ㄨ瘖鎺ヨ瘖 2浣忛櫌闅忚 3鎵嬪伐鏂板")
+    private String sourceType;
+
+    /** 鏉ユ簮涓氬姟ID锛氶棬璇婅褰旾D/浣忛櫌璁板綍ID */
+    @ApiModelProperty(value = "鏉ユ簮涓氬姟ID锛氶棬璇婅褰旾D/浣忛櫌璁板綍ID")
+    private Long sourceBizId;
+
+    /** 鏉ユ簮涓氬姟缂栧彿锛氶棬璇婂彿/浣忛櫌鍙� */
+    @ApiModelProperty(value = "鏉ユ簮涓氬姟缂栧彿锛氶棬璇婂彿/浣忛櫌鍙�")
+    private String sourceBizNo;
+
+    /** 鏉ユ簮闅忚瀛愪换鍔D锛氫綇闄㈤殢璁跨敓鎴愭椂璁板綍瑙﹀彂妗f鐢熸垚鐨� service_subtask.id */
+    @ApiModelProperty(value = "鏉ユ簮闅忚瀛愪换鍔D锛氫綇闄㈤殢璁跨敓鎴愭椂璁板綍瑙﹀彂妗f鐢熸垚鐨� service_subtask.id")
+    private Long sourceSubId;
+
     /** 闂ㄨ瘖缂栧彿 */
     @Excel(name = "闂ㄨ瘖缂栧彿")
     @ApiModelProperty(value = "闂ㄨ瘖缂栧彿")
diff --git a/smartor/src/main/java/com/smartor/domain/PatMaternityArchiveDetail.java b/smartor/src/main/java/com/smartor/domain/PatMaternityArchiveDetail.java
index af5f83b..79480fe 100644
--- a/smartor/src/main/java/com/smartor/domain/PatMaternityArchiveDetail.java
+++ b/smartor/src/main/java/com/smartor/domain/PatMaternityArchiveDetail.java
@@ -34,11 +34,23 @@
     @ApiModelProperty(value = "妗f绫诲瀷: 1 鏃╁瓡鍏崇埍2 鍥寸粷缁忔湡MHI")
     private String archiveType;
 
-    /** 鏉ユ簮绫诲瀷: 1 闂ㄨ瘖璁板綍 */
+    /** 鏉ユ簮绫诲瀷锛�1闂ㄨ瘖鎺ヨ瘖 2浣忛櫌闅忚 3鎵嬪伐鏂板 */
     @Excel(name = "鏉ユ簮绫诲瀷")
-    @ApiModelProperty(value = "鏉ユ簮绫诲瀷: 1 闂ㄨ瘖璁板綍")
+    @ApiModelProperty(value = "鏉ユ簮绫诲瀷锛�1闂ㄨ瘖鎺ヨ瘖 2浣忛櫌闅忚 3鎵嬪伐鏂板")
     private String sourceType;
 
+    /** 鏉ユ簮涓氬姟ID锛氶棬璇婅褰旾D/浣忛櫌璁板綍ID */
+    @ApiModelProperty(value = "鏉ユ簮涓氬姟ID锛氶棬璇婅褰旾D/浣忛櫌璁板綍ID")
+    private Long sourceBizId;
+
+    /** 鏉ユ簮涓氬姟缂栧彿锛氶棬璇婂彿/浣忛櫌鍙� */
+    @ApiModelProperty(value = "鏉ユ簮涓氬姟缂栧彿锛氶棬璇婂彿/浣忛櫌鍙�")
+    private String sourceBizNo;
+
+    /** 鏉ユ簮闅忚瀛愪换鍔D锛氫綇闄㈤殢璁跨敓鎴愭椂璁板綍瑙﹀彂妗f鐢熸垚鐨� service_subtask.id */
+    @ApiModelProperty(value = "鏉ユ簮闅忚瀛愪换鍔D锛氫綇闄㈤殢璁跨敓鎴愭椂璁板綍瑙﹀彂妗f鐢熸垚鐨� service_subtask.id")
+    private Long sourceSubId;
+
     /** 闂ㄨ瘖缂栧彿 */
     @Excel(name = "闂ㄨ瘖缂栧彿")
     @ApiModelProperty(value = "闂ㄨ瘖缂栧彿")
diff --git a/smartor/src/main/java/com/smartor/service/IPatSpecificArchiveGenerateService.java b/smartor/src/main/java/com/smartor/service/IPatSpecificArchiveGenerateService.java
index 4ad425f..f25a083 100644
--- a/smartor/src/main/java/com/smartor/service/IPatSpecificArchiveGenerateService.java
+++ b/smartor/src/main/java/com/smartor/service/IPatSpecificArchiveGenerateService.java
@@ -19,4 +19,22 @@
      * @return 鏈鐢熸垚/鏇存柊鐨勬。妗堟暟閲�
      */
     int generateByOuthosp(PatMedOuthosp patMedOuthosp, PatArchive patArchive);
+
+    /**
+     * 鏍规嵁浣忛櫌闅忚瀛愪换鍔$敓鎴愪笓绉戞。妗堛��
+     *
+     * <p>浠呭鐞嗗凡瀹屾垚鐨勪綇闄㈤殢璁匡紙hosp_type 2/6 + service_type 鐧藉悕鍗曪級锛�
+     * 涓斾粎瀵逛附姘村競濡囧辜淇濆仴闄㈢敓鏁堛�傜敓鎴愬墠鎸夆�滄偅鑰� + 涓撶 + 妗f绫诲瀷鈥濆垽鏂槸鍚﹀凡鏈夋。妗堛��</p>
+     *
+     * @param subId 闅忚瀛愪换鍔D
+     * @return 鏈鐢熸垚鏁伴噺
+     */
+    int generateByInhospFollowup(Long subId);
+
+    /**
+     * 琛ュ伩鎵弿锛氭煡璇㈣繎 7 澶╁凡瀹屾垚浣嗗皻鏈鐞嗙殑浣忛櫌闅忚骞跺皾璇曠敓鎴愭。妗堛��
+     *
+     * @return 鏈鐢熸垚鏁伴噺
+     */
+    int compensateInhospFollowups();
 }
diff --git a/smartor/src/main/java/com/smartor/service/impl/PatChildArchiveServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/PatChildArchiveServiceImpl.java
index 4dd9148..9ccd188 100644
--- a/smartor/src/main/java/com/smartor/service/impl/PatChildArchiveServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/PatChildArchiveServiceImpl.java
@@ -88,8 +88,9 @@
             log.error("insertOrUpdateChildArchive鍏ュ弬涓虹┖锛岃妫�鏌ュ叆鍙�");
             throw new BaseException("鍎跨妗f鍏ュ弬涓虹┖锛岃妫�鏌ュ叆鍙�");
         }
-        if (StringUtils.isEmpty(patChildArchiveDetail.getOuthospno())) {
-            throw new BaseException("鍎跨妗f鍏ュ弬闂ㄨ瘖缂栧彿outhospno涓虹┖锛岃妫�鏌ュ叆鍙傞棬璇婄紪鍙�");
+        if (StringUtils.isEmpty(patChildArchiveDetail.getOuthospno())
+                && StringUtils.isEmpty(patChildArchiveDetail.getInhospno())) {
+            throw new BaseException("鍎跨妗f鍏ュ弬闂ㄨ瘖缂栧彿outhospno鍜屼綇闄㈢紪鍙穒nhospno涓嶈兘鍚屾椂涓虹┖");
         }
         if (StringUtils.isEmpty(patChildArchiveDetail.getArchiveType())) {
             throw new BaseException("鍎跨妗f鍏ュ弬妗f绫诲瀷archiveType涓虹┖锛岃妫�鏌ュ叆鍙傛。妗堢被鍨�");
@@ -100,6 +101,7 @@
         key.setOrgid(patChildArchiveDetail.getOrgid());
         key.setPatid(patChildArchiveDetail.getPatid());
         key.setOuthospno(patChildArchiveDetail.getOuthospno());
+        key.setInhospno(patChildArchiveDetail.getInhospno());
         key.setArchiveType(patChildArchiveDetail.getArchiveType());
         List<PatChildArchiveDetail> olds =
                 patChildArchiveDetailService.selectPatChildArchiveDetailList(key);
@@ -117,6 +119,7 @@
             mainKey.setOrgid(patChildArchiveDetail.getOrgid());
             mainKey.setPatid(patChildArchiveDetail.getPatid());
             mainKey.setOuthospno(patChildArchiveDetail.getOuthospno());
+            mainKey.setInhospno(patChildArchiveDetail.getInhospno());
             mainKey.setArchiveType(patChildArchiveDetail.getArchiveType());
             List<PatChildArchive> mainOlds =
                     patChildArchiveMapper.selectPatChildArchiveList(mainKey);
@@ -133,6 +136,17 @@
         }
 
 
+        // 鏂板妗f鏃惰ˉ榛樿鏉ユ簮锛屾洿鏂版椂淇濈暀鍘熸潵婧�
+        if (existArchiveId == null && patChildArchiveDetail.getId() == null) {
+            if (StringUtils.isEmpty(patChildArchiveDetail.getSourceType())) {
+                patChildArchiveDetail.setSourceType("3");
+            }
+            if (StringUtils.isEmpty(patChildArchiveDetail.getSourceBizNo())) {
+                patChildArchiveDetail.setSourceBizNo(StringUtils.isNotEmpty(patChildArchiveDetail.getOuthospno())
+                        ? patChildArchiveDetail.getOuthospno() : patChildArchiveDetail.getInhospno());
+            }
+        }
+
         // 灏嗚鎯呬腑鐨勫叕鍏卞瓧娈靛鍒跺埌涓昏〃瀵硅薄
         PatChildArchive patChildArchive = DtoConversionUtils.sourceToTarget(patChildArchiveDetail, PatChildArchive.class);
         if (patChildArchive == null) {
diff --git a/smartor/src/main/java/com/smartor/service/impl/PatMaternityArchiveServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/PatMaternityArchiveServiceImpl.java
index cea1042..e7744d3 100644
--- a/smartor/src/main/java/com/smartor/service/impl/PatMaternityArchiveServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/PatMaternityArchiveServiceImpl.java
@@ -99,13 +99,15 @@
         patMaternityArchiveDetailVo.setOrgid(patMaternityArchiveDetail.getOrgid());
         patMaternityArchiveDetailVo.setPatid(patMaternityArchiveDetail.getPatid());
         patMaternityArchiveDetailVo.setOuthospno(patMaternityArchiveDetail.getOuthospno());
+        patMaternityArchiveDetailVo.setInhospno(patMaternityArchiveDetail.getInhospno());
         patMaternityArchiveDetailVo.setArchiveType(patMaternityArchiveDetail.getArchiveType());
         List<PatMaternityArchiveDetail> patMaternityArchiveDetailOlds
                 = patMaternityArchiveDetailService.selectPatMaternityArchiveDetailList(patMaternityArchiveDetailVo);
 
 
-        if (StringUtils.isEmpty(patMaternityArchiveDetail.getOuthospno())) {
-            throw new BaseException("濡囩妗f鍏ュ弬闂ㄨ瘖缂栧彿outhospno涓虹┖锛岃妫�鏌ュ叆鍙傞棬璇婄紪鍙�");
+        if (StringUtils.isEmpty(patMaternityArchiveDetail.getOuthospno())
+                && StringUtils.isEmpty(patMaternityArchiveDetail.getInhospno())) {
+            throw new BaseException("濡囩妗f鍏ュ弬闂ㄨ瘖缂栧彿outhospno鍜屼綇闄㈢紪鍙穒nhospno涓嶈兘鍚屾椂涓虹┖");
         }
         if (StringUtils.isEmpty(patMaternityArchiveDetail.getArchiveType())) {
             throw new BaseException("濡囩妗f鍏ュ弬妗f绫诲瀷archiveType涓虹┖锛岃妫�鏌ュ叆鍙傛。妗堢被鍨�");
@@ -116,6 +118,7 @@
         key.setOrgid(patMaternityArchiveDetail.getOrgid());
         key.setPatid(patMaternityArchiveDetail.getPatid());
         key.setOuthospno(patMaternityArchiveDetail.getOuthospno());
+        key.setInhospno(patMaternityArchiveDetail.getInhospno());
         key.setArchiveType(patMaternityArchiveDetail.getArchiveType());
         List<PatMaternityArchiveDetail> olds =
                 patMaternityArchiveDetailService.selectPatMaternityArchiveDetailList(key);
@@ -133,6 +136,7 @@
             mainKey.setOrgid(patMaternityArchiveDetail.getOrgid());
             mainKey.setPatid(patMaternityArchiveDetail.getPatid());
             mainKey.setOuthospno(patMaternityArchiveDetail.getOuthospno());
+            mainKey.setInhospno(patMaternityArchiveDetail.getInhospno());
             mainKey.setArchiveType(patMaternityArchiveDetail.getArchiveType());
             List<PatMaternityArchive> mainOlds =
                     patMaternityArchiveMapper.selectPatMaternityArchiveList(mainKey);
@@ -156,6 +160,17 @@
             }
         }
 
+        // 鏂板妗f鏃惰ˉ榛樿鏉ユ簮锛屾洿鏂版椂淇濈暀鍘熸潵婧�
+        if (existArchiveId == null && patMaternityArchiveDetail.getId() == null) {
+            if (StringUtils.isEmpty(patMaternityArchiveDetail.getSourceType())) {
+                patMaternityArchiveDetail.setSourceType("3");
+            }
+            if (StringUtils.isEmpty(patMaternityArchiveDetail.getSourceBizNo())) {
+                patMaternityArchiveDetail.setSourceBizNo(StringUtils.isNotEmpty(patMaternityArchiveDetail.getOuthospno())
+                        ? patMaternityArchiveDetail.getOuthospno() : patMaternityArchiveDetail.getInhospno());
+            }
+        }
+
         // 灏嗚鎯呬腑鐨勫叕鍏卞瓧娈靛鍒跺埌涓昏〃瀵硅薄
         PatMaternityArchive patMaternityArchive = DtoConversionUtils.sourceToTarget(patMaternityArchiveDetail, PatMaternityArchive.class);
         if (patMaternityArchive == null) {
diff --git a/smartor/src/main/java/com/smartor/service/impl/PatSpecificArchiveGenerateServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/PatSpecificArchiveGenerateServiceImpl.java
index d0c7d20..ee787a2 100644
--- a/smartor/src/main/java/com/smartor/service/impl/PatSpecificArchiveGenerateServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/PatSpecificArchiveGenerateServiceImpl.java
@@ -3,20 +3,31 @@
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.ruoyi.common.core.domain.entity.PatArchive;
+import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.inhospvisit.api.InhospVisitFacade;
+import com.ruoyi.inhospvisit.domain.PatMedInhosp;
 import com.ruoyi.outpatientvisit.domain.PatMedOuthosp;
 import com.ruoyi.patarchive.domain.PatSpecificArchiveGenerateConfig;
 import com.ruoyi.patarchive.mapper.PatArchiveMapper;
 import com.ruoyi.patarchive.service.IPatSpecificArchiveGenerateConfigService;
+import com.ruoyi.task.api.TaskSubtaskApi;
+import com.ruoyi.task.domain.ServiceSubtask;
+import com.ruoyi.task.service.IServiceSubtaskService;
 import com.smartor.common.SpecificArchiveConstants;
+import com.smartor.domain.PatChildArchive;
 import com.smartor.domain.PatChildArchiveDetail;
+import com.smartor.domain.PatMaternityArchive;
 import com.smartor.domain.PatMaternityArchiveDetail;
+import com.smartor.domain.PatSpecificArchiveGenerateLog;
 import com.smartor.service.IPatChildArchiveService;
 import com.smartor.service.IPatMaternityArchiveService;
+import com.smartor.service.IPatSpecificArchiveGenerateLogService;
 import com.smartor.service.IPatSpecificArchiveGenerateService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
@@ -26,27 +37,37 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
  * 涓撶妗f鐢熸垚Service涓氬姟灞傚鐞嗐��
  *
- * <p>鍙鐞嗕附姘村競濡囧辜淇濆仴闄紙orgid = 47226079133110211G1001锛夌殑闂ㄨ瘖鎺ヨ瘖瀹屾垚璁板綍锛�
- * 鎸� {@code pat_specific_archive_generate_config} 閰嶇疆鍖归厤绉戝鍜岃瘖鏂悗锛�
- * 鐢熸垚瀵瑰簲绫诲瀷鐨勫绉戞。妗堟垨鍎跨妗f銆�</p>
+ * <p>鍙鐞嗕附姘村競濡囧辜淇濆仴闄紙orgid = 47226079133110211G1001锛夛細</p>
+ * <ul>
+ *     <li>闂ㄨ瘖鎺ヨ瘖瀹屾垚锛氭寜绉戝/璇婃柇鍖归厤閰嶇疆鍚庣敓鎴愬绉�/鍎跨妗f锛�</li>
+ *     <li>浣忛櫌闅忚瀹屾垚锛氭寜鍑洪櫌/鍦ㄩ櫌绉戝銆佺梾鍖恒�佽瘖鏂尮閰嶉厤缃悗鐢熸垚濡囩/鍎跨妗f锛�
+ *     鐢熸垚鍓嶆寜鈥滄偅鑰� + 涓撶 + 妗f绫诲瀷鈥濆垽鏂槸鍚﹀凡鏈夊搴旀。妗堬紝宸叉湁鍒欒烦杩囥��</li>
+ * </ul>
  */
 @Slf4j
 @Service
 public class PatSpecificArchiveGenerateServiceImpl implements IPatSpecificArchiveGenerateService {
 
-    /** 閮ㄩ棬鍒嗙被锛氬绉� */
-    private static final String DEPT_CATEGORY_GYNECOLOGY = "1";
-    /** 閮ㄩ棬鍒嗙被锛氬効绉� */
-    private static final String DEPT_CATEGORY_PEDIATRICS = "2";
     /** 閮ㄩ棬绫诲瀷锛氱瀹� */
     private static final String DEPT_TYPE_DEPARTMENT = "1";
-    /** 鏉ユ簮绫诲瀷锛氶棬璇婅褰� */
-    private static final String SOURCE_TYPE_OUTHOSP = "1";
+    /** 閮ㄩ棬绫诲瀷锛氱梾鍖� */
+    private static final String DEPT_TYPE_WARD = "2";
+    /** 灏辫瘖绫诲瀷锛氬嚭闄� */
+    private static final String HOSP_TYPE_DISCHARGE = "2";
+    /** 灏辫瘖绫诲瀷锛氫綇闄�/鍏ラ櫌 */
+    private static final String HOSP_TYPE_INHOSP = "6";
+    /** 浣忛櫌闅忚瀹屾垚鐘舵�� */
+    private static final Long SEND_STATE_FINISHED = 6L;
+    /** 浣忛櫌闅忚妗f鐢熸垚鐨勬渶澶ч噸璇曟鏁� */
+    private static final int MAX_RETRY = 3;
+    /** Redis 閿佸墠缂� */
+    private static final String LOCK_PREFIX = "lock:archive:inhosp:";
 
     @Autowired
     private IPatSpecificArchiveGenerateConfigService patSpecificArchiveGenerateConfigService;
@@ -58,7 +79,32 @@
     private IPatChildArchiveService patChildArchiveService;
 
     @Autowired
+    private IPatSpecificArchiveGenerateLogService patSpecificArchiveGenerateLogService;
+
+    @Autowired
     private PatArchiveMapper patArchiveMapper;
+
+    @Autowired
+    private IServiceSubtaskService serviceSubtaskService;
+
+    @Autowired
+    private InhospVisitFacade inhospVisitFacade;
+
+    @Autowired
+    private TaskSubtaskApi taskSubtaskApi;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 浣忛櫌闅忚鏈嶅姟绫诲瀷鐧藉悕鍗曪紝榛樿鍑洪櫌闅忚銆佷笓绉戦殢璁裤�佸叆闄㈤殢璁裤�佹墜鏈殢璁裤��
+     */
+    @Value("${archive.inhosp.followup.service-types:2,13,18,19}")
+    private String inhospFollowupServiceTypes;
+
+    /** 浣忛櫌闅忚鐢熸垚涓撶妗f寮�鍏筹紝榛樿寮�鍚紝渚夸簬鎸夋満鏋勭伆搴︺�� */
+    @Value("${archive.inhosp.followup.enabled:true}")
+    private boolean inhospFollowupEnabled;
 
     @Override
     public int generateByOuthosp(PatMedOuthosp patMedOuthosp, PatArchive patArchive) {
@@ -86,7 +132,7 @@
         }
 
         String campusid = StringUtils.isNotBlank(patMedOuthosp.getCampusid())
-                ? patMedOuthosp.getCampusid() : "1";
+                ? patMedOuthosp.getCampusid() : SpecificArchiveConstants.DEFAULT_CAMPUS_ID;
         List<PatSpecificArchiveGenerateConfig> configs =
                 patSpecificArchiveGenerateConfigService.selectEffectiveConfigList(patMedOuthosp.getOrgid(), campusid);
         if (CollectionUtils.isEmpty(configs)) {
@@ -99,7 +145,8 @@
         Set<String> generatedKeys = new HashSet<>();
         int generatedCount = 0;
         for (PatSpecificArchiveGenerateConfig config : configs) {
-            if (!matchConfig(config, patMedOuthosp)) {
+            if (!matchConfig(config, patMedOuthosp.getDeptcode(), null,
+                    patMedOuthosp.getIcd10code(), patMedOuthosp.getDiagname())) {
                 continue;
             }
             String archiveType = config.getArchiveType();
@@ -116,12 +163,12 @@
             }
 
             try {
-                if (DEPT_CATEGORY_GYNECOLOGY.equals(deptCategory)) {
+                if (SpecificArchiveConstants.DEPT_CATEGORY_GYNECOLOGY.equals(deptCategory)) {
                     PatMaternityArchiveDetail detail =
                             buildMaternityDetail(patMedOuthosp, targetArchive, config, campusid);
                     patMaternityArchiveService.insertOrUpdateMaternityArchive(detail);
                     generatedCount++;
-                } else if (DEPT_CATEGORY_PEDIATRICS.equals(deptCategory)) {
+                } else if (SpecificArchiveConstants.DEPT_CATEGORY_PEDIATRICS.equals(deptCategory)) {
                     PatChildArchiveDetail detail =
                             buildChildDetail(patMedOuthosp, targetArchive, config, campusid);
                     patChildArchiveService.insertOrUpdateChildArchive(detail);
@@ -138,12 +185,276 @@
         return generatedCount;
     }
 
+    @Override
+    public int generateByInhospFollowup(Long subId) {
+        if (!inhospFollowupEnabled || subId == null) {
+            return 0;
+        }
+        ServiceSubtask subtask = serviceSubtaskService.selectServiceSubtaskById(subId);
+        if (subtask == null || !SEND_STATE_FINISHED.equals(subtask.getSendstate())) {
+            return 0;
+        }
+        if (!isInhospFollowup(subtask)) {
+            return 0;
+        }
+
+        // 浠呴檺涓芥按濡囧辜锛屾満鏋勪负绌烘椂鐢ㄤ綇闄㈣褰�/鎮h�呮。妗堝厹搴�
+        PatMedInhosp inhosp = resolveInhosp(subtask);
+        PatArchive patArchive = resolvePatArchive(subtask.getPatid(), inhosp);
+        String orgid = firstNotBlank(subtask.getOrgid(),
+                inhosp == null ? null : inhosp.getOrgid(),
+                patArchive == null ? null : patArchive.getOrgid());
+        if (!SpecificArchiveConstants.LISHUI_MCH_ORG_ID.equals(orgid)) {
+            log.debug("浣忛櫌闅忚鐢熸垚涓撶妗f璺宠繃锛氶潪涓芥按濡囧辜鏈烘瀯锛宻ubId={}锛宱rgid={}", subId, orgid);
+            return 0;
+        }
+
+        Long patid = firstNonNull(subtask.getPatid(),
+                inhosp == null ? null : inhosp.getPatid(),
+                patArchive == null ? null : patArchive.getId());
+        if (patid == null) {
+            log.warn("浣忛櫌闅忚鐢熸垚涓撶妗f璺宠繃锛氭湭鎵惧埌鎮h�咃紝subId={}锛宨nhospid={}", subId, subtask.getInhospid());
+            return 0;
+        }
+        if (patArchive == null) {
+            patArchive = patArchiveMapper.selectPatArchiveByPatid(patid);
+        }
+
+        String campusid = firstNotBlank(subtask.getCampusid(),
+                inhosp == null ? null : inhosp.getCampusid(),
+                patArchive == null ? null : patArchive.getCampusid(),
+                SpecificArchiveConstants.DEFAULT_CAMPUS_ID);
+
+        boolean admission = HOSP_TYPE_INHOSP.equals(subtask.getHospType());
+        String deptCode = admission
+                ? firstNotBlank(inhosp == null ? null : inhosp.getDeptcode(), subtask.getDeptcode(),
+                subtask.getVisitDeptCode(), subtask.getLeaveldeptcode())
+                : firstNotBlank(inhosp == null ? null : inhosp.getLeaveldeptcode(), subtask.getLeaveldeptcode(),
+                subtask.getVisitDeptCode(), inhosp == null ? null : inhosp.getDeptcode());
+        String deptName = admission
+                ? firstNotBlank(inhosp == null ? null : inhosp.getDeptname(), subtask.getDeptname(),
+                subtask.getVisitDeptName(), subtask.getLeaveldeptname())
+                : firstNotBlank(inhosp == null ? null : inhosp.getLeaveldeptname(), subtask.getLeaveldeptname(),
+                subtask.getVisitDeptName(), inhosp == null ? null : inhosp.getDeptname());
+        String wardCode = admission
+                ? firstNotBlank(inhosp == null ? null : inhosp.getHospitaldistrictcode(),
+                subtask.getHospitaldistrictcode(), subtask.getLeavehospitaldistrictcode())
+                : firstNotBlank(inhosp == null ? null : inhosp.getLeavehospitaldistrictcode(),
+                subtask.getLeavehospitaldistrictcode(), subtask.getHospitaldistrictcode());
+        String wardName = admission
+                ? firstNotBlank(inhosp == null ? null : inhosp.getHospitaldistrictname(),
+                subtask.getHospitaldistrictname(), subtask.getLeavehospitaldistrictname())
+                : firstNotBlank(inhosp == null ? null : inhosp.getLeavehospitaldistrictname(),
+                subtask.getLeavehospitaldistrictname(), subtask.getHospitaldistrictname());
+        String icd10Code = admission
+                ? firstNotBlank(inhosp == null ? null : inhosp.getIcd10code(), subtask.getLeaveicd10code())
+                : firstNotBlank(inhosp == null ? null : inhosp.getLeaveicd10code(),
+                subtask.getLeaveicd10code(), inhosp == null ? null : inhosp.getIcd10code());
+        String diagName = admission
+                ? firstNotBlank(inhosp == null ? null : inhosp.getDiagname(), subtask.getDiagname())
+                : firstNotBlank(inhosp == null ? null : inhosp.getLeavediagname(),
+                subtask.getLeavediagname(), inhosp == null ? null : inhosp.getDiagname());
+
+        InhospArchiveContext context = new InhospArchiveContext();
+        context.subtask = subtask;
+        context.inhosp = inhosp;
+        context.patArchive = patArchive;
+        context.patid = patid;
+        context.orgid = orgid;
+        context.campusid = campusid;
+        context.deptCode = deptCode;
+        context.deptName = deptName;
+        context.wardCode = wardCode;
+        context.wardName = wardName;
+        context.icd10Code = icd10Code;
+        context.diagName = diagName;
+        context.diagTime = firstDate(subtask.getFinishtime(), inhosp == null ? null : inhosp.getEndtime());
+
+        List<PatSpecificArchiveGenerateConfig> configs =
+                patSpecificArchiveGenerateConfigService.selectEffectiveConfigList(orgid, campusid);
+        if (CollectionUtils.isEmpty(configs)) {
+            recordLog(context, null, null, null, SpecificArchiveConstants.RESULT_NO_MATCH, null,
+                    "鏈烘瀯鏈厤缃。妗堢敓鎴愯鍒�");
+            return 0;
+        }
+
+        Set<String> generatedKeys = new HashSet<>();
+        int generatedCount = 0;
+        boolean anyMatched = false;
+        for (PatSpecificArchiveGenerateConfig config : configs) {
+            String archiveType = config.getArchiveType();
+            String deptCategory = config.getDeptCategory();
+            if (StringUtils.isBlank(archiveType) || StringUtils.isBlank(deptCategory)) {
+                log.warn("浣忛櫌闅忚鐢熸垚涓撶妗f璺宠繃锛氶厤缃笉瀹屾暣锛宑onfigId={}锛宒eptCategory={}锛宎rchiveType={}",
+                        config.getId(), deptCategory, archiveType);
+                continue;
+            }
+            if (!matchConfig(config, deptCode, wardCode, icd10Code, diagName)) {
+                continue;
+            }
+            anyMatched = true;
+            String generatedKey = deptCategory + "|" + archiveType;
+            if (!generatedKeys.add(generatedKey)) {
+                continue;
+            }
+            if (alreadyProcessed(subId, config.getId())) {
+                continue;
+            }
+
+            String lockKey = LOCK_PREFIX + orgid + ":" + patid + ":" + deptCategory + ":" + archiveType;
+            boolean locked = false;
+            try {
+                locked = redisCache.setCacheObjectIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
+            } catch (Exception e) {
+                // Redis 涓嶅彲鐢ㄦ椂 fail-open锛屼緷璧栫敓鎴愭棩蹇楀拰鏁版嵁搴撴煡璇㈠厹搴曪紝閬垮厤妗f鐢熸垚鏁翠綋鍋滄憜
+                locked = true;
+                log.warn("浣忛櫌闅忚鐢熸垚涓撶妗f鑾峰彇Redis閿佸紓甯革紝闄嶇骇涓烘棤閿佹墽琛岋紝subId={}锛宭ockKey={}", subId, lockKey, e);
+            }
+            if (!locked) {
+                // 鏈嬁鍒伴攣鏃剁敱琛ュ伩浠诲姟閲嶈瘯锛岄伩鍏嶅苟鍙戦噸澶嶇敓鎴�
+                log.info("浣忛櫌闅忚鐢熸垚涓撶妗f鏈幏鍙栧埌閿侊紝绛夊緟琛ュ伩閲嶈瘯锛宻ubId={}锛宭ockKey={}", subId, lockKey);
+                recordLog(context, config, deptCategory, archiveType, SpecificArchiveConstants.RESULT_FAILED,
+                        null, "鑾峰彇鐢熸垚閿佸け璐�");
+                continue;
+            }
+
+            try {
+                Long existingArchiveId = findExistingArchiveId(orgid, patid, deptCategory, archiveType);
+                if (existingArchiveId != null) {
+                    recordLog(context, config, deptCategory, archiveType,
+                            SpecificArchiveConstants.RESULT_EXISTS, existingArchiveId, "鎮h�呭凡鏈夊搴旀。妗堬紝璺宠繃鐢熸垚");
+                    continue;
+                }
+
+                Long archiveId;
+                if (SpecificArchiveConstants.DEPT_CATEGORY_GYNECOLOGY.equals(deptCategory)) {
+                    PatMaternityArchiveDetail detail = buildInhospMaternityDetail(context, config);
+                    archiveId = (long) patMaternityArchiveService.insertOrUpdateMaternityArchive(detail);
+                } else if (SpecificArchiveConstants.DEPT_CATEGORY_PEDIATRICS.equals(deptCategory)) {
+                    PatChildArchiveDetail detail = buildInhospChildDetail(context, config);
+                    archiveId = (long) patChildArchiveService.insertOrUpdateChildArchive(detail);
+                } else {
+                    log.warn("浣忛櫌闅忚鐢熸垚涓撶妗f璺宠繃锛氭湭鐭ラ儴闂ㄥ垎绫伙紝configId={}锛宒eptCategory={}",
+                            config.getId(), deptCategory);
+                    continue;
+                }
+                recordLog(context, config, deptCategory, archiveType,
+                        SpecificArchiveConstants.RESULT_GENERATED, archiveId, "鐢熸垚鎴愬姛");
+                generatedCount++;
+            } catch (Exception e) {
+                log.error("浣忛櫌闅忚鐢熸垚涓撶妗f澶辫触锛宻ubId={}锛宑onfigId={}锛宒eptCategory={}锛宎rchiveType={}",
+                        subId, config.getId(), deptCategory, archiveType, e);
+                recordLog(context, config, deptCategory, archiveType,
+                        SpecificArchiveConstants.RESULT_FAILED, null, truncateMsg(e.getMessage()));
+            } finally {
+                if (locked) {
+                    try {
+                        redisCache.deleteObject(lockKey);
+                    } catch (Exception e) {
+                        log.warn("浣忛櫌闅忚鐢熸垚涓撶妗f閲婃斁Redis閿佸紓甯革紝lockKey={}", lockKey, e);
+                    }
+                }
+            }
+        }
+
+        if (!anyMatched) {
+            recordLog(context, null, null, null, SpecificArchiveConstants.RESULT_NO_MATCH, null,
+                    "鏈懡涓瀹�/鐥呭尯/璇婃柇閰嶇疆");
+        }
+        return generatedCount;
+    }
+
+    @Override
+    public int compensateInhospFollowups() {
+        if (!inhospFollowupEnabled) {
+            return 0;
+        }
+        List<String> serviceTypes = parseCsv(inhospFollowupServiceTypes);
+        if (CollectionUtils.isEmpty(serviceTypes)) {
+            return 0;
+        }
+        Date startTime = new Date(System.currentTimeMillis() - 7L * 24 * 60 * 60 * 1000);
+        List<ServiceSubtask> subtasks = taskSubtaskApi.findCompletedInhospFollowups(
+                SpecificArchiveConstants.LISHUI_MCH_ORG_ID, serviceTypes, startTime, 200);
+        if (CollectionUtils.isEmpty(subtasks)) {
+            return 0;
+        }
+        int generated = 0;
+        for (ServiceSubtask subtask : subtasks) {
+            if (subtask.getId() == null
+                    || patSpecificArchiveGenerateLogService.existsProcessedBySourceSub(
+                    SpecificArchiveConstants.SOURCE_TYPE_INHOSP_FOLLOWUP, subtask.getId())) {
+                continue;
+            }
+            try {
+                generated += generateByInhospFollowup(subtask.getId());
+            } catch (Exception e) {
+                log.error("琛ュ伩鐢熸垚浣忛櫌闅忚涓撶妗f澶辫触锛宻ubId={}", subtask.getId(), e);
+            }
+        }
+        return generated;
+    }
+
     /**
-     * 鍒ゆ柇闂ㄨ瘖璁板綍鏄惁鍛戒腑閰嶇疆銆�
+     * 鍒ゆ柇闅忚瀛愪换鍔℃槸鍚﹀睘浜庨渶瑕佺敓鎴愭。妗堢殑浣忛櫌闅忚銆�
+     */
+    private boolean isInhospFollowup(ServiceSubtask subtask) {
+        if (!HOSP_TYPE_DISCHARGE.equals(subtask.getHospType())
+                && !HOSP_TYPE_INHOSP.equals(subtask.getHospType())) {
+            return false;
+        }
+        if (StringUtils.isBlank(subtask.getServiceType())) {
+            return false;
+        }
+        return parseCsv(inhospFollowupServiceTypes).contains(subtask.getServiceType().trim());
+    }
+
+    private boolean alreadyProcessed(Long subId, Long configId) {
+        int cid = configId == null ? SpecificArchiveConstants.NO_CONFIG_ID : configId.intValue();
+        PatSpecificArchiveGenerateLog old = patSpecificArchiveGenerateLogService
+                .selectBySourceSubAndConfig(SpecificArchiveConstants.SOURCE_TYPE_INHOSP_FOLLOWUP, subId, cid);
+        if (old == null) {
+            return false;
+        }
+        if (SpecificArchiveConstants.RESULT_FAILED.equals(old.getProcessResult())) {
+            return old.getRetryCount() != null && old.getRetryCount() >= MAX_RETRY;
+        }
+        return true;
+    }
+
+    /**
+     * 鏌ヨ鎮h�呮槸鍚﹀凡鏈夊搴斾笓绉戞。妗堛��
+     *
+     * <p>鐢ㄦ埛纭鍙e緞锛氭寜鈥滀笓绉� + 妗f绫诲瀷鈥濆垽鏂�傚绉戙�佸効绉戝垎琛ㄥ瓨鍌紝鍥犳濡囩鏌ュ绉戣〃锛�
+     * 鍎跨鏌ュ効绉戣〃锛屽啀鎸夋。妗堢被鍨嬪尯鍒嗐��</p>
+     */
+    private Long findExistingArchiveId(String orgid, Long patid, String deptCategory, String archiveType) {
+        if (SpecificArchiveConstants.DEPT_CATEGORY_GYNECOLOGY.equals(deptCategory)) {
+            PatMaternityArchive query = new PatMaternityArchive();
+            query.setOrgid(orgid);
+            query.setPatid(patid);
+            query.setArchiveType(archiveType);
+            List<PatMaternityArchive> list = patMaternityArchiveService.selectPatMaternityArchiveList(query);
+            return CollectionUtils.isNotEmpty(list) ? list.get(0).getId() : null;
+        }
+        if (SpecificArchiveConstants.DEPT_CATEGORY_PEDIATRICS.equals(deptCategory)) {
+            PatChildArchive query = new PatChildArchive();
+            query.setOrgid(orgid);
+            query.setPatid(patid);
+            query.setArchiveType(archiveType);
+            List<PatChildArchive> list = patChildArchiveService.selectPatChildArchiveList(query);
+            return CollectionUtils.isNotEmpty(list) ? list.get(0).getId() : null;
+        }
+        return null;
+    }
+
+    /**
+     * 鍒ゆ柇绉戝/鐥呭尯銆佽瘖鏂槸鍚﹀懡涓厤缃��
      *
      * <p>閮ㄩ棬鏉′欢涓庤瘖鏂潯浠朵负 OR 鍏崇郴锛氫换涓�鏉′欢鍛戒腑鍗崇敓鎴愶紱涓や釜闆嗗悎閮戒负绌烘椂閰嶇疆鏃犳晥銆�</p>
      */
-    private boolean matchConfig(PatSpecificArchiveGenerateConfig config, PatMedOuthosp patMedOuthosp) {
+    private boolean matchConfig(PatSpecificArchiveGenerateConfig config, String deptCode, String wardCode,
+                                String icd10Code, String diagName) {
         List<String> deptCodes = parseCodes(config.getDeptCodes());
         List<String> icd10Codes = parseCodes(config.getIcd10Codes());
         if (CollectionUtils.isEmpty(deptCodes) && CollectionUtils.isEmpty(icd10Codes)) {
@@ -152,22 +463,21 @@
 
         boolean deptMatched = false;
         if (CollectionUtils.isNotEmpty(deptCodes)) {
-            // 闂ㄨ瘖璁板綍鍙湁绉戝锛屾病鏈夌梾鍖猴紱dept_type=2锛堢梾鍖猴級涓嶅弬涓庨棬璇婂尮閰�
             if (DEPT_TYPE_DEPARTMENT.equals(config.getDeptType())) {
-                deptMatched = containsIgnoreCase(deptCodes, patMedOuthosp.getDeptcode());
+                deptMatched = containsIgnoreCase(deptCodes, deptCode);
+            } else if (DEPT_TYPE_WARD.equals(config.getDeptType())) {
+                deptMatched = containsIgnoreCase(deptCodes, wardCode);
             }
         }
 
         boolean diagnosisMatched = false;
         if (CollectionUtils.isNotEmpty(icd10Codes)) {
-            String icd10code = patMedOuthosp.getIcd10code();
-            String diagname = patMedOuthosp.getDiagname();
             diagnosisMatched = icd10Codes.stream().anyMatch(code -> {
-                if (equalsIgnoreCase(code, icd10code)) {
+                if (equalsIgnoreCase(code, icd10Code)) {
                     return true;
                 }
                 // 閮ㄥ垎 HIS 鏁版嵁鍙湁璇婃柇鍚嶇О娌℃湁璇婃柇鐮侊紝姝ゆ椂鍏佽鎸夎瘖鏂悕绉板厹搴曞尮閰�
-                return StringUtils.isBlank(icd10code) && equalsIgnoreCase(code, diagname);
+                return StringUtils.isBlank(icd10Code) && equalsIgnoreCase(code, diagName);
             });
         }
 
@@ -179,7 +489,9 @@
         PatMaternityArchiveDetail detail = new PatMaternityArchiveDetail();
         detail.setArchiveType(config.getArchiveType());
         detail.setFollowupPeriod(config.getFollowupPeriod());
-        detail.setSourceType(SOURCE_TYPE_OUTHOSP);
+        detail.setSourceType(SpecificArchiveConstants.SOURCE_TYPE_OUTHOSP);
+        detail.setSourceBizId(patMedOuthosp.getId());
+        detail.setSourceBizNo(patMedOuthosp.getOuthospno());
         fillCommonDetail(detail, patMedOuthosp, patArchive, campusid);
         if (patArchive != null) {
             detail.setAddress(patArchive.getPlaceOfResidence());
@@ -192,7 +504,9 @@
         PatChildArchiveDetail detail = new PatChildArchiveDetail();
         detail.setArchiveType(config.getArchiveType());
         detail.setFollowupPeriod(config.getFollowupPeriod());
-        detail.setSourceType(SOURCE_TYPE_OUTHOSP);
+        detail.setSourceType(SpecificArchiveConstants.SOURCE_TYPE_OUTHOSP);
+        detail.setSourceBizId(patMedOuthosp.getId());
+        detail.setSourceBizNo(patMedOuthosp.getOuthospno());
         fillCommonChildDetail(detail, patMedOuthosp, patArchive, campusid);
         detail.setParentPhone(patArchive != null
                 ? firstNotBlank(patArchive.getTelcode(), patMedOuthosp.getTelcode())
@@ -205,6 +519,104 @@
             detail.setNutritionIcd10Code(patMedOuthosp.getIcd10code());
             detail.setNutritionDiagName(patMedOuthosp.getDiagname());
         }
+        return detail;
+    }
+
+    private PatMaternityArchiveDetail buildInhospMaternityDetail(InhospArchiveContext context,
+                                                                 PatSpecificArchiveGenerateConfig config) {
+        PatMaternityArchiveDetail detail = new PatMaternityArchiveDetail();
+        detail.setArchiveType(config.getArchiveType());
+        detail.setFollowupPeriod(config.getFollowupPeriod());
+        detail.setSourceType(SpecificArchiveConstants.SOURCE_TYPE_INHOSP_FOLLOWUP);
+        detail.setSourceBizId(inInhospid(context));
+        detail.setSourceBizNo(inInhospno(context));
+        detail.setSourceSubId(context.subtask.getId());
+        detail.setOuthospno(null);
+        detail.setInhospno(inInhospno(context));
+        detail.setSerialnum(inSerialnum(context));
+        detail.setPatid(context.patid);
+        detail.setPatname(firstNotBlank(context.patArchive == null ? null : context.patArchive.getName(),
+                context.inhosp == null ? null : context.inhosp.getPatname()));
+        detail.setBirthdate(context.patArchive == null ? null : context.patArchive.getBirthdate());
+        detail.setIdcardno(firstNotBlank(context.patArchive == null ? null : context.patArchive.getIdcardno(),
+                context.inhosp == null ? null : context.inhosp.getIdcardno()));
+        detail.setPhone(firstNotBlank(context.patArchive == null ? null : context.patArchive.getTelcode(),
+                context.inhosp == null ? null : context.inhosp.getTelcode()));
+        detail.setSex(firstNonNull(context.patArchive == null ? null : context.patArchive.getSex(),
+                context.inhosp == null ? null : context.inhosp.getSex(),
+                context.subtask.getSex()));
+        detail.setDiagTime(context.diagTime);
+        detail.setArchiveTime(new Date());
+        detail.setDoctorCode(inDrcode(context));
+        detail.setDoctorName(inDrname(context));
+        detail.setManagementDoctorCode(firstNotBlank(context.inhosp == null ? null : context.inhosp.getManagementDoctorCode(),
+                inDrcode(context)));
+        detail.setManagementDoctorName(firstNotBlank(context.inhosp == null ? null : context.inhosp.getManagementDoctor(),
+                inDrname(context)));
+        detail.setFirstDoctorCode(inDrcode(context));
+        detail.setFirstDoctorName(inDrname(context));
+        detail.setDeptcode(context.deptCode);
+        detail.setDeptname(context.deptName);
+        detail.setWardcode(context.wardCode);
+        detail.setWardname(context.wardName);
+        detail.setIcd10code(context.icd10Code);
+        detail.setDiagname(context.diagName);
+        detail.setAddress(context.patArchive == null ? null : context.patArchive.getPlaceOfResidence());
+        detail.setRegisterUser("浣忛櫌闅忚");
+        detail.setOrgid(context.orgid);
+        detail.setCampusid(context.campusid);
+        detail.setDelFlag("0");
+        return detail;
+    }
+
+    private PatChildArchiveDetail buildInhospChildDetail(InhospArchiveContext context,
+                                                         PatSpecificArchiveGenerateConfig config) {
+        PatChildArchiveDetail detail = new PatChildArchiveDetail();
+        detail.setArchiveType(config.getArchiveType());
+        detail.setFollowupPeriod(config.getFollowupPeriod());
+        detail.setSourceType(SpecificArchiveConstants.SOURCE_TYPE_INHOSP_FOLLOWUP);
+        detail.setSourceBizId(inInhospid(context));
+        detail.setSourceBizNo(inInhospno(context));
+        detail.setSourceSubId(context.subtask.getId());
+        detail.setOuthospno(null);
+        detail.setInhospno(inInhospno(context));
+        detail.setSerialnum(inSerialnum(context));
+        detail.setPatid(context.patid);
+        detail.setPatname(firstNotBlank(context.patArchive == null ? null : context.patArchive.getName(),
+                context.inhosp == null ? null : context.inhosp.getPatname()));
+        detail.setBirthdate(context.patArchive == null ? null : context.patArchive.getBirthdate());
+        detail.setIdcardno(firstNotBlank(context.patArchive == null ? null : context.patArchive.getIdcardno(),
+                context.inhosp == null ? null : context.inhosp.getIdcardno()));
+        detail.setPhone(firstNotBlank(context.patArchive == null ? null : context.patArchive.getTelcode(),
+                context.inhosp == null ? null : context.inhosp.getTelcode()));
+        detail.setSex(firstNonNull(context.patArchive == null ? null : context.patArchive.getSex(),
+                context.inhosp == null ? null : context.inhosp.getSex(),
+                context.subtask.getSex()));
+        detail.setDiagTime(context.diagTime);
+        detail.setArchiveTime(new Date());
+        detail.setDoctorCode(inDrcode(context));
+        detail.setDoctorName(inDrname(context));
+        detail.setManagementDoctorCode(firstNotBlank(context.inhosp == null ? null : context.inhosp.getManagementDoctorCode(),
+                inDrcode(context)));
+        detail.setManagementDoctorName(firstNotBlank(context.inhosp == null ? null : context.inhosp.getManagementDoctor(),
+                inDrname(context)));
+        detail.setDeptcode(context.deptCode);
+        detail.setDeptname(context.deptName);
+        detail.setWardcode(context.wardCode);
+        detail.setWardname(context.wardName);
+        detail.setIcd10code(context.icd10Code);
+        detail.setDiagname(context.diagName);
+        detail.setParentPhone(firstNotBlank(context.patArchive == null ? null : context.patArchive.getTelcode(),
+                context.inhosp == null ? null : context.inhosp.getTelcode()));
+        detail.setParentAddress(context.patArchive == null ? null : context.patArchive.getPlaceOfResidence());
+        if ("1".equals(config.getArchiveType())) {
+            detail.setNutritionIcd10Code(context.icd10Code);
+            detail.setNutritionDiagName(context.diagName);
+        }
+        detail.setRegisterUser("浣忛櫌闅忚");
+        detail.setOrgid(context.orgid);
+        detail.setCampusid(context.campusid);
+        detail.setDelFlag("0");
         return detail;
     }
 
@@ -289,6 +701,85 @@
         return CollectionUtils.isNotEmpty(archives) ? archives.get(0) : null;
     }
 
+    private PatArchive resolvePatArchive(Long patid, PatMedInhosp inhosp) {
+        if (patid != null) {
+            PatArchive archive = patArchiveMapper.selectPatArchiveByPatid(patid);
+            if (archive != null) {
+                return archive;
+            }
+        }
+        Long inhospPatid = inhosp == null ? null : inhosp.getPatid();
+        return inhospPatid == null ? null : patArchiveMapper.selectPatArchiveByPatid(inhospPatid);
+    }
+
+    private PatMedInhosp resolveInhosp(ServiceSubtask subtask) {
+        if (subtask.getInhospid() != null) {
+            PatMedInhosp inhosp = inhospVisitFacade.selectPatMedInhospByInhospid(subtask.getInhospid());
+            if (inhosp != null) {
+                return inhosp;
+            }
+        }
+        if (StringUtils.isNotBlank(subtask.getHospno())) {
+            PatMedInhosp query = new PatMedInhosp();
+            query.setInhospno(subtask.getHospno());
+            query.setOrgid(subtask.getOrgid());
+            List<PatMedInhosp> list = inhospVisitFacade.selectPatMedInhosp(query);
+            if (CollectionUtils.isNotEmpty(list)) {
+                return list.get(0);
+            }
+        }
+        return null;
+    }
+
+    private void recordLog(InhospArchiveContext context, PatSpecificArchiveGenerateConfig config,
+                           String deptCategory, String archiveType, String result, Long archiveId, String msg) {
+        PatSpecificArchiveGenerateLog log = new PatSpecificArchiveGenerateLog();
+        log.setSourceType(SpecificArchiveConstants.SOURCE_TYPE_INHOSP_FOLLOWUP);
+        log.setSourceBizId(inInhospid(context));
+        log.setSourceBizNo(inInhospno(context));
+        log.setSourceSubId(context.subtask.getId());
+        log.setPatid(context.patid);
+        log.setOrgid(context.orgid);
+        log.setCampusid(context.campusid);
+        log.setDeptCategory(deptCategory);
+        log.setArchiveType(archiveType);
+        log.setConfigId(config == null || config.getId() == null
+                ? SpecificArchiveConstants.NO_CONFIG_ID : config.getId().intValue());
+        log.setArchiveId(archiveId);
+        log.setProcessResult(result);
+        log.setProcessMsg(msg);
+        PatSpecificArchiveGenerateLog old = patSpecificArchiveGenerateLogService.selectBySourceSubAndConfig(
+                log.getSourceType(), log.getSourceSubId(), log.getConfigId());
+        int retry = old == null || old.getRetryCount() == null ? 0 : old.getRetryCount();
+        if (SpecificArchiveConstants.RESULT_FAILED.equals(result)) {
+            retry++;
+        }
+        log.setRetryCount(retry);
+        patSpecificArchiveGenerateLogService.saveOrUpdate(log);
+    }
+
+    private Long inInhospid(InhospArchiveContext context) {
+        return firstNonNull(context.inhosp == null ? null : context.inhosp.getInhospid(),
+                context.subtask.getInhospid());
+    }
+
+    private String inInhospno(InhospArchiveContext context) {
+        return firstNotBlank(context.inhosp == null ? null : context.inhosp.getInhospno(),
+                context.subtask.getHospno());
+    }
+
+    private String inSerialnum(InhospArchiveContext context) {
+        return context.inhosp == null ? null : context.inhosp.getSerialnum();
+    }
+
+    private String inDrcode(InhospArchiveContext context) {
+        return firstNotBlank(context.inhosp == null ? null : context.inhosp.getDrcode(), context.subtask.getDrcode());
+    }
+
+    private String inDrname(InhospArchiveContext context) {
+        return firstNotBlank(context.inhosp == null ? null : context.inhosp.getDrname(), context.subtask.getDrname());
+    }
+
     private List<String> parseCodes(String raw) {
         if (StringUtils.isBlank(raw)) {
             return Collections.emptyList();
@@ -314,8 +805,42 @@
                 .collect(Collectors.toList());
     }
 
-    private String firstNotBlank(String first, String second) {
-        return StringUtils.isNotBlank(first) ? first : second;
+    private List<String> parseCsv(String raw) {
+        if (StringUtils.isBlank(raw)) {
+            return Collections.emptyList();
+        }
+        return Arrays.stream(raw.split(","))
+                .map(String::trim)
+                .filter(StringUtils::isNotBlank)
+                .collect(Collectors.toList());
+    }
+
+    private String firstNotBlank(String... values) {
+        if (values == null) {
+            return null;
+        }
+        for (String value : values) {
+            if (StringUtils.isNotBlank(value)) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    private <T> T firstNonNull(T... values) {
+        if (values == null) {
+            return null;
+        }
+        for (T value : values) {
+            if (value != null) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    private Date firstDate(Date first, Date second) {
+        return first != null ? first : second;
     }
 
     private boolean containsIgnoreCase(List<String> source, String target) {
@@ -328,4 +853,30 @@
     private boolean equalsIgnoreCase(String first, String second) {
         return first != null && second != null && first.trim().equalsIgnoreCase(second.trim());
     }
+
+    private String truncateMsg(String msg) {
+        if (msg == null) {
+            return null;
+        }
+        return msg.length() <= 900 ? msg : msg.substring(0, 900);
+    }
+
+    /**
+     * 浣忛櫌闅忚鐢熸垚妗f鏃剁敤鍒扮殑涓婁笅鏂囥��
+     */
+    private static class InhospArchiveContext {
+        private ServiceSubtask subtask;
+        private PatMedInhosp inhosp;
+        private PatArchive patArchive;
+        private Long patid;
+        private String orgid;
+        private String campusid;
+        private String deptCode;
+        private String deptName;
+        private String wardCode;
+        private String wardName;
+        private String icd10Code;
+        private String diagName;
+        private Date diagTime;
+    }
 }
diff --git a/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java
index 80225ac..3b24af5 100644
--- a/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java
@@ -64,6 +64,7 @@
 import com.ruoyi.task.domain.ServiceSubtaskPreachform;
 import com.ruoyi.task.service.IServiceTaskService;
 import com.ruoyi.task.mapper.ServiceSubtaskPreachformMapper;
+import com.ruoyi.task.event.FollowupCompletedEventPublisher;
 import com.ruoyi.patarchive.mapper.PatArchiveMapper;
 /**
  * 浠诲姟闂嵎闂閫夐」Service涓氬姟灞傚鐞�
@@ -91,6 +92,9 @@
 
     @Autowired
     private ServiceSubtaskMapper serviceSubtaskMapper;
+
+    @Autowired
+    private FollowupCompletedEventPublisher followupCompletedEventPublisher;
 
     @Autowired
     private ServiceSubtaskPreachformMapper serviceSubtaskPreachformMapper;
@@ -476,6 +480,7 @@
                 log.error("灏嗚key鍜寁alue浠巖edis涓�,serviceSubtask鐨勫�间负--------锛歿}", serviceSubtask);
                 serviceSubtask.setScore(formatScore(scoreTotal));
                 serviceSubtaskMapper.updateServiceSubtaskByCondition(serviceSubtask);
+                followupCompletedEventPublisher.publish(serviceSubtask.getId());
 
                 //灏嗗綋鍓嶅彂閫佺姸鎬佹敼鎴� 9 瀹屾垚锛堢紦瀛� preachform 鏌ヨ锛�
                 String currentPreachform = serviceSubtask.getCurrentPreachform();
@@ -664,6 +669,7 @@
             serviceSubtask.setUpdateTime(new Date());
             serviceSubtask.setScore(formatScore(scoreTotal));
             serviceSubtaskMapper.updateServiceSubtaskByCondition(serviceSubtask);
+            followupCompletedEventPublisher.publish(serviceSubtask.getId());
 
             //灏嗗綋鍓嶅彂閫佺姸鎬佹敼鎴�9瀹屾垚
             ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
@@ -823,6 +829,7 @@
                 serviceSubtask.setVisitTime(new Date());
                 serviceSubtask.setScore(formatScore(scoreTotal));
                 serviceSubtaskMapper.insertServiceSubtask(serviceSubtask);
+                followupCompletedEventPublisher.publish(serviceSubtask.getId());
                 //灏嗗綋鍓嶅彂閫佺姸鎬佹敼鎴�9瀹屾垚
                 ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
                 serviceSubtaskPreachform.setPreachform(serviceSubtask.getCurrentPreachform());
diff --git a/smartor/src/main/resources/mapper/smartor/PatChildArchiveDetailMapper.xml b/smartor/src/main/resources/mapper/smartor/PatChildArchiveDetailMapper.xml
index b2d555a..bd865d7 100644
--- a/smartor/src/main/resources/mapper/smartor/PatChildArchiveDetailMapper.xml
+++ b/smartor/src/main/resources/mapper/smartor/PatChildArchiveDetailMapper.xml
@@ -9,6 +9,9 @@
         <result property="archiveid" column="archiveid"/>
         <result property="archiveType" column="archive_type"/>
         <result property="sourceType" column="source_type"/>
+        <result property="sourceBizId" column="source_biz_id"/>
+        <result property="sourceBizNo" column="source_biz_no"/>
+        <result property="sourceSubId" column="source_sub_id"/>
         <result property="outhospno" column="outhospno"/>
         <result property="inhospno" column="inhospno"/>
         <result property="serialnum" column="serialnum"/>
@@ -70,6 +73,9 @@
                archiveid,
                archive_type,
                source_type,
+               source_biz_id,
+               source_biz_no,
+               source_sub_id,
                outhospno,
                inhospno,
                serialnum,
@@ -136,6 +142,9 @@
             <if test="archiveType != null and archiveType != ''">and archive_type = #{archiveType}</if>
             <if test="followupPeriod != null and followupPeriod != ''">and followup_period = #{followupPeriod}</if>
             <if test="sourceType != null and sourceType != ''">and source_type = #{sourceType}</if>
+            <if test="sourceBizId != null">and source_biz_id = #{sourceBizId}</if>
+            <if test="sourceBizNo != null and sourceBizNo != ''">and source_biz_no = #{sourceBizNo}</if>
+            <if test="sourceSubId != null">and source_sub_id = #{sourceSubId}</if>
             <if test="outhospno != null and outhospno != ''">and outhospno = #{outhospno}</if>
             <if test="inhospno != null and inhospno != ''">and inhospno = #{inhospno}</if>
             <if test="serialnum != null and serialnum != ''">and serialnum = #{serialnum}</if>
@@ -187,6 +196,9 @@
             <if test="archiveid != null">archiveid,</if>
             <if test="archiveType != null">archive_type,</if>
             <if test="sourceType != null">source_type,</if>
+            <if test="sourceBizId != null">source_biz_id,</if>
+            <if test="sourceBizNo != null">source_biz_no,</if>
+            <if test="sourceSubId != null">source_sub_id,</if>
             <if test="outhospno != null">outhospno,</if>
             <if test="inhospno != null">inhospno,</if>
             <if test="serialnum != null">serialnum,</if>
@@ -246,6 +258,9 @@
             <if test="archiveid != null">#{archiveid},</if>
             <if test="archiveType != null">#{archiveType},</if>
             <if test="sourceType != null">#{sourceType},</if>
+            <if test="sourceBizId != null">#{sourceBizId},</if>
+            <if test="sourceBizNo != null">#{sourceBizNo},</if>
+            <if test="sourceSubId != null">#{sourceSubId},</if>
             <if test="outhospno != null">#{outhospno},</if>
             <if test="inhospno != null">#{inhospno},</if>
             <if test="serialnum != null">#{serialnum},</if>
@@ -309,6 +324,9 @@
             <if test="archiveid != null">archiveid = #{archiveid},</if>
             <if test="archiveType != null">archive_type = #{archiveType},</if>
             <if test="sourceType != null">source_type = #{sourceType},</if>
+            <if test="sourceBizId != null">source_biz_id = #{sourceBizId},</if>
+            <if test="sourceBizNo != null">source_biz_no = #{sourceBizNo},</if>
+            <if test="sourceSubId != null">source_sub_id = #{sourceSubId},</if>
             <if test="outhospno != null">outhospno = #{outhospno},</if>
             <if test="inhospno != null">inhospno = #{inhospno},</if>
             <if test="serialnum != null">serialnum = #{serialnum},</if>
diff --git a/smartor/src/main/resources/mapper/smartor/PatChildArchiveMapper.xml b/smartor/src/main/resources/mapper/smartor/PatChildArchiveMapper.xml
index 95fb901..1e8dbc2 100644
--- a/smartor/src/main/resources/mapper/smartor/PatChildArchiveMapper.xml
+++ b/smartor/src/main/resources/mapper/smartor/PatChildArchiveMapper.xml
@@ -7,6 +7,10 @@
     <resultMap type="com.smartor.domain.PatChildArchive" id="PatChildArchiveResult">
         <result property="id" column="id"/>
         <result property="archiveType" column="archive_type"/>
+        <result property="sourceType" column="source_type"/>
+        <result property="sourceBizId" column="source_biz_id"/>
+        <result property="sourceBizNo" column="source_biz_no"/>
+        <result property="sourceSubId" column="source_sub_id"/>
         <result property="outhospno" column="outhospno"/>
         <result property="inhospno" column="inhospno"/>
         <result property="serialnum" column="serialnum"/>
@@ -52,6 +56,10 @@
     <sql id="selectPatChildArchiveVo">
         select id,
                archive_type,
+               source_type,
+               source_biz_id,
+               source_biz_no,
+               source_sub_id,
                outhospno,
                inhospno,
                serialnum,
@@ -101,6 +109,10 @@
         where 1=1
             and del_flag = '0'
             <if test="archiveType != null and archiveType != ''">and archive_type = #{archiveType}</if>
+            <if test="sourceType != null and sourceType != ''">and source_type = #{sourceType}</if>
+            <if test="sourceBizId != null">and source_biz_id = #{sourceBizId}</if>
+            <if test="sourceBizNo != null and sourceBizNo != ''">and source_biz_no = #{sourceBizNo}</if>
+            <if test="sourceSubId != null">and source_sub_id = #{sourceSubId}</if>
             <if test="outhospno != null and outhospno != ''">and outhospno = #{outhospno}</if>
             <if test="inhospno != null and inhospno != ''">and inhospno = #{inhospno}</if>
             <if test="serialnum != null and serialnum != ''">and serialnum = #{serialnum}</if>
@@ -152,6 +164,10 @@
         insert into pat_child_archive
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="archiveType != null">archive_type,</if>
+            <if test="sourceType != null">source_type,</if>
+            <if test="sourceBizId != null">source_biz_id,</if>
+            <if test="sourceBizNo != null">source_biz_no,</if>
+            <if test="sourceSubId != null">source_sub_id,</if>
             <if test="outhospno != null">outhospno,</if>
             <if test="inhospno != null">inhospno,</if>
             <if test="serialnum != null">serialnum,</if>
@@ -195,6 +211,10 @@
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="archiveType != null">#{archiveType},</if>
+            <if test="sourceType != null">#{sourceType},</if>
+            <if test="sourceBizId != null">#{sourceBizId},</if>
+            <if test="sourceBizNo != null">#{sourceBizNo},</if>
+            <if test="sourceSubId != null">#{sourceSubId},</if>
             <if test="outhospno != null">#{outhospno},</if>
             <if test="inhospno != null">#{inhospno},</if>
             <if test="serialnum != null">#{serialnum},</if>
@@ -242,6 +262,10 @@
         update pat_child_archive
         <trim prefix="SET" suffixOverrides=",">
             <if test="archiveType != null">archive_type = #{archiveType},</if>
+            <if test="sourceType != null">source_type = #{sourceType},</if>
+            <if test="sourceBizId != null">source_biz_id = #{sourceBizId},</if>
+            <if test="sourceBizNo != null">source_biz_no = #{sourceBizNo},</if>
+            <if test="sourceSubId != null">source_sub_id = #{sourceSubId},</if>
             <if test="outhospno != null">outhospno = #{outhospno},</if>
             <if test="inhospno != null">inhospno = #{inhospno},</if>
             <if test="serialnum != null">serialnum = #{serialnum},</if>
diff --git a/smartor/src/main/resources/mapper/smartor/PatMaternityArchiveDetailMapper.xml b/smartor/src/main/resources/mapper/smartor/PatMaternityArchiveDetailMapper.xml
index fb2fef3..7c2ba79 100644
--- a/smartor/src/main/resources/mapper/smartor/PatMaternityArchiveDetailMapper.xml
+++ b/smartor/src/main/resources/mapper/smartor/PatMaternityArchiveDetailMapper.xml
@@ -9,6 +9,9 @@
         <result property="archiveid" column="archiveid"/>
         <result property="archiveType" column="archive_type"/>
         <result property="sourceType" column="source_type"/>
+        <result property="sourceBizId" column="source_biz_id"/>
+        <result property="sourceBizNo" column="source_biz_no"/>
+        <result property="sourceSubId" column="source_sub_id"/>
         <result property="outhospno" column="outhospno"/>
         <result property="inhospno" column="inhospno"/>
         <result property="serialnum" column="serialnum"/>
@@ -67,6 +70,9 @@
                archiveid,
                archive_type,
                source_type,
+               source_biz_id,
+               source_biz_no,
+               source_sub_id,
                outhospno,
                inhospno,
                serialnum,
@@ -129,6 +135,9 @@
             <if test="archiveid != null">and archiveid = #{archiveid}</if>
             <if test="archiveType != null and archiveType != ''">and archive_type = #{archiveType}</if>
             <if test="sourceType != null and sourceType != ''">and source_type = #{sourceType}</if>
+            <if test="sourceBizId != null">and source_biz_id = #{sourceBizId}</if>
+            <if test="sourceBizNo != null and sourceBizNo != ''">and source_biz_no = #{sourceBizNo}</if>
+            <if test="sourceSubId != null">and source_sub_id = #{sourceSubId}</if>
             <if test="outhospno != null and outhospno != ''">and outhospno = #{outhospno}</if>
             <if test="inhospno != null and inhospno != ''">and inhospno = #{inhospno}</if>
             <if test="serialnum != null and serialnum != ''">and serialnum = #{serialnum}</if>
@@ -174,6 +183,9 @@
             <if test="archiveid != null">archiveid,</if>
             <if test="archiveType != null">archive_type,</if>
             <if test="sourceType != null">source_type,</if>
+            <if test="sourceBizId != null">source_biz_id,</if>
+            <if test="sourceBizNo != null">source_biz_no,</if>
+            <if test="sourceSubId != null">source_sub_id,</if>
             <if test="outhospno != null">outhospno,</if>
             <if test="inhospno != null">inhospno,</if>
             <if test="serialnum != null">serialnum,</if>
@@ -230,6 +242,9 @@
             <if test="archiveid != null">#{archiveid},</if>
             <if test="archiveType != null">#{archiveType},</if>
             <if test="sourceType != null">#{sourceType},</if>
+            <if test="sourceBizId != null">#{sourceBizId},</if>
+            <if test="sourceBizNo != null">#{sourceBizNo},</if>
+            <if test="sourceSubId != null">#{sourceSubId},</if>
             <if test="outhospno != null">#{outhospno},</if>
             <if test="inhospno != null">#{inhospno},</if>
             <if test="serialnum != null">#{serialnum},</if>
@@ -290,6 +305,9 @@
             <if test="archiveid != null">archiveid = #{archiveid},</if>
             <if test="archiveType != null">archive_type = #{archiveType},</if>
             <if test="sourceType != null">source_type = #{sourceType},</if>
+            <if test="sourceBizId != null">source_biz_id = #{sourceBizId},</if>
+            <if test="sourceBizNo != null">source_biz_no = #{sourceBizNo},</if>
+            <if test="sourceSubId != null">source_sub_id = #{sourceSubId},</if>
             <if test="outhospno != null">outhospno = #{outhospno},</if>
             <if test="inhospno != null">inhospno = #{inhospno},</if>
             <if test="serialnum != null">serialnum = #{serialnum},</if>
diff --git a/smartor/src/main/resources/mapper/smartor/PatMaternityArchiveMapper.xml b/smartor/src/main/resources/mapper/smartor/PatMaternityArchiveMapper.xml
index 194b85f..45ad106 100644
--- a/smartor/src/main/resources/mapper/smartor/PatMaternityArchiveMapper.xml
+++ b/smartor/src/main/resources/mapper/smartor/PatMaternityArchiveMapper.xml
@@ -7,6 +7,10 @@
     <resultMap type="com.smartor.domain.PatMaternityArchive" id="PatMaternityArchiveResult">
         <result property="id" column="id"/>
         <result property="archiveType" column="archive_type"/>
+        <result property="sourceType" column="source_type"/>
+        <result property="sourceBizId" column="source_biz_id"/>
+        <result property="sourceBizNo" column="source_biz_no"/>
+        <result property="sourceSubId" column="source_sub_id"/>
         <result property="outhospno" column="outhospno"/>
         <result property="inhospno" column="inhospno"/>
         <result property="serialnum" column="serialnum"/>
@@ -47,6 +51,10 @@
     <sql id="selectPatMaternityArchiveVo">
         select id,
                archive_type,
+               source_type,
+               source_biz_id,
+               source_biz_no,
+               source_sub_id,
                outhospno,
                inhospno,
                serialnum,
@@ -91,6 +99,10 @@
         where 1=1
             and del_flag = '0'
             <if test="archiveType != null and archiveType != ''">and archive_type = #{archiveType}</if>
+            <if test="sourceType != null and sourceType != ''">and source_type = #{sourceType}</if>
+            <if test="sourceBizId != null">and source_biz_id = #{sourceBizId}</if>
+            <if test="sourceBizNo != null and sourceBizNo != ''">and source_biz_no = #{sourceBizNo}</if>
+            <if test="sourceSubId != null">and source_sub_id = #{sourceSubId}</if>
             <if test="outhospno != null and outhospno != ''">and outhospno = #{outhospno}</if>
             <if test="inhospno != null and inhospno != ''">and inhospno = #{inhospno}</if>
             <if test="serialnum != null and serialnum != ''">and serialnum = #{serialnum}</if>
@@ -138,6 +150,10 @@
         insert into pat_maternity_archive
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="archiveType != null">archive_type,</if>
+            <if test="sourceType != null">source_type,</if>
+            <if test="sourceBizId != null">source_biz_id,</if>
+            <if test="sourceBizNo != null">source_biz_no,</if>
+            <if test="sourceSubId != null">source_sub_id,</if>
             <if test="outhospno != null">outhospno,</if>
             <if test="inhospno != null">inhospno,</if>
             <if test="serialnum != null">serialnum,</if>
@@ -176,6 +192,10 @@
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="archiveType != null">#{archiveType},</if>
+            <if test="sourceType != null">#{sourceType},</if>
+            <if test="sourceBizId != null">#{sourceBizId},</if>
+            <if test="sourceBizNo != null">#{sourceBizNo},</if>
+            <if test="sourceSubId != null">#{sourceSubId},</if>
             <if test="outhospno != null">#{outhospno},</if>
             <if test="inhospno != null">#{inhospno},</if>
             <if test="serialnum != null">#{serialnum},</if>
@@ -218,6 +238,10 @@
         update pat_maternity_archive
         <trim prefix="SET" suffixOverrides=",">
             <if test="archiveType != null">archive_type = #{archiveType},</if>
+            <if test="sourceType != null">source_type = #{sourceType},</if>
+            <if test="sourceBizId != null">source_biz_id = #{sourceBizId},</if>
+            <if test="sourceBizNo != null">source_biz_no = #{sourceBizNo},</if>
+            <if test="sourceSubId != null">source_sub_id = #{sourceSubId},</if>
             <if test="outhospno != null">outhospno = #{outhospno},</if>
             <if test="inhospno != null">inhospno = #{inhospno},</if>
             <if test="serialnum != null">serialnum = #{serialnum},</if>

--
Gitblit v1.9.3