| | |
| | | import com.ruoyi.common.exception.base.BaseException; |
| | | import com.ruoyi.common.utils.*; |
| | | import com.ruoyi.common.utils.http.HttpUtils; |
| | | import com.ruoyi.common.utils.sms.smsUtils; |
| | | import com.ruoyi.common.utils.sms.SmsUtils; |
| | | import com.ruoyi.common.utils.spring.SpringUtils; |
| | | import com.ruoyi.system.domain.SysConfig; |
| | | import com.ruoyi.system.mapper.SysConfigMapper; |
| | |
| | | } finally { |
| | | unlockAgainTask(serviceSubtask.getId(), lockToken); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 首次随访任务超时后,按下一任务自动生成再次随访任务(随访中心)。 |
| | | * <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 (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 = patArchiveService.selectPatArchiveByPatid(serviceSubtask.getPatid()); |
| | | if (ObjectUtils.isEmpty(patArchive)) { |
| | | return "再次随访任务创建失败,未找到患者档案, subTaskId = " + serviceSubtask.getId(); |
| | | } |
| | | // 随访中心科室:未配置(或科室不存在)时回退原任务科室,保持超时入口原有行为 |
| | | SysDept visitDept = selectCenterDept(serviceSubtask.getOrgid()); |
| | | String config = configService.selectConfigByKey("visit.early.day"); |
| | | ServiceSubtask serviceSubtaskAgain = patMedInhospService.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(serviceSubtask.getVisitType()); |
| | | if (ObjectUtils.isNotEmpty(visitDept)) { |
| | | serviceSubtaskAgain.setVisitDeptCode(visitDept.getDeptCode()); |
| | | serviceSubtaskAgain.setVisitDeptName(visitDept.getDeptName()); |
| | | } else { |
| | | serviceSubtaskAgain.setVisitDeptCode(serviceSubtask.getVisitDeptCode()); |
| | | serviceSubtaskAgain.setVisitDeptName(serviceSubtask.getVisitDeptName()); |
| | | } |
| | | if (serviceSubtaskMapper.insertServiceSubtask(serviceSubtaskAgain) != 1) { |
| | | return "再次随访任务创建失败,再请次重试"; |
| | | } |
| | | // 初始化发送方式明细,补偿(compensateTask)和超时判断依赖该表 |
| | | patMedInhospService.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 = patMedInhospService.selectPatMedInhospList(patMedInhospVo); |
| | | if (CollectionUtils.isEmpty(patMedInhospList)) { |
| | | return null; |
| | | } |
| | | return patMedInhospList.get(0); |
| | | } |
| | | |
| | | /** |
| | | * 取随访中心科室,未配置或科室不存在时返回 null(由调用方回退原任务科室)。 |
| | | */ |
| | | private SysDept selectCenterDept(String orgid) { |
| | | String centerDept = configService.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); |
| | | List<SysDept> sysDepts = sysDeptService.selectDeptList(sysDeptVo); |
| | | return CollectionUtils.isEmpty(sysDepts) ? null : sysDepts.get(0); |
| | | } |
| | | |
| | | /** |
| | |
| | | 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"); |