package com.ruoyi.outpatientvisit.api;
|
|
import com.ruoyi.outpatientvisit.config.OuthospVisitProperties;
|
import com.ruoyi.outpatientvisit.config.OuthospVisitSwitch;
|
import com.ruoyi.outpatientvisit.support.OuthospPartitionMaintainer;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Component;
|
|
/**
|
* 门急诊随访模块对外门面(<b>常驻 Bean</b>)。
|
* <p>
|
* 这是其它模块访问门急诊随访能力的<b>唯一入口</b>。与
|
* {@code InhospVisitFacade} / {@code PublicityFacade} 同一套设计与理由:
|
* <ul>
|
* <li><b>永远存在</b>(不用 {@code @ConditionalOnProperty})—— 调用方({@code RyTask}
|
* 定时任务)的 {@code @Autowired} 在任何开关状态下都<b>不会启动失败</b>;</li>
|
* <li>开关在 {@code sys_config} 的 {@code outpatientvisit.enabled},由
|
* {@link OuthospVisitSwitch} <b>运行时</b>读取(10 秒进程内缓存),改完无需重启;</li>
|
* <li>关闭时返回安全值并打 WARN,<b>不抛异常</b>,保证调用方主流程照常完成。</li>
|
* </ul>
|
*
|
* <h3>关于"分表维护"是否该受开关管辖</h3>
|
* {@link #createOuthospQuarterTable()} 决定<b>不受</b> {@code outpatientvisit.enabled} 约束,
|
* 理由与出入院模块的基础数据读写一致:
|
* <ul>
|
* <li>它建的是<b>物理分表 + 存储过程</b>,是数据基础设施,不是"生成随访";</li>
|
* <li>关掉随访生成却让分表不建,会导致新周期的门诊记录写进不存在的表 ——
|
* 那是数据故障,与"今天不发随访"完全不是一回事;</li>
|
* <li>而且它本身已有独立的开关:{@code sys_config: outhosp.split.mode}
|
* 没配就整块不执行(见 {@link OuthospPartitionMaintainer})。</li>
|
* </ul>
|
*/
|
@Slf4j
|
@Component
|
public class OuthospVisitFacade {
|
|
private final OuthospVisitProperties properties;
|
|
/**
|
* 运行时开关({@code sys_config} 优先,{@link OuthospVisitProperties} 兜底)
|
*/
|
private final OuthospVisitSwitch outhospVisitSwitch;
|
|
/**
|
* 分表维护与存储过程重建(必存在;它是本模块自己的组件,没有条件装配)。
|
*/
|
private final OuthospPartitionMaintainer partitionMaintainer;
|
|
/**
|
* 门诊随访编排(扫未处理门诊记录 → 匹配长期任务 → 写子任务)。
|
* <p>
|
* ⚠️ 用 {@code ObjectProvider} 惰性取:容器里若没有它也不该让门面装配失败。
|
*/
|
private final ObjectProvider<com.ruoyi.outpatientvisit.service.OuthospVisitTaskService> taskServiceProvider;
|
|
/**
|
* Spring 使用的构造器。
|
* <p>
|
* ⚠️ <b>必须显式标注 {@code @Autowired}</b>:本类有两个公开构造器
|
* (另一个是给测试/非 Spring 环境用的),若不标注,Spring 会因为"构造器不唯一"
|
* 而退回查找无参构造器,从而在启动时报 {@code No default constructor found}。
|
* —— 这是满意度模块<b>实机踩到</b>的缺陷,此处刻意保留同样的写法与注释。
|
*/
|
@Autowired
|
public OuthospVisitFacade(OuthospVisitProperties properties,
|
OuthospVisitSwitch outhospVisitSwitch,
|
OuthospPartitionMaintainer partitionMaintainer,
|
ObjectProvider<com.ruoyi.outpatientvisit.service.OuthospVisitTaskService> taskServiceProvider) {
|
this.properties = properties;
|
this.outhospVisitSwitch = outhospVisitSwitch;
|
this.partitionMaintainer = partitionMaintainer;
|
this.taskServiceProvider = taskServiceProvider;
|
}
|
|
/**
|
* 供<b>测试/非 Spring 环境</b>直接构造。
|
* <p>
|
* 分表维护器与编排服务都不传:测试构造下不提供建表与随访编排能力
|
* (调用会打 WARN 并安全返回),保证开关校验类测试不必拉起数据库。
|
*/
|
public OuthospVisitFacade(OuthospVisitProperties properties, String sysConfigValue) {
|
this(properties, new OuthospVisitSwitch(properties, sysConfigValue), null, null);
|
}
|
|
/**
|
* 取运行时开关(供测试断言 / 拦截器复用)
|
*/
|
public OuthospVisitSwitch getOuthospVisitSwitch() {
|
return outhospVisitSwitch;
|
}
|
|
/**
|
* 门诊随访模块是否可用(开关打开 <b>且</b> 组件在位)
|
*/
|
public boolean isEnabled() {
|
return outhospVisitSwitch.isEnabled();
|
}
|
|
/**
|
* 门诊分表维护 + 存储过程重建(供 {@code RyTask#createOuthospQuarterTable} 调用)。
|
*
|
* <h3>⚠️ 刻意<b>不</b>判 {@code outpatientvisit.enabled}</h3>
|
* 见类注释:它建的是物理分表与存储过程,属数据基础设施;
|
* 它自己的开关是 {@code sys_config: outhosp.split.mode}。
|
* 若把它也套上随访开关,关闭随访会让新周期分表不建 → 门诊记录写不进表。
|
*
|
* @return true = 已执行(不代表"建了新表",周期表已存在时也算已执行);
|
* false = 组件不可用(非 Spring 构造),已打 WARN
|
*/
|
public boolean createOuthospQuarterTable() {
|
if (partitionMaintainer == null) {
|
log.warn("【门急诊随访】分表维护器不可用(非 Spring 构造或装配缺失),createOuthospQuarterTable 跳过。");
|
return false;
|
}
|
partitionMaintainer.createOuthospQuarterTable();
|
return true;
|
}
|
|
/**
|
* 门诊随访编排(供 {@code PatMedOuthospServiceImpl#dealOutpatientInfo} 与
|
* {@code RyTask} 调用)。
|
*
|
* <h3>⚠️ 本方法<b>受</b> {@code outpatientvisit.enabled} 管辖</h3>
|
* 与 {@link #createOuthospQuarterTable()} 相反:那是"建分表/存储过程"的数据基础设施;
|
* 本方法才是"生成门诊随访"的业务动作 —— 关掉开关就该停下。
|
* 关闭时返回 {@code 0} 并打 WARN(不抛异常,保证定时任务主流程不被拖垮)。
|
*
|
* @return 关闭/不可用时返回 0;正常时返回编排结果(原实现固定返回 1)
|
*/
|
public Integer dealOutpatientInfo() {
|
if (!isEnabled()) {
|
log.warn("【门急诊随访】模块未启用(参数配置 outpatientvisit.enabled=false),dealOutpatientInfo 跳过。");
|
return 0;
|
}
|
if (taskServiceProvider == null) {
|
log.warn("【门急诊随访】编排服务不可用(非 Spring 构造),dealOutpatientInfo 跳过。");
|
return 0;
|
}
|
com.ruoyi.outpatientvisit.service.OuthospVisitTaskService svc =
|
taskServiceProvider.stream().findFirst().orElse(null);
|
if (svc == null) {
|
log.warn("【门急诊随访】容器里没有 OuthospVisitTaskService,dealOutpatientInfo 跳过。");
|
return 0;
|
}
|
return svc.dealOutpatientInfo();
|
}
|
}
|