From 87b79ea739ec32bd7d0e493a6ea8525212f6c763 Mon Sep 17 00:00:00 2001
From: liusheng <337615773@qq.com>
Date: 星期六, 10 十月 2026 15:11:17 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into smartor_ls_261008

---
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java |  263 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 256 insertions(+), 7 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 263b88b..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
@@ -1,14 +1,22 @@
 package com.ruoyi.web.controller.smartor;
 
+import com.ruoyi.common.annotation.AddOrgId;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.DtoConversionUtils;
 import com.ruoyi.common.utils.StringUtils;
-import com.smartor.domain.ServiceSubTaskDetailReq;
-import com.smartor.domain.ServiceSubtask;
-import com.smartor.domain.ServiceSubtaskDetail;
+import com.ruoyi.system.service.ISysConfigService;
+import com.smartor.domain.DTO.QuestionResultDTO;
+import com.smartor.domain.*;
+import com.smartor.domain.VO.MydTrendReqVO;
+import com.smartor.domain.VO.MzMydScoreRankVO;
+import com.smartor.domain.VO.QuestionCountKsOrBqVO;
+import com.smartor.domain.VO.SltdMydTotalVO;
+import com.smartor.domain.entity.ServiceSubtaskEntity;
 import com.smartor.service.IServiceSubtaskDetailService;
 import com.smartor.service.IServiceSubtaskService;
 import io.swagger.annotations.Api;
