| | |
| | | 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.task.mapper.ServiceOutPathMapper; |
| | | import com.ruoyi.task.service.IServiceOutPathService; |
| | | import com.ruoyi.task.domain.ServiceSubtaskPreachform; |
| | | import com.ruoyi.task.api.spi.TaskPreachformPort; |
| | | import com.ruoyi.task.mapper.ServiceSubtaskPreachformMapper; |
| | | import com.ruoyi.task.api.spi.TaskArchivePort; |
| | | import com.ruoyi.task.api.spi.TaskFtpPort; |
| | | import com.ruoyi.task.api.spi.TaskSysConfigPort; |
| | | import com.ruoyi.task.api.spi.TaskSysDeptPort; |
| | | import com.ruoyi.task.common.ScheduleSubtaskBuilder; |
| | | import com.ruoyi.task.domain.ServiceTaskScheduleVO; |
| | | import com.ruoyi.task.service.IServiceSubtaskService; |
| | |
| | | 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业务层处理 |
| | |
| | | @Slf4j |
| | | @Service |
| | | public class ServiceSubtaskServiceImpl implements IServiceSubtaskService { |
| | | |
| | | /** |
| | | * 随访子任务组装器(原 smartor 侧 IPatMedInhospService#boxedServiceSubtask 在本模块的落地实现)。 |
| | | * <p> |
| | | * 二次随访要用「下一任务配置 + 出院记录 + 患者档案」组装新的 service_subtask, |
| | | * 这段口径与长期任务生成完全一致,因此直接复用本模块已有的组装器,不再复制一份。 |
| | | */ |
| | | @Autowired |
| | | private OperationSubtaskWriter operationSubtaskWriter; |
| | | |
| | | /** |
| | | * 满意度模块对外门面(常驻 Bean)。 |
| | |
| | | private ServiceSubtaskMapper serviceSubtaskMapper; |
| | | |
| | | @Autowired |
| | | private TaskPreachformPort taskPreachformPort; |
| | | private ServiceSubtaskPreachformMapper taskPreachformPort; |
| | | |
| | | @Autowired |
| | | private ServiceSubtaskDetailMapper serviceSubtaskDetailMapper; |
| | |
| | | private TaskArchivePort taskArchivePort; |
| | | |
| | | @Autowired |
| | | private ScheduleSubtaskBuilder scheduleSubtaskBuilder; |
| | | private ISysDeptService sysDeptService; |
| | | |
| | | @Autowired |
| | | private TaskFtpPort taskFtpPort; |
| | | private ScheduleSubtaskBuilder scheduleSubtaskBuilder; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | |
| | | @Autowired |
| | | private TaskSysConfigPort taskSysConfigPort; |
| | | private ISysConfigService sysConfigService; |
| | | |
| | | /** |
| | | * 消息发送方工厂(短信/微信公众号),替代原来直接调用各站点发送代码的写法 |
| | |
| | | |
| | | |
| | | @Autowired |
| | | private TaskSysDeptPort taskSysDeptPort; |
| | | private SysDept2Mapper sysDept2Mapper; |
| | | |
| | | @Value("${spring.profiles.active}") |
| | | private String active; |
| | |
| | | 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; |
| | | |
| | | /** |
| | | * 查询单一任务(随访) |
| | |
| | | if (StringUtils.isEmpty(serviceSubtask.getCurrentPreachform())) { |
| | | if (StringUtils.isNotEmpty(serviceSubtask.getPreachform())) { |
| | | //默认取第一个 |
| | | serviceSubtaskRes.setCurrentPreachform(serviceSubtask.getPreachform().split(",")[0]); |
| | | serviceSubtaskRes.setCurrentPreachform(serviceSubtask.getPreachform().split(",")[0].trim()); |
| | | } |
| | | } |
| | | PatMedInhosp inhosp = loadInhospCached(inhospCache, serviceSubtask.getInhospid()); |
| | |
| | | |
| | | public List<ServiceSubtask> getServiceSubtasks(ServiceSubtaskEntity serviceSubtaskEntity) { |
| | | if (serviceSubtaskEntity.getSendstateView() != null) { |
| | | // 1:待随访(1 被领取、2 待发送、3 已发送、5 发送失败、7、超时);2:已完成( 6 已完成)、3:无需随访(4 不执行) |
| | | // 1:待随访(1 被领取、2 待发送、3 已发送、7 超时;发送失败(5) 单独统计);2:已完成( 6 已完成)、3:无需随访(4 不执行) |
| | | if (serviceSubtaskEntity.getSendstateView() == 1) |
| | | serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 7L))); |
| | | 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) |
| | |
| | | |
| | | @Override |
| | | public List<ServiceSubtask> 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<ServiceSubtask> serviceSubtaskList = new ArrayList<>(); |
| | | for (Long sendstate : serviceSubtaskEntity.getSendstates()) { |
| | | serviceSubtaskEntity.setSendstate(sendstate); |
| | | List<ServiceSubtask> serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskEntity); |
| | | serviceSubtaskList.addAll(serviceSubtasks); |
| | | if(CollectionUtils.isNotEmpty(serviceSubtaskEntity.getSendstates())){ |
| | | for (Long sendstate : serviceSubtaskEntity.getSendstates()) { |
| | | serviceSubtaskEntity.setSendstate(sendstate); |
| | | List<ServiceSubtask> serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskEntity); |
| | | serviceSubtaskList.addAll(serviceSubtasks); |
| | | } |
| | | } |
| | | return serviceSubtaskList; |
| | | } |
| | |
| | | result.putIfAbsent("xsf", 0); |
| | | result.putIfAbsent("dsf", 0); |
| | | result.putIfAbsent("ywc", 0); |
| | | result.putIfAbsent("cs", 0); |
| | | result.putIfAbsent("yc", 0); |
| | | result.putIfAbsent("jg", 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 业务确认)。 |
| | | * |
| | | * <h3>为什么需要它</h3> |
| | | * 出院随访子任务的科室/病区本应来自出院记录,但「再次随访 / 手工新增」这两个入口是 |
| | | * <b>直接按前端传来的字段落库</b>的:前端不带这些字段时 |
| | | * {@code leaveldeptcode} / {@code leavehospitaldistrictcode} / {@code campusid} 就是空。 |
| | | * 而随访列表是按科室/病区过滤的({@code and leavehospitaldistrictcode = #{...}}), |
| | | * 空值不匹配任何值 → 这些任务"生成了但页面上查不到"(线上 2026-10 实测 314 条)。 |
| | | * |
| | | * <p>口径:<b>病区只认出院记录</b> —— 不按患者档案反推、也不用前端传的值。 |
| | | * 只对出院随访({@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()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | serviceOutPath.setSubId(serviceSubtask1.getId()); |
| | | List<ServiceOutPath> serviceOutPaths = serviceOutPathMapper.selectServiceOutPathList(serviceOutPath); |
| | | if (CollectionUtils.isNotEmpty(serviceOutPaths)) |
| | | format = String.format("%03X", serviceOutPaths.get(0).getId()); |
| | | format = ShortCode.encode(serviceOutPaths.get(0).getId()); |
| | | else format = getOutPath(serviceSubtask1, rsaPublicKeyExample); |
| | | serviceSubtask = serviceSubtask1; |
| | | } else { |
| | |
| | | } |
| | | |
| | | serviceSubtask.setCreateTime(DateUtils.getNowDate()); |
| | | // 口径(2026-10-29 业务确认):出院随访的科室/病区一律以出院记录为准 |
| | | alignDischargeWardFromInhosp(serviceSubtask); |
| | | serviceSubtaskMapper.insertServiceSubtask(serviceSubtask); |
| | | //修改住院满意度状态(避免重复查询) |
| | | if (serviceSubtask.getServiceType() != null && "6".equals(serviceSubtask.getServiceType())) { |
| | |
| | | serviceOutPath.setSubId(serviceSubtask.getId()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | //转成16进制 |
| | | format = String.format("%03X", serviceOutPath.getId()); |
| | | format = ShortCode.encode(serviceOutPath.getId()); |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | |
| | | * @return 结果 |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public String addSubTaskAgain(ServiceSubtask serviceSubtask) { |
| | | ServiceSubtask serviceSubtask1 = selectServiceSubtaskById(serviceSubtask.getId()); |
| | | PatMedInhosp patMedInhosp = new PatMedInhosp(); |
| | |
| | | PatArchive patArchive = taskArchivePort.findByPatid(serviceSubtask1.getPatid()); |
| | | //景宁 新增再次随访不能触发患者再入院 |
| | | boolean inhospAgain = true; |
| | | if (serviceSubtask1.getOrgid().equals("47255004333112711A1001")) { |
| | | if ("47255004333112711A1001".equals(serviceSubtask1.getOrgid())) { |
| | | inhospAgain = false; |
| | | } |
| | | if (patMedInhospList.size() > 0 && inhospAgain) { |
| | |
| | | serviceSubtask1.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + ";无需再次随访,任务被标记不在执行" : "无需再次随访,任务被标记不在执行"); |
| | | serviceSubtaskMapper.updateServiceSubtask(serviceSubtask1); |
| | | return "无需再次随访,任务被标记不在执行"; |
| | | } else if (StringUtils.isNotEmpty(patArchive.getNotrequiredFlag()) && patArchive.getNotrequiredFlag().equals("1")) { |
| | | } 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.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) { |
| | | //新增成功后,需要将之前的任务设置为不要再随访(防止重复点,然后重复生成) |
| | |
| | | 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<PatMedInhosp> 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<SysDept> 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(); |
| | | 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); |
| | | |
| | | // 二次随访时间:上次随访完成时间(未完成则当前时间)+ 下一任务发送天数;过去时间兜底为当前时间 |
| | | applyAgainVisitTime(serviceSubtaskAgain, serviceSubtask, nextServiceTask, config, 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<SysDept> 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; |
| | | } |
| | | 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 可为负)。 |
| | | * <p> |
| | | * 说明:本模块其它地方用的是 {@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(); |
| | | } |
| | | |
| | | /** |
| | | * 首次随访任务超时后,按下一任务自动生成再次随访任务。 |
| | | * <p> |
| | | * 定时任务入口 {@code RyTask#dealSubtaskDeadline} 使用。与手动入口一致的部分: |
| | | * 表单/发送方式取下一任务、链路 upid + visit_count、发送方式明细初始化; |
| | | * 差异:超时再次随访固定走随访中心科室(随访中心未配置时回退原任务科室),原任务置为发送失败(sendstate=5)。 |
| | | * <p> |
| | | * 幂等:同一原任务只允许生成一条再次随访(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<PatMedInhosp> 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<SysDept> 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)。 |
| | | * <p> |
| | | * 迁移说明:原实现是 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<ServiceSubtaskPreachform> preachformList; |
| | | try { |
| | | preachformList = JSON.parseArray(preachformDesc, ServiceSubtaskPreachform.class); |
| | | } catch (Exception e) { |
| | | log.error("preachform转List<ServiceSubtaskPreachform>报错了:{}", 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; |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | /** |
| | | * 科室编码去重,保持原顺序,避免 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(",")); |
| | | } |
| | | |
| | | /** |
| | | * 单一任务 |
| | | * |
| | | * @return 结果 |
| | |
| | | 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中 |
| | |
| | | } |
| | | serviceTask.setLeaveldeptcodes(serviceTaskVO.getLeaveldeptcodes()); |
| | | if (StringUtils.isEmpty(serviceTask.getLeavehospitaldistrictname()) && StringUtils.isNotEmpty(serviceTask.getLeavehospitaldistrictcode())) { |
| | | SysDept sysDept = taskSysDeptPort.selectDeptByCode(serviceTask.getLeavehospitaldistrictcode(), null); |
| | | SysDept sysDept = sysDept2Mapper.selectDeptByCode(serviceTask.getLeavehospitaldistrictcode(), null); |
| | | serviceTask.setLeavehospitaldistrictname(sysDept.getDeptName()); |
| | | } |
| | | if (serviceTaskVO.getLongTask() == 1) serviceTask.setSendState(2L); |
| | |
| | | serviceSubtask.setInhospid(patTaskRelevance.getHospid()); |
| | | //新建完成就是待发送状态 |
| | | serviceSubtask.setSendstate(2L); |
| | | serviceSubtask.setLeaveldeptcode(StringUtils.isNotEmpty(patTaskRelevance.getDeptcode()) ? patTaskRelevance.getDeptcode() : serviceTaskVO.getDeptcode()); |
| | | 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()); |
| | |
| | | ServiceTask serviceTask1 = serviceTaskService.selectServiceTaskByTaskid(serviceTask.getTaskid()); |
| | | ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity(); |
| | | serviceSubtaskVO.setTaskid(serviceTask1.getTaskid()); |
| | | //只删除首次随访未完成的 |
| | | serviceSubtaskVO.setVisitCount(1); |
| | | serviceSubtaskVO.setSendstate(2L); |
| | | List<ServiceSubtask> serviceSubtaskList = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO); |
| | | serviceSubtaskVO.setSendstate(1L); |
| | |
| | | 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(); |
| | |
| | | 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.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); |
| | |
| | | } |
| | | }//二次出院随访 |
| | | else if (serviceSubtask.getVisitCount() != null && serviceSubtask.getVisitCount() > 1) { |
| | | applyAgainFollowUpExtraStatistics(serviceSubtaskStatistic, serviceSubtask); |
| | | //再次应随访 |
| | | if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { |
| | | serviceSubtaskStatistic.setNeedFollowUpAgain(serviceSubtaskStatistic.getNeedFollowUpAgain() + 1L); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 是否属于「及时随访」:随访已完成且完成时状态为正常完成(未超时)。 |
| | | * <p> |
| | | * 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=6)。 |
| | | */ |
| | | 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=6 统计 |
| | | if (StringUtils.equals("6", StringUtils.trim(serviceSubtask.getSuggest()))) { |
| | | statistic.setSuggest6CountAgain(statistic.getSuggest6CountAgain() + 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 |
| | |
| | | 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.getSendstate() != null && serviceSubtask.getSendstate() != 4) { |
| | | serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); |
| | | } |
| | | //及时随访人次:已完成且未超时 |
| | | if (isTimelyFollowUp(serviceSubtask)) { |
| | | serviceSubtaskStatistic.setTimelyFollowUp(serviceSubtaskStatistic.getTimelyFollowUp() + 1L); |
| | | } |
| | | |
| | | //首次出院随访 |
| | |
| | | //出院人次 |
| | | 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.getSendstate() != null && serviceSubtask.getSendstate() != 4) { |
| | | serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); |
| | | } |
| | | //及时随访人次:已完成且未超时 |
| | | if (isTimelyFollowUp(serviceSubtask)) { |
| | | serviceSubtaskStatistic.setTimelyFollowUp(serviceSubtaskStatistic.getTimelyFollowUp() + 1L); |
| | | } |
| | | |
| | | //再次出院随访 |
| | |
| | | serviceSubtaskStatistic.setDrname(serviceSubtaskList.get(0).getDrname()); |
| | | serviceSubtaskStatistic.setJoyCount(0); |
| | | serviceSubtaskStatistic.setJoyAllCount(0); |
| | | |
| | | //出院人次 |
| | | serviceSubtaskStatistic.setDischargeCount(serviceSubtaskList.size()); |
| | | //获取随访统计 |
| | | if (subCounts == null) { |
| | | subCounts = new ArrayList<>(); |
| | |
| | | * 获取随访统计超链接 |
| | | * 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" |
| | |
| | | * 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 |
| | | * suggest6CountAgainInfo - visitCount > 1 && suggest = 6 |
| | | * filterCountList - taskSituation = 6 && sendstate = 4 |
| | | * |
| | | */ |
| | |
| | | public List<ServiceSubtask> getSfStatisticsHyperlink(ServiceSubtaskCountReq serviceSubtaskCountReq) { |
| | | String hyperLinkInfoType = serviceSubtaskCountReq.getHyperLinkInfoType(); |
| | | if (StringUtils.isNotEmpty(hyperLinkInfoType)) { |
| | | applyHyperLinkInfoType(serviceSubtaskCountReq, hyperLinkInfoType); |
| | | if (!applyHyperLinkInfoType(serviceSubtaskCountReq, hyperLinkInfoType)) { |
| | | // 下钻依赖的配置缺失时返回空明细,避免退化成无过滤条件的查询 |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
| | | |
| | | String followUpCountStyle = serviceSubtaskCountReq.getFollowUpCountStyle(); |
| | |
| | | return serviceSubtasks; |
| | | } |
| | | |
| | | private void applyHyperLinkInfoType(ServiceSubtaskCountReq serviceSubtaskCountReq, String hyperLinkInfoType) { |
| | | 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))); |
| | |
| | | serviceSubtaskCountReq.setVisitCount(1); |
| | | serviceSubtaskCountReq.setCurrentPreachform("4"); |
| | | break; |
| | | case "wechatInfo": |
| | | case "weChatInfo": |
| | | serviceSubtaskCountReq.setVisitCount(1); |
| | | serviceSubtaskCountReq.setCurrentPreachform("5"); |
| | | break; |
| | |
| | | serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); |
| | | serviceSubtaskCountReq.setCurrentPreachform("4"); |
| | | break; |
| | | case "wechatSuccessInfo": |
| | | case "weChatSuccessInfo": |
| | | serviceSubtaskCountReq.setVisitCount(1); |
| | | serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); |
| | | serviceSubtaskCountReq.setCurrentPreachform("5"); |
| | |
| | | serviceSubtaskCountReq.setVisitCount(2); |
| | | serviceSubtaskCountReq.setCurrentPreachform("4"); |
| | | break; |
| | | case "wechatAgainInfo": |
| | | case "weChatAgainInfo": |
| | | serviceSubtaskCountReq.setVisitCount(2); |
| | | serviceSubtaskCountReq.setCurrentPreachform("5"); |
| | | break; |
| | |
| | | serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); |
| | | serviceSubtaskCountReq.setCurrentPreachform("4"); |
| | | break; |
| | | case "wechatAgainSuccessInfo": |
| | | case "weChatAgainSuccessInfo": |
| | | serviceSubtaskCountReq.setVisitCount(2); |
| | | serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); |
| | | serviceSubtaskCountReq.setCurrentPreachform("5"); |
| | |
| | | case "abnormalAgainInfo": |
| | | serviceSubtaskCountReq.setVisitCount(2); |
| | | serviceSubtaskCountReq.setExcep("1"); |
| | | break; |
| | | case "suggest6CountAgainInfo": |
| | | // 再次随访回院复诊复查:visitCount > 1 且 suggest = 6 |
| | | serviceSubtaskCountReq.setVisitCount(2); |
| | | serviceSubtaskCountReq.setSuggest("6"); |
| | | break; |
| | | case "taskSituation1Info": |
| | | serviceSubtaskCountReq.setTaskSituation(1); |
| | |
| | | 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; |
| | | } |
| | | |
| | | /** |
| | |
| | | * @return |
| | | */ |
| | | @Override |
| | | @Cacheable(value = "getSfStatisticsScript", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()") |
| | | // @Cacheable(value = "getSfStatisticsScript", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()") |
| | | public List<ServiceSubtaskStatistic> getSfStatisticsScript(ServiceSubtaskCountReq serviceSubtaskCountReq) { |
| | | log.info("getSfStatisticsScript的入参为:{}", serviceSubtaskCountReq); |
| | | List<ServiceSubtaskStatistic> serviceSubtaskStatistics = new ArrayList<>(); |
| | |
| | | } 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"; |
| | | } |
| | | 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<String> groupKeyList = serviceSubtaskMapper.getSfStatisticsGroupKey(serviceSubtaskCountReq); |
| | | /* |
| | |
| | | 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<String, Map<String, Object>> jsRates = getSsRateForSfStatistics(serviceSubtaskCountReq, statisticsGroupKeys); |
| | | for (ServiceSubtaskStatistic statistic : serviceSubtaskStatistics) { |
| | |
| | | sum = new BigDecimal(serviceSubtaskStatistic.getJoyAllCount()); |
| | | } |
| | | if (sum.intValue() != 0) { |
| | | finishedPercentage = finishedSum.divide(sum, 2, RoundingMode.HALF_UP).doubleValue(); |
| | | // 原来只保留 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()); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, ServiceSubtaskScriptCount> getSfStatisticsScriptDetails(ServiceSubtaskCountReq serviceSubtaskCountReq) { |
| | | Map<String, ServiceSubtaskScriptCount> result = new HashMap<>(); |
| | | public Map<String, Object> getSfStatisticsScriptDetails(ServiceSubtaskCountReq serviceSubtaskCountReq) { |
| | | List<ServiceSubtaskScriptCount> allCounts = new ArrayList<>(); |
| | | List<ServiceSubtaskScriptCount> allItemCounts = new ArrayList<>(); |
| | | String type = serviceSubtaskCountReq.getType(); |
| | |
| | | allItemCounts = serviceSubtaskMapper.getSfStatisticsScriptItemDetails(serviceSubtaskCountReq); |
| | | } |
| | | |
| | | for (ServiceSubtaskScriptCount count : allCounts) { |
| | | //返回结构是 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<ServiceSubtaskScriptCount> pageCounts = allCounts.subList(fromIndex, toIndex); |
| | | |
| | | Map<String, ServiceSubtaskScriptCount> pageData = new LinkedHashMap<>(); |
| | | for (ServiceSubtaskScriptCount count : pageCounts) { |
| | | Map<String, ServiceSubtaskScriptCount> itemCountMap = new HashMap<>(); |
| | | //问卷加上空白选项 |
| | | if (ObjectUtils.isNotEmpty(count.getTemplateid()) && ObjectUtils.isNotEmpty(count.getSubtaskType()) && count.getSubtaskType().equals("2")) { |
| | |
| | | } |
| | | } |
| | | allItemCounts.forEach(itemCount -> { |
| | | if (ObjectUtils.isNotEmpty(count.getScriptid()) && ObjectUtils.isNotEmpty(itemCount.getScriptid())) { |
| | | if (count.getScriptid().equals(itemCount.getScriptid())) { |
| | | //放入统计信息 |
| | | 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); |
| | | //明细行已按“题目内容+任务类型”聚合并带出 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<ServiceSubtaskScriptCount> itemCounts = new ArrayList<>(itemCountMap.values()); |
| | | count.setDetails(itemCounts); |
| | | result.put(count.getScriptid().toString(), count); |
| | | pageData.put(count.getScriptid().toString(), count); |
| | | } |
| | | Map<String, Object> 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; |
| | | } |
| | | |
| | |
| | | |
| | | // 初始化数值字段 |
| | | total.setDischargeCount(0); |
| | | total.setFirstDischargeCount(0L); |
| | | total.setAgainFollowUpPushCount(0L); |
| | | total.setNonFollowUp(0L); |
| | | total.setFilterCount(0L); |
| | | total.setFollowUpNeeded(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.setSuggest6CountAgain(0L); |
| | | total.setManualAgain(0L); |
| | | total.setSmsAgain(0L); |
| | | total.setWeChatAgain(0L); |
| | |
| | | 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.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.setSuggest6CountAgain(total.getSuggest6CountAgain() + (stat.getSuggest6CountAgain() != null ? stat.getSuggest6CountAgain() : 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)); |
| | |
| | | return serviceSubtaskMapper.getCurrentUserServiceSubtaskCount(entity); |
| | | } |
| | | |
| | | /** |
| | | * 当前登录人待处理随访任务,按出院年月分组统计(出院随访、门诊随访分开计数) |
| | | * <p> |
| | | * 只返回有数据的月份,前端按「当月 + 前 3 个月」补齐,没有数据显示 0 个。 |
| | | */ |
| | | @Override |
| | | public Map<String, Object> getPendingManualTaskMonthStats(ServiceSubtaskEntity entity) { |
| | | List<Map<String, Object>> rows = serviceSubtaskMapper.countPendingManualTaskByMonth(entity); |
| | | List<Map<String, Object>> months = new ArrayList<>(); |
| | | long total = 0L; |
| | | if (rows != null) { |
| | | for (Map<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> getContinueNurseCount(ServiceSubtaskCotinueCountVO vo) { |
| | | boolean hasDistrict = !CollectionUtils.isEmpty(vo.getLeavehospitaldistrictcodes()); |
| | |
| | | public void setFailSubTaskDefalutVal(Long failDay) { |
| | | //1.先去sys_config中,获取哪些科室或病区需要默认问卷默认值 |
| | | IConfigService configService = SpringUtils.getBean(IConfigService.class); |
| | | String deptConfigValue = taskSysConfigPort.selectConfigValue("hosp.default.dept"); |
| | | String wardConfigValue = taskSysConfigPort.selectConfigValue("hosp.default.ward"); |
| | | String deptConfigValue = sysConfigService.selectConfigByKey("hosp.default.dept"); |
| | | String wardConfigValue = sysConfigService.selectConfigByKey("hosp.default.ward"); |
| | | List<String> leaveWard = null; |
| | | List<String> leaveDept = null; |
| | | if (deptConfigValue != null && !deptConfigValue.isEmpty()) { |
| | |
| | | String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key); |
| | | String taskId = rsaPublicKeyExample.encryptedData(serviceSubtask.getTaskid().toString(), pub_key); |
| | | |
| | | //丽水中医院发送的是微信公众号 |
| | | if (StringUtils.isNotEmpty(serviceSubtask.getOrgid()) && serviceSubtask.getOrgid().equals("47231022633110211A2101")) { |
| | | resultMap = wechatSubTask(subid); |
| | | return resultMap; |
| | | } |
| | | |
| | | //发送数据的封装 |
| | | ServiceOutPath serviceOutPath = new ServiceOutPath(); |
| | | serviceOutPath.setParam1(taskId); |
| | |
| | | serviceOutPath.setCreateTime(new Date()); |
| | | serviceOutPath.setOrgid(serviceSubtask.getOrgid()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | String format = String.format("%03X", serviceOutPath.getId()); |
| | | String format = ShortCode.encode(serviceOutPath.getId()); |
| | | String url = ""; |
| | | SendMagParam sendMagParam = new SendMagParam(); |
| | | sendMagParam.setType("4"); |
| | |
| | | |
| | | // 参数值经端口取用(原为 sysConfigMapper.checkConfigKeyUnique + getConfigValue)。 |
| | | // 语义等价:原判定"行存在"、这里判定"值非 null",而 sys_config.config_value 是 |
| | | // varchar(500) NOT NULL DEFAULT '' ⇒ 二者不可能不同(详见 TaskSysConfigPort javadoc)。 |
| | | String smsContemt = taskSysConfigPort.findConfigValueByKey("wj.sms.template"); |
| | | // varchar(500) NOT NULL DEFAULT '' ⇒ 二者不可能不同(详见 ISysConfigService javadoc)。 |
| | | String smsContemt = sysConfigService.selectConfigByKey("wj.sms.template"); |
| | | |
| | | if (smsContemt != null) { |
| | | sendMagParam.setContent(smsContemt.replace("${wjurl}", sendMagParam.getUrl())); |
| | |
| | | serviceSubtask.setCurrentPreachform("4"); |
| | | } |
| | | } |
| | | return resultMap; |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> weChatSubTask(Long subid) { |
| | | log.info("smsSubTask的入参为:{}", subid); |
| | | Map<String, Object> 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; |
| | | } |
| | | |
| | |
| | | serviceOutPath.setCreateTime(new Date()); |
| | | serviceOutPath.setOrgid(serviceSubtask.getOrgid()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | String format = String.format("%03X", serviceOutPath.getId()); |
| | | String format = ShortCode.encode(serviceOutPath.getId()); |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | serviceOutPath.setUrl(url); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | |
| | | //his患者id校验(与原实现一致:先校验这一项) |
| | | if (StringUtils.isEmpty(serviceSubtask.getPatidHis())) { |
| | | |
| | | 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; |
| | |
| | | serviceOutPath.setCreateTime(new Date()); |
| | | serviceOutPath.setOrgid(serviceTask.getOrgid()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | String format = String.format("%03X", serviceOutPath.getId()); |
| | | 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; |
| | |
| | | return null; |
| | | } |
| | | try { |
| | | SysDept sysDept = taskSysDeptPort.selectDeptByCode(deptCode, orgid); |
| | | SysDept sysDept = sysDept2Mapper.selectDeptByCode(deptCode, orgid); |
| | | return sysDept == null ? null : sysDept.getCampusid(); |
| | | } catch (Exception e) { |
| | | log.warn("按编码反查院区失败:deptCode={}, orgid={}, err={}", deptCode, orgid, e.getMessage()); |