| | |
| | | return "再次随访任务创建失败,找不到对应任务 taskid = " + serviceSubtask.getTaskid() + ", 再请次重试"; |
| | | } |
| | | // nexttaskflag=0 表示任务链终止,不允许再生成 |
| | | if ("0".equals(serviceTask.getNexttaskflag())) { |
| | | log.info("无需再次随访,任务已标记无后续随访, taskid = {}", serviceSubtask.getTaskid()); |
| | | return "无需再次随访,该任务无后续随访安排"; |
| | | } |
| | | // if ("0".equals(serviceTask.getNexttaskflag())) { |
| | | // log.info("无需再次随访,任务已标记无后续随访, taskid = {}", serviceSubtask.getTaskid()); |
| | | // return "无需再次随访,该任务无后续随访安排"; |
| | | // } |
| | | // 幂等校验:同一原任务只允许生成一条二次随访 |
| | | ServiceSubtaskEntity againQuery = new ServiceSubtaskEntity(); |
| | | againQuery.setUpid(serviceSubtask.getId().intValue()); |
| | |
| | | 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()) |
| | |
| | | serviceSubtaskAgain.setIsVisitAgain(1); |
| | | serviceSubtaskAgain.setCreateTime(now); |
| | | serviceSubtaskAgain.setUpdateTime(now); |
| | | |
| | | // 二次随访时间:上次随访完成时间(未完成则当前时间)+ 下一任务发送天数;过去时间兜底为当前时间 |
| | | applyAgainVisitTime(serviceSubtaskAgain, serviceSubtask, nextServiceTask, config, now); |
| | | // 新任务的随访方式记录本次选择的再次随访方式;resource 本身不落库 |
| | | serviceSubtaskAgain.setVisitType(resource); |
| | | serviceSubtaskAgain.setVisitDeptCode(visitDeptCode); |
| | |
| | | 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())) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * 取逗号串里的第一个值(任务上科室/病区是多选,而 {@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})的字段搬运。 |
| | | * <p> |
| | | * <b>为什么不能直接 {@code DtoConversionUtils.sourceToTarget(serviceTaskVO, ServiceSubtask.class)}:</b> |
| | | * 它是纯同名拷贝,而两边同名的 {@code deptcode / deptname} <b>语义不同</b>: |
| | | * <ul> |
| | | * <li>{@code ServiceTaskVO.deptcode / deptname} = 任务的「适用科室」, |
| | | * 出院随访(serviceType=2)/ 出院宣教(4)/ 门诊随访(3)等场景下就是<b>离院科室</b>;</li> |
| | | * <li>{@code ServiceSubtask.deptcode / deptname} = <b>在院科室</b> |
| | | * (2026-11 由原 sendlimitpbegin/pend 复用而来,见 {@code ServiceSubtask} 字段注释)。</li> |
| | | * </ul> |
| | | * 于是纯同名拷贝会把「离院科室」写进「在院科室」列,后果有两个: |
| | | * <ol> |
| | | * <li>按在院维度筛({@code deptcodes} → {@code service_subtask.deptcode})会误命中这些子任务;</li> |
| | | * <li>按离院维度筛({@code leaveldeptcodes} → {@code service_subtask.leaveldeptcode})时, |
| | | * 患者自己没带科室的那些(前端手动勾选患者很常见)会因为 {@code leaveldeptcode} 为空而查不到。</li> |
| | | * </ol> |
| | | * 因此这里按项目既定口径({@code doc/service_subtask_字段改名_改动清单.md} §8:这几条 |
| | | * 「长期任务 / 任务组 / 手动建任务」路径<b>不填在院维度</b>)统一处理: |
| | | * <b>在院维度 4 列清空</b>(在院科室/在院病区只有 HIS 链路能从 {@code pat_med_inhosp} 拿到), |
| | | * <b>科室 / 病区一律落离院维度</b>({@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 结果 |
| | |
| | | // } |
| | | |
| | | //将任务信息放到服务表中 |
| | | ServiceSubtask serviceSubtask = DtoConversionUtils.sourceToTarget(serviceTaskVO, ServiceSubtask.class); |
| | | // 科室/病区按「离院维度」归位(出院随访的科室病区就是离院科室/病区),见 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.setInhospid(patTaskRelevance.getHospid()); |
| | | //新建完成就是待发送状态 |
| | | serviceSubtask.setSendstate(2L); |
| | | String subtaskDeptCode = patTaskRelevance.getDeptcode(); |
| | | if (StringUtils.isEmpty(subtaskDeptCode) && StringUtils.isNotEmpty(serviceTaskVO.getDeptcode())) { |
| | | // service_subtask.leaveldeptcode 为单值字段,不能写入任务的多科室拼接串,取第一个科室兜底 |
| | | subtaskDeptCode = serviceTaskVO.getDeptcode().split(",")[0].trim(); |
| | | } |
| | | serviceSubtask.setLeaveldeptcode(subtaskDeptCode); |
| | | serviceSubtask.setLeaveldeptname(StringUtils.isNotEmpty(patTaskRelevance.getDeptName()) ? patTaskRelevance.getDeptName() : serviceTaskVO.getDeptname()); |
| | | serviceSubtask.setLeavehospitaldistrictcode(patTaskRelevance.getLeavehospitaldistrictcode()); |
| | | serviceSubtask.setLeavehospitaldistrictname(patTaskRelevance.getLeavehospitaldistrictname()); |
| | | // 离院维度(出院随访 = 出院科室 / 出院病区): |
| | | // 患者自带的出院科室/病区优先,患者侧没带(前端手动勾选很常见)时回退到任务配置, |
| | | // 不能无条件覆盖 —— 否则会把 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()); |
| | |
| | | } |
| | | if (CollectionUtils.isNotEmpty(serviceTaskVO.getPatTaskRelevances())) { |
| | | for (PatTaskRelevance patTaskRelevance : serviceTaskVO.getPatTaskRelevances()) { |
| | | ServiceSubtask serviceSubtask = DtoConversionUtils.sourceToTarget(serviceTaskVO, ServiceSubtask.class); |
| | | // 科室/病区按「离院维度」归位(出院随访的科室病区就是离院科室/病区),见 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.setAddr(patTaskRelevance.getAddr()); |
| | | serviceSubtask.setPatid(patTaskRelevance.getPatid()); |
| | | serviceSubtask.setOpenid(patTaskRelevance.getOpenid()); |
| | | serviceSubtask.setLeaveldeptcode(patTaskRelevance.getDeptcode()); |
| | | serviceSubtask.setLeavehospitaldistrictname(patTaskRelevance.getLeavehospitaldistrictname()); |
| | | serviceSubtask.setLeavehospitaldistrictcode(patTaskRelevance.getLeavehospitaldistrictcode()); |
| | | serviceSubtask.setLeaveldeptname(patTaskRelevance.getDeptName()); |
| | | // 离院维度:患者自带的出院科室/病区优先,没带时回退到任务配置(否则会把 |
| | | // 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()); |
| | |
| | | } else { |
| | | groupKey = "deptcode"; |
| | | } |
| | | } else if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 3) { |
| | | // 病种统计:按任务ID分组,每个任务即一个病种随访任务 |
| | | groupKey = "taskid"; |
| | | } |
| | | List<ServiceSubtaskStatistic> serviceSubtaskStatistics = new ArrayList<>(); |
| | | // 根据条件进行分组 |
| | |
| | | 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; |
| | |
| | | continue; |
| | | } |
| | | ServiceSubtaskStatistic statistic = getStatistic(serviceSubtaskList, serviceSubtaskCountReq.getFollowUpCountStyle(), serviceSubtaskCountReq.getVisitCount()); |
| | | if ("taskid".equals(groupKey)) { |
| | | applyTaskGroupInfo(statistic, serviceSubtaskList); |
| | | } |
| | | if (ObjectUtils.isNotEmpty(jsRates)) { |
| | | Map<String, Object> jsRateMap = jsRates.get(collectKey); |
| | | BigDecimal jsRate = new BigDecimal("0"); |
| | |
| | | ssRate.setGroupKey(groupKey); |
| | | ssRate.setGroupKeyList(groupKeyList); |
| | | ssRate.setRateDay(serviceSubtaskCountReq.getRateDay()); |
| | | return serviceSubtaskMapper.selectTimelyRateBatch(ssRate); |
| | | Map<String, Map<String, Object>> rateResult = serviceSubtaskMapper.selectTimelyRateBatch(ssRate); |
| | | if (rateResult == null || rateResult.isEmpty()) { |
| | | return rateResult; |
| | | } |
| | | // taskid 为数值类型,MyBatis 返回的 Map key 可能是 Long,这里统一转成 String 与分组 key 对齐 |
| | | Map<String, Map<String, Object>> jsRates = new HashMap<>(); |
| | | for (Map.Entry<String, Map<String, Object>> entry : rateResult.entrySet()) { |
| | | jsRates.put(String.valueOf(entry.getKey()), entry.getValue()); |
| | | } |
| | | return jsRates; |
| | | } |
| | | |
| | | /** |
| | |
| | | ServiceSubtaskStatistic totalRow = calculateTotalRow(sfStatistics); |
| | | totalRow.setLeavehospitaldistrictname("总计"); |
| | | totalRow.setDeptname("总计"); |
| | | if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 3) { |
| | | totalRow.setTaskName("总计"); |
| | | } |
| | | sfStatistics.add(totalRow); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | return serviceSubtaskStatistics; |
| | | } |
| | | |
| | | /** |
| | | * 病种统计(按 taskid 分组)时补齐任务ID、任务名称和疾病病种。 |
| | | * |
| | | * @param statistic 统计结果 |
| | | * @param serviceSubtaskList 当前任务分组下的子任务 |
| | | */ |
| | | private void applyTaskGroupInfo(ServiceSubtaskStatistic statistic, List<ServiceSubtask> 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<ServiceSubtask> serviceSubtaskList, String followUpCountStyle, Integer visitCount) { |
| | |
| | | } 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 |
| | |
| | | List<ServiceSubtaskStatistic> sumStatistics = serviceSubtaskMapper.getSfStatisticsScriptSum(serviceSubtaskCountReq); |
| | | if (CollectionUtils.isEmpty(sumStatistics)) { |
| | | return serviceSubtaskStatistics; |
| | | } |
| | | |
| | | /* |
| | | * 病种统计(按 taskid 分组)时补齐任务ID、任务名称和疾病病种。 |
| | | * 聚合 SQL 已返回 taskid/task_name,这里再补 diag_type。 |
| | | */ |
| | | if ("taskid".equals(groupKey)) { |
| | | Map<Long, String> 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)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* |
| | |
| | | result.put("rows", new ArrayList<>(pageCounts)); |
| | | result.put("data", pageData); |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 问题选项数字下钻:返回选择了指定选项的 service_subtask 列表。 |
| | | * <p> |
| | | * 统计明细中的选项数量来自 service_subtask_detail 的 |
| | | * IFNULL(matchedtext, asrtext),因此下钻必须使用同一题目的相同选项进行匹配。 |
| | | * |
| | | * @param serviceSubtaskCountReq 下钻条件 |
| | | * @return service_subtask 列表 |
| | | */ |
| | | @Override |
| | | public List<ServiceSubtask> 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 补齐题目内容和任务类型。 |
| | | * <p> |
| | | * 统计明细按“题目内容 + 任务类型”合并,同一道题复制到多个任务模板时 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()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 微信公众号已领取未填写:按题目默认选项补齐当前子任务,并将当前子任务完成。 |
| | | * <p> |
| | | * 所有查询、明细写入、状态更新都只使用当前 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<ServiceSubtaskPreachform> 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<SvyTaskTemplateScript> 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<SvyTaskTemplateTargetoption> options = scriptWithOptions.getSvyTaskTemplateTargetoptions(); |
| | | List<SvyTaskTemplateTargetoption> 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<ServiceSubtaskDetail> 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<String, Object> getHeLibraryCount(@RequestBody HeLibraryCountVO heLibraryCountVO) { |
| | | if (ObjectUtils.isEmpty(heLibraryCountVO)) { |