@@ -17,10 +25,12 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static com.ruoyi.framework.datasource.DynamicDataSourceContextHolder.log;
 
 /**
  * 璇煶浠诲姟缁撴灉鏄庣粏Controller
@@ -36,6 +46,9 @@
     private IServiceSubtaskDetailService ServiceSubtaskDetailService;
     @Autowired
     private IServiceSubtaskService serviceSubtaskService;
+
+    @Autowired
+    private ISysConfigService configService;
 
     /**
      * 鏌ヨ鍗曚釜浜虹殑璇煶淇℃伅
@@ -92,6 +105,9 @@
             serviceSubtask.setSendstate(6L);
             serviceSubtask.setId(serviceSubTaskDetailReq.getSubId());
             serviceSubtask.setRemark("鏁版嵁琛ュ厖瀹屾垚");
+            serviceSubtask.setUpdateTime(new Date());
+            serviceSubtask.setFinishtime(new Date());
+            serviceSubtask.setPreachform("1");
             serviceSubtask.setResult("success");
             aBoolean = serviceSubtaskService.updateServiceSubtask(serviceSubtask);
         }
@@ -143,4 +159,237 @@
         return toAjax(ServiceSubtaskDetailService.deleteServiceSubtaskDetailByCalldetailids(calldetailids));
     }
 
+    /**
+     * 鎸囨爣缁熻
+     */
+    //@PreAuthorize("@ss.hasPermi('smartor:ServiceSubtaskDetail:add')")
+    @ApiOperation("鎸囨爣缁熻")
+    @GetMapping(value = "/countPatByTarget/{targetid}")
+    public AjaxResult countPatByTarget(@PathVariable("targetid") Long targetid) {
+        return success(ServiceSubtaskDetailService.countPatByTarget(targetid));
+    }
+
+
+    /**
+     * 鑾峰彇闅忚璇︽儏-鎸囨爣璇︽儏(瓒呴摼鎺�)
+     */
+    @ApiOperation("鑾峰彇闅忚璇︽儏-鎸囨爣璇︽儏")
+    @PostMapping("/getServiceSubtaskDetails")
+    public List<Map<String, Object>> getServiceSubtaskDetails(@RequestBody ServiceSubtaskDetailVO serviceSubtaskDetailVO) {
+        List<Map<String, Object>> map = new ArrayList<>();
+        map = ServiceSubtaskDetailService.getServiceSubtaskDetails(serviceSubtaskDetailVO);
+        return map;
+    }
+
+    /**
+     * 鑾峰彇闅忚璇︽儏-鎸囨爣璇︽儏(瓒呴摼鎺�)
+     */
+    @ApiOperation("鑾峰彇闅忚璇︽儏-鎸囨爣璇︽儏(瓒呴摼鎺�)")
+    @PostMapping("/getServiceSubtaskDetailsHyperlink")
+    public List<Map<String, Object>> getServiceSubtaskDetailsHyperlink(@RequestBody ServiceSubtaskDetailVO serviceSubtaskDetailVO) {
+        LoginUser loginUser = getLoginUser();
+        String orgid = loginUser.getUser().getOrgid();
+        String configKey = serviceSubtaskDetailVO.getConfigKey();
+        if (StringUtils.isNotEmpty(configKey)) {
+            String configValue = configService.selectConfigByKey(configKey, orgid);
+            serviceSubtaskDetailVO.setConfigValue(configValue);
+            if (StringUtils.isEmpty(configValue)) {
+                String logInfo = "getSfStatisticsCount-鍙傛暟 " + configKey + " 鏈厤缃�, 璇烽厤缃ソ鍚庨噸璇�";
+                log.error(logInfo);
+            }
+        }
+        List<Map<String, Object>> map = new ArrayList<>();
+        map = ServiceSubtaskDetailService.getServiceSubtaskDetails(serviceSubtaskDetailVO);
+        return map;
+    }
+
+
+    /**
+     * 鐪佺珛鍚屽痉婊℃剰搴︽暟鎹粺璁★紙鎸夐鐩粺璁¢�夐」鏁伴噺/鍗犳瘮锛屽苟缁欏嚭璇ラ鐨勭患鍚堝緱鍒嗭級
+     * <p>
+     * 缁煎悎婊℃剰搴� = (寰堟弧鎰忛」鏁懊�1 + 婊℃剰椤规暟脳0.8 + 涓�鑸」鏁懊�0.6 + 涓嶆弧鎰忛」鏁懊�0.4 + 寰堜笉婊℃剰椤规暟脳0.2)
+     * / (寰堟弧鎰忛」鏁� + 婊℃剰椤规暟 + 涓�鑸」鏁� + 涓嶆弧鎰忛」鏁� + 寰堜笉婊℃剰椤规暟) 脳 100%锛�
+     * 銆屾湭缁忓巻銆嶃�屼笉閫傜敤銆嶇瓑涓嶅湪浜旀。閲岀殑閫夐」鏃笉杩涘垎瀛愪篃涓嶈繘鍒嗘瘝銆�
+     */
+    @ApiOperation("鐪佺珛鍚屽痉婊℃剰搴︽暟鎹粺璁�")
+    @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid")
+    @PostMapping("/sltdMydTotalByScore")
+    public Map<String, Object> sltdMydTotalByScore(@RequestBody SltdMydTotalVO sltdMydTotalVO) {
+        List<ServiceSubtaskRes> serviceSubtaskResList = null;
+        if (CollectionUtils.isNotEmpty(sltdMydTotalVO.getServiceTypeList())) {
+            //serviceType鍙兘浼氬嚭鐜板涓紝涓嶆兂澶氬啓鏂规硶浜嗭紝涓�涓竴涓煡璇㈠惂
+            for (String st : sltdMydTotalVO.getServiceTypeList()) {
+                ServiceSubtaskEntity serviceSubtaskEntity = new ServiceSubtaskEntity();
+                serviceSubtaskEntity.setServiceType(st);
+                serviceSubtaskEntity.setEndOutHospTime(sltdMydTotalVO.getEndOutHospTime());
+                serviceSubtaskEntity.setStartOutHospTime(sltdMydTotalVO.getStartOutHospTime());
+                serviceSubtaskEntity.setDeptOrDistrict(sltdMydTotalVO.getDeptOrDistrict());
+                serviceSubtaskEntity.setLeavehospitaldistrictcodes(sltdMydTotalVO.getLeavehospitaldistrictcodes());
+                serviceSubtaskEntity.setLeaveldeptcodes(sltdMydTotalVO.getLeaveldeptcodes());
+                //鏈烘瀯/闄㈠尯鐢� @AddOrgId 娉ㄥ叆锛岃惤鍒版煡璇㈡潯浠朵笂锛岄伩鍏嶈法鏈烘瀯鍙栨暟
+                serviceSubtaskEntity.setOrgid(sltdMydTotalVO.getOrgid());
+                serviceSubtaskEntity.setCampusid(sltdMydTotalVO.getCampusid());
+                if (serviceSubtaskEntity != null) {
+                    List<ServiceSubtask> serviceSubtasks = serviceSubtaskService.getServiceSubtasks(serviceSubtaskEntity);
+                    List<ServiceSubtaskRes> serviceSubtaskRes = DtoConversionUtils.sourceToTarget(serviceSubtasks, ServiceSubtaskRes.class);
+                    if (CollectionUtils.isNotEmpty(serviceSubtaskResList)) {
+                        serviceSubtaskResList.addAll(serviceSubtaskRes);
+                    } else {
+                        if (CollectionUtils.isEmpty(serviceSubtaskResList)) serviceSubtaskResList = serviceSubtaskRes;
+                    }
+                }
+            }
+        }
+        // 鎸� questiontext 鍒嗙粍鍚庤浆鎹负 QuestionResultVO
+        List<QuestionResultDTO> result = new ArrayList<>();
+        if (CollectionUtils.isNotEmpty(serviceSubtaskResList)) {
+            List<ServiceSubtaskDetailRatioExport> detailList = serviceSubtaskService.getDetailRatio(sltdMydTotalVO, serviceSubtaskResList);
+
+            if (detailList == null) {
+                //serviceType 缁勫悎涓嶅湪鏀寔鑼冨洿鍐咃紙濡傚悓鏃跺惈闅忚 2 鍜屾弧鎰忓害 6/14锛夛紝缁欐槑纭彁绀鸿�屼笉鏄倓鎮勮繑鍥炵┖鏁扮粍
+                return error("褰撳墠 serviceType 缁勫悎鏆備笉鏀寔缁熻闂鍗犳瘮锛岃鍒嗗紑鏌ヨ锛堜粎鏀寔闅忚 2 鎴栨弧鎰忓害 6/14锛�");
+            }
+            if (CollectionUtils.isNotEmpty(detailList)) {
+                Map<String, List<ServiceSubtaskDetailRatioExport>> groupedMap = detailList.stream().collect(Collectors.groupingBy(ServiceSubtaskDetailRatioExport::getQuestiontext));
+
+                groupedMap.forEach((questionText, exportList) -> {
+                    QuestionResultDTO questionResultDTO = new QuestionResultDTO();
+                    questionResultDTO.setQeustionText(questionText);
+                    questionResultDTO.setSubtaskDetailRatioExportList(exportList);
+                    //缁煎悎寰楀垎锛�(寰堟弧鎰徝�1 + 婊℃剰脳0.8 + 涓�鑸�0.6 + 涓嶆弧鎰徝�0.4 + 寰堜笉婊℃剰脳0.2) / 浜旀。椤规暟涔嬪拰 脳 100%
+                    questionResultDTO.setAvgScore(calcMydScore(exportList));
+                    result.add(questionResultDTO);
+                });
+            }
+        }
+
+        return success(result);
+    }
+
+    @ApiOperation("鐪佺珛鍚屽痉婊℃剰搴︽暟鎹粺璁¢�氳繃绉戝鎴栫梾鍖�")
+    @PostMapping("/statQuestionOptionByKsOrBq")
+    public Map<String, Object> statQuestionOptionByKsOrBq(@RequestBody QuestionCountKsOrBqVO questionResultVO) {
+        return success(serviceSubtaskService.statQuestionOptionByKsOrBq(questionResultVO));
+    }
+
+    @ApiOperation("鐪佺珛鍚屽痉鎮h�呮弧鎰忓害瓒嬪娍")
+    @PostMapping("/mydTrend")
+    public Map<String, Object> mydTrend(@RequestBody MydTrendReqVO mydTrendReqVO) {
+        return success(serviceSubtaskService.mydTrend(mydTrendReqVO));
+    }
+
+    @ApiOperation("鐪佺珛鍚屽痉鎮h�呮弧鎰忓害缁存姢")
+    @PostMapping("/sltdMydTotalByDimension")
+    public Map<String, Object> sltdMydTotalByDimension(@RequestBody MydTrendReqVO mydTrendReqVO) {
+        return success(serviceSubtaskService.sltdMydTotalByDimension(mydTrendReqVO));
+    }
+
+    @ApiOperation("闂ㄨ瘖婊℃剰搴︾患鍚堝緱鍒嗘帓鍚嶏紙鎸夌瀹ゆ垨鐥呭尯锛�")
+    @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid")
+    @PostMapping("/mzMydScoreRank")
+    public Map<String, Object> mzMydScoreRank(@RequestBody MzMydScoreRankVO mzMydScoreRankVO) {
+        return success(serviceSubtaskService.mzMydScoreRank(mzMydScoreRankVO));
+    }
+
+    /**
+     * 澶氶�夐鐨勯棶棰樼被鍨�
+     */
+    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>
+     * 缁煎悎婊℃剰搴� = (寰堟弧鎰忛」鏁懊�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"
+     */
+    private String calcMydScore(List<ServiceSubtaskDetailRatioExport> exportList) {
+        if (CollectionUtils.isEmpty(exportList)) return "0.00";
+
+        BigDecimal scoreSum = BigDecimal.ZERO;   //鍒嗗瓙锛毼�(妗d綅鏉冮噸 脳 椤规暟)
+        BigDecimal countSum = BigDecimal.ZERO;   //鍒嗘瘝锛氫簲妗i」鏁颁箣鍜�
+
+        for (ServiceSubtaskDetailRatioExport detail : exportList) {
+            //澶氶�夐涓�琛屾槸澶氫釜閫夐」鐨勫垎鍊间箣鍜岋紝鍒嗘瘝鍙畻 1 椤癸紝浼氭妸寰楀垎绠楅珮锛屼笉璁″叆缁煎悎寰楀垎
+            if (VALUE_TYPE_MULTIPLE.equals(detail.getValueType())) continue;
+            //銆屼笉閫傜敤銆嶄笉鍦ㄥ叕寮忕殑浜旀。閲岋紝涓嶈鍏ョ患鍚堝緱鍒�
+            if (isNotApplicable(detail)) continue;
+
+            int optionIndex = mydScoreOptionIndex(detail.getOptionresult());
+            BigDecimal count = parseDecimal(detail.getCount());
+            if (optionIndex < 0 || count == null || count.signum() <= 0) continue;
+
+            scoreSum = scoreSum.add(MYD_SCORE_WEIGHTS[optionIndex].multiply(count));
+            countSum = countSum.add(count);
+        }
+
+        if (countSum.signum() <= 0) return "0.00";
+
+        return scoreSum.divide(countSum, 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) {
+        return containsNotApplicable(detail.getOptionresult()) || containsNotApplicable(detail.getTargetvalue());
+    }
+
+    private boolean containsNotApplicable(String optionText) {
+        if (StringUtils.isEmpty(optionText)) return false;
+        String text = optionText.trim();
+        return text.contains("涓嶉�傜敤") || text.contains("鏈瓟") || text.contains("鎷掔瓟");
+    }
+
+    /**
+     * 瀛楃涓茶浆 BigDecimal锛岀┖鍊�/闈炴硶鍊艰繑鍥� null
+     */
+    private BigDecimal parseDecimal(String value) {
+        if (StringUtils.isEmpty(value)) return null;
+        try {
+            return new BigDecimal(value.trim());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
 }

--
Gitblit v1.9.3