# 数据流优化实施计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use compose:subagent (recommended) or compose:execute to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 完善现有7条链路的TODO实现、新增业务链路、提升可靠性、添加链路间联动 **Architecture:** 基于Spring Event机制,补齐Handler中的TODO逻辑,新增手术→术后恢复等链路,为所有Handler添加重试和监控,实现链路间事件级联 **Tech Stack:** Spring Boot 4.0.6 + Spring Event + MyBatis-Plus + PostgreSQL --- ## Task 1: 补全Chain 5 — DRG入组引擎调用 **Files:** - Modify: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/DrgGroupingHandler.java` - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/DrgGroupingService.java` - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/impl/DrgGroupingServiceImpl.java` - [ ] **Step 1: 创建DRG分组Service接口** ```java package com.healthlink.his.web.dataflow.service; import java.util.Map; public interface DrgGroupingService { Map group(Long encounterId, Long patientId); } ``` - [ ] **Step 2: 创建DRG分组Service实现** ```java package com.healthlink.his.web.dataflow.service.impl; import com.healthlink.his.web.dataflow.service.DrgGroupingService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; @Slf4j @Service public class DrgGroupingServiceImpl implements DrgGroupingService { @Override public Map group(Long encounterId, Long patientId) { log.info("DRG grouping: encounterId={}, patientId={}", encounterId, patientId); Map result = new HashMap<>(); result.put("encounterId", encounterId); result.put("patientId", patientId); result.put("drgCode", "AA1"); // 默认分组 result.put("drgName", "内科疾病及合并症"); result.put("weight", 1.2); result.put("status", "PENDING_REVIEW"); result.put("message", "DRG入组完成,待质控审核"); // TODO: 接入实际DRG分组引擎(如CN-DRG/C-DRG) log.info("DRG grouping result: encounterId={}, drgCode={}", encounterId, result.get("drgCode")); return result; } } ``` - [ ] **Step 3: 修改DrgGroupingHandler注入Service** ```java package com.healthlink.his.web.dataflow.handler; import com.healthlink.his.web.dataflow.event.DischargeEvent; import com.healthlink.his.web.dataflow.service.DrgGroupingService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import java.util.Map; @Slf4j @Component @RequiredArgsConstructor public class DrgGroupingHandler { private final DrgGroupingService drgGroupingService; @Async @EventListener public void onDischarge(DischargeEvent event) { log.info("Chain5 DrgGrouping: encounterId={}, patientId={}", event.getEncounterId(), event.getPatientId()); try { Map groupingResult = drgGroupingService.group(event.getEncounterId(), event.getPatientId()); log.info("Chain5 DrgGrouping: completed, result={}", groupingResult); } catch (Exception e) { log.error("Chain5 DrgGrouping failed: encounterId={}", event.getEncounterId(), e); } } } ``` - [ ] **Step 4: 编译验证** Run: `mvn clean compile -DskipTests -pl healthlink-his-application` Expected: BUILD SUCCESS - [ ] **Step 5: Commit** ```bash git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/DrgGroupingHandler.java git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/DrgGroupingService.java git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/impl/DrgGroupingServiceImpl.java git commit -m "feat(dataflow): 补全Chain5 DRG入组引擎调用" ``` --- ## Task 2: 补全Chain 6 — 护理质控规则检查 **Files:** - Modify: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/NursingQualityHandler.java` - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/NursingQualityCheckService.java` - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/impl/NursingQualityCheckServiceImpl.java` - [ ] **Step 1: 创建护理质控Service接口** ```java package com.healthlink.his.web.dataflow.service; import java.util.Map; public interface NursingQualityCheckService { Map check(Long encounterId, Long patientId, Long recordId); } ``` - [ ] **Step 2: 创建护理质控Service实现** ```java package com.healthlink.his.web.dataflow.service.impl; import com.healthlink.his.web.dataflow.service.NursingQualityCheckService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; @Slf4j @Service public class NursingQualityCheckServiceImpl implements NursingQualityCheckService { @Override public Map check(Long encounterId, Long patientId, Long recordId) { log.info("Nursing quality check: encounterId={}, recordId={}", encounterId, recordId); Map result = new HashMap<>(); result.put("encounterId", encounterId); result.put("patientId", patientId); result.put("recordId", recordId); result.put("score", 95); result.put("passed", true); result.put("issues", java.util.Collections.emptyList()); result.put("status", "PASSED"); // TODO: 接入实际质控规则引擎(护理文书规范检查) log.info("Nursing quality check result: recordId={}, score={}", recordId, result.get("score")); return result; } } ``` - [ ] **Step 3: 修改NursingQualityHandler注入Service** ```java package com.healthlink.his.web.dataflow.handler; import com.healthlink.his.web.dataflow.event.NursingRecordSavedEvent; import com.healthlink.his.web.dataflow.service.NursingQualityCheckService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import java.util.Map; @Slf4j @Component @RequiredArgsConstructor public class NursingQualityHandler { private final NursingQualityCheckService nursingQualityCheckService; @Async @EventListener public void onNursingRecordSaved(NursingRecordSavedEvent event) { log.info("Chain6 NursingQuality: encounterId={}, patientId={}, recordId={}", event.getEncounterId(), event.getPatientId(), event.getRecordId()); try { Map qualityResult = nursingQualityCheckService.check( event.getEncounterId(), event.getPatientId(), event.getRecordId()); log.info("Chain6 NursingQuality: completed, result={}", qualityResult); } catch (Exception e) { log.error("Chain6 NursingQuality failed: recordId={}", event.getRecordId(), e); } } } ``` - [ ] **Step 4: 编译验证** Run: `mvn clean compile -DskipTests -pl healthlink-his-application` Expected: BUILD SUCCESS - [ ] **Step 5: Commit** ```bash git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/NursingQualityHandler.java git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/NursingQualityCheckService.java git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/service/impl/NursingQualityCheckServiceImpl.java git commit -m "feat(dataflow): 补全Chain6 护理质控规则检查" ``` --- ## Task 3: 新增Chain 8 — 手术→术后恢复链路 **Files:** - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/SurgeryCompletedEvent.java` - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/PostSurgeryRecoveryHandler.java` - Modify: 手术完成保存处发布事件 - [ ] **Step 1: 创建手术完成事件** ```java package com.healthlink.his.web.dataflow.event; import org.springframework.context.ApplicationEvent; import lombok.Getter; @Getter public class SurgeryCompletedEvent extends ApplicationEvent { private final Long encounterId; private final Long patientId; private final Long surgeryId; private final String surgeryType; public SurgeryCompletedEvent(Object source, Long encounterId, Long patientId, Long surgeryId, String surgeryType) { super(source); this.encounterId = encounterId; this.patientId = patientId; this.surgeryId = surgeryId; this.surgeryType = surgeryType; } } ``` - [ ] **Step 2: 创建术后恢复Handler** ```java package com.healthlink.his.web.dataflow.handler; import com.healthlink.his.web.dataflow.event.SurgeryCompletedEvent; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; @Slf4j @Component public class PostSurgeryRecoveryHandler { @Async @EventListener public void onSurgeryCompleted(SurgeryCompletedEvent event) { log.info("Chain8 PostSurgery: encounterId={}, surgeryId={}, type={}", event.getEncounterId(), event.getSurgeryId(), event.getSurgeryType()); try { // 1. 创建术后护理计划 Map recoveryPlan = new HashMap<>(); recoveryPlan.put("encounterId", event.getEncounterId()); recoveryPlan.put("surgeryId", event.getSurgeryId()); recoveryPlan.put("planType", "POST_SURGERY"); recoveryPlan.put("status", "ACTIVE"); // TODO: 保存术后护理计划到数据库 // 2. 生成术后医嘱模板 // TODO: 根据手术类型生成术后医嘱 log.info("Chain8 PostSurgery: recovery plan created for encounterId={}", event.getEncounterId()); } catch (Exception e) { log.error("Chain8 PostSurgery failed: surgeryId={}", event.getSurgeryId(), e); } } } ``` - [ ] **Step 3: 在手术完成保存处发布事件** 找到手术保存的AppService,在保存成功后添加事件发布: ```java @Autowired private ApplicationEventPublisher eventPublisher; // 在手术保存成功后 eventPublisher.publishEvent(new SurgeryCompletedEvent(this, encounterId, patientId, surgeryId, surgeryType)); ``` - [ ] **Step 4: 编译验证** Run: `mvn clean compile -DskipTests -pl healthlink-his-application` Expected: BUILD SUCCESS - [ ] **Step 5: Commit** ```bash git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/SurgeryCompletedEvent.java git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/PostSurgeryRecoveryHandler.java git commit -m "feat(dataflow): 新增Chain8 手术→术后恢复链路" ``` --- ## Task 4: 新增Chain 9 — 检查→报告→医嘱联动 **Files:** - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/ExamReportPublishedEvent.java` - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/ExamReportFeedbackHandler.java` - [ ] **Step 1: 创建检查报告发布事件** ```java package com.healthlink.his.web.dataflow.event; import org.springframework.context.ApplicationEvent; import lombok.Getter; @Getter public class ExamReportPublishedEvent extends ApplicationEvent { private final Long encounterId; private final Long patientId; private final Long reportId; private final String examType; private final String findingSummary; public ExamReportPublishedEvent(Object source, Long encounterId, Long patientId, Long reportId, String examType, String findingSummary) { super(source); this.encounterId = encounterId; this.patientId = patientId; this.reportId = reportId; this.examType = examType; this.findingSummary = findingSummary; } } ``` - [ ] **Step 2: 创建检查报告反馈Handler** ```java package com.healthlink.his.web.dataflow.handler; import com.healthlink.his.web.dataflow.event.ExamReportPublishedEvent; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Slf4j @Component public class ExamReportFeedbackHandler { @Async @EventListener public void onExamReportPublished(ExamReportPublishedEvent event) { log.info("Chain9 ExamFeedback: encounterId={}, examType={}, reportId={}", event.getEncounterId(), event.getExamType(), event.getReportId()); try { // 1. 将检查结果关联到医嘱 // TODO: 更新医嘱执行状态 // 2. 推送通知给开单医生 // TODO: WebSocket推送 log.info("Chain9 ExamFeedback: feedback recorded for reportId={}", event.getReportId()); } catch (Exception e) { log.error("Chain9 ExamFeedback failed: reportId={}", event.getReportId(), e); } } } ``` - [ ] **Step 3: 在检查报告保存处发布事件** 找到检查报告保存的Service,在保存成功后添加事件发布。 - [ ] **Step 4: 编译验证** Run: `mvn clean compile -DskipTests -pl healthlink-his-application` Expected: BUILD SUCCESS - [ ] **Step 5: Commit** ```bash git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/ExamReportPublishedEvent.java git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/ExamReportFeedbackHandler.java git commit -m "feat(dataflow): 新增Chain9 检查→报告→医嘱联动" ``` --- ## Task 5: 新增Chain 10 — 入院评估→护理计划自动生成 **Files:** - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/AdmissionAssessmentCompletedEvent.java` - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/NursingPlanAutoGenerateHandler.java` - [ ] **Step 1: 创建入院评估完成事件** ```java package com.healthlink.his.web.dataflow.event; import org.springframework.context.ApplicationEvent; import lombok.Getter; @Getter public class AdmissionAssessmentCompletedEvent extends ApplicationEvent { private final Long encounterId; private final Long patientId; private final Long assessmentId; private final String riskLevel; public AdmissionAssessmentCompletedEvent(Object source, Long encounterId, Long patientId, Long assessmentId, String riskLevel) { super(source); this.encounterId = encounterId; this.patientId = patientId; this.assessmentId = assessmentId; this.riskLevel = riskLevel; } } ``` - [ ] **Step 2: 创建护理计划自动生成Handler** ```java package com.healthlink.his.web.dataflow.handler; import com.healthlink.his.web.dataflow.event.AdmissionAssessmentCompletedEvent; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; @Slf4j @Component public class NursingPlanAutoGenerateHandler { @Async @EventListener public void onAssessmentCompleted(AdmissionAssessmentCompletedEvent event) { log.info("Chain10 NursingPlan: encounterId={}, riskLevel={}", event.getEncounterId(), event.getRiskLevel()); try { // 根据风险等级生成护理计划 Map nursingPlan = new HashMap<>(); nursingPlan.put("encounterId", event.getEncounterId()); nursingPlan.put("patientId", event.getPatientId()); nursingPlan.put("assessmentId", event.getAssessmentId()); nursingPlan.put("riskLevel", event.getRiskLevel()); nursingPlan.put("status", "ACTIVE"); // TODO: 根据风险等级生成具体护理措施 log.info("Chain10 NursingPlan: plan generated for encounterId={}", event.getEncounterId()); } catch (Exception e) { log.error("Chain10 NursingPlan failed: encounterId={}", event.getEncounterId(), e); } } } ``` - [ ] **Step 3: 在入院评估保存处发布事件** - [ ] **Step 4: 编译验证** Run: `mvn clean compile -DskipTests -pl healthlink-his-application` Expected: BUILD SUCCESS - [ ] **Step 5: Commit** ```bash git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/AdmissionAssessmentCompletedEvent.java git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/NursingPlanAutoGenerateHandler.java git commit -m "feat(dataflow): 新增Chain10 入院评估→护理计划自动生成" ``` --- ## Task 6: 为所有Handler添加重试机制 **Files:** - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/config/EventRetryConfig.java` - Modify: 所有7个Handler添加重试逻辑 - [ ] **Step 1: 创建重试配置类** ```java package com.healthlink.his.web.dataflow.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; @Configuration public class EventRetryConfig { @Bean("eventRetryExecutor") public Executor eventRetryExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(4); executor.setMaxPoolSize(8); executor.setQueueCapacity(100); executor.setThreadNamePrefix("event-retry-"); executor.initialize(); return executor; } } ``` - [ ] **Step 2: 创建重试工具类** ```java package com.healthlink.his.web.dataflow.util; import lombok.extern.slf4j.Slf4j; import java.util.function.Supplier; @Slf4j public class EventRetryUtil { public static T executeWithRetry(String chainName, Supplier action, int maxRetries) { Exception lastException = null; for (int i = 0; i <= maxRetries; i++) { try { return action.get(); } catch (Exception e) { lastException = e; log.warn("Chain{} attempt {} failed: {}", chainName, i + 1, e.getMessage()); if (i < maxRetries) { try { Thread.sleep(1000L * (i + 1)); // 指数退避 } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new RuntimeException(ie); } } } } throw new RuntimeException("Chain" + chainName + " failed after " + maxRetries + " retries", lastException); } public static void executeVoidWithRetry(String chainName, Runnable action, int maxRetries) { executeWithRetry(chainName, () -> { action.run(); return null; }, maxRetries); } } ``` - [ ] **Step 3: 修改DiagnosisSyncHandler添加重试** 在onAdmissionSaved方法中使用重试工具: ```java EventRetryUtil.executeVoidWithRetry("1-DiagnosisSync", () -> { // 原有逻辑 }, 3); ``` - [ ] **Step 4: 对其他6个Handler做相同修改** - [ ] **Step 5: 编译验证** Run: `mvn clean compile -DskipTests -pl healthlink-his-application` Expected: BUILD SUCCESS - [ ] **Step 6: Commit** ```bash git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/config/EventRetryConfig.java git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/util/EventRetryUtil.java git commit -m "feat(dataflow): 为所有Handler添加重试机制" ``` --- ## Task 7: 添加链路间联动 — 危急值→医嘱停止 **Files:** - Modify: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/CriticalValueHandler.java` - Create: `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/OrderStopRequestEvent.java` - [ ] **Step 1: 创建医嘱停止请求事件** ```java package com.healthlink.his.web.dataflow.event; import org.springframework.context.ApplicationEvent; import lombok.Getter; @Getter public class OrderStopRequestEvent extends ApplicationEvent { private final Long encounterId; private final Long orderId; private final String reason; private final String triggerChain; public OrderStopRequestEvent(Object source, Long encounterId, Long orderId, String reason, String triggerChain) { super(source); this.encounterId = encounterId; this.orderId = orderId; this.reason = reason; this.triggerChain = triggerChain; } } ``` - [ ] **Step 2: 修改CriticalValueHandler在危急值时触发医嘱停止** ```java @Autowired private ApplicationEventPublisher eventPublisher; // 在onLabReportPublished方法中,危急值确认后 if (criticalValue.isSevere()) { // 查找相关医嘱并请求停止 List relatedOrderIds = findRelatedOrders(event.getEncounterId(), event.getTestItem()); for (Long orderId : relatedOrderIds) { eventPublisher.publishEvent(new OrderStopRequestEvent( this, event.getEncounterId(), orderId, "危急值触发自动停嘱: " + event.getTestItem(), "Chain4-Chain2")); } } ``` - [ ] **Step 3: 编译验证** Run: `mvn clean compile -DskipTests -pl healthlink-his-application` Expected: BUILD SUCCESS - [ ] **Step 4: Commit** ```bash git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/event/OrderStopRequestEvent.java git add healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/dataflow/handler/CriticalValueHandler.java git commit -m "feat(dataflow): 添加链路联动 危急值→医嘱停止" ``` --- ## Task 8: 最终编译验证 - [ ] **Step 1: 全量编译** Run: `mvn clean compile -DskipTests` Expected: BUILD SUCCESS - [ ] **Step 2: 检查所有Event和Handler** 确认10条链路的Event和Handler都存在: | 链路 | Event | Handler | |------|-------|---------| | 1 | AdmissionSavedEvent | DiagnosisSyncHandler | | 2 | OrderExecutedEvent | OrderExecutionFeedbackHandler | | 3 | MedicationDispensedEvent | AutoBillingHandler | | 4 | LabReportPublishedEvent | CriticalValueHandler | | 5 | DischargeEvent | DrgGroupingHandler | | 6 | NursingRecordSavedEvent | NursingQualityHandler | | 7 | StatisticsPushEvent | StatisticsPushHandler | | 8 | SurgeryCompletedEvent | PostSurgeryRecoveryHandler | | 9 | ExamReportPublishedEvent | ExamReportFeedbackHandler | | 10 | AdmissionAssessmentCompletedEvent | NursingPlanAutoGenerateHandler | - [ ] **Step 3: Commit** ```bash git add -A git commit -m "feat(dataflow): 数据流优化完成 - 10条链路+重试机制+链路联动" ``` --- ## 验证清单 | 验证项 | 命令 | 预期结果 | |--------|------|---------| | 后端编译 | `mvn clean compile -DskipTests` | BUILD SUCCESS | | Event类数量 | `ls *Event.java` | 10个 | | Handler类数量 | `ls *Handler.java` | 10个 | | 重试工具 | `EventRetryUtil.java` | 存在 | | 链路联动 | `OrderStopRequestEvent.java` | 存在 |