From 278a56025b6e64e49a3453f0b9be84832de96066 Mon Sep 17 00:00:00 2001
From: liusheng <337615773@qq.com>
Date: 星期一, 28 九月 2026 10:01:07 +0800
Subject: [PATCH] 1.代码提交

---
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java |   64 ++++++--
 smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java                  |  130 ++++++++++++-----
 ruoyi-admin/src/main/resources/application.yml                                                 |    2 
 smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java            |  134 ++++++++++++-------
 smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml                             |   41 +++--
 5 files changed, 247 insertions(+), 124 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java
index d29f168..ca2cba4 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java
@@ -207,9 +207,9 @@
     /**
      * 鐪佺珛鍚屽痉婊℃剰搴︽暟鎹粺璁★紙鎸夐鐩粺璁¢�夐」鏁伴噺/鍗犳瘮锛屽苟缁欏嚭璇ラ鐨勭患鍚堝緱鍒嗭級
      * <p>
-     * 缁煎悎婊℃剰搴� = 危(閫夐」鍒嗗�� 脳 椤规暟) / 危椤规暟 / 鏈鏈�楂樺垎鍊� 脳 100%锛�
-     * 鍒嗗�煎彇 1銆�0.8銆�0.6銆�0.4銆�0.2 浜旀。锛堝緢婊℃剰銆佹弧鎰忋�佷竴鑸�佷笉婊℃剰銆佸緢涓嶆弧鎰忥級锛�
-     * 銆屼笉閫傜敤銆嶃��0 鍒嗐�佺┖鍊肩瓑鏃笉杩涘垎瀛愪篃涓嶈繘鍒嗘瘝銆�
+     * 缁煎悎婊℃剰搴� = (寰堟弧鎰忛」鏁懊�1 + 婊℃剰椤规暟脳0.8 + 涓�鑸」鏁懊�0.6 + 涓嶆弧鎰忛」鏁懊�0.4 + 寰堜笉婊℃剰椤规暟脳0.2)
+     * / (寰堟弧鎰忛」鏁� + 婊℃剰椤规暟 + 涓�鑸」鏁� + 涓嶆弧鎰忛」鏁� + 寰堜笉婊℃剰椤规暟) 脳 100%锛�
+     * 銆屾湭缁忓巻銆嶃�屼笉閫傜敤銆嶇瓑涓嶅湪浜旀。閲岀殑閫夐」鏃笉杩涘垎瀛愪篃涓嶈繘鍒嗘瘝銆�
      */
     @ApiOperation("鐪佺珛鍚屽痉婊℃剰搴︽暟鎹粺璁�")
     @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid")
@@ -256,7 +256,7 @@
                     QuestionResultDTO questionResultDTO = new QuestionResultDTO();
                     questionResultDTO.setQeustionText(questionText);
                     questionResultDTO.setSubtaskDetailRatioExportList(exportList);
-                    //缁煎悎寰楀垎锛毼�(鍒嗗�济楅」鏁�) / 危椤规暟 / 鏈鏈�楂樺垎鍊� 脳 100%锛屼笉閫傜敤/0鍒�/绌哄�间笉杩涘垎瀛愪篃涓嶈繘鍒嗘瘝
+                    //缁煎悎寰楀垎锛�(寰堟弧鎰徝�1 + 婊℃剰脳0.8 + 涓�鑸�0.6 + 涓嶆弧鎰徝�0.4 + 寰堜笉婊℃剰脳0.2) / 浜旀。椤规暟涔嬪拰 脳 100%
                     questionResultDTO.setAvgScore(calcMydScore(exportList));
                     result.add(questionResultDTO);
                 });
