From eb845e8be695ed1280a7cbf854a4d1dedf9db30d Mon Sep 17 00:00:00 2001
From: 陈昶聿 <chychen@nbjetron.com>
Date: 星期五, 30 十月 2026 15:02:55 +0800
Subject: [PATCH] 【丽水】/smartor/serviceSubtask/getSfStatisticsHyperlink 和 /smartor/serviceSubtask/getSfStatistics 统计的时候,对于 service_subtask.current_preachForm 为空的数据 当成 service_subtask.preachform 字符串的第一个执行方式、首次待随访全部(visitCount = 1 && sendstate in (1、2、3、7)) 区别于原先的待随访,这个是给市一使用的                                                                                                                                                                                            再次待随访全部(visitCount > 1 && sendstate in (1、2、3、7)) 区别于原先的待随访,这个是给市一使用的                                                                                                                                                                                            首次待随访待发送(visitCount = 1 && sendstate in (1、2))                                                                                                                                                                                            再次待随访待发送(visitCount > 1 && sendstate in (1、2))                                                                                                                                                                                            首次待随访已发送(visitCount = 1 && sendstate = in (3、7))                                                                                                                                                                                            再次待随访已发送(visitCount > 1 && sendstate = in (3、7))                                                                                                                                                                                            首次已发送(visitCount = 1 && sendstate = 3)                                                                                                                                                                                            再次已发送(visitCount > 1 && sendstate = 3)

---
 smartor/src/main/java/com/smartor/service/impl/PatMedInhospServiceImpl.java              |   56 ++++++++++-
 smartor/src/main/resources/mapper/smartor/PatArchiveMapper.xml                           |    8 +
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java |   10 ++
 smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java                    |   40 ++++++++
 smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java            |  130 ++++++++++++++++++++++++++
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/PatMedInhospController.java   |    7 +
 smartor/src/main/java/com/smartor/mapper/PatArchiveMapper.java                           |    8 +
 smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java                       |   12 ++
 smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml                       |   13 ++
 9 files changed, 277 insertions(+), 7 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/PatMedInhospController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/PatMedInhospController.java
index 8b28e85..3c238c7 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/PatMedInhospController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/PatMedInhospController.java
@@ -29,6 +29,7 @@
 
 import javax.servlet.http.HttpServletResponse;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 鎮h�呬綇闄㈣褰旵ontroller
