liusheng
8 天以前 34f78281cf395a24e1f3f1c3b861186ff8a03b7b
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
package com.ruoyi.inhospvisit.controller;
 
import com.ruoyi.common.core.service.IConfigService;
import com.ruoyi.inhospvisit.api.InhospVisitFacade;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * 出入院随访<b>触发端点</b> —— 从 {@code ruoyi-admin} 的 {@code PatMedInhospController} 迁入。
 *
 * <h3>⚠️ URL 一个都不能变</h3>
 * 类级路径仍是 {@code /smartor/patinhosp},三个方法级路径逐字照抄:
 * <ul>
 *   <li>{@code POST /smartor/patinhosp/dealOutHospInfo}</li>
 *   <li>{@code POST /smartor/patinhosp/dealOutHospInfoBySchedule}</li>
 *   <li>{@code POST /smartor/patinhosp/addOperationSubTask}</li>
 * </ul>
 * 真实前端在仓库外({@code D:\daima\smartor\smartor-web},代理 {@code localhost:8095}),
 * 改了地址就无法回归。由 {@code sql/_probe/verify_inhospvisit_url_equivalence.py} 把关。
 *
 * <h3>迁入时同步删除</h3>
 * {@code PatMedInhospController} 里对应这 3 个方法的
 * {@code @PostMapping} 与 {@code @ApiOperation} 必须<b>同时删掉</b> ——
 * 否则两个类都映射同一路径,Spring 会因 {@code Ambiguous mapping} <b>直接启动失败</b>。
 *
 * <h3>与原 Controller 的两处差异(等价改写,已登记)</h3>
 * <ol>
 *   <li><b>不再注入 {@code ISysConfigService}</b>:{@code visit.early.day} 改由
 *       {@link InhospVisitTaskService} 内部读(它本来就要用这个值)。
 *       原实现是在 Controller 里读好再传进去的,效果一致。</li>
 *   <li><b>{@code active} 只用于"是否做门诊随访"的站点判断</b>(原 L263 的
 *       {@code if (!active.equals("xh"))}),与原实现同一位置、同一写法。</li>
 * </ol>
 *
 * <h3>开关如何生效</h3>
 * 本模块的 {@code InhospVisitAvailabilityInterceptor} 通过
 * {@code InhospVisitWebConfig} 挂在这两条精确路径上:
 * <pre>
 * /smartor/patinhosp/dealOutHospInfo
 * /smartor/patinhosp/dealOutHospInfoBySchedule
 * </pre>
 * 迁入后"模块自己的端点 + 模块自己的拦截器"终于同处一个模块,
 * 不再是跨模块注册(那是本次改造期间的一个临时状态)。
 * <p>
 * ⚠️ {@code /addOperationSubTask} <b>刻意不挂拦截器</b>:它的实现本次未搬
 * (属第二批 {@code ruoyi-othervisit}),挂上会让"还没搬走的端点"也受本开关影响。
 */
@Slf4j
@Api(description = "出入院随访触发")
@RestController
@RequestMapping("/smartor/patinhosp")
public class InhospVisitController {
 
    /** 站点:新华(暂时不做门诊随访) */
    private static final String SITE_XH = "xh";
 
    /** 出院随访「通知类任务」提前几天发(原 Controller 从 sys_config 读的就是这个键) */
    private static final String VISIT_EARLY_DAY_KEY = "visit.early.day";
 
    @Value("${spring.profiles.active}")
    private String active;
 
    @Autowired
    private InhospVisitFacade inhospVisitFacade;
 
    /**
     * 参数配置服务(ruoyi-common 的接口,实现在 ruoyi-system)。
     * <p>
     * ⚠️ 用 {@code ObjectProvider} 惰性取:本模块只依赖 ruoyi-common,
     * 在独立部署/测试等"容器里没有实现"的场景下不能因此启动失败。
     * <p>
     * ⚠️ <b>必须由 Controller 读、不能传给 Service 去读</b>:
     * 原实现就是"Controller 读好再传进去"(原 L259/L274/L285),
     * Service 层收的是<b>值</b>。保持这个形状,行为才一致。
     */
    @Autowired
    private ObjectProvider<IConfigService> configServiceProvider;
 
