liusheng
5 天以前 0bbbd746e8c39d91ad7b47a4e36e29ab972dc98c
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
package com.ruoyi.inhospvisit.support;
 
import com.ruoyi.inhospvisit.domain.row.VisitInhospRow;
import com.ruoyi.inhospvisit.mapper.VisitInhospMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
 
/**
 * 随访标志位回写器 —— 统一封装"改 {@code pat_med_inhosp} 的哪个 check_flag"这件事。
 *
 * <h3>来源对照(@ b25c3b51)</h3>
 * <table border="1">
 *   <tr><th>本类方法</th><th>原实现</th><th>行数</th></tr>
 *   <tr><td>{@link #updateCheckFlag(VisitInhospRow, Integer, String, String)}</td>
 *       <td>{@code updateCheckFlag}(L1660-1684)</td><td>25</td></tr>
 *   <tr><td>{@link #setFlag}</td><td>{@code writeInSubTask} 里逐处
 *       {@code patMedInhosp2.setXxxcheckFlag(...)} + {@code updatePatMedInhosp}</td><td>—</td></tr>
 * </table>
 *
 * <h3>⚠️ type → 列的映射必须原样保留(含历史交叉写)</h3>
 * 原 {@code updateCheckFlag} 的 switch(L1663-1679):
 * <pre>
 * 1 -> deptcheck_flag        2 -> wardcheck_flag       3 -> diagcheck_flag
 * 4 -> in_deptcheck_flag     5 -> in_wardcheck_flag
 * </pre>
 * 而 {@code writeInSubTask} 里回写时会根据 type 单独 set,且存在<b>历史交叉写</b>:
 * <ul>
 *   <li>type=5 的"任务不存在"分支(L721-722)写的是 {@code inWardcheckFlag};</li>
 *   <li>type=5 的"成功/失败回写"(L885/L896)写的也是 {@code inWardcheckFlag};</li>
 *   <li>但 {@code dealOutHospInfo} 的病区宣教分支写的是 {@code in_deptcheck_flag}(见 ruoyi-publicity)。</li>
 * </ul>
 * 所以这里<b>不统一</b>:{@link #updateCheckFlag} 照抄原 switch;
 * 各调用点要写哪一列由它自己用 {@link #setFlag} 显式指定。任何"顺手统一"都是行为变更。
 *
 * <h3>为什么单独成类而不是塞进 VisitSubtaskFactory</h3>
 * 工厂是"纯组装"(可被 A 档逐行比对);本类是"写库"。
 * 混在一起会让"组装器一个副作用都没有"这个前提失效,探针也就失去意义。
 */
@Slf4j
@Component
public class InhospFlagWriter {
 
    /** 允许回写的标志位列白名单(与 {@code VisitInhospMapper.updateFlags} 的 {@code <choose>} 一致) */
    private static final Set<String> ALLOWED_FLAG_COLUMNS = Collections.unmodifiableSet(
            new HashSet<>(Arrays.asList(
                    "deptcheck_flag", "wardcheck_flag", "diagcheck_flag", "medcheck_flag",
                    "in_deptcheck_flag", "in_wardcheck_flag", "schedulecheck_flag")));
 
    @Autowired
    private VisitInhospMapper inhospMapper;
 
    /**
     * 统一回写标志位 —— 照抄原 {@code updateCheckFlag(PatMedInhosp, Integer type, String flagValue, String remark)}。
     * <p>
     * 原实现(L1660-1684):
     * <pre>
     * PatMedInhosp updateObj = new PatMedInhosp();
     * updateObj.setInhospid(patMedInhosp.getInhospid());
     * switch (type) { case 1: updateObj.setDeptcheckFlag(flagValue); break; ... }
     * if (StringUtils.isNotEmpty(remark)) {
     *     updateObj.setRemark(remark + " (type=" + type + ")");
     * }
     * patMedInhospMapper.updatePatMedInhosp(updateObj);
     * </pre>
     * ⚠️ 注意两点:
     * <ol>
     *   <li>它写的是 {@code remark}(不是 {@code long_task_reason})——原样保留;</li>
     *   <li>remark 非空时会拼上 {@code " (type=N)"} 后缀 —— 原样保留这个格式。</li>
     * </ol>
     *
     * @param row       出入院记录(只用 inhospid)
     * @param type      1=离院科室 2=离院病区 3=疾病 4=入院科室 5=入院病区
     * @param flagValue 要写入的标志位值
     * @param remark    备注;非空时会拼 {@code " (type=N)"} 后缀后写入 remark 列
     */
    public void updateCheckFlag(VisitInhospRow row, Integer type, String flagValue, String remark) {
        String column = columnOfType(type);
        if (column == null) {
            log.warn("【出入院随访】updateCheckFlag 收到未知 type={},忽略。inhospid={}",
                    type, row == null ? null : row.getInhospid());
            return;
        }
        String finalRemark = remark;
        if (com.ruoyi.common.utils.StringUtils.isNotEmpty(remark)) {
            finalRemark = remark + " (type=" + type + ")";
        }
        // 原实现走的是"整实体动态更新"(会顺带把 remark 写进去)。
        // 这里 updateFlags 只覆盖 flag + long_task_reason,所以 remark 需要单独写。
        setFlagWithRemark(row, column, flagValue, finalRemark);
    }
 