@@ -274,7 +275,11 @@
     @ApiOperation("addManualVisit")
     @PostMapping("/addManualVisit")
     public AjaxResult addManualVisit(@RequestBody ManualVisitDTO manualVisitDTO) {
-        return success(patMedInhospService.addManualVisit(manualVisitDTO));
+        Map<String, Object> result = patMedInhospService.addManualVisit(manualVisitDTO);
+        if (Boolean.TRUE.equals(result.get("hasDuplicate"))) {
+            return AjaxResult.warn((String) result.get("tipMessage"), result);
+        }
+        return success(result);
     }
 
     /**
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java
index 806e72f..aafb495 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java
@@ -713,6 +713,16 @@
      * taskSituation5Info - taskSituation = 5
      * taskSituation6Info - taskSituation = 7
      * manuallyCalledInfo - isManuallyCalled = 1L
+     * manualCallTimeoutInfo - visitCount = 1 && sendstate = 7 && isManuallyCalled = 0
+     * manualCallTimeoutAgainInfo - visitCount > 1 && sendstate = 7 && isManuallyCalled = 0
+     * pendingFollowUpAllInfo - visitCount = 1 && sendstate in (1,2,3,7)
+     * pendingFollowUpAllAgainInfo - visitCount > 1 && sendstate in (1,2,3,7)
+     * pendingFollowUpWaitSendInfo - visitCount = 1 && sendstate in (1,2)
+     * pendingFollowUpWaitSendAgainInfo - visitCount > 1 && sendstate in (1,2)
+     * pendingFollowUpSentInfo - visitCount = 1 && sendstate in (3,7)
+     * pendingFollowUpSentAgainInfo - visitCount > 1 && sendstate in (3,7)
+     * sentInfo - visitCount = 1 && sendstate = 3
+     * sentAgainInfo - visitCount > 1 && sendstate = 3
      * firstDischargeCountInfo - visitCount = 1
      * againFollowUpPushCountInfo - visitCount = 2 && visitDeptCode = sys.smartor.center.dept
      * filterCountList - taskSituation = 6 && sendstate = 4
diff --git a/smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java b/smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java
index abd6253..918af60 100644
--- a/smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java
+++ b/smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java
@@ -274,6 +274,46 @@
     @Excel(name = " 浜屾寰呴殢璁� ")
     private Long pendingFollowUpAgain = 0L;
 
+    @ApiModelProperty(value = "棣栨闅忚浜哄伐鐢佃瘽瓒呮椂锛坰endstate=7 涓� isManuallyCalled=0锛�")
+    @Excel(name = " 棣栨闅忚浜哄伐鐢佃瘽瓒呮椂 ")
+    private Long manualCallTimeout = 0L;
+
+    @ApiModelProperty(value = "鍐嶆闅忚浜哄伐鐢佃瘽瓒呮椂锛坰endstate=7 涓� isManuallyCalled=0锛�")
+    @Excel(name = " 鍐嶆闅忚浜哄伐鐢佃瘽瓒呮椂 ")
+    private Long manualCallTimeoutAgain = 0L;
+
+    @ApiModelProperty(value = "棣栨寰呴殢璁垮叏閮紙sendstate in 1,2,3,7锛�")
+    @Excel(name = " 棣栨寰呴殢璁垮叏閮� ")
+    private Long pendingFollowUpAll = 0L;
+
+    @ApiModelProperty(value = "鍐嶆寰呴殢璁垮叏閮紙sendstate in 1,2,3,7锛�")
+    @Excel(name = " 鍐嶆寰呴殢璁垮叏閮� ")
+    private Long pendingFollowUpAllAgain = 0L;
+
+    @ApiModelProperty(value = "棣栨寰呴殢璁垮緟鍙戦�侊紙sendstate in 1,2锛�")
+    @Excel(name = " 棣栨寰呴殢璁垮緟鍙戦�� ")
+    private Long pendingFollowUpWaitSend = 0L;
+
+    @ApiModelProperty(value = "鍐嶆寰呴殢璁垮緟鍙戦�侊紙sendstate in 1,2锛�")
+    @Excel(name = " 鍐嶆寰呴殢璁垮緟鍙戦�� ")
+    private Long pendingFollowUpWaitSendAgain = 0L;
+
+    @ApiModelProperty(value = "棣栨寰呴殢璁垮凡鍙戦�侊紙sendstate in 3,7锛�")
+    @Excel(name = " 棣栨寰呴殢璁垮凡鍙戦�� ")
+    private Long pendingFollowUpSent = 0L;
+
+    @ApiModelProperty(value = "鍐嶆寰呴殢璁垮凡鍙戦�侊紙sendstate in 3,7锛�")
+    @Excel(name = " 鍐嶆寰呴殢璁垮凡鍙戦�� ")
+    private Long pendingFollowUpSentAgain = 0L;
+
+    @ApiModelProperty(value = "棣栨宸插彂閫侊紙sendstate=3锛�")
+    @Excel(name = " 棣栨宸插彂閫� ")
+    private Long sent = 0L;
+
+    @ApiModelProperty(value = "鍐嶆宸插彂閫侊紙sendstate=3锛�")
+    @Excel(name = " 鍐嶆宸插彂閫� ")
+    private Long sentAgain = 0L;
+
     @ApiModelProperty(value = "浜屾闅忚鎴愬姛")
     @Excel(name = " 浜屾闅忚鎴愬姛 ")
     private Long followUpSuccessAgain = 0L;
diff --git a/smartor/src/main/java/com/smartor/mapper/PatArchiveMapper.java b/smartor/src/main/java/com/smartor/mapper/PatArchiveMapper.java
index a215622..4b500a6 100644
--- a/smartor/src/main/java/com/smartor/mapper/PatArchiveMapper.java
+++ b/smartor/src/main/java/com/smartor/mapper/PatArchiveMapper.java
@@ -24,6 +24,14 @@
      */
     public PatArchive selectPatArchiveByPatid(Long patid);
 
