陈昶聿
12 小时以前 d1995068ddc93414e01a02bd0a21626a4a6ad9a4
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
@@ -827,7 +827,7 @@
        }
        //丽水中医院根据下次任务ID生成再次随访
        if ("47231022633110211A2101".equals(serviceSubtask1.getOrgid())) {
            return addSubTaskAgainNextTaskId(serviceSubtask1);
            return addSubTaskAgainNextTaskId(serviceSubtask1, serviceSubtask);
        }
        //新增再次随访任务
        ServiceSubtask serviceSubtask2 = DtoConversionUtils.sourceToTarget(serviceSubtask, ServiceSubtask.class);
@@ -850,7 +850,7 @@
        return "再次随访任务创建失败,再请次重试";
    }
    public String addSubTaskAgainNextTaskId(ServiceSubtask serviceSubtask) {
    public String addSubTaskAgainNextTaskId(ServiceSubtask serviceSubtask, ServiceSubtask request) {
        if (ObjectUtils.isEmpty(serviceSubtask.getTaskid())) {
            log.error("再次随访任务创建失败,缺少TaskId, 再请次重试");
            return "再次随访任务创建失败,缺少TaskId, 再请次重试";
@@ -865,6 +865,11 @@
            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();
@@ -885,14 +890,16 @@
                log.error("再次随访任务创建失败,任务缺少 对应的出院记录, taskid = {}, 再请次重试", serviceSubtask.getTaskid());
                return "再次随访任务创建失败,任务缺少 对应的出院记录, taskid = " + serviceSubtask.getTaskid() + ", 再请次重试";
            }
            if (ObjectUtils.isEmpty(serviceTask.getNexttaskid())) {
                log.error("再次随访任务创建失败,任务缺少 nexttaskid, taskid = {}, 再请次重试", serviceSubtask.getTaskid());
                return "再次随访任务创建失败,任务缺少 nexttaskid, 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(serviceTask.getNexttaskid());
            ServiceTask nextServiceTask = serviceTaskService.selectServiceTaskByTaskid(nexttaskid);
            if (ObjectUtils.isEmpty(nextServiceTask)) {
                log.error("再次随访任务创建失败,找不到对应任务 nexttaskid = {}, 再请次重试", serviceTask.getNexttaskid());
                return "再次随访任务创建失败,找不到对应任务 nexttaskid = " + serviceTask.getNexttaskid() + ", 再请次重试";
                log.error("再次随访任务创建失败,找不到对应任务 nexttaskid = {}, 再请次重试", nexttaskid);
                return "再次随访任务创建失败,找不到对应任务 nexttaskid = " + nexttaskid + ", 再请次重试";
            }
            PatArchive patArchive = patArchiveService.selectPatArchiveByPatid(serviceSubtask.getPatid());
            if (ObjectUtils.isEmpty(patArchive)) {
@@ -901,54 +908,86 @@
            }
            String config = configService.selectConfigByKey("visit.early.day");
            Integer type = 1;
            // 随访中心科室
            String centerDept = configService.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() + ", 再请次重试";
            String visitType = resolveAgainVisitType(request, serviceSubtask);
            if (StringUtils.isEmpty(visitType)) {
                String requestVisitType = request == null ? null : request.getVisitType();
                log.error("再次随访任务创建失败,随访方式不合法, visitType = {}, subTaskId = {}", requestVisitType, serviceSubtask.getId());
                return "再次随访任务创建失败,随访方式不合法, visitType = " + requestVisitType + ", 再请次重试";
            }
            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);
            String visitDeptCode;
            String visitDeptName;
            if ("1".equals(visitType)) {
                // 本科室随访:请求值 > 原任务本科室随访科室 > 原任务出院科室
                String requestDeptCode = request == null ? null : request.getVisitDeptCode();
                String requestDeptName = request == null ? null : request.getVisitDeptName();
                String oldVisitType = serviceSubtask.getVisitType();
                String oldOwnDeptCode = "1".equals(oldVisitType) ? serviceSubtask.getVisitDeptCode() : null;
                String oldOwnDeptName = "1".equals(oldVisitType) ? serviceSubtask.getVisitDeptName() : null;
                String preferredDeptCode = firstNonBlank(requestDeptCode, oldOwnDeptCode);
                if (StringUtils.isNotEmpty(preferredDeptCode)) {
                    visitDeptCode = preferredDeptCode;
                    visitDeptName = firstNonBlank(requestDeptName, oldOwnDeptName);
                } else {
                    visitDeptCode = serviceSubtask.getDeptcode();
                    visitDeptName = serviceSubtask.getDeptname();
                }
                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 {
                log.error("再次随访任务创建失败,未找到参数 sys.smartor.center.dept 配置的随访中心科室 deptCode = {}, 再请次重试", centerDept);
                return "再次随访任务创建失败,未找到参数 sys.smartor.center.dept 配置的随访中心科室 deptCode = " + centerDept + ", 再请次重试";
                // 随访中心科室随访
                String centerDept = configService.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();
            }
            // 按下一任务生成二次随访子任务(表单、发送方式取自下一任务)
            ServiceSubtask serviceSubtaskAgain = patMedInhospService.boxedServiceSubtask(nextServiceTask,
                    patMedInhosp, patArchive, config, type);
            if (ObjectUtils.isEmpty(serviceSubtaskAgain) || ObjectUtils.isEmpty(serviceSubtaskAgain.getTaskid())) {
                log.error("再次随访任务创建失败,下一任务生成子任务为空, subTaskId = {}, nextTaskId = {}", serviceSubtask.getId(), serviceTask.getNexttaskid());
                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 : 1);
                    ? serviceSubtask.getVisitCount() + 1 : 2);
            serviceSubtaskAgain.setSendstate(2L);
            serviceSubtaskAgain.setIsVisitAgain(1);
            serviceSubtaskAgain.setCreateTime(now);
            serviceSubtaskAgain.setUpdateTime(now);
//            // 二次随访时间:上次随访完成时间(未完成则当前时间)+ 下一任务发送天数;过去时间兜底为当前时间
//            Date baseTime = ObjectUtils.isNotEmpty(serviceSubtask.getFinishtime()) ? serviceSubtask.getFinishtime() : now;
//            int intervalDays = ObjectUtils.isNotEmpty(nextServiceTask.getSendDay())
//                    ? nextServiceTask.getSendDay().intValue() : 0;
//            Date nextVisitTime = DateUtils.addDays(baseTime, intervalDays);
//            if (nextVisitTime.before(now)) {
//                nextVisitTime = now;
//            }
//            serviceSubtaskAgain.setVisitTime(nextVisitTime);
//            serviceSubtaskAgain.setLongSendTime(nextVisitTime);
            serviceSubtaskAgain.setVisitType(serviceSubtask.getVisitType());
            serviceSubtaskAgain.setVisitDeptCode(sysDept.getDeptCode());
            serviceSubtaskAgain.setVisitDeptName(sysDept.getDeptName());
            // 二次随访时间:上次随访完成时间(未完成则当前时间)+ 下一任务发送天数;过去时间兜底为当前时间
            applyAgainVisitTime(serviceSubtaskAgain, serviceSubtask, nextServiceTask, config, now);
            serviceSubtaskAgain.setVisitType(visitType);
            serviceSubtaskAgain.setVisitDeptCode(visitDeptCode);
            serviceSubtaskAgain.setVisitDeptName(visitDeptName);
            int i = serviceSubtaskMapper.insertServiceSubtask(serviceSubtaskAgain);
            if (i != 1) {
                return "再次随访任务创建失败,再请次重试";
@@ -967,10 +1006,92 @@
    }
    /**
     * 首次随访任务超时后,按下一任务自动生成再次随访任务(随访中心)。
     * 解析再次随访方式:请求参数优先,原任务兜底,未配置时默认随访中心。
     *
     * @return 1-本科室随访;2-随访中心随访;null-非法值
     */
    private String resolveAgainVisitType(ServiceSubtask request, ServiceSubtask old) {
        String visitType = request == null ? null : request.getVisitType();
        if (StringUtils.isEmpty(visitType) || StringUtils.isEmpty(visitType.trim())) {
            visitType = old == null ? null : old.getVisitType();
        }
        if (StringUtils.isEmpty(visitType) || StringUtils.isEmpty(visitType.trim())) {
            return "2";
        }
        visitType = visitType.trim();
        return ("1".equals(visitType) || "2".equals(visitType)) ? visitType : 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 = DateUtils.addDays(baseTime, intervalDays);
        if (dueTime.before(now)) {
            dueTime = now;
        }
        target.setLongSendTime(dueTime);
        Date visitTime = dueTime;
        if ("3".equals(nextTask.getType())) {
            visitTime = DateUtils.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;
        }
    }
    /**
     * 首次随访任务超时后,按下一任务自动生成再次随访任务。
     * <p>
     * 定时任务入口 {@code RyTask#dealSubtaskDeadline} 使用。与手动入口一致的部分:
     * 表单/发送方式取下一任务、链路 upid + visit_count、发送方式明细初始化;
     * 表单/发送方式取下一任务、链路 upid + visit_count、发送方式明细初始化、按 visitType 选择随访科室;
     * 差异:随访中心科室未配置时回退原任务科室,原任务置为发送失败(sendstate=5)。
     * <p>
     * 幂等:同一原任务只允许生成一条再次随访(Redis 锁 + upid 校验 + 原任务条件更新),
@@ -1004,6 +1125,9 @@
            if (ObjectUtils.isEmpty(serviceTask)) {
                return "再次随访任务创建失败,找不到对应任务 taskid = " + serviceSubtask.getTaskid();
            }
            if ("0".equals(serviceTask.getNexttaskflag())) {
                return "无需再次随访,该任务无后续随访安排";
            }
            if (ObjectUtils.isEmpty(serviceTask.getNexttaskid())) {
                return "再次随访任务创建失败,任务缺少 nexttaskid, taskid = " + serviceSubtask.getTaskid();
            }
@@ -1019,9 +1143,50 @@
            if (ObjectUtils.isEmpty(patArchive)) {
                return "再次随访任务创建失败,未找到患者档案, subTaskId = " + serviceSubtask.getId();
            }
            // 随访中心科室:未配置(或科室不存在)时回退原任务科室,保持超时入口原有行为
            SysDept visitDept = selectCenterDept(serviceSubtask.getOrgid());
            String config = configService.selectConfigByKey("visit.early.day");
            String visitType = resolveAgainVisitType(null, serviceSubtask);
            if (StringUtils.isEmpty(visitType)) {
                return "再次随访任务创建失败,随访方式不合法, visitType = " + serviceSubtask.getVisitType();
            }
            String visitDeptCode;
            String visitDeptName;
            if ("1".equals(visitType)) {
                // 本科室随访:原任务随访科室 > 原任务出院科室
                String ownDeptCode = firstNonBlank(serviceSubtask.getVisitDeptCode());
                if (StringUtils.isNotEmpty(ownDeptCode)) {
                    visitDeptCode = ownDeptCode;
                    visitDeptName = serviceSubtask.getVisitDeptName();
                } else {
                    visitDeptCode = serviceSubtask.getDeptcode();
                    visitDeptName = serviceSubtask.getDeptname();
                }
                if (StringUtils.isEmpty(visitDeptCode)) {
                    return "再次随访任务创建失败,本科室随访未找到随访科室, subTaskId = " + serviceSubtask.getId();
                }
                SysDept ownDept = selectDeptByCode(serviceSubtask.getOrgid(), visitDeptCode);
                if (ObjectUtils.isNotEmpty(ownDept)) {
                    visitDeptCode = ownDept.getDeptCode();
                    visitDeptName = ownDept.getDeptName();
                } else if (StringUtils.isEmpty(visitDeptName)) {
                    return "再次随访任务创建失败,本科室随访科室不存在, deptCode = " + visitDeptCode + ", subTaskId = " + serviceSubtask.getId();
                }
            } else {
                // 随访中心科室:未配置(或科室不存在)时回退原任务科室,保持超时入口原有行为
                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 {
                        visitDeptCode = serviceSubtask.getDeptcode();
                        visitDeptName = serviceSubtask.getDeptname();
                    }
                }
            }
            ServiceSubtask serviceSubtaskAgain = patMedInhospService.boxedServiceSubtask(nextServiceTask,
                    patMedInhosp, patArchive, config, 1);
            if (ObjectUtils.isEmpty(serviceSubtaskAgain) || ObjectUtils.isEmpty(serviceSubtaskAgain.getTaskid())) {
@@ -1036,14 +1201,9 @@
            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());
            }
            serviceSubtaskAgain.setVisitType(visitType);
            serviceSubtaskAgain.setVisitDeptCode(visitDeptCode);
            serviceSubtaskAgain.setVisitDeptName(visitDeptName);
            if (serviceSubtaskMapper.insertServiceSubtask(serviceSubtaskAgain) != 1) {
                return "再次随访任务创建失败,再请次重试";
            }