feat(ai): Phase 2A-4 新增 3 个 Agent Tool — 化验报告/预约/用药查询
新增 3 个 AI Agent Tool 扩展医护沙箱能力: - query_patient_lab_reports: 查询患者化验报告列表(含异常计数) - query_patient_appointments: 查询患者即将到来的预约 - query_patient_medications: 查询患者当前用药列表 同时: - HealthDataProvider trait 新增 get_patient_lab_reports 方法 + LabReportListItemDto - erp-health 实现新 trait 方法(含 PII 解密) - sandbox.rs 更新角色权限:Patient 可查体征/化验/用药,MedicalStaff 额外可查预约 - 修复 ai_prompt_tests.rs 中 AnalysisService::new 签名变更的遗留编译错误 - 新增 5 个 agent 测试覆盖新 Tool 和沙箱权限过滤
This commit is contained in:
@@ -4,8 +4,9 @@ use erp_core::crypto::{self as pii, PiiCrypto};
|
||||
use erp_core::error::{AppError, AppResult};
|
||||
use erp_core::health_provider::{
|
||||
AnomalyInfo, AppointmentSummaryDto, HealthDataProvider, HealthReportDto, LabItemDto,
|
||||
LabReportDto, MedicationSummaryDto, MetricTrendAnalysis, PatientSummaryDto, RegressionStats,
|
||||
ReportSectionDto, TimeRange, TrendAnalysisDto, TrendDirection, VitalSignDto,
|
||||
LabReportDto, LabReportListItemDto, MedicationSummaryDto, MetricTrendAnalysis,
|
||||
PatientSummaryDto, RegressionStats, ReportSectionDto, TimeRange, TrendAnalysisDto,
|
||||
TrendDirection, VitalSignDto,
|
||||
};
|
||||
use num_traits::ToPrimitive;
|
||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect};
|
||||
@@ -623,4 +624,48 @@ impl HealthDataProvider for HealthDataProviderImpl {
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn get_patient_lab_reports(
|
||||
&self,
|
||||
tenant_id: Uuid,
|
||||
patient_id: Uuid,
|
||||
limit: u64,
|
||||
) -> AppResult<Vec<LabReportListItemDto>> {
|
||||
let _ = find_patient(&self.db, tenant_id, patient_id).await?;
|
||||
|
||||
let records = lab_report::Entity::find()
|
||||
.filter(lab_report::Column::TenantId.eq(tenant_id))
|
||||
.filter(lab_report::Column::PatientId.eq(patient_id))
|
||||
.filter(lab_report::Column::DeletedAt.is_null())
|
||||
.order_by_desc(lab_report::Column::ReportDate)
|
||||
.limit(limit)
|
||||
.all(&self.db)
|
||||
.await?;
|
||||
|
||||
let result = records
|
||||
.into_iter()
|
||||
.map(|r| {
|
||||
let kek = self.crypto.kek();
|
||||
let decrypted_items = r
|
||||
.items
|
||||
.as_ref()
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|s| pii::decrypt(kek, s).ok())
|
||||
.and_then(|s| serde_json::from_str(&s).ok())
|
||||
.or(r.items.clone());
|
||||
let abnormal_count = parse_lab_items(&decrypted_items)
|
||||
.iter()
|
||||
.filter(|i| i.is_abnormal)
|
||||
.count();
|
||||
LabReportListItemDto {
|
||||
id: r.id,
|
||||
report_type: r.report_type,
|
||||
report_date: r.report_date.to_string(),
|
||||
abnormal_count,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user