Files
hms/crates/erp-core/src/health_provider.rs
iven 2660f1afff feat(ai): Phase 2A-3 随访页 AI 辅助生成小结 — SSE 端点 + 前端集成
- AnalysisType 新增 FollowUpSummary 变体(as_str/prompt_name)
- HealthDataProvider 新增 get_follow_up_summary_data() + FollowUpSummaryDataDto
- erp-health 实现随访数据查询(task + records + PII 解密)
- 新增 /ai/analyze/follow-up-summary SSE 端点
- SanitizationService 新增 sanitize_follow_up_data()
- 前端 analysisSse.ts/AiAnalysisCard 支持 follow-up-summary 类型
- FollowUpTaskList 操作列新增「AI 小结」按钮
2026-05-19 00:54:15 +08:00

229 lines
5.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::error::AppResult;
/// 健康数据提供者 trait由 erp-health 实现
/// 返回的 DTO 已脱去 PII姓名、身份证号等只包含年龄/性别/医疗数据
#[async_trait]
pub trait HealthDataProvider: Send + Sync {
/// 获取化验报告(指标列表)
async fn get_lab_report(&self, tenant_id: Uuid, report_id: Uuid) -> AppResult<LabReportDto>;
/// 获取生命体征趋势数据
async fn get_vital_signs(
&self,
tenant_id: Uuid,
patient_id: Uuid,
metrics: &[String],
range: &TimeRange,
) -> AppResult<Vec<VitalSignDto>>;
/// 获取患者摘要(用于个性化方案)
async fn get_patient_summary(
&self,
tenant_id: Uuid,
patient_id: Uuid,
) -> AppResult<PatientSummaryDto>;
/// 获取完整健康报告(用于摘要生成)
async fn get_full_report(&self, tenant_id: Uuid, report_id: Uuid)
-> AppResult<HealthReportDto>;
/// 获取趋势分析预计算数据(统计摘要 + 异常检测)
async fn get_trend_analysis_data(
&self,
tenant_id: Uuid,
patient_id: Uuid,
metrics: &[String],
range: &TimeRange,
) -> AppResult<TrendAnalysisDto>;
/// 获取患者即将到来的预约
async fn get_upcoming_appointments(
&self,
tenant_id: Uuid,
patient_id: Uuid,
) -> AppResult<Vec<AppointmentSummaryDto>>;
/// 获取患者当前用药列表
async fn get_medication_list(
&self,
tenant_id: Uuid,
patient_id: Uuid,
) -> AppResult<Vec<MedicationSummaryDto>>;
/// 获取患者化验报告列表(简要摘要,不含指标明细)
async fn get_patient_lab_reports(
&self,
tenant_id: Uuid,
patient_id: Uuid,
limit: u64,
) -> AppResult<Vec<LabReportListItemDto>>;
/// 获取随访摘要数据(任务 + 已有记录,用于 AI 生成小结)
async fn get_follow_up_summary_data(
&self,
tenant_id: Uuid,
task_id: Uuid,
) -> AppResult<FollowUpSummaryDataDto>;
}
// === DTO 定义 ===
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeRange {
pub start: chrono::DateTime<chrono::Utc>,
pub end: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabReportDto {
pub age_group: String,
pub sex: String,
pub department: String,
pub report_date: String,
pub items: Vec<LabItemDto>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabItemDto {
pub name: String,
pub value: f64,
pub unit: String,
pub reference_range: String,
pub is_abnormal: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VitalSignDto {
pub metric: String,
pub values: Vec<(String, f64)>,
pub unit: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PatientSummaryDto {
pub age_group: String,
pub sex: String,
pub chronic_conditions: Vec<String>,
pub medications: Vec<String>,
pub family_history: Vec<String>,
pub last_checkup_date: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthReportDto {
pub age_group: String,
pub sex: String,
pub department: String,
pub report_date: String,
pub sections: Vec<ReportSectionDto>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportSectionDto {
pub title: String,
pub findings: Vec<String>,
pub abnormal_items: Vec<String>,
}
// === 趋势分析 DTO ===
/// 趋势方向
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TrendDirection {
Rising,
Falling,
Stable,
}
/// 趋势分析整体 DTO
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrendAnalysisDto {
pub patient_id: Uuid,
pub period_start: String,
pub period_end: String,
pub metrics: Vec<MetricTrendAnalysis>,
}
/// 单个指标的趋势分析结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricTrendAnalysis {
pub metric: String,
pub unit: String,
pub data_point_count: usize,
/// 线性回归统计(数据不足时为 None
pub regression: Option<RegressionStats>,
/// 检测到的异常点
pub anomalies: Vec<AnomalyInfo>,
}
/// 线性回归统计摘要
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegressionStats {
pub slope: f64,
pub intercept: f64,
pub r_squared: f64,
pub direction: TrendDirection,
pub daily_change: f64,
pub period_change: f64,
}
/// 异常点信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnomalyInfo {
pub date: String,
pub value: f64,
pub mean: f64,
pub std_dev: f64,
pub deviation: f64,
}
// === Agent 新增 DTO ===
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppointmentSummaryDto {
pub id: Uuid,
pub department: String,
pub doctor_name: String,
pub scheduled_at: String,
pub status: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MedicationSummaryDto {
pub name: String,
pub dosage: String,
pub frequency: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabReportListItemDto {
pub id: Uuid,
pub report_type: String,
pub report_date: String,
pub abnormal_count: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FollowUpSummaryDataDto {
pub task_id: Uuid,
pub patient_id: Uuid,
pub follow_up_type: String,
pub planned_date: String,
pub task_status: String,
pub records: Vec<FollowUpRecordDto>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FollowUpRecordDto {
pub executed_date: String,
pub result: String,
pub patient_condition: Option<String>,
pub medical_advice: Option<String>,
pub next_follow_up_date: Option<String>,
}