feat(health): vital_signs_daily 日聚合表 + Entity + service

- 新增 vital_signs_daily 表迁移(带唯一索引 tenant+patient+device_type+date)
- 新增 SeaORM Entity(含 percentile_95 统计字段)
- 实现日聚合 service:从 hourly 聚合到 daily(支持 upsert)
- 实现 aggregate_daily_for_all_tenants 多租户遍历聚合
- 实现 query_daily 范围查询
- 单元测试:percentile 计算验证
This commit is contained in:
iven
2026-05-04 02:30:03 +08:00
parent fa0a788cf9
commit 43894446d9
6 changed files with 289 additions and 0 deletions

View File

@@ -42,4 +42,5 @@ pub mod offline_event_registration;
pub mod medication_record;
pub mod medication_reminder;
pub mod vital_signs;
pub mod vital_signs_daily;
pub mod vital_signs_hourly;

View File

@@ -0,0 +1,45 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "vital_signs_daily")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: Uuid,
pub tenant_id: Uuid,
pub patient_id: Uuid,
pub device_type: String,
pub date_bucket: chrono::NaiveDate,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub min_val: Option<f64>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub max_val: Option<f64>,
pub avg_val: f64,
pub sample_count: i32,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub percentile_95: Option<f64>,
pub created_at: DateTimeUtc,
pub updated_at: DateTimeUtc,
pub version: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::patient::Entity",
from = "Column::PatientId",
to = "super::patient::Column::Id"
)]
Patient,
}
impl Related<super::patient::Entity> for Entity {
fn to() -> RelationDef {
Relation::Patient.def()
}
fn via() -> Option<RelationDef> {
None
}
}
impl ActiveModelBehavior for ActiveModel {}