fix(health): 走查止血 — 患者名显示修复 + 枚举补全 + 医护统计 + 设备选择器
后端: - alert_service: list_alerts 批量查询 patient_name 填充 AlertResponse - consultation_service: list_sessions 批量查询 patient_name/doctor_name - erp-ai handler: list_analysis 通过 raw SQL 查询 patient_name 前端: - AlertList/AlertDashboard: 使用后端返回的 patient_name 替代 ID 截断 - ConsultationDetail: 使用 patient_name/doctor_name 替代 ID 截断 - AiAnalysisList: 使用 patient_name 替代 ID 截断 - constants/health: SEVERITY 补 high/medium, STATUS 补 active - AdminDashboard: 医护人数改为 API 查询(useStatsData 新增 doctorCount) - DeviceManage: 患者 ID 输入改为 PatientSelect 搜索选择器
This commit is contained in:
@@ -74,6 +74,7 @@ pub struct AcknowledgeAlertRequest {
|
||||
pub struct AlertResponse {
|
||||
pub id: Uuid,
|
||||
pub patient_id: Uuid,
|
||||
pub patient_name: Option<String>,
|
||||
pub rule_id: Uuid,
|
||||
pub severity: String,
|
||||
pub title: String,
|
||||
|
||||
@@ -6,8 +6,9 @@ use uuid::Uuid;
|
||||
|
||||
use erp_core::error::check_version;
|
||||
|
||||
use crate::dto::alert_dto::AlertResponse;
|
||||
use crate::entity::alerts;
|
||||
use crate::entity::patient_doctor_relation;
|
||||
use crate::entity::{patient, patient_doctor_relation};
|
||||
use crate::error::{HealthError, HealthResult};
|
||||
use crate::service::validation;
|
||||
use crate::state::HealthState;
|
||||
@@ -20,7 +21,7 @@ pub async fn list_alerts(
|
||||
status: Option<&str>,
|
||||
page: u64,
|
||||
page_size: u64,
|
||||
) -> HealthResult<(Vec<alerts::Model>, u64)> {
|
||||
) -> HealthResult<(Vec<AlertResponse>, u64)> {
|
||||
let limit = page_size.min(100);
|
||||
let offset = page.saturating_sub(1) * limit;
|
||||
|
||||
@@ -32,7 +33,6 @@ pub async fn list_alerts(
|
||||
if let Some(did) = doctor_id {
|
||||
let patient_ids = get_patient_ids_for_doctor(&state.db, tenant_id, did).await?;
|
||||
if patient_ids.is_empty() {
|
||||
// 没有管床患者 → 直接返回空结果
|
||||
return Ok((vec![], 0));
|
||||
}
|
||||
query = query.filter(alerts::Column::PatientId.is_in(patient_ids));
|
||||
@@ -47,13 +47,44 @@ pub async fn list_alerts(
|
||||
}
|
||||
|
||||
let total = query.clone().count(&state.db).await?;
|
||||
let items = query
|
||||
let models = query
|
||||
.order_by_desc(alerts::Column::CreatedAt)
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
.all(&state.db)
|
||||
.await?;
|
||||
|
||||
// 批量查询 patient_name
|
||||
let patient_ids: std::collections::HashSet<Uuid> = models.iter().map(|m| m.patient_id).collect();
|
||||
let patient_names: std::collections::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 {
|
||||
std::collections::HashMap::new()
|
||||
};
|
||||
|
||||
let items = models.into_iter().map(|m| AlertResponse {
|
||||
id: m.id,
|
||||
patient_id: m.patient_id,
|
||||
patient_name: patient_names.get(&m.patient_id).cloned(),
|
||||
rule_id: m.rule_id,
|
||||
severity: m.severity,
|
||||
title: m.title,
|
||||
detail: m.detail,
|
||||
status: m.status,
|
||||
acknowledged_by: m.acknowledged_by,
|
||||
acknowledged_at: m.acknowledged_at,
|
||||
resolved_at: m.resolved_at,
|
||||
created_at: m.created_at,
|
||||
version: m.version,
|
||||
}).collect();
|
||||
|
||||
Ok((items, total))
|
||||
}
|
||||
|
||||
|
||||
@@ -142,8 +142,43 @@ pub async fn list_sessions(
|
||||
.all(&state.db)
|
||||
.await?;
|
||||
|
||||
// 批量查询 patient_name 和 doctor_name
|
||||
let patient_ids: std::collections::HashSet<Uuid> = models.iter().map(|m| m.patient_id).collect();
|
||||
let doctor_ids: std::collections::HashSet<Uuid> = models.iter().filter_map(|m| m.doctor_id).collect();
|
||||
|
||||
let patient_names: std::collections::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 {
|
||||
std::collections::HashMap::new()
|
||||
};
|
||||
|
||||
let doctor_names: std::collections::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 {
|
||||
std::collections::HashMap::new()
|
||||
};
|
||||
|
||||
let total_pages = total.div_ceil(limit.max(1));
|
||||
let data = models.into_iter().map(model_to_session_resp).collect();
|
||||
let data = models.into_iter().map(|m| {
|
||||
let mut resp = model_to_session_resp(m.clone());
|
||||
resp.patient_name = patient_names.get(&m.patient_id).cloned();
|
||||
resp.doctor_name = m.doctor_id.and_then(|did| doctor_names.get(&did).cloned());
|
||||
resp
|
||||
}).collect();
|
||||
|
||||
Ok(PaginatedResponse { data, total, page, page_size: limit, total_pages })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user