@@ -297,11 +297,25 @@
     private static final String VALUE_TYPE_MULTIPLE = "2";
 
     /**
+     * 婊℃剰搴︿簲妗i�夐」锛堥『搴忎笌鏉冮噸椤哄簭涓�鑷达級
+     */
+    private static final String[] MYD_SCORE_OPTIONS = {"寰堟弧鎰�", "婊℃剰", "涓�鑸�", "涓嶆弧鎰�", "寰堜笉婊℃剰"};
+
+    /**
+     * 婊℃剰搴︿簲妗f潈閲嶏細寰堟弧鎰� 1銆佹弧鎰� 0.8銆佷竴鑸� 0.6銆佷笉婊℃剰 0.4銆佸緢涓嶆弧鎰� 0.2
+     */
+    private static final BigDecimal[] MYD_SCORE_WEIGHTS = {
+            new BigDecimal("1"), new BigDecimal("0.8"), new BigDecimal("0.6"), new BigDecimal("0.4"), new BigDecimal("0.2")};
+
+    /**
      * 璁$畻涓�閬撻鐨勬弧鎰忓害缁煎悎寰楀垎锛堢櫨鍒嗗埗锛屼繚鐣欎袱浣嶅皬鏁帮級
      * <p>
-     * 缁煎悎婊℃剰搴� = 危(閫夐」鍒嗗�� 脳 椤规暟) / 危椤规暟 / 鏈鏈�楂樺垎鍊� 脳 100%
-     * 绛変环浜� 危(寰堟弧鎰徝�1 + 婊℃剰脳0.8 + 涓�鑸�0.6 + 涓嶆弧鎰徝�0.4 + 寰堜笉婊℃剰脳0.2) / 危(浜旀。椤规暟) 脳 100%銆�
-     * 鐢ㄦ湰棰樻渶楂樺垎鍊煎綊涓�鍖栵紝鍏煎鏄庣粏鍒嗗�煎瓨 0-1 鏉冮噸锛�1銆�0.8鈥︼級鍜屽瓨 5 鍒嗗埗锛�5銆�4鈥︼級涓ょ鍙e緞銆�
+     * 缁煎悎婊℃剰搴� = (寰堟弧鎰忛」鏁懊�1 + 婊℃剰椤规暟脳0.8 + 涓�鑸」鏁懊�0.6 + 涓嶆弧鎰忛」鏁懊�0.4 + 寰堜笉婊℃剰椤规暟脳0.2)
+     * / (寰堟弧鎰忛」鏁� + 婊℃剰椤规暟 + 涓�鑸」鏁� + 涓嶆弧鎰忛」鏁� + 寰堜笉婊℃剰椤规暟) 脳 100%
+     * <p>
+     * 鏉冮噸鎸夐�夐」鏂囨鍒ゅ畾锛堣 {@link #mydScoreOptionIndex(String)}锛夛紝涓嶅啀渚濊禆鏄庣粏鐨� score 瀛楁锛�
+     * 鍘嗗彶鏁版嵁閲� score 鏈� 0銆併��0000000001銆嶈繖绫昏剰鍊硷紝鎸� score 绠椾細鎶婂緱鍒嗗浐瀹氭垚 0 鎴� 100銆�
+     * 銆屾湭缁忓巻銆嶃�屼笉閫傜敤銆嶇瓑涓嶅湪浜旀。閲岀殑閫夐」鏃笉杩涘垎瀛愪篃涓嶈繘鍒嗘瘝銆�
      *
      * @param exportList 鍚屼竴閬撻鐩殑閫夐」缁熻鏄庣粏
      * @return 鐧惧垎鍒剁患鍚堝緱鍒嗭紝鏃犳湁鏁堥」鏁版椂杩斿洖 "0.00"
@@ -309,9 +323,8 @@
     private String calcMydScore(List<ServiceSubtaskDetailRatioExport> exportList) {
         if (CollectionUtils.isEmpty(exportList)) return "0.00";
 
-        BigDecimal scoreSum = BigDecimal.ZERO;   //鍒嗗瓙锛毼�(閫夐」鍒嗗�� 脳 椤规暟)
-        BigDecimal countSum = BigDecimal.ZERO;   //鍒嗘瘝锛毼i」鏁�
-        BigDecimal maxScore = null;              //鏈鏈�楂樺垎鍊硷紝鐢ㄤ簬褰掍竴鍖�
+        BigDecimal scoreSum = BigDecimal.ZERO;   //鍒嗗瓙锛毼�(妗d綅鏉冮噸 脳 椤规暟)
+        BigDecimal countSum = BigDecimal.ZERO;   //鍒嗘瘝锛氫簲妗i」鏁颁箣鍜�
 
         for (ServiceSubtaskDetailRatioExport detail : exportList) {
             //澶氶�夐涓�琛屾槸澶氫釜閫夐」鐨勫垎鍊间箣鍜岋紝鍒嗘瘝鍙畻 1 椤癸紝浼氭妸寰楀垎绠楅珮锛屼笉璁″叆缁煎悎寰楀垎
@@ -319,27 +332,42 @@
             //銆屼笉閫傜敤銆嶄笉鍦ㄥ叕寮忕殑浜旀。閲岋紝涓嶈鍏ョ患鍚堝緱鍒�
             if (isNotApplicable(detail)) continue;
 
-            BigDecimal score = parseDecimal(detail.getScore());
+            int optionIndex = mydScoreOptionIndex(detail.getOptionresult());
             BigDecimal count = parseDecimal(detail.getCount());
-            if (score == null || count == null) continue;
-            //0 鍒嗭紙鏈瓟/绌虹瓟锛夈�佺┖鏁伴噺锛氭棦涓嶈繘鍒嗗瓙涔熶笉杩涘垎姣�
-            if (score.signum() <= 0 || count.signum() <= 0) continue;
+            if (optionIndex < 0 || count == null || count.signum() <= 0) continue;
 
-            if (maxScore == null || score.compareTo(maxScore) > 0) maxScore = score;
-            scoreSum = scoreSum.add(score.multiply(count));
+            scoreSum = scoreSum.add(MYD_SCORE_WEIGHTS[optionIndex].multiply(count));
             countSum = countSum.add(count);
         }
 
-        if (maxScore == null || countSum.signum() <= 0) return "0.00";
+        if (countSum.signum() <= 0) return "0.00";
 
         return scoreSum.divide(countSum, 6, RoundingMode.HALF_UP)
-                .divide(maxScore, 6, RoundingMode.HALF_UP)
                 .multiply(BigDecimal.valueOf(100))
                 .setScale(2, RoundingMode.HALF_UP)
                 .toPlainString();
     }
 
     /**
+     * 閫夐」鏂囨 鈫� 婊℃剰搴︿簲妗d笅鏍囷紙寰堟弧鎰� 0銆佹弧鎰� 1銆佷竴鑸� 2銆佷笉婊℃剰 3銆佸緢涓嶆弧鎰� 4锛夛紝涓嶅湪浜旀。閲岃繑鍥� -1
+     */
+    private int mydScoreOptionIndex(String optionresult) {
+        if (StringUtils.isEmpty(optionresult)) return -1;
+        String text = optionresult.trim();
+        for (int i = 0; i < MYD_SCORE_OPTIONS.length; i++) {
+            if (MYD_SCORE_OPTIONS[i].equals(text)) return i;
+        }
+        //鍏煎銆孉 寰堟弧鎰忋�嶃�孊.婊℃剰銆嶈繖绫诲甫閫夐」搴忓彿鍓嶇紑鐨勫巻鍙叉暟鎹�
+        if (text.length() > 2 && (text.charAt(1) == ' ' || text.charAt(1) == '.' || text.charAt(1) == '銆�')) {
+            String stripped = text.substring(2).trim();
+            for (int i = 0; i < MYD_SCORE_OPTIONS.length; i++) {
+                if (MYD_SCORE_OPTIONS[i].equals(stripped)) return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
      * 鏄惁銆屼笉閫傜敤銆嶉�夐」
      */
     private boolean isNotApplicable(ServiceSubtaskDetailRatioExport detail) {
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index dfa12b4..74fc7a4 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -75,7 +75,7 @@
     # 鍥介檯鍖栬祫婧愭枃浠惰矾寰�
     basename: i18n/messages
   profiles:
-    active: nhfy
+    active: druid
 
   # 鏂囦欢涓婁紶
   servlet:
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 6540161..41cb800 100644
--- a/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java
@@ -97,6 +97,66 @@
     private String dealDeptCode;
 
     /**
+     * 瀹夊叏瑙f瀽鍒嗘暟锛歯ull銆佺┖涓层�佺┖鐧戒覆浠ュ強闈炴硶鏍煎紡涓�寰嬫寜 0 澶勭悊锛岄伩鍏� Double.parseDouble 鎶� NumberFormatException
+     *
+     * @param scoreValue 鍒嗘暟瀛楃涓�
+     * @return 瑙f瀽鍚庣殑鍒嗘暟锛屾棤娉曡В鏋愭椂杩斿洖 0
+     */
+    private double parseScore(String scoreValue) {
+        if (StringUtils.isEmpty(scoreValue)) {
+            return 0D;
+        }
+        try {
+            return Double.parseDouble(scoreValue.trim());
+        } catch (NumberFormatException e) {
+            log.warn("鍒嗘暟鏍煎紡闈炴硶锛屾寜 0 澶勭悊锛屽師濮嬪�硷細{}", scoreValue);
+            return 0D;
+        }
+    }
+
+    /**
+     * 灏嗙疮鍔犲悗鐨勫垎鍊兼牸寮忓寲涓鸿惤搴撳瓧绗︿覆锛屽幓鎺夊浣欑殑灏忔暟浣嶏紙濡� 5.0 -> 5锛�
+     *
+     * @param scoreValue 鍒嗗��
+     * @return 鍒嗘暟瀛楃涓�
+     */
+    private String formatScore(double scoreValue) {
+        if (Double.isNaN(scoreValue) || Double.isInfinite(scoreValue)) {
+            log.warn("鍒嗘暟璁$畻缁撴灉闈炴硶锛屾寜 0 澶勭悊锛屽師濮嬪�硷細{}", scoreValue);
+            return "0";
+        }
+        return BigDecimal.valueOf(scoreValue).stripTrailingZeros().toPlainString();
+    }
+
+    /**
+     * 瀹夊叏瑙f瀽寮傚父鏍囪锛歯ull銆佺┖涓层�侀潪娉曟牸寮忎竴寰嬫寜 0锛堟甯革級澶勭悊
+     *
+     * @param isabnormalFlag 寮傚父鏍囪瀛楃涓�
+     * @return 寮傚父鏍囪鍊�
+     */
+    private Integer parseIsabnormal(String isabnormalFlag) {
+        if (StringUtils.isEmpty(isabnormalFlag)) {
+            return 0;
+        }
+        try {
+            return Integer.valueOf(isabnormalFlag.trim());
+        } catch (NumberFormatException e) {
+            log.warn("寮傚父鏍囪鏍煎紡闈炴硶锛屾寜 0 澶勭悊锛屽師濮嬪�硷細{}", isabnormalFlag);
+            return 0;
+        }
+    }
+
+    /**
+     * 褰掍竴鍖栧垎鏁板瓧绗︿覆锛岄伩鍏嶆妸 null 鎴栫┖涓诧紙鍓嶇鏈紶/鏈綔绛旓級鏀惧埌 map 涓紶閫掔粰绱姞閫昏緫
+     *
+     * @param scoreValue 鍘熷鍒嗗��
+     * @return 闈炵┖鍒嗗�硷紝榛樿 "0"
+     */
+    private String normalizeScore(String scoreValue) {
+        return StringUtils.isEmpty(scoreValue) ? "0" : scoreValue.trim();
+    }
+
+    /**
      * 鏌ヨ浠诲姟闂嵎闂閫夐」
      *
      * @param id 浠诲姟闂嵎闂閫夐」涓婚敭
@@ -237,7 +297,7 @@
                 subtaskCache.put(subtaskCacheKey, initialSubtaskList.get(0));
             }
 
-            String score = "0";
+            double scoreTotal = 0D;
             Long nextScriptno = null;
             aa:
             for (String key : targetKeys) {
@@ -271,11 +331,7 @@
                                     if (map == null) continue aa;
                                     if (!Objects.isNull(map.get("nextScriptNo")))
                                         nextScriptno = Long.valueOf(map.get("nextScriptNo"));
-                                    if (score == null || score.isEmpty()) {
-                                        score = map.get("score");
-                                    } else {
-                                        score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
-                                    }
+                                    scoreTotal += parseScore(map.get("score"));
                                 }
                             }
 
@@ -290,11 +346,7 @@
                                 log.error("nextScriptNo鐨勪俊鎭负锛歿}", map.get("nextScriptNo"));
                                 if (!Objects.isNull(map.get("nextScriptNo")))
                                     nextScriptno = Long.valueOf(map.get("nextScriptNo"));
-                                if (score == null) {
-                                    score = map.get("score");
-                                } else {
-                                    score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
-                                }
+                                scoreTotal += parseScore(map.get("score"));
                             }
                         }
                     }
@@ -313,11 +365,7 @@
                                     Map<String, String> map = setSFInfo(ivrTaskTemplateScriptVO, tid, pid, subid);
                                     if (!Objects.isNull(map.get("nextScriptNo")))
                                         nextScriptno = Long.valueOf(map.get("nextScriptNo"));
-                                    if (score == null || score.isEmpty()) {
-                                        score = map.get("score");
-                                    } else {
-                                        score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
-                                    }
+                                    scoreTotal += parseScore(map.get("score"));
                                 }
                             }
 
@@ -331,11 +379,7 @@
                                 log.error("----nextScriptNo2鐨勪俊鎭负锛歿}", map.get("nextScriptNo"));
                                 if (!Objects.isNull(map.get("nextScriptNo")))
                                     nextScriptno = Long.valueOf(map.get("nextScriptNo"));
-                                if (score == null) {
-                                    score = map.get("score");
-                                } else {
-                                    score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
-                                }
+                                scoreTotal += parseScore(map.get("score"));
                             }
                         }
                     }
@@ -375,7 +419,7 @@
                 serviceSubtask.setFinishtime(new Date());
                 serviceSubtask.setUpdateTime(new Date());
                 log.error("灏嗚key鍜寁alue浠巖edis涓�,serviceSubtask鐨勫�间负--------锛歿}", serviceSubtask);
-                if (score != null && !score.isEmpty()) serviceSubtask.setScore(score);
+                serviceSubtask.setScore(formatScore(scoreTotal));
                 serviceSubtaskMapper.updateServiceSubtaskByCondition(serviceSubtask);
 
                 //灏嗗綋鍓嶅彂閫佺姸鎬佹敼鎴� 9 瀹屾垚锛堢紦瀛� preachform 鏌ヨ锛�
@@ -416,7 +460,7 @@
         Long tid = Long.valueOf(serviceSubTaskCacheReq.getParam1());
         Long pid = Long.valueOf(serviceSubTaskCacheReq.getParam2());
         Long subid = Long.valueOf(serviceSubTaskCacheReq.getParam6());
-        String score = "0";
+        double scoreTotal = 0D;
         if (ObjectUtils.isNotEmpty(serviceSubTaskCacheReq)) {
             Long nextScriptno = null;
             String isabnormalFlag = "0";
@@ -463,18 +507,16 @@
 
                     if (shouldProcess) {
                         Map<String, String> map = setWJInfo(svyTaskTemplateScriptVO, tid, pid, subid, preServiceSubtaskList, preServiceTask, preDetailIdMap, preTraceIdMap);
-                        log.error("nextScriptNo 鐨勪俊鎭负锛歿}", map.get("nextScriptNo"));
                         if (map == null) continue;
+                        log.info("nextScriptNo 鐨勪俊鎭负锛歿}", map.get("nextScriptNo"));
 
                         if (!Objects.isNull(map.get("nextScriptNo")))
                             nextScriptno = Long.valueOf(map.get("nextScriptNo"));
 
-                        if (score == null) {
-                            score = map.get("score");
-                        } else {
-                            score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
+                        scoreTotal += parseScore(map.get("score"));
+                        if (StringUtils.isNotEmpty(map.get("isabnormal"))) {
+                            isabnormalFlag = map.get("isabnormal");
                         }
-                        isabnormalFlag = map.get("isabnormal");
                     }
                 }
             } else if (serviceSubTaskCacheReq.getType() == 1) {
@@ -512,12 +554,10 @@
                         log.error("----nextScriptNo2 鐨勪俊鎭负锛歿}", map.get("nextScriptNo"));
                         if (!Objects.isNull(map.get("nextScriptNo")))
                             nextScriptno = Long.valueOf(map.get("nextScriptNo"));
-                        if (score == null) {
-                            score = map.get("score");
-                        } else {
-                            score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
+                        scoreTotal += parseScore(map.get("score"));
+                        if (StringUtils.isNotEmpty(map.get("isabnormal"))) {
+                            isabnormalFlag = map.get("isabnormal");
                         }
-                        isabnormalFlag = map.get("isabnormal");
                     }
                 }
             }
@@ -533,12 +573,12 @@
             serviceSubtask.setTaskid(tid);
             serviceSubtask.setPatid(pid);
             serviceSubtask.setSubmit(1L);
-            serviceSubtask.setIsabnormal(Integer.valueOf(isabnormalFlag));
+            serviceSubtask.setIsabnormal(parseIsabnormal(isabnormalFlag));
             serviceSubtask.setSendstate(6L);
             serviceSubtask.setExcep(isabnormalFlag);
             serviceSubtask.setFinishtime(new Date());
             serviceSubtask.setUpdateTime(new Date());
-            if (score != null && !score.isEmpty()) serviceSubtask.setScore(score);
+            serviceSubtask.setScore(formatScore(scoreTotal));
             serviceSubtaskMapper.updateServiceSubtaskByCondition(serviceSubtask);
 
             //灏嗗綋鍓嶅彂閫佺姸鎬佹敼鎴�9瀹屾垚
@@ -594,7 +634,7 @@
         }
 
         if (CollectionUtils.isNotEmpty(serviceSubTaskMYDAnswerReq.getSvyTaskTemplateScriptVOS())) {
-            String score = "0";
+            double scoreTotal = 0D;
             List<SvyTaskTemplateScriptVO> svyTaskTemplateScriptVOS = serviceSubTaskMYDAnswerReq.getSvyTaskTemplateScriptVOS();
             Long nextScriptno = null;
 
@@ -628,11 +668,7 @@
                     log.error("nextScriptNo 鐨勪俊鎭负锛歿}", map.get("nextScriptNo"));
                     if (!Objects.isNull(map.get("nextScriptNo"))) nextScriptno = Long.valueOf(map.get("nextScriptNo"));
 
-                    if (score == null || score.isEmpty()) {
-                        score = map.get("score");
-                    } else {
-                        score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
-                    }
+                    scoreTotal += parseScore(map.get("score"));
 
                     if (!Objects.isNull(map.get("id"))) {
                         idList.add(Long.valueOf(map.get("id")));
@@ -694,7 +730,7 @@
                 serviceSubtask.setUpdateTime(new Date());
                 serviceSubtask.setCreateTime(new Date());
                 serviceSubtask.setVisitTime(new Date());
-                if (score != null && !score.isEmpty()) serviceSubtask.setScore(score);
+                serviceSubtask.setScore(formatScore(scoreTotal));
                 serviceSubtaskMapper.insertServiceSubtask(serviceSubtask);
                 //灏嗗綋鍓嶅彂閫佺姸鎬佹敼鎴�9瀹屾垚
                 ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
@@ -998,7 +1034,7 @@
                 nextScriptNo = getNextScriptNo(svyTaskTemplateScriptVO.getTemplateID(), svyTaskTemplateScriptVO.getScriptContent());
             }
             if (svyTaskTemplateScriptVO.getScore() != null) {
-                score = String.valueOf(svyTaskTemplateScriptVO.getScore());
+                score = normalizeScore(String.valueOf(svyTaskTemplateScriptVO.getScore()));
             }
             serviceSubtaskDetailVO.setAsrtext(StringUtils.isEmpty(svyTaskTemplateScriptVO.getScriptResult()) ? "" : svyTaskTemplateScriptVO.getScriptResult().replaceAll("^\"|\"$", ""));
             serviceSubtaskDetailVO.setMatchedtext(StringUtils.isEmpty(svyTaskTemplateScriptVO.getScriptResult()) ? "" : svyTaskTemplateScriptVO.getScriptResult().replaceAll("^\"|\"$", ""));
@@ -1009,7 +1045,7 @@
             if (StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getScriptResult())) {
                 serviceSubtaskDetailVO.setAsrtext(svyTaskTemplateScriptVO.getScriptResult());
                 if (svyTaskTemplateScriptVO.getScore() != null) {
-                    score = String.valueOf(svyTaskTemplateScriptVO.getScore());
+                    score = normalizeScore(String.valueOf(svyTaskTemplateScriptVO.getScore()));
                 }
             }
             nextScriptNo = svyTaskTemplateScriptVO.getNextScriptno();
@@ -1153,7 +1189,7 @@
 
         Map<String, String> map = new HashMap<>();
         map.put("nextScriptNo", nextScriptNo);
-        map.put("score", score);
+        map.put("score", normalizeScore(score));
         map.put("id", "" + serviceSubtaskDetail.getId());
         map.put("isabnormal", isabnormalFlag.toString());
         return map;
@@ -1298,7 +1334,7 @@
             }
 
             if (ivrTaskTemplateScriptVO.getScore() != null) {
-                score = String.valueOf(ivrTaskTemplateScriptVO.getScore());
+                score = normalizeScore(String.valueOf(ivrTaskTemplateScriptVO.getScore()));
             }
             if (StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getQuestionResult())) {
                 serviceSubtaskDetailVO.setAsrtext(ivrTaskTemplateScriptVO.getQuestionResult().replaceAll("^\"|\"$", ""));
@@ -1319,7 +1355,7 @@
                     nextScriptNo = "" + getVoiceNextScriptNo(ivrTaskTemplateScriptVO.getTemplateID(), ivrTaskTemplateScriptVO.getScriptContent());
                 }
                 if (ivrTaskTemplateScriptVO.getScore() != null) {
-                    score = String.valueOf(ivrTaskTemplateScriptVO.getScore());
+                    score = normalizeScore(String.valueOf(ivrTaskTemplateScriptVO.getScore()));
                 }
             }
         }
@@ -1447,7 +1483,7 @@
 
         Map<String, String> map = new HashMap<>();
         map.put("nextScriptNo", nextScriptNo);
-        map.put("score", score);
+        map.put("score", normalizeScore(score));
         map.put("isabnormal", isabnormalFlag);
         return map;
     }
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 ebed5a9..25e9f60 100644
--- a/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
@@ -5596,55 +5596,105 @@
         }
 
         List<ServiceSubtaskDetailRatioExport> serviceSubtaskDetailRatioExports = serviceSubtaskMapper.statQuestionOptionBySubtaskIds(subtaskIds, startOutHospTime, endOutHospTime, startFinishTime, endFinishTime, scoreStart, scoreEnd, scriptContent, valueType);
-        // 澶勭悊 targetvalue锛氭寜 & 鍒嗗壊鎴愬鏉¤褰�
+        // SQL 宸叉寜銆岄鐩� + 閫夐」銆嶆眹鎬绘暟閲忥紝杩欓噷鍐嶆寜棰樼洰鍚堝苟锛堜笉鍚屾ā鏉跨殑 targetvalue 閫夐」椤哄簭涓嶅悓锛屽悓涓�閫夐」浼氭媶鎴愬琛岋級锛�
+        // 骞舵妸娌′汉閫夌殑閫夐」琛ユ垚 0 琛屻�佹寜鍚勯�夐」鏁伴噺涔嬪拰閲嶇畻姣斾緥
+        return mergeMydOptionRows(serviceSubtaskDetailRatioExports);
+    }
+
+    /**
+     * 鎶� SQL 杩斿洖鐨勩�岄鐩� + 閫夐」銆嶆槑缁嗗悎骞舵垚銆屼竴琛屼竴涓�夐」銆�
+     * <ul>
+     *     <li>鍚屼竴棰樼洰涓嬬浉鍚� optionresult 鐨勬暟閲忕疮鍔狅細鍘熷疄鐜伴亣鍒板悓鍚嶉�夐」鐩存帴 continue锛�
+     *         姣忎釜閫夐」鍙細淇濈暀绗竴鏉℃槑缁嗙殑鏁伴噺锛屽浠诲姟/澶氭偅鑰呯殑椤规暟鍏ㄨ涓㈡帀锛屽墠绔�屾暟閲忋�嶆案杩滃彧鏈� 1</li>
+     *     <li>閫夐」娓呭崟鍙� targetvalue锛堢敤 &amp; 杩炴帴锛夛紝娌′汉閫夌殑閫夐」琛� 0 琛岋紝鍓嶇鍥哄畾鍏垪鎵嶈兘娓叉煋</li>
+     *     <li>姣斾緥 = 璇ラ�夐」鏁伴噺 / 璇ラ鍚勯�夐」鏁伴噺涔嬪拰锛屼繚璇佷竴閬撻鍚勯�夐」姣斾緥鍚堣 100%</li>
+     * </ul>
+     *
+     * @param rows SQL 鏄庣粏
+     */
+    private List<ServiceSubtaskDetailRatioExport> mergeMydOptionRows(List<ServiceSubtaskDetailRatioExport> rows) {
         List<ServiceSubtaskDetailRatioExport> result = new ArrayList<>();
-        for (ServiceSubtaskDetailRatioExport export : serviceSubtaskDetailRatioExports) {
-            if (StringUtils.isNotEmpty(export.getTargetvalue()) && export.getTargetvalue().contains("&")) {
-                String[] values = export.getTargetvalue().split("&");
-                // 濡傛灉鏈夊鏉$洰鏍囧�硷紝鎷嗗垎鎴愬琛�
-                for (String value : values) {
-                    //鍏堝幓 result 涓煡涓�涓嬶紝鏈夋病鏈夎繖涓� questiontext 鍜屽搴旂殑 targetvalue
-                    ServiceSubtaskDetailRatioExport existingExport = result.stream().filter(e -> {
-                        if (e == null || export == null) {
-                            return false;
-                        }
-                        String q1 = e.getQuestiontext() != null ? e.getQuestiontext() : "";
-                        String q2 = export.getQuestiontext() != null ? export.getQuestiontext() : "";
-                        String t1 = value.trim();
-                        String t2 = e.getTargetvalue() != null ? e.getTargetvalue() : "";
-                        return q1.equals(q2) && t1.equals(t2);
-                    }).findFirst().orElse(null);
-                    if (existingExport != null && "0".equals(existingExport.getRatio()) && "0".equals(existingExport.getCount())) {
-                        //濡傛灉瀛樺湪锛屽垯灏� result 閲岀殑杩欎釜闂鎵�瀵瑰簲鐨� Targetvalue=value 杩欐潯鏁版嵁鏇存柊鎴愬綋鍓嶈繖鏉℃暟鎹�
-                        if (value.equals(export.getOptionresult())) {
-                            existingExport.setRatio(export.getRatio());
-                            existingExport.setScore(export.getScore());
-                            existingExport.setCount(export.getCount());
-                            existingExport.setOptionresult(export.getOptionresult());
-                        }
-                    } else if (existingExport != null && !"0".equals(existingExport.getRatio())) {
-                        continue;
-                    } else {
-                        ServiceSubtaskDetailRatioExport newExport = DtoConversionUtils.sourceToTarget(export, ServiceSubtaskDetailRatioExport.class);
-                        newExport.setTargetvalue(value.trim()); // targetvalue 鏄剧ず鍗曚釜閫夐」
-                        if (!value.equals(export.getOptionresult())) {
-                            newExport.setOptionresult(null);
-                            newExport.setCount("0");
-                            newExport.setRatio("0");
-                        }
-                        result.add(newExport);
-                    }
+        if (CollectionUtils.isEmpty(rows)) {
+            return result;
+        }
+
+        // key -> 閫夐」 -> 鏁伴噺锛岀敤 LinkedHashMap 淇濆簭锛氶�夐」椤哄簭娌跨敤闂嵎閰嶇疆 targetvalue 鐨勯『搴�
+        Map<String, Map<String, long[]>> countMap = new LinkedHashMap<>();
+        Map<String, Map<String, String>> scoreMap = new LinkedHashMap<>();
+        Map<String, ServiceSubtaskDetailRatioExport> templateMap = new LinkedHashMap<>();
+
+        for (ServiceSubtaskDetailRatioExport row : rows) {
+            if (row == null) {
+                continue;
+            }
+            String key = row.getQuestiontext();
+            if (key == null) {
+                continue;
+            }
+            Map<String, long[]> counts = countMap.computeIfAbsent(key, k -> new LinkedHashMap<>());
+            Map<String, String> scores = scoreMap.computeIfAbsent(key, k -> new LinkedHashMap<>());
+            templateMap.putIfAbsent(key, row);
+
+            // 棰樼洰閰嶇疆鐨勯�夐」娓呭崟锛氭病浜洪�夌殑閫夐」涔熻鍒楀嚭鏉ワ紙鏁伴噺涓� 0锛�
+            for (String option : splitOptions(row.getTargetvalue())) {
+                counts.computeIfAbsent(option, k -> new long[1]);
+            }
+
+            // 鎮h�呭疄闄呴�変腑鐨勯�夐」锛氬閫夐 asrtext 鏄�岄�夐」1&閫夐」2銆嶏紝鍗曢��/闂瓟棰樻槸鏁存鏂囨湰
+            List<String> chosenOptions = "2".equals(row.getValueType())
+                    ? splitOptions(row.getOptionresult())
+                    : singleOption(row.getOptionresult());
+            if (chosenOptions.isEmpty()) {
+                // 鏈綔绛旓細涓嶈繘浠讳綍閫夐」锛屼篃涓嶈繘鍒嗘瘝
+                continue;
+            }
+            long count = parseCount(row.getCount());
+            for (String chosen : chosenOptions) {
+                // 閫変腑鐨勯�夐」鍙兘涓嶅湪閰嶇疆娓呭崟閲岋紙鍘嗗彶鏁版嵁锛夛紝琛ヤ竴琛岋紝鏁伴噺涓嶈兘涓�
+                counts.computeIfAbsent(chosen, k -> new long[1])[0] += count;
+                if (StringUtils.isNotEmpty(row.getScore()) && StringUtils.isEmpty(scores.get(chosen))) {
+                    scores.put(chosen, row.getScore());
                 }
-            } else {
-                // targetvalue 涓嶅寘鍚� &锛岀洿鎺ユ坊鍔犲埌缁撴灉
-                result.add(export);
             }
         }
 
+        for (Map.Entry<String, Map<String, long[]>> entry : countMap.entrySet()) {
+            ServiceSubtaskDetailRatioExport template = templateMap.get(entry.getKey());
+            Map<String, String> scores = scoreMap.get(entry.getKey());
+            long total = 0L;
+            for (long[] count : entry.getValue().values()) {
+                total += count[0];
+            }
+            for (Map.Entry<String, long[]> optionEntry : entry.getValue().entrySet()) {
+                String option = optionEntry.getKey();
+                long count = optionEntry.getValue()[0];
+                ServiceSubtaskDetailRatioExport merged = DtoConversionUtils.sourceToTarget(template, ServiceSubtaskDetailRatioExport.class);
+                merged.setQuestiontext(template.getQuestiontext());
+                merged.setTargetvalue(option);
+                // 娌′汉閫夌殑閫夐」 optionresult 缃┖锛屽墠绔寜 targetvalue 鍏滃簳灞曠ず锛屼繚鎸佸師鏈夊睍绀哄彛寰�
+                merged.setOptionresult(count > 0 ? option : null);
+                merged.setCount(String.valueOf(count));
+                merged.setRatio(formatRatio(count, total));
+                merged.setScore(StringUtils.isNotEmpty(scores.get(option)) ? scores.get(option) : template.getScore());
+                result.add(merged);
+            }
+        }
         return result;
     }
 
     /**
+     * 鍗曢��/闂瓟棰樼殑浣滅瓟鏂囨湰锛氫笉鎸� &amp; 鎷嗭紝閬垮厤鎶婇棶绛旈鐨勬枃鏈瓟妗堟媶鍧�
+     */
+    private static List<String> singleOption(String answer) {
+        List<String> options = new ArrayList<>();
+        String text = trimAll(answer);
+        if (StringUtils.isNotEmpty(text)) {
+            options.add(text);
+        }
+        return options;
+    }
+
+    /**
      * 鏍囧噯鍖栭棶鍗风瓟妗堟枃鏈細鍘绘帀 A/B/C/D 鍗曞瓧姣嶅墠缂�鍜屽悗缁┖鏍�
      * 渚嬪 "A 鏄�" -> "鏄�"锛�"B 鍚�" -> "鍚�"
      */
diff --git a/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml b/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
index 9c23ee0..71d8a36 100644
--- a/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
+++ b/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
@@ -3399,14 +3399,15 @@
     <select id="statQuestionOptionBySubtaskIds" resultType="com.smartor.domain.ServiceSubtaskDetailRatioExport">
         SELECT
         d.questiontext AS questiontext,
-        t.taskid AS taskid,
-        t.task_name AS taskName,
+        <!-- 鏄庣粏宸叉寜銆岄鐩� + 閫夐」銆嶆眹鎬伙紝浠诲姟/绉戝/鐥呭尯鍙槸闄勫甫淇℃伅锛屽繀椤荤敤鑱氬悎鍑芥暟鍙栧�硷紙MySQL ONLY_FULL_GROUP_BY锛� -->
+        MAX(t.taskid) AS taskid,
+        MAX(t.task_name) AS taskName,
         d.asrtext AS optionresult,
         d.score AS score,
-        s.deptcode AS deptcode,
-        s.deptname AS deptname,
-        s.leavehospitaldistrictcode AS leavehospitaldistrictcode,
-        s.leavehospitaldistrictname AS leavehospitaldistrictname,
+        MAX(s.deptcode) AS deptcode,
+        MAX(s.deptname) AS deptname,
+        MAX(s.leavehospitaldistrictcode) AS leavehospitaldistrictcode,
+        MAX(s.leavehospitaldistrictname) AS leavehospitaldistrictname,
         d.targetvalue AS targetvalue,
         d.value_type AS valueType,
         COUNT(*) AS count,
@@ -3424,9 +3425,15 @@
         AND d2.del_flag = '0'
         )
         INNER JOIN (
+        <!-- 鍒嗘瘝 = 璇ラ鍚勯�夐」椤规暟涔嬪拰锛堟湭浣滅瓟鐨勭┖ asrtext 涓嶈繘鍒嗘瘝锛夛紝杩欐牱涓�閬撻鍚勯�夐」姣斾緥鍚堣鎵嶆槸 100% -->
+        SELECT
+        x.questiontext AS questiontext,
+        SUM(x.option_count) AS total_count
+        FROM (
         SELECT
         d.questiontext,
-        COUNT(*) AS total_count
+        d.asrtext,
+        COUNT(*) AS option_count
         FROM
         service_task t
         INNER JOIN service_subtask s ON s.taskid = t.taskid
@@ -3467,7 +3474,11 @@
         <if test="endFinishTime != null">
             AND date_format(s.finishtime,'%y%m%d') &lt;= date_format(#{endFinishTime},'%y%m%d')
         </if>
-        GROUP BY d.questiontext
+        <!-- 鏈綔绛旓紙asrtext 涓虹┖锛夌殑鏄庣粏涓嶈鍏ュ垎姣� -->
+        AND d.asrtext IS NOT NULL AND TRIM(d.asrtext) &lt;&gt; ''
+        GROUP BY d.questiontext, d.asrtext
+        ) x
+        GROUP BY x.questiontext
         ) t2 ON t2.questiontext = d.questiontext
         WHERE 1=1
         <!-- 鍘婚噸锛氭槑缁嗚鍚屼竴瀛愪换鍔″悓涓�棰樼洰鍙繚鐣欐渶鏂颁竴鏉★紝閲嶇瓟涓嶉噸澶嶈鍏ラ」鏁� -->
@@ -3486,6 +3497,8 @@
         </if>
         AND s.sendstate = 6
         AND d.del_flag=0
+        <!-- 鏈綔绛旓紙asrtext 涓虹┖锛変笉绠椾换浣曢�夐」锛屾槑缁嗛噷鐩存帴鎺掗櫎锛岄伩鍏嶅嚭鐜扮┖閫夐」琛� -->
+        AND d.asrtext IS NOT NULL AND TRIM(d.asrtext) &lt;&gt; ''
         <if test="valueType != null">AND d.value_type &gt;= #{valueType}</if>
         <if test="scoreStart != null">AND d.score &gt;= #{scoreStart}</if>
         <if test="scoreEnd != null">AND d.score &lt;= #{scoreEnd}</if>
@@ -3504,21 +3517,17 @@
         <if test="endFinishTime != null">
             AND date_format(s.finishtime,'%y%m%d') &lt;= date_format(#{endFinishTime},'%y%m%d')
         </if>
+        <!-- 鍙寜銆岄鐩� + 閫夐」銆嶆眹鎬伙細鍘熸潵 GROUP BY 甯︿笂 taskid/绉戝/鐥呭尯锛屽悓涓�涓�夐」琚媶鎴愬琛屻�佹瘡琛屾暟閲忛兘鏄� 1锛�
+             鍓嶇/瀵煎嚭鎷垮埌鐨勩�屾暟閲忋�嶅氨姘歌繙鍋氫笉浜嗙疮鍔� -->
         GROUP BY
-        t.taskid,
         d.questiontext,
+        d.asrtext,
         d.score,
         d.targetvalue,
-        d.asrtext,
-        t.task_name,
-        s.deptcode,
-        s.deptname,
-        s.leavehospitaldistrictcode,
-        s.leavehospitaldistrictname,
         d.value_type
         ORDER BY
         d.questiontext,
-        t.taskid
+        MIN(t.taskid)
     </select>
 
     <select id="statQuestionOptionByKsOrBq" resultType="com.smartor.domain.DTO.QuestionCountKsOrBqDTO"

--
Gitblit v1.9.3