liusheng
8 天以前 f0a09ee996ab2605869844d6a3d812709e2bf0fa
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
package com.ruoyi.task.api.contract;
 
import com.ruoyi.common.core.service.VisitTaskCreateApi;
import com.ruoyi.common.core.service.dto.VisitLongTaskDto;
import com.ruoyi.common.core.service.dto.VisitPendingSubtaskDto;
import com.ruoyi.common.core.service.dto.VisitSubtaskDraft;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.ruoyi.task.domain.entity.ServiceSubtaskEntity;
import com.ruoyi.task.domain.ServiceSubtask;
import com.ruoyi.task.domain.ServiceTask;
import com.ruoyi.task.mapper.ServiceSubtaskMapper;
import com.ruoyi.task.mapper.ServiceTaskMapper;
 
/**
 * 【过渡实现·临时】{@link VisitTaskCreateApi} 在 smartor 侧的桥接。
 *
 * <h3>为什么需要它</h3>
 * 出入院随访要"建随访任务",但按你的版图,<b>任务创建将来是独立模块</b>。
 * 在它落地之前,先把现有的写库能力({@link ServiceSubtaskMapper} /
 * {@code IPatMedInhospService#persistSubtask})原样包一层,
 * 让 {@code ruoyi-inhospvisit} 现在就只依赖 {@link VisitTaskCreateApi} 这个接口。
 * <p>
 * <b>将来动作</b>:新模块建好后,把它的实现注册进容器,
 * 本类整体删除即可,{@code ruoyi-inhospvisit} <b>一行都不用改</b>。
 *
 * <h3>⚠️ 本类必须保持"纯搬运"</h3>
 * 这里<b>不得</b>加入去重、状态机、默认值补齐、合并更新等任何新逻辑 ——
 * 那些语义在 {@code ruoyi-inhospvisit} 的 {@code writeInSubTask} 里。
 * 本类只做:<b>字段搬运</b> + <b>转发现有 Mapper 调用</b>。
 * 逐字段对应关系由 {@code sql/_probe/verify_inhospvisit_equivalence.py}(A 档)与
 * {@code verify_inhospvisit_semantics.py}(B 档口径断言)把关。
 *
 * <h3>逐方法来源(迁移前 {@code PatMedInhospServiceImpl},@ b25c3b51)</h3>
 * <table border="1">
 *   <tr><th>本类方法</th><th>原实现位置</th></tr>
 *   <tr><td>{@link #findPublishedLongTask(Long)}</td><td>L686-728(查 ServiceTask,sendState=2)</td></tr>
 *   <tr><td>{@link #insertSubtask(VisitSubtaskDraft)}</td><td>L823 / L838 / L854 / L862 / L873</td></tr>
 *   <tr><td>{@link #findPendingSubtasks(Long, Long)}</td><td>L760-764、L1325-1328</td></tr>
 *   <tr><td>{@link #updatePendingSubtask(VisitPendingSubtaskDto)}</td><td>L782 / L791 / L812 / L836 / L1349</td></tr>
 * </table>
 *
 * @see com.ruoyi.common.core.service.VisitTaskCreateApi
 */
@Slf4j
@Component
public class VisitTaskCreateApiImpl implements VisitTaskCreateApi {
 
    @Autowired
    private ServiceTaskMapper serviceTaskMapper;
 
    @Autowired
    private ServiceSubtaskMapper serviceSubtaskMapper;
 
 
    /**
     * 按 taskid 取「已发布的长期任务」。
     * <p>
     * 原实现({@code PatMedInhospServiceImpl} L686-690):
     * <pre>
     * ServiceTask st = new ServiceTask();
     * st.setTaskid(taskid);
     * st.setSendState(2L);
     * List&lt;ServiceTask&gt; serviceTasks = serviceTaskMapper.selectServiceTaskList(st);
     * ServiceTask serviceTask = null;
     * if (CollectionUtils.isEmpty(serviceTasks)) { ...按 type 写不同 flag 后 return... }
     * else { serviceTask = serviceTasks.get(0); }
     * </pre>
     * 这里只负责"查 + 取第一条";"查不到时按 type 写哪个 flag"属于随访域,
     * 留在 {@code writeInSubTask} 里。
     */
    @Override
    public VisitLongTaskDto findPublishedLongTask(Long taskid) {
        ServiceTask query = new ServiceTask();
        query.setTaskid(taskid);
        query.setSendState(2L);
        List<ServiceTask> tasks = serviceTaskMapper.selectServiceTaskList(query);
        if (CollectionUtils.isEmpty(tasks)) {
            return null;
        }
        return toLongTaskDto(tasks.get(0));
    }
 