+    /**
+     * 閿佸畾鎮h�呮。妗堣锛屼覆琛屽寲鍚屼竴鎮h�呯殑浜哄伐闅忚鍒涘缓
+     *
+     * @param patid 鎮h�呮。妗堜富閿�
+     * @return 鎮h�呮。妗堜富閿紝妗f涓嶅瓨鍦ㄦ垨宸插垹闄ゆ椂杩斿洖 null
+     */
+    Long lockPatArchiveByPatid(@Param("patid") Long patid);
+
     List<PatArchive> selectPatArchiveByPatnos(@Param("patnos") List<String> patnos);
 
     List<PatArchive> selectPatArchiveByPatidHiss(@Param("patidHiss") List<String> patidHiss);
diff --git a/smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java b/smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java
index 4c633bf..877625d 100644
--- a/smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java
+++ b/smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java
@@ -168,6 +168,18 @@
                                                          @Param("sendstates") List<Long> sendstates);
 
     /**
+     * 缁熻鎮h�呮寚瀹氫换鍔′笅鏈畬鎴愮殑闅忚浠诲姟鏁伴噺锛堢敤浜庝汉宸ラ殢璁块噸澶嶆牎楠岋級
+     *
+     * @param patid      鎮h�匢D
+     * @param taskid     浠诲姟ID
+     * @param sendstates 鏈畬鎴愮姸鎬侀泦鍚�
+     * @return 鏈畬鎴愪换鍔℃暟閲�
+     */
+    int countUnfinishedServiceSubtaskByPatidAndTaskid(@Param("patid") Long patid,
+                                                      @Param("taskid") Long taskid,
+                                                      @Param("sendstates") List<Long> sendstates);
+
+    /**
      * 鍒犻櫎鍗曚竴浠诲姟锛堥殢璁匡級
      *
      * @return 缁撴灉
diff --git a/smartor/src/main/java/com/smartor/service/impl/PatMedInhospServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/PatMedInhospServiceImpl.java
index c6db543..8cf5d67 100644
--- a/smartor/src/main/java/com/smartor/service/impl/PatMedInhospServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/PatMedInhospServiceImpl.java
@@ -22,6 +22,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Isolation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.ObjectUtils;
 
@@ -2009,10 +2010,11 @@
 
     /**
      * 浜哄伐闅忚锛氬垹闄ゆ偅鑰呭嚭闄㈣褰曞搴旂殑鏈畬鎴愰殢璁夸换鍔★紝骞舵寜鎸囧畾浠诲姟閲嶆柊鐢熸垚銆�
-     * 鏈畬鎴愮姸鎬佸彛寰勶細sendstate in (1,2,3,7)銆�
+     * 鍒犻櫎鏃т换鍔″彛寰勶細sendstate in (1,2,3,7)锛�
+     * 閲嶅浠诲姟鏍¢獙鍙e緞锛歴endstate in (1,2,3,5,7)锛屽凡鏈夌浉鍚� taskid 鏈畬鎴愪换鍔$殑鎮h�呰烦杩囥��
      */
     @Override
