feat(health): appointment list API 内联 patient_name/doctor_name
列表查询后批量获取 patient 和 doctor 名称,消除前端 N+1 请求。 DTO 新增 patient_name/doctor_name Option 字段,向后兼容。
This commit is contained in:
@@ -38,6 +38,8 @@ pub struct AppointmentResp {
|
||||
pub id: Uuid,
|
||||
pub patient_id: Uuid,
|
||||
pub doctor_id: Option<Uuid>,
|
||||
pub patient_name: Option<String>,
|
||||
pub doctor_name: Option<String>,
|
||||
pub appointment_type: String,
|
||||
pub appointment_date: NaiveDate,
|
||||
pub start_time: NaiveTime,
|
||||
|
||||
@@ -14,6 +14,7 @@ use erp_core::types::PaginatedResponse;
|
||||
use crate::dto::appointment_dto::*;
|
||||
use crate::entity::{appointment, doctor_profile, doctor_schedule, patient};
|
||||
use crate::error::{HealthError, HealthResult};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use crate::service::validation::{
|
||||
validate_appointment_status_transition, validate_appointment_type,
|
||||
validate_period_type, validate_schedule_status,
|
||||
@@ -54,9 +55,41 @@ pub async fn list_appointments(
|
||||
.all(&state.db)
|
||||
.await?;
|
||||
|
||||
// 批量查询 patient_name 和 doctor_name
|
||||
let patient_ids: HashSet<Uuid> = models.iter().map(|m| m.patient_id).collect();
|
||||
let doctor_ids: HashSet<Uuid> = models.iter().filter_map(|m| m.doctor_id).collect();
|
||||
|
||||
let patient_names: HashMap<Uuid, String> = if !patient_ids.is_empty() {
|
||||
patient::Entity::find()
|
||||
.filter(patient::Column::Id.is_in(patient_ids))
|
||||
.filter(patient::Column::TenantId.eq(tenant_id))
|
||||
.all(&state.db)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|p| (p.id, p.name))
|
||||
.collect()
|
||||
} else {
|
||||
HashMap::new()
|
||||
};
|
||||
|
||||
let doctor_names: HashMap<Uuid, String> = if !doctor_ids.is_empty() {
|
||||
doctor_profile::Entity::find()
|
||||
.filter(doctor_profile::Column::Id.is_in(doctor_ids))
|
||||
.filter(doctor_profile::Column::TenantId.eq(tenant_id))
|
||||
.all(&state.db)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|d| (d.id, d.name))
|
||||
.collect()
|
||||
} else {
|
||||
HashMap::new()
|
||||
};
|
||||
|
||||
let total_pages = total.div_ceil(limit.max(1));
|
||||
let data = models.into_iter().map(|m| AppointmentResp {
|
||||
id: m.id, patient_id: m.patient_id, doctor_id: m.doctor_id,
|
||||
patient_name: patient_names.get(&m.patient_id).cloned(),
|
||||
doctor_name: m.doctor_id.and_then(|did| doctor_names.get(&did).cloned()),
|
||||
appointment_type: m.appointment_type, appointment_date: m.appointment_date,
|
||||
start_time: m.start_time, end_time: m.end_time,
|
||||
status: m.status, cancel_reason: m.cancel_reason, notes: m.notes,
|
||||
@@ -81,6 +114,7 @@ pub async fn get_appointment(
|
||||
|
||||
Ok(AppointmentResp {
|
||||
id: m.id, patient_id: m.patient_id, doctor_id: m.doctor_id,
|
||||
patient_name: None, doctor_name: None,
|
||||
appointment_type: m.appointment_type, appointment_date: m.appointment_date,
|
||||
start_time: m.start_time, end_time: m.end_time,
|
||||
status: m.status, cancel_reason: m.cancel_reason, notes: m.notes,
|
||||
@@ -189,6 +223,7 @@ pub async fn create_appointment(
|
||||
|
||||
Ok(AppointmentResp {
|
||||
id: m.id, patient_id: m.patient_id, doctor_id: m.doctor_id,
|
||||
patient_name: None, doctor_name: None,
|
||||
appointment_type: m.appointment_type, appointment_date: m.appointment_date,
|
||||
start_time: m.start_time, end_time: m.end_time,
|
||||
status: m.status, cancel_reason: m.cancel_reason, notes: m.notes,
|
||||
@@ -280,6 +315,7 @@ pub async fn update_appointment_status(
|
||||
|
||||
Ok(AppointmentResp {
|
||||
id: m.id, patient_id: m.patient_id, doctor_id: m.doctor_id,
|
||||
patient_name: None, doctor_name: None,
|
||||
appointment_type: m.appointment_type, appointment_date: m.appointment_date,
|
||||
start_time: m.start_time, end_time: m.end_time,
|
||||
status: m.status, cancel_reason: m.cancel_reason, notes: m.notes,
|
||||
|
||||
Reference in New Issue
Block a user