    @Override
    public boolean insertSubtask(VisitSubtaskDraft draft) {
        if (draft == null) {
            log.warn("【出入院随访·过渡桥】insertSubtask 收到 null 草稿,跳过");
            return false;
        }
        ServiceSubtask entity = toSubtaskEntity(draft);
        // 转发现有过渡入口(等价于 serviceSubtaskMapper.insertServiceSubtask(entity) == 1)
        boolean ok = serviceSubtaskMapper.insertServiceSubtask(entity) == 1;
        // useGeneratedKeys 会把自增主键回填到 entity 上,回传给出参草稿,
        // 供"先 insert 再补字段回写"的那条链路使用(原实现也是复用同一个对象)
        draft.setId(entity.getId());
        return ok;
    }
 
    @Override
    public List<VisitPendingSubtaskDto> findPendingSubtasks(Long patid, Long taskid) {
        ServiceSubtaskEntity query = new ServiceSubtaskEntity();
        query.setPatid(patid);
        query.setSendstate(2L);
        // 原实现在 dealInHospInfo(L1325-1328)里【不设 taskid】(按患者全量查),
        // 在 writeInSubTask(L760-764)里【设 taskid】。这里保持同样的可选语义。
        query.setTaskid(taskid);
        List<ServiceSubtask> rows = serviceSubtaskMapper.selectServiceSubtaskList(query);
        if (CollectionUtils.isEmpty(rows)) {
            return Collections.emptyList();
        }
        List<VisitPendingSubtaskDto> out = new ArrayList<>(rows.size());
        for (ServiceSubtask row : rows) {
            out.add(toPendingDto(row));
        }
        return out;
    }
 
    @Override
    public boolean updatePendingSubtask(VisitPendingSubtaskDto pending) {
        if (pending == null || pending.getId() == null) {
            log.warn("【出入院随访·过渡桥】updatePendingSubtask 缺少 id,跳过。pending={}", pending);
            return false;
        }
        ServiceSubtask entity = new ServiceSubtask();
        // 只映射"原实现会带过去"的字段:
        // 原实现传的是【查询出来的完整对象】+ 在内存里改的那几个字段。
        // 查询出来的完整对象里,与本方法语义相关的只有 id/taskid/endtime/longSendTime/serviceType/orgid/sendstate/patid,
        // 其余字段值不变、写回也等于不写,故此处只带这些 + 调用方改过的 result/remark/updateBy/updateTime。
        entity.setId(pending.getId());
        entity.setTaskid(pending.getTaskid());
        entity.setSendstate(pending.getSendstate());
        entity.setResult(pending.getResult());
        entity.setRemark(pending.getRemark());
        entity.setUpdateBy(pending.getUpdateBy());
        entity.setUpdateTime(pending.getUpdateTime());
        entity.setIsVisitAgain(pending.getIsVisitAgain());
        // finishtime:出入院侧从不设置(原样保留"不写"),门诊侧会设置
        entity.setFinishtime(pending.getFinishtime());
        return Boolean.TRUE.equals(serviceSubtaskMapper.updateServiceSubtask(entity));
    }
 
