From f668e642660b649f6fe1ed2fe9c7b7807736f971 Mon Sep 17 00:00:00 2001 From: iven Date: Wed, 6 May 2026 10:20:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(health):=20FHIR=20converter=20=E8=BA=AB?= =?UTF-8?q?=E4=BB=BD=E8=AF=81=E5=8F=B7=E8=84=B1=E6=95=8F=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/erp-health/src/fhir/converter.rs | 59 ++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/crates/erp-health/src/fhir/converter.rs b/crates/erp-health/src/fhir/converter.rs index 2114c36..e40a85c 100644 --- a/crates/erp-health/src/fhir/converter.rs +++ b/crates/erp-health/src/fhir/converter.rs @@ -32,9 +32,15 @@ pub fn patient_to_fhir(p: &patient::Model) -> serde_json::Value { } if let Some(ref id_number) = p.id_number { + // 加密密文(v1| 前缀)不输出,明文做脱敏处理 + let display_value = if id_number.starts_with("v1|") { + "[REDACTED]".to_string() + } else { + mask_sensitive(id_number) + }; result["identifier"] = serde_json::json!([{ "system": "urn:oid:2.16.156.10011.1.3", - "value": id_number, + "value": display_value, }]); } @@ -332,6 +338,15 @@ pub fn follow_up_to_fhir(t: &follow_up_task::Model) -> serde_json::Value { }) } +/// 对敏感字符串做脱敏:保留前 1 位和后 4 位,中间用 * 替代 +fn mask_sensitive(s: &str) -> String { + if s.len() <= 5 { + "*".repeat(s.len()) + } else { + format!("{}{}{}", &s[..1], "*".repeat(s.len() - 5), &s[s.len() - 4..]) + } +} + #[cfg(test)] mod tests { use super::*; @@ -370,7 +385,47 @@ mod tests { assert_eq!(fhir["id"], "00000000-0000-0000-0000-000000000001"); assert_eq!(fhir["gender"], "male"); assert_eq!(fhir["birthDate"], "1968-05-15"); - assert_eq!(fhir["identifier"][0]["value"], "110101196805150001"); + assert_eq!(fhir["identifier"][0]["value"], "1*************0001"); + } + + #[test] + fn test_patient_to_fhir_encrypted_id_number_redacted() { + let p = patient::Model { + id: uuid::Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap(), + tenant_id: uuid::Uuid::now_v7(), + user_id: None, + name: "测试".into(), + gender: None, + birth_date: None, + blood_type: None, + id_number: Some("v1|encrypted_payload_here".into()), + id_number_hash: None, + allergy_history: None, + medical_history_summary: None, + emergency_contact_name: None, + emergency_contact_phone: None, + emergency_contact_phone_hash: None, + key_version: None, + status: "active".into(), + verification_status: "pending".into(), + source: None, + notes: None, + created_at: chrono::Utc::now(), + updated_at: chrono::Utc::now(), + created_by: None, + updated_by: None, + deleted_at: None, + version: 1, + }; + let fhir = patient_to_fhir(&p); + assert_eq!(fhir["identifier"][0]["value"], "[REDACTED]"); + } + + #[test] + fn test_mask_sensitive() { + assert_eq!(mask_sensitive("110101196805150001"), "1*************0001"); + assert_eq!(mask_sensitive("12345"), "*****"); + assert_eq!(mask_sensitive("123456"), "1*3456"); } #[test]