From 67f2d0780933d01611501a3d722c014dc1975f44 Mon Sep 17 00:00:00 2001 From: iven Date: Mon, 27 Apr 2026 11:31:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(health):=20=E4=BD=93=E5=BE=81=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E4=BD=93=E6=B8=A9/SpO2/=E8=A1=80=E7=B3=96=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 迁移 079: vital_signs 表新增 body_temperature/spo2/blood_sugar_type 列 - Entity/DTO/Service 全链路支持新字段 - blood_sugar_type: fasting/postprandial/random/ogtt - daily_monitoring 兼容层补全新字段为 None --- crates/erp-health/src/dto/health_data_dto.rs | 10 ++++ crates/erp-health/src/entity/vital_signs.rs | 6 +++ .../src/service/daily_monitoring_service.rs | 6 +++ .../src/service/health_data_service.rs | 18 +++++++ crates/erp-server/migration/src/lib.rs | 2 + ...m20260427_000079_add_vital_signs_fields.rs | 54 +++++++++++++++++++ 6 files changed, 96 insertions(+) create mode 100644 crates/erp-server/migration/src/m20260427_000079_add_vital_signs_fields.rs diff --git a/crates/erp-health/src/dto/health_data_dto.rs b/crates/erp-health/src/dto/health_data_dto.rs index 90b9608..09d9981 100644 --- a/crates/erp-health/src/dto/health_data_dto.rs +++ b/crates/erp-health/src/dto/health_data_dto.rs @@ -20,6 +20,10 @@ pub struct CreateVitalSignsReq { pub heart_rate: Option, pub weight: Option, pub blood_sugar: Option, + pub body_temperature: Option, + pub spo2: Option, + /// fasting / postprandial / random / ogtt + pub blood_sugar_type: Option, pub water_intake_ml: Option, pub urine_output_ml: Option, pub notes: Option, @@ -42,6 +46,9 @@ pub struct UpdateVitalSignsReq { pub heart_rate: Option, pub weight: Option, pub blood_sugar: Option, + pub body_temperature: Option, + pub spo2: Option, + pub blood_sugar_type: Option, pub water_intake_ml: Option, pub urine_output_ml: Option, pub notes: Option, @@ -66,6 +73,9 @@ pub struct VitalSignsResp { pub heart_rate: Option, pub weight: Option, pub blood_sugar: Option, + pub body_temperature: Option, + pub spo2: Option, + pub blood_sugar_type: Option, pub water_intake_ml: Option, pub urine_output_ml: Option, pub notes: Option, diff --git a/crates/erp-health/src/entity/vital_signs.rs b/crates/erp-health/src/entity/vital_signs.rs index 7b40cd1..d9115fd 100644 --- a/crates/erp-health/src/entity/vital_signs.rs +++ b/crates/erp-health/src/entity/vital_signs.rs @@ -24,6 +24,12 @@ pub struct Model { #[sea_orm(skip_serializing_if = "Option::is_none")] pub blood_sugar: Option, #[sea_orm(skip_serializing_if = "Option::is_none")] + pub body_temperature: Option, + #[sea_orm(skip_serializing_if = "Option::is_none")] + pub spo2: Option, + #[sea_orm(skip_serializing_if = "Option::is_none")] + pub blood_sugar_type: Option, + #[sea_orm(skip_serializing_if = "Option::is_none")] pub water_intake_ml: Option, #[sea_orm(skip_serializing_if = "Option::is_none")] pub urine_output_ml: Option, diff --git a/crates/erp-health/src/service/daily_monitoring_service.rs b/crates/erp-health/src/service/daily_monitoring_service.rs index 30dc62d..40d73e2 100644 --- a/crates/erp-health/src/service/daily_monitoring_service.rs +++ b/crates/erp-health/src/service/daily_monitoring_service.rs @@ -83,6 +83,9 @@ pub async fn create_daily_monitoring( heart_rate: None, weight: req.weight, blood_sugar: req.blood_sugar, + body_temperature: None, + spo2: None, + blood_sugar_type: None, water_intake_ml: req.fluid_intake, urine_output_ml: req.urine_output, notes: req.notes, @@ -121,6 +124,9 @@ pub async fn update_daily_monitoring( heart_rate: None, weight: req.weight, blood_sugar: req.blood_sugar, + body_temperature: None, + spo2: None, + blood_sugar_type: None, water_intake_ml: req.fluid_intake, urine_output_ml: req.urine_output, notes: req.notes, diff --git a/crates/erp-health/src/service/health_data_service.rs b/crates/erp-health/src/service/health_data_service.rs index c2f31d0..4a4719d 100644 --- a/crates/erp-health/src/service/health_data_service.rs +++ b/crates/erp-health/src/service/health_data_service.rs @@ -59,6 +59,9 @@ pub async fn list_vital_signs( heart_rate: m.heart_rate, weight: m.weight.map(|d| d.to_f64().unwrap_or(0.0)), blood_sugar: m.blood_sugar.map(|d| d.to_f64().unwrap_or(0.0)), + body_temperature: m.body_temperature.map(|d| d.to_f64().unwrap_or(0.0)), + spo2: m.spo2, + blood_sugar_type: m.blood_sugar_type, water_intake_ml: m.water_intake_ml, urine_output_ml: m.urine_output_ml, notes: m.notes, @@ -100,6 +103,9 @@ pub async fn create_vital_signs( heart_rate: Set(req.heart_rate), weight: Set(req.weight.map(|v| sea_orm::prelude::Decimal::from_f64_retain(v).unwrap_or_default())), blood_sugar: Set(req.blood_sugar.map(|v| sea_orm::prelude::Decimal::from_f64_retain(v).unwrap_or_default())), + body_temperature: Set(req.body_temperature.map(|v| sea_orm::prelude::Decimal::from_f64_retain(v).unwrap_or_default())), + spo2: Set(req.spo2), + blood_sugar_type: Set(req.blood_sugar_type), water_intake_ml: Set(req.water_intake_ml), urine_output_ml: Set(req.urine_output_ml), notes: Set(req.notes), @@ -131,6 +137,9 @@ pub async fn create_vital_signs( heart_rate: m.heart_rate, weight: m.weight.map(|d| d.to_f64().unwrap_or(0.0)), blood_sugar: m.blood_sugar.map(|d| d.to_f64().unwrap_or(0.0)), + body_temperature: m.body_temperature.map(|d| d.to_f64().unwrap_or(0.0)), + spo2: m.spo2, + blood_sugar_type: m.blood_sugar_type, water_intake_ml: m.water_intake_ml, urine_output_ml: m.urine_output_ml, notes: m.notes, created_at: m.created_at, updated_at: m.updated_at, version: m.version, }) @@ -178,6 +187,9 @@ pub async fn update_vital_signs( if let Some(v) = req.heart_rate { active.heart_rate = Set(Some(v)); } if let Some(v) = req.weight { active.weight = Set(Some(sea_orm::prelude::Decimal::from_f64_retain(v).unwrap_or_default())); } if let Some(v) = req.blood_sugar { active.blood_sugar = Set(Some(sea_orm::prelude::Decimal::from_f64_retain(v).unwrap_or_default())); } + if let Some(v) = req.body_temperature { active.body_temperature = Set(Some(sea_orm::prelude::Decimal::from_f64_retain(v).unwrap_or_default())); } + if let Some(v) = req.spo2 { active.spo2 = Set(Some(v)); } + if let Some(v) = req.blood_sugar_type { active.blood_sugar_type = Set(Some(v)); } if let Some(v) = req.water_intake_ml { active.water_intake_ml = Set(Some(v)); } if let Some(v) = req.urine_output_ml { active.urine_output_ml = Set(Some(v)); } if let Some(v) = req.notes { active.notes = Set(Some(v)); } @@ -210,6 +222,9 @@ pub async fn update_vital_signs( heart_rate: m.heart_rate, weight: m.weight.map(|d| d.to_f64().unwrap_or(0.0)), blood_sugar: m.blood_sugar.map(|d| d.to_f64().unwrap_or(0.0)), + body_temperature: m.body_temperature.map(|d| d.to_f64().unwrap_or(0.0)), + spo2: m.spo2, + blood_sugar_type: m.blood_sugar_type.clone(), water_intake_ml: m.water_intake_ml, urine_output_ml: m.urine_output_ml, notes: m.notes.clone(), @@ -232,6 +247,9 @@ pub async fn update_vital_signs( heart_rate: m.heart_rate, weight: m.weight.map(|d| d.to_f64().unwrap_or(0.0)), blood_sugar: m.blood_sugar.map(|d| d.to_f64().unwrap_or(0.0)), + body_temperature: m.body_temperature.map(|d| d.to_f64().unwrap_or(0.0)), + spo2: m.spo2, + blood_sugar_type: m.blood_sugar_type, water_intake_ml: m.water_intake_ml, urine_output_ml: m.urine_output_ml, notes: m.notes, created_at: m.created_at, updated_at: m.updated_at, version: m.version, }) diff --git a/crates/erp-server/migration/src/lib.rs b/crates/erp-server/migration/src/lib.rs index 7b8282f..dac2b5b 100644 --- a/crates/erp-server/migration/src/lib.rs +++ b/crates/erp-server/migration/src/lib.rs @@ -78,6 +78,7 @@ mod m20260426_000075_create_patient_devices; mod m20260426_000076_create_alert_rules; mod m20260426_000077_create_alerts; mod m20260427_000078_normalize_follow_up_types; +mod m20260427_000079_add_vital_signs_fields; pub struct Migrator; @@ -163,6 +164,7 @@ impl MigratorTrait for Migrator { Box::new(m20260426_000076_create_alert_rules::Migration), Box::new(m20260426_000077_create_alerts::Migration), Box::new(m20260427_000078_normalize_follow_up_types::Migration), + Box::new(m20260427_000079_add_vital_signs_fields::Migration), ] } } diff --git a/crates/erp-server/migration/src/m20260427_000079_add_vital_signs_fields.rs b/crates/erp-server/migration/src/m20260427_000079_add_vital_signs_fields.rs new file mode 100644 index 0000000..b04bec1 --- /dev/null +++ b/crates/erp-server/migration/src/m20260427_000079_add_vital_signs_fields.rs @@ -0,0 +1,54 @@ +use sea_orm_migration::prelude::*; + +pub struct Migration; + +impl MigrationName for Migration { + fn name(&self) -> &str { + "m20260427_000079_add_vital_signs_fields" + } +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let conn = manager.get_connection(); + + conn.execute_unprepared( + "ALTER TABLE vital_signs ADD COLUMN IF NOT EXISTS body_temperature DECIMAL(4,1)", + ) + .await?; + + conn.execute_unprepared( + "ALTER TABLE vital_signs ADD COLUMN IF NOT EXISTS spo2 INTEGER", + ) + .await?; + + conn.execute_unprepared( + "ALTER TABLE vital_signs ADD COLUMN IF NOT EXISTS blood_sugar_type VARCHAR(20) DEFAULT 'fasting'", + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let conn = manager.get_connection(); + + conn.execute_unprepared( + "ALTER TABLE vital_signs DROP COLUMN IF EXISTS blood_sugar_type", + ) + .await?; + + conn.execute_unprepared( + "ALTER TABLE vital_signs DROP COLUMN IF EXISTS spo2", + ) + .await?; + + conn.execute_unprepared( + "ALTER TABLE vital_signs DROP COLUMN IF EXISTS body_temperature", + ) + .await?; + + Ok(()) + } +}