diff --git a/crates/erp-health/src/fhir/mod.rs b/crates/erp-health/src/fhir/mod.rs new file mode 100644 index 0000000..383d616 --- /dev/null +++ b/crates/erp-health/src/fhir/mod.rs @@ -0,0 +1,5 @@ +pub mod converter; +pub mod handler; +pub mod types; + +pub use types::*; diff --git a/crates/erp-health/src/fhir/types.rs b/crates/erp-health/src/fhir/types.rs new file mode 100644 index 0000000..c9622ab --- /dev/null +++ b/crates/erp-health/src/fhir/types.rs @@ -0,0 +1,97 @@ +use serde::Serialize; + +/// FHIR 搜索参数 +#[derive(Debug, serde::Deserialize, utoipa::IntoParams)] +pub struct FhirSearchParams { + #[serde(rename = "_id")] + pub id: Option, + #[serde(rename = "_count")] + pub count: Option, + #[serde(rename = "_offset")] + pub offset: Option, + pub patient: Option, + pub category: Option, + pub code: Option, + pub date: Option, + pub name: Option, + pub identifier: Option, + pub status: Option, +} + +/// HMS device_type → FHIR Observation LOINC 映射 +pub fn device_type_to_loinc(device_type: &str) -> Option<(&'static str, &'static str)> { + match device_type { + "heart_rate" => Some(("8867-4", "Heart rate")), + "blood_oxygen" => Some(("2708-6", "Oxygen saturation in Arterial blood")), + "blood_pressure" => Some(("85354-9", "Blood pressure panel")), + "blood_glucose" => Some(("2339-0", "Glucose in Blood")), + "temperature" => Some(("8310-5", "Body temperature")), + "steps" => Some(("55423-8", "Number of steps in 24 hours")), + "sleep" => Some(("93832-4", "Sleep duration")), + "stress" => Some(("80319-1", "Stress level")), + _ => None, + } +} + +/// HMS device_type → FHIR Observation category +pub fn device_type_to_category(device_type: &str) -> &'static str { + match device_type { + "heart_rate" | "blood_oxygen" | "blood_pressure" | "temperature" => "vital-signs", + "steps" | "sleep" | "stress" => "activity", + "blood_glucose" => "laboratory", + _ => "survey", + } +} + +/// HMS device_type → FHIR UCUM unit +pub fn device_type_to_unit(device_type: &str) -> (&'static str, &'static str) { + match device_type { + "heart_rate" => ("beats/minute", "/min"), + "blood_oxygen" => ("%", "%"), + "blood_pressure" => ("mmHg", "mm[Hg]"), + "blood_glucose" => ("mg/dL", "mg/dL"), + "temperature" => ("\u{00b0}C", "Cel"), + "steps" => ("steps", "{steps}"), + "sleep" => ("hours", "h"), + "stress" => ("score", "{score}"), + _ => ("unknown", "unknown"), + } +} + +/// OperationOutcome(错误响应) +#[derive(Debug, Serialize)] +pub struct OperationOutcomeResource { + pub resource_type: String, + pub issue: Vec, +} + +#[derive(Debug, Serialize)] +pub struct OperationOutcomeIssue { + pub severity: String, + pub code: String, + pub diagnostics: Option, +} + +/// LOINC code → device_type 反向映射 +pub fn loinc_to_device_type(loinc: &str) -> Option<&'static str> { + match loinc { + "8867-4" => Some("heart_rate"), + "2708-6" => Some("blood_oxygen"), + "85354-9" | "8480-6" | "8462-4" => Some("blood_pressure"), + "2339-0" => Some("blood_glucose"), + "8310-5" => Some("temperature"), + "55423-8" => Some("steps"), + "93832-4" => Some("sleep"), + _ => None, + } +} + +/// FHIR category → device_type 列表 +pub fn category_to_device_types(category: &str) -> Vec<&'static str> { + match category { + "vital-signs" => vec!["heart_rate", "blood_oxygen", "blood_pressure", "temperature"], + "laboratory" => vec!["blood_glucose"], + "activity" => vec!["steps", "sleep", "stress"], + _ => vec![], + } +}