-    @Transactional(rollbackFor = Exception.class)
+    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
     public Map<String, Object> addManualVisit(ManualVisitDTO manualVisitDTO) {
         if (manualVisitDTO == null) {
             throw new BaseException("鍏ュ弬涓嶈兘涓虹┖");
@@ -2029,20 +2031,27 @@
             throw new BaseException("浜哄伐闅忚浠诲姟涓嶅瓨鍦紝taskid锛�" + manualVisitDTO.getTaskid());
         }
 
-        LinkedHashSet<Long> patids = manualVisitDTO.getPatids().stream()
+        // 鍗囧簭澶勭悊锛岄厤鍚堟偅鑰呮。妗堣閿侊紝閬垮厤鎵归噺璇锋眰浜ゅ弶鍔犻攣浜х敓姝婚攣
+        List<Long> patids = manualVisitDTO.getPatids().stream()
                 .filter(Objects::nonNull)
-                .collect(Collectors.toCollection(LinkedHashSet::new));
+                .distinct()
+                .sorted()
+                .collect(Collectors.toList());
         if (patids.isEmpty()) {
             throw new BaseException("鎮h�卲atid闆嗗悎涓嶈兘涓虹┖");
         }
 
         String config = iSysConfigService.selectConfigByKey("visit.early.day");
         List<Long> unfinishedSendstates = Arrays.asList(1L, 2L, 3L, 7L);
+        // 涓庡墠绔緟闅忚鍙e緞淇濇寔涓�鑷达紝鍙戦�佸け璐�(5)涔熻涓哄凡鏈夋湭瀹屾垚浠诲姟
+        List<Long> activeSendstates = Arrays.asList(1L, 2L, 3L, 5L, 7L);
         int deletedCount = 0;
         int generatedCount = 0;
         List<Long> noDischargeRecordPatids = new ArrayList<>();
         List<Long> noArchivePatids = new ArrayList<>();
         List<Long> generateFailedPatids = new ArrayList<>();
+        List<Long> duplicatePatids = new ArrayList<>();
+        List<String> duplicatePatientNames = new ArrayList<>();
 
         for (Long patid : patids) {
             // 鏌ヨ鎮h�呭叏閮ㄥ嚭闄㈣褰曪紝SQL 鎸夊嚭闄㈡椂闂村�掑簭锛岀涓�鏉′綔涓烘湰娆$敓鎴愪换鍔$殑鍑洪櫌璁板綍
@@ -2067,6 +2076,26 @@
             PatArchive patArchive = patArchiveMapper.selectPatArchiveByPatid(patid);
             if (Objects.isNull(patArchive)) {
                 noArchivePatids.add(patid);
+                continue;
+            }
+
+            // 閿佸畾鎮h�呮。妗堣锛屼覆琛屽寲鍚屼竴鎮h�呯殑骞跺彂鍒涘缓璇锋眰
+            Long lockedPatid = patArchiveMapper.lockPatArchiveByPatid(patid);
+            if (Objects.isNull(lockedPatid)) {
+                noArchivePatids.add(patid);
+                continue;
+            }
+
+            // 鍚屼竴鎮h�呭湪鍚屼竴 taskid 涓嬪凡鏈夋湭瀹屾垚闅忚浠诲姟鏃讹紝璺宠繃璇ユ偅鑰咃紝閬垮厤閲嶅鍒涘缓
+            int existingSubtaskCount = serviceSubtaskMapper.countUnfinishedServiceSubtaskByPatidAndTaskid(
+                    patid, serviceTask.getTaskid(), activeSendstates);
+            if (existingSubtaskCount > 0) {
+                duplicatePatids.add(patid);
+                String patientName = StringUtils.isNotEmpty(patArchive.getName())
+                        ? patArchive.getName() : String.valueOf(patid);
+                duplicatePatientNames.add(patientName + "(" + patid + ")");
+                log.info("addManualVisit 鎮h�呭凡鏈夌浉鍚屾湇鍔★紝璺宠繃鐢熸垚锛宲atid锛歿}锛宼askid锛歿}锛屽凡鏈変换鍔℃暟锛歿}",
+                        patid, serviceTask.getTaskid(), existingSubtaskCount);
                 continue;
             }
 
@@ -2111,14 +2140,29 @@
                     patid, serviceTask.getTaskid(), serviceSubtask.getId());
         }
 
