From e76f4feb4f6c1b6eeb88a289c3e63671889feefd Mon Sep 17 00:00:00 2001 From: iven Date: Tue, 28 Apr 2026 19:43:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(health):=20=E5=91=8A=E8=AD=A6=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E6=A8=A1=E6=9D=BF=E6=B6=88=E6=81=AF=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=20+=20alert.triggered=20=E4=BA=8B=E4=BB=B6=E6=B6=88=E8=B4=B9?= =?UTF-8?q?=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/services/wechat-templates.ts | 2 + crates/erp-health/src/event.rs | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/apps/miniprogram/src/services/wechat-templates.ts b/apps/miniprogram/src/services/wechat-templates.ts index c09336a..d3d963d 100644 --- a/apps/miniprogram/src/services/wechat-templates.ts +++ b/apps/miniprogram/src/services/wechat-templates.ts @@ -5,6 +5,8 @@ export const TEMPLATE_IDS = { APPOINTMENT_REMINDER: '', FOLLOWUP_REMINDER: '', REPORT_NOTIFICATION: '', + CRITICAL_HEALTH_ALERT: '', + HEALTH_DATA_ABNORMAL: '', } as const; /** 检查模板 ID 是否已配置,未配置时返回 false 并打印警告 */ diff --git a/crates/erp-health/src/event.rs b/crates/erp-health/src/event.rs index 168777a..2d6de1f 100644 --- a/crates/erp-health/src/event.rs +++ b/crates/erp-health/src/event.rs @@ -159,6 +159,46 @@ pub fn register_handlers_with_state(state: crate::state::HealthState) { // ── P1 事件消费者补全 ── + // alert.triggered → 告警消息通知 + let (mut alert_rx, _alert_handle) = state.event_bus.subscribe_filtered("alert.".to_string()); + let alert_db = state.db.clone(); + let alert_bus = state.event_bus.clone(); + tokio::spawn(async move { + loop { + match alert_rx.recv().await { + Some(event) if event.event_type == ALERT_TRIGGERED => { + if erp_core::events::is_event_processed(&alert_db, event.id, "alert_notifier").await.unwrap_or(false) { + continue; + } + let patient_id = event.payload.get("patient_id").and_then(|v| v.as_str()); + let severity = event.payload.get("severity").and_then(|v| v.as_str()).unwrap_or("warning"); + let rule_name = event.payload.get("rule_name").and_then(|v| v.as_str()).unwrap_or("健康告警"); + if let Some(pid) = patient_id { + let notify_event = 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": if severity == "critical" { "CRITICAL_HEALTH_ALERT" } else { "HEALTH_DATA_ABNORMAL" }, + "params": { + "rule_name": rule_name, + "severity": severity, + } + })), + ); + alert_bus.publish(notify_event, &alert_db).await; + tracing::info!(patient_id = %pid, severity = %severity, "告警通知已发送"); + } + let _ = erp_core::events::mark_event_processed(&alert_db, event.id, "alert_notifier").await; + } + Some(_) => {} + None => break, + } + } + }); + // patient.created → 欢迎消息通知 let (mut patient_rx, _patient_handle) = state.event_bus.subscribe_filtered("patient.".to_string()); let patient_db = state.db.clone();