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
package com.ruoyi.othervisit.api;
 
import com.ruoyi.common.core.service.OtherVisitApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
/**
 * {@link OtherVisitApi} 的<b>本模块实现</b>。
 *
 * <h3>它取代了什么</h3>
 * 在 {@code ruoyi-othervisit} 建好之前,{@link OtherVisitApi} 只有 smartor 侧的
 * 过渡桥接 {@code OtherVisitApiBridge}。手术随访的实现搬进本模块后,
 * 由本类接管 —— 这正是那个 Bridge 的类注释里预告的"将来动作"。
 *
 * <h3>⚠️ 本类两个方法<b>本次都还委托 smartor</b>(刻意,不是漏做)</h3>
 * <table border="1">
 *   <tr><th>接口方法</th><th>原实现位置</th><th>为什么本次不搬</th></tr>
 *   <tr><td>{@link #addOperationSubTask(String)}</td>
 *       <td>{@code PatMedInhospServiceImpl#addOperationSubTask} L1247-1316</td>
 *       <td>它是<b>手术等级({@code oplevelcode})+ 离院科室/病区维度</b>的扫描,
 *           属"出院随访里混着的手术分支",且依赖
 *           {@code ServiceTaskoperMapper}(仍在 smartor)与
 *           {@code writeInSubTaskForOp}(依赖 {@code ScheduleSubtaskBuilder})。</td></tr>
 *   <tr><td>{@link #dealOutHospInfoBySchedule(String)}</td>
 *       <td>同文件 L380-614</td>
 *       <td>它的<b>非手术分支</b>与"HIS 自动纳入"、"前端手动勾选"共用
 *           {@code ScheduleSubtaskBuilder}。搬它得连 builder 一起搬 ——
 *           那是独立的一次改造。</td></tr>
 * </table>
 *
 * <h3>那本模块搬了什么?</h3>
 * <b>手术编码({@code opcode})维度</b>的那条扫描:
 * {@code PatMedOperationServiceImpl#dealOperationInfo}(原 L107-149)。
 * 它的入口<b>不走</b>本接口,而是 {@link OtherVisitFacade#dealOperationInfo()} ——
 * 调用方是 {@code RyTask#dealOperationInfo}(定时任务),已直接改走门面。
 * 之所以不塞进本接口,是因为两者语义不同:
 * 接口上那两个是"出院/任务组流程里的手术分支",而这条是"手术记录自身的扫描"。
 *
 * <h3>⚠️ 为什么编译期看不到 smartor</h3>
 * 依赖方向是 smartor → ruoyi-othervisit,反过来会形成 Maven 循环依赖,直接构建失败。
 * 所以这里用 {@code ObjectProvider<OtherVisitApi>} 在<b>运行时</b>按类型惰性查找
 * smartor 侧那个承接实现,并<b>排除本类自己</b>(否则会自己调自己 → {@code StackOverflowError})。
 * 取不到就打 WARN 并返回安全值,绝不让定时任务抛异常。
 *
 * @see OtherVisitApi
 */
@Slf4j
@Component
public class OtherVisitApiImpl implements OtherVisitApi {
 
    /**
     * smartor 侧的过渡承接({@code com.smartor.service.impl.bridge.OtherVisitApiBridge})。
     * <p>
     * ⚠️ 类型参数刻意写成 {@link OtherVisitApi} 而<b>不是</b>那个具体类:
     * 本模块编译期看不到 smartor 的类型(也不允许看到)。
     */
    @Autowired
    private ObjectProvider<OtherVisitApi> otherVisitApiProvider;
 
    /**
     * 手术随访扫描(手术等级 + 离院科室/病区维度)—— 本次仍委托 smartor。
     *
     * @param config {@code sys_config: visit.early.day} 的值,可能为 null
     * @return 处理的手术记录数;承接实现不可用时返回 0
     */
    @Override
    public int addOperationSubTask(String config) {
        OtherVisitApi delegate = findExternalDelegate();
        if (delegate == null) {
            log.warn("【手术随访】addOperationSubTask 的 smartor 侧承接实现不可用(未打进应用或未装配),本次跳过。");
            return 0;
        }
        return delegate.addOperationSubTask(config);
    }
 
    /**
     * 任务组(appltype=5)首轮纳入 —— 本次仍委托 smartor。
     *
     * @param config {@code sys_config: visit.early.day}
     * @return 原实现固定返回 1;承接实现不可用时返回 0
     */
    @Override
    public int dealOutHospInfoBySchedule(String config) {
        OtherVisitApi delegate = findExternalDelegate();
        if (delegate == null) {
            log.warn("【手术随访】dealOutHospInfoBySchedule 的 smartor 侧承接实现不可用(未打进应用或未装配),本次跳过。");
            return 0;
        }
        return delegate.dealOutHospInfoBySchedule(config);
    }
 
    /**
     * 找 smartor 侧那个承接实现。
     * <p>
     * ⚠️ <b>必须排除本类</b>:本类也实现了 {@link OtherVisitApi},
     * 若不过滤就会取到自己,形成无限递归。
     * ⚠️ 用 {@code stream()} 而不是 {@code getIfAvailable()}:
     * 后者在存在多个候选时行为不确定,而这里天然有<b>两个</b>候选实现(本类 + smartor 桥接)。
     */
    private OtherVisitApi findExternalDelegate() {
        if (otherVisitApiProvider == null) {
            return null;
        }
        try {
            return otherVisitApiProvider.stream()
                    .filter(api -> api != this)
                    .findFirst()
                    .orElse(null);
        } catch (Exception e) {
            log.warn("【手术随访】获取其它随访承接实现失败,按不可用处理:{}", e.toString());
            return null;
        }
    }
}