package com.ruoyi.inhospvisit.service; import com.ruoyi.common.core.service.OtherVisitApi; import com.ruoyi.common.core.service.PublicityApi; import com.ruoyi.common.core.service.PublicityDataPort; import com.ruoyi.common.core.service.dto.InHospPublicityRowDto; import com.ruoyi.common.core.service.dto.VisitInhospUpdateDto; import com.ruoyi.common.core.service.dto.VisitTaskRuleDto; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.core.service.dto.VisitArchiveRow; import com.ruoyi.inhospvisit.domain.row.VisitInhospRow; import com.ruoyi.inhospvisit.mapper.VisitArchiveMapper; import com.ruoyi.inhospvisit.mapper.VisitInhospMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * 出入院随访的两个入口 —— 逐行搬自 {@code PatMedInhospServiceImpl} 的 * {@code dealOutHospInfo}(L324-463,140 行)与 {@code dealOutHospInfoBySchedule}(L471-614,144 行)。 * *
* 顺序与原实现一致:先入院宣教,再药品宣教。 * 取不到宣教模块时按"没有宣教要做"处理并打 WARN(fail-open)。 */ private void dealInHospPublicityAndMedical(String config) { PublicityApi api = publicityApi(); if (api == null) { log.warn("【出入院随访】PublicityApi 不可用(宣教模块未装配),跳过入院宣教与药品宣教。"); return; } try { // 原 L331-409 api.dealInHospPublicity(config); } catch (Exception e) { // 宣教失败不能拖垮随访主流程 log.warn("【出入院随访】入院宣教回调失败,已忽略:{}", e.toString()); } try { // 原 L411-444 api.dealMedicalPublicity(config); } catch (Exception e) { log.warn("【出入院随访】药品宣教回调失败,已忽略:{}", e.toString()); } } /** * 手术随访回调(原 L449-451 与 L559-608 的 {@code addOperationSubTask})。 */ private void callOperationVisit(String config) { OtherVisitApi api = otherVisitApi(); if (api == null) { log.warn("【出入院随访】OtherVisitApi 不可用(手术随访模块未装配),跳过手术随访。"); return; } try { api.addOperationSubTask(config); } catch (Exception e) { log.warn("【出入院随访】手术随访回调失败,已忽略:{}", e.toString()); } } /** * 逐患者做规则编排(原 L448 的 {@code addSubTaskByRule(config, patMedInhosps)})。 *
* 原 {@code addSubTaskByRule}(L1691) 是个"遍历患者"的外层方法,
* 本次把"遍历"放在这里,把"单患者规则判定"放进
* {@link InhospTaskOrchestrator#addSubTaskByRule}。
* 这样切分之后,两边的方法名相同但职责不同,已在各自注释里写明。
*/
private void addSubTaskByRule(String config, List2026-11 第 7 轮之后的实际链路
*
* InhospVisitFacade#dealOutHospInfoBySchedule
* → DefaultInhospVisitApi#dealOutHospInfoBySchedule
* → OtherVisitApi(ruoyi-common 契约)
* → ruoyi-task/api/contract/OtherVisitApiImpl
* → OperationSubtaskWriter#dealOutHospInfoBySchedule
*
* 即:实现在 ruoyi-task(smartor 侧那个 {@code OtherVisitApiBridge} 已在第 7 轮删除)。
* 之所以不在 othervisit:{@code task -> othervisit -> patarchive -> task} 会成环。
*
* 为什么这里不实现、也不删
* 本方法全仓零调用(只有 {@code DefaultInhospVisitApi} 调的是
* {@code inhospVisitTaskService.dealOutHospInfo},不是它),
* 是最早一轮留下的占位;删它要走 {@code plan_method_prune.py} 的证据流程,
* 本轮只把"仍由 smartor 承接"这句已经过期的话改掉,免得后人照着注释找错地方。
*
* @param config {@code sys_config: visit.early.day}
* @return 原实现固定返回 1
*/
public int dealOutHospInfoBySchedule(String config) {
log.warn("【出入院随访】InhospVisitTaskService#dealOutHospInfoBySchedule 是未被调用的占位;"
+ "真正的实现在 ruoyi-task/api/contract/OtherVisitApiImpl。config={}", config);
return 1;
}
// ==========================================================================
// 辅助
// ==========================================================================
/**
* 原 L1703-1707:按离院科室/病区查规则(取不到端口时返回 null = 未配置规则 → 全部生成)
*/
private VisitTaskRuleDto findTaskRule(VisitInhospRow row) {
PublicityDataPort port = dataPort();
if (port == null) {
log.warn("【出入院随访】PublicityDataPort 不可用,规则按「未配置」处理(全部生成)。inhospid={}", row.getInhospid());
return null;
}
try {
return port.findTaskRule(row.getLeaveldeptcode(), row.getLeavehospitaldistrictcode());
} catch (Exception e) {
log.warn("【出入院随访】查任务规则失败,按「未配置」处理:{}", e.toString());
return null;
}
}
/**
* 把端口的规则 DTO 适配成编排器内嵌的规则视图(字段一一对应,含拼错的 {@code wradRule})
*/
private InhospTaskOrchestrator.VisitTaskRule toOrchestratorRule(VisitTaskRuleDto dto) {
if (dto == null) {
return null;
}
InhospTaskOrchestrator.VisitTaskRule r = new InhospTaskOrchestrator.VisitTaskRule();
r.setDeptRule(dto.getDeptRule());
r.setWradRule(dto.getWradRule());
r.setDiagRule(dto.getDiagRule());
return r;
}
private void updateInhosp(VisitInhospUpdateDto u) {
PublicityDataPort port = dataPort();
if (port == null) {
log.warn("【出入院随访】PublicityDataPort 不可用,无法写回标志位。inhospid={}", u.getInhospid());
return;
}
port.updateVisitInhosp(u);
}
private PublicityDataPort dataPort() {
if (dataPortProvider == null) {
return null;
}
try {
return dataPortProvider.stream().findFirst().orElse(null);
} catch (Exception e) {
log.warn("【出入院随访】获取 PublicityDataPort 失败:{}", e.toString());
return null;
}
}
private PublicityApi publicityApi() {
if (publicityApiProvider == null) {
return null;
}
try {
return publicityApiProvider.stream().findFirst().orElse(null);
} catch (Exception e) {
log.warn("【出入院随访】获取 PublicityApi 失败:{}", e.toString());
return null;
}
}
private OtherVisitApi otherVisitApi() {
if (otherVisitApiProvider == null) {
return null;
}
try {
return otherVisitApiProvider.stream().findFirst().orElse(null);
} catch (Exception e) {
log.warn("【出入院随访】获取 OtherVisitApi 失败:{}", e.toString());
return null;
}
}
}