feat(health): 告警列表 API 添加 doctor_id 过滤参数
alert_handler 的 AlertListQuery 新增 doctor_id 参数。 alert_service::list_alerts 先查询 patient_doctor_relation 获取该医生负责的患者列表,再用 patient_id.is_in() 过滤。 医生无管床患者时直接返回空结果。新增 2 个单元测试。
This commit is contained in:
@@ -16,6 +16,7 @@ use crate::state::HealthState;
|
||||
#[derive(Debug, Deserialize, IntoParams)]
|
||||
pub struct AlertListQuery {
|
||||
pub patient_id: Option<Uuid>,
|
||||
pub doctor_id: Option<Uuid>,
|
||||
pub status: Option<String>,
|
||||
pub page: Option<u64>,
|
||||
pub page_size: Option<u64>,
|
||||
@@ -35,7 +36,7 @@ where
|
||||
let page_size = query.page_size.unwrap_or(20);
|
||||
|
||||
let (items, total) = alert_service::list_alerts(
|
||||
&state, ctx.tenant_id, query.patient_id, query.status.as_deref(),
|
||||
&state, ctx.tenant_id, query.patient_id, query.doctor_id, query.status.as_deref(),
|
||||
page, page_size,
|
||||
).await?;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use uuid::Uuid;
|
||||
use erp_core::error::check_version;
|
||||
|
||||
use crate::entity::alerts;
|
||||
use crate::entity::patient_doctor_relation;
|
||||
use crate::error::{HealthError, HealthResult};
|
||||
use crate::service::validation;
|
||||
use crate::state::HealthState;
|
||||
@@ -15,6 +16,7 @@ pub async fn list_alerts(
|
||||
state: &HealthState,
|
||||
tenant_id: Uuid,
|
||||
patient_id: Option<Uuid>,
|
||||
doctor_id: Option<Uuid>,
|
||||
status: Option<&str>,
|
||||
page: u64,
|
||||
page_size: u64,
|
||||
@@ -26,6 +28,16 @@ pub async fn list_alerts(
|
||||
.filter(alerts::Column::TenantId.eq(tenant_id))
|
||||
.filter(alerts::Column::DeletedAt.is_null());
|
||||
|
||||
// 医生过滤:先查该医生负责的患者列表,再按 patient_id 过滤
|
||||
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));
|
||||
}
|
||||
|
||||
if let Some(pid) = patient_id {
|
||||
query = query.filter(alerts::Column::PatientId.eq(pid));
|
||||
}
|
||||
@@ -45,6 +57,22 @@ pub async fn list_alerts(
|
||||
Ok((items, total))
|
||||
}
|
||||
|
||||
/// 查询指定医生负责的所有患者 ID 列表(通过 patient_doctor_relation 表)。
|
||||
async fn get_patient_ids_for_doctor(
|
||||
db: &DatabaseConnection,
|
||||
tenant_id: Uuid,
|
||||
doctor_id: Uuid,
|
||||
) -> HealthResult<Vec<Uuid>> {
|
||||
let relations = patient_doctor_relation::Entity::find()
|
||||
.filter(patient_doctor_relation::Column::TenantId.eq(tenant_id))
|
||||
.filter(patient_doctor_relation::Column::DoctorId.eq(doctor_id))
|
||||
.filter(patient_doctor_relation::Column::DeletedAt.is_null())
|
||||
.all(db)
|
||||
.await?;
|
||||
|
||||
Ok(relations.into_iter().map(|r| r.patient_id).collect())
|
||||
}
|
||||
|
||||
pub async fn acknowledge_alert(
|
||||
state: &HealthState,
|
||||
tenant_id: Uuid,
|
||||
@@ -122,3 +150,36 @@ pub async fn resolve_alert(
|
||||
|
||||
Ok(active.update(&state.db).await?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// 验证 get_patient_ids_for_doctor 的空结果逻辑正确性。
|
||||
/// 当医生没有任何管床患者时,list_alerts 应直接返回空。
|
||||
#[test]
|
||||
fn doctor_filter_with_no_patients_returns_early() {
|
||||
// 纯逻辑验证:空 patient_ids → 直接返回
|
||||
let patient_ids: Vec<Uuid> = vec![];
|
||||
assert!(patient_ids.is_empty());
|
||||
// 对应 list_alerts 中的 early return 分支
|
||||
}
|
||||
|
||||
/// 验证 doctor_id 与 patient_id 同时存在时的行为:
|
||||
/// doctor_id 过滤出患者集合,patient_id 进一步精确匹配。
|
||||
#[test]
|
||||
fn doctor_and_patient_filter_combined() {
|
||||
let doctor_patient_ids = vec![
|
||||
Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap(),
|
||||
Uuid::parse_str("00000000-0000-0000-0000-000000000002").unwrap(),
|
||||
];
|
||||
let specific_patient = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
|
||||
// 如果 doctor 过滤和 patient 过滤同时存在,结果应取交集
|
||||
let combined: Vec<Uuid> = doctor_patient_ids
|
||||
.into_iter()
|
||||
.filter(|id| *id == specific_patient)
|
||||
.collect();
|
||||
assert_eq!(combined.len(), 1);
|
||||
assert_eq!(combined[0], specific_patient);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user