    /**
     * 出院随访主扫描 + 门诊随访(原 {@code PatMedInhospController#dealOutHospInfo} L256-266)。
     * <p>
     * 逐行对应:
     * <pre>
     * String config = configService.selectConfigByKey("visit.early.day");
     * //出院表
     * iPatMedInhospService.dealOutHospInfo(config);
     * //门诊表(新华的暂时不做门诊随访)
     * if (!active.equals("xh")) {
     *     iPatMedOuthospService.dealOutpatientInfo();
     * }
     * </pre>
     * 搬迁后 {@code config} 由 {@link InhospVisitTaskService} 内部读取。
     * 返回类型保持 {@code void}(与前端契约一致),<b>不改出参</b>。
     */
    @ApiOperation("dealOutHospInfo")
    @PostMapping("/dealOutHospInfo")
    public void dealOutHospInfo() {
        // 原 L259:String config = configService.selectConfigByKey("visit.early.day");
        String config = readVisitEarlyDay();
        //出院表(含入院宣教 / 药品宣教 / 规则编排 / 手术随访 / 再入院处理)
        inhospVisitFacade.dealOutHospInfo(config);
        //门诊表(新华的暂时不做门诊随访)
        if (!SITE_XH.equals(active)) {
            inhospVisitFacade.dealOutpatientInfo();
        }
    }
 
    /**
     * 任务组首轮纳入(原 {@code PatMedInhospController#dealOutHospInfoBySchedule} L271-277)。
     * <p>
     * ⚠️ 实现本次<b>未搬迁</b>(含手术分支与任务组 builder,属第二批范围),
     * 由门面转发到 smartor 的实现 —— 行为与原 Controller 直接调用完全一致。
     */
    @ApiOperation("dealOutHospInfoBySchedule")
    @PostMapping("/dealOutHospInfoBySchedule")
    public void dealOutHospInfoBySchedule() {
        // 原 L274:String config = configService.selectConfigByKey("visit.early.day");
        inhospVisitFacade.dealOutHospInfoBySchedule(readVisitEarlyDay());
    }
 
    /**
     * 手术随访手动触发(原 {@code PatMedInhospController#addOperationSubTask} L282-287)。
     * <p>
     * ⚠️ 实现本次<b>未搬迁</b>(属第二批 {@code ruoyi-othervisit}),
     * 由门面转发到 smartor 的实现。
     */
    @ApiOperation("addOperationSubTask")
    @PostMapping("/addOperationSubTask")
    public void addOperationSubTask() {
        // 原 L285:String config = configService.selectConfigByKey("visit.early.day");
        inhospVisitFacade.addOperationSubTask(readVisitEarlyDay());
    }
 
    /**
     * 读 {@code sys_config: visit.early.day}。
     * <p>
     * 对应原 Controller 三处 {@code configService.selectConfigByKey("visit.early.day")}。
     * 取不到(没有实现 / 读库异常)时返回 {@code null} 并打 WARN ——
     * 原实现在这种情况下拿到的也是 {@code null}({@code selectConfigByKey} 查不到即返回 null),
     * 所以语义一致。
     */
    private String readVisitEarlyDay() {
        if (configServiceProvider == null) {
            return null;
        }
        try {
            IConfigService svc = configServiceProvider.stream().findFirst().orElse(null);
            if (svc == null) {
                log.warn("【出入院随访】容器里没有 IConfigService 实现,{} 按未配置(null)处理。",
                        VISIT_EARLY_DAY_KEY);
                return null;
            }
            return svc.selectConfigByKey(VISIT_EARLY_DAY_KEY);
        } catch (Exception e) {
            log.warn("【出入院随访】读取 {} 失败,按未配置(null)处理:{}",
                    VISIT_EARLY_DAY_KEY, e.toString());
            return null;
        }
    }
}