From 93078044580c2781cb8cf3ac18d2ab90513267de Mon Sep 17 00:00:00 2001
From: liusheng <337615773@qq.com>
Date: 星期一, 28 九月 2026 17:13:36 +0800
Subject: [PATCH] 处理患者再入院状态代码提交
---
smartor/src/main/java/com/smartor/service/impl/PatSatisfactionServiceImpl.java | 968 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 965 insertions(+), 3 deletions(-)
diff --git a/smartor/src/main/java/com/smartor/service/impl/PatSatisfactionServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/PatSatisfactionServiceImpl.java
index 918caac..d952ca2 100644
--- a/smartor/src/main/java/com/smartor/service/impl/PatSatisfactionServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/PatSatisfactionServiceImpl.java
@@ -1,14 +1,31 @@
package com.smartor.service.impl;
-import java.util.List;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.stream.Collectors;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.entity.SysUserDept;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.utils.Arith;
+import com.ruoyi.common.utils.ArrayListUtils;
import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.DtoConversionUtils;
+import com.smartor.domain.*;
+import com.smartor.domain.DTO.ServiceSubtaskDetailDTO;
+import com.smartor.domain.VO.PatSatisfactionReqVO;
+import com.smartor.domain.VO.PatSatisfactionResVO;
+import com.smartor.domain.entity.PatSatisfactionDetailEntity;
+import com.smartor.domain.entity.SatisfactionStatQuery;
+import com.smartor.domain.entity.ServiceSubtaskSatisfactionEntity;
+import com.smartor.mapper.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import com.smartor.mapper.PatSatisfactionMapper;
-import com.smartor.domain.PatSatisfaction;
import com.smartor.service.IPatSatisfactionService;
+
+import static com.ruoyi.common.utils.SecurityUtils.getLoginUser;
/**
* 鎮h�呮弧鎰忓害Service涓氬姟灞傚鐞�
@@ -20,6 +37,30 @@
public class PatSatisfactionServiceImpl implements IPatSatisfactionService {
@Autowired
private PatSatisfactionMapper patSatisfactionMapper;
+
+ @Autowired
+ private ServiceSubtaskMapper serviceSubtaskMapper;
+
+ @Autowired
+ private ServiceSubtaskDetailMapper serviceSubtaskDetailMapper;
+
+ @Autowired
+ private IvrLibaTemplateScriptMapper ivrLibaTemplateScriptMapper;
+
+ @Autowired
+ private IvrLibaScriptAssortMapper ivrLibaScriptAssortMapper;
+
+ @Autowired
+ private SvyLibScriptCategoryMapper svyLibScriptCategoryMapper;
+
+ @Autowired
+ private IvrLibaTemplateTargetoptionMapper ivrLibaTemplateTargetoptionMapper;
+
+ @Autowired
+ private SvyLibTemplateTargetoptionMapper svyLibTemplateTargetoptionMapper;
+
+ @Autowired
+ private SvyLibTemplateScriptMapper svyLibTemplateScriptMapper;
/**
* 鏌ヨ鎮h�呮弧鎰忓害
@@ -67,6 +108,50 @@
}
/**
+ * 鏂板鎮h�呮弧鎰忓害
+ *
+ * @param patSatisfactions 鎮h�呮弧鎰忓害
+ * @return 缁撴灉
+ */
+ @Override
+ public int batchInsert(List<PatSatisfaction> patSatisfactions) {
+ if(CollectionUtils.isEmpty(patSatisfactions)){
+ return 0;
+ }
+ List<Long> ids = patSatisfactions.stream().map(PatSatisfaction::getId).
+ distinct().collect(Collectors.toList());
+ List<PatSatisfaction> patSatisfactionsOld = new ArrayList<>();
+ PatSatisfaction patSatisfactionVo = new PatSatisfaction();
+ patSatisfactionVo.setIds(ids);
+ patSatisfactionsOld = patSatisfactionMapper.selectPatSatisfactionList(patSatisfactionVo);
+ Map<String, List<PatSatisfaction>> maps = ArrayListUtils.splitListsById(patSatisfactions,
+ patSatisfactionsOld, PatSatisfaction::getId);
+ //鍙湪patSatisfactions鐨勬暟鎹紝鎵ц鏂板鎿嶄綔
+ List<PatSatisfaction> addItems = maps.get("onlyIn1");
+ //鍙湪patSatisfactionsOld鐨勬暟鎹紝鎵ц鍒犻櫎鎿嶄綔
+// List<PatSatisfaction> delItems = maps.get("onlyIn2");
+ //閲嶅彔鐨勬暟鎹紝鎵ц鏇存柊鎿嶄綔
+ List<PatSatisfaction> editItems = maps.get("common");
+ Integer count = 0;
+ LoginUser loginUser = getLoginUser();
+ SysUser user = loginUser.getUser();
+ for (PatSatisfaction patSatisfaction0 : editItems) {
+ patSatisfaction0.setUpdateBy(user.getNickName());
+ patSatisfaction0.setUpdateTime(DateUtils.getNowDate());
+ count = count + patSatisfactionMapper.updatePatSatisfaction(patSatisfaction0);
+ }
+
+ for (PatSatisfaction patSatisfaction1 : addItems) {
+ patSatisfaction1.setCreateBy(user.getNickName());
+ patSatisfaction1.setOrgid(user.getOrgid());
+ patSatisfaction1.setCreateTime(DateUtils.getNowDate());
+ patSatisfaction1.setUpdateTime(DateUtils.getNowDate());
+ count = count + patSatisfactionMapper.insertPatSatisfaction(patSatisfaction1);
+ }
+ return count;
+ }
+
+ /**
* 淇敼鎮h�呮弧鎰忓害
*
* @param patSatisfaction 鎮h�呮弧鎰忓害
@@ -99,4 +184,881 @@
public int deletePatSatisfactionById(Long id) {
return patSatisfactionMapper.deletePatSatisfactionById(id);
}
+
+ /**
+ * 鎮h�呮弧鎰忓害缁熻
+ *
+ * @param patSatisfactionReqVO 鎮h�呮弧鎰忓害缁熻鏉′欢
+ * @return 鎮h�呮弧鎰忓害缁熻缁撴灉
+ */
+ @Override
+ public PatSatisfactionResVO statistics(PatSatisfactionReqVO patSatisfactionReqVO) {
+ //瀹氫箟杩斿弬
+ PatSatisfactionResVO result = new PatSatisfactionResVO();
+ //鎮h�呮弧鎰忓害缁熻鎯�
+ List<PatSatisfactionDetailEntity> patSatisfactionDetailEntities = new ArrayList<>();
+ // [0]=绛旈鎬讳汉鏁�(宸茬粡鍥炵瓟闂鐨�) [1]=鎬讳汉鏁帮紙鍖呭惈鏈洖绛旂殑锛�
+ int[] personTotals = new int[2];
+
+ // 鍙煡鏈鏉′欢涓嬪疄闄呭瓨鍦ㄥ摢浜� type锛堝師鏉ユ槸鎶婃帴杩戝叏琛ㄧ殑涓婄櫨涓瓧娈垫煡鍥炴潵锛屼粎鐢ㄤ簬鍒ゆ柇涓嬮潰涓や釜鍒嗘敮鏄惁涓虹┖锛�
+ List<String> types = serviceSubtaskMapper.selectSatisfactionSubtaskTypes(patSatisfactionReqVO);
+ boolean hasVoice = types != null && types.contains("1");
+ boolean hasQuestionnaire = types != null && types.contains("2");
+
+ if (hasVoice) {
+ //1. 鍏堣幏鍙杋vr_liba_script_assort鐨勬弧鎰忓害鍒嗙被ID
+ IvrLibaScriptAssort ivrLibaScriptAssort = new IvrLibaScriptAssort();
+ ivrLibaScriptAssort.setOrgid(patSatisfactionReqVO.getOrgid());
+ List<IvrLibaScriptAssort> ivrLibaScriptAssorts = ivrLibaScriptAssortMapper.selectIvrLibaScriptAssortList(ivrLibaScriptAssort);
+ List<Long> mydIdList = ivrLibaScriptAssorts.stream().filter(item -> item.getType() != null && item.getType().contains("myd")).map(IvrLibaScriptAssort::getId).collect(Collectors.toList());
+
+ //2 鍐嶈幏鍙栬闂婊℃剰搴﹀垎绫讳笅鐨処vrLibaTemplateScript鐨勯泦鍚�
+ List<IvrLibaTemplateScript> ivrLibaTemplateScripts = ivrLibaTemplateScriptMapper.queryLibTemplateIds(mydIdList);
+
+ //3 涓�娆$粺璁″叏閮ㄩ棶棰樼殑鍙戦�侀噺/濉姤閲�/閫夐」鍒嗗�硷紙鍘熸潵鏄瘡涓棶棰樺悇鏌� 3 娆★級
+ List<SatScriptRef> scriptRefs = new ArrayList<>();
+ for (IvrLibaTemplateScript ivrLibaTemplateScript : ivrLibaTemplateScripts) {
+ scriptRefs.add(new SatScriptRef(ivrLibaTemplateScript.getTemplateid(), ivrLibaTemplateScript.getScriptid(), ivrLibaTemplateScript.getScriptContent()));
+ }
+ buildSatisfactionDetailEntities(patSatisfactionReqVO, "1", true, scriptRefs, patSatisfactionDetailEntities, personTotals);
+ }
+
+ if (hasQuestionnaire) {
+ //1. 鍏堣幏鍙杝vy_lib_script_category鐨勬弧鎰忓害鍒嗙被ID
+ SvyLibScriptCategory svyLibScriptCategory = new SvyLibScriptCategory();
+ svyLibScriptCategory.setOrgid(patSatisfactionReqVO.getOrgid());
+ List<SvyLibScriptCategory> svyLibScriptCategories = svyLibScriptCategoryMapper.selectSvyLibScriptCategoryList(svyLibScriptCategory);
+ List<Long> mydIdList = svyLibScriptCategories.stream().filter(item -> item.getType() != null && item.getType().contains("myd")).map(SvyLibScriptCategory::getId).collect(Collectors.toList());
+
+ //2 鍐嶈幏鍙栬闂婊℃剰搴﹀垎绫讳笅鐨処vrLibaTemplateScript鐨勯泦鍚�
+ List<SvyLibTemplateScript> svyLibTemplateScripts = svyLibTemplateScriptMapper.querySvyLibTemplateIds(mydIdList);
+
+ //3 涓�娆$粺璁″叏閮ㄩ棶棰樼殑鍙戦�侀噺/濉姤閲�/閫夐」鍒嗗�硷紙鍘熸潵鏄瘡涓棶棰樺悇鏌� 3 娆★級
+ List<SatScriptRef> scriptRefs = new ArrayList<>();
+ for (SvyLibTemplateScript svyLibTemplateScript : svyLibTemplateScripts) {
+ // 闂嵎鐨勯�夐」琛ㄦ寜 svy_lib_template_script 鐨勪富閿叧鑱�
+ scriptRefs.add(new SatScriptRef(svyLibTemplateScript.getSvyid(), svyLibTemplateScript.getId(), svyLibTemplateScript.getScriptContent()));
+ }
+ buildSatisfactionDetailEntities(patSatisfactionReqVO, "2", false, scriptRefs, patSatisfactionDetailEntities, personTotals);
+ }
+ result.setTotalAnswerRate(Arith.div(personTotals[0], personTotals[1]));
+ result.setPatSatisfactionDetailEntities(patSatisfactionDetailEntities);
+ result.setTotalPerson(personTotals[0]);
+
+ return result;
+ }
+
+ /**
+ * 鎮h�呮弧鎰忓害缁熻锛堢淮搴︼級
+ *
+ * @param patSatisfactionReqVO 鎮h�呮弧鎰忓害缁熻鏉′欢
+ * @return 鎮h�呮弧鎰忓害缁熻缁撴灉
+ */
+ @Override
+ public PatSatisfactionResVO statisticsByDimension(PatSatisfactionReqVO patSatisfactionReqVO) {
+ //瀹氫箟杩斿弬
+ PatSatisfactionResVO result = new PatSatisfactionResVO();
+ //鎮h�呮弧鎰忓害缁熻鎯�
+ List<PatSatisfactionDetailEntity> patSatisfactionDetailEntities = new ArrayList<>();
+ // [0]=绛旈鎬讳汉鏁�(宸茬粡鍥炵瓟闂鐨�) [1]=鎬讳汉鏁帮紙鍖呭惈鏈洖绛旂殑锛�
+ int[] personTotals = new int[2];
+
+ // 鍙煡鏈鏉′欢涓嬪疄闄呭瓨鍦ㄥ摢浜� type锛堝師鏉ユ槸鎶婃帴杩戝叏琛ㄧ殑涓婄櫨涓瓧娈垫煡鍥炴潵锛屼粎鐢ㄤ簬鍒ゆ柇涓嬮潰涓や釜鍒嗘敮鏄惁涓虹┖锛�
+ List<String> types = serviceSubtaskMapper.selectSatisfactionSubtaskTypes(patSatisfactionReqVO);
+ boolean hasVoice = types != null && types.contains("1");
+ boolean hasQuestionnaire = types != null && types.contains("2");
+
+ if (hasVoice) {
+ //1. 鍏堣幏鍙栧叆鍙備腑鐨勭淮鎶ら泦鍚�
+ IvrLibaTemplateScript iltscript = new IvrLibaTemplateScript();
+ iltscript.setDimensionList(patSatisfactionReqVO.getDimensionList());
+
+ //2 鍐嶈幏鍙栬闂婊℃剰搴﹀垎绫讳笅鐨処vrLibaTemplateScript鐨勯泦鍚�
+ List<IvrLibaTemplateScript> ivrLibaTemplateScripts = ivrLibaTemplateScriptMapper.selectILTSBydimension(iltscript);
+ if (CollectionUtils.isNotEmpty(ivrLibaTemplateScripts)) {
+ //3 涓�娆$粺璁″叏閮ㄩ棶棰樼殑鍙戦�侀噺/濉姤閲�/閫夐」鍒嗗�硷紙鍘熸潵鏄瘡涓棶棰樺悇鏌� 3 娆★級
+ List<SatScriptRef> scriptRefs = new ArrayList<>();
+ for (IvrLibaTemplateScript ivrLibaTemplateScript : ivrLibaTemplateScripts) {
+ scriptRefs.add(new SatScriptRef(ivrLibaTemplateScript.getTemplateid(), ivrLibaTemplateScript.getScriptid(), ivrLibaTemplateScript.getScriptContent()));
+ }
+ buildSatisfactionDetailEntities(patSatisfactionReqVO, "1", true, scriptRefs, patSatisfactionDetailEntities, personTotals);
+ }
+ }
+
+ if (hasQuestionnaire) {
+ //1. 鍏堣幏鍙栧叆鍙備腑鐨勬弧鎰忓害缁村害
+ SvyLibTemplateScriptVO svyLibTemplateScriptVO = new SvyLibTemplateScriptVO();
+ svyLibTemplateScriptVO.setDimensionList(patSatisfactionReqVO.getDimensionList());
+ //2 鍐嶈幏鍙栬闂婊℃剰搴﹀垎绫讳笅鐨処vrLibaTemplateScript鐨勯泦鍚�
+ List<SvyLibTemplateScript> svyLibTemplateScripts = svyLibTemplateScriptMapper.selectSLTScriptListBydimension(svyLibTemplateScriptVO);
+ if (CollectionUtils.isNotEmpty(svyLibTemplateScripts)) {
+ //3 涓�娆$粺璁″叏閮ㄩ棶棰樼殑鍙戦�侀噺/濉姤閲�/閫夐」鍒嗗�硷紙鍘熸潵鏄瘡涓棶棰樺悇鏌� 3 娆★級
+ List<SatScriptRef> scriptRefs = new ArrayList<>();
+ for (SvyLibTemplateScript svyLibTemplateScript : svyLibTemplateScripts) {
+ // 闂嵎鐨勯�夐」琛ㄦ寜 svy_lib_template_script 鐨勪富閿叧鑱�
+ scriptRefs.add(new SatScriptRef(svyLibTemplateScript.getSvyid(), svyLibTemplateScript.getId(), svyLibTemplateScript.getScriptContent()));
+ }
+ buildSatisfactionDetailEntities(patSatisfactionReqVO, "2", false, scriptRefs, patSatisfactionDetailEntities, personTotals);
+ }
+ }
+ result.setTotalAnswerRate(Arith.div(personTotals[0], personTotals[1]));
+ result.setPatSatisfactionDetailEntities(patSatisfactionDetailEntities);
+ result.setTotalPerson(personTotals[0]);
+
+ return result;
+ }
+
+ @Override
+ public Map<String, Object> satisfactionGraph(PatSatisfactionReqVO patSatisfactionReqVO) {
+ //鐢ㄦ潵璁板綍鏌辩姸鍥句俊鎭紙key=婊℃剰搴﹀垎绫诲悕绉帮紝value=婊℃剰搴﹀垎绫讳笅鐨勬�讳汉鏁板拰濉姤浜烘暟锛�
+ Map<String, Object> zzt = new HashMap<>();
+
+ // 璁板綍涓�涓嬫瘡绉嶅垎绫荤殑濉姤鎯呭喌锛堝彧璁板垎鍊间笌鏉℃暟锛屼笉鍐嶆妸鏄庣粏琛屽叏閮ㄦ煡鍥� Java锛�
+ Map<String, List<ScoreCount>> assortNameFillCountMap = new HashMap<>();
+
+ if (patSatisfactionReqVO.getType() == null || patSatisfactionReqVO.getType() == 1) {
+ //1. 鍏堣幏鍙杋vr_liba_script_assort鐨勬弧鎰忓害鍒嗙被ID
+ IvrLibaScriptAssort ivrLibaScriptAssort = new IvrLibaScriptAssort();
+ ivrLibaScriptAssort.setOrgid(patSatisfactionReqVO.getOrgid());
+ List<IvrLibaScriptAssort> ivrLibaScriptAssorts = ivrLibaScriptAssortMapper.selectIvrLibaScriptAssortList(ivrLibaScriptAssort);
+ List<Long> mydIdList = ivrLibaScriptAssorts.stream().filter(item -> item.getType() != null && item.getType().contains("myd")).map(IvrLibaScriptAssort::getId).collect(Collectors.toList());
+
+ //2 鍐嶈幏鍙栬闂婊℃剰搴﹀垎绫讳笅鐨処vrLibaTemplateScript鐨勯泦鍚�
+ List<IvrLibaTemplateScript> ivrLibaTemplateScripts = ivrLibaTemplateScriptMapper.queryLibTemplateIds(mydIdList);
+
+ //2.1 涓�娆℃�ф妸鏈璇锋眰鍏ㄩ儴妯℃澘鐨勫彂閫侀噺銆佸~鎶ラ噺鏌ュ洖鏉ワ紙鍘熸潵鏄瘡涓ā鏉块棶棰樺悇鏌ヤ袱娆★級
+ SatisfactionStatQuery statQuery = buildSatisfactionStatQuery(patSatisfactionReqVO, "1",
+ ivrLibaTemplateScripts.stream().map(IvrLibaTemplateScript::getTemplateid).collect(Collectors.toList()));
+ Map<Long, Long> sendCountMap = mapSatisfactionSendCount(statQuery);
+ SatisfactionFillStat fillStat = querySatisfactionFillStat(statQuery);
+
+ //3 鎸塻criptAssortname鍒嗙粍,骞惰幏鍙栨瘡涓泦鍚堣繘琛岄亶鍘嗭紝璁$畻姣忎釜鍒嗙被鐨勬�讳汉鏁板拰濉姤浜烘暟
+ Map<String, List<IvrLibaTemplateScript>> scriptGroupByAssortName = ivrLibaTemplateScripts.stream().filter(item -> item.getScriptAssortname() != null).collect(Collectors.groupingBy(IvrLibaTemplateScript::getScriptAssortname));
+ if (scriptGroupByAssortName != null && !scriptGroupByAssortName.isEmpty()) {
+ for (String assortNameKey : scriptGroupByAssortName.keySet()) {
+ //璁板綍鎬讳汉鏁�
+ Double subidAll = 0.0;
+ //璁板綍鎬荤殑濉姤浜烘暟
+ Double fillCountAll = 0.0;
+ //鑾峰彇璇ュ垎绫荤殑濉姤鎬绘暟閲�
+ List<ScoreCount> allFillCountList = new ArrayList<>();
+
+ List<IvrLibaTemplateScript> ivrLibaTemplateScriptList = scriptGroupByAssortName.get(assortNameKey);
+ for (IvrLibaTemplateScript ivrLibaTemplateScript : ivrLibaTemplateScriptList) {
+ //閫氳繃妯℃澘id鍙栭棶棰樺彂閫佹�婚噺锛堝師鏉ユ槸鎶婂叏閮� sub_id 鏌ュ洖 Java 鍐嶅彇 size锛�
+ subidAll += sendCountMap.getOrDefault(ivrLibaTemplateScript.getTemplateid(), 0L);
+ //鑾峰彇濉姤鏁伴噺锛堝師鏉ユ槸鎶婃槑缁嗚鍏ㄩ儴鏌ュ洖 Java 鍐嶅彇 size锛�
+ List<ScoreCount> fillCount = fillStat.get(ivrLibaTemplateScript.getTemplateid(), ivrLibaTemplateScript.getScriptContent());
+ if (CollectionUtils.isNotEmpty(fillCount)) allFillCountList.addAll(fillCount);
+ fillCountAll += countFillRows(fillCount);
+ }
+
+ // 杩欓噷鍏堣褰曚竴涓嬫瘡涓垎绫荤殑鎬讳汉鏁板拰濉姤浜烘暟
+ Map<String, Object> personCount = new HashMap<>();
+ personCount.put("fillCountAll", fillCountAll);
+ personCount.put("subidAll", subidAll);
+ personCount.put("receiveRate", Arith.div(fillCountAll, subidAll));
+ personCount.put("averageScore", averageScoreByStat(allFillCountList));
+ zzt.put(assortNameKey, personCount);
+ assortNameFillCountMap.put(assortNameKey, allFillCountList);
+ }
+ }
+ }
+
+ if (patSatisfactionReqVO.getType() == null || patSatisfactionReqVO.getType() == 2) {
+ //1. 鍏堣幏鍙杝vy_lib_script_category鐨勬弧鎰忓害鍒嗙被ID
+ SvyLibScriptCategory svyLibScriptCategory = new SvyLibScriptCategory();
+ svyLibScriptCategory.setOrgid(patSatisfactionReqVO.getOrgid());
+ List<SvyLibScriptCategory> svyLibScriptCategories = svyLibScriptCategoryMapper.selectSvyLibScriptCategoryList(svyLibScriptCategory);
+ List<Long> mydIdList = svyLibScriptCategories.stream().filter(item -> item.getType() != null && item.getType().contains("myd")).map(SvyLibScriptCategory::getId).collect(Collectors.toList());
+
+ //2 鍐嶈幏鍙栬闂婊℃剰搴﹀垎绫讳笅鐨処vrLibaTemplateScript鐨勯泦鍚�
+ List<SvyLibTemplateScript> svyLibTemplateScripts = svyLibTemplateScriptMapper.querySvyLibTemplateIds(mydIdList);
+
+ //2.1 涓�娆℃�ф妸鏈璇锋眰鍏ㄩ儴妯℃澘鐨勫彂閫侀噺銆佸~鎶ラ噺鏌ュ洖鏉ワ紙鍘熸潵鏄瘡涓ā鏉块棶棰樺悇鏌ヤ袱娆★級
+ SatisfactionStatQuery statQuery = buildSatisfactionStatQuery(patSatisfactionReqVO, "2",
+ svyLibTemplateScripts.stream().map(SvyLibTemplateScript::getSvyid).collect(Collectors.toList()));
+ Map<Long, Long> sendCountMap = mapSatisfactionSendCount(statQuery);
+ SatisfactionFillStat fillStat = querySatisfactionFillStat(statQuery);
+
+ //3 鎸塻criptAssortname鍒嗙粍,骞惰幏鍙栨瘡涓泦鍚堣繘琛岄亶鍘嗭紝璁$畻姣忎釜鍒嗙被鐨勬�讳汉鏁板拰濉姤浜烘暟
+ Map<String, List<SvyLibTemplateScript>> scriptGroupByatCegoryName = svyLibTemplateScripts.stream().filter(item -> item.getCategoryName() != null).collect(Collectors.groupingBy(SvyLibTemplateScript::getCategoryName));
+ if (scriptGroupByatCegoryName != null && !scriptGroupByatCegoryName.isEmpty()) {
+ for (String categoryNameKey : scriptGroupByatCegoryName.keySet()) {
+ //璁板綍鎬讳汉鏁�
+ Double subidAll = 0.0;
+ //璁板綍鎬荤殑濉姤浜烘暟
+ Double fillCountAll = 0.0;
+ //鑾峰彇璇ュ垎绫荤殑濉姤鎬绘暟閲�
+ List<ScoreCount> allFillCountList = new ArrayList<>();
+
+ List<SvyLibTemplateScript> svyLibTemplateScriptList = scriptGroupByatCegoryName.get(categoryNameKey);
+ for (SvyLibTemplateScript svyLibTemplateScript : svyLibTemplateScriptList) {
+ //閫氳繃妯℃澘id鍙栭棶棰樺彂閫佹�婚噺锛堝師鏉ユ槸鎶婂叏閮� sub_id 鏌ュ洖 Java 鍐嶅彇 size锛�
+ subidAll += sendCountMap.getOrDefault(svyLibTemplateScript.getSvyid(), 0L);
+ //鑾峰彇濉姤鏁伴噺锛堝師鏉ユ槸鎶婃槑缁嗚鍏ㄩ儴鏌ュ洖 Java 鍐嶅彇 size锛�
+ List<ScoreCount> fillCount = fillStat.get(svyLibTemplateScript.getSvyid(), svyLibTemplateScript.getScriptContent());
+ if (CollectionUtils.isNotEmpty(fillCount)) allFillCountList.addAll(fillCount);
+ fillCountAll += countFillRows(fillCount);
+ }
+
+
+ // 杩欓噷鍏堣褰曚竴涓嬫瘡涓垎绫荤殑鎬讳汉鏁板拰濉姤浜烘暟
+ Map<String, Object> personCount = (Map<String, Object>) zzt.get(categoryNameKey);
+ if (!Objects.isNull(personCount)) {
+ Double fillCountAll2 = (Double) personCount.get("fillCountAll");
+ Double subidAll2 = (Double) personCount.get("subidAll");
+ personCount.put("fillCountAll", fillCountAll2 + fillCountAll);
+ personCount.put("subidAll", subidAll2 + subidAll);
+ personCount.put("receiveRate", Arith.div((Double) personCount.get("fillCountAll"), (Double) personCount.get("subidAll")));
+
+ //鐪嬩竴涓嬩箣鍓嶆湁娌℃湁璇ュ垎绫荤殑濉姤閲�
+ List<ScoreCount> serviceSubtaskDetailDTOS = assortNameFillCountMap.get(categoryNameKey);
+ if (CollectionUtils.isNotEmpty(serviceSubtaskDetailDTOS))
+ allFillCountList.addAll(serviceSubtaskDetailDTOS);
+ personCount.put("averageScore", averageScoreByStat(allFillCountList));
+ } else {
+ personCount = new HashMap<>();
+ personCount.put("fillCountAll", fillCountAll);
+ personCount.put("subidAll", subidAll);
+ personCount.put("receiveRate", Arith.div(fillCountAll, subidAll));
+ personCount.put("averageScore", averageScoreByStat(allFillCountList));
+ zzt.put(categoryNameKey, personCount);
+ }
+ }
+ }
+ }
+ return zzt;
+ }
+
+
+ @Override
+ public Map<String, Object> satisfactionGraphDimension(PatSatisfactionReqVO patSatisfactionReqVO) {
+ //鐢ㄦ潵璁板綍鏌辩姸鍥句俊鎭紙key=婊℃剰搴︾淮搴﹀悕绉帮紝value=璇ョ淮搴︿笅鐨勬�讳汉鏁板拰濉姤浜烘暟锛�
+ Map<String, Object> zzt = new HashMap<>();
+
+ // 璁板綍涓�涓嬫瘡涓淮搴︾殑濉姤鎯呭喌锛堝彧璁板垎鍊间笌鏉℃暟锛屼笉鍐嶆妸鏄庣粏琛屽叏閮ㄦ煡鍥� Java锛�
+ Map<String, List<ScoreCount>> assortNameFillCountMap = new HashMap<>();
+
+ if (patSatisfactionReqVO.getType() == null || patSatisfactionReqVO.getType() == 1) {
+ //1. 浠庡叆鍙備腑鑾峰彇婊℃剰搴︾淮缁村害
+ IvrLibaTemplateScript ivrLibaTemplateScript2 = new IvrLibaTemplateScript();
+ ivrLibaTemplateScript2.setDimensionList(patSatisfactionReqVO.getDimensionList());
+
+ //2 鍐嶈幏鍙栬闂婊℃剰搴﹀垎绫讳笅鐨処vrLibaTemplateScript鐨勯泦鍚�
+ List<IvrLibaTemplateScript> ivrLibaTemplateScripts = ivrLibaTemplateScriptMapper.selectILTSBydimension(ivrLibaTemplateScript2);
+ if (ivrLibaTemplateScripts != null && !ivrLibaTemplateScripts.isEmpty()) {
+ //3 鎸塪imension缁村害鍒嗙粍,骞惰幏鍙栨瘡涓泦鍚堣繘琛岄亶鍘嗭紝璁$畻姣忎釜鍒嗙被鐨勬�讳汉鏁板拰濉姤浜烘暟
+ List<IvrLibaTemplateScript> dimensionScripts = ivrLibaTemplateScripts.stream().filter(item -> item.getDimension() != null).collect(Collectors.toList());
+ Map<String, List<IvrLibaTemplateScript>> groupByDimension = dimensionScripts.stream().collect(Collectors.groupingBy(IvrLibaTemplateScript::getDimension));
+
+ if (groupByDimension != null && !groupByDimension.isEmpty()) {
+ //3.1 涓�娆℃�ф妸鏈璇锋眰鍏ㄩ儴妯℃澘鐨勫彂閫侀噺銆佸~鎶ラ噺鏌ュ洖鏉ワ紙鍘熸潵鏄瘡涓ā鏉块棶棰樺悇鏌ヤ袱娆★級
+ SatisfactionStatQuery statQuery = buildSatisfactionStatQuery(patSatisfactionReqVO, "1",
+ dimensionScripts.stream().map(IvrLibaTemplateScript::getTemplateid).collect(Collectors.toList()));
+ Map<Long, Long> sendCountMap = mapSatisfactionSendCount(statQuery);
+ SatisfactionFillStat fillStat = querySatisfactionFillStat(statQuery);
+
+ for (String dimension : groupByDimension.keySet()) {
+ //璁板綍鎬讳汉鏁�
+ Double subidAll = 0.0;
+ //璁板綍鎬荤殑濉姤浜烘暟
+ Double fillCountAll = 0.0;
+ //鑾峰彇璇ョ淮搴︾殑濉姤鎬绘暟閲�
+ List<ScoreCount> allFillCountList = new ArrayList<>();
+
+ List<IvrLibaTemplateScript> ivrLibaTemplateScriptList = groupByDimension.get(dimension);
+ for (IvrLibaTemplateScript ivrLibaTemplateScript : ivrLibaTemplateScriptList) {
+ //閫氳繃妯℃澘id鍙栭棶棰樺彂閫佹�婚噺锛堝師鏉ユ槸鎶婂叏閮� sub_id 鏌ュ洖 Java 鍐嶅彇 size锛�
+ subidAll += sendCountMap.getOrDefault(ivrLibaTemplateScript.getTemplateid(), 0L);
+ //鑾峰彇濉姤鏁伴噺锛堝師鏉ユ槸鎶婃槑缁嗚鍏ㄩ儴鏌ュ洖 Java 鍐嶅彇 size锛�
+ List<ScoreCount> fillCount = fillStat.get(ivrLibaTemplateScript.getTemplateid(), ivrLibaTemplateScript.getScriptContent());
+ if (CollectionUtils.isNotEmpty(fillCount)) allFillCountList.addAll(fillCount);
+ fillCountAll += countFillRows(fillCount);
+ }
+
+ // 杩欓噷鍏堣褰曚竴涓嬫瘡涓垎绫荤殑鎬讳汉鏁板拰濉姤浜烘暟
+ Map<String, Object> personCount = new HashMap<>();
+ personCount.put("fillCountAll", fillCountAll);
+ personCount.put("subidAll", subidAll);
+ personCount.put("receiveRate", Arith.div(fillCountAll, subidAll));
+ personCount.put("averageScore", averageScoreByStat(allFillCountList));
+ zzt.put(dimension, personCount);
+ assortNameFillCountMap.put(dimension, allFillCountList);
+ }
+ }
+ }
+ }
+
+ if (patSatisfactionReqVO.getType() == null || patSatisfactionReqVO.getType() == 2) {
+ //1. 浠庡叆鍙備腑鑾峰彇婊℃剰搴︾淮缁村害
+ SvyLibTemplateScriptVO svyLibTemplateScriptVO = new SvyLibTemplateScriptVO();
+ svyLibTemplateScriptVO.setDimensionList(patSatisfactionReqVO.getDimensionList());
+
+ //2 鍐嶈幏鍙栬闂婊℃剰搴﹀垎绫讳笅鐨処vrLibaTemplateScript鐨勯泦鍚�
+ List<SvyLibTemplateScript> svyLibTemplateScripts = svyLibTemplateScriptMapper.selectSLTScriptListBydimension(svyLibTemplateScriptVO);
+ if (svyLibTemplateScripts != null && !svyLibTemplateScripts.isEmpty()) {
+ //3 鎸塪imension缁村害鍒嗙粍,骞惰幏鍙栨瘡涓泦鍚堣繘琛岄亶鍘嗭紝璁$畻姣忎釜鍒嗙被鐨勬�讳汉鏁板拰濉姤浜烘暟
+ List<SvyLibTemplateScript> dimensionScripts = svyLibTemplateScripts.stream().filter(item -> item.getDimension() != null).collect(Collectors.toList());
+ Map<String, List<SvyLibTemplateScript>> groupByDimension = dimensionScripts.stream().collect(Collectors.groupingBy(SvyLibTemplateScript::getDimension));
+ if (groupByDimension != null && !groupByDimension.isEmpty()) {
+ //3.1 涓�娆℃�ф妸鏈璇锋眰鍏ㄩ儴妯℃澘鐨勫彂閫侀噺銆佸~鎶ラ噺鏌ュ洖鏉ワ紙鍘熸潵鏄瘡涓ā鏉块棶棰樺悇鏌ヤ袱娆★級
+ SatisfactionStatQuery statQuery = buildSatisfactionStatQuery(patSatisfactionReqVO, "2",
+ dimensionScripts.stream().map(SvyLibTemplateScript::getSvyid).collect(Collectors.toList()));
+ Map<Long, Long> sendCountMap = mapSatisfactionSendCount(statQuery);
+ SatisfactionFillStat fillStat = querySatisfactionFillStat(statQuery);
+
+ for (String dimension : groupByDimension.keySet()) {
+ //璁板綍鎬讳汉鏁�
+ Double subidAll = 0.0;
+ //璁板綍鎬荤殑濉姤浜烘暟
+ Double fillCountAll = 0.0;
+ //鑾峰彇璇ュ垎绫荤殑濉姤鎬绘暟閲�
+ List<ScoreCount> allFillCountList = new ArrayList<>();
+
+ List<SvyLibTemplateScript> svyLibTemplateScriptList = groupByDimension.get(dimension);
+ for (SvyLibTemplateScript svyLibTemplateScript : svyLibTemplateScriptList) {
+ //閫氳繃妯℃澘id鍙栭棶棰樺彂閫佹�婚噺锛堝師鏉ユ槸鎶婂叏閮� sub_id 鏌ュ洖 Java 鍐嶅彇 size锛�
+ subidAll += sendCountMap.getOrDefault(svyLibTemplateScript.getSvyid(), 0L);
+ //鑾峰彇濉姤鏁伴噺锛堝師鏉ユ槸鎶婃槑缁嗚鍏ㄩ儴鏌ュ洖 Java 鍐嶅彇 size锛�
+ List<ScoreCount> fillCount = fillStat.get(svyLibTemplateScript.getSvyid(), svyLibTemplateScript.getScriptContent());
+ if (CollectionUtils.isNotEmpty(fillCount)) allFillCountList.addAll(fillCount);
+ fillCountAll += countFillRows(fillCount);
+ }
+
+
+ // 杩欓噷鍏堣褰曚竴涓嬫瘡涓垎绫荤殑鎬讳汉鏁板拰濉姤浜烘暟
+ Map<String, Object> personCount = (Map<String, Object>) zzt.get(dimension);
+ if (!Objects.isNull(personCount)) {
+ Double fillCountAll2 = (Double) personCount.get("fillCountAll");
+ Double subidAll2 = (Double) personCount.get("subidAll");
+ personCount.put("fillCountAll", fillCountAll2 + fillCountAll);
+ personCount.put("subidAll", subidAll2 + subidAll);
+ personCount.put("receiveRate", Arith.div((Double) personCount.get("fillCountAll"), (Double) personCount.get("subidAll")));
+
+ //鐪嬩竴涓嬩箣鍓嶆湁娌℃湁璇ュ垎绫荤殑濉姤閲�
+ List<ScoreCount> serviceSubtaskDetailDTOS = assortNameFillCountMap.get(dimension);
+ if (CollectionUtils.isNotEmpty(serviceSubtaskDetailDTOS))
+ allFillCountList.addAll(serviceSubtaskDetailDTOS);
+ personCount.put("averageScore", averageScoreByStat(allFillCountList));
+ } else {
+ personCount = new HashMap<>();
+ personCount.put("fillCountAll", fillCountAll);
+ personCount.put("subidAll", subidAll);
+ personCount.put("receiveRate", Arith.div(fillCountAll, subidAll));
+ personCount.put("averageScore", averageScoreByStat(allFillCountList));
+ zzt.put(dimension, personCount);
+ }
+ }
+ }
+ }
+ }
+ return zzt;
+ }
+
+ /**
+ * 鑾峰彇鏈�楂樺垎
+ *
+ * @param options
+ * @return
+ */
+ private Double maxScore(List<IvrLibaTemplateTargetoption> options) {
+ if (CollectionUtils.isEmpty(options)) return 0.0;
+ Double maxScore = options.stream()
+ .map(IvrLibaTemplateTargetoption::getScore)
+ .filter(scoreStr -> scoreStr != null && !scoreStr.isEmpty())
+ .mapToDouble(Double::parseDouble)
+ .max()
+ .orElse(0.0);
+ return maxScore;
+ }
+
+ /**
+ * 鑾峰彇鏈�浣庡垎
+ *
+ * @param options
+ * @return
+ */
+ private Double minScore(List<IvrLibaTemplateTargetoption> options) {
+ if (CollectionUtils.isEmpty(options)) return 0.0;
+ Double minScore = options.stream()
+ .map(IvrLibaTemplateTargetoption::getScore)
+ .filter(scoreStr -> scoreStr != null && !scoreStr.isEmpty())
+ .mapToDouble(Double::parseDouble)
+ .min()
+ .orElse(0.0);
+ return minScore;
+ }
+
+ /**
+ * 鑾峰彇骞冲潎鍒�
+ *
+ * @param fillCount
+ * @return
+ */
+ private Double averageScore(List<ServiceSubtaskDetailDTO> fillCount) {
+ if (CollectionUtils.isEmpty(fillCount)) return 0.0;
+ double sum = fillCount.stream().filter(dto -> dto.getScore() != null && !dto.getScore().isEmpty()).mapToDouble(dto -> Double.parseDouble(dto.getScore())).sum();
+ return new BigDecimal(sum / fillCount.size()).setScale(1, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ // ==================== satisfactionGraph 鑱氬悎缁熻锛堟浛浠i�愪釜妯℃澘鏌ュ簱锛� ====================
+
+ /**
+ * 鏋勫缓鑱氬悎缁熻鍏ュ弬锛堝彇鍊兼潵婧愪笌鍘� DtoConversionUtils.sourceToTarget(patSatisfactionReqVO, ServiceSubtaskSatisfactionEntity.class) 涓�鑷达級
+ *
+ * @param reqVO 鍘熷璇锋眰
+ * @param type service_subtask.type锛�1 璇煶銆�2 闂嵎锛夛紝鐢ㄥ瓧绗︿覆姣旇緝閬垮厤闅愬紡杞崲
+ * @param templateIds 鏈璇锋眰娑夊強鐨勬ā鏉縤d锛坕vr 鐢� templateid锛岄棶鍗风敤 svyid锛�
+ */
+ private SatisfactionStatQuery buildSatisfactionStatQuery(PatSatisfactionReqVO reqVO, String type, List<Long> templateIds) {
+ SatisfactionStatQuery statQuery = new SatisfactionStatQuery();
+ statQuery.setOrgid(reqVO.getOrgid());
+ statQuery.setCampusid(reqVO.getCampusid());
+ statQuery.setType(type);
+ statQuery.setStartTime(reqVO.getStartTime());
+ statQuery.setEndTime(reqVO.getEndTime());
+ statQuery.setDeptcodes(reqVO.getDeptcodes());
+ statQuery.setHospitaldistrictcodes(reqVO.getHospitaldistrictcodes());
+ statQuery.setLibTemplateIds(CollectionUtils.isEmpty(templateIds) ? templateIds
+ : templateIds.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()));
+ return statQuery;
+ }
+
+ /**
+ * 涓�娆℃煡鍑哄叏閮ㄦā鏉跨殑鍙戦�侀噺
+ *
+ * @return key=妯℃澘id锛寁alue=鍙戦�侀噺锛堢瓑浠蜂簬鍘� querySendCount 缁撴灉鐨� size锛�
+ */
+ private Map<Long, Long> mapSatisfactionSendCount(SatisfactionStatQuery statQuery) {
+ Map<Long, Long> sendCountMap = new HashMap<>();
+ if (statQuery == null || CollectionUtils.isEmpty(statQuery.getLibTemplateIds())) return sendCountMap;
+ List<Map<String, Object>> rows = serviceSubtaskMapper.selectSatisfactionSendCount(statQuery);
+ if (CollectionUtils.isEmpty(rows)) return sendCountMap;
+ for (Map<String, Object> row : rows) {
+ Long templateId = toLong(row.get("libtemplateid"));
+ if (templateId == null) continue;
+ sendCountMap.put(templateId, toLong(row.get("cnt"), 0L));
+ }
+ return sendCountMap;
+ }
+
+ /**
+ * 涓�娆℃煡鍑哄叏閮ㄦā鏉跨殑濉姤閲忥紙鎸� 妯℃澘+闂+鍒嗗�� 鍒嗙粍锛�
+ */
+ private SatisfactionFillStat querySatisfactionFillStat(SatisfactionStatQuery statQuery) {
+ SatisfactionFillStat fillStat = new SatisfactionFillStat();
+ if (statQuery == null || CollectionUtils.isEmpty(statQuery.getLibTemplateIds())) return fillStat;
+ List<Map<String, Object>> rows = serviceSubtaskDetailMapper.selectSatisfactionFillStat(statQuery);
+ if (CollectionUtils.isEmpty(rows)) return fillStat;
+ for (Map<String, Object> row : rows) {
+ Long templateId = toLong(row.get("libtemplateid"));
+ if (templateId == null) continue;
+ long cnt = toLong(row.get("cnt"), 0L);
+ if (cnt <= 0L) continue;
+ Object scoreValue = row.get("score");
+ Object questiontextValue = row.get("questiontext");
+ ScoreCount scoreCount = new ScoreCount(scoreValue == null ? null : String.valueOf(scoreValue), cnt);
+ fillStat.add(templateId, questiontextValue == null ? null : String.valueOf(questiontextValue), scoreCount);
+ }
+ return fillStat;
+ }
+
+ /**
+ * 鍙栧~鎶ユ槑缁嗚鏁帮紙鍘� fillCount.size()锛�
+ */
+ private long countFillRows(List<ScoreCount> fillCount) {
+ if (CollectionUtils.isEmpty(fillCount)) return 0L;
+ long rows = 0L;
+ for (ScoreCount scoreCount : fillCount) {
+ rows += scoreCount.getCount();
+ }
+ return rows;
+ }
+
+ /**
+ * 鑾峰彇骞冲潎鍒嗭紙鑱氬悎鐗堬細鍒嗗�间笌鏉℃暟锛�
+ * <p>
+ * 鍙e緞涓� {@link #averageScore(List)} 瀹屽叏涓�鑷达細鍒嗗瓙涓哄彲瑙f瀽鍒嗗�间箣鍜岋紝鍒嗘瘝涓烘槑缁嗚鏁帮紙鍖呭惈鍒嗗�间负绌虹殑琛岋級銆�
+ * 娉ㄦ剰涓嶈兘鏀规垚 sql 鐨� avg() 鎴栥�屾湁鍒嗗�肩殑琛屾暟銆嶅仛鍒嗘瘝锛屽惁鍒欒繑鍥炵殑 averageScore 浼氬彉銆�
+ */
+ private Double averageScoreByStat(List<ScoreCount> fillCount) {
+ if (CollectionUtils.isEmpty(fillCount)) return 0.0;
+ double sum = 0.0;
+ long rows = 0L;
+ for (ScoreCount scoreCount : fillCount) {
+ if (scoreCount.getCount() <= 0L) continue;
+ rows += scoreCount.getCount();
+ if (scoreCount.getScore() != null && !scoreCount.getScore().isEmpty()) {
+ sum += Double.parseDouble(scoreCount.getScore()) * scoreCount.getCount();
+ }
+ }
+ if (rows == 0L) return 0.0;
+ return new BigDecimal(sum / rows).setScale(1, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ /**
+ * 鍒嗗�煎垎缁勯敭锛氭ā鏉縤d + 鍒嗛殧绗� + 瑙勮寖鍖栧悗鐨勯棶棰樺唴瀹�
+ * <p>
+ * MySQL 閲� questiontext = #{questiontext} 鏄�屽拷鐣ュぇ灏忓啓銆佸拷鐣ュ熬閮ㄧ┖鏍笺�嶇殑姣旇緝锛�
+ * 杩欓噷鐢� trim + 灏忓啓鍋氱瓑浠峰尮閰嶃��
+ */
+ private static String statKey(Long templateId, String questiontext) {
+ return templateId + "\u0001" + (questiontext == null ? "" : questiontext.trim().toLowerCase(Locale.ROOT));
+ }
+
+ private static Long toLong(Object value) {
+ if (value == null) return null;
+ if (value instanceof Number) return ((Number) value).longValue();
+ String text = String.valueOf(value).trim();
+ return text.isEmpty() ? null : Long.valueOf(text);
+ }
+
+ private static long toLong(Object value, long defaultValue) {
+ Long result = toLong(value);
+ return result == null ? defaultValue : result;
+ }
+
+ /**
+ * 婊℃剰搴﹀垎鍊艰仛鍚堢粨鏋滐細鍒嗗�� + 璇ュ垎鍊煎搴旂殑鏄庣粏琛屾暟
+ */
+ private static class ScoreCount {
+ private final String score;
+ private final long count;
+
+ ScoreCount(String score, long count) {
+ this.score = score;
+ this.count = count;
+ }
+
+ String getScore() {
+ return score;
+ }
+
+ long getCount() {
+ return count;
+ }
+ }
+
+ /**
+ * 婊℃剰搴﹀~鎶ラ噺鑱氬悎缁撴灉
+ * <p>
+ * byTemplateQuestion锛氭寜 妯℃澘+闂 鍒嗙粍锛�
+ * byTemplate锛氭寜妯℃澘鍒嗙粍锛堣妯℃澘鍏ㄩ儴闂锛夛紝鐢ㄤ簬鍏煎鍘� queryFillCount 鍦�
+ * script_content 涓� null 鏃朵笉鎷� questiontext 鏉′欢鐨勮涓恒��
+ */
+ private static class SatisfactionFillStat {
+ private final Map<String, List<ScoreCount>> byTemplateQuestion = new HashMap<>();
+ private final Map<Long, List<ScoreCount>> byTemplate = new HashMap<>();
+
+ void add(Long templateId, String questiontext, ScoreCount scoreCount) {
+ byTemplate.computeIfAbsent(templateId, key -> new ArrayList<>()).add(scoreCount);
+ if (questiontext != null) {
+ byTemplateQuestion.computeIfAbsent(statKey(templateId, questiontext), key -> new ArrayList<>()).add(scoreCount);
+ }
+ }
+
+ List<ScoreCount> get(Long templateId, String scriptContent) {
+ if (templateId == null) return null;
+ if (scriptContent == null) return byTemplate.get(templateId);
+ return byTemplateQuestion.get(statKey(templateId, scriptContent));
+ }
+ }
+
+ // ==================== statistics / statisticsByDimension 鎵归噺缁熻锛堟浛浠i�愪釜闂鏌ュ簱锛� ====================
+
+ /**
+ * 婊℃剰搴︽槑缁嗙粺璁★紙statistics銆乻tatisticsByDimension 鍏辩敤锛�
+ * <p>
+ * 鎶婂師鏉ャ�屾瘡涓棶棰� 3 鏉� SQL銆嶆敼鎴愩�屾暣涓姹� 3 鏉℃煡璇� + 鍐呭瓨缁勮銆嶏細
+ * 鈶� 鍙戦�侀噺鎸� libtemplateid 鍒嗙粍锛涒憽 濉姤閲忔寜 妯℃澘+闂+matchedtext+score 鍒嗙粍锛涒憿 閫夐」鍒嗗�兼寜 scriptid 鍒嗙粍銆�
+ *
+ * @param reqVO 鍘熷璇锋眰
+ * @param type service_subtask.type锛�1 璇煶銆�2 闂嵎锛�
+ * @param voice true=璇煶闂锛堥�夐」鍒嗗�煎彇 ivr_liba_template_targetoption锛�
+ * @param scriptRefs 鏈瑕佺粺璁$殑闂锛堥『搴忓嵆杩斿洖椤哄簭锛�
+ * @param out 鏄庣粏缁撴灉
+ * @param totals [0]=totalPerson, [1]=allPerson
+ */
+ private void buildSatisfactionDetailEntities(PatSatisfactionReqVO reqVO, String type, boolean voice,
+ List<SatScriptRef> scriptRefs,
+ List<PatSatisfactionDetailEntity> out, int[] totals) {
+ if (CollectionUtils.isEmpty(scriptRefs)) return;
+
+ List<Long> templateIds = scriptRefs.stream().map(SatScriptRef::getTemplateId)
+ .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+ SatisfactionStatQuery statQuery = buildSatisfactionStatQuery(reqVO, type, templateIds);
+ Map<Long, Long> sendCountMap = mapSatisfactionSendCount(statQuery);
+ SatisfactionFillStatByMatchedtext fillStat = querySatisfactionFillStatByMatchedtext(statQuery);
+ Map<Long, List<String>> optionScores = loadTargetOptionScores(voice, scriptRefs);
+
+ for (SatScriptRef scriptRef : scriptRefs) {
+ Long templateId = scriptRef.getTemplateId();
+ //鍙戦�佹�婚噺锛堝師鏉ユ槸鎶婂叏閮� sub_id 鏌ュ洖 Java 鍐嶅彇 size锛�
+ long sendCount = templateId == null ? 0L : sendCountMap.getOrDefault(templateId, 0L);
+ //濉姤鏁伴噺锛堝師鏉ユ槸鎶婃槑缁嗚鍏ㄩ儴鏌ュ洖 Java 鍐嶇粺璁★級
+ List<MatchedtextCount> fillRows = fillStat.get(templateId, scriptRef.getScriptContent());
+ long fillCount = countFillRowsByMatchedtext(fillRows);
+
+ PatSatisfactionDetailEntity detail = new PatSatisfactionDetailEntity();
+ detail.setScriptContent(scriptRef.getScriptContent());
+ detail.setAnswerPerson((int) fillCount);
+ detail.setNoAnswerPerson(fillCount > 0L && sendCount > 0L ? (int) (sendCount - fillCount) : sendCount > 0L ? (int) sendCount : 0);
+ detail.setAverageScore(String.valueOf(averageScoreByMatchedtext(fillRows)));
+ List<String> scores = optionScores.get(scriptRef.getOptionScriptId());
+ detail.setMaxScore(String.valueOf(maxScoreOf(scores)));
+ detail.setMinScore(String.valueOf(minScoreOf(scores)));
+ detail.setAnswerRate(sendCount == 0L ? 0 : fillCount == 0L ? 0 : fillCount * 1.0 / sendCount);
+ detail.setMatchedtextStats(buildMatchedtextStats(fillRows, fillCount));
+ out.add(detail);
+
+ totals[0] += (int) fillCount;
+ totals[1] += (int) sendCount;
+ }
+ }
+
+ /**
+ * 涓�娆℃煡鍑哄叏閮ㄩ棶棰樼殑濉姤閲忥紙鎸� 妯℃澘+闂+matchedtext+score 鍒嗙粍锛屽惈 targetvalue锛�
+ */
+ private SatisfactionFillStatByMatchedtext querySatisfactionFillStatByMatchedtext(SatisfactionStatQuery statQuery) {
+ SatisfactionFillStatByMatchedtext fillStat = new SatisfactionFillStatByMatchedtext();
+ if (statQuery == null || CollectionUtils.isEmpty(statQuery.getLibTemplateIds())) return fillStat;
+ List<Map<String, Object>> rows = serviceSubtaskDetailMapper.selectSatisfactionFillStatByMatchedtext(statQuery);
+ if (CollectionUtils.isEmpty(rows)) return fillStat;
+ for (Map<String, Object> row : rows) {
+ Long templateId = toLong(row.get("libtemplateid"));
+ if (templateId == null) continue;
+ long cnt = toLong(row.get("cnt"), 0L);
+ if (cnt <= 0L) continue;
+ Object questiontext = row.get("questiontext");
+ Object matchedtext = row.get("matchedtext");
+ Object score = row.get("score");
+ Object targetvalue = row.get("targetvalue");
+ fillStat.add(templateId, questiontext == null ? null : String.valueOf(questiontext),
+ new MatchedtextCount(matchedtext == null ? null : String.valueOf(matchedtext),
+ score == null ? null : String.valueOf(score),
+ targetvalue == null ? null : String.valueOf(targetvalue), cnt));
+ }
+ return fillStat;
+ }
+
+ /**
+ * 涓�娆℃煡鍑哄叏閮ㄩ棶棰樼殑閫夐」鍒嗗�硷紙鍙彇 scriptid銆乻core 涓ゅ垪锛�
+ * <p>
+ * 鍘熷疄鐜版槸姣忎釜闂鏌ヤ竴娆℃暣琛岋紝鑰岃皟鐢ㄦ柟鍙敤鍒� score 绠楁渶楂�/鏈�浣庡垎锛�
+ * 闂 id 涓� null 鏃跺師瀹炵幇涓嶆嫾 scriptid 鏉′欢锛堢瓑浜庡彇璇ヨ〃鍏ㄩ儴鍒嗗�硷級锛岃繖閲岀敤 null 浣滀负 key 瀛樿繖涓�浠姐��
+ */
+ private Map<Long, List<String>> loadTargetOptionScores(boolean voice, List<SatScriptRef> scriptRefs) {
+ Map<Long, List<String>> optionScores = new HashMap<>();
+ List<Long> scriptIds = scriptRefs.stream().map(SatScriptRef::getOptionScriptId)
+ .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+ if (CollectionUtils.isNotEmpty(scriptIds)) {
+ addTargetOptionScores(optionScores, voice
+ ? ivrLibaTemplateTargetoptionMapper.selectIvrLibaTargetoptionScores(scriptIds)
+ : svyLibTemplateTargetoptionMapper.selectSvyLibTargetoptionScores(scriptIds));
+ }
+ if (scriptRefs.stream().anyMatch(ref -> ref.getOptionScriptId() == null)) {
+ optionScores.put(null, collectTargetOptionScores(voice
+ ? ivrLibaTemplateTargetoptionMapper.selectIvrLibaTargetoptionScores(null)
+ : svyLibTemplateTargetoptionMapper.selectSvyLibTargetoptionScores(null)));
+ }
+ return optionScores;
+ }
+
+ private void addTargetOptionScores(Map<Long, List<String>> optionScores, List<Map<String, Object>> rows) {
+ if (CollectionUtils.isEmpty(rows)) return;
+ for (Map<String, Object> row : rows) {
+ Long scriptId = toLong(row.get("scriptid"));
+ if (scriptId == null) continue;
+ Object score = row.get("score");
+ optionScores.computeIfAbsent(scriptId, key -> new ArrayList<>())
+ .add(score == null ? null : String.valueOf(score));
+ }
+ }
+
+ private List<String> collectTargetOptionScores(List<Map<String, Object>> rows) {
+ List<String> scores = new ArrayList<>();
+ if (CollectionUtils.isEmpty(rows)) return scores;
+ for (Map<String, Object> row : rows) {
+ Object score = row.get("score");
+ scores.add(score == null ? null : String.valueOf(score));
+ }
+ return scores;
+ }
+
+ /**
+ * 鍚勯�夐」锛坢atchedtext锛夋暟閲忓強鍗犳瘮
+ * <p>
+ * 鍙e緞涓庡師瀹炵幇涓�鑷达細鍒嗘瘝鏄叏閮ㄦ槑缁嗚鏁帮紙鍚� matchedtext 涓� null 鐨勮锛夛紱
+ * targetvalue 鐢ㄤ簬琛ュ叏鏈嚭鐜扮殑閫夐」锛坈ount=0銆乺atio=0锛夈��
+ */
+ private Map<String, Map<String, Object>> buildMatchedtextStats(List<MatchedtextCount> fillRows, long totalFill) {
+ Map<String, Map<String, Object>> matchedtextStats = new HashMap<>();
+ if (CollectionUtils.isEmpty(fillRows) || totalFill <= 0L) return matchedtextStats;
+
+ Map<String, Long> matchedtextCounts = new LinkedHashMap<>();
+ String targetvalue = null;
+ for (MatchedtextCount row : fillRows) {
+ if (row.getMatchedtext() != null) {
+ matchedtextCounts.merge(row.getMatchedtext(), row.getCount(), Long::sum);
+ }
+ if (targetvalue == null && row.getTargetvalue() != null) {
+ targetvalue = row.getTargetvalue();
+ }
+ }
+ for (Map.Entry<String, Long> entry : matchedtextCounts.entrySet()) {
+ Map<String, Object> stat = new HashMap<>();
+ stat.put("count", entry.getValue());
+ stat.put("ratio", new BigDecimal((double) entry.getValue() / totalFill * 100).setScale(1, RoundingMode.HALF_UP).doubleValue());
+ matchedtextStats.put(entry.getKey(), stat);
+ }
+ // 浠庢槑缁嗛噷鍙杢argetvalue锛�&鍒嗛殧鐨勫綋鍓嶉棶棰樼殑鎵�鏈夐�夐」锛夛紝琛ュ叏鏈嚭鐜扮殑閫夐」锛宑ount鍜宺atio鍧囦负0
+ if (targetvalue != null) {
+ for (String option : targetvalue.split("&")) {
+ String optionTrim = option.trim();
+ if (!matchedtextStats.containsKey(optionTrim)) {
+ Map<String, Object> emptyStat = new HashMap<>();
+ emptyStat.put("count", 0L);
+ emptyStat.put("ratio", 0.0);
+ matchedtextStats.put(optionTrim, emptyStat);
+ }
+ }
+ }
+ return matchedtextStats;
+ }
+
+ /**
+ * 鍙栧~鎶ユ槑缁嗚鏁帮紙鍘� fillCount.size()锛�
+ */
+ private long countFillRowsByMatchedtext(List<MatchedtextCount> fillRows) {
+ if (CollectionUtils.isEmpty(fillRows)) return 0L;
+ long rows = 0L;
+ for (MatchedtextCount row : fillRows) {
+ rows += row.getCount();
+ }
+ return rows;
+ }
+
+ /**
+ * 鑾峰彇骞冲潎鍒嗭紙鑱氬悎鐗堬細鍒嗗�间笌鏉℃暟锛�
+ * <p>
+ * 鍙e緞涓� {@link #averageScore(List)} 涓�鑷达細鍒嗗瓙涓哄彲瑙f瀽鍒嗗�间箣鍜岋紝鍒嗘瘝涓烘槑缁嗚鏁帮紙鍚垎鍊间负绌虹殑琛岋級銆�
+ */
+ private Double averageScoreByMatchedtext(List<MatchedtextCount> fillRows) {
+ if (CollectionUtils.isEmpty(fillRows)) return 0.0;
+ double sum = 0.0;
+ long rows = 0L;
+ for (MatchedtextCount row : fillRows) {
+ if (row.getCount() <= 0L) continue;
+ rows += row.getCount();
+ if (row.getScore() != null && !row.getScore().isEmpty()) {
+ sum += Double.parseDouble(row.getScore()) * row.getCount();
+ }
+ }
+ if (rows == 0L) return 0.0;
+ return new BigDecimal(sum / rows).setScale(1, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ /**
+ * 鑾峰彇鏈�楂樺垎锛堣仛鍚堢増锛屽彛寰勫悓 {@link #maxScore(List)}锛氱┖鍒楄〃杩斿洖 0.0锛�
+ */
+ private Double maxScoreOf(List<String> scores) {
+ if (CollectionUtils.isEmpty(scores)) return 0.0;
+ return scores.stream().filter(scoreStr -> scoreStr != null && !scoreStr.isEmpty())
+ .mapToDouble(Double::parseDouble).max().orElse(0.0);
+ }
+
+ /**
+ * 鑾峰彇鏈�浣庡垎锛堣仛鍚堢増锛屽彛寰勫悓 {@link #minScore(List)}锛氱┖鍒楄〃杩斿洖 0.0锛�
+ */
+ private Double minScoreOf(List<String> scores) {
+ if (CollectionUtils.isEmpty(scores)) return 0.0;
+ return scores.stream().filter(scoreStr -> scoreStr != null && !scoreStr.isEmpty())
+ .mapToDouble(Double::parseDouble).min().orElse(0.0);
+ }
+
+ /**
+ * 婊℃剰搴︾粺璁$敤鐨勯棶棰樺紩鐢細妯℃澘id銆侀�夐」琛ㄥ叧鑱旂殑闂id锛堝彲鑳戒负 null锛夈�侀棶棰樺唴瀹�
+ */
+ private static class SatScriptRef {
+ private final Long templateId;
+ private final Long optionScriptId;
+ private final String scriptContent;
+
+ SatScriptRef(Long templateId, Long optionScriptId, String scriptContent) {
+ this.templateId = templateId;
+ this.optionScriptId = optionScriptId;
+ this.scriptContent = scriptContent;
+ }
+
+ Long getTemplateId() {
+ return templateId;
+ }
+
+ Long getOptionScriptId() {
+ return optionScriptId;
+ }
+
+ String getScriptContent() {
+ return scriptContent;
+ }
+ }
+
+ /**
+ * 婊℃剰搴﹀~鎶ヨ仛鍚堢粨鏋滐細matchedtext + score + targetvalue + 鏉℃暟
+ */
+ private static class MatchedtextCount {
+ private final String matchedtext;
+ private final String score;
+ private final String targetvalue;
+ private final long count;
+
+ MatchedtextCount(String matchedtext, String score, String targetvalue, long count) {
+ this.matchedtext = matchedtext;
+ this.score = score;
+ this.targetvalue = targetvalue;
+ this.count = count;
+ }
+
+ String getMatchedtext() {
+ return matchedtext;
+ }
+
+ String getScore() {
+ return score;
+ }
+
+ String getTargetvalue() {
+ return targetvalue;
+ }
+
+ long getCount() {
+ return count;
+ }
+ }
+
+ /**
+ * 婊℃剰搴﹀~鎶ヨ仛鍚堢粨鏋滐紙鎸� matchedtext 鐗堬級
+ * <p>
+ * byTemplateQuestion锛氭寜 妯℃澘+闂 鍒嗙粍锛�
+ * byTemplate锛氭寜妯℃澘鍒嗙粍锛堣妯℃澘鍏ㄩ儴闂锛夛紝鐢ㄤ簬鍏煎鍘� queryFillCount 鍦�
+ * script_content 涓� null 鏃朵笉鎷� questiontext 鏉′欢鐨勮涓恒��
+ */
+ private static class SatisfactionFillStatByMatchedtext {
+ private final Map<String, List<MatchedtextCount>> byTemplateQuestion = new HashMap<>();
+ private final Map<Long, List<MatchedtextCount>> byTemplate = new HashMap<>();
+
+ void add(Long templateId, String questiontext, MatchedtextCount row) {
+ byTemplate.computeIfAbsent(templateId, key -> new ArrayList<>()).add(row);
+ if (questiontext != null) {
+ byTemplateQuestion.computeIfAbsent(statKey(templateId, questiontext), key -> new ArrayList<>()).add(row);
+ }
+ }
+
+ List<MatchedtextCount> get(Long templateId, String scriptContent) {
+ if (templateId == null) return null;
+ if (scriptContent == null) return byTemplate.get(templateId);
+ return byTemplateQuestion.get(statKey(templateId, scriptContent));
+ }
+ }
}
--
Gitblit v1.9.3