功能修复: 1. 患者创建空名称验证:后端添加 name.trim().is_empty() 检查 2. 仪表盘统计容错:单个查询失败返回零值而非 500 3. FHIR 路由修复:从 /fhir 移到 /api/v1/fhir 保持一致 4. 冻结模块后端中间件:新增 frozen_module_middleware 拦截冻结路径 5. 积分端点权限码:health.health-data.list → health.points.list 6. 角色权限迁移:护士补充 devices.list,运营补充 points.list/manage 7. 测试结果文档:R01-R05 角色测试 + T00/T10 结果归档 Clippy 全 workspace 清零(14→0 errors): - erp-core: 修复 empty doc line、collapsible if、redundant closure 等 9 处 - erp-health: 修复 too_many_arguments、unused var、unnecessary parens 等 58 处 - erp-ai: 修复 dead_code、unused import 等 11 处 - erp-plugin: 修复 too_many_arguments、wildcard pattern 等 11 处 - erp-server-migration: 修复 enum_variant_names 5 处 - erp-auth/config/workflow/message: 各 1-3 处 工程改进: - lint-staged 配置迁移到 .lintstagedrc.js(函数式避免文件列表传给 clippy) - cargo fmt 统一格式化
233 lines
7.4 KiB
Rust
233 lines
7.4 KiB
Rust
//! erp-health 诊断记录集成测试
|
|
//!
|
|
//! 验证诊断 CRUD、列表按患者过滤、租户隔离、乐观锁。
|
|
|
|
use erp_health::dto::diagnosis_dto::*;
|
|
use erp_health::service::diagnosis_service;
|
|
|
|
use super::test_fixture::TestApp;
|
|
|
|
fn default_create_diagnosis_req() -> CreateDiagnosisReq {
|
|
CreateDiagnosisReq {
|
|
icd_code: "N18.9".to_string(),
|
|
diagnosis_name: "慢性肾脏病".to_string(),
|
|
diagnosis_type: "primary".to_string(),
|
|
diagnosed_date: chrono::NaiveDate::from_ymd_opt(2026, 4, 15).unwrap(),
|
|
status: "active".to_string(),
|
|
health_record_id: None,
|
|
diagnosed_by: None,
|
|
notes: None,
|
|
}
|
|
}
|
|
|
|
async fn seed_diagnosis(
|
|
app: &TestApp,
|
|
patient_id: uuid::Uuid,
|
|
icd_code: &str,
|
|
name: &str,
|
|
) -> DiagnosisResp {
|
|
diagnosis_service::create_diagnosis(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
patient_id,
|
|
Some(app.operator_id()),
|
|
CreateDiagnosisReq {
|
|
icd_code: icd_code.to_string(),
|
|
diagnosis_name: name.to_string(),
|
|
..default_create_diagnosis_req()
|
|
},
|
|
)
|
|
.await
|
|
.expect("创建诊断应成功")
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 1: 创建诊断
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_diagnosis_create() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("诊断患者").await;
|
|
|
|
let diag = seed_diagnosis(&app, patient_id, "N18.9", "慢性肾脏病").await;
|
|
|
|
assert_eq!(diag.patient_id, patient_id);
|
|
assert_eq!(diag.icd_code, "N18.9");
|
|
assert_eq!(diag.diagnosis_type, "primary");
|
|
assert_eq!(diag.status, "active");
|
|
assert_eq!(diag.version, 1);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 2: 更新诊断
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_diagnosis_update() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("诊断更新患者").await;
|
|
let diag = seed_diagnosis(&app, patient_id, "N18.8", "CKD更新").await;
|
|
|
|
let updated = diagnosis_service::update_diagnosis(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
diag.id,
|
|
Some(app.operator_id()),
|
|
UpdateDiagnosisReq {
|
|
status: Some("chronic".to_string()),
|
|
notes: Some("长期随访".to_string()),
|
|
icd_code: None,
|
|
diagnosis_name: None,
|
|
diagnosis_type: None,
|
|
diagnosed_date: None,
|
|
health_record_id: None,
|
|
diagnosed_by: None,
|
|
},
|
|
diag.version,
|
|
)
|
|
.await
|
|
.expect("更新应成功");
|
|
|
|
assert_eq!(updated.status, "chronic");
|
|
assert_eq!(updated.version, 2);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 3: 列表按患者过滤
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_diagnosis_list_by_patient() {
|
|
let app = TestApp::new().await;
|
|
let patient_a = app.create_patient("诊断列表A").await;
|
|
let patient_b = app.create_patient("诊断列表B").await;
|
|
|
|
seed_diagnosis(&app, patient_a, "N18.1", "CKD 1期").await;
|
|
seed_diagnosis(&app, patient_a, "N18.2", "CKD 2期").await;
|
|
seed_diagnosis(&app, patient_b, "E11.9", "2型糖尿病").await;
|
|
|
|
let list_a =
|
|
diagnosis_service::list_diagnoses(app.health_state(), app.tenant_id(), patient_a, 1, 20)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(list_a.total, 2);
|
|
|
|
let list_b =
|
|
diagnosis_service::list_diagnoses(app.health_state(), app.tenant_id(), patient_b, 1, 20)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(list_b.total, 1);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 4: 软删除
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_diagnosis_soft_delete() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("诊断删除患者").await;
|
|
let diag = seed_diagnosis(&app, patient_id, "N18.3", "CKD删除").await;
|
|
|
|
diagnosis_service::delete_diagnosis(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
diag.id,
|
|
Some(app.operator_id()),
|
|
diag.version,
|
|
)
|
|
.await
|
|
.expect("删除应成功");
|
|
|
|
let list =
|
|
diagnosis_service::list_diagnoses(app.health_state(), app.tenant_id(), patient_id, 1, 20)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(list.total, 0);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 5: 租户隔离
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_diagnosis_tenant_isolation() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("诊断隔离患者").await;
|
|
seed_diagnosis(&app, patient_id, "N18.4", "CKD隔离").await;
|
|
|
|
let other_tenant = uuid::Uuid::new_v4();
|
|
let list =
|
|
diagnosis_service::list_diagnoses(app.health_state(), other_tenant, patient_id, 1, 20)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(list.total, 0, "不同租户不应看到诊断记录");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 6: 无效患者创建诊断返回错误
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_diagnosis_invalid_patient() {
|
|
let app = TestApp::new().await;
|
|
let fake_patient = uuid::Uuid::new_v4();
|
|
|
|
let result = diagnosis_service::create_diagnosis(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
fake_patient,
|
|
None,
|
|
default_create_diagnosis_req(),
|
|
)
|
|
.await;
|
|
assert!(result.is_err(), "无效患者应返回错误");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 7: 乐观锁冲突
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_diagnosis_version_conflict() {
|
|
let app = TestApp::new().await;
|
|
let patient_id = app.create_patient("诊断锁患者").await;
|
|
let diag = seed_diagnosis(&app, patient_id, "N18.5", "CKD锁").await;
|
|
|
|
// 先更新一次
|
|
diagnosis_service::update_diagnosis(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
diag.id,
|
|
Some(app.operator_id()),
|
|
UpdateDiagnosisReq {
|
|
status: Some("resolved".to_string()),
|
|
icd_code: None,
|
|
diagnosis_name: None,
|
|
diagnosis_type: None,
|
|
diagnosed_date: None,
|
|
health_record_id: None,
|
|
diagnosed_by: None,
|
|
notes: None,
|
|
},
|
|
diag.version,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// 用旧 version 再更新应失败
|
|
let result = diagnosis_service::update_diagnosis(
|
|
app.health_state(),
|
|
app.tenant_id(),
|
|
diag.id,
|
|
Some(app.operator_id()),
|
|
UpdateDiagnosisReq {
|
|
status: Some("chronic".to_string()),
|
|
icd_code: None,
|
|
diagnosis_name: None,
|
|
diagnosis_type: None,
|
|
diagnosed_date: None,
|
|
health_record_id: None,
|
|
diagnosed_by: None,
|
|
notes: None,
|
|
},
|
|
diag.version,
|
|
)
|
|
.await;
|
|
assert!(result.is_err(), "乐观锁冲突应返回错误");
|
|
}
|