feat(ai): Phase 2B 洞察→推送→反馈闭环 — 风险评分+通知+建议反馈
- 风险评分引擎 load_patient_data 实装(体征+化验异常)
- refresh_all_patients 高风险自动创建洞察+事件推送
- erp-message 订阅 copilot.insight.created 推送医护通知
- 每日 cron 增加洞察过期清理+建议过期清理
- POST /ai/suggestions/{id}/feedback 建议反馈端点
- SuggestionFeedbackService 反馈服务层
- 小程序健康页建议卡片增加采纳/忽略/咨询医生按钮
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use axum::Router;
|
||||
use axum::routing::{delete, get, put};
|
||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
|
||||
use sea_orm::{ColumnTrait, EntityTrait, FromQueryResult, QueryFilter};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Semaphore;
|
||||
use uuid::Uuid;
|
||||
@@ -1003,6 +1003,69 @@ async fn handle_workflow_event(
|
||||
"医生在线状态变更"
|
||||
);
|
||||
}
|
||||
// AI Copilot 洞察生成 → 通知主管医生
|
||||
"copilot.insight.created" => {
|
||||
let patient_id = event
|
||||
.payload
|
||||
.get("patient_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| uuid::Uuid::parse_str(s).ok());
|
||||
let severity = event
|
||||
.payload
|
||||
.get("severity")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("warning");
|
||||
let title = event
|
||||
.payload
|
||||
.get("title")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("AI 健康洞察");
|
||||
|
||||
if let Some(pid) = patient_id {
|
||||
// 查询患者的责任医生(通过 follow_up_task 的 assigned_to)
|
||||
#[derive(sea_orm::FromQueryResult)]
|
||||
struct DoctorRow {
|
||||
assigned_to: uuid::Uuid,
|
||||
}
|
||||
let doctor: Option<DoctorRow> = DoctorRow::find_by_statement(
|
||||
sea_orm::Statement::from_sql_and_values(
|
||||
sea_orm::DatabaseBackend::Postgres,
|
||||
"SELECT assigned_to FROM follow_up_task WHERE tenant_id = $1 AND patient_id = $2 AND assigned_to IS NOT NULL AND deleted_at IS NULL AND status IN ('pending', 'in_progress') ORDER BY created_at DESC LIMIT 1",
|
||||
[event.tenant_id.into(), pid.into()],
|
||||
),
|
||||
)
|
||||
.one(db)
|
||||
.await
|
||||
.unwrap_or(None);
|
||||
|
||||
if let Some(doc) = doctor {
|
||||
let priority = match severity {
|
||||
"critical" => "urgent",
|
||||
"warning" | "high" => "important",
|
||||
_ => "normal",
|
||||
};
|
||||
if should_skip_for_dnd(event.tenant_id, doc.assigned_to, priority, db).await {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = crate::service::message_service::MessageService::send_system(
|
||||
event.tenant_id,
|
||||
doc.assigned_to,
|
||||
format!("AI 健康洞察:{}", title),
|
||||
format!(
|
||||
"AI 系统检测到患者存在「{}」级别的健康风险,请及时关注。洞察内容:{}",
|
||||
severity, title
|
||||
),
|
||||
priority,
|
||||
Some("ai_insight".to_string()),
|
||||
Some(event.id),
|
||||
db,
|
||||
event_bus,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 关怀计划激活 — 温暖通知患者
|
||||
"care_plan.activated" => {
|
||||
let patient_id = event
|
||||
|
||||
Reference in New Issue
Block a user