    /**
     * 取任务的 {@code preachformDesc}。
     * <p>
     * 原实现({@code PatMedInhospServiceImpl#addServiceSubtaskPreachform} L1063)用的是
     * {@code serviceTaskMapper.selectServiceTaskByTaskid(taskid)} ——
     * <b>不带 sendState 条件</b>,且查不到时返回 null。
     * 这里逐字照搬,不复用 {@link #findPublishedLongTask}(那个带 {@code sendState=2})。
     */
    @Override
    public String findPreachformDesc(Long taskid) {
        if (taskid == null) {
            return null;
        }
        ServiceTask task = serviceTaskMapper.selectServiceTaskByTaskid(taskid);
        return task == null ? null : task.getPreachformDesc();
    }
 
    /**
     * 是否存在「指定状态 + 指定服务类型」的子任务。
     * <p>
     * 原实现(门诊 {@code selectPatMedOuthospList} L108-117):调
     * {@code serviceSubtaskMapper.selectServiceSubtaskBySendstate(v)},
     * 参数是 {@code ServiceSubtaskEntity},设了 {@code patid} / {@code sendstates} / {@code serviceType}。
     * 这里逐字照搬,只把"非空"折叠成 {@code boolean}(调用方原本只用它做 if 判断)。
     *
     * <p>⚠️ 不属于 {@link #findPendingSubtasks(Long, Long)}:那个固定 {@code sendstate=2}
     * 且按 taskid 过滤、查 {@code selectServiceSubtaskList},口径不同、不可互替。
     */
    @Override
    public boolean existsSubtaskWithStates(Long patid, java.util.List<Long> sendstates, String serviceType) {
        if (patid == null) {
            return false;
        }
        ServiceSubtaskEntity v = new ServiceSubtaskEntity();
        v.setPatid(patid);
        v.setSendstates(sendstates);
        v.setServiceType(serviceType);
        List<ServiceSubtask> list = serviceSubtaskMapper.selectServiceSubtaskBySendstate(v);
        return !CollectionUtils.isEmpty(list);
    }
 
    // ==========================================================================
    // 字段搬运(逐字段对照,勿"顺手精简")
    // ==========================================================================
 
    private VisitLongTaskDto toLongTaskDto(ServiceTask t) {
        VisitLongTaskDto dto = new VisitLongTaskDto();
        dto.setTaskid(t.getTaskid());
        dto.setTaskName(t.getTaskName());
        dto.setType(t.getType());
        dto.setServiceType(t.getServiceType());
        dto.setTemplateid(t.getTemplateid());
        dto.setTemplatename(t.getTemplatename());
        dto.setLibtemplateid(t.getLibtemplateid());
        dto.setSendDay(t.getSendDay());
        dto.setPreachform(t.getPreachform());
        dto.setPreachformDesc(t.getPreachformDesc());
        dto.setOrgid(t.getOrgid());
        dto.setCampusid(t.getCampusid());
        dto.setHosType(t.getHospType());
        dto.setUpdateBy(t.getUpdateBy());
        dto.setCreateBy(t.getCreateBy());
        return dto;
    }
 
