feat(health): 告警微信模板消息通知 + alert.triggered 事件消费者
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

This commit is contained in:
iven
2026-04-28 19:43:57 +08:00
parent 601b2d7f52
commit e76f4feb4f
2 changed files with 42 additions and 0 deletions

View File

@@ -5,6 +5,8 @@ export const TEMPLATE_IDS = {
APPOINTMENT_REMINDER: '',
FOLLOWUP_REMINDER: '',
REPORT_NOTIFICATION: '',
CRITICAL_HEALTH_ALERT: '',
HEALTH_DATA_ABNORMAL: '',
} as const;
/** 检查模板 ID 是否已配置,未配置时返回 false 并打印警告 */

View File

@@ -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();