将单体 event.rs 按业务域拆分为 event/ 模块目录: - mod.rs (219 行): 31 事件常量 + 调度器 + 测试 - 12 个消费者文件: workflow/device/alert/patient/appointment/ follow_up/health_data/ai/consent/consultation/points/lab_report 每个消费者文件 50-215 行,独立可维护。 编译零错误,测试全部通过。
136 lines
5.9 KiB
Rust
136 lines
5.9 KiB
Rust
/// consultation.opened/new_message/closed → 通知相关方
|
|
pub fn spawn(state: &crate::state::HealthState) -> Vec<erp_core::events::SubscriptionHandle> {
|
|
let mut handles = Vec::new();
|
|
|
|
let (mut consult_rx, consult_handle) = state
|
|
.event_bus
|
|
.subscribe_filtered("consultation.".to_string());
|
|
handles.push(consult_handle);
|
|
let consult_db = state.db.clone();
|
|
let consult_bus = state.event_bus.clone();
|
|
tokio::spawn(async move {
|
|
loop {
|
|
match consult_rx.recv().await {
|
|
Some(event) if event.event_type == super::CONSULTATION_OPENED => {
|
|
if erp_core::events::is_event_processed(
|
|
&consult_db,
|
|
event.id,
|
|
"consult_opened_notifier",
|
|
)
|
|
.await
|
|
.unwrap_or(false)
|
|
{
|
|
continue;
|
|
}
|
|
let doctor_id = event.payload.get("doctor_id").and_then(|v| v.as_str());
|
|
let patient_id = event.payload.get("patient_id").and_then(|v| v.as_str());
|
|
if let (Some(did), Some(pid)) = (doctor_id, patient_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": "doctor",
|
|
"recipient_id": did,
|
|
"template_key": "CONSULTATION_OPENED",
|
|
"params": { "patient_id": pid }
|
|
})),
|
|
);
|
|
consult_bus.publish(notify, &consult_db).await;
|
|
tracing::info!(
|
|
doctor_id = did,
|
|
patient_id = pid,
|
|
"咨询开启通知已发送给医生"
|
|
);
|
|
}
|
|
let _ = erp_core::events::mark_event_processed(
|
|
&consult_db,
|
|
event.id,
|
|
"consult_opened_notifier",
|
|
)
|
|
.await;
|
|
}
|
|
Some(event) if event.event_type == super::CONSULTATION_NEW_MESSAGE => {
|
|
if erp_core::events::is_event_processed(
|
|
&consult_db,
|
|
event.id,
|
|
"consult_msg_notifier",
|
|
)
|
|
.await
|
|
.unwrap_or(false)
|
|
{
|
|
continue;
|
|
}
|
|
let recipient_id = event.payload.get("recipient_id").and_then(|v| v.as_str());
|
|
let sender_role = event
|
|
.payload
|
|
.get("sender_role")
|
|
.and_then(|v| v.as_str())
|
|
.unwrap_or("unknown");
|
|
if let Some(rid) = recipient_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": if sender_role == "patient" { "doctor" } else { "patient" },
|
|
"recipient_id": rid,
|
|
"template_key": "CONSULTATION_NEW_MESSAGE",
|
|
})),
|
|
);
|
|
consult_bus.publish(notify, &consult_db).await;
|
|
tracing::info!(
|
|
recipient_id = rid,
|
|
sender_role = sender_role,
|
|
"咨询新消息通知已发送"
|
|
);
|
|
}
|
|
let _ = erp_core::events::mark_event_processed(
|
|
&consult_db,
|
|
event.id,
|
|
"consult_msg_notifier",
|
|
)
|
|
.await;
|
|
}
|
|
Some(event) if event.event_type == super::CONSULTATION_CLOSED => {
|
|
if erp_core::events::is_event_processed(
|
|
&consult_db,
|
|
event.id,
|
|
"consult_closed_notifier",
|
|
)
|
|
.await
|
|
.unwrap_or(false)
|
|
{
|
|
continue;
|
|
}
|
|
let patient_id = event.payload.get("patient_id").and_then(|v| v.as_str());
|
|
if let Some(pid) = patient_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": "CONSULTATION_CLOSED",
|
|
})),
|
|
);
|
|
consult_bus.publish(notify, &consult_db).await;
|
|
tracing::info!(patient_id = pid, "咨询关闭通知已发送");
|
|
}
|
|
let _ = erp_core::events::mark_event_processed(
|
|
&consult_db,
|
|
event.id,
|
|
"consult_closed_notifier",
|
|
)
|
|
.await;
|
|
}
|
|
Some(_) => {}
|
|
None => break,
|
|
}
|
|
}
|
|
});
|
|
|
|
handles
|
|
}
|