liusheng
5 天以前 cc479e6a056785103996cc7ea67dbd5faa3e800e
ruoyi-inhospvisit/src/main/java/com/ruoyi/inhospvisit/service/InhospSubtaskWriter.java
@@ -105,8 +105,13 @@
     * @param archive  患者档案
     * @param type     0=药品宣教 / 1=离院科室 / 2=离院病区 / 3=疾病 / 4=入院科室 / 5=入院病区
     * @param config   {@code sys_config: visit.early.day}
     * @return <b>是否真的落了库</b>(或"本来就已经有")。
     *         返回值是 2026-10"一个患者只生成一条随访任务"改造的判据:
     *         编排层按维度优先级逐个尝试,只有拿到 {@code true} 才算该维度成功并停止。
     *         原实现是 {@code void},编排层用"调用了几次"当成功数 —— 那是错的
     *         (任务未发布/被去重时同样是"生成了一条")。
     */
    public void writeInSubTask(Long taskid, Boolean check, VisitInhospRow inhosp,
    public boolean writeInSubTask(Long taskid, Boolean check, VisitInhospRow inhosp,
                               VisitArchiveRow archive, Integer type, String config) {
        // 原 L683-685
        String longTaskReason = inhosp.getLongTaskReason();
@@ -120,17 +125,32 @@
        if (taskApi == null) {
            log.warn("【出入院随访】VisitTaskCreateApi 不可用(任务创建模块未装配),本患者不生成子任务。"
                    + "inhospid={}, taskid={}", inhosp.getInhospid(), taskid);
            return;
            return false;
        }
        VisitLongTaskDto serviceTask = taskApi.findPublishedLongTask(taskid);
        if (serviceTask == null) {
            writeMissingTaskFlag(inhosp, type, longTaskReason, taskid);
            return;
            return false;
        }
        // 原 L729-731
        if ("1".equals(inhosp.getInhospstate()) && inhosp.getEndtime() == null) {
            return;
            return false;
        }
        // ------------------------------------------------------------------
        // 【改造·2026-10】落库前最后一道判重:
        //   同一患者 + 同一次出院记录 + 同一任务,只要已经有一条未删除的子任务(含已停用的),
        //   就不再 insert。原因见 VisitTaskCreateApi#existsSubtask 的注释:
        //   患者被重复扫到时会走"停旧 + 再 insert 一条 sendstate=4"的分支,
        //   每跑一轮多一条,最终同一患者几十条。
        // ------------------------------------------------------------------
        if (taskApi.existsSubtask(archive == null ? null : archive.getId(),
                inhosp.getInhospid(), taskid)) {
            log.info("【出入院随访】患者{}出院记录{}任务{}已有子任务,跳过重复生成。",
                    inhosp.getPatid(), inhosp.getInhospid(), taskid);
            writeFlagByType(inhosp.getInhospid(), type, "1", null);
            return true;
        }
        // 原 L732-736:组装(副作用由本类实现,见 missingOutHospTime)
@@ -138,7 +158,7 @@
                toTaskSource(serviceTask, inhosp), inhosp, archive, config, type,
                row -> onMissingOutHospTime(row));
        if (ObjectUtils.isEmpty(serviceSubtask)) {
            return;
            return false;
        }
        // 原 L737-753:就诊科室/病区填充
@@ -286,6 +306,7 @@
                        serviceSubtask.getTaskid(), serviceSubtask.getPatid());
                writeFlagByType(inhosp.getInhospid(), type, "2", "生成子任务失败 " + type);
            }
            return i == 1;
        } catch (Exception e) {
            // 原 L900-912:出错回滚事务
            log.info("生成子任务报错回滚serviceSubtask的taskid为:{},patid为:{}",
@@ -294,6 +315,7 @@
            //     原样保留(见类注释第 1 条)。
            writeFlagByTypeForRollback(inhosp.getInhospid(), type, "2", "生成子任务报错回滚 " + type);
            e.printStackTrace();
            return false;
        }
    }
@@ -478,16 +500,25 @@
        com.ruoyi.inhospvisit.domain.row.VisitTaskRow t = new com.ruoyi.inhospvisit.domain.row.VisitTaskRow();
        t.setTaskid(dto.getTaskid());
        t.setTaskName(dto.getTaskName());
        t.setTaskDesc(dto.getTaskDesc());
        t.setType(dto.getType());
        t.setServiceType(dto.getServiceType());
        t.setTemplateid(dto.getTemplateid());
        t.setTemplatename(dto.getTemplatename());
        t.setLibtemplateid(dto.getLibtemplateid());
        t.setLibtemplatename(dto.getLibtemplatename());
        t.setSendDay(dto.getSendDay());
        t.setPreachform(dto.getPreachform());
        t.setPreachformDesc(dto.getPreachformDesc());
        t.setOrgid(dto.getOrgid());
        t.setCampusid(dto.getCampusid());
        // 以下 6 个同样属于"原 DtoConversionUtils 拷贝、随 insert 落库"的列
        t.setGuid(dto.getGuid());
        t.setPid(dto.getPid());
        t.setSendType(dto.getSendType());
        t.setIsupload(dto.getIsupload());
        t.setTextParam(dto.getTextParam());
        t.setUploadTime(dto.getUploadTime());
        t.setUpdateBy(dto.getUpdateBy());
        t.setCreateBy(dto.getCreateBy());
        return t;