package com.ruoyi.satisfaction.service.impl;
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.ruoyi.satisfaction.domain.vo.PatSatisfactionReqVO;
import com.ruoyi.satisfaction.domain.vo.PatSatisfactionResVO;
import com.ruoyi.satisfaction.domain.entity.PatSatisfactionDetailEntity;
import com.ruoyi.satisfaction.domain.entity.SatisfactionStatQuery;
import com.ruoyi.satisfaction.domain.entity.ServiceSubtaskSatisfactionEntity;
import com.ruoyi.satisfaction.mapper.PatSatisfactionMapper;
import com.ruoyi.satisfaction.mapper.SatisfactionMapper;
import com.ruoyi.satisfaction.mapper.SatisfactionScriptMapper;
import com.ruoyi.satisfaction.domain.row.SatisfactionCategoryRow;
import com.ruoyi.satisfaction.domain.row.SatisfactionIvrScriptRow;
import com.ruoyi.satisfaction.domain.row.SatisfactionOptionScoreRow;
import com.ruoyi.satisfaction.domain.row.SatisfactionScriptQuery;
import com.ruoyi.satisfaction.domain.row.SatisfactionSvyScriptRow;
import com.ruoyi.satisfaction.domain.ServiceSubtaskDetailRatioExport;
import com.ruoyi.satisfaction.service.strategy.SatisfactionScoreStrategyResolver;
import com.ruoyi.satisfaction.service.strategy.SatisfactionSites;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.satisfaction.domain.PatSatisfaction;
import com.ruoyi.satisfaction.service.IPatSatisfactionService;
import static com.ruoyi.common.utils.SecurityUtils.getLoginUser;
/**
* 患者满意度Service业务层处理
*
* @author lihu
* @date 2025-06-30
*/
@Service
public class PatSatisfactionServiceImpl implements IPatSatisfactionService {
@Autowired
private PatSatisfactionMapper patSatisfactionMapper;
@Autowired
private SatisfactionMapper satisfactionMapper;
@Autowired
private SatisfactionScriptMapper satisfactionScriptMapper;
/**
* 站点口径策略解析器。
*
* 本类的 {@code averageScoreByStat} 就是「通用口径(南华)」的综合满意度得分口径,
* 现改为委托 {@link com.ruoyi.satisfaction.service.strategy.CommonSatisfactionScoreStrategy},
* 与省立同德口径({@code SltdSatisfactionScoreStrategy})通过同一策略接口并列,
* 避免同一个概念在两处各写一份实现。
*/
@Autowired
private SatisfactionScoreStrategyResolver satisfactionScoreStrategyResolver;
/**
* 查询患者满意度
*
* @param id 患者满意度主键
* @return 患者满意度
*/
@Override
public PatSatisfaction selectPatSatisfactionById(Long id) {
PatSatisfaction ps = patSatisfactionMapper.selectPatSatisfactionById(id);
double total = ps.getDoctorSatisfaction() + ps.getAuthenticity() + ps.getWeekFinish() + ps.getStandard() + ps.getTimeliness() + ps.getLibrary() + ps.getEnvironment() + ps.getNurseSatisfaction();
ps.setTotal(total);
return ps;
}
/**
* 查询患者满意度列表
*
* @param patSatisfaction 患者满意度
* @return 患者满意度
*/
@Override
public List selectPatSatisfactionList(PatSatisfaction patSatisfaction) {
List patSatisfactions = patSatisfactionMapper.selectPatSatisfactionList(patSatisfaction);
if (CollectionUtils.isNotEmpty(patSatisfactions)) {
patSatisfactions.forEach(ps -> {
double total = ps.getDoctorSatisfaction() + ps.getAuthenticity() + ps.getWeekFinish() + ps.getStandard() + ps.getTimeliness() + ps.getLibrary() + ps.getEnvironment() + ps.getNurseSatisfaction();
ps.setTotal(total);
});
}
return patSatisfactions;
}
/**
* 新增患者满意度
*
* @param patSatisfaction 患者满意度
* @return 结果
*/
@Override
public int insertPatSatisfaction(PatSatisfaction patSatisfaction) {
patSatisfaction.setCreateTime(DateUtils.getNowDate());
patSatisfaction.setUpdateTime(DateUtils.getNowDate());
return patSatisfactionMapper.insertPatSatisfaction(patSatisfaction);
}
/**
* 新增患者满意度
*
* @param patSatisfactions 患者满意度
* @return 结果
*/
@Override
public int batchInsert(List patSatisfactions) {
if(CollectionUtils.isEmpty(patSatisfactions)){
return 0;
}
List ids = patSatisfactions.stream().map(PatSatisfaction::getId).
distinct().collect(Collectors.toList());
List patSatisfactionsOld = new ArrayList<>();
PatSatisfaction patSatisfactionVo = new PatSatisfaction();
patSatisfactionVo.setIds(ids);
patSatisfactionsOld = patSatisfactionMapper.selectPatSatisfactionList(patSatisfactionVo);
Map> maps = ArrayListUtils.splitListsById(patSatisfactions,
patSatisfactionsOld, PatSatisfaction::getId);
//只在patSatisfactions的数据,执行新增操作
List addItems = maps.get("onlyIn1");
//只在patSatisfactionsOld的数据,执行删除操作
// List delItems = maps.get("onlyIn2");
//重叠的数据,执行更新操作
List 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;
}
/**
* 修改患者满意度
*
* @param patSatisfaction 患者满意度
* @return 结果
*/
@Override
public int updatePatSatisfaction(PatSatisfaction patSatisfaction) {
patSatisfaction.setUpdateTime(DateUtils.getNowDate());
return patSatisfactionMapper.updatePatSatisfaction(patSatisfaction);
}
/**
* 批量删除患者满意度
*
* @param ids 需要删除的患者满意度主键
* @return 结果
*/
@Override
public int deletePatSatisfactionByIds(Long[] ids) {
return patSatisfactionMapper.deletePatSatisfactionByIds(ids);
}
/**
* 删除患者满意度信息
*
* @param id 患者满意度主键
* @return 结果
*/
@Override
public int deletePatSatisfactionById(Long id) {
return patSatisfactionMapper.deletePatSatisfactionById(id);
}
/**
* 患者满意度统计
*
* @param patSatisfactionReqVO 患者满意度统计条件
* @return 患者满意度统计结果
*/
@Override
public PatSatisfactionResVO statistics(PatSatisfactionReqVO patSatisfactionReqVO) {
//定义返参
PatSatisfactionResVO result = new PatSatisfactionResVO();
//患者满意度统详情
List patSatisfactionDetailEntities = new ArrayList<>();
// [0]=答题总人数(已经回答问题的) [1]=总人数(包含未回答的)
int[] personTotals = new int[2];
// 只查本次条件下实际存在哪些 type(原来是把接近全表的上百个字段查回来,仅用于判断下面两个分支是否为空)
List types = satisfactionMapper.selectSatisfactionSubtaskTypes(patSatisfactionReqVO);
boolean hasVoice = types != null && types.contains("1");
boolean hasQuestionnaire = types != null && types.contains("2");
if (hasVoice) {
List ivrLibaScriptAssorts = satisfactionScriptMapper.selectIvrCategoryList(ivrCategoryQuery(patSatisfactionReqVO));
List mydIdList = ivrLibaScriptAssorts.stream().filter(item -> item.getType() != null && item.getType().contains("myd")).map(SatisfactionCategoryRow::getId).collect(Collectors.toList());
List ivrLibaTemplateScripts = satisfactionScriptMapper.queryIvrScriptByAssort(assortQuery(mydIdList));
//3 一次统计全部问题的发送量/填报量/选项分值(原来是每个问题各查 3 次)
List scriptRefs = new ArrayList<>();
for (SatisfactionIvrScriptRow ivrLibaTemplateScript : ivrLibaTemplateScripts) {
scriptRefs.add(new SatScriptRef(ivrLibaTemplateScript.getTemplateid(), ivrLibaTemplateScript.getScriptid(), ivrLibaTemplateScript.getScriptContent(), ivrLibaTemplateScript.getDimension()));
}
buildSatisfactionDetailEntities(patSatisfactionReqVO, "1", true, scriptRefs, patSatisfactionDetailEntities, personTotals);
}
if (hasQuestionnaire) {
List svyLibScriptCategories = satisfactionScriptMapper.selectSvyCategoryList(svyCategoryQuery(patSatisfactionReqVO));
List mydIdList = svyLibScriptCategories.stream().filter(item -> item.getType() != null && item.getType().contains("myd")).map(SatisfactionCategoryRow::getId).collect(Collectors.toList());
List svyLibTemplateScripts = satisfactionScriptMapper.querySvyScriptByCategory(categoryQuery(mydIdList));
//3 一次统计全部问题的发送量/填报量/选项分值(原来是每个问题各查 3 次)
List scriptRefs = new ArrayList<>();
for (SatisfactionSvyScriptRow svyLibTemplateScript : svyLibTemplateScripts) {
// 问卷的选项表按 svy_lib_template_script 的主键关联
scriptRefs.add(new SatScriptRef(svyLibTemplateScript.getSvyid(), svyLibTemplateScript.getId(), svyLibTemplateScript.getScriptContent(), svyLibTemplateScript.getDimension()));
}
buildSatisfactionDetailEntities(patSatisfactionReqVO, "2", false, scriptRefs, patSatisfactionDetailEntities, personTotals);
}
result.setTotalAnswerRate(Arith.div(personTotals[0], personTotals[1]));
result.setPatSatisfactionDetailEntities(patSatisfactionDetailEntities);
result.setTotalPerson(personTotals[0]);
return result;
}
/**
* 患者满意度统计(维度)
*
* @param patSatisfactionReqVO 患者满意度统计条件
* @return 患者满意度统计结果
*/
@Override
public PatSatisfactionResVO statisticsByDimension(PatSatisfactionReqVO patSatisfactionReqVO) {
//定义返参
PatSatisfactionResVO result = new PatSatisfactionResVO();
//患者满意度统详情
List patSatisfactionDetailEntities = new ArrayList<>();
// [0]=答题总人数(已经回答问题的) [1]=总人数(包含未回答的)
int[] personTotals = new int[2];
// 只查本次条件下实际存在哪些 type(原来是把接近全表的上百个字段查回来,仅用于判断下面两个分支是否为空)
List types = satisfactionMapper.selectSatisfactionSubtaskTypes(patSatisfactionReqVO);
boolean hasVoice = types != null && types.contains("1");
boolean hasQuestionnaire = types != null && types.contains("2");
if (hasVoice) {
//1. 先获取入参中的维护集合
List ivrLibaTemplateScripts = satisfactionScriptMapper.selectIvrScriptByDimension(dimensionQuery(patSatisfactionReqVO));
if (CollectionUtils.isNotEmpty(ivrLibaTemplateScripts)) {
//3 一次统计全部问题的发送量/填报量/选项分值(原来是每个问题各查 3 次)
List scriptRefs = new ArrayList<>();
for (SatisfactionIvrScriptRow ivrLibaTemplateScript : ivrLibaTemplateScripts) {
scriptRefs.add(new SatScriptRef(ivrLibaTemplateScript.getTemplateid(), ivrLibaTemplateScript.getScriptid(), ivrLibaTemplateScript.getScriptContent(), ivrLibaTemplateScript.getDimension()));
}
buildSatisfactionDetailEntities(patSatisfactionReqVO, "1", true, scriptRefs, patSatisfactionDetailEntities, personTotals);
}
}
if (hasQuestionnaire) {
//1. 先获取入参中的满意度维度
List svyLibTemplateScripts = satisfactionScriptMapper.selectSvyScriptByDimension(dimensionQuery(patSatisfactionReqVO));
if (CollectionUtils.isNotEmpty(svyLibTemplateScripts)) {
//3 一次统计全部问题的发送量/填报量/选项分值(原来是每个问题各查 3 次)
List scriptRefs = new ArrayList<>();
for (SatisfactionSvyScriptRow svyLibTemplateScript : svyLibTemplateScripts) {
// 问卷的选项表按 svy_lib_template_script 的主键关联
scriptRefs.add(new SatScriptRef(svyLibTemplateScript.getSvyid(), svyLibTemplateScript.getId(), svyLibTemplateScript.getScriptContent(), svyLibTemplateScript.getDimension()));
}
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 satisfactionGraph(PatSatisfactionReqVO patSatisfactionReqVO) {
//用来记录柱状图信息(key=满意度分类名称,value=满意度分类下的总人数和填报人数)
Map zzt = new HashMap<>();
// 记录一下每种分类的填报情况(只记分值与条数,不再把明细行全部查回 Java)
Map> assortNameFillCountMap = new HashMap<>();
if (patSatisfactionReqVO.getType() == null || patSatisfactionReqVO.getType() == 1) {
List ivrLibaScriptAssorts = satisfactionScriptMapper.selectIvrCategoryList(ivrCategoryQuery(patSatisfactionReqVO));
List mydIdList = ivrLibaScriptAssorts.stream().filter(item -> item.getType() != null && item.getType().contains("myd")).map(SatisfactionCategoryRow::getId).collect(Collectors.toList());
List ivrLibaTemplateScripts = satisfactionScriptMapper.queryIvrScriptByAssort(assortQuery(mydIdList));
//2.1 一次性把本次请求全部模板的发送量、回收人数查回来(原来是每个模板问题各查两次)
SatisfactionStatQuery statQuery = buildSatisfactionStatQuery(patSatisfactionReqVO, "1",
ivrLibaTemplateScripts.stream().map(SatisfactionIvrScriptRow::getTemplateid).collect(Collectors.toList()));
Map sendCountMap = mapSatisfactionSendCount(statQuery);
SatisfactionFillStat fillStat = querySatisfactionFillStat(statQuery);
Map fillPersonCountMap = mapSatisfactionFillPersonCount(statQuery);
//3 按scriptAssortname分组,并获取每个集合进行遍历,计算每个分类的总人数和填报人数
Map> scriptGroupByAssortName = ivrLibaTemplateScripts.stream().filter(item -> item.getScriptAssortname() != null).collect(Collectors.groupingBy(SatisfactionIvrScriptRow::getScriptAssortname));
if (scriptGroupByAssortName != null && !scriptGroupByAssortName.isEmpty()) {
for (String assortNameKey : scriptGroupByAssortName.keySet()) {
// 该分类涉及的去重模板:发送人数/回收人数都按模板统计,
// 按题目循环累加会把同一个模板的量重复计成「题量」
Set categoryTemplateIds = new LinkedHashSet<>();
//获取该分类的填报总数量(只用于算平均分,按题目聚合的行数)
List allFillCountList = new ArrayList<>();
List ivrLibaTemplateScriptList = scriptGroupByAssortName.get(assortNameKey);
for (SatisfactionIvrScriptRow ivrLibaTemplateScript : ivrLibaTemplateScriptList) {
Long templateId = ivrLibaTemplateScript.getTemplateid();
if (templateId != null) {
categoryTemplateIds.add(templateId);
}
//获取填报分值分布(只用于平均分)
List fillCount = fillStat.get(templateId, ivrLibaTemplateScript.getScriptContent());
if (CollectionUtils.isNotEmpty(fillCount)) allFillCountList.addAll(fillCount);
}
//记录发送总人数、回收总人数
Double subidAll = 0.0;
Double fillCountAll = 0.0;
for (Long templateId : categoryTemplateIds) {
subidAll += sendCountMap.getOrDefault(templateId, 0L);
fillCountAll += fillPersonCountMap.getOrDefault(templateId, 0L);
}
// 这里先记录一下每个分类的总人数和填报人数
Map 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) {
List svyLibScriptCategories = satisfactionScriptMapper.selectSvyCategoryList(svyCategoryQuery(patSatisfactionReqVO));
List mydIdList = svyLibScriptCategories.stream().filter(item -> item.getType() != null && item.getType().contains("myd")).map(SatisfactionCategoryRow::getId).collect(Collectors.toList());
List svyLibTemplateScripts = satisfactionScriptMapper.querySvyScriptByCategory(categoryQuery(mydIdList));
//2.1 一次性把本次请求全部模板的发送量、回收人数查回来(原来是每个模板问题各查两次)
SatisfactionStatQuery statQuery = buildSatisfactionStatQuery(patSatisfactionReqVO, "2",
svyLibTemplateScripts.stream().map(SatisfactionSvyScriptRow::getSvyid).collect(Collectors.toList()));
Map sendCountMap = mapSatisfactionSendCount(statQuery);
SatisfactionFillStat fillStat = querySatisfactionFillStat(statQuery);
Map fillPersonCountMap = mapSatisfactionFillPersonCount(statQuery);
//3 按scriptAssortname分组,并获取每个集合进行遍历,计算每个分类的总人数和填报人数
Map> scriptGroupByatCegoryName = svyLibTemplateScripts.stream().filter(item -> item.getCategoryName() != null).collect(Collectors.groupingBy(SatisfactionSvyScriptRow::getCategoryName));
if (scriptGroupByatCegoryName != null && !scriptGroupByatCegoryName.isEmpty()) {
for (String categoryNameKey : scriptGroupByatCegoryName.keySet()) {
// 该分类涉及的去重模板:发送人数/回收人数都按模板统计,
// 按题目循环累加会把同一个模板的量重复计成「题量」
Set categoryTemplateIds = new LinkedHashSet<>();
//获取该分类的填报总数量(只用于算平均分,按题目聚合的行数)
List allFillCountList = new ArrayList<>();
List svyLibTemplateScriptList = scriptGroupByatCegoryName.get(categoryNameKey);
for (SatisfactionSvyScriptRow svyLibTemplateScript : svyLibTemplateScriptList) {
Long templateId = svyLibTemplateScript.getSvyid();
if (templateId != null) {
categoryTemplateIds.add(templateId);
}
//获取填报分值分布(只用于平均分)
List fillCount = fillStat.get(templateId, svyLibTemplateScript.getScriptContent());
if (CollectionUtils.isNotEmpty(fillCount)) allFillCountList.addAll(fillCount);
}
//记录发送总人数、回收总人数
Double subidAll = 0.0;
Double fillCountAll = 0.0;
for (Long templateId : categoryTemplateIds) {
subidAll += sendCountMap.getOrDefault(templateId, 0L);
fillCountAll += fillPersonCountMap.getOrDefault(templateId, 0L);
}
// 这里先记录一下每个分类的总人数和填报人数
Map personCount = (Map) 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 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 satisfactionGraphDimension(PatSatisfactionReqVO patSatisfactionReqVO) {
//用来记录柱状图信息(key=满意度维度名称,value=该维度下的总人数和填报人数)
Map zzt = new HashMap<>();
// 记录一下每个维度的填报情况(只记分值与条数,不再把明细行全部查回 Java)
Map> assortNameFillCountMap = new HashMap<>();
if (patSatisfactionReqVO.getType() == null || patSatisfactionReqVO.getType() == 1) {
List ivrLibaTemplateScripts = satisfactionScriptMapper.selectIvrScriptByDimension(dimensionQuery(patSatisfactionReqVO));
if (ivrLibaTemplateScripts != null && !ivrLibaTemplateScripts.isEmpty()) {
//3 按dimension维度分组,并获取每个集合进行遍历,计算每个分类的总人数和填报人数
List dimensionScripts = ivrLibaTemplateScripts.stream().filter(item -> item.getDimension() != null).collect(Collectors.toList());
Map> groupByDimension = dimensionScripts.stream().collect(Collectors.groupingBy(SatisfactionIvrScriptRow::getDimension));
if (groupByDimension != null && !groupByDimension.isEmpty()) {
//3.1 一次性把本次请求全部模板的发送量、回收人数查回来(原来是每个模板问题各查两次)
SatisfactionStatQuery statQuery = buildSatisfactionStatQuery(patSatisfactionReqVO, "1",
dimensionScripts.stream().map(SatisfactionIvrScriptRow::getTemplateid).collect(Collectors.toList()));
Map sendCountMap = mapSatisfactionSendCount(statQuery);
SatisfactionFillStat fillStat = querySatisfactionFillStat(statQuery);
Map fillPersonCountMap = mapSatisfactionFillPersonCount(statQuery);
for (String dimension : groupByDimension.keySet()) {
// 该维度涉及的去重模板:发送人数/回收人数都按模板统计,按题目累加会变成题量
Set dimensionTemplateIds = new LinkedHashSet<>();
//获取该维度的填报分值分布(只用于算平均分)
List allFillCountList = new ArrayList<>();
List ivrLibaTemplateScriptList = groupByDimension.get(dimension);
for (SatisfactionIvrScriptRow ivrLibaTemplateScript : ivrLibaTemplateScriptList) {
Long templateId = ivrLibaTemplateScript.getTemplateid();
if (templateId != null) {
dimensionTemplateIds.add(templateId);
}
//获取填报分值分布(只用于平均分)
List fillCount = fillStat.get(templateId, ivrLibaTemplateScript.getScriptContent());
if (CollectionUtils.isNotEmpty(fillCount)) allFillCountList.addAll(fillCount);
}
//记录发送总人数、回收总人数
Double subidAll = 0.0;
Double fillCountAll = 0.0;
for (Long templateId : dimensionTemplateIds) {
subidAll += sendCountMap.getOrDefault(templateId, 0L);
fillCountAll += fillPersonCountMap.getOrDefault(templateId, 0L);
}
// 这里先记录一下每个分类的总人数和填报人数
Map 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. 从入参中获取满意度维维度
List svyLibTemplateScripts = satisfactionScriptMapper.selectSvyScriptByDimension(dimensionQuery(patSatisfactionReqVO));
if (svyLibTemplateScripts != null && !svyLibTemplateScripts.isEmpty()) {
//3 按dimension维度分组,并获取每个集合进行遍历,计算每个分类的总人数和填报人数
List dimensionScripts = svyLibTemplateScripts.stream().filter(item -> item.getDimension() != null).collect(Collectors.toList());
Map> groupByDimension = dimensionScripts.stream().collect(Collectors.groupingBy(SatisfactionSvyScriptRow::getDimension));
if (groupByDimension != null && !groupByDimension.isEmpty()) {
//3.1 一次性把本次请求全部模板的发送量、回收人数查回来(原来是每个模板问题各查两次)
SatisfactionStatQuery statQuery = buildSatisfactionStatQuery(patSatisfactionReqVO, "2",
dimensionScripts.stream().map(SatisfactionSvyScriptRow::getSvyid).collect(Collectors.toList()));
Map sendCountMap = mapSatisfactionSendCount(statQuery);
SatisfactionFillStat fillStat = querySatisfactionFillStat(statQuery);
Map fillPersonCountMap = mapSatisfactionFillPersonCount(statQuery);
for (String dimension : groupByDimension.keySet()) {
// 该维度涉及的去重模板:发送人数/回收人数都按模板统计,按题目累加会变成题量
Set dimensionTemplateIds = new LinkedHashSet<>();
//获取该分类的填报分值分布(只用于算平均分)
List allFillCountList = new ArrayList<>();
List svyLibTemplateScriptList = groupByDimension.get(dimension);
for (SatisfactionSvyScriptRow svyLibTemplateScript : svyLibTemplateScriptList) {
Long templateId = svyLibTemplateScript.getSvyid();
if (templateId != null) {
dimensionTemplateIds.add(templateId);
}
//获取填报分值分布(只用于平均分)
List fillCount = fillStat.get(templateId, svyLibTemplateScript.getScriptContent());
if (CollectionUtils.isNotEmpty(fillCount)) allFillCountList.addAll(fillCount);
}
//记录发送总人数、回收总人数
Double subidAll = 0.0;
Double fillCountAll = 0.0;
for (Long templateId : dimensionTemplateIds) {
subidAll += sendCountMap.getOrDefault(templateId, 0L);
fillCountAll += fillPersonCountMap.getOrDefault(templateId, 0L);
}
// 这里先记录一下每个分类的总人数和填报人数
Map personCount = (Map) 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 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;
}
// ==================== satisfactionGraph 聚合统计(替代逐个模板查库) ====================
/**
* 构建聚合统计入参(取值来源与原 DtoConversionUtils.sourceToTarget(patSatisfactionReqVO, ServiceSubtaskSatisfactionEntity.class) 一致)
*
* @param reqVO 原始请求
* @param type service_subtask.type(1 语音、2 问卷),用字符串比较避免隐式转换
* @param templateIds 本次请求涉及的模板id(ivr 用 templateid,问卷用 svyid)
*/
private SatisfactionStatQuery buildSatisfactionStatQuery(PatSatisfactionReqVO reqVO, String type, List 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,value=发送量(等价于原 querySendCount 结果的 size)
*/
private Map mapSatisfactionSendCount(SatisfactionStatQuery statQuery) {
Map sendCountMap = new HashMap<>();
if (statQuery == null || CollectionUtils.isEmpty(statQuery.getLibTemplateIds())) return sendCountMap;
List