+        String tipMessage = null;
+        if (CollectionUtils.isNotEmpty(duplicatePatids)) {
+            String taskName = StringUtils.isNotEmpty(serviceTask.getTaskName())
+                    ? serviceTask.getTaskName() : String.valueOf(serviceTask.getTaskid());
+            tipMessage = "鎮h��" + String.join("銆�", duplicatePatientNames)
+                    + "宸叉湁鐩稿悓鏈嶅姟銆�" + taskName + "銆戯紝宸茶烦杩�";
+            if (generatedCount > 0) {
+                tipMessage += "锛涘叾浣欐偅鑰呭凡澶勭悊";
+            }
+        }
+
         Map<String, Object> result = new HashMap<>();
         result.put("deletedCount", deletedCount);
         result.put("generatedCount", generatedCount);
         result.put("noDischargeRecordPatids", noDischargeRecordPatids);
         result.put("noArchivePatids", noArchivePatids);
         result.put("generateFailedPatids", generateFailedPatids);
-        log.info("addManualVisit 澶勭悊瀹屾垚锛宲atid鏁帮細{}锛宼askid锛歿}锛屽垹闄ゆ湭瀹屾垚浠诲姟鏁帮細{}锛岀敓鎴愪换鍔℃暟锛歿}",
-                patids.size(), serviceTask.getTaskid(), deletedCount, generatedCount);
+        result.put("duplicatePatids", duplicatePatids);
+        result.put("duplicatePatientNames", duplicatePatientNames);
+        result.put("hasDuplicate", CollectionUtils.isNotEmpty(duplicatePatids));
+        result.put("tipMessage", tipMessage);
+        log.info("addManualVisit 澶勭悊瀹屾垚锛宲atid鏁帮細{}锛宼askid锛歿}锛屽垹闄ゆ湭瀹屾垚浠诲姟鏁帮細{}锛岀敓鎴愪换鍔℃暟锛歿}锛岄噸澶嶈烦杩囨暟锛歿}",
+                patids.size(), serviceTask.getTaskid(), deletedCount, generatedCount, duplicatePatids.size());
         return result;
     }
 