    /**
     * 草稿 → 实体。
     * <p>
     * 逐个 setter 对照迁移前的 {@code boxedServiceSubtask} 与 {@code writeInSubTask},
     * <b>少一个字段就会让对应列静默不更新</b>(XML 里是 {@code <if test="xxx != null">}),
     * 所以这里刻意写全,不做精简。
     */
    private ServiceSubtask toSubtaskEntity(VisitSubtaskDraft d) {
        ServiceSubtask e = new ServiceSubtask();
        e.setId(d.getId());
        e.setTaskid(d.getTaskid());
        e.setOrgid(d.getOrgid());
        e.setCampusid(d.getCampusid());
        e.setPatid(d.getPatid());
        e.setSendname(d.getSendname());
        e.setSfzh(d.getSfzh());
        e.setPhone(d.getPhone());
        e.setSex(d.getSex());
        e.setAge(d.getAge());
        e.setInhospid(d.getInhospid());
        e.setNurseId(d.getNurseId());
        e.setNurseName(d.getNurseName());
        e.setDrcode(d.getDrcode());
        e.setDrname(d.getDrname());
        e.setManagementDoctor(d.getManagementDoctor());
        e.setManagementDoctorCode(d.getManagementDoctorCode());
        e.setDeptcode(d.getDeptcode());
        e.setDeptname(d.getDeptname());
        e.setLeavehospitaldistrictcode(d.getLeavehospitaldistrictcode());
        e.setLeavehospitaldistrictname(d.getLeavehospitaldistrictname());
        e.setLeaveicd10code(d.getLeaveicd10code());
        e.setLeavediagname(d.getLeavediagname());
        e.setDiagname(d.getDiagname());
        e.setTemplateid(d.getTemplateid());
        e.setTemplatename(d.getTemplatename());
        e.setLibtemplateid(d.getLibtemplateid());
        e.setStarttime(d.getStarttime());
        e.setEndtime(d.getEndtime());
        e.setLongSendTime(d.getLongSendTime());
        e.setVisitTime(d.getVisitTime());
        e.setSendstate(d.getSendstate());
        e.setSubmit(d.getSubmit());
        e.setServiceType(d.getServiceType());
        e.setDiagType(d.getDiagType());
        e.setHospType(d.getHospType());
        e.setPreachform(d.getPreachform());
        e.setVisitCount(d.getVisitCount());
        e.setIsVisitAgain(d.getIsVisitAgain());
        e.setVisitDeptCode(d.getVisitDeptCode());
        e.setVisitDeptName(d.getVisitDeptName());
        e.setTaskSituation(d.getTaskSituation());
        e.setResult(d.getResult());
        e.setRemark(d.getRemark());
        e.setOperationItemId(d.getOperationItemId());
        e.setCreateBy(d.getCreateBy());
        e.setUpdateBy(d.getUpdateBy());
 
        // ------------------------------------------------------------------
        // 门急诊随访专用字段(OuthospSubtaskDraft)。
        //
        // ⚠️ 用 instanceof 分流,而不是给 VisitSubtaskDraft 加字段:
        //    加了就必须在这里补映射,而补映射会让【出入院那条已验收的路径】多写列
        //    (insertServiceSubtask 是 39 个条件列,本来传 null 的列从此会被写进去)。
        //    分流后:出入院传的是 VisitSubtaskDraft,下面整块不执行 —— 行为完全不变。
        //    见 OuthospSubtaskDraft 的类注释。
        // ------------------------------------------------------------------
        if (d instanceof com.ruoyi.common.core.service.dto.OuthospSubtaskDraft) {
            com.ruoyi.common.core.service.dto.OuthospSubtaskDraft o =
                    (com.ruoyi.common.core.service.dto.OuthospSubtaskDraft) d;
            // 只有父类没有的字段才在这里补映射(其余如 sendname/sfzh/phone/sex/age 父类已有)
            e.setHospno(o.getHospno());
            e.setAdmindate(o.getAdmitdate());
            e.setFinishtime(o.getFinishtime());
            // ⚠️ 原实现硬编码 "1"(不读 serviceTask.getHospType()),此处保持一致
            e.setHospType(o.getHospType());
        }
        return e;
    }
 
    private VisitPendingSubtaskDto toPendingDto(ServiceSubtask s) {
        VisitPendingSubtaskDto dto = new VisitPendingSubtaskDto();
        dto.setId(s.getId());
        dto.setTaskid(s.getTaskid());
        dto.setEndtime(s.getEndtime());
        dto.setLongSendTime(s.getLongSendTime());
        dto.setServiceType(s.getServiceType());
        dto.setOrgid(s.getOrgid());
        dto.setSendstate(s.getSendstate());
        // finishtime:门诊侧停旧子任务时要读到它吗?原实现是"在查询出来的完整对象上改",
        // 而它要改的就是 finishtime 本身(设为 new Date()),所以这里带上查询值可保证
        // "未改动的字段回写等于不写"这一语义成立。
        dto.setFinishtime(s.getFinishtime());
        // result / remark / updateBy / updateTime 刻意【不带过来】:
        // 它们原本就是 null(查询结果为 sendstate=2 的待执行记录),
        // 由调用方在"移出"时按原实现设置。
        return dto;
    }
}