package com.ruoyi.task.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.service.IConfigService; import com.ruoyi.satisfaction.api.SatisfactionFacade; import com.ruoyi.message.sms.provider.sltd.ws.MessageSend; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.*; import com.ruoyi.common.utils.http.HttpUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.message.SendResult; import com.ruoyi.message.sms.SmsSendRequest; import com.ruoyi.message.sms.SmsSenderFactory; import com.ruoyi.message.wechat.WechatSendRequest; import com.ruoyi.message.wechat.WechatSenderFactory; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestBody; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import java.util.stream.Collectors; import com.ruoyi.template.domain.VO.HeLibraryCountVO; import com.ruoyi.inhospvisit.domain.PatMedInhosp; import com.ruoyi.othervisit.domain.PatMedOperationItem; import com.ruoyi.outpatientvisit.domain.PatMedOuthosp; import com.ruoyi.outpatientvisit.domain.PatMedOuthospQueryReq; import com.ruoyi.inhospvisit.api.InhospVisitFacade; import com.ruoyi.outpatientvisit.api.OuthospDataFacade; import com.ruoyi.othervisit.api.OtherVisitFacade; import com.ruoyi.template.domain.IvrTaskTemplate; import com.ruoyi.template.domain.IvrTaskTemplateScript; import com.ruoyi.template.domain.IvrTaskTemplateScriptVO; import com.ruoyi.template.domain.IvrTaskTemplateTargetoption; import com.ruoyi.template.domain.IvrTaskTemplateVO; import com.ruoyi.template.mapper.IvrTaskTemplateTargetoptionMapper; import com.ruoyi.template.service.IIvrTaskTemplateScriptService; import com.ruoyi.template.service.IIvrTaskTemplateService; import com.ruoyi.template.service.IIvrTaskTemplateTargetoptionService; import com.ruoyi.template.domain.IvrLibaExtemplatescript; import com.ruoyi.template.mapper.IvrLibaExtemplatescriptMapper; import com.ruoyi.template.domain.SvyLibScriptCategory; import com.ruoyi.template.domain.SvyTaskTemplate; import com.ruoyi.template.domain.SvyTaskTemplateScript; import com.ruoyi.template.domain.SvyTaskTemplateScriptVO; import com.ruoyi.template.domain.SvyTaskTemplateTargetoption; import com.ruoyi.template.mapper.SvyLibScriptCategoryMapper; import com.ruoyi.template.service.ISvyTaskTemplateScriptService; import com.ruoyi.template.service.ISvyTaskTemplateService; import static cn.hutool.core.convert.Convert.toHex; import com.ruoyi.common.core.domain.entity.PatArchive; import com.ruoyi.task.domain.DTO.ServiceSubtaskDetailDTO; import com.ruoyi.task.domain.entity.ServiceSubtaskEntity; import com.ruoyi.task.domain.ServiceStatisticsRequest; import com.ruoyi.task.domain.ServiceStatisticsResponse; import com.ruoyi.task.domain.ServiceSubtask; import com.ruoyi.task.domain.ServiceSubtaskCount; import com.ruoyi.task.domain.ServiceSubtaskCountReq; import com.ruoyi.task.domain.ServiceSubtaskDetail; import com.ruoyi.task.domain.ServiceSubtaskDetailVO; import com.ruoyi.task.domain.ServiceSubtaskScriptCount; import com.ruoyi.task.domain.ServiceSubtaskStatistic; import com.ruoyi.task.domain.ServiceTask; import com.ruoyi.task.domain.ServiceTaskdept; import com.ruoyi.task.domain.ServiceTaskdiag; import com.ruoyi.task.domain.ServiceTaskmedical; import com.ruoyi.task.domain.ServiceTaskoper; import com.ruoyi.task.domain.ServiceTaskSchedule; import com.ruoyi.task.domain.ServiceTaskScheduleDetail; import com.ruoyi.task.domain.TaskSendTimeVO; import com.ruoyi.task.domain.VO.ServiceSubtaskCotinueCountVO; import com.ruoyi.task.mapper.ServiceSubtaskDetailMapper; import com.ruoyi.task.mapper.ServiceSubtaskMapper; import com.ruoyi.task.domain.ServiceSubtaskDetailTrace; import com.ruoyi.task.domain.ServiceOutPath; import com.ruoyi.task.mapper.ServiceOutPathMapper; import com.ruoyi.task.service.IServiceOutPathService; import com.ruoyi.task.domain.ServiceSubtaskPreachform; import com.ruoyi.task.mapper.ServiceSubtaskPreachformMapper; import com.ruoyi.task.api.spi.TaskArchivePort; import com.ruoyi.task.common.ScheduleSubtaskBuilder; import com.ruoyi.task.domain.ServiceTaskScheduleVO; import com.ruoyi.task.service.IServiceSubtaskService; import com.ruoyi.task.service.IServiceTaskScheduleService; import com.ruoyi.task.service.IServiceTaskService; import com.ruoyi.task.service.IServiceTaskdeptService; import com.ruoyi.task.service.IServiceTaskdiagService; import com.ruoyi.task.service.IServiceTaskmedicalService; import com.ruoyi.task.service.IServiceTaskoperService; import com.ruoyi.task.domain.PatArchiveSrmVO; import com.ruoyi.task.domain.PatTaskRelevance; import com.ruoyi.task.domain.SendMagParam; import com.ruoyi.task.domain.ServiceSubtaskDiagname; import com.ruoyi.task.domain.ServiceSubtaskIsAbnormalStatistic; import com.ruoyi.task.domain.ServiceSubtaskRes; import com.ruoyi.task.domain.ServiceSubtaskTemplateVO; import com.ruoyi.task.domain.ServiceTaskVO; import com.ruoyi.task.domain.VO.TransferDeptVO; import com.ruoyi.system.service.ISysConfigService; import com.ruoyi.system.service.ISysDeptService; import com.ruoyi.system.mapper.ext.SysDept2Mapper; import com.ruoyi.task.api.contract.OperationSubtaskWriter; /** * 单一任务(随访)Service业务层处理 * * @author ruoyi * @date 2024-02-02 */ @Slf4j @Service public class ServiceSubtaskServiceImpl implements IServiceSubtaskService { /** * 随访子任务组装器(原 smartor 侧 IPatMedInhospService#boxedServiceSubtask 在本模块的落地实现)。 *

* 二次随访要用「下一任务配置 + 出院记录 + 患者档案」组装新的 service_subtask, * 这段口径与长期任务生成完全一致,因此直接复用本模块已有的组装器,不再复制一份。 */ @Autowired private OperationSubtaskWriter operationSubtaskWriter; /** * 满意度模块对外门面(常驻 Bean)。 *

* 随访统计里的「满意度指数」({@code getSfStatisticsJoy})只能通过它取数; * 满意度模块关闭时门面返回全零 Map,不影响随访统计的其它字段与启动。 */ @Autowired private SatisfactionFacade satisfactionFacade; /** * 跨模块访问一律经模块门面(禁止直连已搬走的 Mapper)。 */ @Autowired private OtherVisitFacade otherVisitFacade; /** * 跨模块访问一律经模块门面(禁止直连已搬走的 Mapper)。 */ @Autowired private OuthospDataFacade outhospDataFacade; /** * 跨模块访问一律经模块门面(禁止直连已搬走的 Mapper)。 */ @Autowired private InhospVisitFacade inhospVisitFacade; @Autowired private ServiceSubtaskMapper serviceSubtaskMapper; @Autowired private ServiceSubtaskPreachformMapper taskPreachformPort; @Autowired private ServiceSubtaskDetailMapper serviceSubtaskDetailMapper; @Autowired private IServiceTaskService serviceTaskService; @Autowired private IvrTaskTemplateTargetoptionMapper serviceTaskScriptTargetoptionMapper; @Autowired private IServiceTaskdeptService serviceTaskdeptService; @Autowired private IServiceTaskmedicalService serviceTaskmedicalService; @Autowired private IServiceTaskdiagService serviceTaskdiagService; @Autowired private IServiceTaskoperService serviceTaskoperService; @Autowired private RedisCache redisCache; @Autowired private IvrLibaExtemplatescriptMapper ivrLibaExtemplatescriptMapper; @Autowired private ISvyTaskTemplateScriptService svyTaskTemplateScriptService; @Autowired private IIvrTaskTemplateService ivrTaskTemplateService; @Autowired private ISvyTaskTemplateService svyTaskTemplateService; @Autowired private IIvrTaskTemplateScriptService iIvrTaskTemplateScriptService; @Autowired private IIvrTaskTemplateTargetoptionService iIvrTaskTemplateTargetoptionService; @Autowired private IServiceOutPathService iServiceOutPathService; @Autowired private IServiceTaskScheduleService serviceTaskScheduleService; @Autowired private TaskArchivePort taskArchivePort; @Autowired private ISysDeptService sysDeptService; @Autowired private ScheduleSubtaskBuilder scheduleSubtaskBuilder; @Autowired private SvyLibScriptCategoryMapper svyLibScriptCategoryMapper; @Value("${pub_key}") private String pub_key; @Autowired private ISysConfigService sysConfigService; /** * 消息发送方工厂(短信/微信公众号),替代原来直接调用各站点发送代码的写法 */ @Autowired private SmsSenderFactory smsSenderFactory; @Autowired private WechatSenderFactory wechatSenderFactory; @Value("${localIP}") private String localIP; @Value("${req_path}") private String req_path; @Autowired private SysDept2Mapper sysDept2Mapper; @Value("${spring.profiles.active}") private String active; @Autowired private ServiceOutPathMapper serviceOutPathMapper; private static final String KEY_SEP = "\u0001"; /** 二次随访生成锁前缀,防止同一原任务并发生成多条二次随访 */ private static final String AGAIN_LOCK_KEY_PREFIX = "smartor:again:lock:"; private static final long AGAIN_LOCK_SECONDS = 30L; /** * 查询单一任务(随访) * * @param id 单一任务(随访)主键 * @return 单一任务(随访) */ @Override public ServiceSubtask selectServiceSubtaskById(Long id) { return serviceSubtaskMapper.selectServiceSubtaskById(id); } @Override public List selectServiceSubtaskByDiagname(ServiceSubtask serviceSubtask) { return serviceSubtaskMapper.selectServiceSubtaskByDiagname(serviceSubtask); } /** * 查询单一任务(随访)列表 * * @param serviceSubtaskEntity 单一任务(随访) * @return 单一任务(随访) */ @Override public List selectServiceSubtaskList(ServiceSubtaskEntity serviceSubtaskEntity) { return serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskEntity); } public List selectServiceSubtaskListAgain(ServiceSubtaskEntity serviceSubtaskEntity) { return serviceSubtaskMapper.selectServiceSubtaskListAgain(serviceSubtaskEntity); } @Override public ServiceTaskVO queryTaskByCondition(ServiceSubtask serviceSubtask) { //定义患者与单一任务关联表集合 List patTaskRelevances = new ArrayList<>(); ServiceSubtaskEntity serviceSubtaskVO = DtoConversionUtils.sourceToTarget(serviceSubtask, ServiceSubtaskEntity.class); List list = selectServiceSubtaskList(serviceSubtaskVO); ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); if (ObjectUtils.isEmpty(serviceTask)) { log.error("找不到对应的serviceTask, orgid:{}, taskid: {}", serviceSubtask.getOrgid(), serviceSubtask.getTaskid()); return null; } if (CollectionUtils.isEmpty(list) || list.size() == 0) { ServiceTaskVO serviceTaskVO = DtoConversionUtils.sourceToTarget(serviceTask, ServiceTaskVO.class); ObjectMapper objectMapper = new ObjectMapper(); try { List> mapList = objectMapper.readValue(serviceTask.getPreachformDesc(), List.class); serviceTaskVO.setPreachformList(mapList); if (ObjectUtils.isNotEmpty(serviceTask.getTaskid())) { ServiceTaskoper operVo = new ServiceTaskoper(); operVo.setTaskId(serviceTask.getTaskid()); operVo.setOrgid(serviceTask.getOrgid()); List serviceTaskopers = serviceTaskoperService.selectServiceTaskoperList(operVo); if (ObjectUtils.isNotEmpty(serviceTaskopers)) { serviceTaskVO.setOplevelcode(serviceTaskopers.get(0).getOplevelcode()); } } // // String result = mapList.stream().map(mapList1 -> mapList1.get("preachform")).map(String::valueOf).collect(Collectors.joining(",")); // serviceTaskVO.setPreachform(result); } catch (JsonProcessingException e) { e.printStackTrace(); } findServiceTaskScheduleVO(serviceTaskVO); return serviceTaskVO; } //将查出来的数据倒入ServiceSubtaskVO中 ServiceTaskVO serviceTaskVO = DtoConversionUtils.sourceToTarget(serviceTask, ServiceTaskVO.class); serviceTaskVO.setShowDate(serviceTask.getShowDate()); serviceTaskVO.setShowTimeMorn(serviceTask.getShowTimeMorn()); serviceTaskVO.setShowTimeNoon(serviceTask.getShowTimeNoon()); serviceTaskVO.setShowTimeNight(serviceTask.getShowTimeNight()); serviceTaskVO.setPreachform(serviceTask.getPreachform()); if (ObjectUtils.isNotEmpty(serviceTask.getTaskid())) { ServiceTaskoper operVo = new ServiceTaskoper(); operVo.setTaskId(serviceTask.getTaskid()); operVo.setOrgid(serviceTask.getOrgid()); List serviceTaskopers = serviceTaskoperService.selectServiceTaskoperList(operVo); if (ObjectUtils.isNotEmpty(serviceTaskopers)) { serviceTaskVO.setOplevelcode(serviceTaskopers.get(0).getOplevelcode()); } } String sendTimeSlot = serviceTask.getSendTimeSlot(); ObjectMapper objectMapper = new ObjectMapper(); try { //获取到发送时间的集合 if (com.ruoyi.common.utils.StringUtils.isNotEmpty(sendTimeSlot)) { List taskSendTimeVOList = objectMapper.readValue(sendTimeSlot, List.class); serviceTaskVO.setSendTimeslot(taskSendTimeVOList); serviceTaskVO.setSendType(serviceTask.getSendType()); } //文本变量参数 if (com.ruoyi.common.utils.StringUtils.isNotEmpty(serviceTask.getTextParam())) { Map> textParam = objectMapper.readValue(serviceTask.getTextParam(), Map.class); serviceTaskVO.setTextParam(textParam); } } catch (JsonProcessingException e) { e.printStackTrace(); } List serviceSubtaskPreachformLists = taskPreachformPort.selectBySubtask(serviceSubtask); for (ServiceSubtask serviceSubtask1 : list) { PatTaskRelevance patTaskRelevance = new PatTaskRelevance(); if (!serviceSubtask1.getHospType().equals("2")) { log.info("随访查询不为出院,{}", serviceSubtask1.getHospType()); //获取到患者信息,并放入到集合中 patTaskRelevance.setName(serviceSubtask1.getSendname()); patTaskRelevance.setAge(serviceSubtask1.getAge()); patTaskRelevance.setFinishtime(serviceSubtask1.getFinishtime()); patTaskRelevance.setSfzh(serviceSubtask1.getSfzh()); patTaskRelevance.setPhone(serviceSubtask1.getPhone()); patTaskRelevance.setTelcode(serviceSubtask1.getPhone()); patTaskRelevance.setAddr(serviceSubtask1.getAddr()); patTaskRelevance.setDiagname(serviceSubtask1.getLeavediagname()); patTaskRelevance.setPatid(serviceSubtask1.getPatid()); patTaskRelevance.setSendStatus(serviceSubtask1.getSendstate()); patTaskRelevance.setDeptcode(serviceSubtask1.getLeaveldeptcode()); patTaskRelevance.setDeptName(serviceSubtask1.getLeaveldeptname()); patTaskRelevance.setLeavehospitaldistrictcode(serviceSubtask1.getLeavehospitaldistrictcode()); patTaskRelevance.setLeavehospitaldistrictname(serviceSubtask1.getLeavehospitaldistrictname()); patTaskRelevance.setInhosptime(serviceSubtask1.getInhosptime()); patTaskRelevance.setDrname(serviceSubtask1.getDrname()); patTaskRelevance.setDrcode(serviceSubtask1.getDrcode()); patTaskRelevance.setEndtime(serviceSubtask1.getEndtime()); patTaskRelevance.setNurseId(serviceSubtask1.getNurseId()); patTaskRelevance.setNurseName(serviceSubtask1.getNurseName()); patTaskRelevances.add(patTaskRelevance); } if (serviceSubtask1.getHospType().equals("2")) { log.info("随访查询为出院,{}", serviceSubtask1.getHospType()); patTaskRelevance.setName(serviceSubtask1.getSendname()); patTaskRelevance.setAge(serviceSubtask1.getAge()); patTaskRelevance.setSfzh(serviceSubtask1.getSfzh()); patTaskRelevance.setPhone(serviceSubtask1.getPhone()); patTaskRelevance.setTelcode(serviceSubtask1.getPhone()); patTaskRelevance.setFinishtime(serviceSubtask1.getFinishtime()); patTaskRelevance.setAddr(serviceSubtask1.getAddr()); patTaskRelevance.setDeptName(serviceSubtask1.getLeaveldeptname()); patTaskRelevance.setDeptcode(serviceSubtask1.getLeaveldeptcode()); patTaskRelevance.setBedNo(serviceSubtask1.getBedNo()); patTaskRelevance.setDiagname(serviceSubtask1.getLeavediagname()); patTaskRelevance.setPatid(serviceSubtask1.getPatid()); patTaskRelevance.setSendStatus(serviceSubtask1.getSendstate()); patTaskRelevance.setLeavehospitaldistrictcode(serviceSubtask1.getLeavehospitaldistrictcode()); patTaskRelevance.setLeavehospitaldistrictname(serviceSubtask1.getLeavehospitaldistrictname()); patTaskRelevance.setInhosptime(serviceSubtask1.getInhosptime()); patTaskRelevance.setStarttime(serviceSubtask1.getStarttime()); patTaskRelevance.setDrname(serviceSubtask1.getDrname()); patTaskRelevance.setDrcode(serviceSubtask1.getDrcode()); patTaskRelevance.setEndtime(serviceSubtask1.getEndtime()); patTaskRelevance.setStarttime(serviceSubtask1.getStarttime()); patTaskRelevance.setNurseId(serviceSubtask1.getNurseId()); patTaskRelevance.setNurseName(serviceSubtask1.getNurseName()); patTaskRelevances.add(patTaskRelevance); } //获取该患者所有的执行状态 // List serviceSubtaskPreachformList = serviceSubtaskPreachformLists.stream().filter((item -> item.getSubid().equals(serviceSubtask1.getId()) && item.getTaskid().equals(serviceTask.getTaskid()))).collect(Collectors.toList()); // List> resultList = serviceSubtaskPreachformList.stream().map(item -> { // Map map = new HashMap<>(); // map.put("sort", item.getSort()); // map.put("preachform", item.getPreachform()); // map.put("compensateTime", item.getCompensateTime()); // return map; // }).collect(Collectors.toList()); // serviceTaskVO.setPreachformList(resultList); // String result = resultList.stream().map(mapList1 -> mapList1.get("preachform")).map(String::valueOf).collect(Collectors.joining(",")); // serviceTaskVO.setPreachform(result); } if (StringUtils.isNotEmpty(serviceTaskVO.getPreachformDesc())) { //直接通过PreachformDesc生成List返回 try { List> mapList = objectMapper.readValue(serviceTaskVO.getPreachformDesc(), List.class); serviceTaskVO.setPreachformList(mapList); } catch (Exception e) { } } else { if (CollectionUtils.isNotEmpty(list)) { //获取该患者所有的执行状态 List serviceSubtaskPreachformList = serviceSubtaskPreachformLists.stream().filter((item -> item.getSubid().equals(list.get(0).getId()) && item.getTaskid().equals(serviceTask.getTaskid()))).collect(Collectors.toList()); List> resultList = serviceSubtaskPreachformList.stream().map(item -> { Map map = new HashMap<>(); map.put("sort", item.getSort()); map.put("preachform", item.getPreachform()); map.put("compensateTime", item.getCompensateTime()); return map; }).collect(Collectors.toList()); serviceTaskVO.setPreachformList(resultList); } } serviceTaskVO.setPatTaskRelevances(patTaskRelevances); findServiceTaskScheduleVO(serviceTaskVO); return serviceTaskVO; } @Override public List patItem(ServiceSubtaskEntity serviceSubtaskEntity) { List selectServiceSubtaskList = getServiceSubtasks(serviceSubtaskEntity); List serviceSubtaskResList = new ArrayList<>(); // 同一次请求(列表分页 / 全量导出)里,inhospid 与 patid 高度重复 // (再次随访、同一患者多任务都会指向同一条住院记录/同一份档案)。 // 原来每行都要 2 次单条查询,导出几千行就是几千×2 次往返;这里按 id 做进程内缓存, // 把「每行 2 次」压成「每个不同 id 1 次」,取数语义不变。 Map inhospCache = new HashMap<>(); Map archiveCache = new HashMap<>(); for (ServiceSubtask serviceSubtask : selectServiceSubtaskList) { ServiceSubtaskRes serviceSubtaskRes = DtoConversionUtils.sourceToTarget(serviceSubtask, ServiceSubtaskRes.class); if (ObjectUtils.isNotEmpty(serviceSubtask.getContinueContent())) { serviceSubtaskRes.setContinueContent(serviceSubtask.getContinueContent()); } // 1:待随访(2 待发送);2:随访中(3 已发送、1 被领取)、3:未完成(5 发送失败、7、超时)、4:已完成( 6 已完成)、5:无需随访(4 不执行) if (serviceSubtaskRes.getSendstate() == 1 || serviceSubtaskRes.getSendstate() == 2L || serviceSubtaskRes.getSendstate() == 3L || serviceSubtaskRes.getSendstate() == 5 || serviceSubtaskRes.getSendstate() == 7L) serviceSubtaskRes.setSendstateView(1L); if (serviceSubtaskRes.getSendstate() == 6) serviceSubtaskRes.setSendstateView(2L); if (serviceSubtaskRes.getSendstate() == 4) serviceSubtaskRes.setSendstateView(3L); // 填充当前补偿 if (StringUtils.isEmpty(serviceSubtask.getCurrentPreachform())) { if (StringUtils.isNotEmpty(serviceSubtask.getPreachform())) { //默认取第一个 serviceSubtaskRes.setCurrentPreachform(serviceSubtask.getPreachform().split(",")[0].trim()); } } PatMedInhosp inhosp = loadInhospCached(inhospCache, serviceSubtask.getInhospid()); if (ObjectUtils.isNotEmpty(inhosp)) { PatArchive patArchive = loadArchiveCached(archiveCache, inhosp.getPatid()); if (ObjectUtils.isNotEmpty(patArchive)) { Map stringStringMap = calculateAge(patArchive.getBirthdate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), LocalDate.now()); serviceSubtaskRes.setAge(StringUtils.isNotEmpty(stringStringMap.get("age")) ? Long.valueOf(stringStringMap.get("age")) : null); serviceSubtaskRes.setSex(patArchive.getSex()); serviceSubtaskRes.setSexName(patArchive.getSex() != null ? (patArchive.getSex() == 1 ? "男" : "女") : null); } serviceSubtaskRes.setHospno(inhosp.getInhospno()); serviceSubtaskRes.setPatno(inhosp.getPatno()); } serviceSubtaskResList.add(serviceSubtaskRes); } return serviceSubtaskResList; } /** * 按 inhospid 取住院记录(带进程内缓存)。 *

* 只是把「同一次请求内同一个 id 只查一次」这件事收口,不改变取数语义: * 查不到(null)也会缓存,避免同一批数据里对不存在的 id 反复打库。 * 缓存生命周期 = 单次 {@code patItem} 调用,不跨请求、不共享。 */ private PatMedInhosp loadInhospCached(Map cache, Long inhospid) { if (inhospid == null) { return null; } if (!cache.containsKey(inhospid)) { cache.put(inhospid, inhospVisitFacade.selectPatMedInhospByInhospid(inhospid)); } return cache.get(inhospid); } /** * 按 patid 取患者档案(带进程内缓存),语义同 {@link #loadInhospCached}。 */ private PatArchive loadArchiveCached(Map cache, Long patid) { if (patid == null) { return null; } if (!cache.containsKey(patid)) { cache.put(patid, taskArchivePort.findByPatid(patid)); } return cache.get(patid); } public List getServiceSubtasks(ServiceSubtaskEntity serviceSubtaskEntity) { if (serviceSubtaskEntity.getSendstateView() != null) { // 1:待随访(1 被领取、2 待发送、3 已发送、7 超时;发送失败(5) 单独统计);2:已完成( 6 已完成)、3:无需随访(4 不执行) if (serviceSubtaskEntity.getSendstateView() == 1) serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 7L))); if (serviceSubtaskEntity.getSendstateView() == 2) serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(6L))); if (serviceSubtaskEntity.getSendstateView() == 3) serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(4L))); } //患者获取随访任务-需要查询同个患者(身份证)所有的任务 景宁 if (StringUtils.isNotEmpty(serviceSubtaskEntity.getOrgid()) && serviceSubtaskEntity.getOrgid().equals("47255004333112711A1001")) { if (ObjectUtils.isNotEmpty(serviceSubtaskEntity.getPatid())) { PatArchive patArchive = taskArchivePort.findByPatid(serviceSubtaskEntity.getPatid()); if (ObjectUtils.isNotEmpty(patArchive) && StringUtils.isNotEmpty(patArchive.getIdcardno())) { serviceSubtaskEntity.setPatid(null); serviceSubtaskEntity.setSfzh(patArchive.getIdcardno()); } } } // 分页请求走「两阶段」:先只取当页 id,再按 id 回表。 // 列表 select 约 100 列,深翻页时被 offset 跳过的每一行原本都要回表读整行; // 只取 id 的查询能走覆盖索引并提前截断,代价小得多。 if (serviceSubtaskEntity.getPageNum() != null && serviceSubtaskEntity.getPageSize() != null) { return selectServiceSubtaskPage(serviceSubtaskEntity); } return this.selectServiceSubtaskList(serviceSubtaskEntity); } /** * 两阶段分页:① 只查 id(覆盖索引 + limit offset)② 按 id 回表取整行。 *

* 第二阶段复用 {@code selectServiceSubtaskList} 的 subIdList 条件回表, * 必须把 pageNum/pageSize 摘掉 —— 否则会在「当页 id 集合」上再翻一次页。 *

* 统计缓存(Controller 的 {@code getPatItemCountWithCache})用 ReflectUtils 比对整个 * entity 作为缓存命中条件,{@code subIdList} 参与比对,所以用完必须原样还原, * 否则缓存永远不命中,每次请求都要重算一次聚合。 */ private List selectServiceSubtaskPage(ServiceSubtaskEntity serviceSubtaskEntity) { List pageIds = serviceSubtaskMapper.selectServiceSubtaskIdsPage(serviceSubtaskEntity); if (CollectionUtils.isEmpty(pageIds)) { return new ArrayList<>(); } Integer pageNum = serviceSubtaskEntity.getPageNum(); Integer pageSize = serviceSubtaskEntity.getPageSize(); List originSubIdList = serviceSubtaskEntity.getSubIdList(); serviceSubtaskEntity.setPageNum(null); serviceSubtaskEntity.setPageSize(null); serviceSubtaskEntity.setSubIdList(pageIds); List rows; try { rows = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskEntity); } finally { serviceSubtaskEntity.setPageNum(pageNum); serviceSubtaskEntity.setPageSize(pageSize); serviceSubtaskEntity.setSubIdList(originSubIdList); } if (CollectionUtils.isEmpty(rows)) { return new ArrayList<>(); } // 以第一阶段的 id 顺序为准重排:第二阶段的 order by 只保证「同一页内」有序, // 遇到排序字段值相同的行时相对顺序不一定与第一阶段一致。 Map byId = new HashMap<>(Math.max(16, rows.size() * 2)); for (ServiceSubtask row : rows) { if (row.getId() != null) { byId.put(row.getId(), row); } } List ordered = new ArrayList<>(pageIds.size()); for (Long id : pageIds) { ServiceSubtask row = byId.get(id); if (row != null) { ordered.add(row); } } return ordered; } @Override public Integer transferDept(TransferDeptVO transferDeptVO) { log.info("transferDept的入参为:{}", transferDeptVO); //查询该患者的子任务信息 ServiceSubtask serviceSubtask = serviceSubtaskMapper.selectServiceSubtaskById(transferDeptVO.getSubId()); if (ObjectUtils.isEmpty(serviceSubtask)) throw new BaseException("转患者失败,请联系管理员处理"); //删除该患者的信息通过subid serviceSubtaskMapper.deleteServiceSubtaskById(transferDeptVO.getSubId()); //修改患者的离院科室病区通过inhospid和患者的任务生成状态 PatMedInhosp patMedInhosp = new PatMedInhosp(); patMedInhosp.setInhospid(serviceSubtask.getInhospid()); patMedInhosp.setLeaveldeptcode(transferDeptVO.getLeavelDeptCode()); patMedInhosp.setLeaveldeptname(transferDeptVO.getLeavelDeptName()); patMedInhosp.setLeavehospitaldistrictcode(transferDeptVO.getLeavehospitaldistrictcode()); patMedInhosp.setLeavehospitaldistrictname(transferDeptVO.getLeavehospitaldistrictname()); patMedInhosp.setDeptcheckFlag("0"); patMedInhosp.setWardcheckFlag("0"); patMedInhosp.setDiagcheckFlag("0"); return inhospVisitFacade.updatePatMedInhosp(patMedInhosp); } public Map calculateAge(LocalDate birthdate, LocalDate today) { if (birthdate == null || today.isBefore(birthdate)) { return null; } Map ageMap = new HashMap<>(); Period period = Period.between(birthdate, today); long totalDays = ChronoUnit.DAYS.between(birthdate, today); long totalMonths = ChronoUnit.MONTHS.between(birthdate, today); int years = period.getYears(); int months = period.getMonths(); int days = period.getDays(); String ageUnit; Integer age; String ageUnit2 = null; Integer age2 = null; if (totalDays < 90) { // 小于 1 个月,按天计算 ageUnit = "天"; age = (int) totalDays; ageMap.put("age", age != null ? age.toString() : null); ageMap.put("ageUnit", ageUnit); ageMap.put("age2", null); ageMap.put("ageUnit2", null); } else if (totalMonths < 36) { // 小于 1 年,按月 + 天计算 ageUnit = "月"; age = (int) totalMonths; ageUnit2 = "天"; age2 = days; ageMap.put("age", age != null ? age.toString() : null); ageMap.put("ageUnit", ageUnit); ageMap.put("age2", age2 != null ? age2.toString() : null); ageMap.put("ageUnit2", ageUnit2); } else { // 大于 1 年,按年 + 月计算 ageUnit = "岁"; age = years; ageUnit2 = "月"; age2 = months; ageMap.put("age", age != null ? age.toString() : null); ageMap.put("ageUnit", ageUnit); ageMap.put("age2", age2 != null ? age2.toString() : null); ageMap.put("ageUnit2", ageUnit2); } return ageMap; } @Override public List patItem2(ServiceSubtaskEntity serviceSubtaskEntity) { if (serviceSubtaskEntity.getSendstateView() != null) { // 1:待随访(1 被领取、2 待发送、3 已发送、5 发送失败、7、超时);2:已完成( 6 已完成)、3:无需随访(4 不执行) if (serviceSubtaskEntity.getSendstateView() == 1) serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 7L))); if (serviceSubtaskEntity.getSendstateView() == 2) serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(6L))); if (serviceSubtaskEntity.getSendstateView() == 3) serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(4L))); } List serviceSubtaskList = new ArrayList<>(); if(CollectionUtils.isNotEmpty(serviceSubtaskEntity.getSendstates())){ for (Long sendstate : serviceSubtaskEntity.getSendstates()) { serviceSubtaskEntity.setSendstate(sendstate); List serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskEntity); serviceSubtaskList.addAll(serviceSubtasks); } } return serviceSubtaskList; } // 原方法 // @Override // public Map patItemCount(ServiceSubtaskVO serviceSubtaskVO) { // serviceSubtaskVO.setPageSize(99999999); // serviceSubtaskVO.setPageNum(1); // List selectServiceSubtaskList = this.selectServiceSubtaskList(serviceSubtaskVO); // Map map = new HashMap<>(); // Integer wzx = 0; // Integer ysf = 0; // Integer yc = 0; // Integer fssb = 0; // Integer yfs = 0; // Integer blq = 0; // Integer dsf = 0; // for (ServiceSubtask serviceSubtask : selectServiceSubtaskList) { // if (serviceSubtask.getSendstate() == 4L) wzx = wzx + 1; // else if (serviceSubtask.getSendstate() != 4L && serviceSubtask.getSendstate() != 2L) ysf = ysf + 1; // if (serviceSubtask.getSendstate() == 5L) fssb = fssb + 1; // if (serviceSubtask.getSendstate() >= 3L || serviceSubtask.getSendstate() == 1L) yfs = yfs + 1; // if (serviceSubtask.getSendstate() == 2L) dsf = dsf + 1; // if (serviceSubtask.getSendstate() == 1L) blq = blq + 1; // if (StringUtils.isNotEmpty(serviceSubtask.getExcep()) && !serviceSubtask.getExcep().equals("0")) // yc = yc + 1; // } // // map.put("wzx", wzx); // map.put("ysf", ysf); // map.put("yc", yc); // map.put("fssb", fssb); // map.put("yfs", yfs); // map.put("blq", blq); // map.put("dsf", dsf); // // return map; // } /** * 统计任务各种状态的数量(已优化) * 优化说明: * 1. 使用数据库层聚合计算,替代应用层遍历 * 2. 性能提升 10-100 倍(取决于数据量) * 3. 降低内存占用和网络传输 * * @param serviceSubtaskEntity 查询条件 * @return 各状态统计结果 */ @Override public Map patItemCount(ServiceSubtaskEntity serviceSubtaskEntity) { // 直接调用数据库统计方法,在数据库层完成聚合计算 Map result = serviceSubtaskMapper.countByCondition(serviceSubtaskEntity); // 处理空异常 if (MapUtils.isEmpty(result)) { result = new HashMap<>(); // 确保所有 key 都有值,避免空指针异常 // MyBatis 的 SUM 在没有匹配行时会返回 null result.putIfAbsent("wzx", 0); result.putIfAbsent("ysf", 0); result.putIfAbsent("fssb", 0); result.putIfAbsent("yfs", 0); result.putIfAbsent("blq", 0); result.putIfAbsent("total", 0); result.putIfAbsent("wxsf", 0); result.putIfAbsent("xsf", 0); result.putIfAbsent("dsf", 0); result.putIfAbsent("ywc", 0); result.putIfAbsent("cs", 0); result.putIfAbsent("yc", 0); result.putIfAbsent("jg", 0); } return result; } /** * 统计任务各种状态的数量(已优化) * 优化说明: * 1. 使用数据库层聚合计算,替代应用层遍历 * 2. 性能提升 10-100 倍(取决于数据量) * 3. 降低内存占用和网络传输 * * @param serviceSubtaskEntity 查询条件 * @return 各状态统计结果 */ @Override public Map countByCondition(ServiceSubtaskEntity serviceSubtaskEntity) { // 直接调用数据库统计方法,在数据库层完成聚合计算 Map result = serviceSubtaskMapper.countByCondition(serviceSubtaskEntity); // 处理空异常 if (MapUtils.isEmpty(result)) { result = new HashMap<>(); // 确保所有 key 都有值,避免空指针异常 // MyBatis 的 SUM 在没有匹配行时会返回 null result.putIfAbsent("wzx", 0); result.putIfAbsent("ysf", 0); result.putIfAbsent("fssb", 0); result.putIfAbsent("yfs", 0); result.putIfAbsent("blq", 0); result.putIfAbsent("total", 0); result.putIfAbsent("wxsf", 0); result.putIfAbsent("xsf", 0); result.putIfAbsent("dsf", 0); result.putIfAbsent("dfs", 0); result.putIfAbsent("yfs", 0); result.putIfAbsent("cs", 0); result.putIfAbsent("ywc", 0); result.putIfAbsent("yc", 0); result.putIfAbsent("jg", 0); } return result; } /** * 统一「随访病区」口径:一律以【出院记录】{@code pat_med_inhosp} 为准(2026-10-29 业务确认)。 * *

为什么需要它

* 出院随访子任务的科室/病区本应来自出院记录,但「再次随访 / 手工新增」这两个入口是 * 直接按前端传来的字段落库的:前端不带这些字段时 * {@code leaveldeptcode} / {@code leavehospitaldistrictcode} / {@code campusid} 就是空。 * 而随访列表是按科室/病区过滤的({@code and leavehospitaldistrictcode = #{...}}), * 空值不匹配任何值 → 这些任务"生成了但页面上查不到"(线上 2026-10 实测 314 条)。 * *

口径:病区只认出院记录 —— 不按患者档案反推、也不用前端传的值。 * 只对出院随访({@code service_type='2'})且能定位到出院记录({@code inhospid} 非空)的行生效; * 其余情况原样放行,对满意度(6)/宣教/门诊等其它类型没有任何影响。 * * @param serviceSubtask 待落库的子任务(就地修改) */ private void alignDischargeWardFromInhosp(ServiceSubtask serviceSubtask) { if (serviceSubtask == null || serviceSubtask.getInhospid() == null) { return; } if (!"2".equals(serviceSubtask.getServiceType())) { return; } PatMedInhosp inhosp; try { inhosp = inhospVisitFacade.selectPatMedInhospByInhospid(serviceSubtask.getInhospid()); } catch (Exception e) { log.warn("【随访任务】按 inhospid={} 取出院记录失败,病区沿用入参:{}", serviceSubtask.getInhospid(), e.toString()); return; } if (inhosp == null) { log.warn("【随访任务】inhospid={} 查不到出院记录,病区沿用入参", serviceSubtask.getInhospid()); return; } serviceSubtask.setLeaveldeptcode(inhosp.getLeaveldeptcode()); serviceSubtask.setLeaveldeptname(inhosp.getLeaveldeptname()); serviceSubtask.setLeavehospitaldistrictcode(inhosp.getLeavehospitaldistrictcode()); serviceSubtask.setLeavehospitaldistrictname(inhosp.getLeavehospitaldistrictname()); if (StringUtils.isNotEmpty(inhosp.getCampusid())) { serviceSubtask.setCampusid(inhosp.getCampusid()); } } /** * 新增单一任务(随访) * * @param serviceSubtask 单一任务(随访) * @return 结果 */ @Override public Map insertServiceSubtask(ServiceSubtask serviceSubtask) { List serviceSubtasks = null; //先查询一下该患者是否已经创建根据serviceType,sendstate,inhospid,patid,orgid //这样判断主要是为了想让新华医院的外部导入患者创建任务,也能用这个接口 if (StringUtils.isEmpty(serviceSubtask.getPatfrom()) || !serviceSubtask.getPatfrom().equals("2")) { ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity(); serviceSubtaskVO.setServiceType(serviceSubtask.getServiceType()); serviceSubtaskVO.setInhospid(serviceSubtask.getInhospid()); serviceSubtaskVO.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 7L))); serviceSubtaskVO.setPatid(serviceSubtask.getPatid()); serviceSubtaskVO.setOrgid(serviceSubtask.getOrgid()); serviceSubtaskVO.setCampusid(serviceSubtask.getCampusid()); serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO); } RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample(); String format = null; if (CollectionUtils.isNotEmpty(serviceSubtasks)) { ServiceSubtask serviceSubtask1 = serviceSubtasks.get(0); ServiceOutPath serviceOutPath = new ServiceOutPath(); serviceOutPath.setSubId(serviceSubtask1.getId()); List serviceOutPaths = serviceOutPathMapper.selectServiceOutPathList(serviceOutPath); if (CollectionUtils.isNotEmpty(serviceOutPaths)) format = ShortCode.encode(serviceOutPaths.get(0).getId()); else format = getOutPath(serviceSubtask1, rsaPublicKeyExample); serviceSubtask = serviceSubtask1; } else { //如果不存在,则新增 ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); if (ObjectUtils.isNotEmpty(serviceTask)) { serviceSubtask.setTaskDesc(serviceTask.getTaskDesc()); serviceSubtask.setTaskName(serviceTask.getTaskName()); serviceSubtask.setTemplatename(serviceTask.getTemplatename()); } serviceSubtask.setCreateTime(DateUtils.getNowDate()); // 口径(2026-10-29 业务确认):出院随访的科室/病区一律以出院记录为准 alignDischargeWardFromInhosp(serviceSubtask); serviceSubtaskMapper.insertServiceSubtask(serviceSubtask); //修改住院满意度状态(避免重复查询) if (serviceSubtask.getServiceType() != null && "6".equals(serviceSubtask.getServiceType())) { Long inhospid = serviceSubtask.getInhospid(); if (inhospid != null) { PatMedInhosp patMedInhosp = new PatMedInhosp(); patMedInhosp.setInhospMydFlag("1"); patMedInhosp.setInhospid(inhospid); inhospVisitFacade.updatePatMedInhosp(patMedInhosp); } } format = getOutPath(serviceSubtask, rsaPublicKeyExample); } Map result = new HashMap<>(); if (StringUtils.isNotEmpty(format)) result.put("url", StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format); else result.put("url", null); result.put("subId", serviceSubtask.getId()); return result; } private String getOutPath(ServiceSubtask serviceSubtask, RSAPublicKeyExample rsaPublicKeyExample) { String format; String taskId = rsaPublicKeyExample.encryptedData(serviceSubtask.getTaskid().toString(), pub_key); String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key); String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key); ServiceOutPath serviceOutPath = new ServiceOutPath(); serviceOutPath.setParam1(taskId); serviceOutPath.setParam2(patid); serviceOutPath.setCreateTime(new Date()); serviceOutPath.setParam6(subId); serviceOutPath.setOrgid(serviceSubtask.getOrgid()); serviceOutPath.setTaskId(serviceSubtask.getTaskid()); serviceOutPath.setSubId(serviceSubtask.getId()); iServiceOutPathService.insertServiceOutPath(serviceOutPath); //转成16进制 format = ShortCode.encode(serviceOutPath.getId()); serviceOutPath.setRadix(format); serviceOutPath.setUpdateTime(new Date()); iServiceOutPathService.updateServiceOutPath(serviceOutPath); return format; } /** * 再次新增单一任务(随访) * * @param serviceSubtask 再次新增单一任务(随访) * @return 结果 */ @Override @Transactional(rollbackFor = Exception.class) public String addSubTaskAgain(ServiceSubtask serviceSubtask) { ServiceSubtask serviceSubtask1 = selectServiceSubtaskById(serviceSubtask.getId()); PatMedInhosp patMedInhosp = new PatMedInhosp(); patMedInhosp.setPatid(serviceSubtask1.getPatid()); patMedInhosp.setInhospstate("0"); List patMedInhospList = inhospVisitFacade.selectPatMedInhospList(patMedInhosp); PatArchive patArchive = taskArchivePort.findByPatid(serviceSubtask1.getPatid()); //景宁 新增再次随访不能触发患者再入院 boolean inhospAgain = true; if ("47255004333112711A1001".equals(serviceSubtask1.getOrgid())) { inhospAgain = false; } if (patMedInhospList.size() > 0 && inhospAgain) { serviceSubtask1.setIsVisitAgain(2); serviceSubtask1.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + ";患者再入院了" : "患者再入院了"); serviceSubtask1.setSendstate(4L); serviceSubtaskMapper.updateServiceSubtask(serviceSubtask1); return "无需再次随访,患者再入院了"; } else if (serviceSubtask1.getSendstate() == 4L) { serviceSubtask1.setIsVisitAgain(2); serviceSubtask1.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + ";无需再次随访,任务被标记不在执行" : "无需再次随访,任务被标记不在执行"); serviceSubtaskMapper.updateServiceSubtask(serviceSubtask1); return "无需再次随访,任务被标记不在执行"; } else if (patArchive != null && StringUtils.isNotEmpty(patArchive.getNotrequiredFlag()) && patArchive.getNotrequiredFlag().equals("1")) { serviceSubtask1.setIsVisitAgain(2); serviceSubtaskMapper.updateServiceSubtask(serviceSubtask1); serviceSubtask1.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + ";无需再次随访,患者被标记不需要被服务" : "无需再次随访,患者被标记不需要被服务"); return "无需再次随访,患者被标记不需要被服务"; } else if (ObjectUtils.isNotEmpty(serviceSubtask1.getIsVisitAgain()) && serviceSubtask1.getIsVisitAgain() == 2) { return "无需再次随访,该任务已经再次随访过了"; } //丽水中医院根据下次任务ID生成再次随访 if ("47231022633110211A2101".equals(serviceSubtask1.getOrgid())) { return addSubTaskAgainNextTaskId(serviceSubtask1, serviceSubtask); } //新增再次随访任务 ServiceSubtask serviceSubtask2 = DtoConversionUtils.sourceToTarget(serviceSubtask, ServiceSubtask.class); serviceSubtask2.setId(null); serviceSubtask2.setUpid(serviceSubtask1.getId().intValue()); serviceSubtask2.setVisitCount(serviceSubtask1.getVisitCount() + 1); serviceSubtask2.setSendstate(2L); serviceSubtask2.setCreateTime(new Date()); serviceSubtask2.setUpdateTime(new Date()); serviceSubtask2.setVisitType(serviceSubtask.getVisitType()); serviceSubtask2.setVisitDeptCode(serviceSubtask.getVisitDeptCode()); serviceSubtask2.setVisitDeptName(serviceSubtask.getVisitDeptName()); // 口径(2026-10-29 业务确认):随访病区一律取出院记录的 // ① 再次随访是从请求 DTO 复制出来的,出院记录ID 不在请求里 → 先用原任务的上; // ② 再按出院记录把科室/病区/院区统一过来(取不到就保持不变)。 if (serviceSubtask2.getInhospid() == null) { serviceSubtask2.setInhospid(serviceSubtask1.getInhospid()); } alignDischargeWardFromInhosp(serviceSubtask2); int i = serviceSubtaskMapper.insertServiceSubtask(serviceSubtask2); if (i == 1) { //新增成功后,需要将之前的任务设置为不要再随访(防止重复点,然后重复生成) serviceSubtask1.setIsVisitAgain(2); serviceSubtaskMapper.updateServiceSubtask(serviceSubtask1); return "再次随访任务创建成功"; } return "再次随访任务创建失败,再请次重试"; } public String addSubTaskAgainNextTaskId(ServiceSubtask serviceSubtask, ServiceSubtask request) { if (ObjectUtils.isEmpty(serviceSubtask.getTaskid())) { log.error("再次随访任务创建失败,缺少TaskId, 再请次重试"); return "再次随访任务创建失败,缺少TaskId, 再请次重试"; } // 同一原任务串行生成,防止并发重复插入 String lockToken = tryLockAgainTask(serviceSubtask.getId()); if (lockToken == null) { return "再次随访任务正在创建中,请勿重复提交"; } try { ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); if (ObjectUtils.isEmpty(serviceTask)) { log.error("再次随访任务创建失败,找不到对应任务 taskid = {}, 再请次重试", serviceSubtask.getTaskid()); return "再次随访任务创建失败,找不到对应任务 taskid = " + serviceSubtask.getTaskid() + ", 再请次重试"; } // nexttaskflag=0 表示任务链终止,不允许再生成 // if ("0".equals(serviceTask.getNexttaskflag())) { // log.info("无需再次随访,任务已标记无后续随访, taskid = {}", serviceSubtask.getTaskid()); // return "无需再次随访,该任务无后续随访安排"; // } // 幂等校验:同一原任务只允许生成一条二次随访 ServiceSubtaskEntity againQuery = new ServiceSubtaskEntity(); againQuery.setUpid(serviceSubtask.getId().intValue()); if (CollectionUtils.isNotEmpty(serviceSubtaskMapper.selectServiceSubtaskList(againQuery))) { return "无需再次随访,该任务已经再次随访过了"; } // 查询出院记录 PatMedInhosp patMedInhospVo = new PatMedInhosp(); patMedInhospVo.setOrgid(serviceSubtask.getOrgid()); patMedInhospVo.setInhospid(serviceSubtask.getInhospid()); patMedInhospVo.setCry(1); List patMedInhospList = inhospVisitFacade.selectPatMedInhospList(patMedInhospVo); PatMedInhosp patMedInhosp = new PatMedInhosp(); if (CollectionUtils.isNotEmpty(patMedInhospList)) { patMedInhosp = patMedInhospList.get(0); } else { log.error("再次随访任务创建失败,任务缺少 对应的出院记录, taskid = {}, 再请次重试", serviceSubtask.getTaskid()); return "再次随访任务创建失败,任务缺少 对应的出院记录, taskid = " + serviceSubtask.getTaskid() + ", 再请次重试"; } // 未配置 nexttaskid 时复用当前任务配置,防止历史任务直接失败 Long nexttaskid = serviceTask.getNexttaskid(); if (ObjectUtils.isEmpty(nexttaskid) || Long.valueOf(0L).equals(nexttaskid)) { nexttaskid = serviceTask.getTaskid(); log.warn("再次随访任务未配置 nexttaskid,按当前任务配置生成, taskid = {}", nexttaskid); } ServiceTask nextServiceTask = serviceTaskService.selectServiceTaskByTaskid(nexttaskid); if (ObjectUtils.isEmpty(nextServiceTask)) { log.error("再次随访任务创建失败,找不到对应任务 nexttaskid = {}, 再请次重试", nexttaskid); return "再次随访任务创建失败,找不到对应任务 nexttaskid = " + nexttaskid + ", 再请次重试"; } PatArchive patArchive = taskArchivePort.findByPatid(serviceSubtask.getPatid()); if (ObjectUtils.isEmpty(patArchive)) { log.error("再次随访任务创建失败,未找到患者档案 patid = {}, subTaskId = {}", serviceSubtask.getPatid(), serviceSubtask.getId()); return "再次随访任务创建失败,未找到患者档案, subTaskId = " + serviceSubtask.getId() + ", 再请次重试"; } String config = sysConfigService.selectConfigByKey("visit.early.day"); Integer type = 1; String resource = resolveAgainResource(request); if (StringUtils.isEmpty(resource)) { String requestResource = request == null ? null : request.getResource(); log.error("再次随访任务创建失败,再次随访方式不合法, resource = {}, subTaskId = {}", requestResource, serviceSubtask.getId()); return "再次随访任务创建失败,再次随访方式不合法, resource = " + requestResource + ", 再请次重试"; } String visitDeptCode; String visitDeptName; if ("1".equals(resource)) { // 本科室随访:请求科室优先,未传时使用原任务出院科室;不依赖原任务 visitType String requestDeptCode = firstNonBlank(request == null ? null : request.getVisitDeptCode()); String requestDeptName = firstNonBlank(request == null ? null : request.getVisitDeptName()); if (StringUtils.isNotEmpty(requestDeptCode)) { visitDeptCode = requestDeptCode; visitDeptName = requestDeptName; } else { // 出院科室:service_subtask 里对应的是 leaveldeptcode(deptcode 已改为在院科室) visitDeptCode = serviceSubtask.getLeaveldeptcode(); visitDeptName = serviceSubtask.getLeaveldeptname(); } if (StringUtils.isEmpty(visitDeptCode)) { log.error("再次随访任务创建失败,本科室随访未找到随访科室, subTaskId = {}", serviceSubtask.getId()); return "再次随访任务创建失败,本科室随访未找到随访科室, subTaskId = " + serviceSubtask.getId() + ", 再请次重试"; } SysDept ownDept = selectDeptByCode(serviceSubtask.getOrgid(), visitDeptCode); if (ObjectUtils.isNotEmpty(ownDept)) { visitDeptCode = ownDept.getDeptCode(); visitDeptName = ownDept.getDeptName(); } else if (StringUtils.isNotEmpty(requestDeptCode) || StringUtils.isEmpty(visitDeptName)) { log.error("再次随访任务创建失败,本科室随访科室不存在, deptCode = {}, subTaskId = {}", visitDeptCode, serviceSubtask.getId()); return "再次随访任务创建失败,本科室随访科室不存在, deptCode = " + visitDeptCode + ", 再请次重试"; } } else { // 随访中心科室随访 String centerDept = sysConfigService.selectConfigByKey("sys.smartor.center.dept", serviceSubtask.getOrgid()); if (ObjectUtils.isEmpty(centerDept)) { log.error("再次随访任务创建失败,未配置随访中心科室参数 sys.smartor.center.dept ,subTaskId = {}, 再请次重试", serviceSubtask.getId()); return "再次随访任务创建失败,未配置随访中心科室参数 sys.smartor.center.dept ,subTaskId = " + serviceSubtask.getId() + ", 再请次重试"; } SysDept sysDeptVo = new SysDept(); sysDeptVo.setDeptType("1"); sysDeptVo.setOrgid(serviceSubtask.getOrgid()); sysDeptVo.setDeptCode(centerDept); List sysDepts = sysDeptService.selectDeptList(sysDeptVo); SysDept sysDept = new SysDept(); if (CollectionUtils.isNotEmpty(sysDepts)) { sysDept = sysDepts.get(0); } else { log.error("再次随访任务创建失败,未找到参数 sys.smartor.center.dept 配置的随访中心科室 deptCode = {}, 再请次重试", centerDept); return "再次随访任务创建失败,未找到参数 sys.smartor.center.dept 配置的随访中心科室 deptCode = " + centerDept + ", 再请次重试"; } visitDeptCode = sysDept.getDeptCode(); visitDeptName = sysDept.getDeptName(); } // 按下一任务生成二次随访子任务(表单、发送方式取自下一任务); // 组装逻辑已在本模块的 OperationSubtaskWriter 里(原 IPatMedInhospService#boxedServiceSubtask),这里直接复用 ServiceSubtask serviceSubtaskAgain = operationSubtaskWriter.boxedServiceSubtask(nextServiceTask, patMedInhosp, patArchive, config, type); if (ObjectUtils.isEmpty(serviceSubtaskAgain) || ObjectUtils.isEmpty(serviceSubtaskAgain.getTaskid())) { log.error("再次随访任务创建失败,下一任务生成子任务为空, subTaskId = {}, nextTaskId = {}", serviceSubtask.getId(), nexttaskid); return "再次随访任务创建失败,患者出院记录不完整或下一任务配置异常, 再请次重试"; } Date now = new Date(); applyAgainVisitTime(serviceSubtaskAgain, serviceSubtask, nextServiceTask, config, now); // 医生处理意见取自本次请求,按下一任务重建子任务时需显式带入,否则不会落库 if (request != null) { serviceSubtaskAgain.setDoctorOpinion(request.getDoctorOpinion()); serviceSubtaskAgain.setRemark(request.getRemark()); serviceSubtaskAgain.setDrcode(request.getDrcode()); serviceSubtaskAgain.setDrname(request.getDrname()); serviceSubtaskAgain.setNurseId(request.getNurseId()); serviceSubtaskAgain.setNurseName(request.getNurseName()); serviceSubtaskAgain.setManagementDoctor(request.getManagementDoctor()); serviceSubtaskAgain.setManagementDoctorCode(request.getManagementDoctorCode()); } serviceSubtaskAgain.setId(null); serviceSubtaskAgain.setUpid(serviceSubtask.getId().intValue()); serviceSubtaskAgain.setVisitCount(ObjectUtils.isNotEmpty(serviceSubtask.getVisitCount()) ? serviceSubtask.getVisitCount() + 1 : 2); serviceSubtaskAgain.setSendstate(2L); serviceSubtaskAgain.setIsVisitAgain(1); serviceSubtaskAgain.setCreateTime(now); serviceSubtaskAgain.setUpdateTime(now); // 新任务的随访方式记录本次选择的再次随访方式;resource 本身不落库 serviceSubtaskAgain.setVisitType(resource); serviceSubtaskAgain.setVisitDeptCode(visitDeptCode); serviceSubtaskAgain.setVisitDeptName(visitDeptName); int i = serviceSubtaskMapper.insertServiceSubtask(serviceSubtaskAgain); if (i != 1) { return "再次随访任务创建失败,再请次重试"; } // 初始化发送方式明细,补偿(compensateTask)和超时判断依赖该表 addServiceSubtaskPreachform(serviceSubtaskAgain, null); // 条件更新原任务:0 行说明已被其他请求生成,抛异常回滚本次插入的重复数据 int updated = serviceSubtaskMapper.updateIsVisitAgainById(serviceSubtask.getId(), 2); if (updated != 1) { throw new BaseException("无需再次随访,该任务已经再次随访过了"); } return "再次随访任务创建成功"; } finally { unlockAgainTask(serviceSubtask.getId(), lockToken); } } /** * 解析再次随访方式:仅取请求参数 resource,不使用原任务 visitType;未传时默认随访中心。 * * @return 1-本科室随访;2-随访中心随访;null-非法值 */ private String resolveAgainResource(ServiceSubtask request) { String resource = request == null ? null : request.getResource(); if (StringUtils.isEmpty(resource) || StringUtils.isEmpty(resource.trim())) { return "2"; } resource = resource.trim(); return ("1".equals(resource) || "2".equals(resource)) ? resource : null; } private String firstNonBlank(String... values) { if (values == null) { return null; } for (String value : values) { if (StringUtils.isNotEmpty(value) && StringUtils.isNotEmpty(value.trim())) { return value.trim(); } } return null; } /** * 按 orgid + deptCode 查询启用科室,查不到返回 null。 */ private SysDept selectDeptByCode(String orgid, String deptCode) { if (StringUtils.isEmpty(orgid) || StringUtils.isEmpty(deptCode)) { return null; } SysDept query = new SysDept(); query.setDeptType("1"); query.setOrgid(orgid); query.setDeptCode(deptCode); List deptList = sysDeptService.selectDeptList(query); return CollectionUtils.isEmpty(deptList) ? null : deptList.get(0); } /** * 二次随访时间:首次随访完成时间(未完成取当前时间)+ 下一任务发送天数,过去时间兜底为当前时间。 * 通知类任务按 visit.early.day 提前发送。 */ private void applyAgainVisitTime(ServiceSubtask target, ServiceSubtask origin, ServiceTask nextTask, String earlyDayConfig, Date now) { if (target == null || origin == null || nextTask == null || now == null) { return; } Date baseTime = ObjectUtils.isNotEmpty(origin.getFinishtime()) ? origin.getFinishtime() : now; int intervalDays = ObjectUtils.isNotEmpty(nextTask.getSendDay()) ? nextTask.getSendDay().intValue() : 0; Date dueTime = addDays(baseTime, intervalDays); if (dueTime.before(now)) { dueTime = now; } if(ObjectUtils.isNotEmpty(origin.getVisitTime())){ dueTime = ObjectUtils.isNotEmpty(origin.getVisitTime()) ? origin.getVisitTime() : now; } target.setLongSendTime(dueTime); Date visitTime = dueTime; if ("3".equals(nextTask.getType())) { visitTime = addDays(dueTime, -parseIntConfig(earlyDayConfig)); if (visitTime.before(now)) { visitTime = now; } } target.setVisitTime(visitTime); } private int parseIntConfig(String value) { if (StringUtils.isEmpty(value)) { return 0; } try { return Integer.parseInt(value.trim()); } catch (NumberFormatException e) { log.warn("配置值不是合法整数,按0处理, value={}", value); return 0; } } /** * 日期加减天数(days 可为负)。 *

* 说明:本模块其它地方用的是 {@code DateUtils.addDays},但 ruoyi-common 的 DateUtils 并未提供该方法, * 这里是二次随访时间计算自带的私有实现,避免依赖不存在的工具方法。 */ private Date addDays(Date date, int days) { if (date == null) { return null; } Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.DAY_OF_MONTH, days); return calendar.getTime(); } /** * 首次随访任务超时后,按下一任务自动生成再次随访任务。 *

* 定时任务入口 {@code RyTask#dealSubtaskDeadline} 使用。与手动入口一致的部分: * 表单/发送方式取下一任务、链路 upid + visit_count、发送方式明细初始化; * 差异:超时再次随访固定走随访中心科室(随访中心未配置时回退原任务科室),原任务置为发送失败(sendstate=5)。 *

* 幂等:同一原任务只允许生成一条再次随访(Redis 锁 + upid 校验 + 原任务条件更新), * 多节点/多线程同时扫描时,后到的事务会在条件更新处拿到 0 行并回滚本次插入。 * * @param serviceSubtask 已超时的首次随访子任务 * @return 结果描述 */ @Override @Transactional(rollbackFor = Exception.class) public String addSubTaskAgainByDeadline(ServiceSubtask serviceSubtask) { if (ObjectUtils.isEmpty(serviceSubtask) || ObjectUtils.isEmpty(serviceSubtask.getId())) { return "再次随访任务创建失败,原任务不存在"; } String lockToken = tryLockAgainTask(serviceSubtask.getId()); if (lockToken == null) { return "再次随访任务正在创建中,请勿重复提交"; } try { // 幂等校验:同一原任务只允许生成一条再次随访 ServiceSubtaskEntity againQuery = new ServiceSubtaskEntity(); againQuery.setUpid(serviceSubtask.getId().intValue()); if (CollectionUtils.isNotEmpty(serviceSubtaskMapper.selectServiceSubtaskList(againQuery))) { return "无需再次随访,该任务已经再次随访过了"; } // 原任务已被标记为不再随访(手动入口写过 is_visit_again=2) if (ObjectUtils.isNotEmpty(serviceSubtask.getIsVisitAgain()) && serviceSubtask.getIsVisitAgain() == 2) { return "无需再次随访,该任务已经再次随访过了"; } ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); if (ObjectUtils.isEmpty(serviceTask)) { return "再次随访任务创建失败,找不到对应任务 taskid = " + serviceSubtask.getTaskid(); } if ("0".equals(serviceTask.getNexttaskflag())) { return "无需再次随访,该任务无后续随访安排"; } if (ObjectUtils.isEmpty(serviceTask.getNexttaskid())) { return "再次随访任务创建失败,任务缺少 nexttaskid, taskid = " + serviceSubtask.getTaskid(); } ServiceTask nextServiceTask = serviceTaskService.selectServiceTaskByTaskid(serviceTask.getNexttaskid()); if (ObjectUtils.isEmpty(nextServiceTask)) { return "再次随访任务创建失败,找不到对应任务 nexttaskid = " + serviceTask.getNexttaskid(); } PatMedInhosp patMedInhosp = selectOutHospRecord(serviceSubtask); if (ObjectUtils.isEmpty(patMedInhosp)) { return "再次随访任务创建失败,任务缺少对应的出院记录, taskid = " + serviceSubtask.getTaskid(); } PatArchive patArchive = taskArchivePort.findByPatid(serviceSubtask.getPatid()); if (ObjectUtils.isEmpty(patArchive)) { return "再次随访任务创建失败,未找到患者档案, subTaskId = " + serviceSubtask.getId(); } String config = sysConfigService.selectConfigByKey("visit.early.day"); String visitDeptCode; String visitDeptName; // 随访中心科室:未配置(或科室不存在)时回退原任务科室,保持超时入口原有行为 SysDept centerDept = selectCenterDept(serviceSubtask.getOrgid()); if (ObjectUtils.isNotEmpty(centerDept)) { visitDeptCode = centerDept.getDeptCode(); visitDeptName = centerDept.getDeptName(); } else { String fallbackDeptCode = firstNonBlank(serviceSubtask.getVisitDeptCode()); if (StringUtils.isNotEmpty(fallbackDeptCode)) { visitDeptCode = fallbackDeptCode; visitDeptName = serviceSubtask.getVisitDeptName(); } else { // 出院科室:service_subtask 里对应的是 leaveldeptcode(deptcode 已改为在院科室) visitDeptCode = serviceSubtask.getLeaveldeptcode(); visitDeptName = serviceSubtask.getLeaveldeptname(); } } // 组装逻辑复用本模块 OperationSubtaskWriter(原 IPatMedInhospService#boxedServiceSubtask) ServiceSubtask serviceSubtaskAgain = operationSubtaskWriter.boxedServiceSubtask(nextServiceTask, patMedInhosp, patArchive, config, 1); if (ObjectUtils.isEmpty(serviceSubtaskAgain) || ObjectUtils.isEmpty(serviceSubtaskAgain.getTaskid())) { return "再次随访任务创建失败,患者出院记录不完整或下一任务配置异常, subTaskId = " + serviceSubtask.getId(); } Date now = new Date(); serviceSubtaskAgain.setId(null); serviceSubtaskAgain.setUpid(serviceSubtask.getId().intValue()); serviceSubtaskAgain.setVisitCount(ObjectUtils.isNotEmpty(serviceSubtask.getVisitCount()) ? serviceSubtask.getVisitCount() + 1 : 2); serviceSubtaskAgain.setSendstate(2L); serviceSubtaskAgain.setIsVisitAgain(1); serviceSubtaskAgain.setCreateTime(now); serviceSubtaskAgain.setUpdateTime(now); // 超时再次随访固定为随访中心随访 serviceSubtaskAgain.setVisitType("2"); serviceSubtaskAgain.setVisitDeptCode(visitDeptCode); serviceSubtaskAgain.setVisitDeptName(visitDeptName); if (serviceSubtaskMapper.insertServiceSubtask(serviceSubtaskAgain) != 1) { return "再次随访任务创建失败,再请次重试"; } // 初始化发送方式明细,补偿(compensateTask)和超时判断依赖该表 addServiceSubtaskPreachform(serviceSubtaskAgain, null); // 条件更新原任务:0 行说明已被其他请求生成,抛异常回滚本次插入的重复数据 if (serviceSubtaskMapper.updateIsVisitAgainById(serviceSubtask.getId(), 2) != 1) { throw new BaseException("无需再次随访,该任务已经再次随访过了"); } // 原任务超时,置为发送失败 ServiceSubtask originUpdate = new ServiceSubtask(); originUpdate.setId(serviceSubtask.getId()); originUpdate.setSendstate(5L); originUpdate.setUpdateTime(now); serviceSubtaskMapper.updateServiceSubtask(originUpdate); return "再次随访任务创建成功"; } finally { unlockAgainTask(serviceSubtask.getId(), lockToken); } } /** * 按 orgid + inhospid 取出院记录(超时再次随访用)。 */ private PatMedInhosp selectOutHospRecord(ServiceSubtask serviceSubtask) { PatMedInhosp patMedInhospVo = new PatMedInhosp(); patMedInhospVo.setOrgid(serviceSubtask.getOrgid()); patMedInhospVo.setInhospid(serviceSubtask.getInhospid()); patMedInhospVo.setCry(1); List patMedInhospList = inhospVisitFacade.selectPatMedInhospList(patMedInhospVo); if (CollectionUtils.isEmpty(patMedInhospList)) { return null; } return patMedInhospList.get(0); } /** * 取随访中心科室,未配置或科室不存在时返回 null(由调用方回退原任务科室)。 */ private SysDept selectCenterDept(String orgid) { String centerDept = sysConfigService.selectConfigByKey("sys.smartor.center.dept", orgid); if (StringUtils.isEmpty(centerDept)) { return null; } SysDept sysDeptVo = new SysDept(); sysDeptVo.setDeptType("1"); sysDeptVo.setOrgid(orgid); sysDeptVo.setDeptCode(centerDept); // 定时任务线程没有登录上下文,不能调用带 @DataScope 的 selectDeptList,否则会抛“获取用户信息异常”。 List sysDepts = sysDeptService.selectSysDeptList(sysDeptVo); return CollectionUtils.isEmpty(sysDepts) ? null : sysDepts.get(0); } /** * 获取二次随访生成锁。Redis 异常时降级为数据库幂等校验,不阻断业务。 */ private String tryLockAgainTask(Long subId) { String token = UUID.randomUUID().toString(); try { Boolean locked = redisCache.setCacheObjectIfAbsent( AGAIN_LOCK_KEY_PREFIX + subId, token, AGAIN_LOCK_SECONDS, TimeUnit.SECONDS); return Boolean.TRUE.equals(locked) ? token : null; } catch (Exception e) { log.warn("再次随访获取Redis锁失败,降级使用数据库幂等校验, subId={}", subId, e); return token; } } /** * 释放二次随访生成锁,仅释放自己持有的锁。 */ private void unlockAgainTask(Long subId, String token) { if (token == null) { return; } try { String lockKey = AGAIN_LOCK_KEY_PREFIX + subId; Object current = redisCache.getCacheObject(lockKey); if (token.equals(current)) { redisCache.deleteObject(lockKey); } } catch (Exception e) { log.warn("再次随访释放Redis锁失败, subId={}", subId, e); } } /** * 按任务的 preachformDesc 初始化发送方式明细(service_subtask_preachform)。 *

* 迁移说明:原实现是 smartor 侧 {@code IPatMedInhospService#addServiceSubtaskPreachform}, * 读写的两张表都属于本模块,故按模块边界搬到这里,语义保持一致: * 先按 subid+preachform 查重(已存在就不新增),sendstate 默认为 "1"(传参可覆盖)。 * * @param serviceSubtask 已落库的子任务 * @param sendstate 发送状态覆盖值,为空则用 "1" * @return 固定返回 0(与原实现一致) */ private Integer addServiceSubtaskPreachform(ServiceSubtask serviceSubtask, String sendstate) { ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); if (serviceTask == null) { log.error("addServiceSubtaskPreachform taskid={} 查不到任务,跳过preachform子表生成", serviceSubtask.getTaskid()); return 0; } String preachformDesc = serviceTask.getPreachformDesc(); if (StringUtils.isEmpty(preachformDesc)) { return 0; } List preachformList; try { preachformList = JSON.parseArray(preachformDesc, ServiceSubtaskPreachform.class); } catch (Exception e) { log.error("preachform转List报错了:{}", e.getMessage()); return 0; } if (CollectionUtils.isEmpty(preachformList)) { log.error("preachformDesc解析后为空,跳过preachform子表生成,taskid为:{},preachformDesc为:{}", serviceSubtask.getTaskid(), preachformDesc); return 0; } for (ServiceSubtaskPreachform serviceSubtaskPreachform : preachformList) { serviceSubtaskPreachform.setTaskid(serviceSubtask.getTaskid()); serviceSubtaskPreachform.setSubid(serviceSubtask.getId()); //先查询一下,是否存在,如果已经存在,就不新增了 if (CollectionUtils.isNotEmpty(taskPreachformPort.selectServiceSubtaskPreachformList(serviceSubtaskPreachform))) { continue; } serviceSubtaskPreachform.setSendstate(StringUtils.isNotEmpty(sendstate) ? sendstate : "1"); serviceSubtaskPreachform.setOrgid(serviceSubtask.getOrgid()); taskPreachformPort.insertServiceSubtaskPreachform(serviceSubtaskPreachform); } return 0; } /** * 修改单一任务(随访) * * @param serviceSubtask 单一任务(随访) * @return 结果 */ @Override public Boolean updateServiceSubtask(ServiceSubtask serviceSubtask) { serviceSubtask.setUpdateTime(DateUtils.getNowDate()); if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 6) serviceSubtask.setFinishtime(new Date()); return serviceSubtaskMapper.updateServiceSubtask(serviceSubtask); } @Override public Boolean updateTemplate(ServiceSubtaskTemplateVO serviceSubtaskTemplateVO) { ServiceSubtask serviceSubtask = serviceSubtaskMapper.selectServiceSubtaskById(serviceSubtaskTemplateVO.getSubId()); if (serviceSubtask == null || serviceSubtask.getSendstate() != 2L) throw new BaseException("该任务已发送给患者,不能再进行修改模板"); serviceSubtaskTemplateVO.getSvyTaskTemplateVO().setIntroduce("该问卷是替换后的问题,替换前的问题是:" + serviceSubtask.getTemplateid()); Integer taskTempid = svyTaskTemplateService.saveOrUpdateTemplate(serviceSubtaskTemplateVO.getSvyTaskTemplateVO()); if (taskTempid == null) return false; //每次都新建一个也可以,但新建之后要把之前的删除 if (serviceSubtask.getType().equals("2")) { svyTaskTemplateService.deleteSvyTaskTemplateBySvyid(serviceSubtask.getTemplateid()); } else if (serviceSubtask.getType().equals("1")) ivrTaskTemplateService.deleteIvrTaskTemplateByID(serviceSubtask.getTemplateid()); String tempName = svyTaskTemplateService.selectSvyTaskTemplateBySvyid(Long.valueOf(taskTempid)).getSvyname(); serviceSubtask.setTemplateid(taskTempid.longValue()); serviceSubtask.setTemplatename(tempName); serviceSubtask.setUpdateBy(serviceSubtaskTemplateVO.getUpdateBy()); serviceSubtask.setLibtemplateid(serviceSubtaskTemplateVO.getSvyTaskTemplateVO().getTemplateid()); return updateServiceSubtask(serviceSubtask); } /** * 批量删除单一任务(随访) * * @return 结果 */ @Override public int deleteServiceSubtaskByIds(Long[] ids) { Integer i = 0; for (Long id : ids) { i = serviceSubtaskMapper.deleteServiceSubtaskById(id); } return i; } /** * 科室编码去重,保持原顺序,避免 service_task.deptcode 超长和 service_taskdept 重复绑定 */ private String normalizeDeptCodes(String deptCodes) { if (StringUtils.isEmpty(deptCodes)) { return deptCodes; } return Arrays.stream(deptCodes.split(",")) .map(String::trim) .filter(code -> StringUtils.isNotEmpty(code)) .distinct() .collect(Collectors.joining(",")); } /** * 取逗号串里的第一个值(任务上科室/病区是多选,而 {@code service_subtask} 上都是单值列)。 */ private String firstValue(String value) { if (StringUtils.isEmpty(value)) { return null; } for (String item : value.split(",")) { if (StringUtils.isNotEmpty(item.trim())) { return item.trim(); } } return null; } /** * 任务配置({@link ServiceTaskVO})→ 子任务({@link ServiceSubtask})的字段搬运。 *

* 为什么不能直接 {@code DtoConversionUtils.sourceToTarget(serviceTaskVO, ServiceSubtask.class)}: * 它是纯同名拷贝,而两边同名的 {@code deptcode / deptname} 语义不同: *

* 于是纯同名拷贝会把「离院科室」写进「在院科室」列,后果有两个: *
    *
  1. 按在院维度筛({@code deptcodes} → {@code service_subtask.deptcode})会误命中这些子任务;
  2. *
  3. 按离院维度筛({@code leaveldeptcodes} → {@code service_subtask.leaveldeptcode})时, * 患者自己没带科室的那些(前端手动勾选患者很常见)会因为 {@code leaveldeptcode} 为空而查不到。
  4. *
* 因此这里按项目既定口径({@code doc/service_subtask_字段改名_改动清单.md} §8:这几条 * 「长期任务 / 任务组 / 手动建任务」路径不填在院维度)统一处理: * 在院维度 4 列清空(在院科室/在院病区只有 HIS 链路能从 {@code pat_med_inhosp} 拿到), * 科室 / 病区一律落离院维度({@code leaveldeptcode/name}、{@code leavehospitaldistrictcode/name})。 * * @param serviceTaskVO 建任务入参 * @return 已按离院维度归位的子任务对象(在院维度为空) */ private ServiceSubtask toSubtaskFromTaskVO(ServiceTaskVO serviceTaskVO) { ServiceSubtask serviceSubtask = DtoConversionUtils.sourceToTarget(serviceTaskVO, ServiceSubtask.class); // ① 在院维度必须清空:任务配置的科室不是患者本人的在院科室 serviceSubtask.setDeptcode(null); serviceSubtask.setDeptname(null); serviceSubtask.setHospitaldistrictcode(null); serviceSubtask.setHospitaldistrictname(null); // ② 科室 / 病区 → 离院维度(多选串取第一个,子任务是单值列) serviceSubtask.setLeaveldeptcode(firstValue(serviceTaskVO.getDeptcode())); serviceSubtask.setLeaveldeptname(firstValue(serviceTaskVO.getDeptname())); serviceSubtask.setLeavehospitaldistrictcode(firstValue(serviceTaskVO.getLeavehospitaldistrictcode())); serviceSubtask.setLeavehospitaldistrictname(firstValue(serviceTaskVO.getLeavehospitaldistrictname())); return serviceSubtask; } /** * 单一任务 * * @return 结果 */ @Transactional(rollbackFor = Exception.class) @Override public Map insertOrUpdateTask(ServiceTaskVO serviceTaskVO) { if (ObjectUtils.isEmpty(serviceTaskVO)) { log.info("任务入参为空,请检查入参"); throw new BaseException("任务入参为空,请检查入参"); } // 科室编码去重,避免 service_task.deptcode 超长及 service_taskdept 重复绑定 serviceTaskVO.setDeptcode(normalizeDeptCodes(serviceTaskVO.getDeptcode())); ServiceTask serviceTask = DtoConversionUtils.sourceToTarget(serviceTaskVO, ServiceTask.class); if (CollectionUtils.isEmpty(serviceTaskVO.getPreachformList())) throw new BaseException("任务的发送方式为空"); //将preachfromList放到serviceTask中的preachfrom中 ObjectMapper mapper = new ObjectMapper(); try { String preachformList = mapper.writeValueAsString(serviceTaskVO.getPreachformList()); serviceTask.setPreachformDesc(preachformList); } catch (JsonProcessingException e) { e.printStackTrace(); } serviceTask.setTextParam(JSON.toJSONString(serviceTaskVO.getTextParam())); if (serviceTaskVO.getIsoperation() != null && serviceTaskVO.getIsoperation() == 1) { //新增模板信息 Long tempid = null; String tempName = null; if (ObjectUtils.isNotEmpty(serviceTaskVO.getSvyTaskTemplateVO())) { tempid = Long.valueOf(svyTaskTemplateService.saveOrUpdateTemplate(serviceTaskVO.getSvyTaskTemplateVO())); tempName = svyTaskTemplateService.selectSvyTaskTemplateBySvyid(tempid).getSvyname(); } if (ObjectUtils.isNotEmpty(serviceTaskVO.getIvrTaskTemplateVO())) { tempid = Long.valueOf(ivrTaskTemplateService.saveOrUpdateTempScript(serviceTaskVO.getIvrTaskTemplateVO())); log.info("IVR模板插入成功,返回的tempid={}", tempid); IvrTaskTemplate ivrTaskTemplate = ivrTaskTemplateService.selectIvrTaskTemplateByID(tempid); if (ivrTaskTemplate == null) { log.error("根据tempid={}查询IVR模板失败,返回null!请检查del_flag字段是否正确设置", tempid); throw new BaseException("IVR模板保存成功但查询失败,请联系管理员检查数据"); } tempName = ivrTaskTemplate.getTemplateName(); log.info("IVR模板查询成功,tempName={}", tempName); } //往任务表中,新增任务 if (ObjectUtils.isNotEmpty(serviceTaskVO.getSendTimeslot())) serviceTask.setSendTimeSlot(JSON.toJSONString(serviceTaskVO.getSendTimeslot())); if (serviceTask.getSendState() == null) { serviceTask.setSendState(1L); serviceTaskVO.setSendState(1L); } else { serviceTask.setSendState(serviceTaskVO.getSendState()); } if (StringUtils.isNotEmpty(serviceTaskVO.getLibtemplateid())) { serviceTask.setLibtemplateid(serviceTaskVO.getLibtemplateid()); serviceTask.setLibtemplatename(serviceTaskVO.getLibtemplatename()); } else { if (ObjectUtils.isNotEmpty(serviceTaskVO.getSvyTaskTemplateVO())) { serviceTask.setLibtemplateid("" + serviceTaskVO.getSvyTaskTemplateVO().getTemplateid()); serviceTask.setLibtemplatename("" + serviceTaskVO.getLibtemplatename()); } if (ObjectUtils.isNotEmpty(serviceTaskVO.getIvrTaskTemplateVO())) { serviceTask.setLibtemplateid("" + serviceTaskVO.getIvrTaskTemplateVO().getLibtemplateid()); serviceTask.setLibtemplatename("" + serviceTaskVO.getIvrTaskTemplateVO().getLibtemplatename()); } } if (serviceTaskVO.getTemplateid() != null) { serviceTask.setTemplateid(serviceTaskVO.getTemplateid()); serviceTask.setTemplatename(serviceTaskVO.getTemplatename()); } else { serviceTask.setTemplateid(tempid); serviceTask.setTemplatename(tempName); } serviceTask.setLeaveldeptcodes(serviceTaskVO.getLeaveldeptcodes()); if (StringUtils.isEmpty(serviceTask.getLeavehospitaldistrictname()) && StringUtils.isNotEmpty(serviceTask.getLeavehospitaldistrictcode())) { SysDept sysDept = sysDept2Mapper.selectDeptByCode(serviceTask.getLeavehospitaldistrictcode(), null); serviceTask.setLeavehospitaldistrictname(sysDept.getDeptName()); } if (serviceTaskVO.getLongTask() == 1) serviceTask.setSendState(2L); serviceTask.setCreateTime(new Date()); serviceTask.setUpdateTime(new Date()); serviceTaskService.insertServiceTask(serviceTask); log.info("----serviceTaskVO.getAppltype()的值为:{}", serviceTaskVO.getAppltype()); if (StringUtils.isNotEmpty(serviceTaskVO.getAppltype())) { if (serviceTaskVO.getAppltype().equals("3")) { ServiceTaskdiag serviceTaskdiag = new ServiceTaskdiag(); serviceTaskdiag.setTaskId(serviceTask.getTaskid()); serviceTaskdiag.setTaskName(serviceTask.getTaskName()); serviceTaskdiag.setServiceType(serviceTaskVO.getServiceType()); serviceTaskdiag.setLongtask(Long.valueOf(serviceTask.getLongTask())); if (serviceTaskVO.getLongTask() == 1) serviceTaskdiag.setLongtask(1L); serviceTaskdiag.setIcd10code(serviceTaskVO.getIcd10code()); serviceTaskdiag.setIcd10name(serviceTaskVO.getIcd10name()); serviceTaskdiag.setGuid(serviceTask.getGuid()); serviceTaskdiag.setOrgid(serviceTask.getOrgid()); serviceTaskdiag.setCreateTime(new Date()); serviceTaskdiag.setDeptCode(serviceTaskVO.getDeptcode()); serviceTaskdiag.setDeptName(serviceTaskVO.getDeptname()); serviceTaskdiag.setWardCode(serviceTaskVO.getLeavehospitaldistrictcode()); serviceTaskdiag.setWardName(serviceTaskVO.getLeavehospitaldistrictname()); //南华附一的icd10code是有重复的,所以不能用南华附一的icd10code去查询 log.info("----serviceTaskdiag的值为:{}", serviceTaskdiag); if (!StringUtils.isEmpty(serviceTaskVO.getIcd10name())) { String[] Icd10Names = serviceTaskVO.getIcd10name().split(","); String[] Icd10codes = serviceTaskVO.getIcd10code().split(","); for (int i = 0; i < Icd10Names.length; i++) { serviceTaskdiag.setIcd10code(Icd10codes[i]); serviceTaskdiag.setIcd10name(Icd10Names[i]); serviceTaskdiagService.insertServiceTaskdiag(serviceTaskdiag); } } } else if (serviceTaskVO.getAppltype().equals("4")) { ServiceTaskoper serviceTaskoper = new ServiceTaskoper(); serviceTaskoper.setOpcode(serviceTaskVO.getOpcode()); serviceTaskoper.setOpdesc(serviceTaskVO.getOpdesc()); // serviceTaskoper.setOplevelcode(serviceTaskVO.getOplevelcode()); serviceTaskoper.setTaskId(serviceTask.getTaskid()); serviceTaskoper.setTaskName(serviceTask.getTaskName()); serviceTaskoper.setLongtask(Long.valueOf(serviceTask.getLongTask())); serviceTaskoper.setGuid(serviceTask.getGuid()); serviceTaskoper.setOrgid(serviceTask.getOrgid()); serviceTaskoper.setCreateTime(new Date()); //配置科室、病区 serviceTaskoper.setDeptCode(serviceTaskVO.getDeptcode()); serviceTaskoper.setDeptName(serviceTaskVO.getDeptname()); serviceTaskoper.setWardCode(serviceTaskVO.getLeavehospitaldistrictcode()); serviceTaskoper.setWardName(serviceTaskVO.getLeavehospitaldistrictname()); //多选手术等级 if (StringUtils.isNotEmpty(serviceTaskVO.getOplevelcode())) { String[] opLevelcodes = serviceTaskVO.getOplevelcode().split(","); for (String opLevelcode : opLevelcodes) { //先查询一下是否存在 log.info("----serviceTaskoper的值为:{}", serviceTaskoper); serviceTaskoper.setOplevelcode(opLevelcode); serviceTaskoperService.insertServiceTaskoper(serviceTaskoper); } } } else if (serviceTaskVO.getAppltype().equals("5")) { // 任务组:必须为长期任务(否则 findMatchingTaskIds 扫不到,无法自动纳入新出院患者) if (serviceTaskVO.getLongTask() == null || serviceTaskVO.getLongTask() != 1) { throw new BaseException("appltype=5 任务组必须为长期任务(longTask=1)"); } // 保存计划 + 明细 ServiceTaskScheduleVO scheduleVO = serviceTaskVO.getServiceTaskScheduleVO(); if (scheduleVO == null) { throw new BaseException("appltype=5 任务组:serviceTaskScheduleVO 不能为空"); } scheduleVO.setTaskid(serviceTask.getTaskid()); scheduleVO.setOrgid(serviceTask.getOrgid()); scheduleVO.setCampusid(serviceTask.getCampusid()); scheduleVO.setCreateBy(serviceTask.getCreateBy()); scheduleVO.setDeptCodes(serviceTaskVO.getDeptcode()); scheduleVO.setWardCodes(serviceTaskVO.getLeavehospitaldistrictcode()); scheduleVO.setIcd10Codes(serviceTaskVO.getIcd10code()); scheduleVO.setOplevelCodes(serviceTaskVO.getOplevelcode()); log.info("----serviceTaskSchedule的值为:{}", scheduleVO); serviceTaskScheduleService.saveScheduleWithDetail(scheduleVO); } else if (serviceTaskVO.getAppltype().equals("6")) { ServiceTaskmedical serviceTaskmedical = new ServiceTaskmedical(); serviceTaskmedical.setTaskId(serviceTask.getTaskid()); serviceTaskmedical.setTaskName(serviceTask.getTaskName()); serviceTaskmedical.setServiceType(serviceTaskVO.getServiceType()); serviceTaskmedical.setLongtask(Long.valueOf(serviceTask.getLongTask())); if (serviceTaskVO.getLongTask() == 1) serviceTaskmedical.setLongtask(1L); serviceTaskmedical.setMedicalCode(serviceTaskVO.getIcd10code()); serviceTaskmedical.setMedicalName(serviceTaskVO.getIcd10name()); serviceTaskmedical.setGuid(serviceTask.getGuid()); serviceTaskmedical.setOrgid(serviceTask.getOrgid()); serviceTaskmedical.setCreateTime(new Date()); serviceTaskmedical.setDeptCode(serviceTaskVO.getDeptcode()); serviceTaskmedical.setDeptName(serviceTaskVO.getDeptname()); serviceTaskmedical.setWardCode(serviceTaskVO.getLeavehospitaldistrictcode()); serviceTaskmedical.setWardName(serviceTaskVO.getLeavehospitaldistrictname()); //南华附一的icd10code是有重复的,所以不能用南华附一的icd10code去查询 log.info("----serviceTaskmedical的值为:{}", serviceTaskmedical); if (!StringUtils.isEmpty(serviceTaskVO.getMedicalName())) { String[] medicalNames = serviceTaskVO.getMedicalName().split(","); String[] medicalcodes = serviceTaskVO.getMedicalCode().split(","); String[] medicalCompanys = serviceTaskVO.getMedicalCompany().split(","); for (int i = 0; i < medicalNames.length; i++) { serviceTaskmedical.setMedicalCode(medicalNames[i]); serviceTaskmedical.setMedicalName(medicalcodes[i]); if (ObjectUtils.isNotEmpty(medicalCompanys)) serviceTaskmedical.setMedicalCompany(medicalCompanys[i]); serviceTaskmedicalService.insertServiceTaskmedical(serviceTaskmedical); } } } else { ServiceTaskdept serviceTaskdept = new ServiceTaskdept(); serviceTaskdept.setTaskId(serviceTask.getTaskid()); serviceTaskdept.setTaskName(serviceTask.getTaskName()); serviceTaskdept.setOrgid(serviceTask.getOrgid()); serviceTaskdept.setLongtask(Long.valueOf(serviceTaskVO.getLongTask())); if (StringUtils.isNotEmpty(serviceTaskVO.getDeptcode())) { String[] deptcodes = serviceTaskVO.getDeptcode().split(","); for (String deptCode : deptcodes) { serviceTaskdept.setDeptCode(deptCode); serviceTaskdept.setDeptType("1"); serviceTaskdept.setServiceType(serviceTaskVO.getServiceType()); serviceTaskdeptService.insertServiceTaskdept(serviceTaskdept); } } if (StringUtils.isNotEmpty(serviceTaskVO.getLeavehospitaldistrictcode())) { String[] leavehospitaldistrictcodes = serviceTaskVO.getLeavehospitaldistrictcode().split(","); for (String districtcode : leavehospitaldistrictcodes) { serviceTaskdept.setDeptCode(districtcode); serviceTaskdept.setDeptType("2"); serviceTaskdept.setServiceType(serviceTaskVO.getServiceType()); serviceTaskdeptService.insertServiceTaskdept(serviceTaskdept); } } } } //长期任务,也允许加人了 // if (serviceTaskVO.getLongTask() != null && serviceTaskVO.getLongTask() == 1 && serviceTaskVO.getPatCycle() == 0L) { // Map map = new HashMap<>(); // map.put("taskId", serviceTask.getTaskid().intValue()); // return map; // } //将任务信息放到服务表中 // 科室/病区按「离院维度」归位(出院随访的科室病区就是离院科室/病区),见 toSubtaskFromTaskVO ServiceSubtask serviceSubtask = toSubtaskFromTaskVO(serviceTaskVO); serviceSubtask.setTaskid(serviceTask.getTaskid().longValue()); serviceSubtask.setTemplatename(ObjectUtils.isNotEmpty(tempid) ? tempName : serviceTask.getTemplatename()); serviceSubtask.setTemplateid(ObjectUtils.isNotEmpty(tempid) ? tempid : serviceTask.getTemplateid()); serviceSubtask.setLibtemplateid(ObjectUtils.isEmpty(serviceTask.getLibtemplateid()) ? null : Long.valueOf(serviceTask.getLibtemplateid())); serviceSubtask.setLibtemplatename(serviceTask.getLibtemplatename()); //新增 if (CollectionUtils.isNotEmpty(serviceTaskVO.getPatTaskRelevances())) { for (PatTaskRelevance patTaskRelevance : serviceTaskVO.getPatTaskRelevances()) { //将任务信息新增到随访服务表中 serviceSubtask.setSendname(patTaskRelevance.getName()); serviceSubtask.setAge(patTaskRelevance.getAge()); // serviceSubtask.setLibtemplateid(Long.valueOf(serviceTask.getLibtemplateid())); serviceSubtask.setSfzh(patTaskRelevance.getIdcardno()); serviceSubtask.setPhone(patTaskRelevance.getTelcode()); serviceSubtask.setAddr(patTaskRelevance.getAddr()); serviceSubtask.setPatid(patTaskRelevance.getPatid()); serviceSubtask.setCreateTime(DateUtils.getNowDate()); serviceSubtask.setInhospid(patTaskRelevance.getHospid()); //新建完成就是待发送状态 serviceSubtask.setSendstate(2L); // 离院维度(出院随访 = 出院科室 / 出院病区): // 患者自带的出院科室/病区优先,患者侧没带(前端手动勾选很常见)时回退到任务配置, // 不能无条件覆盖 —— 否则会把 toSubtaskFromTaskVO 按任务配置兜好的离院维度抹成 null, // 结果「任务配了科室病区、生成出来的子任务离院科室/病区却是空」。 serviceSubtask.setLeaveldeptcode(firstNonBlank(patTaskRelevance.getDeptcode(), firstValue(serviceTaskVO.getDeptcode()))); serviceSubtask.setLeaveldeptname(firstNonBlank(patTaskRelevance.getDeptName(), firstValue(serviceTaskVO.getDeptname()))); serviceSubtask.setLeavehospitaldistrictcode(firstNonBlank(patTaskRelevance.getLeavehospitaldistrictcode(), firstValue(serviceTaskVO.getLeavehospitaldistrictcode()))); serviceSubtask.setLeavehospitaldistrictname(firstNonBlank(patTaskRelevance.getLeavehospitaldistrictname(), firstValue(serviceTaskVO.getLeavehospitaldistrictname()))); serviceSubtask.setType(serviceTaskVO.getType()); serviceSubtask.setHospType(patTaskRelevance.getHospType()); serviceSubtask.setOpenid(patTaskRelevance.getOpenid()); serviceSubtask.setDrname(patTaskRelevance.getDrname()); serviceSubtask.setDrcode(patTaskRelevance.getDrcode()); serviceSubtask.setInhosptime(patTaskRelevance.getInhosptime()); serviceSubtask.setLeaveicd10code(patTaskRelevance.getLeaveicd10code()); serviceSubtask.setLeavediagname(patTaskRelevance.getLeavediagname()); serviceSubtask.setEndtime(patTaskRelevance.getEndtime()); serviceSubtask.setNurseId(patTaskRelevance.getNurseId()); serviceSubtask.setNurseName(patTaskRelevance.getNurseName()); serviceSubtask.setContinueContent(ObjectUtils.isNotEmpty(patTaskRelevance.getContinueContent()) ? patTaskRelevance.getContinueContent().toString() : null); serviceSubtask.setContinueCount(patTaskRelevance.getContinueCount()); serviceSubtask.setContinueFlag(patTaskRelevance.getContinueFlag()); serviceSubtask.setContinueTimeNext(patTaskRelevance.getContinueTimeNext()); serviceSubtask.setContinueTimeNow(patTaskRelevance.getContinueTimeNow()); serviceSubtask.setCreateBy(serviceTask.getCreateBy()); serviceSubtask.setUpdateBy(serviceTask.getCreateBy()); serviceSubtask.setVisitTime(DateUtils.parseDate(serviceTaskVO.getShowTimeMorn())); //如果立即执行,时间就是当前时间 if (serviceTaskVO.getSendType() != null && serviceTaskVO.getSendType() == 2) serviceSubtask.setVisitTime(new Date()); if (serviceTaskVO.getLongTask() != null && serviceTaskVO.getLongTask() == 1) { serviceSubtask.setLongSendTime(patTaskRelevance.getLongSendTime()); serviceSubtask.setVisitTime(patTaskRelevance.getVisittime()); } // ===== appltype=5 任务组:按 schedule 的 detailList 派生多条 subtask ===== if ("5".equals(serviceTaskVO.getAppltype())) { ServiceTaskSchedule schedule = serviceTaskScheduleService.selectByTaskid(serviceTask.getTaskid()); if (schedule == null) { throw new BaseException("appltype=5 任务组:未找到 taskid=" + serviceTask.getTaskid() + " 的计划"); } List detailList = serviceTaskScheduleService.selectDetailByScheduleid(schedule.getId()); scheduleSubtaskBuilder.buildSubtasksForPatient(serviceTask, serviceTaskVO.getPreachformList(), schedule, detailList, patTaskRelevance, serviceSubtask); continue; } serviceSubtaskMapper.insertServiceSubtask(serviceSubtask); serviceSubtask.getId().intValue(); //需要按service_task里的preachform的顺序将发送方式保存到service_subtask_preachform表中 if (StringUtils.isNotEmpty(serviceTaskVO.getPreachformList())) { List> pfList = serviceTaskVO.getPreachformList(); for (Map map : pfList) { ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform(); serviceSubtaskPreachform.setSort(ObjectUtils.isEmpty(map.get("sort")) ? 0 : Long.valueOf(map.get("sort").toString())); serviceSubtaskPreachform.setPreachform(ObjectUtils.isEmpty(map.get("preachform")) ? "" : map.get("preachform").toString()); serviceSubtaskPreachform.setCompensateTime(ObjectUtils.isEmpty(map.get("compensateTime")) ? "" : map.get("compensateTime").toString()); serviceSubtaskPreachform.setTaskid(serviceTask.getTaskid()); serviceSubtaskPreachform.setSubid(serviceSubtask.getId()); //这个sendstate需要在数据库设置一个默认值为“1” serviceSubtaskPreachform.setSendstate("1"); serviceSubtaskPreachform.setOrgid(serviceTask.getOrgid()); serviceSubtaskPreachform.setCreateTime(new Date()); taskPreachformPort.insertServiceSubtaskPreachform(serviceSubtaskPreachform); } } } } } else if (serviceTaskVO.getIsoperation() != null && serviceTaskVO.getIsoperation() == 2) { //任务修改 if (ObjectUtils.isNotEmpty(serviceTaskVO.getSendTimeslot())) serviceTask.setSendTimeSlot(JSON.toJSONString(serviceTaskVO.getSendTimeslot())); //修改操作,需要将stopState状态+1 ServiceTask serviceTask1 = serviceTaskService.selectServiceTaskByTaskid(serviceTask.getTaskid()); ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity(); serviceSubtaskVO.setTaskid(serviceTask1.getTaskid()); //只删除首次随访未完成的 serviceSubtaskVO.setVisitCount(1); serviceSubtaskVO.setSendstate(2L); List serviceSubtaskList = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO); serviceSubtaskVO.setSendstate(1L); List serviceSubtaskList1 = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO); if (CollectionUtils.isNotEmpty(serviceSubtaskList)) { if (CollectionUtils.isNotEmpty(serviceSubtaskList1)) serviceSubtaskList.addAll(serviceSubtaskList1); } else { if (CollectionUtils.isNotEmpty(serviceSubtaskList1)) serviceSubtaskList = serviceSubtaskList1; } if (CollectionUtils.isNotEmpty(serviceSubtaskList)) { for (ServiceSubtask serviceSubtask : serviceSubtaskList) { log.error("sfSend需要移除的subId为:{}", serviceSubtask.getId().toString()); serviceSubtaskMapper.deleteServiceSubtaskById(serviceSubtask.getId()); // redisCache.removeElementFromList("cache-exist", serviceSubtask.getId().toString()); redisCache.removeElementFromList("cache-0", serviceSubtask.getId().toString()); redisCache.removeElementFromList("cache-1", serviceSubtask.getId().toString()); redisCache.removeElementFromList("cache-2", serviceSubtask.getId().toString()); redisCache.removeElementFromList("cache-3", serviceSubtask.getId().toString()); redisCache.removeElementFromList("cache-4", serviceSubtask.getId().toString()); //将出入院表的数据,还原成还未处理的状态 if (serviceSubtask.getServiceType().equals("2") || serviceSubtask.getServiceType().equals("13")) { ServiceTask st = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); //如果任务是长期任务,需要将该患者的出入院数据还原成还未处理的状态 if (st != null && st.getLongTask() == 1) { PatMedInhosp patMedInhosp = new PatMedInhosp(); patMedInhosp.setDeptcheckFlag("0"); patMedInhosp.setWardcheckFlag("0"); patMedInhosp.setDiagcheckFlag("0"); patMedInhosp.setInhospid(serviceSubtask.getInhospid()); inhospVisitFacade.updatePatMedInhosp(patMedInhosp); } } else if (serviceSubtask.getServiceType().equals("3")) { if (serviceSubtask.getInhospid() != null) { PatMedOuthospQueryReq req = new PatMedOuthospQueryReq(); req.setOuthospno(serviceSubtask.getHospno()); List patMedOuthosps = outhospDataFacade.callSpQueryOuthosp(req); if (CollectionUtils.isNotEmpty(patMedOuthosps)) { PatMedOuthosp patMedOuthosp = patMedOuthosps.get(0); patMedOuthosp.setServerState("0"); outhospDataFacade.update(patMedOuthosp); } } } else if (serviceSubtask.getServiceType().equals("19")) { ServiceTask st = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); //如果任务是长期任务,需要将该患者的出院详情状态还原成还未处理的状态 if (st != null && st.getLongTask() == 1 && ObjectUtils.isNotEmpty(serviceSubtask.getOperationItemId())) { PatMedOperationItem patMedOperationItem = new PatMedOperationItem(); patMedOperationItem.setOpercheckFlag("0"); patMedOperationItem.setId(serviceSubtask.getOperationItemId()); otherVisitFacade.updateOperationItem(patMedOperationItem); } } } } if (serviceTaskVO.getLibtemplateid() != null) serviceTask.setLibtemplateid(serviceTaskVO.getLibtemplateid().toString()); serviceTask.setTemplateid(serviceTaskVO.getTemplateid()); serviceTask.setLongTask(serviceTaskVO.getLongTask()); serviceTask.setUpdateTime(new Date()); serviceTaskService.updateServiceTask(serviceTask); if (StringUtils.isNotEmpty(serviceTaskVO.getAppltype())) { if (serviceTaskVO.getAppltype().equals("1") || serviceTaskVO.getAppltype().equals("2")) { if (StringUtils.isNotEmpty(serviceTaskVO.getDeptcode())) { // 修改任务时先软删除旧的科室绑定,避免旧科室残留 ServiceTaskdept oldDept = new ServiceTaskdept(); oldDept.setTaskId(serviceTask.getTaskid()); oldDept.setDeptType("1"); serviceTaskdeptService.deleteServiceTaskdeptByTaskId(oldDept); String[] deptcodes = serviceTaskVO.getDeptcode().split(","); for (String deptCode : deptcodes) { ServiceTaskdept serviceTaskdept = new ServiceTaskdept(); serviceTaskdept.setTaskId(serviceTask.getTaskid()); serviceTaskdept.setTaskName(serviceTask.getTaskName()); serviceTaskdept.setLongtask(Long.valueOf(serviceTask.getLongTask())); serviceTaskdept.setOrgid(serviceTaskVO.getOrgid()); serviceTaskdept.setDeptCode(deptCode); serviceTaskdept.setDeptType("1"); serviceTaskdept.setServiceType(serviceTaskVO.getServiceType()); ServiceTaskdept st = new ServiceTaskdept(); st.setDeptCode(deptCode); st.setTaskId(serviceTask.getTaskid()); List serviceTaskdepts = serviceTaskdeptService.selectServiceTaskdeptList(st); if (CollectionUtils.isEmpty(serviceTaskdepts)) { serviceTaskdeptService.insertServiceTaskdept(serviceTaskdept); } else { serviceTaskdeptService.updateServiceTaskdept(serviceTaskdept); } } } if (StringUtils.isNotEmpty(serviceTaskVO.getLeavehospitaldistrictcode())) { String[] leavehospitaldistrictcodes = serviceTaskVO.getLeavehospitaldistrictcode().split(","); for (String districtcode : leavehospitaldistrictcodes) { ServiceTaskdept serviceTaskdept = new ServiceTaskdept(); serviceTaskdept.setTaskId(serviceTask.getTaskid()); serviceTaskdept.setTaskName(serviceTask.getTaskName()); serviceTaskdept.setLongtask(Long.valueOf(serviceTask.getLongTask())); serviceTaskdept.setOrgid(serviceTaskVO.getOrgid()); serviceTaskdept.setDeptCode(districtcode); serviceTaskdept.setDeptType("2"); serviceTaskdept.setServiceType(serviceTaskVO.getServiceType()); //先通过任务ID、部门code,判断ServiceTaskdept是否存在,不存在则新增,存在则修改 ServiceTaskdept st = new ServiceTaskdept(); st.setDeptCode(districtcode); st.setTaskId(serviceTask.getTaskid()); List serviceTaskdepts = serviceTaskdeptService.selectServiceTaskdeptList(st); if (CollectionUtils.isEmpty(serviceTaskdepts)) { serviceTaskdeptService.insertServiceTaskdept(serviceTaskdept); } else { serviceTaskdeptService.updateServiceTaskdept(serviceTaskdept); } } } } else if (serviceTaskVO.getAppltype().equals("3")) { ServiceTaskdiag serviceTaskdiag = new ServiceTaskdiag(); serviceTaskdiag.setTaskId(serviceTask.getTaskid()); serviceTaskdiag.setTaskName(serviceTask.getTaskName()); if (StringUtils.isEmpty(serviceTaskVO.getIcd10code())) { throw new BaseException("疾病编码为空"); } serviceTaskdiag.setLongtask(Long.valueOf(serviceTask.getLongTask())); serviceTaskdiag.setIcd10name(serviceTaskVO.getIcd10name()); serviceTaskdiag.setGuid(serviceTask1.getGuid()); serviceTaskdiag.setServiceType(serviceTask1.getServiceType()); serviceTaskdiag.setOrgid(serviceTask1.getOrgid()); serviceTaskdiag.setDeptCode(serviceTask1.getDeptcode()); serviceTaskdiag.setDeptName(serviceTask1.getDeptname()); serviceTaskdiag.setWardCode(serviceTask1.getLeavehospitaldistrictcode()); serviceTaskdiag.setWardName(serviceTask1.getLeavehospitaldistrictname()); serviceTaskdiag.setUpdateTime(new Date()); if (StringUtils.isNotEmpty(serviceTaskVO.getIcd10code())) { String[] icd10codes = serviceTaskVO.getIcd10code().split(","); String[] icd10names = serviceTaskVO.getIcd10name().split(","); if (!active.equals("nhfy") && !active.equals("druid")) { if (icd10codes.length != icd10names.length) { throw new BaseException("疾病编码和疾病名称数量不一致"); } } for (int i = 0; i < icd10codes.length; i++) { //先查询一下是否存在 ServiceTaskdiag serviceTaskdiag2 = new ServiceTaskdiag(); serviceTaskdiag2.setTaskId(serviceTaskVO.getTaskid()); serviceTaskdiag2.setIcd10code(icd10codes[i]); serviceTaskdiag2.setIcd10name(icd10names[i]); List serviceTaskdiags = serviceTaskdiagService.selectServiceTaskdiagList(serviceTaskdiag2); serviceTaskdiag.setIcd10code(icd10codes[i]); serviceTaskdiag.setIcd10name(icd10names[i]); log.info("----serviceTaskdiag更新的值为:{}", serviceTaskdiag); if (CollectionUtils.isNotEmpty(serviceTaskdiags)) { serviceTaskdiag.setId(serviceTaskdiags.get(0).getId()); serviceTaskdiagService.updateServiceTaskdiag(serviceTaskdiag); } else { serviceTaskdiagService.insertServiceTaskdiag(serviceTaskdiag); } } } } else if (serviceTaskVO.getAppltype().equals("6")) { ServiceTaskmedical serviceTaskmedical = new ServiceTaskmedical(); serviceTaskmedical.setTaskId(serviceTask.getTaskid()); serviceTaskmedical.setTaskName(serviceTask.getTaskName()); if (StringUtils.isEmpty(serviceTaskVO.getMedicalCode())) { throw new BaseException("药品编码为空"); } serviceTaskmedical.setLongtask(Long.valueOf(serviceTask.getLongTask())); serviceTaskmedical.setMedicalName(serviceTaskVO.getMedicalName()); serviceTaskmedical.setGuid(serviceTask1.getGuid()); serviceTaskmedical.setServiceType(serviceTask1.getServiceType()); serviceTaskmedical.setOrgid(serviceTask1.getOrgid()); serviceTaskmedical.setDeptCode(serviceTask1.getDeptcode()); serviceTaskmedical.setDeptName(serviceTask1.getDeptname()); serviceTaskmedical.setWardCode(serviceTask1.getLeavehospitaldistrictcode()); serviceTaskmedical.setWardName(serviceTask1.getLeavehospitaldistrictname()); serviceTaskmedical.setUpdateTime(new Date()); if (StringUtils.isNotEmpty(serviceTaskVO.getMedicalCode())) { String[] medicalCodes = serviceTaskVO.getMedicalCode().split(","); String[] medicalNames = serviceTaskVO.getMedicalName().split(","); String[] medicalCompanys = serviceTaskVO.getMedicalCompany().split(","); if (!active.equals("nhfy") && !active.equals("druid")) { if (medicalCodes.length != medicalNames.length && medicalNames.length != medicalCompanys.length) { throw new BaseException("药品编码和药品名称数量不一致或者药品名称和药品公司数量不一致"); } } for (int i = 0; i < medicalCodes.length; i++) { //先查询一下是否存在 ServiceTaskmedical serviceTaskmedical1 = new ServiceTaskmedical(); serviceTaskmedical1.setTaskId(serviceTaskVO.getTaskid()); serviceTaskmedical1.setMedicalCode(medicalCodes[i]); serviceTaskmedical1.setMedicalName(medicalNames[i]); serviceTaskmedical1.setMedicalCompany(medicalCompanys[i]); List serviceTaskmedicals = serviceTaskmedicalService.selectServiceTaskmedicalList(serviceTaskmedical1); serviceTaskmedical.setMedicalCode(medicalCodes[i]); serviceTaskmedical.setMedicalName(medicalNames[i]); serviceTaskmedical.setMedicalCompany(medicalCompanys[i]); log.info("----serviceTaskmedical更新的值为:{}", serviceTaskmedical); if (CollectionUtils.isNotEmpty(serviceTaskmedicals)) { serviceTaskmedical.setId(serviceTaskmedicals.get(0).getId()); serviceTaskmedicalService.updateServiceTaskmedical(serviceTaskmedical); } else { serviceTaskmedicalService.insertServiceTaskmedical(serviceTaskmedical); } } } } else if (serviceTaskVO.getAppltype().equals("4")) { ServiceTaskoper serviceTaskoper = new ServiceTaskoper(); // if (StringUtils.isEmpty(serviceTaskVO.getOpcode())) { // throw new BaseException("手术编码为空"); // } // serviceTaskoper.setOpcode(serviceTaskVO.getOpcode()); serviceTaskoper.setOpdesc(serviceTaskVO.getOpdesc()); // serviceTaskoper.setOplevelcode(serviceTaskVO.getOplevelcode()); serviceTaskoper.setTaskId(serviceTask.getTaskid()); serviceTaskoper.setTaskName(serviceTask.getTaskName()); serviceTaskoper.setLongtask(Long.valueOf(serviceTask.getLongTask())); serviceTaskoper.setGuid(serviceTask.getGuid()); serviceTaskoper.setOrgid(serviceTask.getOrgid()); serviceTaskoper.setDeptCode(serviceTask1.getDeptcode()); serviceTaskoper.setDeptName(serviceTask1.getDeptname()); serviceTaskoper.setWardCode(serviceTask1.getLeavehospitaldistrictcode()); serviceTaskoper.setWardName(serviceTask1.getLeavehospitaldistrictname()); serviceTaskoper.setCreateTime(new Date()); if (StringUtils.isNotEmpty(serviceTaskVO.getOplevelcode())) { String[] opLevelcodes = serviceTaskVO.getOplevelcode().split(","); for (String opLevelcode : opLevelcodes) { //先查询一下是否存在 log.info("----serviceTaskoper的值为:{}", serviceTaskoper); ServiceTaskoper serviceTaskoper2 = new ServiceTaskoper(); serviceTaskoper2.setTaskId(serviceTaskVO.getTaskid()); serviceTaskoper2.setOrgid(serviceTask.getOrgid()); serviceTaskoper2.setOplevelcode(opLevelcode); List serviceTaskopers = serviceTaskoperService.selectServiceTaskoperList(serviceTaskoper2); serviceTaskoper.setOplevelcode(opLevelcode); if (CollectionUtils.isNotEmpty(serviceTaskopers)) { serviceTaskoper.setId(serviceTaskopers.get(0).getId()); serviceTaskoperService.updateServiceTaskoper(serviceTaskoper); } else { serviceTaskoperService.insertServiceTaskoper(serviceTaskoper); } } } } else if (serviceTaskVO.getAppltype().equals("5")) { // 任务组修改:删旧 schedule + 明细,重建。subtask 上面已批量清理。 if (serviceTaskVO.getLongTask() == null || serviceTaskVO.getLongTask() != 1) { throw new BaseException("appltype=5 任务组必须为长期任务(longTask=1)"); } ServiceTaskScheduleVO scheduleVO = serviceTaskVO.getServiceTaskScheduleVO(); if (scheduleVO == null) { throw new BaseException("appltype=5 任务组:serviceTaskScheduleVO 不能为空"); } scheduleVO.setTaskid(serviceTask.getTaskid()); scheduleVO.setOrgid(serviceTask.getOrgid()); scheduleVO.setCampusid(serviceTask.getCampusid()); scheduleVO.setDeptCodes(serviceTaskVO.getDeptcode()); scheduleVO.setWardCodes(serviceTaskVO.getLeavehospitaldistrictcode()); scheduleVO.setIcd10Codes(serviceTaskVO.getIcd10code()); scheduleVO.setOplevelCodes(serviceTaskVO.getOplevelcode()); scheduleVO.setCreateBy(serviceTask.getUpdateBy()); serviceTaskScheduleService.saveScheduleWithDetail(scheduleVO); } } if (ObjectUtils.isNotEmpty(serviceTaskVO.getIvrTaskTemplateVO())) { IvrTaskTemplate ivrTaskTemplate = new IvrTaskTemplate(); ivrTaskTemplate.setTaskid(serviceTaskVO.getIvrTaskTemplateVO().getTaskid()); ivrTaskTemplate.setId(serviceTaskVO.getIvrTaskTemplateVO().getId()); ivrTaskTemplateService.updateIvrTaskTemplate(ivrTaskTemplate); } else if (ObjectUtils.isNotEmpty(serviceTaskVO.getSvyTaskTemplateVO())) { SvyTaskTemplate svyTaskTemplate = new SvyTaskTemplate(); svyTaskTemplate.setTaskid(serviceTaskVO.getSvyTaskTemplateVO().getTaskid()); svyTaskTemplate.setId(serviceTaskVO.getSvyTaskTemplateVO().getId()); svyTaskTemplateService.updateSvyTaskTemplate(svyTaskTemplate); } if (serviceTaskVO.getLongTask() != null && serviceTaskVO.getLongTask() == 1) { //这里需要将任务id与任务模板ID,在任务模板中绑定 Map map = new HashMap<>(); map.put("taskId", serviceTask.getTaskid().intValue()); return map; } if (CollectionUtils.isNotEmpty(serviceTaskVO.getPatTaskRelevances())) { for (PatTaskRelevance patTaskRelevance : serviceTaskVO.getPatTaskRelevances()) { // 科室/病区按「离院维度」归位(出院随访的科室病区就是离院科室/病区),见 toSubtaskFromTaskVO ServiceSubtask serviceSubtask = toSubtaskFromTaskVO(serviceTaskVO); serviceSubtask.setLibtemplateid(ObjectUtils.isEmpty(serviceTaskVO.getLibtemplateid()) ? null : Long.valueOf(serviceTaskVO.getLibtemplateid())); serviceSubtask.setLibtemplatename(serviceTaskVO.getLibtemplatename()); serviceSubtask.setTemplateid(serviceTask.getTemplateid()); serviceSubtask.setTemplatename(serviceTask.getTemplatename()); serviceSubtask.setSendname(patTaskRelevance.getName()); serviceSubtask.setAge(patTaskRelevance.getAge()); serviceSubtask.setSfzh(patTaskRelevance.getSfzh()); serviceSubtask.setPhone(patTaskRelevance.getTelcode()); serviceSubtask.setAddr(patTaskRelevance.getAddr()); serviceSubtask.setPatid(patTaskRelevance.getPatid()); serviceSubtask.setOpenid(patTaskRelevance.getOpenid()); // 离院维度:患者自带的出院科室/病区优先,没带时回退到任务配置(否则会把 // toSubtaskFromTaskVO 按任务配置兜好的值抹成 null,出院随访就成「离院科室/病区为空」) serviceSubtask.setLeaveldeptcode(firstNonBlank(patTaskRelevance.getDeptcode(), firstValue(serviceTaskVO.getDeptcode()))); serviceSubtask.setLeaveldeptname(firstNonBlank(patTaskRelevance.getDeptName(), firstValue(serviceTaskVO.getDeptname()))); serviceSubtask.setLeavehospitaldistrictcode(firstNonBlank(patTaskRelevance.getLeavehospitaldistrictcode(), firstValue(serviceTaskVO.getLeavehospitaldistrictcode()))); serviceSubtask.setLeavehospitaldistrictname(firstNonBlank(patTaskRelevance.getLeavehospitaldistrictname(), firstValue(serviceTaskVO.getLeavehospitaldistrictname()))); serviceSubtask.setType(serviceTaskVO.getType()); serviceSubtask.setCreateTime(DateUtils.getNowDate()); serviceSubtask.setDrname(patTaskRelevance.getDrname()); serviceSubtask.setDrcode(patTaskRelevance.getDrcode()); serviceSubtask.setInhosptime(patTaskRelevance.getInhosptime()); serviceSubtask.setHospType(patTaskRelevance.getHospType()); serviceSubtask.setContinueContent(ObjectUtils.isNotEmpty(patTaskRelevance.getContinueContent()) ? patTaskRelevance.getContinueContent().toString() : null); serviceSubtask.setContinueCount(patTaskRelevance.getContinueCount()); serviceSubtask.setContinueFlag(patTaskRelevance.getContinueFlag()); serviceSubtask.setContinueTimeNext(patTaskRelevance.getContinueTimeNext()); serviceSubtask.setContinueTimeNow(patTaskRelevance.getContinueTimeNow()); serviceSubtask.setEndtime(patTaskRelevance.getEndtime()); serviceSubtask.setNurseId(patTaskRelevance.getNurseId()); serviceSubtask.setNurseName(patTaskRelevance.getNurseName()); serviceSubtask.setVisitTime(patTaskRelevance.getVisittime()); serviceSubtask.setTextParam(new Gson().toJson(serviceTaskVO.getTextParam())); if (patTaskRelevance.getIsoperation() != null) { // appltype=5 任务组:追加患者(isoperation=1)走计划派生;修改(2)/删除(3)仍走原逻辑 if ("5".equals(serviceTaskVO.getAppltype()) && patTaskRelevance.getIsoperation() == 1) { ServiceTaskSchedule schedule = serviceTaskScheduleService.selectByTaskid(serviceTask.getTaskid()); if (schedule == null) { throw new BaseException("appltype=5 任务组:未找到 taskid=" + serviceTask.getTaskid() + " 的计划"); } List detailList = serviceTaskScheduleService.selectDetailByScheduleid(schedule.getId()); serviceSubtask.setUpdateBy(serviceTask.getUpdateBy()); serviceSubtask.setCreateBy(serviceTask.getUpdateBy()); scheduleSubtaskBuilder.buildSubtasksForPatient(serviceTask, serviceTaskVO.getPreachformList(), schedule, detailList, patTaskRelevance, serviceSubtask); continue; } if (patTaskRelevance.getIsoperation() == 2) { serviceSubtask.setUpdateBy(serviceTask.getUpdateBy()); serviceSubtaskMapper.updateServiceSubtaskByCondition(serviceSubtask); } if (patTaskRelevance.getIsoperation() == 1) { serviceSubtask.setSendstate(1L); serviceSubtask.setUpdateBy(serviceTask.getUpdateBy()); serviceSubtask.setCreateBy(serviceTask.getUpdateBy()); serviceSubtaskMapper.insertServiceSubtask(serviceSubtask); } if (patTaskRelevance.getIsoperation() == 3) // 通过taskid和patid去删除该条数据 serviceSubtaskMapper.deleteServiceSubtaskByCondition(serviceTaskVO.getTaskid(), patTaskRelevance.getPatid()); } serviceSubtask.getTaskid().intValue(); } } // 有可能会把发送顺序也修改了(需要根据taskId将所有的sendstate!=4,5,6的subTask拉出来,进行修改一下) ServiceSubtaskEntity ssVo = new ServiceSubtaskEntity(); ssVo.setTaskid(serviceTaskVO.getTaskid()); ssVo.setDelFlag("0"); List ssList = new ArrayList<>(); ssList.add(1l); ssList.add(2L); ssList.add(3L); ssVo.setSendstates(ssList); List ssTaskList = serviceSubtaskMapper.selectServiceSubtaskBySendstate(ssVo); for (int i = 0; i < ssTaskList.size(); i++) { ServiceSubtask serviceSubtask = ssTaskList.get(i); taskPreachformPort.deleteServiceSubtaskPreachformBySubid(serviceSubtask.getId()); if (StringUtils.isNotEmpty(serviceTaskVO.getPreachformList())) { List> pfList = serviceTaskVO.getPreachformList(); for (Map map : pfList) { ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform(); serviceSubtaskPreachform.setSort(ObjectUtils.isEmpty(map.get("sort")) ? 0 : Long.valueOf(map.get("sort").toString())); serviceSubtaskPreachform.setPreachform(ObjectUtils.isEmpty(map.get("preachform")) ? "" : map.get("preachform").toString()); serviceSubtaskPreachform.setCompensateTime(ObjectUtils.isEmpty(map.get("compensateTime")) ? "" : map.get("compensateTime").toString()); serviceSubtaskPreachform.setTaskid(serviceTask.getTaskid()); serviceSubtaskPreachform.setSubid(serviceSubtask.getId()); //这个sendstate需要在数据库设置一个默认值为“1” serviceSubtaskPreachform.setSendstate("1"); serviceSubtaskPreachform.setOrgid(serviceTask.getOrgid()); // serviceSubtaskPreachform.setSort(Long.valueOf(i)); taskPreachformPort.insertServiceSubtaskPreachform(serviceSubtaskPreachform); } } } } Map map = new HashMap<>(); map.put("taskId", serviceTask.getTaskid().intValue()); return map; } @Override public List getSfFzInfoEveryMonth(ServiceSubtaskCountReq serviceSubtaskCountReq) { if (serviceSubtaskCountReq.getUserId() == null) { Long userId = SecurityUtils.getUserId(); serviceSubtaskCountReq.setUserId(userId); } if (serviceSubtaskCountReq.getStartTime() == null) { LocalDate of = LocalDate.of(LocalDate.now().getYear(), 1, 1); serviceSubtaskCountReq.setStartTime(Date.from(of.atStartOfDay(ZoneId.systemDefault()).toInstant())); } if (serviceSubtaskCountReq.getEndTime() == null) { serviceSubtaskCountReq.setEndTime(new Date()); } List sfFzInfoEveryMonth = serviceSubtaskMapper.getSfFzInfoEveryMonth(serviceSubtaskCountReq); List result = sfFzInfoEveryMonth.stream().collect(Collectors.groupingBy(ServiceSubtaskCount::getMonth, Collectors.groupingBy(ServiceSubtaskCount::getServiceType, Collectors.summingLong(ServiceSubtaskCount::getCount)))).entrySet().stream().flatMap(monthEntry -> monthEntry.getValue().entrySet().stream().map(typeEntry -> new ServiceSubtaskCount(monthEntry.getKey(), typeEntry.getKey(), typeEntry.getValue()))).collect(Collectors.toList()); List result2 = new ArrayList<>(); //根据服务类型进行筛选 if (CollectionUtils.isNotEmpty(serviceSubtaskCountReq.getServiceType())) { for (ServiceSubtaskCount serviceSubtaskCount : result) { for (Long type : serviceSubtaskCountReq.getServiceType()) { if (type == serviceSubtaskCount.getServiceType()) { result2.add(serviceSubtaskCount); } } } } else { result2 = result; } return result2; } /** * 服务统计查询 - 按时间维度统计出院/门诊随访数据 * * @param request 统计请求参数 * @return 统计结果列表 */ @Override public List getServiceStatistics(ServiceStatisticsRequest request) { log.info("getServiceStatistics的入参为:{}", request); // 参数校验 if (request.getStartDate() == null || request.getEndDate() == null) { throw new IllegalArgumentException("开始日期和结束日期不能为空"); } if (request.getStartDate().after(request.getEndDate())) { throw new IllegalArgumentException("开始日期不能晚于结束日期"); } // 如果timeType为空,默认按天统计 if (StringUtils.isEmpty(request.getTimeType())) { request.setTimeType("day"); } List result = serviceSubtaskMapper.getServiceStatistics(request); //获取门急诊数据 //填充门诊数据 for (ServiceStatisticsResponse serviceStatisticsResponse : result) { PatMedOuthospQueryReq req = new PatMedOuthospQueryReq(); String deptcodes = CollectionUtils.isEmpty(request.getDeptcodes()) ? null : String.join(",", request.getDeptcodes()); if (!request.getTimeType().equals("month")) { req.setBeginAdmitdate(DateUtils.parseDate(serviceStatisticsResponse.getTimePeriod())); req.setEndAdmitdate(DateUtils.addDays(DateUtils.parseDate(serviceStatisticsResponse.getTimePeriod()), 1)); } else { // year 类型:timePeriod 格式为 "yyyy-MM",取当月第一天和最后一天 java.time.YearMonth ym = java.time.YearMonth.parse(serviceStatisticsResponse.getTimePeriod()); req.setBeginAdmitdate(DateUtils.toDate(ym.atDay(1))); req.setEndAdmitdate(DateUtils.toDate(ym.atEndOfMonth())); } req.setDeptcode(deptcodes); req.setOrgid(request.getOrgid()); Long count = outhospDataFacade.callSpQueryOuthospCount(req); serviceStatisticsResponse.setPmoCount(count); } log.info("getServiceStatistics返回结果数量:{}", result.size()); return result; } @Override public List sendMsgTemplate(List patArchiveSrmVOS) { //用来记录发送失败的 List sendError = new ArrayList<>(); for (PatArchiveSrmVO patArchiveSrmVO : patArchiveSrmVOS) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY年MM月dd日HH:mm"); String timestamp = simpleDateFormat.format(patArchiveSrmVO.getVisitTime()); StringBuilder stringBuilder = new StringBuilder(); if (patArchiveSrmVO.getSrmTemplate().equals("入院准备中心-无检查")) { stringBuilder.append(patArchiveSrmVO.getName() + ",您好!主管医生已为您安排住院,请于当天"); } else if (patArchiveSrmVO.getSrmTemplate().equals("入院准备中心-空腹检查")) { stringBuilder.append(patArchiveSrmVO.getName() + ",您好!主管医生已为您安排住院,请当天空腹并于"); } else if (patArchiveSrmVO.getSrmTemplate().equals("日间病房—择期病人检查")) { stringBuilder.append(patArchiveSrmVO.getName() + ",您好!主管医生已为您安排住院前检查,请当天空腹并于"); } stringBuilder.append(timestamp + "之前携带医保卡或电子医保卡身份证凭此条短信到1号楼3楼南入院准备中心入院登记窗口,办理正式住院手续,完成各项检查后再到相应病区护士站报到。"); stringBuilder.append("入院准备中心电话:89975977。入院办理须知:https://mp.weixin.qq.com/s/OCkotuRyQ8Ld2owFF0YErw"); String data = MessageSend.sendMsg(stringBuilder.toString(), "6", patArchiveSrmVO.getPhone(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); if (StringUtils.isNotEmpty(data)) { ObjectMapper mapper = new ObjectMapper(); JsonNode root = null; try { root = mapper.readTree(data); } catch (JsonProcessingException e) { e.printStackTrace(); } String status = root.get("result").get(0).get("status").asText(); if (status.equals("00000")) { sendError.add(patArchiveSrmVO); } } } return sendError; } /** * 获取随访统计比例 * * @param serviceSubtaskCountReq * @return */ @Override // @Cacheable(value = "sfStatistics", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()") public List getSfStatistics(ServiceSubtaskCountReq serviceSubtaskCountReq) { log.info("getSfStatistics的入参为:{}", serviceSubtaskCountReq); String drcode = "drcode"; //缙云人民 根据经管医生分组 if (serviceSubtaskCountReq.getOrgid().equals("47246116333112211A1001")) { drcode = "management_doctor_code"; } String groupKey = drcode; if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 1) { if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) { groupKey = drcode; } else { groupKey = "leavehospitaldistrictcode"; } } else if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 2) { if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) { groupKey = drcode; } else { // 2026-11 字段重命名后:deptcode 是在院科室(历史数据为空), // 出院科室已改名为 leaveldeptcode,分组必须用后者, // 否则 getSfStatisticsGroupKey 会返回 NULL,拼成 IN (NULL) 导致整表查空。 groupKey = "leaveldeptcode"; } } else if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 3) { // 病种统计:按任务ID分组,每个任务即一个病种随访任务 groupKey = "taskid"; } List serviceSubtaskStatistics = new ArrayList<>(); // 根据条件进行分组 Map> collect = new HashMap<>(); serviceSubtaskCountReq.setGroupKey(groupKey); List groupKeyList = serviceSubtaskMapper.getSfStatisticsGroupKey(serviceSubtaskCountReq); /* * 分组键可能为 NULL(历史数据、或重命名后尚未回填的在院维度列), * 直接拼进 SQL 会变成 `AND IFNULL(列,'Unknown') IN (NULL)`,恒不成立,整张统计表为空。 * 这里统一成 'Unknown',与聚合 SQL 的 IFNULL(列,'Unknown') 口径对齐。 */ if (groupKeyList != null) { groupKeyList = groupKeyList.stream() .map(key -> key == null ? "Unknown" : key) .distinct() .collect(Collectors.toList()); } serviceSubtaskCountReq.setGroupKeyList(groupKeyList); List rawData = serviceSubtaskMapper.getSfStatistics(serviceSubtaskCountReq); switch (groupKey) { case "drcode": collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getDrcode()).orElse("Unknown"))); break; case "management_doctor_code": rawData = rawData.stream().peek(item -> { item.setDrname(item.getManagementDoctor()); item.setDrcode(item.getManagementDoctorCode()); }).collect(Collectors.toList()); collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getManagementDoctorCode()).orElse("Unknown"))); break; case "deptcode": case "leaveldeptcode": collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getLeaveldeptcode()).orElse("Unknown"))); break; case "leavehospitaldistrictcode": collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getLeavehospitaldistrictcode()).orElse("Unknown"))); break; case "taskid": collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getTaskid()).map(String::valueOf).orElse("Unknown"))); break; default: collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getDrcode()).orElse("Unknown"))); break; } //获取及时率统计合集 Map> jsRates = getSsRateForSfStatistics(serviceSubtaskCountReq, collect); for (String collectKey : collect.keySet()) { List serviceSubtaskList = collect.get(collectKey); if (CollectionUtils.isEmpty(serviceSubtaskList)) { continue; } ServiceSubtaskStatistic statistic = getStatistic(serviceSubtaskList, serviceSubtaskCountReq.getFollowUpCountStyle(), serviceSubtaskCountReq.getVisitCount()); if ("taskid".equals(groupKey)) { applyTaskGroupInfo(statistic, serviceSubtaskList); } if (ObjectUtils.isNotEmpty(jsRates)) { Map jsRateMap = jsRates.get(collectKey); BigDecimal jsRate = new BigDecimal("0"); if (ObjectUtils.isNotEmpty(jsRateMap) && ObjectUtils.isNotEmpty(jsRateMap.get("rate"))) { jsRate = new BigDecimal(jsRateMap.get("rate").toString()); } Double jsRateDouble = (jsRate.setScale(4, RoundingMode.HALF_UP)).doubleValue(); statistic.setRate(jsRateDouble); } if (ObjectUtils.isNotEmpty(statistic)) { serviceSubtaskStatistics.add(statistic); } } return serviceSubtaskStatistics; } /** * 获取专病随访统计比例 * * @param serviceSubtaskCountReq * @return */ @Override // @Cacheable(value = "specialSfStatistics", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()") public List getSpecialSfStatistics(ServiceSubtaskCountReq serviceSubtaskCountReq) { log.info("getSpecialSfStatistics的入参为:{}", serviceSubtaskCountReq); String groupKey = "drcode"; if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) { groupKey = "drcode"; } else { groupKey = "task_name"; } List serviceSubtaskStatistics = new ArrayList<>(); serviceSubtaskCountReq.setGroupKey(groupKey); serviceSubtaskStatistics = serviceSubtaskMapper.getSpecialSfStatistics(serviceSubtaskCountReq); return serviceSubtaskStatistics; } /** * 随访统计-及时率统计 * * @param serviceSubtaskCountReq * @param collect * @return */ public Map> getSsRateForSfStatistics(ServiceSubtaskCountReq serviceSubtaskCountReq, Map> collect) { if (ObjectUtils.isEmpty(serviceSubtaskCountReq) || ObjectUtils.isEmpty(collect)) { return null; } return getSsRateForSfStatistics(serviceSubtaskCountReq, new ArrayList<>(collect.keySet())); } /** * 随访统计-及时率统计(分组键直接传值的重载) *

* 统计下推到 SQL 的 {@code getSfStatisticsScript} 不再把明细行捞回内存,拿不到 * {@code Map<分组, List<明细>>},因此直接传分组键集合;查询语句与原来完全同一个。 * * @param groupKeyList 分组键集合(drcode / leaveldeptcode / leavehospitaldistrictcode 的实际取值) */ public Map> getSsRateForSfStatistics(ServiceSubtaskCountReq serviceSubtaskCountReq, List groupKeyList) { if (ObjectUtils.isEmpty(serviceSubtaskCountReq)) { return null; } String groupKey = serviceSubtaskCountReq.getGroupKey(); if (StringUtils.isEmpty(groupKey)) { return null; } if (ObjectUtils.isEmpty(groupKeyList)) { return null; } //及时率统计 ServiceSubtaskEntity ssRate = new ServiceSubtaskEntity(); ssRate.setOrgid(serviceSubtaskCountReq.getOrgid()); ssRate.setStarttime(serviceSubtaskCountReq.getStartTime()); ssRate.setEndtime(serviceSubtaskCountReq.getEndTime()); ssRate.setStartOutHospTime(serviceSubtaskCountReq.getHospitalStartTime()); ssRate.setEndOutHospTime(serviceSubtaskCountReq.getHospitalEndTime()); ssRate.setVisitCount(serviceSubtaskCountReq.getVisitCount()); ssRate.setServiceTypeList(serviceSubtaskCountReq.getServiceType()); if (serviceSubtaskCountReq.getEndTime() != null && new Date().before(serviceSubtaskCountReq.getEndTime())) { ssRate.setEndtime(new Date()); } ssRate.setGroupKey(groupKey); ssRate.setGroupKeyList(groupKeyList); ssRate.setRateDay(serviceSubtaskCountReq.getRateDay()); Map> rateResult = serviceSubtaskMapper.selectTimelyRateBatch(ssRate); if (rateResult == null || rateResult.isEmpty()) { return rateResult; } // taskid 为数值类型,MyBatis 返回的 Map key 可能是 Long,这里统一转成 String 与分组 key 对齐 Map> jsRates = new HashMap<>(); for (Map.Entry> entry : rateResult.entrySet()) { jsRates.put(String.valueOf(entry.getKey()), entry.getValue()); } return jsRates; } /** * 空值兜底:SUM(CASE ...) 理论上不会是 null,这里只做防御,避免拆箱 NPE。 */ private long nvlLong(Long value) { return value == null ? 0L : value; } /** * 把数据库聚合值(BigDecimal / Long / Integer 等)转成 int。 */ private int toIntValue(Object value) { return value instanceof Number ? ((Number) value).intValue() : 0; } public List getSfStatisticsExport(ServiceSubtaskCountReq serviceSubtaskCountReq) { List sfStatistics = getSfStatistics(serviceSubtaskCountReq); // 添加总计行 if (CollectionUtils.isNotEmpty(sfStatistics)) { ServiceSubtaskStatistic totalRow = calculateTotalRow(sfStatistics); totalRow.setLeavehospitaldistrictname("总计"); totalRow.setDeptname("总计"); if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 3) { totalRow.setTaskName("总计"); } sfStatistics.add(totalRow); } return sfStatistics; } @Override public List getSfStatisticsIsAbnormalExport(ServiceSubtaskCountReq serviceSubtaskCountReq) { return null; } /** * 获取随访统计比例 * * @param serviceSubtaskCountReq * @return */ @Override @Cacheable(value = "sfStatisticsJoy", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()") public List getSfStatisticsJoy(ServiceSubtaskCountReq serviceSubtaskCountReq) { log.error("getSfStatistics的入参为:{}", serviceSubtaskCountReq); List serviceSubtaskStatistics = new ArrayList<>(); // 根据条件进行分组 Map> collect = new HashMap<>(); String orgid = null; if (serviceSubtaskCountReq.getLeavehospitaldistrictcodes() != null && serviceSubtaskCountReq.getLeavehospitaldistrictcodes().size() > 0) { if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) { collect = serviceSubtaskMapper.getSfStatistics(serviceSubtaskCountReq).stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getDrname()).orElse("Unknown"))); } else { collect = serviceSubtaskMapper.getSfStatistics(serviceSubtaskCountReq).stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getLeavehospitaldistrictname()).orElse("Unknown"))); } } else if (serviceSubtaskCountReq.getDeptcodes() != null && serviceSubtaskCountReq.getDeptcodes().size() > 0) { if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) { collect = serviceSubtaskMapper.getSfStatistics(serviceSubtaskCountReq).stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getDrname()).orElse("Unknown"))); } else { collect = serviceSubtaskMapper.getSfStatistics(serviceSubtaskCountReq).stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getLeaveldeptname()).orElse("Unknown"))); } } List joySubCount = serviceSubtaskMapper.getSfStatisticsJoy(serviceSubtaskCountReq); for (List serviceSubtaskList : collect.values()) { if (CollectionUtils.isEmpty(serviceSubtaskList)) { continue; } ServiceSubtaskStatistic statistic = getStatisticJoy(serviceSubtaskList, joySubCount); //及时率 ServiceSubtask ss = new ServiceSubtask(); orgid = serviceSubtaskList.get(0).getOrgid(); ss.setOrgid(orgid); // 如果有医生编码,设置医生编码用于及时率查询 if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) { ss.setDrcode(serviceSubtaskList.get(0).getDrcode()); } else { if (CollectionUtils.isNotEmpty(serviceSubtaskCountReq.getLeavehospitaldistrictcodes())) { ss.setLeavehospitaldistrictcode(serviceSubtaskList.get(0).getLeavehospitaldistrictcode()); } else if (CollectionUtils.isNotEmpty(serviceSubtaskCountReq.getDeptcodes())) { ss.setLeaveldeptcode(serviceSubtaskList.get(0).getLeaveldeptcode()); } } ss.setStarttime(serviceSubtaskCountReq.getStartTime()); ss.setEndtime(serviceSubtaskCountReq.getEndTime()); if (serviceSubtaskCountReq.getEndTime() != null && new Date().before(serviceSubtaskCountReq.getEndTime())) { ss.setEndtime(new Date()); } ss.setStartOutHospTime(serviceSubtaskCountReq.getHospitalStartTime()); ss.setEndOutHospTime(serviceSubtaskCountReq.getHospitalEndTime()); Double jsRate = serviceSubtaskMapper.selectTimelyRate(ss); statistic.setRate(jsRate); if (ObjectUtils.isNotEmpty(statistic)) { serviceSubtaskStatistics.add(statistic); } } if (CollectionUtils.isNotEmpty(serviceSubtaskStatistics)) { for (ServiceSubtaskStatistic serviceSubtaskStatistic : serviceSubtaskStatistics) { //所有满意度数量 //满意度模块化后:满意度指数据此改为调用满意度模块门面; //模块关闭时门面返回全零 Map(与被迁移实现的实际输出一致),不影响随访统计其它字段。 if (CollectionUtils.isNotEmpty(serviceSubtaskCountReq.getDeptcodes())) { Map satisfactionIndex = satisfactionFacade.getSatisfactionIndex("1", serviceSubtaskStatistic.getDeptcode(), orgid, serviceSubtaskCountReq.getIvrCategoryid(), serviceSubtaskCountReq.getSvyCategoryid()); serviceSubtaskStatistic.setJoyAllCount(satisfactionIndex.get("mydtmzl") != null ? (Integer) satisfactionIndex.get("mydtmzl") : 0); serviceSubtaskStatistic.setJoyCount(satisfactionIndex.get("mydtbl") != null ? (Integer) satisfactionIndex.get("mydtbl") : 0); serviceSubtaskStatistic.setJoyTotal((Double) satisfactionIndex.get("wcbl")); } else if (CollectionUtils.isNotEmpty(serviceSubtaskCountReq.getLeavehospitaldistrictcodes())) { Map satisfactionIndex = satisfactionFacade.getSatisfactionIndex("2", serviceSubtaskStatistic.getLeavehospitaldistrictcode(), orgid, serviceSubtaskCountReq.getIvrCategoryid(), serviceSubtaskCountReq.getSvyCategoryid()); serviceSubtaskStatistic.setJoyAllCount(satisfactionIndex.get("mydtmzl") != null ? (Integer) satisfactionIndex.get("mydtmzl") : 0); serviceSubtaskStatistic.setJoyCount(satisfactionIndex.get("mydtbl") != null ? (Integer) satisfactionIndex.get("mydtbl") : 0); serviceSubtaskStatistic.setJoyTotal((Double) satisfactionIndex.get("wcbl")); } } } return serviceSubtaskStatistics; } /** * 病种统计(按 taskid 分组)时补齐任务ID、任务名称和疾病病种。 * * @param statistic 统计结果 * @param serviceSubtaskList 当前任务分组下的子任务 */ private void applyTaskGroupInfo(ServiceSubtaskStatistic statistic, List serviceSubtaskList) { if (statistic == null || CollectionUtils.isEmpty(serviceSubtaskList)) { return; } ServiceSubtask first = serviceSubtaskList.get(0); statistic.setTaskId(first.getTaskid()); statistic.setTaskName(first.getTaskName()); statistic.setDiagType(first.getDiagType()); } private ServiceSubtaskStatistic getStatistic(List serviceSubtaskList, String followUpCountStyle, Integer visitCount) { ServiceSubtaskStatistic serviceSubtaskStatistic = new ServiceSubtaskStatistic(); if (visitCount != null && visitCount > 1) { serviceSubtaskStatistic = getStatisticAgain(serviceSubtaskList, followUpCountStyle); } else if (visitCount != null && visitCount == 1) { serviceSubtaskStatistic = getStatisticFirst(serviceSubtaskList, followUpCountStyle); } else { //格式化为两位小数的百分比 DecimalFormat percentFormat = new DecimalFormat("##.##%"); serviceSubtaskStatistic.setDeptname(serviceSubtaskList.get(0).getLeaveldeptname()); serviceSubtaskStatistic.setDeptcode(serviceSubtaskList.get(0).getLeaveldeptcode()); serviceSubtaskStatistic.setLeavehospitaldistrictname(serviceSubtaskList.get(0).getLeavehospitaldistrictname()); serviceSubtaskStatistic.setLeavehospitaldistrictcode(serviceSubtaskList.get(0).getLeavehospitaldistrictcode()); serviceSubtaskStatistic.setDrcode(serviceSubtaskList.get(0).getDrcode()); serviceSubtaskStatistic.setDrname(serviceSubtaskList.get(0).getDrname()); //随访中心科室,用于统计再次随访推送到随访中心的人数 String centerDept = sysConfigService.selectConfigByKey("sys.smartor.center.dept", serviceSubtaskList.get(0).getOrgid()); //出院人次 serviceSubtaskStatistic.setDischargeCount(serviceSubtaskList.size()); for (ServiceSubtask serviceSubtask : serviceSubtaskList) { //无需随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 4) { serviceSubtaskStatistic.setNonFollowUp(serviceSubtaskStatistic.getNonFollowUp() + 1L); if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 6) { serviceSubtaskStatistic.setFilterCount(serviceSubtaskStatistic.getFilterCount() + 1L); } } //应随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); } //及时随访人次:已完成且未超时 if (isTimelyFollowUp(serviceSubtask)) { serviceSubtaskStatistic.setTimelyFollowUp(serviceSubtaskStatistic.getTimelyFollowUp() + 1L); } //首次出院人次:visitCount = 1,作为再次随访推送率的分母 if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() == 1) { serviceSubtaskStatistic.setFirstDischargeCount(serviceSubtaskStatistic.getFirstDischargeCount() + 1L); } //再次随访推送人数:首个再次随访(visitCount = 2)且执行科室为随访中心科室 if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() == 2 && StringUtils.isNotEmpty(centerDept) && StringUtils.equals(StringUtils.trim(centerDept), StringUtils.trim(serviceSubtask.getVisitDeptCode()))) { serviceSubtaskStatistic.setAgainFollowUpPushCount(serviceSubtaskStatistic.getAgainFollowUpPushCount() + 1L); } //人工已拨通总量 if (ObjectUtils.isNotEmpty(serviceSubtask.getIsManuallyCalled()) && serviceSubtask.getIsManuallyCalled().equals(1L)) { serviceSubtaskStatistic.setManuallyCalled(serviceSubtaskStatistic.getManuallyCalled() + 1L); } //首次出院随访 if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() == 1) { applyFirstFollowUpExtraStatistics(serviceSubtaskStatistic, serviceSubtask); //首次应随访 if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L)) { serviceSubtaskStatistic.setNeedFollowUp(serviceSubtaskStatistic.getNeedFollowUp() + 1L); } //首次无需随访 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(4L)) { serviceSubtaskStatistic.setNonFollowUpFirst(serviceSubtaskStatistic.getNonFollowUpFirst() + 1L); } //首次随访失败(包括随访失败+人工超时) if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(5L) || serviceSubtask.getSendstate().equals(7L))) { serviceSubtaskStatistic.setFollowUpFail(serviceSubtaskStatistic.getFollowUpFail() + 1L); } /** * 不同统计方式下不同的随访成功数 参数 followUpCountStyle 控制 */ if (StringUtils.isNotEmpty(followUpCountStyle) && followUpCountStyle.equals("1")) { //首次随访成功 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(6L))) { serviceSubtaskStatistic.setFollowUpSuccess(serviceSubtaskStatistic.getFollowUpSuccess() + 1L); } //首次无需随访 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(4L))) { serviceSubtaskStatistic.setNonFollowUpFirst(serviceSubtaskStatistic.getNonFollowUpFirst() + 1L); } //首次随访人工 (不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManual(serviceSubtaskStatistic.getManual() + 1L); } //首次随访语音 (不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoice(serviceSubtaskStatistic.getVoice() + 1L); } //首次随访短信(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSms(serviceSubtaskStatistic.getSms() + 1L); } //首次随访微信(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L); } } else if (StringUtils.isNotEmpty(followUpCountStyle) && followUpCountStyle.equals("3")) { //首次随访成功 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(6L))) { serviceSubtaskStatistic.setFollowUpSuccess(serviceSubtaskStatistic.getFollowUpSuccess() + 1L); } //首次无需随访 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(4L))) { serviceSubtaskStatistic.setNonFollowUpFirst(serviceSubtaskStatistic.getNonFollowUpFirst() + 1L); } //首次随访人工 (只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManual(serviceSubtaskStatistic.getManual() + 1L); } //首次随访语音 (只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoice(serviceSubtaskStatistic.getVoice() + 1L); } //首次随访短信(只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSms(serviceSubtaskStatistic.getSms() + 1L); } //首次随访微信(只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L); } } else { //首次随访成功 - 统计时候加上不执行的,已发送的 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(6L) || serviceSubtask.getSendstate().equals(3L) || serviceSubtask.getSendstate().equals(4L))) { serviceSubtaskStatistic.setFollowUpSuccess(serviceSubtaskStatistic.getFollowUpSuccess() + 1L); } //首次无需随访 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(4L))) { serviceSubtaskStatistic.setNonFollowUpFirst(serviceSubtaskStatistic.getNonFollowUpFirst() + 1L); } //首次随访人工 (统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManual(serviceSubtaskStatistic.getManual() + 1L); } //首次随访语音 (统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoice(serviceSubtaskStatistic.getVoice() + 1L); } //首次随访短信(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSms(serviceSubtaskStatistic.getSms() + 1L); } //首次随访微信(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L); } } //首次随访人工成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualSuccess(serviceSubtaskStatistic.getManualSuccess() + 1L); } //首次随访语音成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceSuccess(serviceSubtaskStatistic.getVoiceSuccess() + 1L); } //首次随访短信成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsSuccess(serviceSubtaskStatistic.getSmsSuccess() + 1L); } //首次随访微信成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatSuccess(serviceSubtaskStatistic.getWeChatSuccess() + 1L); } if (serviceSubtaskStatistic.getNeedFollowUp() > 0) { double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccess() + serviceSubtaskStatistic.getFollowUpFail()) / serviceSubtaskStatistic.getNeedFollowUp(); serviceSubtaskStatistic.setFollowUpRate(percentFormat.format(rate)); } else { serviceSubtaskStatistic.setFollowUpRate("0.00%"); } //结果异常 if (serviceSubtask.getSendstate() != null && serviceSubtask.getExcep().equals("1")) { serviceSubtaskStatistic.setAbnormal(serviceSubtaskStatistic.getAbnormal() + 1L); } }//二次出院随访 else if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() > 1) { applyAgainFollowUpExtraStatistics(serviceSubtaskStatistic, serviceSubtask); //再次应随访 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setNeedFollowUpAgain(serviceSubtaskStatistic.getNeedFollowUpAgain() + 1L); } //再次无需随访 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 4) { serviceSubtaskStatistic.setNonFollowUpAgain(serviceSubtaskStatistic.getNonFollowUpAgain() + 1L); } //再次待随访 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 2) { serviceSubtaskStatistic.setPendingFollowUpAgain(serviceSubtaskStatistic.getPendingFollowUpAgain() + 1L); } //再次随访失败 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 5) { serviceSubtaskStatistic.setFollowUpFailAgain(serviceSubtaskStatistic.getFollowUpFailAgain() + 1L); } /** * 不同统计方式下不同的随访成功数 参数 followUpCountStyle 控制 */ if (StringUtils.isNotEmpty(followUpCountStyle) && followUpCountStyle.equals("1")) { //再次随访成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L)) { serviceSubtaskStatistic.setFollowUpSuccessAgain(serviceSubtaskStatistic.getFollowUpSuccessAgain() + 1L); } //再次随访人工(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgain(serviceSubtaskStatistic.getManualAgain() + 1L); } //再次随访语音(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceAgain(serviceSubtaskStatistic.getVoiceAgain() + 1L); } //再次随访短信(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgain(serviceSubtaskStatistic.getSmsAgain() + 1L); } //再次随访微信(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L); } } else if (StringUtils.isNotEmpty(followUpCountStyle) && followUpCountStyle.equals("3")) { //再次随访成功 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(6L))) { serviceSubtaskStatistic.setFollowUpSuccessAgain(serviceSubtaskStatistic.getFollowUpSuccessAgain() + 1L); } //再次随访人工 (只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgain(serviceSubtaskStatistic.getManualAgain() + 1L); } //再次随访语音 (只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceAgain(serviceSubtaskStatistic.getVoiceAgain() + 1L); } //再次随访短信(只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgain(serviceSubtaskStatistic.getSmsAgain() + 1L); } //再次随访微信(只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L); } } else { //再次随访成功 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(1L) || serviceSubtask.getSendstate().equals(6L) || serviceSubtask.getSendstate().equals(3L) || serviceSubtask.getSendstate().equals(4L))) { serviceSubtaskStatistic.setFollowUpSuccessAgain(serviceSubtaskStatistic.getFollowUpSuccessAgain() + 1L); } //再次随访人工(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgain(serviceSubtaskStatistic.getManualAgain() + 1L); } //再次随访语音(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceAgain(serviceSubtaskStatistic.getVoiceAgain() + 1L); } //再次随访短信(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgain(serviceSubtaskStatistic.getSmsAgain() + 1L); } //再次随访微信(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L); } } //再次随访人工成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgainSuccess(serviceSubtaskStatistic.getManualAgainSuccess() + 1L); } //再次随访语音成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceAgainSuccess(serviceSubtaskStatistic.getVoiceAgainSuccess() + 1L); } //再次随访短信成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgainSuccess(serviceSubtaskStatistic.getSmsAgainSuccess() + 1L); } //再次随访微信成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgainSuccess(serviceSubtaskStatistic.getWeChatAgainSuccess() + 1L); } if (serviceSubtaskStatistic.getNeedFollowUp() > 0) { double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccessAgain() + serviceSubtaskStatistic.getFollowUpFailAgain()) / serviceSubtaskStatistic.getNeedFollowUpAgain(); serviceSubtaskStatistic.setFollowUpRateAgain(percentFormat.format(rate)); } else { serviceSubtaskStatistic.setFollowUpRateAgain("0.00%"); } //再次异常 if (serviceSubtask.getSendstate() != null && serviceSubtask.getExcep().equals("1")) { serviceSubtaskStatistic.setAbnormalAgain(serviceSubtaskStatistic.getAbnormalAgain() + 1L); } } //随访情况 if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 1) { serviceSubtaskStatistic.setTaskSituation1(serviceSubtaskStatistic.getTaskSituation1() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 2) { serviceSubtaskStatistic.setTaskSituation2(serviceSubtaskStatistic.getTaskSituation2() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 3) { serviceSubtaskStatistic.setTaskSituation3(serviceSubtaskStatistic.getTaskSituation3() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 4) { serviceSubtaskStatistic.setTaskSituation4(serviceSubtaskStatistic.getTaskSituation4() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 5) { serviceSubtaskStatistic.setTaskSituation5(serviceSubtaskStatistic.getTaskSituation5() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 7) { serviceSubtaskStatistic.setTaskSituation6(serviceSubtaskStatistic.getTaskSituation6() + 1); } } return serviceSubtaskStatistic; } return serviceSubtaskStatistic; } /** * 是否属于「及时随访」:随访已完成且完成时状态为正常完成(未超时)。 *

* finish_state:1-正常完成 2-延期完成 3-超时完成,只有 1 计入及时随访。 * * @param serviceSubtask 随访子任务 * @return true-计入及时随访人次 */ private boolean isTimelyFollowUp(ServiceSubtask serviceSubtask) { return serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && serviceSubtask.getFinishState() != null && serviceSubtask.getFinishState().equals(1L); } /** * 市一统计口径:首次待随访、已发送及人工电话超时。 */ private void applyFirstFollowUpExtraStatistics(ServiceSubtaskStatistic statistic, ServiceSubtask serviceSubtask) { if (serviceSubtask.getVisitCount() == null || serviceSubtask.getVisitCount() != 1 || serviceSubtask.getSendstate() == null) { return; } Long sendstate = serviceSubtask.getSendstate(); if (sendstate.equals(3L)) { statistic.setSent(statistic.getSent() + 1L); } if (sendstate.equals(7L) && isManuallyNotCalled(serviceSubtask)) { statistic.setManualCallTimeout(statistic.getManualCallTimeout() + 1L); } if (sendstate.equals(1L) || sendstate.equals(2L) || sendstate.equals(3L) || sendstate.equals(7L)) { statistic.setPendingFollowUpAll(statistic.getPendingFollowUpAll() + 1L); } if (sendstate.equals(1L) || sendstate.equals(2L)) { statistic.setPendingFollowUpWaitSend(statistic.getPendingFollowUpWaitSend() + 1L); } if (sendstate.equals(3L) || sendstate.equals(7L)) { statistic.setPendingFollowUpSent(statistic.getPendingFollowUpSent() + 1L); } } /** * 再次随访附加统计:待随访、已发送、人工电话超时及回院复诊复查(suggest=7)。 */ private void applyAgainFollowUpExtraStatistics(ServiceSubtaskStatistic statistic, ServiceSubtask serviceSubtask) { if (serviceSubtask.getVisitCount() == null || serviceSubtask.getVisitCount() <= 1) { return; } if (serviceSubtask.getSendstate() == null) { return; } Long sendstate = serviceSubtask.getSendstate(); // 回院复诊复查:再次随访中按处理意见 suggest=7 统计 if (StringUtils.equals("7", StringUtils.trim(serviceSubtask.getSuggest()))) { statistic.setSuggest7CountAgain(statistic.getSuggest7CountAgain() + 1L); } if (sendstate.equals(3L)) { statistic.setSentAgain(statistic.getSentAgain() + 1L); } if (sendstate.equals(7L) && isManuallyNotCalled(serviceSubtask)) { statistic.setManualCallTimeoutAgain(statistic.getManualCallTimeoutAgain() + 1L); } if (sendstate.equals(1L) || sendstate.equals(2L) || sendstate.equals(3L) || sendstate.equals(7L)) { statistic.setPendingFollowUpAllAgain(statistic.getPendingFollowUpAllAgain() + 1L); } if (sendstate.equals(1L) || sendstate.equals(2L)) { statistic.setPendingFollowUpWaitSendAgain(statistic.getPendingFollowUpWaitSendAgain() + 1L); } if (sendstate.equals(3L) || sendstate.equals(7L)) { statistic.setPendingFollowUpSentAgain(statistic.getPendingFollowUpSentAgain() + 1L); } } private boolean isManuallyNotCalled(ServiceSubtask serviceSubtask) { return serviceSubtask.getIsManuallyCalled() != null && serviceSubtask.getIsManuallyCalled().equals(0L); } /** * 首次随访统计 * * @param serviceSubtaskList * @param followUpCountStyle * @return */ private ServiceSubtaskStatistic getStatisticFirst(List serviceSubtaskList, String followUpCountStyle) { ServiceSubtaskStatistic serviceSubtaskStatistic = new ServiceSubtaskStatistic(); //格式化为两位小数的百分比 DecimalFormat percentFormat = new DecimalFormat("##.##%"); serviceSubtaskStatistic.setDeptname(serviceSubtaskList.get(0).getLeaveldeptname()); serviceSubtaskStatistic.setDeptcode(serviceSubtaskList.get(0).getLeaveldeptcode()); serviceSubtaskStatistic.setLeavehospitaldistrictname(serviceSubtaskList.get(0).getLeavehospitaldistrictname()); serviceSubtaskStatistic.setLeavehospitaldistrictcode(serviceSubtaskList.get(0).getLeavehospitaldistrictcode()); serviceSubtaskStatistic.setDrcode(serviceSubtaskList.get(0).getDrcode()); serviceSubtaskStatistic.setDrname(serviceSubtaskList.get(0).getDrname()); //出院人次 serviceSubtaskStatistic.setDischargeCount(serviceSubtaskList.size()); for (ServiceSubtask serviceSubtask : serviceSubtaskList) { applyFirstFollowUpExtraStatistics(serviceSubtaskStatistic, serviceSubtask); //无需随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 4) { serviceSubtaskStatistic.setNonFollowUp(serviceSubtaskStatistic.getNonFollowUp() + 1L); if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 6) { serviceSubtaskStatistic.setFilterCount(serviceSubtaskStatistic.getFilterCount() + 1L); } } //应随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); } //及时随访人次:已完成且未超时 if (isTimelyFollowUp(serviceSubtask)) { serviceSubtaskStatistic.setTimelyFollowUp(serviceSubtaskStatistic.getTimelyFollowUp() + 1L); } //首次出院随访 if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() == 1) { //首次应随访 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setNeedFollowUp(serviceSubtaskStatistic.getNeedFollowUp() + 1L); } //首次无需随访 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(4L))) { serviceSubtaskStatistic.setNonFollowUpFirst(serviceSubtaskStatistic.getNonFollowUpFirst() + 1L); } //首次待随访 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 2) { serviceSubtaskStatistic.setPendingFollowUp(serviceSubtaskStatistic.getPendingFollowUp() + 1L); } //首次随访失败(包括随访失败+人工超时) if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate() == 5 || serviceSubtask.getSendstate() == 7)) { serviceSubtaskStatistic.setFollowUpFail(serviceSubtaskStatistic.getFollowUpFail() + 1L); } /** * 不同统计方式下不同的随访成功数 参数 followUpCountStyle 控制 */ if (StringUtils.isNotEmpty(followUpCountStyle) && followUpCountStyle.equals("1")) { //首次随访成功 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(6L))) { serviceSubtaskStatistic.setFollowUpSuccess(serviceSubtaskStatistic.getFollowUpSuccess() + 1L); } //首次随访人工 (不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManual(serviceSubtaskStatistic.getManual() + 1L); } //首次随访语音 (不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoice(serviceSubtaskStatistic.getVoice() + 1L); } //首次随访短信(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSms(serviceSubtaskStatistic.getSms() + 1L); } //首次随访微信(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L); } } else if (StringUtils.isNotEmpty(followUpCountStyle) && followUpCountStyle.equals("3")) { //首次随访成功 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(6L))) { serviceSubtaskStatistic.setFollowUpSuccess(serviceSubtaskStatistic.getFollowUpSuccess() + 1L); } //首次随访人工 (只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManual(serviceSubtaskStatistic.getManual() + 1L); } //首次随访语音 (只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoice(serviceSubtaskStatistic.getVoice() + 1L); } //首次随访短信(只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSms(serviceSubtaskStatistic.getSms() + 1L); } //首次随访微信(只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L); } } else { //首次随访成功 - 统计时候加上不执行的,已发送的 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(6L) || serviceSubtask.getSendstate().equals(3L) || serviceSubtask.getSendstate().equals(4L))) { serviceSubtaskStatistic.setFollowUpSuccess(serviceSubtaskStatistic.getFollowUpSuccess() + 1L); } //首次随访人工 (统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManual(serviceSubtaskStatistic.getManual() + 1L); } //首次随访语音 (统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoice(serviceSubtaskStatistic.getVoice() + 1L); } //首次随访短信(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSms(serviceSubtaskStatistic.getSms() + 1L); } //首次随访微信(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L); } } //首次随访人工成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualSuccess(serviceSubtaskStatistic.getManualSuccess() + 1L); } //首次随访语音成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceSuccess(serviceSubtaskStatistic.getVoiceSuccess() + 1L); } //首次随访短信成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsSuccess(serviceSubtaskStatistic.getSmsSuccess() + 1L); } //首次随访微信成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatSuccess(serviceSubtaskStatistic.getWeChatSuccess() + 1L); } if (serviceSubtaskStatistic.getNeedFollowUp() > 0) { double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccess() + serviceSubtaskStatistic.getFollowUpFail()) / serviceSubtaskStatistic.getNeedFollowUp(); serviceSubtaskStatistic.setFollowUpRate(percentFormat.format(rate)); } else { serviceSubtaskStatistic.setFollowUpRate("0.00%"); } //结果异常 if (serviceSubtask.getSendstate() != null && serviceSubtask.getExcep().equals("1")) { serviceSubtaskStatistic.setAbnormal(serviceSubtaskStatistic.getAbnormal() + 1L); } } //随访情况 if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 1) { serviceSubtaskStatistic.setTaskSituation1(serviceSubtaskStatistic.getTaskSituation1() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 2) { serviceSubtaskStatistic.setTaskSituation2(serviceSubtaskStatistic.getTaskSituation2() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 3) { serviceSubtaskStatistic.setTaskSituation3(serviceSubtaskStatistic.getTaskSituation3() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 4) { serviceSubtaskStatistic.setTaskSituation4(serviceSubtaskStatistic.getTaskSituation4() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 5) { serviceSubtaskStatistic.setTaskSituation5(serviceSubtaskStatistic.getTaskSituation5() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 7) { serviceSubtaskStatistic.setTaskSituation6(serviceSubtaskStatistic.getTaskSituation6() + 1); } } return serviceSubtaskStatistic; } /** * 再次随访统计 * * @param serviceSubtaskList * @param followUpCountStyle * @return */ private ServiceSubtaskStatistic getStatisticAgain(List serviceSubtaskList, String followUpCountStyle) { ServiceSubtaskStatistic serviceSubtaskStatistic = new ServiceSubtaskStatistic(); //格式化为两位小数的百分比 DecimalFormat percentFormat = new DecimalFormat("##.##%"); serviceSubtaskStatistic.setDeptname(serviceSubtaskList.get(0).getLeaveldeptname()); serviceSubtaskStatistic.setDeptcode(serviceSubtaskList.get(0).getLeaveldeptcode()); serviceSubtaskStatistic.setLeavehospitaldistrictname(serviceSubtaskList.get(0).getLeavehospitaldistrictname()); serviceSubtaskStatistic.setLeavehospitaldistrictcode(serviceSubtaskList.get(0).getLeavehospitaldistrictcode()); serviceSubtaskStatistic.setDrcode(serviceSubtaskList.get(0).getDrcode()); serviceSubtaskStatistic.setDrname(serviceSubtaskList.get(0).getDrname()); //出院人次 serviceSubtaskStatistic.setDischargeCount(serviceSubtaskList.size()); for (ServiceSubtask serviceSubtask : serviceSubtaskList) { applyAgainFollowUpExtraStatistics(serviceSubtaskStatistic, serviceSubtask); //无需随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 4) { serviceSubtaskStatistic.setNonFollowUp(serviceSubtaskStatistic.getNonFollowUp() + 1L); if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 6) { serviceSubtaskStatistic.setFilterCount(serviceSubtaskStatistic.getFilterCount() + 1L); } } //应随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); } //及时随访人次:已完成且未超时 if (isTimelyFollowUp(serviceSubtask)) { serviceSubtaskStatistic.setTimelyFollowUp(serviceSubtaskStatistic.getTimelyFollowUp() + 1L); } //再次出院随访 if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() > 1) { //再次应随访 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setNeedFollowUpAgain(serviceSubtaskStatistic.getNeedFollowUpAgain() + 1L); } //再次无需随访 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 4) { serviceSubtaskStatistic.setNonFollowUpAgain(serviceSubtaskStatistic.getNonFollowUpAgain() + 1L); } //再次待随访 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 2) { serviceSubtaskStatistic.setPendingFollowUpAgain(serviceSubtaskStatistic.getPendingFollowUpAgain() + 1L); } //再次随访失败 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 5) { serviceSubtaskStatistic.setFollowUpFailAgain(serviceSubtaskStatistic.getFollowUpFailAgain() + 1L); } /** * 不同统计方式下不同的随访成功数 参数 followUpCountStyle 控制 */ if (StringUtils.isNotEmpty(followUpCountStyle) && followUpCountStyle.equals("1")) { //再次随访成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L)) { serviceSubtaskStatistic.setFollowUpSuccessAgain(serviceSubtaskStatistic.getFollowUpSuccessAgain() + 1L); } //再次随访人工(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgain(serviceSubtaskStatistic.getManualAgain() + 1L); } //再次随访语音(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceAgain(serviceSubtaskStatistic.getVoiceAgain() + 1L); } //再次随访短信(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgain(serviceSubtaskStatistic.getSmsAgain() + 1L); } //再次随访微信(不统计不执行) if (serviceSubtask.getSendstate() != null && !serviceSubtask.getSendstate().equals(4L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L); } } else if (StringUtils.isNotEmpty(followUpCountStyle) && followUpCountStyle.equals("3")) { //再次随访成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L)) { serviceSubtaskStatistic.setFollowUpSuccessAgain(serviceSubtaskStatistic.getFollowUpSuccessAgain() + 1L); } //再次随访人工 (只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgain(serviceSubtaskStatistic.getManualAgain() + 1L); } //再次随访语音 (只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceAgain(serviceSubtaskStatistic.getVoiceAgain() + 1L); } //再次随访短信(只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgain(serviceSubtaskStatistic.getSmsAgain() + 1L); } //首次随访微信(只统计已完成) if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L); } } else { //再次随访成功 if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate().equals(1L) || serviceSubtask.getSendstate().equals(6L) || serviceSubtask.getSendstate().equals(3L) || serviceSubtask.getSendstate().equals(4L))) { serviceSubtaskStatistic.setFollowUpSuccessAgain(serviceSubtaskStatistic.getFollowUpSuccessAgain() + 1L); } //再次随访人工(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgain(serviceSubtaskStatistic.getManualAgain() + 1L); } //再次随访语音(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceAgain(serviceSubtaskStatistic.getVoiceAgain() + 1L); } //再次随访短信(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgain(serviceSubtaskStatistic.getSmsAgain() + 1L); } //再次随访微信(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L); } } //再次随访人工成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgainSuccess(serviceSubtaskStatistic.getManualAgainSuccess() + 1L); } //再次随访语音成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceAgainSuccess(serviceSubtaskStatistic.getVoiceAgainSuccess() + 1L); } //再次随访短信成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgainSuccess(serviceSubtaskStatistic.getSmsAgainSuccess() + 1L); } //再次随访微信成功 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgainSuccess(serviceSubtaskStatistic.getWeChatAgainSuccess() + 1L); } if (serviceSubtaskStatistic.getNeedFollowUp() > 0) { double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccessAgain() + serviceSubtaskStatistic.getFollowUpFailAgain()) / serviceSubtaskStatistic.getNeedFollowUpAgain(); serviceSubtaskStatistic.setFollowUpRateAgain(percentFormat.format(rate)); } else { serviceSubtaskStatistic.setFollowUpRateAgain("0.00%"); } //再次异常 if (serviceSubtask.getSendstate() != null && serviceSubtask.getExcep().equals("1")) { serviceSubtaskStatistic.setAbnormalAgain(serviceSubtaskStatistic.getAbnormalAgain() + 1L); } } //随访情况 if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 1) { serviceSubtaskStatistic.setTaskSituation1(serviceSubtaskStatistic.getTaskSituation1() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 2) { serviceSubtaskStatistic.setTaskSituation2(serviceSubtaskStatistic.getTaskSituation2() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 3) { serviceSubtaskStatistic.setTaskSituation3(serviceSubtaskStatistic.getTaskSituation3() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 4) { serviceSubtaskStatistic.setTaskSituation4(serviceSubtaskStatistic.getTaskSituation4() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 5) { serviceSubtaskStatistic.setTaskSituation5(serviceSubtaskStatistic.getTaskSituation5() + 1); } if (serviceSubtask.getTaskSituation() != null && serviceSubtask.getTaskSituation() == 7) { serviceSubtaskStatistic.setTaskSituation6(serviceSubtaskStatistic.getTaskSituation6() + 1); } } return serviceSubtaskStatistic; } private ServiceSubtaskStatistic getStatisticJoy(List serviceSubtaskList, List joySubCount) { ServiceSubtaskStatistic serviceSubtaskStatistic = new ServiceSubtaskStatistic(); //格式化为两位小数的百分比 DecimalFormat percentFormat = new DecimalFormat("##.##%"); serviceSubtaskStatistic.setDeptname(serviceSubtaskList.get(0).getLeaveldeptname()); serviceSubtaskStatistic.setDeptcode(serviceSubtaskList.get(0).getLeaveldeptcode()); serviceSubtaskStatistic.setLeavehospitaldistrictname(serviceSubtaskList.get(0).getLeavehospitaldistrictname()); serviceSubtaskStatistic.setLeavehospitaldistrictcode(serviceSubtaskList.get(0).getLeavehospitaldistrictcode()); serviceSubtaskStatistic.setDrcode(serviceSubtaskList.get(0).getDrcode()); serviceSubtaskStatistic.setDrname(serviceSubtaskList.get(0).getDrname()); //出院人次 serviceSubtaskStatistic.setDischargeCount(serviceSubtaskList.size()); //出院人次详情 serviceSubtaskStatistic.setDischargeCountInfo(serviceSubtaskList); serviceSubtaskStatistic.setJoyCount(0); serviceSubtaskStatistic.setJoyAllCount(0); for (ServiceSubtask serviceSubtask : serviceSubtaskList) { //满意度 List joyCountTemp = joySubCount.stream().filter(r -> r.getSubTaskId().equals(serviceSubtask.getId())).collect(Collectors.toList()); if (joyCountTemp != null && joyCountTemp.size() > 0) { if (ObjectUtils.isNotEmpty(joyCountTemp.get(0).getJoyCount())) serviceSubtaskStatistic.setJoyCount(serviceSubtaskStatistic.getJoyCount() + joyCountTemp.get(0).getJoyCount()); if (ObjectUtils.isNotEmpty(joyCountTemp.get(0).getJoyAllCount())) serviceSubtaskStatistic.setJoyAllCount(serviceSubtaskStatistic.getJoyAllCount() + joyCountTemp.get(0).getJoyAllCount()); } //无需随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 4) { serviceSubtaskStatistic.setNonFollowUp(serviceSubtaskStatistic.getNonFollowUp() + 1L); } //应随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); } //首次出院随访 if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() == 1) { if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setNeedFollowUp(serviceSubtaskStatistic.getNeedFollowUp() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 2) { serviceSubtaskStatistic.setPendingFollowUp(serviceSubtaskStatistic.getPendingFollowUp() + 1L); } if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate() == 6)) { serviceSubtaskStatistic.setFollowUpSuccess(serviceSubtaskStatistic.getFollowUpSuccess() + 1L); } if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate() == 5 || serviceSubtask.getSendstate() == 7)) { serviceSubtaskStatistic.setFollowUpFail(serviceSubtaskStatistic.getFollowUpFail() + 1L); } if (serviceSubtaskStatistic.getNeedFollowUp() > 0) { double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccess() + serviceSubtaskStatistic.getFollowUpFail()) / serviceSubtaskStatistic.getNeedFollowUp(); serviceSubtaskStatistic.setFollowUpRate(percentFormat.format(rate)); } else { serviceSubtaskStatistic.setFollowUpRate("0.00%"); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManual(serviceSubtaskStatistic.getManual() + 1L); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSms(serviceSubtaskStatistic.getSms() + 1L); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getExcep().equals("1")) { serviceSubtaskStatistic.setAbnormal(serviceSubtaskStatistic.getAbnormal() + 1L); } }//二次出院随访 else if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() > 1) { if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setNeedFollowUpAgain(serviceSubtaskStatistic.getNeedFollowUpAgain() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 2) { serviceSubtaskStatistic.setPendingFollowUpAgain(serviceSubtaskStatistic.getPendingFollowUpAgain() + 1L); } if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate() == 1 || serviceSubtask.getSendstate() == 3 || serviceSubtask.getSendstate() == 6)) { serviceSubtaskStatistic.setFollowUpSuccessAgain(serviceSubtaskStatistic.getFollowUpSuccessAgain() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 5) { serviceSubtaskStatistic.setFollowUpFailAgain(serviceSubtaskStatistic.getFollowUpFailAgain() + 1L); } if (serviceSubtaskStatistic.getNeedFollowUp() > 0) { double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccessAgain() + serviceSubtaskStatistic.getFollowUpFailAgain()) / serviceSubtaskStatistic.getNeedFollowUpAgain(); serviceSubtaskStatistic.setFollowUpRateAgain(percentFormat.format(rate)); } else { serviceSubtaskStatistic.setFollowUpRateAgain("0.00%"); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgain(serviceSubtaskStatistic.getManualAgain() + 1L); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgain(serviceSubtaskStatistic.getSmsAgain() + 1L); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getExcep().equals("1")) { serviceSubtaskStatistic.setAbnormalAgain(serviceSubtaskStatistic.getAbnormalAgain() + 1L); } } } return serviceSubtaskStatistic; } private ServiceSubtaskStatistic getStatisticCategory(List serviceSubtaskList, ServiceSubtaskCountReq serviceSubtaskCountReq, List subCounts) { ServiceSubtaskStatistic serviceSubtaskStatistic = new ServiceSubtaskStatistic(); //格式化为两位小数的百分比 DecimalFormat percentFormat = new DecimalFormat("##.##%"); serviceSubtaskStatistic.setDeptname(serviceSubtaskList.get(0).getLeaveldeptname()); serviceSubtaskStatistic.setDeptcode(serviceSubtaskList.get(0).getLeaveldeptcode()); serviceSubtaskStatistic.setLeavehospitaldistrictname(serviceSubtaskList.get(0).getLeavehospitaldistrictname()); serviceSubtaskStatistic.setLeavehospitaldistrictcode(serviceSubtaskList.get(0).getLeavehospitaldistrictcode()); serviceSubtaskStatistic.setDrcode(serviceSubtaskList.get(0).getDrcode()); serviceSubtaskStatistic.setDrname(serviceSubtaskList.get(0).getDrname()); serviceSubtaskStatistic.setJoyCount(0); serviceSubtaskStatistic.setJoyAllCount(0); //出院人次 serviceSubtaskStatistic.setDischargeCount(serviceSubtaskList.size()); //获取随访统计 if (subCounts == null) { subCounts = new ArrayList<>(); } for (ServiceSubtask serviceSubtask : serviceSubtaskList) { List subCountTemp = subCounts.stream().filter(r -> r.getSubTaskId().equals(serviceSubtask.getId())).collect(Collectors.toList()); //统计 if (subCountTemp != null && subCountTemp.size() > 0) { if (ObjectUtils.isNotEmpty(subCountTemp.get(0).getJoyCount())) serviceSubtaskStatistic.setJoyCount(serviceSubtaskStatistic.getJoyCount() + subCountTemp.get(0).getJoyCount()); if (ObjectUtils.isNotEmpty(subCountTemp.get(0).getJoyAllCount())) serviceSubtaskStatistic.setJoyAllCount(serviceSubtaskStatistic.getJoyAllCount() + subCountTemp.get(0).getJoyAllCount()); } //无需随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 4) { serviceSubtaskStatistic.setNonFollowUp(serviceSubtaskStatistic.getNonFollowUp() + 1L); } //应随访人次 if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); } //首次出院随访 if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() == 1) { if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setNeedFollowUp(serviceSubtaskStatistic.getNeedFollowUp() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 2) { serviceSubtaskStatistic.setPendingFollowUp(serviceSubtaskStatistic.getPendingFollowUp() + 1L); } if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate() == 6)) { serviceSubtaskStatistic.setFollowUpSuccess(serviceSubtaskStatistic.getFollowUpSuccess() + 1L); } if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate() == 5 || serviceSubtask.getSendstate() == 7)) { serviceSubtaskStatistic.setFollowUpFail(serviceSubtaskStatistic.getFollowUpFail() + 1L); } if (serviceSubtaskStatistic.getNeedFollowUp() > 0) { double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccess() + serviceSubtaskStatistic.getFollowUpFail()) / serviceSubtaskStatistic.getNeedFollowUp(); serviceSubtaskStatistic.setFollowUpRate(percentFormat.format(rate)); } else { serviceSubtaskStatistic.setFollowUpRate("0.00%"); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManual(serviceSubtaskStatistic.getManual() + 1L); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoice(serviceSubtaskStatistic.getVoice() + 1L); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSms(serviceSubtaskStatistic.getSms() + 1L); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getExcep().equals("1")) { serviceSubtaskStatistic.setAbnormal(serviceSubtaskStatistic.getAbnormal() + 1L); } }//二次出院随访 else if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() > 1) { if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { serviceSubtaskStatistic.setNeedFollowUpAgain(serviceSubtaskStatistic.getNeedFollowUpAgain() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 2) { serviceSubtaskStatistic.setPendingFollowUpAgain(serviceSubtaskStatistic.getPendingFollowUpAgain() + 1L); } if (serviceSubtask.getSendstate() != null && (serviceSubtask.getSendstate() == 1 || serviceSubtask.getSendstate() == 3 || serviceSubtask.getSendstate() == 6)) { serviceSubtaskStatistic.setFollowUpSuccessAgain(serviceSubtaskStatistic.getFollowUpSuccessAgain() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 5) { serviceSubtaskStatistic.setFollowUpFailAgain(serviceSubtaskStatistic.getFollowUpFailAgain() + 1L); } if (serviceSubtaskStatistic.getNeedFollowUp() > 0) { double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccessAgain() + serviceSubtaskStatistic.getFollowUpFailAgain()) / serviceSubtaskStatistic.getNeedFollowUpAgain(); serviceSubtaskStatistic.setFollowUpRateAgain(percentFormat.format(rate)); } else { serviceSubtaskStatistic.setFollowUpRateAgain("0.00%"); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) { serviceSubtaskStatistic.setManualAgain(serviceSubtaskStatistic.getManualAgain() + 1L); } //再次随访语音(统计不执行) if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) { serviceSubtaskStatistic.setVoiceAgain(serviceSubtaskStatistic.getVoiceAgain() + 1L); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) { serviceSubtaskStatistic.setSmsAgain(serviceSubtaskStatistic.getSmsAgain() + 1L); } if (serviceSubtask.getSendstate() != null && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) { serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L); } if (serviceSubtask.getSendstate() != null && serviceSubtask.getExcep().equals("1")) { serviceSubtaskStatistic.setAbnormalAgain(serviceSubtaskStatistic.getAbnormalAgain() + 1L); } } } return serviceSubtaskStatistic; } public List getSfStatisticsJoydetails(ServiceSubtaskCountReq serviceSubtaskCountReq) { return serviceSubtaskMapper.getSfStatisticsJoydetails(serviceSubtaskCountReq); } /** * 获取随访统计超链接 * dischargeCountInfo * followUpNeededAllInfo - sendstate != 4 (1,2,3,5,6,7) * firstDischargeCountInfo - visitCount = 1 * againFollowUpPushCountInfo - visitCount = 2 && visitDeptCode = sys.smartor.center.dept(随访中心科室) * nonFollowUpInfo - sendstate = 4 * needFollowUpInfo - visitCount = 1 && sendstate != 4 * pendingFollowUpInfo - visitCount = 1 && sendstate = 2 * followUpSuccessInfo - visitCount = 1 && sendstate = 6 * followUpFailInfo - visitCount = 1 && (sendstate = 5 || sendstate = 7) * timelyFollowUpInfo - sendstate = 6 && finish_state = 1(沿用请求的 visitCount 口径) * manualInfo - visitCount = 1 && currentPreachForm = "1" * voiceInfo - visitCount = 1 && currentPreachForm = "3" * smsInfo - visitCount = 1 && currentPreachForm = "4" * wechatInfo - visitCount = 1 && currentPreachForm = "5" * manualSuccessInfo - visitCount = 1 && currentPreachForm = "1" && sendstate = 6 * voiceSuccessInfo - visitCount = 1 && currentPreachForm = "3" && sendstate = 6 * smsSuccessInfo - visitCount = 1 && currentPreachForm = "4" && sendstate = 6 * wechatSuccessInfo - visitCount = 1 && currentPreachForm = "5" && sendstate = 6 * abnormalInfo - visitCount = 1 && excep = "1" * needFollowUpAgainInfo - visitCount > 1 && sendstate != 4 * pendingFollowUpAgainInfo - visitCount > 1 && sendstate = 2 * followUpSuccessAgainInfo - visitCount > 1 && sendstate =6 * followUpFailAgainInfo - visitCount > 1 && (sendstate = 5 || sendstate = 7) * manualAgainInfo - visitCount > 1 && currentPreachForm = "1" * voiceAgainInfo - visitCount > 1 && currentPreachForm = "3" * smsAgainInfo - visitCount > 1 && currentPreachForm = "4" * wechatAgainInfo - visitCount > 1 && currentPreachForm = "5" * manualAgainSuccessInfo - visitCount > 1 && currentPreachForm = "1" && sendstate = 6 * voiceAgainSuccessInfo - visitCount > 1 && currentPreachForm = "3" && sendstate = 6 * smsAgainSuccessInfo - visitCount > 1 && currentPreachForm = "4" && sendstate = 6 * wechatAgainSuccessInfo - visitCount > 1&& currentPreachForm = "5" && sendstate = 6 * abnormalAgainInfo- visitCount = 1 && excep = "1" * taskSituation1Info - taskSituation = 1 * taskSituation2Info - taskSituation = 2 * taskSituation3Info - taskSituation = 3 * taskSituation4Info - taskSituation = 4 * taskSituation5Info - taskSituation = 5 * taskSituation6Info - taskSituation = 7 * manuallyCalledInfo - isManuallyCalled = 1L * manualCallTimeoutInfo - visitCount = 1 && sendstate = 7 && isManuallyCalled = 0 * manualCallTimeoutAgainInfo - visitCount > 1 && sendstate = 7 && isManuallyCalled = 0 * pendingFollowUpAllInfo - visitCount = 1 && sendstate in (1,2,3,7) * pendingFollowUpAllAgainInfo - visitCount > 1 && sendstate in (1,2,3,7) * pendingFollowUpWaitSendInfo - visitCount = 1 && sendstate in (1,2) * pendingFollowUpWaitSendAgainInfo - visitCount > 1 && sendstate in (1,2) * pendingFollowUpSentInfo - visitCount = 1 && sendstate in (3,7) * pendingFollowUpSentAgainInfo - visitCount > 1 && sendstate in (3,7) * sentInfo - visitCount = 1 && sendstate = 3 * sentAgainInfo - visitCount > 1 && sendstate = 3 * suggest7CountAgainInfo - visitCount > 1 && suggest = 7 * filterCountList - taskSituation = 6 && sendstate = 4 * */ @Override public List getSfStatisticsHyperlink(ServiceSubtaskCountReq serviceSubtaskCountReq) { String hyperLinkInfoType = serviceSubtaskCountReq.getHyperLinkInfoType(); if (StringUtils.isNotEmpty(hyperLinkInfoType)) { if (!applyHyperLinkInfoType(serviceSubtaskCountReq, hyperLinkInfoType)) { // 下钻依赖的配置缺失时返回空明细,避免退化成无过滤条件的查询 return new ArrayList<>(); } } String followUpCountStyle = serviceSubtaskCountReq.getFollowUpCountStyle(); /** * 统计时算上不发送的 */ if (StringUtils.isNotEmpty(followUpCountStyle) && followUpCountStyle.equals("2")) { List sendstates = serviceSubtaskCountReq.getSendstates(); if (CollectionUtils.isNotEmpty(sendstates) && sendstates.get(0).equals(6L)) { List sendstates1 = new ArrayList<>(); sendstates1.add(3L); sendstates1.add(4L); sendstates1.add(6L); serviceSubtaskCountReq.setSendstates(sendstates1); } } List serviceSubtasks = serviceSubtaskMapper.getSfStatisticsHyperlink(serviceSubtaskCountReq); return serviceSubtasks; } private boolean applyHyperLinkInfoType(ServiceSubtaskCountReq serviceSubtaskCountReq, String hyperLinkInfoType) { //及时随访明细需要沿用请求的首次/再次口径 Integer originVisitCount = serviceSubtaskCountReq.getVisitCount(); serviceSubtaskCountReq.setVisitCount(null); serviceSubtaskCountReq.setSendstates(null); serviceSubtaskCountReq.setCurrentPreachform(null); serviceSubtaskCountReq.setExcep(null); serviceSubtaskCountReq.setTaskSituation(null); serviceSubtaskCountReq.setFinishState(null); serviceSubtaskCountReq.setSuggest(null); switch (hyperLinkInfoType) { case "dischargeCountInfo": break; case "firstDischargeCountInfo": //首次出院人次:visitCount = 1 serviceSubtaskCountReq.setVisitCount(1); break; case "againFollowUpPushCountInfo": { //再次随访推送人数:visitCount = 2 且执行科室为随访中心科室 String centerDept = sysConfigService.selectConfigByKey("sys.smartor.center.dept", serviceSubtaskCountReq.getOrgid()); if (StringUtils.isBlank(centerDept)) { log.warn("获取再次随访推送明细失败,未配置随访中心科室参数 sys.smartor.center.dept, orgid={}", serviceSubtaskCountReq.getOrgid()); return false; } serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setVisitDeptCode(centerDept.trim()); serviceSubtaskCountReq.setVisitDeptName(null); break; } case "timelyFollowUpInfo": serviceSubtaskCountReq.setVisitCount(originVisitCount); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); serviceSubtaskCountReq.setFinishState(1L); break; case "followUpNeededAllInfo": serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 6L, 7L))); break; case "nonFollowUpInfo": serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(4L))); break; case "needFollowUpInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 6L, 7L))); break; case "pendingFollowUpInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(2L))); break; case "followUpSuccessInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); break; case "followUpFailInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(5L, 7L))); break; case "manualInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setCurrentPreachform("1"); break; case "voiceInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setCurrentPreachform("3"); break; case "smsInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setCurrentPreachform("4"); break; case "weChatInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setCurrentPreachform("5"); break; case "manualSuccessInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); serviceSubtaskCountReq.setCurrentPreachform("1"); break; case "voiceSuccessInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); serviceSubtaskCountReq.setCurrentPreachform("3"); break; case "smsSuccessInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); serviceSubtaskCountReq.setCurrentPreachform("4"); break; case "weChatSuccessInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); serviceSubtaskCountReq.setCurrentPreachform("5"); break; case "abnormalInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setExcep("1"); break; case "needFollowUpAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 6L, 7L))); break; case "pendingFollowUpAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(2L))); break; case "followUpSuccessAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); break; case "followUpFailAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(5L, 7L))); break; case "manualAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setCurrentPreachform("1"); break; case "voiceAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setCurrentPreachform("3"); break; case "smsAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setCurrentPreachform("4"); break; case "weChatAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setCurrentPreachform("5"); break; case "manualAgainSuccessInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); serviceSubtaskCountReq.setCurrentPreachform("1"); break; case "voiceAgainSuccessInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); serviceSubtaskCountReq.setCurrentPreachform("3"); break; case "smsAgainSuccessInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); serviceSubtaskCountReq.setCurrentPreachform("4"); break; case "weChatAgainSuccessInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); serviceSubtaskCountReq.setCurrentPreachform("5"); break; case "abnormalAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setExcep("1"); break; case "suggest7CountAgainInfo": // 再次随访回院复诊复查:visitCount > 1 且 suggest = 7 serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSuggest("7"); break; case "taskSituation1Info": serviceSubtaskCountReq.setTaskSituation(1); break; case "taskSituation2Info": serviceSubtaskCountReq.setTaskSituation(2); break; case "taskSituation3Info": serviceSubtaskCountReq.setTaskSituation(3); break; case "taskSituation4Info": serviceSubtaskCountReq.setTaskSituation(4); break; case "taskSituation5Info": serviceSubtaskCountReq.setTaskSituation(5); break; case "taskSituation6Info": serviceSubtaskCountReq.setTaskSituation(7); break; case "filterCountList": serviceSubtaskCountReq.setTaskSituation(6); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(4L))); break; case "manuallyCalledInfo": serviceSubtaskCountReq.setIsManuallyCalled(1L); break; case "manualCallTimeoutInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(7L))); serviceSubtaskCountReq.setIsManuallyCalled(0L); break; case "manualCallTimeoutAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(7L))); serviceSubtaskCountReq.setIsManuallyCalled(0L); break; case "pendingFollowUpAllInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 7L))); break; case "pendingFollowUpAllAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 7L))); break; case "pendingFollowUpWaitSendInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L))); break; case "pendingFollowUpWaitSendAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L))); break; case "pendingFollowUpSentInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(3L, 7L))); break; case "pendingFollowUpSentAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(3L, 7L))); break; case "sentInfo": serviceSubtaskCountReq.setVisitCount(1); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(3L))); break; case "sentAgainInfo": serviceSubtaskCountReq.setVisitCount(2); serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(3L))); break; default: break; } return true; } /** * 获取随访统计比例 * * @param serviceSubtaskCountReq * @return */ @Override // @Cacheable(value = "getSfStatisticsScript", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()") public List getSfStatisticsScript(ServiceSubtaskCountReq serviceSubtaskCountReq) { log.info("getSfStatisticsScript的入参为:{}", serviceSubtaskCountReq); List serviceSubtaskStatistics = new ArrayList<>(); // 根据条件决定分组维度:离院维度按 leaveldeptcode / leavehospitaldistrictcode(含历史 deptcodes 入参), // 在院维度按 deptcode / hospitaldistrictcode String groupKey = "drcode"; boolean hasDrcode = serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty(); if (serviceSubtaskCountReq.getLeavehospitaldistrictcodes() != null && !serviceSubtaskCountReq.getLeavehospitaldistrictcodes().isEmpty()) { groupKey = hasDrcode ? "drcode" : "leavehospitaldistrictcode"; } else if (serviceSubtaskCountReq.getLeaveldeptcodes() != null && !serviceSubtaskCountReq.getLeaveldeptcodes().isEmpty()) { groupKey = hasDrcode ? "drcode" : "leaveldeptcode"; } else if (serviceSubtaskCountReq.getHospitaldistrictcodes() != null && !serviceSubtaskCountReq.getHospitaldistrictcodes().isEmpty()) { // 在院满意度:按在院病区分组(hospitaldistrictcode) groupKey = hasDrcode ? "drcode" : "hospitaldistrictcode"; } else if (serviceSubtaskCountReq.getHospitaldeptcodes() != null && !serviceSubtaskCountReq.getHospitaldeptcodes().isEmpty()) { // 在院满意度:按在院科室分组(deptcode) groupKey = hasDrcode ? "drcode" : "deptcode"; } else if (serviceSubtaskCountReq.getDeptcodes() != null && !serviceSubtaskCountReq.getDeptcodes().isEmpty()) { // 历史入参 deptcodes 表示离院科室 groupKey = hasDrcode ? "drcode" : "leaveldeptcode"; } else if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 1) { // 历史入参(市一等老前端只传 statisticaltype):1 = 病区统计 groupKey = hasDrcode ? "drcode" : "leavehospitaldistrictcode"; } else if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 2) { // 历史入参:2 = 科室统计(原 deptcode 即现在的离院科室 leaveldeptcode) groupKey = hasDrcode ? "drcode" : "leaveldeptcode"; } else if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 3) { // 病种统计:按任务ID分组,每个任务即一个病种随访任务 groupKey = "taskid"; } serviceSubtaskCountReq.setGroupKey(groupKey); // 分组列与过滤列保持一致:离院科室 leaveldeptcode、在院科室 deptcode serviceSubtaskCountReq.setGroupColumn(groupKey); /* * 满意度「病区统计」(离院维度):出院病区为空则回退到在院病区。 * 满意度子任务(service_type 6/14/15/16)的 leavehospitaldistrictcode 约三成为空, * 之前为了“查得到数据”把病区条件写成 `xxx IS NULL OR xxx IN (...)`, * 于是选了 A 病区也会把空病区的全量数据带进来,再统一归到 'Unknown' 组, * 该组的病区名又是 MAX(hospitaldistrictname) 随便挑的 —— 表现就是 * “选了血液内科病区,却查出一行显示骨科中心三病区”。 * 用“有效病区”列过滤 + 分组后:筛选真正生效,空病区的记录也回到它真实的在院病区。 */ if ("leavehospitaldistrictcode".equals(groupKey)) { String districtColumn = "IFNULL(leavehospitaldistrictcode, hospitaldistrictcode)"; serviceSubtaskCountReq.setGroupColumn(districtColumn); serviceSubtaskCountReq.setDistrictColumn(districtColumn); } //分组键集合:这一步保持不变(分页参数照旧作用在该查询上),保证“参与统计的分组”与改造前一致 List groupKeyList = serviceSubtaskMapper.getSfStatisticsGroupKey(serviceSubtaskCountReq); /* * 分组列可能为 NULL:满意度子任务(service_type 6/14/15/16)的 leavehospitaldistrictcode * 大量为 NULL,getSfStatisticsGroupKey 会把 NULL 原样带回来, * 拼进 SQL 就变成 `AND xxx IN (null)`(恒不成立),整张统计表直接空。 * 这里统一成 'Unknown',与聚合 SQL 的 GROUP BY IFNULL(列,'Unknown') 对齐。 */ if (groupKeyList != null) { groupKeyList = groupKeyList.stream() .map(key -> key == null ? "Unknown" : key) .distinct() .collect(Collectors.toList()); } serviceSubtaskCountReq.setGroupKeyList(groupKeyList); /* * 统计下推到数据库:一次 GROUP BY 只返回“分组数”行。 * 改造前是 serviceSubtaskMapper.getSfStatistics() 把命中的全部明细行(39 个字段, * 含 continue_content 等大字段)捞回 JVM 后逐行累加,几千行时传输和遍历都很慢。 * 这里的聚合口径与原 getStatisticCategory 逐条对齐(见 Mapper 中 getSfStatisticsScriptSum 的注释)。 */ List sumStatistics = serviceSubtaskMapper.getSfStatisticsScriptSum(serviceSubtaskCountReq); if (CollectionUtils.isEmpty(sumStatistics)) { return serviceSubtaskStatistics; } /* * 病种统计(按 taskid 分组)时补齐任务ID、任务名称和疾病病种。 * 聚合 SQL 已返回 taskid/task_name,这里再补 diag_type。 */ if ("taskid".equals(groupKey)) { Map diagTypeCache = new HashMap<>(); for (ServiceSubtaskStatistic statistic : sumStatistics) { Long taskId = statistic.getTaskId(); if (taskId == null && StringUtils.isNotEmpty(statistic.getGroupCode())) { try { taskId = Long.valueOf(statistic.getGroupCode()); } catch (NumberFormatException ignore) { // 历史数据可能不是数值 taskid,保持原分组键即可 } } statistic.setTaskId(taskId); if (StringUtils.isEmpty(statistic.getTaskName())) { statistic.setTaskName(statistic.getGroupName()); } if (taskId != null) { if (!diagTypeCache.containsKey(taskId)) { ServiceTask task = serviceTaskService.selectServiceTaskByTaskid(taskId); diagTypeCache.put(taskId, task == null ? null : task.getDiagType()); } statistic.setDiagType(diagTypeCache.get(taskId)); } } } /* * 满意度题目量:也改成按分组在库里聚合。 * 改造前是先把本次命中的全部子任务 id 灌进 getSfStatisticsCategory 的 IN 列表查一遍, * 再在内存里对每个子任务做一次 subCounts.stream().filter(...)(N*M 次比较)。 */ Map joyCountMap = new HashMap<>(); Map joyAllCountMap = new HashMap<>(); if (StringUtils.isNotEmpty(serviceSubtaskCountReq.getConfigValue())) { List> joySums = serviceSubtaskMapper.getSfStatisticsScriptJoySum(serviceSubtaskCountReq); if (CollectionUtils.isNotEmpty(joySums)) { for (Map joySum : joySums) { String joyGroupCode = joySum.get("groupCode") == null ? "Unknown" : joySum.get("groupCode").toString(); joyCountMap.put(joyGroupCode, toIntValue(joySum.get("joyCount"))); joyAllCountMap.put(joyGroupCode, toIntValue(joySum.get("joyAllCount"))); } } } //随访率:口径与原 getStatisticCategory 一致(首次率的判断沿用原来的 needFollowUp、再次率沿用原来的分母) DecimalFormat percentFormat = new DecimalFormat("##.##%"); List statisticsGroupKeys = new ArrayList<>(); for (ServiceSubtaskStatistic statistic : sumStatistics) { String statisticGroupCode = statistic.getGroupCode() == null ? "Unknown" : statistic.getGroupCode(); statistic.setJoyCount(joyCountMap.getOrDefault(statisticGroupCode, 0)); statistic.setJoyAllCount(joyAllCountMap.getOrDefault(statisticGroupCode, 0)); //首次随访率:只有该分组存在首次随访记录时才会被赋值(不存在则是 null,与改造前一致) if (statistic.getFirstVisitCount() != null && statistic.getFirstVisitCount() > 0) { if (statistic.getNeedFollowUp() != null && statistic.getNeedFollowUp() > 0) { double rate = (double) (nvlLong(statistic.getFollowUpSuccess()) + nvlLong(statistic.getFollowUpFail())) / statistic.getNeedFollowUp(); statistic.setFollowUpRate(percentFormat.format(rate)); } else { statistic.setFollowUpRate("0.00%"); } } //再次随访率:判断条件与原实现一致(原来判断的是 needFollowUp,这里照搬以免口径变化) if (statistic.getAgainVisitCount() != null && statistic.getAgainVisitCount() > 0) { if (statistic.getNeedFollowUp() != null && statistic.getNeedFollowUp() > 0) { double rateAgain = (double) (nvlLong(statistic.getFollowUpSuccessAgain()) + nvlLong(statistic.getFollowUpFailAgain())) / nvlLong(statistic.getNeedFollowUpAgain()); statistic.setFollowUpRateAgain(percentFormat.format(rateAgain)); } else { statistic.setFollowUpRateAgain("0.00%"); } } statisticsGroupKeys.add(statisticGroupCode); serviceSubtaskStatistics.add(statistic); } /* * 病区统计:这一行的病区就是分组键本身,展示名取该组自己的病区名。 * 聚合 SQL 里原来的 MAX(hospitaldistrictname) 在“一个组混了多个病区”时会挑出 * 一个毫不相干的病区名(选血液内科病区显示成骨科中心三病区就是这么来的)。 * 这里把分组键回填到在院/离院两套病区字段,保证前端不论读哪一列都是同一个病区, * 也让“查看详情”带上来的病区编码能查回同一批数据。 */ if (StringUtils.isNotEmpty(serviceSubtaskCountReq.getDistrictColumn())) { for (ServiceSubtaskStatistic statistic : serviceSubtaskStatistics) { String districtCode = statistic.getGroupCode() == null ? "Unknown" : statistic.getGroupCode(); String districtName = StringUtils.isNotEmpty(statistic.getGroupName()) ? statistic.getGroupName() : districtCode; statistic.setLeavehospitaldistrictcode(districtCode); statistic.setLeavehospitaldistrictname(districtName); statistic.setHospitaldistrictcode(districtCode); statistic.setHospitaldistrictname(districtName); } } //获取及时率统计合集(一次批量查询,不按分组循环查) Map> jsRates = getSsRateForSfStatistics(serviceSubtaskCountReq, statisticsGroupKeys); for (ServiceSubtaskStatistic statistic : serviceSubtaskStatistics) { String statisticGroupCode = statistic.getGroupCode() == null ? "Unknown" : statistic.getGroupCode(); Map jsRateMap = jsRates == null ? null : jsRates.get(statisticGroupCode); BigDecimal jsRate = new BigDecimal("0"); if (ObjectUtils.isNotEmpty(jsRateMap) && ObjectUtils.isNotEmpty(jsRateMap.get("rate"))) { jsRate = new BigDecimal(jsRateMap.get("rate").toString()); } statistic.setRate((jsRate.setScale(4, RoundingMode.HALF_UP)).doubleValue()); } //统计随访题目分类 if (CollectionUtils.isNotEmpty(serviceSubtaskStatistics)) { for (ServiceSubtaskStatistic serviceSubtaskStatistic : serviceSubtaskStatistics) { //获取满意度题目总量 BigDecimal sum = new BigDecimal(0); //获取满意度题目填报量 BigDecimal finishedSum = new BigDecimal(0); //完成比例 Double finishedPercentage = null; if (ObjectUtils.isNotEmpty(serviceSubtaskStatistic.getJoyCount())) { finishedSum = new BigDecimal(serviceSubtaskStatistic.getJoyCount()); } if (ObjectUtils.isNotEmpty(serviceSubtaskStatistic.getJoyAllCount())) { sum = new BigDecimal(serviceSubtaskStatistic.getJoyAllCount()); } if (sum.intValue() != 0) { // 原来只保留 2 位小数(23634/26106 会被截成 0.91),前端再 ×100 // 就显示成 91.00%,与实际的 90.53% 差了半个百分点。这里保留 4 位。 finishedPercentage = finishedSum.divide(sum, 4, RoundingMode.HALF_UP).doubleValue(); } serviceSubtaskStatistic.setJoyAllCount(sum.intValue()); serviceSubtaskStatistic.setJoyCount(finishedSum.intValue()); serviceSubtaskStatistic.setJoyTotal(finishedPercentage); clearStatisticDetailInfo(serviceSubtaskStatistic); } } return serviceSubtaskStatistics; } /** * Trim detail lists for summary response to avoid oversized payloads. */ private void clearStatisticDetailInfo(ServiceSubtaskStatistic serviceSubtaskStatistic) { serviceSubtaskStatistic.setDischargeCountInfo(null); serviceSubtaskStatistic.setNonFollowUpInfo(null); serviceSubtaskStatistic.setFollowUpNeededAllInfo(null); serviceSubtaskStatistic.setNeedFollowUpInfo(null); serviceSubtaskStatistic.setPendingFollowUpInfo(null); serviceSubtaskStatistic.setFollowUpSuccessInfo(null); serviceSubtaskStatistic.setFollowUpFailInfo(null); serviceSubtaskStatistic.setManualInfo(null); serviceSubtaskStatistic.setVoiceInfo(null); serviceSubtaskStatistic.setSmsInfo(null); serviceSubtaskStatistic.setWechatInfo(null); serviceSubtaskStatistic.setNeedFollowUpAgainInfo(null); serviceSubtaskStatistic.setPendingFollowUpAgainInfo(null); serviceSubtaskStatistic.setFollowUpSuccessAgainInfo(null); serviceSubtaskStatistic.setFollowUpFailAgainInfo(null); serviceSubtaskStatistic.setManualAgainInfo(null); serviceSubtaskStatistic.setVoiceAgainInfo(null); serviceSubtaskStatistic.setSmsAgainInfo(null); serviceSubtaskStatistic.setWechatAgainInfo(null); serviceSubtaskStatistic.setTaskSituation1Info(null); serviceSubtaskStatistic.setTaskSituation2Info(null); serviceSubtaskStatistic.setTaskSituation3Info(null); serviceSubtaskStatistic.setTaskSituation4Info(null); serviceSubtaskStatistic.setTaskSituation5Info(null); serviceSubtaskStatistic.setTaskSituation6Info(null); serviceSubtaskStatistic.setFilterCountList(null); } @Override public Map getSfStatisticsScriptDetails(ServiceSubtaskCountReq serviceSubtaskCountReq) { List allCounts = new ArrayList<>(); List allItemCounts = new ArrayList<>(); String type = serviceSubtaskCountReq.getType(); if (ObjectUtils.isEmpty(type)) { //查询语音统计明细 serviceSubtaskCountReq.setType("1"); List ivyCounts = serviceSubtaskMapper.getSfStatisticsScriptDetails(serviceSubtaskCountReq); List ivyItemCounts = serviceSubtaskMapper.getSfStatisticsScriptItemDetails(serviceSubtaskCountReq); //查询短信统计明细 serviceSubtaskCountReq.setType("2"); List svyCounts = serviceSubtaskMapper.getSfStatisticsScriptDetails(serviceSubtaskCountReq); List svyItemCounts = serviceSubtaskMapper.getSfStatisticsScriptItemDetails(serviceSubtaskCountReq); allCounts.addAll(ivyCounts); allCounts.addAll(svyCounts); allItemCounts.addAll(ivyItemCounts); allItemCounts.addAll(svyItemCounts); } else { allCounts = serviceSubtaskMapper.getSfStatisticsScriptDetails(serviceSubtaskCountReq); allItemCounts = serviceSubtaskMapper.getSfStatisticsScriptItemDetails(serviceSubtaskCountReq); } //返回结构是 Map,且不传 type 时会执行两条 SQL,PageHelper 没法对整体分页, //所以在题目合并完成之后按题目(scriptid)在这里分页,保证 total 和每页数据都是题目维度的。 allCounts.sort(Comparator .comparing(ServiceSubtaskScriptCount::getSubtaskType, Comparator.nullsLast(String::compareTo)) .thenComparing(ServiceSubtaskScriptCount::getScriptid, Comparator.nullsLast(Long::compareTo))); int pageNum = ObjectUtils.isNotEmpty(serviceSubtaskCountReq.getPageNum()) && serviceSubtaskCountReq.getPageNum() > 0 ? serviceSubtaskCountReq.getPageNum() : 1; int pageSize = ObjectUtils.isNotEmpty(serviceSubtaskCountReq.getPageSize()) && serviceSubtaskCountReq.getPageSize() > 0 ? serviceSubtaskCountReq.getPageSize() : 10; int total = allCounts.size(); int fromIndex = (int) Math.min((long) (pageNum - 1) * pageSize, total); int toIndex = Math.min(fromIndex + pageSize, total); List pageCounts = allCounts.subList(fromIndex, toIndex); Map pageData = new LinkedHashMap<>(); for (ServiceSubtaskScriptCount count : pageCounts) { Map itemCountMap = new HashMap<>(); //问卷加上空白选项 if (ObjectUtils.isNotEmpty(count.getTemplateid()) && ObjectUtils.isNotEmpty(count.getSubtaskType()) && count.getSubtaskType().equals("2")) { SvyTaskTemplateScriptVO svyTaskTemplateScriptVO = new SvyTaskTemplateScriptVO(); svyTaskTemplateScriptVO.setId(count.getScriptid()); svyTaskTemplateScriptVO.setOrgid(serviceSubtaskCountReq.getOrgid()); SvyTaskTemplateScriptVO svyTaskTemplateScriptResultVo = svyTaskTemplateScriptService.selectInfoByCondition(svyTaskTemplateScriptVO); if (ObjectUtils.isNotEmpty(svyTaskTemplateScriptResultVo)) { List svyTaskTemplateTargetoptions = svyTaskTemplateScriptResultVo.getSvyTaskTemplateTargetoptions(); if (ObjectUtils.isNotEmpty(svyTaskTemplateTargetoptions)) { //填入空白信息 svyTaskTemplateTargetoptions.forEach(targetoption -> { ServiceSubtaskScriptCount emptyCount = new ServiceSubtaskScriptCount(); emptyCount.setScriptid(count.getScriptid()); emptyCount.setScriptContent(count.getScriptContent()); emptyCount.setScriptType(count.getScriptType()); emptyCount.setSubtaskType(count.getSubtaskType()); emptyCount.setCompletedQuantity(count.getCompletedQuantity()); emptyCount.setAllQuantity(count.getAllQuantity()); emptyCount.setCompletedPercentage(count.getCompletedPercentage()); emptyCount.setTemplateid(count.getTemplateid()); emptyCount.setChosenQuantity(0); emptyCount.setChosenPercentage("0.0"); emptyCount.setOptionText(targetoption.getOptioncontent()); itemCountMap.put(targetoption.getOptioncontent(), emptyCount); }); } } } allItemCounts.forEach(itemCount -> { //明细行已按“题目内容+任务类型”聚合并带出 script_content,不能用 scriptid 匹配: //同一道题会被复制到多个任务模板,每个模板的 scriptid 都不同 boolean sameQuestion = ObjectUtils.isNotEmpty(count.getScriptContent()) && ObjectUtils.isNotEmpty(itemCount.getScriptContent()) && count.getScriptContent().equals(itemCount.getScriptContent()) && Objects.equals(count.getSubtaskType(), itemCount.getSubtaskType()); if (sameQuestion) { //放入统计信息 itemCount.setScriptContent(count.getScriptContent()); itemCount.setScriptType(count.getScriptType()); itemCount.setSubtaskType(count.getSubtaskType()); itemCount.setCompletedQuantity(count.getCompletedQuantity()); itemCount.setAllQuantity(count.getAllQuantity()); itemCount.setCompletedPercentage(count.getCompletedPercentage()); itemCount.setTemplateid(count.getTemplateid()); //计算选择比例 int chosenQuantity = ObjectUtils.isNotEmpty(itemCount.getChosenQuantity()) ? itemCount.getChosenQuantity() : 0; int completedQuantity = itemCount.getCompletedQuantity(); if (ObjectUtils.isNotEmpty(completedQuantity) && completedQuantity != 0) { BigDecimal chosenPercentage = (new BigDecimal(chosenQuantity)).divide(new BigDecimal(completedQuantity), 2, RoundingMode.HALF_UP); itemCount.setChosenPercentage(chosenPercentage.toString()); } itemCountMap.put(itemCount.getOptionText(), itemCount); } }); List itemCounts = new ArrayList<>(itemCountMap.values()); count.setDetails(itemCounts); pageData.put(count.getScriptid().toString(), count); } Map result = new HashMap<>(); // total 是题目总数(已按题目合并),rows/data 是当前页数据 result.put("total", total); result.put("pageNum", pageNum); result.put("pageSize", pageSize); result.put("rows", new ArrayList<>(pageCounts)); result.put("data", pageData); return result; } /** * 问题选项数字下钻:返回选择了指定选项的 service_subtask 列表。 *

* 统计明细中的选项数量来自 service_subtask_detail 的 * IFNULL(matchedtext, asrtext),因此下钻必须使用同一题目的相同选项进行匹配。 * * @param serviceSubtaskCountReq 下钻条件 * @return service_subtask 列表 */ @Override public List getSfStatisticsScriptDetailsHyperlink(ServiceSubtaskCountReq serviceSubtaskCountReq) { log.info("getSfStatisticsScriptDetailsHyperlink的入参为:{}", serviceSubtaskCountReq); if (serviceSubtaskCountReq == null) { return new ArrayList<>(); } // 兼容前端直接回传统计明细行中的 subtaskType if (StringUtils.isBlank(serviceSubtaskCountReq.getType()) && StringUtils.isNotBlank(serviceSubtaskCountReq.getSubtaskType())) { serviceSubtaskCountReq.setType(serviceSubtaskCountReq.getSubtaskType()); } resolveScriptContentAndType(serviceSubtaskCountReq); if (StringUtils.isBlank(serviceSubtaskCountReq.getScriptContent()) && serviceSubtaskCountReq.getScriptid() == null) { log.warn("getSfStatisticsScriptDetailsHyperlink-题目scriptid和scriptContent均为空,返回空列表"); return new ArrayList<>(); } if (serviceSubtaskCountReq.getOptionText() == null) { log.warn("getSfStatisticsScriptDetailsHyperlink-选项optionText为空,返回空列表"); return new ArrayList<>(); } return serviceSubtaskMapper.getSfStatisticsScriptDetailsHyperlink(serviceSubtaskCountReq); } /** * 根据 scriptid 补齐题目内容和任务类型。 *

* 统计明细按“题目内容 + 任务类型”合并,同一道题复制到多个任务模板时 scriptid 可能不同, * 因此优先按题目内容下钻;只有查不到题目内容时才退化为 scriptid 精确匹配。 */ private void resolveScriptContentAndType(ServiceSubtaskCountReq serviceSubtaskCountReq) { if (serviceSubtaskCountReq.getScriptid() == null) { return; } // 已有题目内容和任务类型时无需再查模板问题表 if (StringUtils.isNotBlank(serviceSubtaskCountReq.getScriptContent()) && StringUtils.isNotBlank(serviceSubtaskCountReq.getType())) { return; } String type = serviceSubtaskCountReq.getType(); if (StringUtils.isBlank(type) || "1".equals(type)) { IvrTaskTemplateScript ivrTaskTemplateScript = iIvrTaskTemplateScriptService.selectIvrTaskTemplateScriptByID(serviceSubtaskCountReq.getScriptid()); if (ObjectUtils.isNotEmpty(ivrTaskTemplateScript)) { if (StringUtils.isBlank(serviceSubtaskCountReq.getType())) { serviceSubtaskCountReq.setType("1"); } if (StringUtils.isBlank(serviceSubtaskCountReq.getScriptContent())) { serviceSubtaskCountReq.setScriptContent(ivrTaskTemplateScript.getScriptContent()); } return; } // 明确指定了语音类型时不再尝试问卷表 if (StringUtils.isNotBlank(type)) { return; } } if (StringUtils.isBlank(serviceSubtaskCountReq.getType()) || "2".equals(type)) { SvyTaskTemplateScript svyTaskTemplateScript = svyTaskTemplateScriptService.selectSvyTaskTemplateScriptByID(serviceSubtaskCountReq.getScriptid()); if (ObjectUtils.isNotEmpty(svyTaskTemplateScript)) { if (StringUtils.isBlank(serviceSubtaskCountReq.getType())) { serviceSubtaskCountReq.setType("2"); } if (StringUtils.isBlank(serviceSubtaskCountReq.getScriptContent())) { serviceSubtaskCountReq.setScriptContent(svyTaskTemplateScript.getScriptContent()); } } } } /** * 计算总计行 * * @param statistics 统计数据列表 * @return 总计行数据 */ private ServiceSubtaskStatistic calculateTotalRow(List statistics) { ServiceSubtaskStatistic total = new ServiceSubtaskStatistic(); // 初始化数值字段 total.setDischargeCount(0); total.setFirstDischargeCount(0L); total.setAgainFollowUpPushCount(0L); total.setNonFollowUp(0L); total.setFilterCount(0L); total.setFollowUpNeeded(0L); total.setNeedFollowUp(0L); total.setPendingFollowUp(0L); total.setFollowUpSuccess(0L); total.setFollowUpFail(0L); total.setTimelyFollowUp(0L); total.setManual(0L); total.setSms(0L); total.setWeChat(0L); total.setAbnormal(0L); total.setNeedFollowUpAgain(0L); total.setPendingFollowUpAgain(0L); total.setManualCallTimeout(0L); total.setManualCallTimeoutAgain(0L); total.setPendingFollowUpAll(0L); total.setPendingFollowUpAllAgain(0L); total.setPendingFollowUpWaitSend(0L); total.setPendingFollowUpWaitSendAgain(0L); total.setPendingFollowUpSent(0L); total.setPendingFollowUpSentAgain(0L); total.setSent(0L); total.setSentAgain(0L); total.setFollowUpSuccessAgain(0L); total.setFollowUpFailAgain(0L); total.setSuggest7CountAgain(0L); total.setManualAgain(0L); total.setSmsAgain(0L); total.setWeChatAgain(0L); total.setAbnormalAgain(0L); total.setTaskSituation1(0); total.setTaskSituation2(0); total.setTaskSituation3(0); total.setTaskSituation4(0); total.setTaskSituation5(0); total.setTaskSituation6(0); // 累加各个字段的值 for (ServiceSubtaskStatistic stat : statistics) { if (stat.getDischargeCount() != null) { total.setDischargeCount(total.getDischargeCount() + stat.getDischargeCount()); } total.setFirstDischargeCount(total.getFirstDischargeCount() + (stat.getFirstDischargeCount() != null ? stat.getFirstDischargeCount() : 0L)); total.setAgainFollowUpPushCount(total.getAgainFollowUpPushCount() + (stat.getAgainFollowUpPushCount() != null ? stat.getAgainFollowUpPushCount() : 0L)); total.setNonFollowUp(total.getNonFollowUp() + (stat.getNonFollowUp() != null ? stat.getNonFollowUp() : 0L)); total.setFilterCount(total.getFilterCount() + (stat.getFilterCount() != null ? stat.getFilterCount() : 0L)); total.setFollowUpNeeded(total.getFollowUpNeeded() + (stat.getFollowUpNeeded() != null ? stat.getFollowUpNeeded() : 0L)); total.setNeedFollowUp(total.getNeedFollowUp() + (stat.getNeedFollowUp() != null ? stat.getNeedFollowUp() : 0L)); total.setPendingFollowUp(total.getPendingFollowUp() + (stat.getPendingFollowUp() != null ? stat.getPendingFollowUp() : 0L)); total.setFollowUpSuccess(total.getFollowUpSuccess() + (stat.getFollowUpSuccess() != null ? stat.getFollowUpSuccess() : 0L)); total.setFollowUpFail(total.getFollowUpFail() + (stat.getFollowUpFail() != null ? stat.getFollowUpFail() : 0L)); total.setTimelyFollowUp(total.getTimelyFollowUp() + (stat.getTimelyFollowUp() != null ? stat.getTimelyFollowUp() : 0L)); total.setManual(total.getManual() + (stat.getManual() != null ? stat.getManual() : 0L)); total.setSms(total.getSms() + (stat.getSms() != null ? stat.getSms() : 0L)); total.setWeChat(total.getWeChat() + (stat.getWeChat() != null ? stat.getWeChat() : 0L)); total.setAbnormal(total.getAbnormal() + (stat.getAbnormal() != null ? stat.getAbnormal() : 0L)); total.setNeedFollowUpAgain(total.getNeedFollowUpAgain() + (stat.getNeedFollowUpAgain() != null ? stat.getNeedFollowUpAgain() : 0L)); total.setPendingFollowUpAgain(total.getPendingFollowUpAgain() + (stat.getPendingFollowUpAgain() != null ? stat.getPendingFollowUpAgain() : 0L)); total.setManualCallTimeout(total.getManualCallTimeout() + (stat.getManualCallTimeout() != null ? stat.getManualCallTimeout() : 0L)); total.setManualCallTimeoutAgain(total.getManualCallTimeoutAgain() + (stat.getManualCallTimeoutAgain() != null ? stat.getManualCallTimeoutAgain() : 0L)); total.setPendingFollowUpAll(total.getPendingFollowUpAll() + (stat.getPendingFollowUpAll() != null ? stat.getPendingFollowUpAll() : 0L)); total.setPendingFollowUpAllAgain(total.getPendingFollowUpAllAgain() + (stat.getPendingFollowUpAllAgain() != null ? stat.getPendingFollowUpAllAgain() : 0L)); total.setPendingFollowUpWaitSend(total.getPendingFollowUpWaitSend() + (stat.getPendingFollowUpWaitSend() != null ? stat.getPendingFollowUpWaitSend() : 0L)); total.setPendingFollowUpWaitSendAgain(total.getPendingFollowUpWaitSendAgain() + (stat.getPendingFollowUpWaitSendAgain() != null ? stat.getPendingFollowUpWaitSendAgain() : 0L)); total.setPendingFollowUpSent(total.getPendingFollowUpSent() + (stat.getPendingFollowUpSent() != null ? stat.getPendingFollowUpSent() : 0L)); total.setPendingFollowUpSentAgain(total.getPendingFollowUpSentAgain() + (stat.getPendingFollowUpSentAgain() != null ? stat.getPendingFollowUpSentAgain() : 0L)); total.setSent(total.getSent() + (stat.getSent() != null ? stat.getSent() : 0L)); total.setSentAgain(total.getSentAgain() + (stat.getSentAgain() != null ? stat.getSentAgain() : 0L)); total.setFollowUpSuccessAgain(total.getFollowUpSuccessAgain() + (stat.getFollowUpSuccessAgain() != null ? stat.getFollowUpSuccessAgain() : 0L)); total.setFollowUpFailAgain(total.getFollowUpFailAgain() + (stat.getFollowUpFailAgain() != null ? stat.getFollowUpFailAgain() : 0L)); total.setSuggest7CountAgain(total.getSuggest7CountAgain() + (stat.getSuggest7CountAgain() != null ? stat.getSuggest7CountAgain() : 0L)); total.setManualAgain(total.getManualAgain() + (stat.getManualAgain() != null ? stat.getManualAgain() : 0L)); total.setSmsAgain(total.getSmsAgain() + (stat.getSmsAgain() != null ? stat.getSmsAgain() : 0L)); total.setWeChatAgain(total.getWeChatAgain() + (stat.getWeChatAgain() != null ? stat.getWeChatAgain() : 0L)); total.setAbnormalAgain(total.getAbnormalAgain() + (stat.getAbnormalAgain() != null ? stat.getAbnormalAgain() : 0L)); total.setTaskSituation1(total.getTaskSituation1() + (stat.getTaskSituation1() != null ? stat.getTaskSituation1() : 0)); total.setTaskSituation2(total.getTaskSituation2() + (stat.getTaskSituation2() != null ? stat.getTaskSituation2() : 0)); total.setTaskSituation3(total.getTaskSituation3() + (stat.getTaskSituation3() != null ? stat.getTaskSituation3() : 0)); total.setTaskSituation4(total.getTaskSituation4() + (stat.getTaskSituation4() != null ? stat.getTaskSituation4() : 0)); total.setTaskSituation5(total.getTaskSituation5() + (stat.getTaskSituation5() != null ? stat.getTaskSituation5() : 0)); total.setTaskSituation6(total.getTaskSituation6() + (stat.getTaskSituation6() != null ? stat.getTaskSituation6() : 0)); } // 计算总计行的比率字段 DecimalFormat percentFormat = new DecimalFormat("##.##%"); if (total.getNeedFollowUp() > 0) { double rate = (double) (total.getFollowUpSuccess() + total.getFollowUpFail()) / total.getNeedFollowUp(); total.setFollowUpRate(percentFormat.format(rate)); } else { total.setFollowUpRate("0.00%"); } if (total.getNeedFollowUpAgain() > 0) { double rateAgain = (double) (total.getFollowUpSuccessAgain() + total.getFollowUpFailAgain()) / total.getNeedFollowUpAgain(); total.setFollowUpRateAgain(percentFormat.format(rateAgain)); } else { total.setFollowUpRateAgain("0.00%"); } return total; } /** * 历史随访记录导出类封装 * ServiceSubtask 转换为 ServiceSubtaskDiagname */ public List convertToDiagnameList(List subtaskList) { if (CollectionUtils.isEmpty(subtaskList)) { return new ArrayList<>(); } return subtaskList.stream().map(subtask -> { ServiceSubtaskDiagname diagname = new ServiceSubtaskDiagname(); diagname.setTaskName(subtask.getTaskName()); diagname.setSendstate(subtask.getSendstate()); diagname.setSendname(subtask.getSendname()); diagname.setLeavediagname(subtask.getLeavediagname()); diagname.setSuggest(subtask.getSuggest()); diagname.setOperator(subtask.getOperator()); diagname.setFinishtime(subtask.getFinishtime()); diagname.setVisitTime(subtask.getVisitTime()); diagname.setEndtime(subtask.getEndtime()); //计算出院天数 if (!Objects.isNull(diagname.getEndtime())) { Integer endDay = DateUtils.differentDaysByMillisecond(diagname.getEndtime(), new Date()); diagname.setEndDay(endDay); } diagname.setSfzh(subtask.getSfzh()); diagname.setPhone(subtask.getPhone()); diagname.setNurseName(subtask.getNurseName()); diagname.setDrname(subtask.getDrname()); diagname.setDeptname(subtask.getLeaveldeptname()); diagname.setLeavehospitaldistrictname(subtask.getLeavehospitaldistrictname()); diagname.setTemplatename(subtask.getTemplatename()); diagname.setPreachform(subtask.getPreachform()); diagname.setResult(subtask.getResult()); return diagname; }).collect(Collectors.toList()); } public Map getCurrentUserServiceSubtaskCount(ServiceSubtaskEntity entity) { return serviceSubtaskMapper.getCurrentUserServiceSubtaskCount(entity); } /** * 当前登录人待处理随访任务,按出院年月分组统计(出院随访、门诊随访分开计数) *

* 只返回有数据的月份,前端按「当月 + 前 3 个月」补齐,没有数据显示 0 个。 */ @Override public Map getPendingManualTaskMonthStats(ServiceSubtaskEntity entity) { List> rows = serviceSubtaskMapper.countPendingManualTaskByMonth(entity); List> months = new ArrayList<>(); long total = 0L; if (rows != null) { for (Map row : rows) { if (row == null || row.get("month") == null) { continue; } long dischargeCount = parsePendingCount(row.get("dischargeCnt")); long outpatientCount = parsePendingCount(row.get("outpatientCnt")); if (dischargeCount <= 0 && outpatientCount <= 0) { continue; } Map item = new LinkedHashMap<>(); item.put("month", row.get("month").toString()); item.put("dischargeCount", dischargeCount); item.put("outpatientCount", outpatientCount); months.add(item); total += dischargeCount + outpatientCount; } } Map result = new LinkedHashMap<>(); result.put("total", total); result.put("months", months); return result; } /** * 统计结果里的数量转 long,解析失败按 0 处理 */ private long parsePendingCount(Object value) { if (value == null) { return 0L; } try { return Long.parseLong(value.toString()); } catch (NumberFormatException e) { log.warn("统计待处理随访任务失败,数量无法解析:{}", value); return 0L; } } @Override public Map getContinueNurseCount(ServiceSubtaskCotinueCountVO vo) { boolean hasDistrict = !CollectionUtils.isEmpty(vo.getLeavehospitaldistrictcodes()); boolean hasDept = !CollectionUtils.isEmpty(vo.getDeptcodes()); List> districtRows; List> deptRows; if (hasDistrict) { // 只传了病区:仅按病区维度统计 districtRows = serviceSubtaskMapper.getContinueNurseCount(vo); deptRows = Collections.emptyList(); } else if (hasDept) { // 只传了科室:仅按科室维度统计 districtRows = Collections.emptyList(); deptRows = serviceSubtaskMapper.getContinueNurseCountByDept(vo); } else { // 都未传:病区和科室各统计一遍 districtRows = serviceSubtaskMapper.getContinueNurseCount(vo); deptRows = serviceSubtaskMapper.getContinueNurseCountByDept(vo); } long totalNoContinue = 0L; long totalContinue = 0L; List> detail = new ArrayList<>(); for (Map row : districtRows) { String groupName = row.get("groupName") == null ? (row.get("groupCode") == null ? "" : row.get("groupCode").toString()) : row.get("groupName").toString(); long noCnt = row.get("noContinueCnt") == null ? 0L : Long.parseLong(row.get("noContinueCnt").toString()); long yesCnt = row.get("continueCnt") == null ? 0L : Long.parseLong(row.get("continueCnt").toString()); totalNoContinue += noCnt; totalContinue += yesCnt; Map item = new LinkedHashMap<>(); item.put("未延续_" + groupName, noCnt); item.put("已延续_" + groupName, yesCnt); detail.add(item); } for (Map row : deptRows) { String groupName = row.get("groupName") == null ? (row.get("groupCode") == null ? "" : row.get("groupCode").toString()) : row.get("groupName").toString(); long noCnt = row.get("noContinueCnt") == null ? 0L : Long.parseLong(row.get("noContinueCnt").toString()); long yesCnt = row.get("continueCnt") == null ? 0L : Long.parseLong(row.get("continueCnt").toString()); totalNoContinue += noCnt; totalContinue += yesCnt; Map item = new LinkedHashMap<>(); item.put("未延续_" + groupName, noCnt); item.put("已延续_" + groupName, yesCnt); detail.add(item); } Map result = new LinkedHashMap<>(); result.put("未延续总数量", totalNoContinue); result.put("已延续总数量", totalContinue); result.put("详情", detail); return result; } /** * 设置失败任务默认值,并将失败任务重新置为成功 * * @param failDay (失败天数:距离当前日期失败天数) * @return */ @Override public void setFailSubTaskDefalutVal(Long failDay) { //1.先去sys_config中,获取哪些科室或病区需要默认问卷默认值 IConfigService configService = SpringUtils.getBean(IConfigService.class); String deptConfigValue = sysConfigService.selectConfigByKey("hosp.default.dept"); String wardConfigValue = sysConfigService.selectConfigByKey("hosp.default.ward"); List leaveWard = null; List leaveDept = null; if (deptConfigValue != null && !deptConfigValue.isEmpty()) { leaveDept = Arrays.stream(deptConfigValue.split(",")).filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); } if (wardConfigValue != null && !wardConfigValue.isEmpty()) { leaveWard = Arrays.stream(wardConfigValue.split(",")).filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); } log.info("离院病区leaveWard: {}, 离院科室leaveDept: {}", leaveWard, leaveDept); if (leaveWard == null && leaveDept == null) return; //2.获取leaveWard,leaveDept中的servic_subtask表中sendstate=5的任务 ServiceSubtaskEntity serviceSubtaskEntity = new ServiceSubtaskEntity(); serviceSubtaskEntity.setSendstate(5L); serviceSubtaskEntity.setLeavehospitaldistrictcodes(leaveWard); serviceSubtaskEntity.setLeaveldeptcodes(leaveDept); if (!Objects.isNull(leaveWard) && !Objects.isNull(leaveDept)) serviceSubtaskEntity.setDeptOrDistrict("2"); List serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskEntity); if (CollectionUtils.isEmpty(serviceSubtasks)) return; //3.如果查出来的集合不为空,则进行循环 for (ServiceSubtask serviceSubtask : serviceSubtasks) { Integer preachformSize = 0; ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform(); serviceSubtaskPreachform.setSubid(serviceSubtask.getId()); List serviceSubtaskPreachforms = taskPreachformPort.selectServiceSubtaskPreachformList(serviceSubtaskPreachform); if (CollectionUtils.isNotEmpty(serviceSubtaskPreachforms)) preachformSize = serviceSubtaskPreachforms.size(); if (serviceSubtask.getUpdateTime() != null && DateUtils.differentDaysByMillisecond(new Date(), serviceSubtask.getUpdateTime()) >= failDay) { //3.1 判断当前serviceSubtask的updateTime是不是为空,如果不为空,则判断当前时间是不是与updateTime差距大于等于failDay log.debug("【失败任务默认值】子任务 {} 达到失败天数(updateTime)", serviceSubtask.getId()); } else if (serviceSubtask.getVisitTime() != null && DateUtils.differentDaysByMillisecond(new Date(), serviceSubtask.getVisitTime()) >= failDay + preachformSize) { //3.2 如果当前serviceSubtask的updateTime为空,根据当前serviceSubtask的subid去查service_subtask_preachform得到size(如果size为空,则默认0),则根据当前时间是不是与当前serviceSubtask的visitTime差距大于等于failDay + size log.debug("【失败任务默认值】子任务 {} 达到失败天数(visitTime+preachformSize)", serviceSubtask.getId()); } else { //3.3 如果2.1且2.2都为false,则continue continue; } //4. ⚠️ 2026-10-21 加固:先"算完"再"落库",彻底去掉"先插入、失败再删除"的写法。 // 旧逻辑是边插边判断,只要有一题没配默认值,就把这个 sub_id 下**所有**明细(含患者真实作答、 // 甚至刚插进去的那批)统统置 del_flag='1' —— nhfy 2026-09-08 那 10 位患者的满意度作答 // 就是这样被删掉、导致导出「问题详情占比」370 而「随访信息表单」380 的。 // 现在:① 清单为空(=有题没配默认值)→ 整份跳过,不写也不删; // ② 清单齐全 → 统一落库(存在则更新并复活,不存在则插入)。 List defaultDetails = buildDefaultDetails(serviceSubtask); if (CollectionUtils.isEmpty(defaultDetails)) { log.info("【失败任务默认值】任务 {} 子任务 {} 有题目未配置默认值,整份跳过(不插入、不删除任何明细)", serviceSubtask.getTaskid(), serviceSubtask.getId()); continue; } persistDefaultDetails(defaultDetails); //5.全部落库成功后再把任务置为已完成 serviceSubtask.setSendstate(6L); serviceSubtask.setPreachform("1"); serviceSubtaskMapper.updateServiceSubtask(serviceSubtask); } } /** * 按模板构造"默认值明细"清单(只计算、不落库) *

* 2026-10-21 新增:把原来的 {@code saveServiceSubtaskDetail}(边算边插、失败再删)拆成 * 「build(本方法)」+「persist({@link #persistDefaultDetails})」两步, * 保证"默认值不全"时**一个字节都不会写、更不会删**。 * * @param serviceSubtask 子任务 * @return 明细清单;任一题没配默认值(或模板为空)时返回 {@code null},表示整份不处理 */ private List buildDefaultDetails(ServiceSubtask serviceSubtask) { if (serviceSubtask.getType() == null) { return null; } List details = new ArrayList<>(); if (serviceSubtask.getType().equals("1")) { //3.3.1 如果type是 1,则用当前serviceSubtask的templateid去ivr_task_temaplate_script中获取问题和选项 IvrTaskTemplateScript ivrTaskTemplateScript = new IvrTaskTemplateScript(); ivrTaskTemplateScript.setTemplateID(serviceSubtask.getTemplateid()); List ivrTaskTemplateScripts = iIvrTaskTemplateScriptService.selectIvrTaskTemplateScriptList(ivrTaskTemplateScript); if (CollectionUtils.isEmpty(ivrTaskTemplateScripts)) return null; for (IvrTaskTemplateScript its : ivrTaskTemplateScripts) { IvrTaskTemplateScriptVO ivrTaskTemplateScriptVO = DtoConversionUtils.sourceToTarget(its, IvrTaskTemplateScriptVO.class); IvrTaskTemplateTargetoption ivrTaskTemplateTargetoption = new IvrTaskTemplateTargetoption(); ivrTaskTemplateTargetoption.setScriptid(ivrTaskTemplateScriptVO.getId()); List ivrTaskTemplateTargetoptions = iIvrTaskTemplateTargetoptionService.selectIvrTaskTemplateTargetoptionList(ivrTaskTemplateTargetoption); ivrTaskTemplateScriptVO.setIvrTaskScriptTargetoptionList(ivrTaskTemplateTargetoptions); ServiceSubtaskDetail detail = buildSFDetail(ivrTaskTemplateScriptVO, serviceSubtask); if (detail == null) return null; details.add(detail); } } else if (serviceSubtask.getType().equals("2")) { //3.3.2 如果type是 2,则用当前serviceSubtask的templateid去svy_task_temaplate_script中获取问题和选项 SvyTaskTemplateScript svyTaskTemplateScript = new SvyTaskTemplateScript(); svyTaskTemplateScript.setTemplateID(serviceSubtask.getTemplateid()); List svyTaskTemplateScripts = svyTaskTemplateScriptService.selectSvyTaskTemplateScriptList(svyTaskTemplateScript); if (CollectionUtils.isEmpty(svyTaskTemplateScripts)) return null; for (SvyTaskTemplateScript taskTemplateScript : svyTaskTemplateScripts) { SvyTaskTemplateScriptVO svyTaskTemplateScriptVO = DtoConversionUtils.sourceToTarget(taskTemplateScript, SvyTaskTemplateScriptVO.class); SvyTaskTemplateScriptVO svyTaskTemplateScriptVO1 = svyTaskTemplateScriptService.selectInfoByCondition(svyTaskTemplateScriptVO); ServiceSubtaskDetail detail = buildWJDetail(svyTaskTemplateScriptVO1, serviceSubtask); if (detail == null) return null; details.add(detail); } } else { return null; } return details; } /** * 落库"默认值明细":存在则更新并复活,不存在则插入(只增不删) */ private void persistDefaultDetails(List details) { for (ServiceSubtaskDetail detail : details) { ServiceSubtaskDetailDTO exist = serviceSubtaskDetailMapper.isExistServiceSubtaskDetail(detail.getSubId(), detail.getScriptid()); if (ObjectUtils.isNotEmpty(exist)) { detail.setId(exist.getId()); detail.setUpdateTime(new Date()); serviceSubtaskDetailMapper.updateServiceSubtaskDetail(detail); //命中历史被删副本时置回 del_flag='0',避免再插一份新副本 serviceSubtaskDetailMapper.reviveServiceSubtaskDetail(exist.getId()); } else { serviceSubtaskDetailMapper.insertServiceSubtaskDetail(detail); } } } /** * 微信公众号已领取未填写:按题目默认选项补齐当前子任务,并将当前子任务完成。 *

* 所有查询、明细写入、状态更新都只使用当前 subid,避免影响其他任务/子任务。 */ @Override @Transactional(rollbackFor = Exception.class) public Boolean completeWechatClaimedByDefault(ServiceSubtask serviceSubtask) { if (serviceSubtask == null || serviceSubtask.getId() == null) { return false; } // 重新读取当前子任务,所有判断只针对这一个 subid ServiceSubtask current = serviceSubtaskMapper.selectServiceSubtaskById(serviceSubtask.getId()); if (current == null) { return false; } // 只处理:丽水中医院、问卷、当前方式公众号、已领取、未提交 // 其他医院 orgid 不匹配时直接返回 false,继续走原补偿逻辑。 if (!IServiceSubtaskService.WECHAT_DEFAULT_COMPLETE_ORGID.equals(current.getOrgid()) || !"2".equals(current.getType()) || !"5".equals(current.getCurrentPreachform()) || !Long.valueOf(1L).equals(current.getSendstate()) || Long.valueOf(1L).equals(current.getSubmit())) { return false; } // 查询当前子任务自己的公众号发送方式,必须是已发送(2)或已领取(3) ServiceSubtaskPreachform query = new ServiceSubtaskPreachform(); query.setSubid(current.getId()); query.setTaskid(current.getTaskid()); query.setPreachform("5"); List preachforms = taskPreachformPort.selectServiceSubtaskPreachformList(query); if (CollectionUtils.isEmpty(preachforms)) { return false; } ServiceSubtaskPreachform currentPreachform = preachforms.stream() .filter(item -> "2".equals(item.getSendstate()) || "3".equals(item.getSendstate())) .findFirst().orElse(null); if (currentPreachform == null) { return false; } // 只给当前 subid 补齐默认选项;至少有一题默认选项才继续 int filled = fillWechatDefaultDetailForCurrentSubtask(current); if (filled <= 0) { log.info("【微信公众号默认完成】subid:{} 没有可填充的默认选项,跳过", current.getId()); return false; } // 当前公众号发送方式:已发送/已领取 -> 完成(9) ServiceSubtaskPreachform updatePreachform = new ServiceSubtaskPreachform(); updatePreachform.setId(currentPreachform.getId()); updatePreachform.setSubid(current.getId()); updatePreachform.setPreachform("5"); updatePreachform.setOrgid(current.getOrgid()); updatePreachform.setRemark("已领取未填写,按默认选项完成"); int preachformUpdated = taskPreachformPort.updateWechatPreachformComplete(updatePreachform); if (preachformUpdated == 0) { throw new BaseException("微信公众号默认完成失败:发送方式状态已变化,subid=" + current.getId()); } // 当前子任务:已领取(1) -> 完成(6),只更新这一个 subid ServiceSubtask complete = new ServiceSubtask(); complete.setId(current.getId()); complete.setOrgid(current.getOrgid()); complete.setFinishtime(new Date()); complete.setResult("success"); complete.setRemark("已领取未填写,按默认选项完成"); int subtaskUpdated = serviceSubtaskMapper.updateWechatDefaultComplete(complete); if (subtaskUpdated == 0) { throw new BaseException("微信公众号默认完成失败:子任务状态已变化,subid=" + current.getId()); } log.info("【微信公众号默认完成】subid:{},已按默认选项完成,填充题目数:{}", current.getId(), filled); return true; } /** * 仅给当前子任务补齐问卷单选/多选题中 default_value=2 的选项。 * 已有非空答案的题目跳过,不覆盖患者已填写内容。 * * @return 实际填充(或此前已由系统默认填充)的题目数 */ private int fillWechatDefaultDetailForCurrentSubtask(ServiceSubtask serviceSubtask) { Long templateId = serviceSubtask.getTemplateid(); ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); if (templateId == null && serviceTask != null) { templateId = serviceTask.getTemplateid(); } if (templateId == null) { return 0; } SvyTaskTemplateScript scriptQuery = new SvyTaskTemplateScript(); scriptQuery.setTemplateID(templateId); List scripts = svyTaskTemplateScriptService.selectSvyTaskTemplateScriptList(scriptQuery); if (CollectionUtils.isEmpty(scripts)) { return 0; } int filled = 0; for (SvyTaskTemplateScript script : scripts) { SvyTaskTemplateScriptVO scriptVO = DtoConversionUtils.sourceToTarget(script, SvyTaskTemplateScriptVO.class); SvyTaskTemplateScriptVO scriptWithOptions = svyTaskTemplateScriptService.selectInfoByCondition(scriptVO); if (scriptWithOptions == null || scriptWithOptions.getId() == null || CollectionUtils.isEmpty(scriptWithOptions.getSvyTaskTemplateTargetoptions()) || (!"1".equals(scriptWithOptions.getScriptType()) && !"2".equals(scriptWithOptions.getScriptType()))) { continue; } List options = scriptWithOptions.getSvyTaskTemplateTargetoptions(); List defaultOptions = options.stream() .filter(option -> option.getDefaultValue() != null && option.getDefaultValue() == 2L) .filter(option -> StringUtils.isNotBlank(option.getOptioncontent())) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(defaultOptions)) { continue; } // 已有非空答案则不覆盖,避免影响患者已填写内容 ServiceSubtaskDetail detailQuery = new ServiceSubtaskDetail(); detailQuery.setSubId(serviceSubtask.getId()); detailQuery.setScriptid(scriptWithOptions.getId()); List existingDetails = serviceSubtaskDetailMapper.selectServiceSubtaskDetailList(detailQuery); ServiceSubtaskDetail existing = CollectionUtils.isNotEmpty(existingDetails) ? existingDetails.get(0) : null; if (existing != null && (StringUtils.isNotBlank(existing.getAsrtext()) || StringUtils.isNotBlank(existing.getMatchedtext()))) { // 之前已由系统默认填充过的,计入已填充,保证重试幂等 if ("DEFAULT".equals(existing.getOperate())) { filled++; } continue; } String targetValue = options.stream() .map(SvyTaskTemplateTargetoption::getOptioncontent) .filter(StringUtils::isNotBlank) .collect(Collectors.joining("&")); String defaultValue = defaultOptions.stream() .map(SvyTaskTemplateTargetoption::getOptioncontent) .collect(Collectors.joining("&")); ServiceSubtaskDetail detail = new ServiceSubtaskDetail(); detail.setSubId(serviceSubtask.getId()); detail.setTaskid(serviceSubtask.getTaskid()); detail.setPatid(serviceSubtask.getPatid()); detail.setScriptid(scriptWithOptions.getId()); detail.setTemplatequestionnum(scriptWithOptions.getId()); detail.setQuestiontext(scriptWithOptions.getScriptContent()); detail.setCategoryid(scriptWithOptions.getCategoryid()); detail.setTargetid(scriptWithOptions.getTargetid() != null ? scriptWithOptions.getTargetid().intValue() : null); detail.setValueType(scriptWithOptions.getScriptType()); detail.setTargetvalue(targetValue); detail.setAsrtext(defaultValue); detail.setMatchedtext(defaultValue); detail.setOperate("DEFAULT"); detail.setTemplateType(2); detail.setLibTemplateid(serviceSubtask.getLibtemplateid() != null ? serviceSubtask.getLibtemplateid().intValue() : null); detail.setTemplateid(templateId.toString()); detail.setGuid(scriptWithOptions.getGuid()); detail.setOrgid(StringUtils.isNotEmpty(scriptWithOptions.getOrgid()) ? scriptWithOptions.getOrgid() : (serviceTask != null ? serviceTask.getOrgid() : null)); detail.setCreateTime(new Date()); detail.setUpdateTime(new Date()); if (existing != null) { detail.setId(existing.getId()); serviceSubtaskDetailMapper.updateServiceSubtaskDetail(detail); } else { serviceSubtaskDetailMapper.insertServiceSubtaskDetail(detail); } filled++; } return filled; } @Override public Map getHeLibraryCount(@RequestBody HeLibraryCountVO heLibraryCountVO) { if (ObjectUtils.isEmpty(heLibraryCountVO)) { return new HashMap<>(); } // 1. 查询分组统计(发送总量、发送成功量、已读量) List> groupStats = serviceSubtaskMapper.getHeLibraryCount(heLibraryCountVO); // 2. 计算各组的发送成功率和已读率 List> result = new ArrayList<>(); if (CollectionUtils.isNotEmpty(groupStats)) { for (Map row : groupStats) { long totalCount = row.get("totalCount") != null ? ((Number) row.get("totalCount")).longValue() : 0L; long sendSuccessCount = row.get("sendSuccessCount") != null ? ((Number) row.get("sendSuccessCount")).longValue() : 0L; long readCount = row.get("readCount") != null ? ((Number) row.get("readCount")).longValue() : 0L; // 发送成功率 double sendSuccessRate = totalCount > 0 ? (double) sendSuccessCount / totalCount : 0.0; // 已读率(基于发送成功的数量计算) double readRate = sendSuccessCount > 0 ? (double) readCount / sendSuccessCount : 0.0; row.put("sendSuccessRate", sendSuccessRate); row.put("readRate", readRate); result.add(row); } } Map resultMap = new HashMap<>(); resultMap.put("list", result); resultMap.put("total", result.size()); return resultMap; } @Override public List gethelibraryCountHyperlink(HeLibraryCountVO heLibraryCountVO) { String hyperLinkInfoType = heLibraryCountVO.getHyperLinkInfoType(); if (StringUtils.isNotEmpty(hyperLinkInfoType)) { heLibraryCountVO.setSendstate(null); heLibraryCountVO.setIsFinished(null); switch (hyperLinkInfoType) { case "totalCountInfo": break; case "sendSuccessCountInfo": heLibraryCountVO.setSendstate(6L); break; case "readCountInfo": heLibraryCountVO.setIsFinished("1"); break; default: break; } } List serviceSubtasks = serviceSubtaskMapper.gethelibraryCountHyperlink(heLibraryCountVO); return serviceSubtasks; } @Override public Map smsSubTask(Long subid) { log.info("smsSubTask的入参为:{}", subid); Map resultMap = new HashMap<>(); resultMap.put("code", "500"); resultMap.put("msg", "发送失败"); //获取患者的基本信息 ServiceSubtask serviceSubtask = selectServiceSubtaskById(subid); RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample(); String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key); String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key); String taskId = rsaPublicKeyExample.encryptedData(serviceSubtask.getTaskid().toString(), pub_key); //发送数据的封装 ServiceOutPath serviceOutPath = new ServiceOutPath(); serviceOutPath.setParam1(taskId); serviceOutPath.setParam2(patid); serviceOutPath.setParam3(serviceSubtask.getTaskName()); serviceOutPath.setParam6(subId); serviceOutPath.setCreateTime(new Date()); serviceOutPath.setOrgid(serviceSubtask.getOrgid()); iServiceOutPathService.insertServiceOutPath(serviceOutPath); String format = ShortCode.encode(serviceOutPath.getId()); String url = ""; SendMagParam sendMagParam = new SendMagParam(); sendMagParam.setType("4"); sendMagParam.setPhone(serviceSubtask.getPhone()); url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format; sendMagParam.setUrl(url); serviceOutPath.setRadix(format); serviceOutPath.setUpdateTime(new Date()); serviceOutPath.setUrl(url); iServiceOutPathService.updateServiceOutPath(serviceOutPath); // 参数值经端口取用(原为 sysConfigMapper.checkConfigKeyUnique + getConfigValue)。 // 语义等价:原判定"行存在"、这里判定"值非 null",而 sys_config.config_value 是 // varchar(500) NOT NULL DEFAULT '' ⇒ 二者不可能不同(详见 ISysConfigService javadoc)。 String smsContemt = sysConfigService.selectConfigByKey("wj.sms.template"); if (smsContemt != null) { sendMagParam.setContent(smsContemt.replace("${wjurl}", sendMagParam.getUrl())); } //短信发送:各站点对接方式差异较大,已收口到 ruoyi-message 模块 if (active.equals("nhfy")) { SendResult smsResult = smsSenderFactory.send(active, SmsSendRequest.of(sendMagParam.getPhone(), sendMagParam.getContent(), serviceSubtask.getOrgid())); if (smsResult.isOk()) { resultMap.put("code", "200"); resultMap.put("msg", "发送成功"); serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + ";短信发送成功(手动提交)" : "短信发送成功(手动提交)"); log.info("是否发送成功:{}", serviceSubtask.getRemark()); serviceSubtask.setSendstate(3L); serviceSubtask.setCurrentPreachform("4"); } } return resultMap; } @Override public Map weChatSubTask(Long subid) { log.info("smsSubTask的入参为:{}", subid); Map resultMap = new HashMap<>(); resultMap.put("code", "500"); resultMap.put("msg", "发送失败"); //获取患者的基本信息 ServiceSubtask serviceSubtask = selectServiceSubtaskById(subid); RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample(); String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key); String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key); String taskId = rsaPublicKeyExample.encryptedData(serviceSubtask.getTaskid().toString(), pub_key); //丽水中医院发送的是微信公众号 resultMap = wechatSubTask(subid); return resultMap; } public Map wechatSubTask(Long subid){ log.info("wechatSubTask的入参为:{}", subid); Map resultMap = new HashMap<>(); resultMap.put("code", "500"); resultMap.put("msg", "发送失败"); try{ //获取随访的基本信息 ServiceSubtask serviceSubtask = selectServiceSubtaskById(subid); //获取患者信息 PatArchive patArchive = taskArchivePort.findByPatid(serviceSubtask.getPatid()); RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample(); String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key); String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key); String taskId = rsaPublicKeyExample.encryptedData(serviceSubtask.getTaskid().toString(), pub_key); String url = localIP + ":" + req_path + "/outsideChainwt?param1=" + taskId + "¶m2=" + patid + "¶m3=" + URLEncoder.encode(serviceSubtask.getTaskName(), StandardCharsets.UTF_8.toString()) + "¶m5=false" + "$param6=" + subId; ServiceOutPath serviceOutPath = new ServiceOutPath(); serviceOutPath.setParam1(taskId); serviceOutPath.setParam2(patid); serviceOutPath.setParam3(serviceSubtask.getTaskName()); serviceOutPath.setParam6(subId); serviceOutPath.setCreateTime(new Date()); serviceOutPath.setOrgid(serviceSubtask.getOrgid()); iServiceOutPathService.insertServiceOutPath(serviceOutPath); String format = ShortCode.encode(serviceOutPath.getId()); serviceOutPath.setRadix(format); serviceOutPath.setUpdateTime(new Date()); serviceOutPath.setUrl(url); iServiceOutPathService.updateServiceOutPath(serviceOutPath); if (patArchive == null) { resultMap.put("code", -1); resultMap.put("message", "发送异常:" + "【公众号】未查询到患者档案信息,无法通过公众号发送"); return resultMap; } // his系统的患者id取自患者档案pat_archive.patid_his, // service_subtask查询未关联该字段(serviceSubtask.getPatidHis()恒为空),不能用于校验 if (StringUtils.isEmpty(patArchive.getPatidHis())) { resultMap.put("code", -1); resultMap.put("message", "发送异常:" + "【公众号】公众号发送失败,his系统的患者id为空"); return resultMap; } //机构配置校验、报文签名与返回判定均已收口到 ruoyi-message 的发送方实现 WechatSendRequest wechatRequest = new WechatSendRequest(); wechatRequest.setOrgid(serviceSubtask.getOrgid()); wechatRequest.setIdCard(serviceSubtask.getSfzh()); wechatRequest.setUrl(url); wechatRequest.setTitle(serviceSubtask.getTaskName()); wechatRequest.setContent(serviceSubtask.getTaskDesc()); wechatRequest.setPhone(patArchive.getTelcode()); wechatRequest.setPatientName(serviceSubtask.getSendname()); wechatRequest.setPatidHis(patArchive.getPatidHis()); SendResult wechatResult = wechatSenderFactory.send(active, wechatRequest); //发送完成后,修改状态 serviceSubtask.setSendstate(3L); if (wechatResult.isOk()) { serviceSubtask.setResult("success"); resultMap.put("code", "200"); resultMap.put("msg", "发送成功"); } else { log.error("【sfHandlle】公众号发送失败,患者信息:{},错误信息:{}", serviceSubtask, wechatResult.getMessage()); resultMap.put("code", -1); resultMap.put("message", "【公众号】公众号发送失败"); return resultMap; } } catch (Exception e) { String guid = UUID.randomUUID().toString(); log.error("【sfHandlle】长期任务公众号发送失败,原因:{},GUID:{}", e.getMessage(), guid); resultMap.put("code", -1); resultMap.put("message", "【公众号】长期任务公众号发送失败,原因:" + e.getMessage()); return resultMap; } return resultMap; } /* * 2026-10-21 已删除 saveServiceSubtaskDetail(...)。 * 它原来的语义是"边算默认值边落库,最后返回布尔值",调用方在返回 false 时把该 sub_id 下的 * 全部明细置 del_flag='1'(连患者真实作答一起删)。 * 现在拆成 buildDefaultDetails(...)(只算不写) + persistDefaultDetails(...)(只增不删), * 任何一题缺默认值就整份跳过,不会再产生"删除"动作。 */ /** * 按「问卷模板」构造一条"默认值明细"(只计算、不落库) *

* 2026-10-21 由 {@code setWJDetailInfo}(算完就直接 insert/update,失败返回 0)改造而来: * 现在只负责把实体拼出来,由 {@link #persistDefaultDetails} 统一落库。 * * @return 明细;该题没配默认值(单/多选题一个默认选项都没有)时返回 {@code null},表示整份问卷不处理 */ private ServiceSubtaskDetail buildWJDetail(SvyTaskTemplateScriptVO svyTaskTemplateScriptVO, ServiceSubtask serviceSubtask) { if (svyTaskTemplateScriptVO == null) { return null; } log.info("-----buildWJDetail的入参为:{}", svyTaskTemplateScriptVO); ServiceSubtaskDetailVO serviceSubtaskDetailVO = new ServiceSubtaskDetailVO(); if ("1".equals(svyTaskTemplateScriptVO.getScriptType()) || "2".equals(svyTaskTemplateScriptVO.getScriptType())) { //1、2为单选或多选 for (SvyTaskTemplateTargetoption svyTaskTemplateTargetoption : svyTaskTemplateScriptVO.getSvyTaskTemplateTargetoptions()) { //将问题选项记录下来 if (StringUtils.isEmpty(serviceSubtaskDetailVO.getTargetvalue())) { serviceSubtaskDetailVO.setTargetvalue(svyTaskTemplateTargetoption.getOptioncontent()); } else { serviceSubtaskDetailVO.setTargetvalue(serviceSubtaskDetailVO.getTargetvalue() + "&" + svyTaskTemplateTargetoption.getOptioncontent()); } if (svyTaskTemplateTargetoption.getDefaultValue() != null && svyTaskTemplateTargetoption.getDefaultValue() == 2) { serviceSubtaskDetailVO.setAsrtext(StringUtils.isNotBlank(serviceSubtaskDetailVO.getAsrtext()) ? serviceSubtaskDetailVO.getAsrtext() + "&" + svyTaskTemplateTargetoption.getOptioncontent() : svyTaskTemplateTargetoption.getOptioncontent()); serviceSubtaskDetailVO.setMatchedtext(StringUtils.isNotBlank(serviceSubtaskDetailVO.getMatchedtext()) ? serviceSubtaskDetailVO.getMatchedtext() + "&" + svyTaskTemplateTargetoption.getOptioncontent() : svyTaskTemplateTargetoption.getOptioncontent()); } } //如果asrtext和matchedtext都为空,则没有默认值,则不进行处理(返回 null = 整份问卷跳过) if (StringUtils.isEmpty(serviceSubtaskDetailVO.getAsrtext()) && StringUtils.isEmpty(serviceSubtaskDetailVO.getMatchedtext())) { return null; } } ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); serviceSubtaskDetailVO.setQuestiontext(svyTaskTemplateScriptVO.getScriptContent()); serviceSubtaskDetailVO.setCategoryid(svyTaskTemplateScriptVO.getCategoryid()); serviceSubtaskDetailVO.setTaskid(serviceSubtask.getTaskid()); serviceSubtaskDetailVO.setTargetid(svyTaskTemplateScriptVO.getTargetid() != null ? svyTaskTemplateScriptVO.getTargetid().intValue() : null); serviceSubtaskDetailVO.setPatid(serviceSubtask.getPatid()); serviceSubtaskDetailVO.setScriptid(svyTaskTemplateScriptVO.getId()); serviceSubtaskDetailVO.setTemplatequestionnum(StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getScriptno()) ? Long.valueOf(svyTaskTemplateScriptVO.getScriptno()) : null); serviceSubtaskDetailVO.setValueType(svyTaskTemplateScriptVO.getScriptType()); serviceSubtaskDetailVO.setComment(null); serviceSubtaskDetailVO.setCreateTime(new Date()); serviceSubtaskDetailVO.setUpdateTime(new Date()); serviceSubtaskDetailVO.setTemplateType(2); serviceSubtaskDetailVO.setLibTemplateid(serviceSubtask.getLibtemplateid() != null ? serviceSubtask.getLibtemplateid().intValue() : null); if (ObjectUtils.isNotEmpty(serviceTask)) { serviceSubtaskDetailVO.setGuid(serviceTask.getGuid()); serviceSubtaskDetailVO.setOrgid(serviceTask.getOrgid()); } serviceSubtaskDetailVO.setSubId(serviceSubtask.getId()); serviceSubtaskDetailVO.setTemplatequestionnum(svyTaskTemplateScriptVO.getId()); return DtoConversionUtils.sourceToTarget(serviceSubtaskDetailVO, ServiceSubtaskDetail.class); } /** * 按「电话模板」构造一条"默认值明细"(只计算、不落库),语义同 {@link #buildWJDetail} */ private ServiceSubtaskDetail buildSFDetail(IvrTaskTemplateScriptVO ivrTaskTemplateScriptVO, ServiceSubtask serviceSubtask) { if (ivrTaskTemplateScriptVO == null) { return null; } ServiceSubtaskDetailVO serviceSubtaskDetailVO = new ServiceSubtaskDetailVO(); if (ivrTaskTemplateScriptVO.getScriptType() != null && (ivrTaskTemplateScriptVO.getScriptType().equals("1") || ivrTaskTemplateScriptVO.getScriptType().equals("2"))) { //1、2为单选或多选 for (IvrTaskTemplateTargetoption ivrTaskTemplateTargetoption : ivrTaskTemplateScriptVO.getIvrTaskScriptTargetoptionList()) { //将问题选项记录下来 if (StringUtils.isEmpty(serviceSubtaskDetailVO.getTargetvalue())) { serviceSubtaskDetailVO.setTargetvalue(ivrTaskTemplateTargetoption.getTargetvalue()); } else { serviceSubtaskDetailVO.setTargetvalue(serviceSubtaskDetailVO.getTargetvalue() + "&" + ivrTaskTemplateTargetoption.getTargetvalue()); } if (ivrTaskTemplateTargetoption.getDefaultValue() != null && ivrTaskTemplateTargetoption.getDefaultValue() == 2) { //医生手动填报时,值是在ivrtext中 serviceSubtaskDetailVO.setAsrtext(StringUtils.isEmpty(serviceSubtaskDetailVO.getAsrtext()) ? ivrTaskTemplateTargetoption.getTargetvalue() : serviceSubtaskDetailVO.getAsrtext() + "&" + ivrTaskTemplateTargetoption.getTargetvalue()); serviceSubtaskDetailVO.setMatchedtext(StringUtils.isEmpty(serviceSubtaskDetailVO.getMatchedtext()) ? ivrTaskTemplateTargetoption.getTargetvalue() : serviceSubtaskDetailVO.getMatchedtext() + "&" + ivrTaskTemplateTargetoption.getTargetvalue()); } } //如果asrtext和matchedtext都为空,则没有默认值,不进行处理(返回 null = 整份问卷跳过) if (StringUtils.isEmpty(serviceSubtaskDetailVO.getAsrtext()) && StringUtils.isEmpty(serviceSubtaskDetailVO.getMatchedtext())) { return null; } } else if (ivrTaskTemplateScriptVO.getScriptType() == null) { return null; } serviceSubtaskDetailVO.setTargetid(ivrTaskTemplateScriptVO.getTargetid() != null ? ivrTaskTemplateScriptVO.getTargetid().intValue() : null); serviceSubtaskDetailVO.setQuestiontext(ivrTaskTemplateScriptVO.getScriptContent()); serviceSubtaskDetailVO.setTaskid(serviceSubtask.getTaskid()); serviceSubtaskDetailVO.setPatid(serviceSubtask.getPatid()); serviceSubtaskDetailVO.setScriptid(ivrTaskTemplateScriptVO.getScriptID() == null ? ivrTaskTemplateScriptVO.getId() : ivrTaskTemplateScriptVO.getScriptID()); serviceSubtaskDetailVO.setTemplatequestionnum(ivrTaskTemplateScriptVO.getId()); serviceSubtaskDetailVO.setValueType(ivrTaskTemplateScriptVO.getScriptType()); serviceSubtaskDetailVO.setComment(null); serviceSubtaskDetailVO.setCreateTime(new Date()); serviceSubtaskDetailVO.setGuid(ivrTaskTemplateScriptVO.getGuid()); serviceSubtaskDetailVO.setOrgid(ivrTaskTemplateScriptVO.getOrgid()); serviceSubtaskDetailVO.setUpdateTime(new Date()); serviceSubtaskDetailVO.setSubId(serviceSubtask.getId()); serviceSubtaskDetailVO.setTemplatequestionnum(ivrTaskTemplateScriptVO.getId()); serviceSubtaskDetailVO.setTemplateType(1); serviceSubtaskDetailVO.setTemplateid(ivrTaskTemplateScriptVO.getTemplateID() == null ? null : ivrTaskTemplateScriptVO.getTemplateID().toString()); serviceSubtaskDetailVO.setLibTemplateid(serviceSubtask.getLibtemplateid() != null ? serviceSubtask.getLibtemplateid().intValue() : null); return DtoConversionUtils.sourceToTarget(serviceSubtaskDetailVO, ServiceSubtaskDetail.class); } public String scanGenerateSubtask(ServiceTask serviceTaskVo) { String content = ""; String ip = localIP; ServiceTask serviceTask = new ServiceTask(); serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceTaskVo.getTaskid()); if (ObjectUtils.isNotEmpty(serviceTask)) { try { ServiceTaskdept serviceTaskdept = new ServiceTaskdept(); if (ObjectUtils.isNotEmpty(serviceTaskVo.getDeptcode())) { serviceTaskdept.setDeptType("1"); serviceTaskdept.setDeptCode(serviceTaskVo.getDeptcode()); } if (ObjectUtils.isNotEmpty(serviceTaskVo.getLeavehospitaldistrictcode())) { serviceTaskdept.setDeptType("2"); serviceTaskdept.setDeptCode(serviceTaskVo.getLeavehospitaldistrictcode()); } serviceTaskdept.setServiceType(serviceTask.getServiceType()); serviceTaskdept.setOrgid(serviceTask.getOrgid()); serviceTaskdept.setTaskId(serviceTaskVo.getTaskid()); List serviceTaskdepts = serviceTaskdeptService.selectServiceTaskdeptList(serviceTaskdept); if (!CollectionUtils.isEmpty(serviceTaskdepts)) { PatArchive patArchive = new PatArchive(); patArchive.setId(999999999L); patArchive.setName("虚拟患者"); //封装serviceSubtask ServiceSubtask serviceSubtask = boxedServiceSubtask(serviceTask, serviceTaskdepts.get(0), patArchive); int i = serviceSubtaskMapper.insertServiceSubtask(serviceSubtask); //根据生成外链 if (ObjectUtils.isNotEmpty(serviceSubtask.getTaskid()) && ObjectUtils.isNotEmpty(serviceSubtask.getPatid()) && ObjectUtils.isNotEmpty(serviceSubtask.getId())) { RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample(); String taskId = rsaPublicKeyExample.encryptedData(serviceSubtask.getTaskid().toString(), pub_key); String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key); String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key); ServiceOutPath serviceOutPath = new ServiceOutPath(); serviceOutPath.setParam1(taskId); serviceOutPath.setParam2(patid); serviceOutPath.setParam3(serviceTask.getTaskName()); serviceOutPath.setParam6(subId); serviceOutPath.setCreateTime(new Date()); serviceOutPath.setOrgid(serviceTask.getOrgid()); iServiceOutPathService.insertServiceOutPath(serviceOutPath); String format = ShortCode.encode(serviceOutPath.getId()); serviceOutPath.setRadix(format); serviceOutPath.setUpdateTime(new Date()); String url = StringUtils.isNotEmpty(req_path) ? ip + ":" + req_path + "/wt?p=" + format : ip + "/wt?p=" + format; content = url; serviceOutPath.setUrl(url); iServiceOutPathService.updateServiceOutPath(serviceOutPath); } } } catch (Exception e) { e.printStackTrace(); log.error("【扫码生成任务】处理异常:{}", e.getMessage()); } } return content; } public ServiceSubtask boxedServiceSubtask(ServiceTask serviceTask, ServiceTaskdept serviceTaskdept, PatArchive patArchive) { ServiceSubtask serviceSubtask = DtoConversionUtils.sourceToTarget(serviceTask, ServiceSubtask.class); serviceSubtask.setTaskid(serviceTask.getTaskid()); if (StringUtils.isNotEmpty(serviceTask.getLibtemplateid())) serviceSubtask.setLibtemplateid(Long.valueOf(serviceTask.getLibtemplateid())); // serviceSubtask.setNurseId(patMedInhosp1.getNurseId()); // serviceSubtask.setNurseName(patMedInhosp1.getNurseName()); // serviceSubtask.setDrcode(patMedInhosp1.getDrcode()); // serviceSubtask.setDrname(patMedInhosp1.getDrname()); if (StringUtils.isNotEmpty(serviceTaskdept.getDeptType()) && serviceTaskdept.getDeptType().equals("1")) { serviceSubtask.setLeaveldeptcode(serviceTaskdept.getDeptCode()); serviceSubtask.setLeaveldeptname(serviceTaskdept.getDeptName()); } else { serviceSubtask.setLeavehospitaldistrictcode(serviceTaskdept.getDeptCode()); serviceSubtask.setLeavehospitaldistrictname(serviceTaskdept.getDeptName()); } serviceSubtask.setTemplateid(serviceTask.getTemplateid()); serviceSubtask.setTemplatename(serviceTask.getTemplatename()); serviceSubtask.setPatid(patArchive.getId()); serviceSubtask.setSendname(patArchive.getName()); serviceSubtask.setSfzh(patArchive.getIdcardno()); serviceSubtask.setPhone(patArchive.getTelcode()); if (StringUtils.isBlank(patArchive.getTelcode())) serviceSubtask.setPhone(patArchive.getRelativetelcode()); serviceSubtask.setSex(patArchive.getSex()); serviceSubtask.setAge(patArchive.getAge()); serviceSubtask.setSendstate(3L); // serviceSubtask.setManagementDoctor(patMedInhosp1.getManagementDoctor()); // serviceSubtask.setManagementDoctorCode(patMedInhosp1.getManagementDoctorCode()); serviceSubtask.setServiceType(serviceTask.getServiceType()); serviceSubtask.setPreachform(serviceTask.getPreachform()); serviceSubtask.setHospType("8"); serviceSubtask.setCreateTime(new Date()); serviceSubtask.setUpdateTime(new Date()); // serviceSubtask.setCreateBy(patMedInhosp1.getNurseName()); // serviceSubtask.setLeavehospitaldistrictcode(patMedInhosp1.getLeavehospitaldistrictcode()); // serviceSubtask.setLeavehospitaldistrictname(patMedInhosp1.getLeavehospitaldistrictname()); serviceSubtask.setUpdateBy(serviceTask.getUpdateBy()); serviceSubtask.setUpdateTime(new Date()); serviceTask.setSendDay(1L); Date newDate = new Date(); serviceSubtask.setLongSendTime(newDate); serviceSubtask.setVisitTime(newDate); // 院区:/scanGenerateSubtask 是匿名接口(SecurityConfig permitAll),取不到登录用户; // 而 service_task.campusid 在本库是占位值 '1',直接沿用会让统计接口(@AddOrgId 按院区过滤)查不到数据。 // 这里用任务配置的病区(其次科室)反查 sys_dept.campusid 落库,保证问卷统计能按院区取到。 String campusIdByDept = queryCampusIdByDeptCode(serviceSubtask.getLeavehospitaldistrictcode(), serviceTask.getOrgid()); if (StringUtils.isEmpty(campusIdByDept)) { campusIdByDept = queryCampusIdByDeptCode(serviceSubtask.getLeaveldeptcode(), serviceTask.getOrgid()); } if (StringUtils.isNotEmpty(campusIdByDept)) { serviceSubtask.setCampusid(campusIdByDept); } // 只配了科室(没有病区)的满意度任务:这道答卷在按病区筛选的报表里统计不到,留日志便于运维发现 if (StringUtils.isEmpty(serviceSubtask.getLeavehospitaldistrictcode()) && ("6".equals(serviceSubtask.getServiceType()) || "14".equals(serviceSubtask.getServiceType()))) { log.warn("【扫码生成任务】满意度子任务没有病区,按病区筛选的报表将统计不到该答卷:taskid={}, deptcode={}, campusid={}", serviceSubtask.getTaskid(), serviceSubtask.getLeaveldeptcode(), serviceSubtask.getCampusid()); } return serviceSubtask; } /** * 按科室/病区编码反查所属院区(查不到返回 null) */ private String queryCampusIdByDeptCode(String deptCode, String orgid) { if (StringUtils.isEmpty(deptCode)) { return null; } try { SysDept sysDept = sysDept2Mapper.selectDeptByCode(deptCode, orgid); return sysDept == null ? null : sysDept.getCampusid(); } catch (Exception e) { log.warn("按编码反查院区失败:deptCode={}, orgid={}, err={}", deptCode, orgid, e.getMessage()); return null; } } /** * Ai 匹配选项 * * @param questionText * @param voiceText * @param options * @return */ @Override public Integer matchOptionIndex(String url, String questionText, String voiceText, List options, String uuid) { JSONObject jsonObject = new JSONObject(); jsonObject.put("userQuestion", questionText); jsonObject.put("userAnswer", voiceText); jsonObject.put("options", options); jsonObject.put("uuid", uuid); String jsonString = jsonObject.toJSONString(); String result = null; // String url = "http://localhost:8099/matchOptionIndex"; if (StringUtils.isNotEmpty(url)) { try { Map headers = new HashMap<>(); headers.put("Content-Type", "application/json"); result = HttpUtils.sendPostByHeader(url, jsonString, headers); } catch (Exception e) { log.error("AI识别失败", e); } } if (StringUtils.isNotEmpty(result) && result.matches("^-?\\d+$")) { return Integer.parseInt(result); } else { return -1; } } //获取任务组信息 private void findServiceTaskScheduleVO(ServiceTaskVO serviceTaskVO) { if (StringUtils.isNotEmpty(serviceTaskVO.getAppltype()) && serviceTaskVO.getAppltype().equals("5")) { //任务组信息 ServiceTaskSchedule schedule = serviceTaskScheduleService.selectByTaskid(serviceTaskVO.getTaskid()); if (ObjectUtils.isNotEmpty(schedule)) { ServiceTaskScheduleVO serviceTaskScheduleVO = DtoConversionUtils.sourceToTarget(schedule, ServiceTaskScheduleVO.class); List scheduleDetailList = serviceTaskScheduleService.selectDetailByScheduleid(schedule.getId()); serviceTaskScheduleVO.setDetailList(scheduleDetailList); serviceTaskVO.setServiceTaskScheduleVO(serviceTaskScheduleVO); } } } // --------------------------------------------------------------------- // 说明:原私有 getWXCode / encode 已随发送方一起收口到 ruoyi-message 模块 // (XinHuaMpApi),此处已删除,避免三份拷贝各写一套签名逻辑。 // // 另:本类原本还有一个 @Test 标注的 TestMatch()(开发期手写的 AI 选项匹配调试方法), // 全仓无任何调用点。它会把 org.junit 拖进【生产】源码依赖,而 ruoyi-task 是 // jar 模块、不带 junit —— 故随模块化一并删除(属死代码,行为无影响)。 // --------------------------------------------------------------------- }