feat(message+health): 补全 14 个事件消费者 + 修复 6 个事件 payload 缺失字段
事件消费者补全(erp-message/module.rs): - consultation.opened: 医生收到新咨询会话通知 - consultation.closed: 患者收到会话结束通知 - follow_up.created: 被分配人收到新随访任务通知 - follow_up.completed: 患者收到随访完成通知 - points.earned: 患者收到积分到账通知 - points.exchanged: 患者收到兑换成功通知 - points.expired: 患者收到积分过期提醒 - article.published/rejected: 作者收到审核结果通知 - ai.analysis.failed: 医生收到 AI 分析失败通知 - lab_report.uploaded/patient.updated/daily_monitoring/doctor: 审计日志记录 事件 payload 补充(erp-health services): - consultation.opened: 添加 doctor_id 字段 - follow_up.created: 添加 assigned_to + planned_date 字段 - points.earned: 添加 patient_id + reason 字段 - points.exchanged: 添加 product_name 字段 - article.rejected: 添加 author_id 字段
This commit is contained in:
@@ -235,7 +235,8 @@ pub async fn reject_article(
|
||||
|
||||
state.event_bus.publish(
|
||||
DomainEvent::new(crate::event::ARTICLE_REJECTED, tenant_id, erp_core::events::build_event_payload(serde_json::json!({
|
||||
"article_id": m.id, "title": m.title,
|
||||
"article_id": m.id.to_string(), "title": m.title,
|
||||
"author_id": m.created_by.map(|id| id.to_string()).unwrap_or_default(),
|
||||
}))),
|
||||
&state.db,
|
||||
).await;
|
||||
|
||||
@@ -77,7 +77,11 @@ pub async fn create_session(
|
||||
let event = DomainEvent::new(
|
||||
crate::event::CONSULTATION_OPENED,
|
||||
tenant_id,
|
||||
erp_core::events::build_event_payload(serde_json::json!({ "session_id": m.id, "patient_id": m.patient_id })),
|
||||
erp_core::events::build_event_payload(serde_json::json!({
|
||||
"session_id": m.id.to_string(),
|
||||
"patient_id": m.patient_id.to_string(),
|
||||
"doctor_id": m.doctor_id.map(|id| id.to_string()).unwrap_or_default(),
|
||||
})),
|
||||
);
|
||||
state.event_bus.publish(event, &state.db).await;
|
||||
|
||||
@@ -175,7 +179,10 @@ pub async fn close_session(
|
||||
let event = DomainEvent::new(
|
||||
crate::event::CONSULTATION_CLOSED,
|
||||
tenant_id,
|
||||
erp_core::events::build_event_payload(serde_json::json!({ "session_id": m.id, "patient_id": m.patient_id })),
|
||||
erp_core::events::build_event_payload(serde_json::json!({
|
||||
"session_id": m.id.to_string(),
|
||||
"patient_id": m.patient_id.to_string(),
|
||||
})),
|
||||
);
|
||||
state.event_bus.publish(event, &state.db).await;
|
||||
|
||||
|
||||
@@ -170,7 +170,12 @@ pub async fn create_task(
|
||||
let event = DomainEvent::new(
|
||||
crate::event::FOLLOW_UP_CREATED,
|
||||
tenant_id,
|
||||
erp_core::events::build_event_payload(serde_json::json!({ "task_id": m.id, "patient_id": m.patient_id })),
|
||||
erp_core::events::build_event_payload(serde_json::json!({
|
||||
"task_id": m.id.to_string(),
|
||||
"patient_id": m.patient_id.to_string(),
|
||||
"assigned_to": m.assigned_to.map(|id| id.to_string()).unwrap_or_default(),
|
||||
"planned_date": m.planned_date.to_string(),
|
||||
})),
|
||||
);
|
||||
state.event_bus.publish(event, &state.db).await;
|
||||
|
||||
|
||||
@@ -195,6 +195,7 @@ pub async fn earn_points(
|
||||
DomainEvent::new(crate::event::POINTS_EARNED, tenant_id, erp_core::events::build_event_payload(serde_json::json!({
|
||||
"transaction_id": inserted.id, "account_id": inserted.account_id,
|
||||
"amount": inserted.amount, "balance_after": inserted.balance_after,
|
||||
"patient_id": patient_id.to_string(), "reason": event_type,
|
||||
}))),
|
||||
&state.db,
|
||||
).await;
|
||||
@@ -980,6 +981,7 @@ pub async fn exchange_product(
|
||||
DomainEvent::new(crate::event::POINTS_EXCHANGED, tenant_id, erp_core::events::build_event_payload(serde_json::json!({
|
||||
"order_id": inserted_order.id, "patient_id": inserted_order.patient_id,
|
||||
"product_id": inserted_order.product_id, "points_cost": inserted_order.points_cost,
|
||||
"product_name": product.name,
|
||||
}))),
|
||||
&state.db,
|
||||
).await;
|
||||
|
||||
@@ -602,6 +602,350 @@ async fn handle_workflow_event(
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 咨询会话开启通知医生
|
||||
"consultation.opened" => {
|
||||
let doctor_id = event
|
||||
.payload
|
||||
.get("doctor_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
let patient_name = event
|
||||
.payload
|
||||
.get("patient_name")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("患者");
|
||||
let session_id = event
|
||||
.payload
|
||||
.get("session_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
if let Some(did) = doctor_id {
|
||||
if should_skip_for_dnd(event.tenant_id, did, "normal", db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
did,
|
||||
format!("新咨询会话 — {}", patient_name),
|
||||
format!("患者 {} 发起了咨询会话,请及时响应。", patient_name),
|
||||
"normal",
|
||||
Some("consultation".to_string()),
|
||||
uuid::Uuid::parse_str(session_id).ok(),
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 咨询会话关闭通知患者
|
||||
"consultation.closed" => {
|
||||
let patient_id = event
|
||||
.payload
|
||||
.get("patient_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
let session_id = event
|
||||
.payload
|
||||
.get("session_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
if let Some(pid) = patient_id {
|
||||
if should_skip_for_dnd(event.tenant_id, pid, "normal", db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
pid,
|
||||
"咨询会话已结束".to_string(),
|
||||
"您的咨询会话已由医生关闭,感谢使用。".to_string(),
|
||||
"normal",
|
||||
Some("consultation".to_string()),
|
||||
uuid::Uuid::parse_str(session_id).ok(),
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 随访任务创建通知被分配人
|
||||
"follow_up.created" => {
|
||||
let assigned_to = event
|
||||
.payload
|
||||
.get("assigned_to")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
let patient_name = event
|
||||
.payload
|
||||
.get("patient_name")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
let planned_date = event
|
||||
.payload
|
||||
.get("planned_date")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("未知日期");
|
||||
let task_id = event
|
||||
.payload
|
||||
.get("task_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
if let Some(assignee) = assigned_to {
|
||||
if should_skip_for_dnd(event.tenant_id, assignee, "normal", db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let patient_info = if patient_name.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!("(患者:{})", patient_name)
|
||||
};
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
assignee,
|
||||
format!("新随访任务{}", patient_info),
|
||||
format!("您被分配了一个随访任务{},计划日期:{}。", patient_info, planned_date),
|
||||
"normal",
|
||||
Some("follow_up".to_string()),
|
||||
uuid::Uuid::parse_str(task_id).ok(),
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 随访完成通知患者
|
||||
"follow_up.completed" => {
|
||||
let patient_id = event
|
||||
.payload
|
||||
.get("patient_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
|
||||
if let Some(pid) = patient_id {
|
||||
if should_skip_for_dnd(event.tenant_id, pid, "normal", db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
pid,
|
||||
"随访已完成".to_string(),
|
||||
"您的随访任务已完成,感谢配合。".to_string(),
|
||||
"normal",
|
||||
Some("follow_up".to_string()),
|
||||
None,
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 积分获得通知患者
|
||||
"points.earned" => {
|
||||
let patient_id = event
|
||||
.payload
|
||||
.get("patient_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
let points = event
|
||||
.payload
|
||||
.get("points")
|
||||
.and_then(|v| v.as_i64())
|
||||
.unwrap_or(0);
|
||||
let reason = event
|
||||
.payload
|
||||
.get("reason")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("系统奖励");
|
||||
|
||||
if let Some(pid) = patient_id {
|
||||
if should_skip_for_dnd(event.tenant_id, pid, "low", db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
pid,
|
||||
"积分到账".to_string(),
|
||||
format!("您获得了 {} 积分({})。", points, reason),
|
||||
"low",
|
||||
Some("points".to_string()),
|
||||
None,
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 积分兑换通知患者
|
||||
"points.exchanged" => {
|
||||
let patient_id = event
|
||||
.payload
|
||||
.get("patient_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
let product_name = event
|
||||
.payload
|
||||
.get("product_name")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("商品");
|
||||
|
||||
if let Some(pid) = patient_id {
|
||||
if should_skip_for_dnd(event.tenant_id, pid, "normal", db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
pid,
|
||||
"兑换成功".to_string(),
|
||||
format!("您已成功兑换「{}」,请留意后续通知。", product_name),
|
||||
"normal",
|
||||
Some("points".to_string()),
|
||||
None,
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 积分过期通知患者
|
||||
"points.expired" => {
|
||||
let patient_id = event
|
||||
.payload
|
||||
.get("patient_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
let points = event
|
||||
.payload
|
||||
.get("points")
|
||||
.and_then(|v| v.as_i64())
|
||||
.unwrap_or(0);
|
||||
|
||||
if let Some(pid) = patient_id {
|
||||
if should_skip_for_dnd(event.tenant_id, pid, "low", db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
pid,
|
||||
"积分过期提醒".to_string(),
|
||||
format!("您有 {} 积分已过期。", points),
|
||||
"low",
|
||||
Some("points".to_string()),
|
||||
None,
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 文章发布通知(暂记录日志,无直接用户推送)
|
||||
"article.published" => {
|
||||
tracing::info!(
|
||||
article_id = %event.payload.get("article_id").and_then(|v| v.as_str()).unwrap_or(""),
|
||||
"文章已发布"
|
||||
);
|
||||
}
|
||||
// 文章驳回通知作者
|
||||
"article.rejected" => {
|
||||
let author_id = event
|
||||
.payload
|
||||
.get("author_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
let title = event
|
||||
.payload
|
||||
.get("title")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("文章");
|
||||
|
||||
if let Some(aid) = author_id {
|
||||
if should_skip_for_dnd(event.tenant_id, aid, "normal", db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
aid,
|
||||
format!("文章未通过审核 — {}", title),
|
||||
format!("您的文章「{}」未通过审核,请修改后重新提交。", title),
|
||||
"normal",
|
||||
Some("article".to_string()),
|
||||
None,
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 患者信息更新通知(审计日志用途)
|
||||
"patient.updated" => {
|
||||
tracing::info!(
|
||||
patient_id = %event.payload.get("patient_id").and_then(|v| v.as_str()).unwrap_or(""),
|
||||
"患者信息已更新"
|
||||
);
|
||||
}
|
||||
// AI 分析失败通知医生
|
||||
"ai.analysis.failed" => {
|
||||
let doctor_id = event
|
||||
.payload
|
||||
.get("doctor_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
let error = event
|
||||
.payload
|
||||
.get("error")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("未知错误");
|
||||
|
||||
if let Some(did) = doctor_id {
|
||||
if should_skip_for_dnd(event.tenant_id, did, "normal", db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
did,
|
||||
"AI 分析失败".to_string(),
|
||||
format!("AI 分析任务执行失败:{},请稍后重试。", error),
|
||||
"normal",
|
||||
Some("ai".to_string()),
|
||||
None,
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
// 化验单上传记录日志
|
||||
"lab_report.uploaded" => {
|
||||
tracing::info!(
|
||||
patient_id = %event.payload.get("patient_id").and_then(|v| v.as_str()).unwrap_or(""),
|
||||
"化验单已上传"
|
||||
);
|
||||
}
|
||||
// 日常监测记录日志
|
||||
"daily_monitoring.created" => {
|
||||
tracing::info!(
|
||||
patient_id = %event.payload.get("patient_id").and_then(|v| v.as_str()).unwrap_or(""),
|
||||
"日常监测数据已记录"
|
||||
);
|
||||
}
|
||||
// 医生在线状态变更记录日志
|
||||
"doctor.online_status_changed" => {
|
||||
tracing::info!(
|
||||
doctor_id = %event.payload.get("doctor_id").and_then(|v| v.as_str()).unwrap_or(""),
|
||||
status = %event.payload.get("status").and_then(|v| v.as_str()).unwrap_or(""),
|
||||
"医生在线状态变更"
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user