diff --git a/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
index a2be971..34497eb 100644
--- a/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
@@ -3801,6 +3801,7 @@
 
                 //棣栨鍑洪櫌闅忚
                 if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() == 1) {
+                    applyFirstFollowUpExtraStatistics(serviceSubtaskStatistic, serviceSubtask);
                     //棣栨搴旈殢璁�
                     if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L)) {
                         serviceSubtaskStatistic.setNeedFollowUp(serviceSubtaskStatistic.getNeedFollowUp() + 1L);
@@ -3922,6 +3923,7 @@
                     }
                 }//浜屾鍑洪櫌闅忚
                 else if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() > 1) {
+                    applyAgainFollowUpExtraStatistics(serviceSubtaskStatistic, serviceSubtask);
                     //鍐嶆搴旈殢璁�
                     if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) {
                         serviceSubtaskStatistic.setNeedFollowUpAgain(serviceSubtaskStatistic.getNeedFollowUpAgain() + 1L);
@@ -4073,6 +4075,60 @@
     }
 
     /**
+     * 甯備竴缁熻鍙e緞锛氶娆″緟闅忚銆佸凡鍙戦�佸強浜哄伐鐢佃瘽瓒呮椂銆�
+     */
+    private void applyFirstFollowUpExtraStatistics(ServiceSubtaskStatistic statistic, ServiceSubtask serviceSubtask) {
+        if (serviceSubtask.getVisitCount() == null || serviceSubtask.getVisitCount() != 1 || serviceSubtask.getSendstate() == null) {
+            return;
+        }
+        Long sendstate = serviceSubtask.getSendstate();
+        if (sendstate.equals(3L)) {
+            statistic.setSent(statistic.getSent() + 1L);
+        }
+        if (sendstate.equals(7L) && isManuallyNotCalled(serviceSubtask)) {
+            statistic.setManualCallTimeout(statistic.getManualCallTimeout() + 1L);
+        }
+        if (sendstate.equals(1L) || sendstate.equals(2L) || sendstate.equals(3L) || sendstate.equals(7L)) {
+            statistic.setPendingFollowUpAll(statistic.getPendingFollowUpAll() + 1L);
+        }
+        if (sendstate.equals(1L) || sendstate.equals(2L)) {
+            statistic.setPendingFollowUpWaitSend(statistic.getPendingFollowUpWaitSend() + 1L);
+        }
+        if (sendstate.equals(3L) || sendstate.equals(7L)) {
+            statistic.setPendingFollowUpSent(statistic.getPendingFollowUpSent() + 1L);
+        }
+    }
+
+    /**
+     * 甯備竴缁熻鍙e緞锛氬啀娆″緟闅忚銆佸凡鍙戦�佸強浜哄伐鐢佃瘽瓒呮椂銆�
+     */
+    private void applyAgainFollowUpExtraStatistics(ServiceSubtaskStatistic statistic, ServiceSubtask serviceSubtask) {
+        if (serviceSubtask.getVisitCount() == null || serviceSubtask.getVisitCount() <= 1 || serviceSubtask.getSendstate() == null) {
+            return;
+        }
+        Long sendstate = serviceSubtask.getSendstate();
+        if (sendstate.equals(3L)) {
+            statistic.setSentAgain(statistic.getSentAgain() + 1L);
+        }
+        if (sendstate.equals(7L) && isManuallyNotCalled(serviceSubtask)) {
+            statistic.setManualCallTimeoutAgain(statistic.getManualCallTimeoutAgain() + 1L);
+        }
+        if (sendstate.equals(1L) || sendstate.equals(2L) || sendstate.equals(3L) || sendstate.equals(7L)) {
+            statistic.setPendingFollowUpAllAgain(statistic.getPendingFollowUpAllAgain() + 1L);
+        }
+        if (sendstate.equals(1L) || sendstate.equals(2L)) {
+            statistic.setPendingFollowUpWaitSendAgain(statistic.getPendingFollowUpWaitSendAgain() + 1L);
+        }
+        if (sendstate.equals(3L) || sendstate.equals(7L)) {
+            statistic.setPendingFollowUpSentAgain(statistic.getPendingFollowUpSentAgain() + 1L);
+        }
+    }
+
+    private boolean isManuallyNotCalled(ServiceSubtask serviceSubtask) {
+        return serviceSubtask.getIsManuallyCalled() != null && serviceSubtask.getIsManuallyCalled().equals(0L);
+    }
+
+    /**
      * 棣栨闅忚缁熻
      *
      * @param serviceSubtaskList
@@ -4093,6 +4149,7 @@
         serviceSubtaskStatistic.setDischargeCount(serviceSubtaskList.size());
 
         for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
+            applyFirstFollowUpExtraStatistics(serviceSubtaskStatistic, serviceSubtask);
             //鏃犻渶闅忚浜烘
             if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 4) {
                 serviceSubtaskStatistic.setNonFollowUp(serviceSubtaskStatistic.getNonFollowUp() + 1L);
@@ -4266,6 +4323,7 @@
         //鍑洪櫌浜烘
         serviceSubtaskStatistic.setDischargeCount(serviceSubtaskList.size());
         for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
+            applyAgainFollowUpExtraStatistics(serviceSubtaskStatistic, serviceSubtask);
             //鏃犻渶闅忚浜烘
             if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 4) {
                 serviceSubtaskStatistic.setNonFollowUp(serviceSubtaskStatistic.getNonFollowUp() + 1L);
@@ -4844,6 +4902,16 @@
      * taskSituation5Info - taskSituation = 5
      * taskSituation6Info - taskSituation = 7
      * manuallyCalledInfo - isManuallyCalled = 1L
+     * manualCallTimeoutInfo - visitCount = 1 && sendstate = 7 && isManuallyCalled = 0
+     * manualCallTimeoutAgainInfo - visitCount > 1 && sendstate = 7 && isManuallyCalled = 0
+     * pendingFollowUpAllInfo - visitCount = 1 && sendstate in (1,2,3,7)
+     * pendingFollowUpAllAgainInfo - visitCount > 1 && sendstate in (1,2,3,7)
+     * pendingFollowUpWaitSendInfo - visitCount = 1 && sendstate in (1,2)
+     * pendingFollowUpWaitSendAgainInfo - visitCount > 1 && sendstate in (1,2)
+     * pendingFollowUpSentInfo - visitCount = 1 && sendstate in (3,7)
+     * pendingFollowUpSentAgainInfo - visitCount > 1 && sendstate in (3,7)
+     * sentInfo - visitCount = 1 && sendstate = 3
+     * sentAgainInfo - visitCount > 1 && sendstate = 3
      * filterCountList - taskSituation = 6 && sendstate = 4
      *
      */
