diff --git a/crates/erp-health/src/event.rs b/crates/erp-health/src/event.rs index ff69ff8..10cea41 100644 --- a/crates/erp-health/src/event.rs +++ b/crates/erp-health/src/event.rs @@ -825,4 +825,81 @@ pub fn register_handlers_with_state(state: crate::state::HealthState) { } } }); + + // lab_report.uploaded → 触发 AI 自动分析 + let (mut lab_upload_rx, _lab_upload_handle) = state.event_bus.subscribe_filtered("lab_report.".to_string()); + let lab_upload_db = state.db.clone(); + let lab_upload_bus = state.event_bus.clone(); + tokio::spawn(async move { + loop { + match lab_upload_rx.recv().await { + Some(event) if event.event_type == LAB_REPORT_UPLOADED => { + if erp_core::events::is_event_processed(&lab_upload_db, event.id, "lab_upload_ai_trigger").await.unwrap_or(false) { + continue; + } + let report_id = event.payload.get("report_id").and_then(|v| v.as_str()); + let patient_id = event.payload.get("patient_id").and_then(|v| v.as_str()); + if let (Some(rid), Some(pid)) = (report_id, patient_id) { + let ai_event = erp_core::events::DomainEvent::new( + "ai.analysis.requested", + event.tenant_id, + erp_core::events::build_event_payload(serde_json::json!({ + "source_type": "lab_report", + "source_id": rid, + "patient_id": pid, + })), + ); + lab_upload_bus.publish(ai_event, &lab_upload_db).await; + tracing::info!(report_id = rid, patient_id = pid, "化验单上传触发 AI 分析请求"); + } + let _ = erp_core::events::mark_event_processed(&lab_upload_db, event.id, "lab_upload_ai_trigger").await; + } + Some(event) if event.event_type == LAB_REPORT_REVIEWED => { + if erp_core::events::is_event_processed(&lab_upload_db, event.id, "lab_reviewed_notifier").await.unwrap_or(false) { + continue; + } + let patient_id = event.payload.get("patient_id").and_then(|v| v.as_str()); + let reviewer_id = event.payload.get("reviewer_id").and_then(|v| v.as_str()); + if let (Some(pid), Some(rid)) = (patient_id, reviewer_id) { + let notify = erp_core::events::DomainEvent::new( + "message.send", + event.tenant_id, + erp_core::events::build_event_payload(serde_json::json!({ + "channel": "in_app", + "recipient_type": "patient", + "recipient_id": pid, + "template_key": "LAB_REPORT_REVIEWED", + "params": { "reviewer_id": rid } + })), + ); + lab_upload_bus.publish(notify, &lab_upload_db).await; + tracing::info!(patient_id = pid, reviewer_id = rid, "化验报告审核通知已发送给患者"); + } + let _ = erp_core::events::mark_event_processed(&lab_upload_db, event.id, "lab_reviewed_notifier").await; + } + Some(_) => {} + None => break, + } + } + }); + + // patient.updated → 审计日志 + let (mut patient_update_rx, _patient_update_handle) = state.event_bus.subscribe_filtered("patient.".to_string()); + let patient_update_db = state.db.clone(); + tokio::spawn(async move { + loop { + match patient_update_rx.recv().await { + Some(event) if event.event_type == PATIENT_UPDATED => { + if erp_core::events::is_event_processed(&patient_update_db, event.id, "patient_updated_audit").await.unwrap_or(false) { + continue; + } + let patient_id = event.payload.get("patient_id").and_then(|v| v.as_str()); + tracing::info!(patient_id = ?patient_id, tenant_id = %event.tenant_id, "患者信息已更新"); + let _ = erp_core::events::mark_event_processed(&patient_update_db, event.id, "patient_updated_audit").await; + } + Some(_) => {} + None => break, + } + } + }); }