package com.smartor.service.impl;
|
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import com.alibaba.fastjson2.JSON;
|
import com.github.pagehelper.util.StringUtil;
|
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
import com.smartor.domain.*;
|
import com.smartor.domain.DTO.DetailTraceDealDTO;
|
import com.smartor.domain.VO.DetailTraceDealVO;
|
import com.smartor.domain.VO.SatisfactionExceptConfigQuestionReqVO;
|
import com.smartor.domain.VO.ServiceSubtaskDetailTraceVO;
|
import com.smartor.mapper.ServiceSubtaskDetailMapper;
|
import com.smartor.mapper.ServiceSubtaskDetailTraceMapper;
|
import com.smartor.mapper.SvyLibScriptCategoryMapper;
|
import com.smartor.mapper.SvyLibTemplateScriptMapper;
|
import com.smartor.service.*;
|
import org.apache.commons.collections4.CollectionUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
/**
|
* 随访任务异常记录跟踪Service业务层处理
|
*
|
* @author lihu
|
* @date 2026-03-24
|
*/
|
@Service
|
public class ServiceSubtaskDetailTraceServiceImpl implements IServiceSubtaskDetailTraceService {
|
@Autowired
|
private ServiceSubtaskDetailTraceMapper serviceSubtaskDetailTraceMapper;
|
|
@Autowired
|
private ServiceSubtaskDetailMapper serviceSubtaskDetailMapper;
|
|
@Autowired
|
private ISvyLibScriptCategoryService iSvyLibScriptCategoryService;
|
|
@Autowired
|
private SvyLibScriptCategoryMapper svyLibScriptCategoryMapper;
|
|
@Autowired
|
private ISvyLibTemplateScriptService isvyLibTemplateScriptService;
|
|
@Autowired
|
private IIvrLibaScriptAssortService iIvrLibaScriptAssortService;
|
|
@Autowired
|
private IIvrLibaTemplateScriptService iIvrLibaTemplateScriptService;
|
|
/**
|
* 查询随访任务异常记录跟踪
|
*
|
* @param id 随访任务异常记录跟踪主键
|
* @return 随访任务异常记录跟踪
|
*/
|
@Override
|
public ServiceSubtaskDetailTrace selectServiceSubtaskDetailTtraceById(Long id) {
|
return serviceSubtaskDetailTraceMapper.selectServiceSubtaskDetailTtraceById(id);
|
}
|
|
/**
|
* 查询随访任务异常记录跟踪列表
|
*
|
* @param serviceSubtaskDetailTraceVO 随访任务异常记录跟踪
|
* @return 随访任务异常记录跟踪
|
*/
|
@Override
|
public List<ServiceSubtaskDetailTrace> selectServiceSubtaskDetailTtraceList(ServiceSubtaskDetailTraceVO serviceSubtaskDetailTraceVO) {
|
List<ServiceSubtaskDetailTrace> serviceSubtaskDetailTraces = serviceSubtaskDetailTraceMapper.selectServiceSubtaskDetailTtraceList(serviceSubtaskDetailTraceVO);
|
for (ServiceSubtaskDetailTrace serviceSubtaskDetailTrace : serviceSubtaskDetailTraces) {
|
if (StringUtils.isNotEmpty(serviceSubtaskDetailTrace.getPatdesc())) {
|
serviceSubtaskDetailTrace.setPatdescJson(JSON.parseObject(serviceSubtaskDetailTrace.getPatdesc()));
|
}
|
}
|
return serviceSubtaskDetailTraces;
|
}
|
|
@Override
|
public Map<String, Object> tracedeallist(DetailTraceDealVO detailTraceDealVO) {
|
// 优化前:① 这条 SQL 没有 limit,每次都把整表 trace(含 patdesc/recordurl 大字段)拉回 Java 再分组;
|
// ② 每个问题都拿 scriptid 去 service_subtask_detail 查一次全表只为取 size(N+1);
|
// ③ controller 把这个方法调了两遍(第二遍为了总数),等于上面两步各跑两次。
|
// 优化后:固定的 5 条聚合 SQL,DB 只处理当前页的题目。
|
// 1) 当前页的问题分组聚合(分页下推到 SQL)
|
List<Map<String, Object>> groupRows = serviceSubtaskDetailTraceMapper.selectTraceDealGroups(detailTraceDealVO);
|
// 2) 问题总数(分页 total,全量口径)
|
long questionTotal = serviceSubtaskDetailTraceMapper.countTraceDealQuestions(detailTraceDealVO);
|
// 3) 汇总统计(全量口径,不受分页影响)
|
Map<String, Object> sumRow = serviceSubtaskDetailTraceMapper.sumTraceDeal(detailTraceDealVO);
|
long totalException = toLong(sumRow == null ? null : sumRow.get("totalException"), 0L);
|
long yesDealException = toLong(sumRow == null ? null : sumRow.get("yesDeal"), 0L);
|
long noDealException = totalException - yesDealException;
|
|
List<DetailTraceDealDTO> detailTraceDealDTOList = new ArrayList<>();
|
if (CollectionUtils.isNotEmpty(groupRows)) {
|
// 本页涉及的问题文本,后面 3 条查询都按它过滤
|
List<String> questiontexts = groupRows.stream()
|
.map(row -> row.get("questiontext"))
|
.filter(Objects::nonNull)
|
.map(String::valueOf)
|
.distinct()
|
.collect(Collectors.toList());
|
|
// 4) 本页问题的负责科室(按科室编号去重)
|
Map<String, List<Map<String, Object>>> deptMap = new HashMap<>();
|
// 5) 本页问题的最新处理人/处理时间
|
Map<String, Map<String, Object>> latestHandleMap = new HashMap<>();
|
if (CollectionUtils.isNotEmpty(questiontexts)) {
|
for (Map<String, Object> row : serviceSubtaskDetailTraceMapper.selectTraceDealDepts(detailTraceDealVO, questiontexts)) {
|
String questiontext = row.get("questiontext") == null ? null : String.valueOf(row.get("questiontext"));
|
if (questiontext == null) continue;
|
Map<String, Object> deptMapItem = new HashMap<>();
|
deptMapItem.put("deptName", row.get("deptName"));
|
deptMapItem.put("deptCode", row.get("deptCode"));
|
deptMap.computeIfAbsent(questiontext, key -> new ArrayList<>()).add(deptMapItem);
|
}
|
|
for (Map<String, Object> row : serviceSubtaskDetailTraceMapper.selectTraceDealLatestHandle(detailTraceDealVO, questiontexts)) {
|
String questiontext = row.get("questiontext") == null ? null : String.valueOf(row.get("questiontext"));
|
if (questiontext == null) continue;
|
// 同一个最大处理时间可能有多条,保留第一条即可(原实现取组内 handle_time 最大的那条)
|
latestHandleMap.putIfAbsent(questiontext, row);
|
}
|
}
|
|
// 6) 本页问题的有效填写数:一次 group by 查回,替代逐个 scriptid 查询
|
// 一个问题可能对应多个 scriptid,所以先把 questiontext -> scriptid 列表解开,
|
// 再把该问题所有 scriptid 的填写数相加(与原实现 for 循环累加的口径一致)
|
Map<String, List<Long>> questionScriptIds = new LinkedHashMap<>();
|
Set<Long> scriptIdSet = new LinkedHashSet<>();
|
for (Map<String, Object> row : groupRows) {
|
String questiontext = row.get("questiontext") == null ? null : String.valueOf(row.get("questiontext"));
|
if (questiontext == null) continue;
|
List<Long> ids = parseScriptIds(row.get("scriptids"));
|
questionScriptIds.put(questiontext, ids);
|
scriptIdSet.addAll(ids);
|
}
|
Map<Long, Long> effectiveFillMap = new HashMap<>();
|
if (CollectionUtils.isNotEmpty(scriptIdSet)) {
|
for (Map<String, Object> row : serviceSubtaskDetailMapper.countDetailByScriptIds(new ArrayList<>(scriptIdSet))) {
|
Long scriptId = toLongObj(row.get("scriptid"));
|
if (scriptId == null) continue;
|
effectiveFillMap.put(scriptId, toLong(row.get("cnt"), 0L));
|
}
|
}
|
|
// 7) 组装返回结构(顺序 = SQL 的 order by questiontext,保证分页稳定)
|
for (Map<String, Object> row : groupRows) {
|
String questiontext = row.get("questiontext") == null ? null : String.valueOf(row.get("questiontext"));
|
if (questiontext == null) continue;
|
|
DetailTraceDealDTO dto = new DetailTraceDealDTO();
|
dto.setQuestiontext(questiontext);
|
Long scriptId = toLongObj(row.get("scriptid"));
|
dto.setScriptid(scriptId);
|
dto.setScriptids(parseScriptIds(row.get("scriptids")));
|
Object templateType = row.get("templateType");
|
dto.setTemplateType(templateType == null ? null : Integer.valueOf(String.valueOf(templateType)));
|
dto.setResponsibleDept(deptMap.getOrDefault(questiontext, new ArrayList<>()));
|
|
long exceptionFillNum = toLong(row.get("exceptionFillNum"), 0L);
|
// 该问题下所有 scriptid 的有效填写数之和(一个 questiontext 可能对应多个 scriptid)
|
long effectiveFillNum = 0L;
|
for (Long sid : questionScriptIds.getOrDefault(questiontext, new ArrayList<>())) {
|
effectiveFillNum += effectiveFillMap.getOrDefault(sid, 0L);
|
}
|
Map<String, Object> fillSituation = new HashMap<>();
|
fillSituation.put("effectiveFillNum", effectiveFillNum);
|
fillSituation.put("exceptionFillNum", exceptionFillNum);
|
dto.setFillSituation(fillSituation);
|
|
long yesDeal = toLong(row.get("yesDeal"), 0L);
|
long noDeal = toLong(row.get("noDeal"), 0L);
|
Map<String, Object> exceptionQuesNum = new HashMap<>();
|
exceptionQuesNum.put("yesDeal", yesDeal);
|
exceptionQuesNum.put("noDeal", noDeal);
|
exceptionQuesNum.put("all", exceptionFillNum);
|
dto.setExceptionQuesNum(exceptionQuesNum);
|
|
Map<String, Object> latestHandle = latestHandleMap.get(questiontext);
|
if (latestHandle != null) {
|
dto.setHandleBy(latestHandle.get("handleBy") == null ? null : String.valueOf(latestHandle.get("handleBy")));
|
Object handleTime = latestHandle.get("handleTime");
|
dto.setHandleTime(handleTime instanceof Date ? (Date) handleTime : null);
|
}
|
|
detailTraceDealDTOList.add(dto);
|
}
|
}
|
|
Map<String, Object> result = new HashMap<>();
|
result.put("detailTraceDealDTOList", detailTraceDealDTOList);
|
result.put("totalException", totalException);
|
result.put("noDealException", noDealException);
|
result.put("yesDealException", yesDealException);
|
// 分页总数(按问题维度),controller 直接用它,不用再全量查一遍
|
result.put("questionTotal", questionTotal);
|
return result;
|
}
|
|
private static Long toLongObj(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 = toLongObj(value);
|
return result == null ? defaultValue : result;
|
}
|
|
/**
|
* 解析 group_concat(distinct scriptid) 的结果(如 "101,102")为 scriptid 列表
|
*/
|
private static List<Long> parseScriptIds(Object value) {
|
List<Long> scriptIds = new ArrayList<>();
|
if (value == null) return scriptIds;
|
for (String item : String.valueOf(value).split(",")) {
|
Long scriptId = toLongObj(item);
|
if (scriptId != null && !scriptIds.contains(scriptId)) {
|
scriptIds.add(scriptId);
|
}
|
}
|
return scriptIds;
|
}
|
|
/**
|
* 新增随访任务异常记录跟踪
|
*
|
* @param serviceSubtaskDetailTrace 随访任务异常记录跟踪
|
* @return 结果
|
*/
|
@Override
|
public int insertServiceSubtaskDetailTtrace(ServiceSubtaskDetailTrace serviceSubtaskDetailTrace) {
|
serviceSubtaskDetailTrace.setCreateTime(DateUtils.getNowDate());
|
return serviceSubtaskDetailTraceMapper.insertServiceSubtaskDetailTtrace(serviceSubtaskDetailTrace);
|
}
|
|
/**
|
* 修改随访任务异常记录跟踪
|
*
|
* @param serviceSubtaskDetailTrace 随访任务异常记录跟踪
|
* @return 结果
|
*/
|
@Override
|
public int updateServiceSubtaskDetailTtrace(ServiceSubtaskDetailTrace serviceSubtaskDetailTrace) {
|
serviceSubtaskDetailTrace.setUpdateTime(DateUtils.getNowDate());
|
return serviceSubtaskDetailTraceMapper.updateServiceSubtaskDetailTtrace(serviceSubtaskDetailTrace);
|
}
|
|
/**
|
* 批量删除随访任务异常记录跟踪
|
*
|
* @param ids 需要删除的随访任务异常记录跟踪主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteServiceSubtaskDetailTtraceByIds(Long[] ids) {
|
return serviceSubtaskDetailTraceMapper.deleteServiceSubtaskDetailTtraceByIds(ids);
|
}
|
|
/**
|
* 删除随访任务异常记录跟踪信息
|
*
|
* @param id 随访任务异常记录跟踪主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteServiceSubtaskDetailTtraceById(Long id) {
|
return serviceSubtaskDetailTraceMapper.deleteServiceSubtaskDetailTtraceById(id);
|
}
|
|
@Override
|
public Map<String, Object> getSatisfactionExceptConfigQuestion(SatisfactionExceptConfigQuestionReqVO questionReqVO) {
|
// 初始化结果集
|
Map<String, Object> result = new HashMap<>();
|
|
if (StringUtils.isEmpty(questionReqVO.getScriptType()) || questionReqVO.getScriptType().equals("1")) {
|
List<Map<String, Object>> voicetDataList = new ArrayList<>();
|
//获取满意度的分类
|
IvrLibaScriptAssort ivrLibaScriptAssort = new IvrLibaScriptAssort();
|
ivrLibaScriptAssort.setType("myd");
|
if (!StringUtils.isEmpty(questionReqVO.getType())) ivrLibaScriptAssort.setType(questionReqVO.getType());
|
List<IvrLibaScriptAssortVO> ivrLibaScriptAssortVOS = iIvrLibaScriptAssortService.selectIvrLibaScriptAssortList(ivrLibaScriptAssort);
|
List<Long> assortIdList = Optional.ofNullable(ivrLibaScriptAssortVOS).filter(list -> !list.isEmpty()).map(list -> list.stream().map(IvrLibaScriptAssortVO::getId).collect(Collectors.toList())).orElse(Collections.emptyList());
|
|
//用来记录满意度的所有问题
|
List<IvrLibaTemplateScript> ivrLibaTemplateScriptList = new ArrayList<>();
|
if (CollectionUtils.isNotEmpty(assortIdList)) {
|
for (Long assortId : assortIdList) {
|
IvrLibaTemplateScript ivrLibaTemplateScript = new IvrLibaTemplateScript();
|
ivrLibaTemplateScript.setScriptAssortid(assortId);
|
List<IvrLibaTemplateScript> ivrLibaTemplateScripts = iIvrLibaTemplateScriptService.selectIvrLibaTemplateScriptList(ivrLibaTemplateScript);
|
ivrLibaTemplateScriptList.addAll(ivrLibaTemplateScripts);
|
}
|
for (IvrLibaTemplateScript ivrLibaTemplateScript : ivrLibaTemplateScriptList) {
|
Map<String, Object> voicetData = new HashMap<>();
|
voicetData.put("questionId", ivrLibaTemplateScript.getId());
|
voicetData.put("libtemplateid", ivrLibaTemplateScript.getTemplateid());
|
voicetData.put("questionContent", ivrLibaTemplateScript.getScriptContent());
|
voicetData.put("questionTopic", ivrLibaTemplateScript.getScriptTopic());
|
voicetData.put("questionType", ivrLibaTemplateScript.getScriptType());
|
voicetData.put("categoryName", ivrLibaTemplateScript.getScriptAssortname());
|
voicetData.put("categoryId", ivrLibaTemplateScript.getScriptAssortid());
|
voicetDataList.add(voicetData);
|
}
|
}
|
//语音数据返回集合
|
result.put("voiceDataList", voicetDataList);
|
}
|
|
if (StringUtils.isEmpty(questionReqVO.getScriptType()) || questionReqVO.getScriptType().equals("2")) {
|
List<Map<String, Object>> questionnaireDataList = new ArrayList<>();
|
//获取满意度的分类
|
SvyLibScriptCategory svyLibScriptCategory = new SvyLibScriptCategory();
|
svyLibScriptCategory.setType("myd");
|
if (!StringUtils.isEmpty(questionReqVO.getType())) svyLibScriptCategory.setType(questionReqVO.getType());
|
List<SvyLibScriptCategory> svyLibScriptCategoryVOS = svyLibScriptCategoryMapper.selectSvyLibScriptCategoryList(svyLibScriptCategory);
|
List<Long> assortIdList = Optional.ofNullable(svyLibScriptCategoryVOS).filter(list -> !list.isEmpty()).map(list -> list.stream().map(SvyLibScriptCategory::getId).collect(Collectors.toList())).orElse(Collections.emptyList());
|
|
//用来记录满意度的所有问题
|
List<SvyLibTemplateScript> svyLibTemplateScriptList = new ArrayList<>();
|
if (CollectionUtils.isNotEmpty(assortIdList)) {
|
for (Long categoryid : assortIdList) {
|
SvyLibTemplateScript svyLibTemplateScript = new SvyLibTemplateScript();
|
svyLibTemplateScript.setCategoryid(categoryid);
|
List<SvyLibTemplateScript> svyLibTemplateScripts = isvyLibTemplateScriptService.selectSvyLibTemplateScriptList(svyLibTemplateScript);
|
svyLibTemplateScriptList.addAll(svyLibTemplateScripts);
|
}
|
for (SvyLibTemplateScript svyLibTemplateScript : svyLibTemplateScriptList) {
|
Map<String, Object> voicetData = new HashMap<>();
|
voicetData.put("questionId", svyLibTemplateScript.getId());
|
voicetData.put("libtemplateid", svyLibTemplateScript.getSvyid());
|
voicetData.put("questionContent", svyLibTemplateScript.getScriptContent());
|
voicetData.put("questionTopic", svyLibTemplateScript.getScriptTopic());
|
voicetData.put("questionType", svyLibTemplateScript.getScriptType());
|
voicetData.put("categoryName", svyLibTemplateScript.getCategoryName());
|
voicetData.put("categoryId", svyLibTemplateScript.getCategoryid());
|
questionnaireDataList.add(voicetData);
|
}
|
}
|
//问卷数据返回集合
|
result.put("questionnaireDataList", questionnaireDataList);
|
}
|
return result;
|
}
|
}
|