    /**
     * 只回写一个标志位(对应 {@code writeInSubTask} 里逐处 set 单个 flag 的写法)。
     * <p>
     * 原实现的写法是:新建一个"只有 inhospid + 要改的 flag"的 {@code PatMedInhosp},
     * 再调 {@code updatePatMedInhosp}(XML 里每个字段各自 {@code <if test="xxx != null">},
     * 所以只有非 null 字段生效)。
     *
     * @param inhospid 出入院记录ID
     * @param column   标志位列名(白名单校验)
     * @param value    标志位值
     * @return true = 影响行数 > 0
     */
    public boolean setFlag(Long inhospid, String column, String value) {
        if (!ALLOWED_FLAG_COLUMNS.contains(column)) {
            log.warn("【出入院随访】setFlag 收到非法列名「{}」,忽略。inhospid={}", column, inhospid);
            return false;
        }
        return inhospMapper.updateFlags(inhospid, column, value, null) > 0;
    }
 
    /**
     * 回写标志位 + 覆盖式写 {@code long_task_reason}。
     * <p>
     * 对应 {@code writeInSubTask} 里"任务不存在"/"异常"分支的写法:
     * 先 {@code setLongTaskReason(旧值 + 文案)} 再 update。
     * 注意:那些分支在 Java 侧是 {@code longTaskReason + "..."} 的字符串拼接
     * (多数不判 null),所以这里由调用方传入拼好的完整值。
     *
     * @param inhospid 出入院记录ID
     * @param column   标志位列名
     * @param value    标志位值
     * @param reason   {@code long_task_reason} 的新值;null = 不改动
     */
    public boolean setFlagWithReason(Long inhospid, String column, String value, String reason) {
        if (!ALLOWED_FLAG_COLUMNS.contains(column)) {
            log.warn("【出入院随访】setFlagWithReason 收到非法列名「{}」,忽略。inhospid={}", column, inhospid);
            return false;
        }
        return inhospMapper.updateFlags(inhospid, column, value, reason) > 0;
    }
 
    /**
     * 标志位列 + remark 一起写(原 {@code updateCheckFlag} 的实际效果)。
     * <p>
     * {@code VisitInhospMapper.updateFlags} 不覆盖 remark,所以这里复用它写 flag,
     * 另外单独更新 remark —— 两个 update 与原实现的"一次整实体 update"在结果上等价
     * (原实现也只会有 flag 与 remark 两个字段非 null)。
     */
    /**
     * 回写标志位 + 覆盖式写 {@code remark}(原 {@code updateCheckFlag} 的实际效果)。
     * <p>
     * {@code VisitInhospMapper.updateFlags} 不覆盖 remark,所以这里复用它写 flag,
     * 另外单独更新 remark —— 两个 update 与原实现的"一次整实体 update"在结果上等价
     * (原实现那次调用也只有 flag 与 remark 两个字段非 null)。
     *
     * @param inhospid  出入院记录ID
     * @param column    标志位列名(白名单校验)
     * @param flagValue 标志位值
     * @param remark    新的 remark;null 表示只写 flag
     */
    public void setFlagWithRemark(Long inhospid, String column, String flagValue, String remark) {
        if (!ALLOWED_FLAG_COLUMNS.contains(column)) {
            log.warn("【出入院随访】setFlagWithRemark 收到非法列名「{}」,忽略。inhospid={}", column, inhospid);
            return;
        }
        if (inhospid == null) {
            log.warn("【出入院随访】setFlagWithRemark 缺少 inhospid,忽略。column={}", column);
            return;
        }
        inhospMapper.updateFlags(inhospid, column, flagValue, null);
        if (remark != null) {
            inhospMapper.updateRemark(inhospid, remark);
        }
    }
 
    /**
     * 标志位列 + remark 一起写({@link #updateCheckFlag} 用,入参是行对象)。
     */
    private void setFlagWithRemark(VisitInhospRow row, String column, String flagValue, String remark) {
        if (row == null || row.getInhospid() == null) {
            log.warn("【出入院随访】setFlagWithRemark 缺少 inhospid,忽略。column={}", column);
            return;
        }
        setFlagWithRemark(row.getInhospid(), column, flagValue, remark);
    }
 
    /**
     * type → 标志位列。照抄原 {@code updateCheckFlag} 的 switch。
     *
     * @return 列名;未知 type 返回 {@code null}
     */
    private String columnOfType(Integer type) {
        if (type == null) {
            return null;
        }
        switch (type) {
            case 1:
                return "deptcheck_flag";
            case 2:
                return "wardcheck_flag";
            case 3:
                return "diagcheck_flag";
            case 4:
                return "in_deptcheck_flag";
            case 5:
                return "in_wardcheck_flag";
            default:
                return null;
        }
    }
}