陈昶聿
2026-11-04 579438ab87a88332f3643fbeefb3bbc43c87ae59
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
@@ -28,6 +28,7 @@
import com.smartor.common.LSHospTokenUtil;
import com.smartor.common.MtSubmitSmUtil;
import com.smartor.common.QwenLLMUtil;
import com.smartor.common.SpecificArchiveConstants;
import com.smartor.domain.*;
import com.smartor.domain.VO.ServiceSubtaskDetailTraceVO;
import com.smartor.domain.entity.ServiceSubtaskEntity;
@@ -36,6 +37,7 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@@ -940,6 +942,25 @@
            Optional<Long> currentSort = serviceSubtaskPreachforms.stream().filter(item -> serviceSubtask.getCurrentPreachform().equals(item.getPreachform())).map(ServiceSubtaskPreachform::getSort).findFirst();
            Optional<Long> id = serviceSubtaskPreachforms.stream().filter(item -> serviceSubtask.getCurrentPreachform().equals(item.getPreachform())).map(ServiceSubtaskPreachform::getId).findFirst();
            if (currentSort.isPresent()) {
                // 方案B:只处理当前子任务——公众号已领取(service_subtask.sendstate=1 + current_preachform=5)
                // 且未填写时,按默认选项完成,避免进入下一种发送方式或最后一步超时。
                // 先用内存字段快速过滤,其他医院/任务/发送方式不会进入下面的默认完成逻辑。
                if (IServiceSubtaskService.WECHAT_DEFAULT_COMPLETE_ORGID.equals(serviceSubtask.getOrgid())
                        && "2".equals(serviceSubtask.getType())
                        && "5".equals(serviceSubtask.getCurrentPreachform())
                        && Long.valueOf(1L).equals(serviceSubtask.getSendstate())
                        && !Long.valueOf(1L).equals(serviceSubtask.getSubmit())) {
                    try {
                        if (iServiceSubtaskService.completeWechatClaimedByDefault(serviceSubtask)) {
                            log.info("【compensateTask】subid:{},微信公众号已领取未填写,按默认选项完成", serviceSubtask.getId());
                            continue;
                        }
                    } catch (Exception e) {
                        // 单个子任务失败不影响其他任务,回滚后继续原补偿流程
                        log.error("【compensateTask】微信公众号默认完成失败,subid:{},继续原补偿流程", serviceSubtask.getId(), e);
                    }
                }
                //1先检查一下,是不是有执行状态是完成的(怕之前已经有完的了,没有将servuce_subtask的状态改成功,这里再检查一下)
                boolean finishState = serviceSubtaskPreachforms.stream().allMatch(item -> item.getSendstate().equals("9"));
                if (finishState) {
@@ -1414,6 +1435,7 @@
                    //任务发送记录
                    ServiceSubtaskRecord serviceSubtaskRecord = new ServiceSubtaskRecord();
                    serviceSubtaskRecord.setTaskid(serviceSubtask.getTaskid().toString());
                    serviceSubtaskRecord.setSubtaskId(serviceSubtask.getId());
                    serviceSubtaskRecord.setUuid(UUID.randomUUID().toString());
                    serviceSubtaskRecord.setTasktype(serviceSubtask.getType());
                    serviceSubtaskRecord.setPreachform("4");
@@ -1672,6 +1694,25 @@
        }
    }
    /**
     * 采集丽水市妇幼保健院门诊接诊完成记录,并按配置生成妇科/儿科档案。
     * 定时任务默认采集昨天 00:00:00 ~ 今天 00:00:00。
     */
    public void collectMchArchive() {
        try {
            LocalDateTime todayZero = LocalDateTime.now().with(LocalTime.MIN);
            LocalDateTime yesterdayZero = todayZero.minusDays(1);
            Date startTime = Date.from(yesterdayZero.atZone(ZoneId.systemDefault()).toInstant());
            Date endTime = Date.from(todayZero.atZone(ZoneId.systemDefault()).toInstant());
            log.info("【collectMchArchive】开始采集丽水妇幼门诊接诊完成记录");
            ichService.collectMchOuthospAndGenerateArchive(
                    SpecificArchiveConstants.LISHUI_MCH_ORG_ID, startTime, endTime);
            log.info("【collectMchArchive】丽水妇幼门诊接诊完成记录采集结束");
        } catch (Exception e) {
            log.error("【collectMchArchive】丽水妇幼门诊接诊完成记录采集异常", e);
        }
    }
    public void collectHISYesterday() {
        try {
            // 获取昨天0点到今天0点的时间范围
@@ -1892,11 +1933,15 @@
            return false;
        }
        // 基准时刻:出院时间 + 发送日(sendDay 缺省按 1),并兜底避免 NPE/脏数据
        if (serviceSubtask.getEndtime() == null) {
            log.warn("【isSubtaskDeadline】subid:{} endtime为空,无法计算超时,按未超时处理", serviceSubtask.getId());
            return false;
        }
        ServiceTask serviceTask = serviceTaskMapper.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
        int sendDay = serviceTask != null && serviceTask.getSendDay() != null ? serviceTask.getSendDay().intValue() : 1;
        Date deadline = DateUtils.addDays(serviceSubtask.getEndtime(), sendDay);
        int sumCompensateTime = CollectionUtils.isEmpty(serviceSubtaskPreachforms) ? 0 : serviceSubtaskPreachforms.stream()
                .mapToInt(x -> x.getCompensateTime() == null ? 0 : Integer.parseInt(x.getCompensateTime()))
                .mapToInt(x -> NumberUtils.toInt(x.getCompensateTime(), 0))
                .sum();
        sumCompensateTime = sumCompensateTime + 1;
        // 只补偿最后一步自身的补偿时间(天),脏值一律按 0 兜底
@@ -1907,7 +1952,16 @@
    /**
     * 处理超时随访任务
     * @return
     * <p>
     * 扫描「出院满 deadlineDay 天仍未完成」的首次随访任务(sendstate=7 + visit_count=1),
     * 按当前任务的 nexttaskid 生成再次随访任务,科室固定为随访中心科室。
     * <p>
     * 注意:截止时间必须在循环外计算一次。历史实现把 {@code deadlineDay = -deadlineDay}
     * 写在循环体内,每轮取反一次,导致偶数轮用「今天 + deadlineDay」做截止时间,
     * 把出院不满 28 天的超时任务也扫了进来。
     *
     * @param orgid       机构ID
     * @param deadlineDay 出院满多少天算超时(正数,如 28)
     */
    public void dealSubtaskDeadline(String orgid, Integer deadlineDay){
        //获取任务信息
@@ -1918,24 +1972,16 @@
        st.setOrgid(orgid);
        List<ServiceTask> serviceTasks = serviceTaskMapper.selectServiceTaskList(st);
        // 随访中心科室
        String centerDept = configService.selectConfigByKey("sys.smartor.center.dept", orgid);
        SysDept sysDeptVo = new SysDept();
        SysDept centerSysDept = null;
        if(StringUtils.isNotEmpty(centerDept)){
            sysDeptVo.setDeptType("1");
            sysDeptVo.setOrgid(orgid);
            sysDeptVo.setDeptCode(centerDept);
            List<SysDept> sysDepts = sysDeptService.selectDeptList(sysDeptVo);
            if (CollectionUtils.isNotEmpty(sysDepts)) {
                centerSysDept = sysDepts.get(0);
            }
        }
        // 截止时间只算一次:出院时间 <= 今天 - deadlineDay
        int days = Math.abs(ObjectUtils.isEmpty(deadlineDay) ? 28 : deadlineDay);
        Date deadline = DateUtils.addDays(new Date(), -days);
        log.info("【dealSubtaskDeadline】开始扫描, orgid={}, day={}, deadline={}, 任务数={}",
                orgid, days, deadline, serviceTasks.size());
        String config = configService.selectConfigByKey("visit.early.day");
        for (ServiceTask serviceTask : serviceTasks) {
            deadlineDay = -deadlineDay;
            Date deadline = DateUtils.addDays(new Date(), deadlineDay);
            if (ObjectUtils.isEmpty(serviceTask.getNexttaskid())) {
                continue;
            }
            //通过任务ID拿到患者信息,并且随访时间得是今天之前的
            ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
            serviceSubtaskVO.setOrgid(orgid);
@@ -1949,46 +1995,15 @@
                    = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO);
            log.info("【dealSubtaskDeadline】获取到{}个超时任务, taskid={}", serviceSubtaskList.size(), serviceTask.getTaskid());
            for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
                PatMedInhosp patMedInhospVo = new PatMedInhosp();
                patMedInhospVo.setOrgid(serviceSubtask.getOrgid());
                patMedInhospVo.setInhospid(serviceSubtask.getInhospid());
                patMedInhospVo.setCry(1);
                List<PatMedInhosp> patMedInhospList = iPatMedInhospService.selectPatMedInhospList(patMedInhospVo);
                PatMedInhosp patMedInhosp = new PatMedInhosp();
                if (!patMedInhospList.isEmpty()) {
                    patMedInhosp = patMedInhospList.get(0);
                }else {
                    continue;
                }
                if(ObjectUtils.isEmpty(serviceTask.getNexttaskid())){
                    continue;
                }
                ServiceTask nextServiceTask = serviceTaskMapper.selectServiceTaskByTaskid(serviceTask.getNexttaskid());
                PatArchive patArchive = patArchiveService.selectPatArchiveByPatid(serviceSubtask.getPatid());
                Integer type = 1;
                //新增再次随访任务
                ServiceSubtask serviceSubtaskAgain = iPatMedInhospService.boxedServiceSubtask(nextServiceTask,
                        patMedInhosp, patArchive, config, type);
                serviceSubtaskAgain.setId(null);
                serviceSubtaskAgain.setUpid(serviceSubtask.getId().intValue());
                serviceSubtaskAgain.setVisitCount(serviceSubtask.getVisitCount() + 1);
                serviceSubtaskAgain.setSendstate(2L);
                serviceSubtaskAgain.setCreateTime(new Date());
                serviceSubtaskAgain.setUpdateTime(new Date());
                serviceSubtaskAgain.setVisitType(serviceSubtask.getVisitType());
                if(ObjectUtils.isNotEmpty(centerSysDept)){
                    serviceSubtaskAgain.setVisitDeptCode(centerSysDept.getDeptCode());
                    serviceSubtaskAgain.setVisitDeptName(centerSysDept.getDeptName());
                }else {
                    serviceSubtaskAgain.setVisitDeptCode(serviceSubtask.getVisitDeptCode());
                    serviceSubtaskAgain.setVisitDeptName(serviceSubtask.getVisitDeptName());
                }
                int i = serviceSubtaskMapper.insertServiceSubtask(serviceSubtaskAgain);
                if (i == 1) {
                    //再次随访任务创建成功后,原任务改为失败状态
                    serviceSubtask.setSendstate(5L);
                    serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
                try {
                    // 生成逻辑统一收口到 service:锁 + 幂等 + 事务 + 发送方式明细初始化
                    String result = iServiceSubtaskService.addSubTaskAgainByDeadline(serviceSubtask);
                    log.info("【dealSubtaskDeadline】生成再次随访, subId={}, taskid={}, 结果={}",
                            serviceSubtask.getId(), serviceTask.getTaskid(), result);
                } catch (Exception e) {
                    // 单条失败不影响其他患者
                    log.error("【dealSubtaskDeadline】生成再次随访失败, subId=" + serviceSubtask.getId()
                            + ", taskid=" + serviceTask.getTaskid(), e);
                }
            }
        }