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; /** * 门急诊随访模块对外门面(常驻 Bean)。 *

* 这是其它模块访问门急诊随访能力的唯一入口。与 * {@code InhospVisitFacade} / {@code PublicityFacade} 同一套设计与理由: *

* *

关于"分表维护"是否该受开关管辖

* {@link #createOuthospQuarterTable()} 决定不受 {@code outpatientvisit.enabled} 约束, * 理由与出入院模块的基础数据读写一致: * */ @Slf4j @Component public class OuthospVisitFacade { private final OuthospVisitProperties properties; /** * 运行时开关({@code sys_config} 优先,{@link OuthospVisitProperties} 兜底) */ private final OuthospVisitSwitch outhospVisitSwitch; /** * 分表维护与存储过程重建(必存在;它是本模块自己的组件,没有条件装配)。 */ private final OuthospPartitionMaintainer partitionMaintainer; /** * 门诊随访编排(扫未处理门诊记录 → 匹配长期任务 → 写子任务)。 *

* ⚠️ 用 {@code ObjectProvider} 惰性取:容器里若没有它也不该让门面装配失败。 */ private final ObjectProvider taskServiceProvider; /** * Spring 使用的构造器。 *

* ⚠️ 必须显式标注 {@code @Autowired}:本类有两个公开构造器 * (另一个是给测试/非 Spring 环境用的),若不标注,Spring 会因为"构造器不唯一" * 而退回查找无参构造器,从而在启动时报 {@code No default constructor found}。 * —— 这是满意度模块实机踩到的缺陷,此处刻意保留同样的写法与注释。 */ @Autowired public OuthospVisitFacade(OuthospVisitProperties properties, OuthospVisitSwitch outhospVisitSwitch, OuthospPartitionMaintainer partitionMaintainer, ObjectProvider taskServiceProvider) { this.properties = properties; this.outhospVisitSwitch = outhospVisitSwitch; this.partitionMaintainer = partitionMaintainer; this.taskServiceProvider = taskServiceProvider; } /** * 供测试/非 Spring 环境直接构造。 *

* 分表维护器与编排服务都不传:测试构造下不提供建表与随访编排能力 * (调用会打 WARN 并安全返回),保证开关校验类测试不必拉起数据库。 */ public OuthospVisitFacade(OuthospVisitProperties properties, String sysConfigValue) { this(properties, new OuthospVisitSwitch(properties, sysConfigValue), null, null); } /** * 取运行时开关(供测试断言 / 拦截器复用) */ public OuthospVisitSwitch getOuthospVisitSwitch() { return outhospVisitSwitch; } /** * 门诊随访模块是否可用(开关打开 且 组件在位) */ public boolean isEnabled() { return outhospVisitSwitch.isEnabled(); } /** * 门诊分表维护 + 存储过程重建(供 {@code RyTask#createOuthospQuarterTable} 调用)。 * *

⚠️ 刻意不判 {@code outpatientvisit.enabled}

* 见类注释:它建的是物理分表与存储过程,属数据基础设施; * 它自己的开关是 {@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} 调用)。 * *

⚠️ 本方法受 {@code outpatientvisit.enabled} 管辖

* 与 {@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(); } }