@@ -5051,6 +5119,48 @@
                 break;
             case "manuallyCalledInfo":
                 serviceSubtaskCountReq.setIsManuallyCalled(1L);
+                break;
+            case "manualCallTimeoutInfo":
+                serviceSubtaskCountReq.setVisitCount(1);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(7L)));
+                serviceSubtaskCountReq.setIsManuallyCalled(0L);
+                break;
+            case "manualCallTimeoutAgainInfo":
+                serviceSubtaskCountReq.setVisitCount(2);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(7L)));
+                serviceSubtaskCountReq.setIsManuallyCalled(0L);
+                break;
+            case "pendingFollowUpAllInfo":
+                serviceSubtaskCountReq.setVisitCount(1);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 7L)));
+                break;
+            case "pendingFollowUpAllAgainInfo":
+                serviceSubtaskCountReq.setVisitCount(2);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 7L)));
+                break;
+            case "pendingFollowUpWaitSendInfo":
+                serviceSubtaskCountReq.setVisitCount(1);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L)));
+                break;
+            case "pendingFollowUpWaitSendAgainInfo":
+                serviceSubtaskCountReq.setVisitCount(2);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L)));
+                break;
+            case "pendingFollowUpSentInfo":
+                serviceSubtaskCountReq.setVisitCount(1);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(3L, 7L)));
+                break;
+            case "pendingFollowUpSentAgainInfo":
+                serviceSubtaskCountReq.setVisitCount(2);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(3L, 7L)));
+                break;
+            case "sentInfo":
+                serviceSubtaskCountReq.setVisitCount(1);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(3L)));
+                break;
+            case "sentAgainInfo":
+                serviceSubtaskCountReq.setVisitCount(2);
+                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(3L)));
                 break;
             default:
                 break;
@@ -5413,6 +5523,16 @@
         total.setAbnormal(0L);
         total.setNeedFollowUpAgain(0L);
         total.setPendingFollowUpAgain(0L);
+        total.setManualCallTimeout(0L);
+        total.setManualCallTimeoutAgain(0L);
+        total.setPendingFollowUpAll(0L);
+        total.setPendingFollowUpAllAgain(0L);
+        total.setPendingFollowUpWaitSend(0L);
+        total.setPendingFollowUpWaitSendAgain(0L);
+        total.setPendingFollowUpSent(0L);
+        total.setPendingFollowUpSentAgain(0L);
+        total.setSent(0L);
+        total.setSentAgain(0L);
         total.setFollowUpSuccessAgain(0L);
         total.setFollowUpFailAgain(0L);
         total.setManualAgain(0L);
@@ -5447,6 +5567,16 @@
             total.setAbnormal(total.getAbnormal() + (stat.getAbnormal() != null ? stat.getAbnormal() : 0L));
             total.setNeedFollowUpAgain(total.getNeedFollowUpAgain() + (stat.getNeedFollowUpAgain() != null ? stat.getNeedFollowUpAgain() : 0L));
             total.setPendingFollowUpAgain(total.getPendingFollowUpAgain() + (stat.getPendingFollowUpAgain() != null ? stat.getPendingFollowUpAgain() : 0L));
