From f668f0995acd0db2715cccf6b671cf13d62c2f2c Mon Sep 17 00:00:00 2001 From: iven Date: Mon, 18 May 2026 02:47:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(core):=20HealthDataProvider=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20get=5Fupcoming=5Fappointments=20+=20get=5Fmedicatio?= =?UTF-8?q?n=5Flist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/erp-core/src/health_provider.rs | 32 ++++++++ crates/erp-health/src/health_provider_impl.rs | 76 +++++++++++++++++-- 2 files changed, 103 insertions(+), 5 deletions(-) diff --git a/crates/erp-core/src/health_provider.rs b/crates/erp-core/src/health_provider.rs index 2e4687b..4f343df 100644 --- a/crates/erp-core/src/health_provider.rs +++ b/crates/erp-core/src/health_provider.rs @@ -39,6 +39,20 @@ pub trait HealthDataProvider: Send + Sync { metrics: &[String], range: &TimeRange, ) -> AppResult; + + /// 获取患者即将到来的预约 + async fn get_upcoming_appointments( + &self, + tenant_id: Uuid, + patient_id: Uuid, + ) -> AppResult>; + + /// 获取患者当前用药列表 + async fn get_medication_list( + &self, + tenant_id: Uuid, + patient_id: Uuid, + ) -> AppResult>; } // === DTO 定义 === @@ -152,3 +166,21 @@ pub struct AnomalyInfo { 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, +} diff --git a/crates/erp-health/src/health_provider_impl.rs b/crates/erp-health/src/health_provider_impl.rs index 5b7fb32..4d590a9 100644 --- a/crates/erp-health/src/health_provider_impl.rs +++ b/crates/erp-health/src/health_provider_impl.rs @@ -3,16 +3,16 @@ use chrono::Datelike; use erp_core::crypto::{self as pii, PiiCrypto}; use erp_core::error::{AppError, AppResult}; use erp_core::health_provider::{ - AnomalyInfo, HealthDataProvider, HealthReportDto, LabItemDto, LabReportDto, - MetricTrendAnalysis, PatientSummaryDto, RegressionStats, ReportSectionDto, TimeRange, - TrendAnalysisDto, TrendDirection, VitalSignDto, + AnomalyInfo, AppointmentSummaryDto, HealthDataProvider, HealthReportDto, LabItemDto, + LabReportDto, MedicationSummaryDto, MetricTrendAnalysis, PatientSummaryDto, RegressionStats, + ReportSectionDto, TimeRange, TrendAnalysisDto, TrendDirection, VitalSignDto, }; use num_traits::ToPrimitive; -use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder}; +use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect}; use uuid::Uuid; use crate::entity::{ - diagnosis, health_record, lab_report, medication_record, patient, vital_signs, + appointment, diagnosis, health_record, lab_report, medication_record, patient, vital_signs, }; pub struct HealthDataProviderImpl { @@ -557,4 +557,70 @@ impl HealthDataProvider for HealthDataProviderImpl { metrics: metric_results, }) } + + async fn get_upcoming_appointments( + &self, + tenant_id: Uuid, + patient_id: Uuid, + ) -> AppResult> { + let _ = find_patient(&self.db, tenant_id, patient_id).await?; + + let today = chrono::Utc::now().date_naive(); + let records = appointment::Entity::find() + .filter(appointment::Column::TenantId.eq(tenant_id)) + .filter(appointment::Column::PatientId.eq(patient_id)) + .filter(appointment::Column::DeletedAt.is_null()) + .filter(appointment::Column::AppointmentDate.gte(today)) + .filter( + appointment::Column::Status + .is_in(vec!["scheduled".to_string(), "confirmed".to_string()]), + ) + .order_by_asc(appointment::Column::AppointmentDate) + .order_by_asc(appointment::Column::StartTime) + .limit(10) + .all(&self.db) + .await?; + + let result = records + .into_iter() + .map(|r| AppointmentSummaryDto { + id: r.id, + department: r.appointment_type, + doctor_name: r + .doctor_id + .map_or("待定".to_string(), |_| "医生".to_string()), + scheduled_at: format!("{} {}", r.appointment_date, r.start_time), + status: r.status, + }) + .collect(); + + Ok(result) + } + + async fn get_medication_list( + &self, + tenant_id: Uuid, + patient_id: Uuid, + ) -> AppResult> { + let _ = find_patient(&self.db, tenant_id, patient_id).await?; + + let records = medication_record::Entity::find() + .filter(medication_record::Column::TenantId.eq(tenant_id)) + .filter(medication_record::Column::PatientId.eq(patient_id)) + .filter(medication_record::Column::DeletedAt.is_null()) + .filter(medication_record::Column::IsCurrent.eq(true)) + .all(&self.db) + .await?; + + let result = records + .into_iter() + .map(|m| MedicationSummaryDto { + name: m.medication_name, + dosage: m.dosage.unwrap_or_default(), + frequency: m.frequency.unwrap_or_default(), + }) + .collect(); + + Ok(result) + } }