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:
@@ -193,6 +193,69 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, utoipa::ToSchema)]
|
||||
pub struct SubmitFeedbackBody {
|
||||
pub action: String, // "adopt" | "ignore" | "consult"
|
||||
pub feedback_text: Option<String>,
|
||||
}
|
||||
|
||||
/// 患者端提交建议反馈(采纳/忽略/咨询医生)
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/ai/suggestions/{id}/feedback",
|
||||
responses((status = 200, description = "提交建议反馈")),
|
||||
tag = "AI 建议",
|
||||
security(("bearer_auth" = [])),
|
||||
)]
|
||||
pub async fn submit_feedback<S>(
|
||||
State(state): State<AiState>,
|
||||
Extension(ctx): Extension<TenantContext>,
|
||||
Path(id): Path<uuid::Uuid>,
|
||||
Json(body): Json<SubmitFeedbackBody>,
|
||||
) -> Result<Json<ApiResponse<serde_json::Value>>, erp_core::error::AppError>
|
||||
where
|
||||
AiState: FromRef<S>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
require_permission(&ctx, "ai.suggestion.manage")?;
|
||||
|
||||
if !matches!(body.action.as_str(), "adopt" | "ignore" | "consult") {
|
||||
return Err(erp_core::error::AppError::Validation(
|
||||
"action 必须为 adopt、ignore 或 consult".into(),
|
||||
));
|
||||
}
|
||||
|
||||
let feedback_id =
|
||||
crate::service::suggestion_feedback::SuggestionFeedbackService::submit_feedback(
|
||||
&state.db,
|
||||
ctx.tenant_id,
|
||||
id,
|
||||
ctx.user_id,
|
||||
body.action.clone(),
|
||||
body.feedback_text.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 发布反馈事件
|
||||
let event = erp_core::events::DomainEvent::new(
|
||||
"ai.suggestion.feedback",
|
||||
ctx.tenant_id,
|
||||
erp_core::events::build_event_payload(serde_json::json!({
|
||||
"suggestion_id": id,
|
||||
"action": body.action,
|
||||
"feedback_text": body.feedback_text,
|
||||
"user_id": ctx.user_id,
|
||||
})),
|
||||
);
|
||||
state.event_bus.publish(event, &state.db).await;
|
||||
|
||||
Ok(Json(ApiResponse::ok(serde_json::json!({
|
||||
"id": feedback_id,
|
||||
"suggestion_id": id,
|
||||
"action": body.action,
|
||||
}))))
|
||||
}
|
||||
|
||||
/// 发布建议状态变更事件
|
||||
async fn publish_status_event(state: &AiState, suggestion: &crate::entity::ai_suggestion::Model) {
|
||||
let event = erp_core::events::DomainEvent::new(
|
||||
|
||||
Reference in New Issue
Block a user