+            total.setManualCallTimeout(total.getManualCallTimeout() + (stat.getManualCallTimeout() != null ? stat.getManualCallTimeout() : 0L));
+            total.setManualCallTimeoutAgain(total.getManualCallTimeoutAgain() + (stat.getManualCallTimeoutAgain() != null ? stat.getManualCallTimeoutAgain() : 0L));
+            total.setPendingFollowUpAll(total.getPendingFollowUpAll() + (stat.getPendingFollowUpAll() != null ? stat.getPendingFollowUpAll() : 0L));
+            total.setPendingFollowUpAllAgain(total.getPendingFollowUpAllAgain() + (stat.getPendingFollowUpAllAgain() != null ? stat.getPendingFollowUpAllAgain() : 0L));
+            total.setPendingFollowUpWaitSend(total.getPendingFollowUpWaitSend() + (stat.getPendingFollowUpWaitSend() != null ? stat.getPendingFollowUpWaitSend() : 0L));
+            total.setPendingFollowUpWaitSendAgain(total.getPendingFollowUpWaitSendAgain() + (stat.getPendingFollowUpWaitSendAgain() != null ? stat.getPendingFollowUpWaitSendAgain() : 0L));
+            total.setPendingFollowUpSent(total.getPendingFollowUpSent() + (stat.getPendingFollowUpSent() != null ? stat.getPendingFollowUpSent() : 0L));
+            total.setPendingFollowUpSentAgain(total.getPendingFollowUpSentAgain() + (stat.getPendingFollowUpSentAgain() != null ? stat.getPendingFollowUpSentAgain() : 0L));
+            total.setSent(total.getSent() + (stat.getSent() != null ? stat.getSent() : 0L));
+            total.setSentAgain(total.getSentAgain() + (stat.getSentAgain() != null ? stat.getSentAgain() : 0L));
             total.setFollowUpSuccessAgain(total.getFollowUpSuccessAgain() + (stat.getFollowUpSuccessAgain() != null ? stat.getFollowUpSuccessAgain() : 0L));
             total.setFollowUpFailAgain(total.getFollowUpFailAgain() + (stat.getFollowUpFailAgain() != null ? stat.getFollowUpFailAgain() : 0L));
             total.setManualAgain(total.getManualAgain() + (stat.getManualAgain() != null ? stat.getManualAgain() : 0L));
diff --git a/smartor/src/main/resources/mapper/smartor/PatArchiveMapper.xml b/smartor/src/main/resources/mapper/smartor/PatArchiveMapper.xml
index 329cf76..de5d42f 100644
--- a/smartor/src/main/resources/mapper/smartor/PatArchiveMapper.xml
+++ b/smartor/src/main/resources/mapper/smartor/PatArchiveMapper.xml
@@ -286,6 +286,14 @@
         where id = #{id} and del_flag=0
     </select>
 
+    <!-- 涓茶鍖栧悓涓�鎮h�呯殑浜哄伐闅忚鍒涘缓锛岄伩鍏嶅苟鍙戦噸澶嶆牎楠屽け鏁� -->
+    <select id="lockPatArchiveByPatid" resultType="java.lang.Long">
+        select id
+        from pat_archive
+        where id = #{patid} and del_flag = 0
+        for update
+    </select>
+
     <select id="selectPatArchiveByPatnos" resultMap="PatArchiveResult">
         SELECT id, patientno
         FROM pat_archive
diff --git a/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml b/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
index 33fef15..c67e8c4 100644
--- a/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
+++ b/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
@@ -1671,6 +1671,19 @@
           </foreach>
     </update>
 
+    <!-- 浜哄伐闅忚閲嶅鏍¢獙锛氬悓涓�鎮h�呭悓涓�浠诲姟涓嬫槸鍚﹀凡鏈夋湭瀹屾垚闅忚浠诲姟 -->
+    <select id="countUnfinishedServiceSubtaskByPatidAndTaskid" resultType="int">
+        select count(1)
+        from service_subtask
+        where del_flag = 0
+          and patid = #{patid}
+          and taskid = #{taskid}
+          and sendstate in
+          <foreach collection="sendstates" item="sendstate" open="(" separator="," close=")">
+              #{sendstate}
+          </foreach>
+    </select>
+
     <select id="getSfStatistics" parameterType="com.smartor.domain.ServiceSubtaskCountReq"
             resultMap="ServiceSubtaskResult">
         select id,

--
Gitblit v1.9.3