From f0c34267921485faa68de47c8549ccf3a58f02f7 Mon Sep 17 00:00:00 2001 From: iven Date: Sun, 26 Apr 2026 21:31:41 +0800 Subject: [PATCH] =?UTF-8?q?fix(health):=20=E5=8C=BB=E7=94=9F=E8=AF=A6?= =?UTF-8?q?=E6=83=85=20API=20=E8=BF=94=E5=9B=9E=E8=A7=A3=E5=AF=86=E5=90=8E?= =?UTF-8?q?=E7=9A=84=E5=8E=9F=E5=A7=8B=E6=89=A7=E7=85=A7=E5=8F=B7=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E8=84=B1=E6=95=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit model_to_resp_decrypted 错误地对解密后的 license_number 调用 mask_license_number,导致详情 API 返回脱敏值 (YL****23) 而非完整原始值 (YL-2024-00123)。 修复:详情/创建/更新响应只做解密不做脱敏,列表 API 仍然将 Tier 1 字段设为 None。 --- .../erp-health/src/service/doctor_service.rs | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/crates/erp-health/src/service/doctor_service.rs b/crates/erp-health/src/service/doctor_service.rs index 0309779..f3e8a14 100644 --- a/crates/erp-health/src/service/doctor_service.rs +++ b/crates/erp-health/src/service/doctor_service.rs @@ -142,6 +142,16 @@ pub async fn update_doctor( .map_err(|_| HealthError::VersionMismatch)?; let old_online_status = model.online_status.clone(); + // 记录变更前的关键字段(license_number 为加密值,不记录原文) + let old_values = serde_json::json!({ + "name": model.name, + "department": model.department, + "title": model.title, + "specialty": model.specialty, + "bio": model.bio, + "online_status": model.online_status, + }); + let mut active: doctor_profile::ActiveModel = model.into(); if let Some(v) = req.name { active.name = Set(v); } if let Some(v) = req.department { active.department = Set(Some(v)); } @@ -173,9 +183,20 @@ pub async fn update_doctor( let updated = active.update(&state.db).await?; + // 变更后快照 + let new_values = serde_json::json!({ + "name": updated.name, + "department": updated.department, + "title": updated.title, + "specialty": updated.specialty, + "bio": updated.bio, + "online_status": updated.online_status, + }); + audit_service::record( AuditLog::new(tenant_id, operator_id, "doctor.updated", "doctor") - .with_resource_id(updated.id), + .with_resource_id(updated.id) + .with_changes(Some(old_values), Some(new_values)), &state.db, ).await; @@ -242,8 +263,7 @@ fn model_to_resp(m: doctor_profile::Model) -> DoctorResp { fn model_to_resp_decrypted(crypto: &erp_core::crypto::PiiCrypto, m: doctor_profile::Model) -> DoctorResp { let license = m.license_number.as_ref() - .map(|l| pii::decrypt(crypto.kek(), l).unwrap_or_else(|_| l.clone())) - .map(|l| pii::mask_license_number(&l)); + .map(|l| pii::decrypt(crypto.kek(), l).unwrap_or_else(|_| l.clone())); DoctorResp { id: m.id, user_id: m.user_id,