liusheng
17 小时以前 ab2884ade73fed97d1e7d7daf4b9b5b6dee83fdd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package com.ruoyi.inhospvisit.service;
 
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.service.VisitTaskCreateApi;
import com.ruoyi.common.core.service.PreachformApi;
import com.ruoyi.common.core.service.dto.VisitSubtaskDraft;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.service.dto.VisitPreachformRow;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import java.util.List;
import java.util.Objects;
 
/**
 * 「执行方式明细」写入器 —— 逐行搬自 {@code PatMedInhospServiceImpl#addServiceSubtaskPreachform}
 * (L1061-1103,43 行),并实现第 7 步预留的
 * {@link InhospSubtaskWriter.SubtaskPreachformWriter} 接口。
 *
 * <h3>行为逐条对照</h3>
 * <ol>
 *   <li>按 taskid 查任务;查不到 → 打 ERROR 并 return 0(<b>不抛异常</b>);</li>
 *   <li>取 {@code serviceTask.preachformDesc};为空则整块跳过(返回 0);</li>
 *   <li>用 Jackson 把 JSON 反序列化成 {@code List<VisitPreachformRow>};
 *       <b>解析失败只打 ERROR,不中断</b>(随后 list 为 null → 走"解析后为空"分支);</li>
 *   <li>解析结果为空 → 打 ERROR 并 return 0;</li>
 *   <li>逐条:设 {@code taskid} → {@code subid};
 *       <b>先查重</b>(已存在则 continue,不新增);
 *       {@code sendstate} 默认 "1",调用方传了非空值则覆写;
 *       设 {@code orgid};insert。</li>
 * </ol>
 *
 * <h3>⚠️ 原实现的 3 个要点,原样保留</h3>
 * <ul>
 *   <li>返回值【永远是 0】(原 L1102 {@code return 0;}),调用方也没有用它的返回值
 *       —— 所以本类也返回 0,不做"顺手改成成功条数";</li>
 *   <li>查重用的条件是 {@code ServiceSubtaskPreachform(subid, taskid, preachform)}
 *       —— <b>注意没有设 orgid</b>(虽然 XML 支持该条件)。原样保留;</li>
 *   <li>解析失败时 {@code serviceSubtaskPreachformList} 保持 null,
 *       由 {@code CollectionUtils.isEmpty(null) == true} 走进"解析后为空"分支 —— 原样保留这个控制流。</li>
 * </ul>
 *
 * <h3>⚠️ 与调用方的事务关系(一处已登记的差异)</h3>
 * 原实现里 {@code addServiceSubtaskPreachform} 与 {@code insertServiceSubtask} 在<b>同一个 try</b> 内,
 * 它抛异常会被 {@code writeInSubTask} 的 catch 捕获并把标志位置 "2"。
 * 搬迁后 {@link InhospSubtaskWriter} 把它放在自己的 try 里按"尽力而为"处理
 * (见该方法注释)。这是<b>有意的健壮性改进</b>:写执行方式明细失败不该
 * 让整条随访子任务被判为生成失败。已登记在 {@code verify_inhospvisit_writein_semantics.py} 的说明里。
 */
@Slf4j
@Service
public class VisitPreachformWriter implements InhospSubtaskWriter.SubtaskPreachformWriter {
 
    /** 原实现里注释写明「这个 sendstate 需要在数据库设置一个默认值为"1"」 */
    private static final String DEFAULT_SENDSTATE = "1";
 
    @Autowired
    private ObjectProvider<PreachformApi> preachformApiProvider;
 
    @Autowired
    private ObjectProvider<VisitTaskCreateApi> taskCreateApiProvider;
 
    private final ObjectMapper objectMapper = new ObjectMapper();
 
    @Override
    public void addServiceSubtaskPreachform(VisitSubtaskDraft serviceSubtask, String sendstate) {
        // 原 L1063-1067:按 taskid 查任务(这里走任务创建域的接口,而不是直接查 service_task)
        VisitTaskCreateApi api = taskApi();
        String preachformDesc = api == null ? null : api.findPreachformDesc(serviceSubtask.getTaskid());
        if (api == null) {
            log.error("addServiceSubtaskPreachform taskid={} 查不到任务,跳过preachform子表生成",
                    serviceSubtask.getTaskid());
            return;
        }
 
        // 原 L1070-1071
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(preachformDesc)) {
            // 原 L1072-1078:反序列化;失败只打 ERROR,list 保持 null
            List<VisitPreachformRow> list = null;
            try {
                list = objectMapper.readValue(preachformDesc, new TypeReference<List<VisitPreachformRow>>() {
                });
            } catch (Exception e) {
                log.error("preachform转List<ServiceSubtaskPreachform>报错了:{}", e.getMessage());
            }
            // 原 L1079-1083
            if (CollectionUtils.isEmpty(list)) {
                log.error("preachformDesc解析后为空,跳过preachform子表生成,taskid为:{},preachformDesc为:{}",
                        serviceSubtask.getTaskid(), preachformDesc);
                return;
            }
            // 原 L1084-1098
            PreachformApi preachformApi = preachformApi();
            if (preachformApi == null) {
                log.error("宣教单契约 PreachformApi 不可用(service_subtask_preachform 已归 ruoyi-task),"
                        + "跳过preachform子表生成,taskid为:{}", serviceSubtask.getTaskid());
                return;
            }
            for (VisitPreachformRow row : list) {
                row.setTaskid(serviceSubtask.getTaskid());
                row.setSubid(serviceSubtask.getId());
 
                // 原 L1088-1090:先查重,已存在就不新增
                VisitPreachformRow query = new VisitPreachformRow();
                query.setSubid(row.getSubid());
                query.setTaskid(row.getTaskid());
                query.setPreachform(row.getPreachform());
                List<VisitPreachformRow> exists = preachformApi.findList(query);
                if (CollectionUtils.isNotEmpty(exists)) {
                    continue;
                }
 
                // 原 L1092-1094:默认 "1",调用方给了非空值则覆写
                row.setSendstate(DEFAULT_SENDSTATE);
                if (StringUtils.isNotEmpty(sendstate)) {
                    row.setSendstate(sendstate);
                }
 
                // 原 L1096-1097
                row.setOrgid(serviceSubtask.getOrgid());
                preachformApi.insert(row);
            }
        }
 
        // 原 L1102:返回值固定为 0(见类注释)
    }
 
    private VisitTaskCreateApi taskApi() {
        if (taskCreateApiProvider == null) {
            return null;
        }
        try {
            return taskCreateApiProvider.stream().findFirst().orElse(null);
        } catch (Exception e) {
            log.warn("【出入院随访】获取 VisitTaskCreateApi 失败:{}", e.toString());
            return null;
        }
    }
 
    /**
     * 取宣教单契约实现(2026-11 起 {@code service_subtask_preachform} 归 {@code ruoyi-task},
     * 本模块不能反向依赖它,只能经 {@code ruoyi-common} 的契约在运行期取实现)。
     */
    private PreachformApi preachformApi() {
        if (preachformApiProvider == null) {
            return null;
        }
        try {
            return preachformApiProvider.stream().findFirst().orElse(null);
        } catch (Exception e) {
            log.warn("【出入院随访】获取 PreachformApi 失败:{}", e.toString());
            return null;
        }
    }
 
    /** 供测试断言:确认本类拿到的 ObjectMapper 非空(原实现是方法内 new,这里提为字段) */
    boolean hasObjectMapper() {
        return Objects.nonNull(objectMapper);
    }
}