feat(health+ai): P2 咨询联动 + AI 巡检消费 — 全链路打通
业务链路打通 5/5 断点全部完成: - 咨询→随访:医生端新增"创建随访"按钮,从咨询会话直接创建随访任务 - 咨询→AI:医生端新增"AI 分析"按钮,对咨询上下文触发 AI 分析 - 告警→咨询:小程序告警详情页新增"在线咨询"快捷入口 - AI 巡检消费:erp-ai 新增 patrol_consumer,订阅 ai.patrol.requested 事件 - 前端联动:Web ConsultationDetail + 小程序 alerts 页面联动实现 后端:2 新 API + 2 handler + 1 service + AI event consumer 前端:Web 2 API + 1 页面改造 + 小程序 2 页面改造 测试:Web consultations.test.ts 9/9 通过
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
|
||||
|
||||
/// alert.triggered → 告警消息通知 + 告警聚合
|
||||
pub fn spawn(state: &crate::state::HealthState) -> Vec<erp_core::events::SubscriptionHandle> {
|
||||
let mut handles = Vec::new();
|
||||
@@ -28,7 +30,54 @@ pub fn spawn(state: &crate::state::HealthState) -> Vec<erp_core::events::Subscri
|
||||
.get("rule_name")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("健康告警");
|
||||
|
||||
if let Some(pid) = patient_id {
|
||||
// 检查患者是否有活跃咨询会话(active / waiting)
|
||||
let patient_uuid = uuid::Uuid::parse_str(pid).ok();
|
||||
let active_session = if let Some(puid) = patient_uuid {
|
||||
crate::entity::consultation_session::Entity::find()
|
||||
.filter(
|
||||
crate::entity::consultation_session::Column::PatientId.eq(puid),
|
||||
)
|
||||
.filter(
|
||||
crate::entity::consultation_session::Column::TenantId
|
||||
.eq(event.tenant_id),
|
||||
)
|
||||
.filter(
|
||||
crate::entity::consultation_session::Column::DeletedAt
|
||||
.is_null(),
|
||||
)
|
||||
.filter(
|
||||
sea_orm::Condition::any()
|
||||
.add(
|
||||
crate::entity::consultation_session::Column::Status
|
||||
.eq("active"),
|
||||
)
|
||||
.add(
|
||||
crate::entity::consultation_session::Column::Status
|
||||
.eq("waiting"),
|
||||
),
|
||||
)
|
||||
.one(&alert_db)
|
||||
.await
|
||||
.ok()
|
||||
.flatten()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let consultation_session_id =
|
||||
active_session.as_ref().map(|s| s.id.to_string());
|
||||
|
||||
let mut params = serde_json::json!({
|
||||
"rule_name": rule_name,
|
||||
"severity": severity,
|
||||
"suggested_action": "consult",
|
||||
});
|
||||
if let Some(ref sid) = consultation_session_id {
|
||||
params["consultation_session_id"] = serde_json::json!(sid);
|
||||
}
|
||||
|
||||
let notify_event = erp_core::events::DomainEvent::new(
|
||||
"message.send",
|
||||
event.tenant_id,
|
||||
@@ -37,14 +86,16 @@ pub fn spawn(state: &crate::state::HealthState) -> Vec<erp_core::events::Subscri
|
||||
"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,
|
||||
}
|
||||
"params": params,
|
||||
})),
|
||||
);
|
||||
alert_bus.publish(notify_event, &alert_db).await;
|
||||
tracing::info!(patient_id = %pid, severity = %severity, "告警通知已发送");
|
||||
tracing::info!(
|
||||
patient_id = %pid,
|
||||
severity = %severity,
|
||||
consultation_session_id = ?consultation_session_id,
|
||||
"告警通知已发送(含咨询联动建议)"
|
||||
);
|
||||
}
|
||||
let _ = erp_core::events::mark_event_processed(
|
||||
&alert_db,
|
||||
|
||||
Reference in New Issue
Block a user