Files
hms/crates/erp-health/src/dto/health_data_dto.rs
iven fa9278590d
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
refactor(dialysis): 透析模块拆分为独立 erp-dialysis crate
- 创建 erp-dialysis crate(DialysisState + DialysisError + DialysisModule)
- 迁移 2 Entity + 2 Service + 2 Handler + 2 DTO 共 8 个文件
- Entity 移除跨 crate patient Relation(FK 列保留)
- Service 内联 validation 逻辑,移除 patient 存在性检查(FK 约束保证)
- erp-health 的 stats/consultation 中 dialysis 查询改为 raw SQL
- ReviewLabReportReq 从 dialysis_dto 移至 health_data_dto(正确归属)
- workspace 全量编译通过
2026-04-28 12:37:23 +08:00

278 lines
8.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use chrono::NaiveDate;
use erp_core::sanitize::sanitize_option;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use uuid::Uuid;
/// 用 f64 表示 Decimal 值以满足 utoipa ToSchema 要求。
/// 对于健康数值(血压 60-200mmHg、血糖 3.9-11.1mmol/L、体重 30-300kg
/// f64 的 15 位有效数字精度完全足够,不存在实际精度丢失风险。
/// 数据库层仍使用 SeaORM Decimal 类型,转换仅在 DTO 边界进行。
type Decimal = f64;
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateVitalSignsReq {
pub record_date: NaiveDate,
pub systolic_bp_morning: Option<i32>,
pub diastolic_bp_morning: Option<i32>,
pub systolic_bp_evening: Option<i32>,
pub diastolic_bp_evening: Option<i32>,
pub heart_rate: Option<i32>,
pub weight: Option<Decimal>,
pub blood_sugar: Option<Decimal>,
pub body_temperature: Option<Decimal>,
pub spo2: Option<i32>,
/// fasting / postprandial / random / ogtt
pub blood_sugar_type: Option<String>,
pub water_intake_ml: Option<i32>,
pub urine_output_ml: Option<i32>,
pub notes: Option<String>,
pub source: Option<String>,
}
impl CreateVitalSignsReq {
pub fn sanitize(&mut self) {
self.notes = sanitize_option(self.notes.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdateVitalSignsReq {
pub record_date: Option<NaiveDate>,
pub systolic_bp_morning: Option<i32>,
pub diastolic_bp_morning: Option<i32>,
pub systolic_bp_evening: Option<i32>,
pub diastolic_bp_evening: Option<i32>,
pub heart_rate: Option<i32>,
pub weight: Option<Decimal>,
pub blood_sugar: Option<Decimal>,
pub body_temperature: Option<Decimal>,
pub spo2: Option<i32>,
pub blood_sugar_type: Option<String>,
pub water_intake_ml: Option<i32>,
pub urine_output_ml: Option<i32>,
pub notes: Option<String>,
}
impl UpdateVitalSignsReq {
pub fn sanitize(&mut self) {
self.notes = sanitize_option(self.notes.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct VitalSignsResp {
pub id: Uuid,
pub patient_id: Uuid,
pub record_date: NaiveDate,
pub source: String,
pub systolic_bp_morning: Option<i32>,
pub diastolic_bp_morning: Option<i32>,
pub systolic_bp_evening: Option<i32>,
pub diastolic_bp_evening: Option<i32>,
pub heart_rate: Option<i32>,
pub weight: Option<Decimal>,
pub blood_sugar: Option<Decimal>,
pub body_temperature: Option<Decimal>,
pub spo2: Option<i32>,
pub blood_sugar_type: Option<String>,
pub water_intake_ml: Option<i32>,
pub urine_output_ml: Option<i32>,
pub notes: Option<String>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub version: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateLabReportReq {
pub report_date: NaiveDate,
pub report_type: String,
/// manual_input / photo_upload
pub source: Option<String>,
/// V2 JSON 结构: [{name, value, unit, reference_low, reference_high, is_abnormal}]
pub items: Option<serde_json::Value>,
pub image_urls: Option<serde_json::Value>,
pub doctor_notes: Option<String>,
}
impl CreateLabReportReq {
pub fn sanitize(&mut self) {
self.doctor_notes = sanitize_option(self.doctor_notes.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdateLabReportReq {
pub report_date: Option<NaiveDate>,
pub report_type: Option<String>,
pub source: Option<String>,
pub items: Option<serde_json::Value>,
pub image_urls: Option<serde_json::Value>,
pub doctor_notes: Option<String>,
}
impl UpdateLabReportReq {
pub fn sanitize(&mut self) {
self.doctor_notes = sanitize_option(self.doctor_notes.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct LabReportResp {
pub id: Uuid,
pub patient_id: Uuid,
pub report_date: NaiveDate,
pub report_type: String,
pub source: Option<String>,
pub items: Option<serde_json::Value>,
pub image_urls: Option<serde_json::Value>,
pub doctor_notes: Option<String>,
pub status: String,
pub reviewed_by: Option<Uuid>,
pub reviewed_at: Option<chrono::DateTime<chrono::Utc>>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub version: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateHealthRecordReq {
pub record_type: Option<String>,
pub record_date: NaiveDate,
pub source: Option<String>,
pub overall_assessment: Option<String>,
pub report_file_url: Option<String>,
pub notes: Option<String>,
}
impl CreateHealthRecordReq {
pub fn sanitize(&mut self) {
self.source = sanitize_option(self.source.take());
self.overall_assessment = sanitize_option(self.overall_assessment.take());
self.notes = sanitize_option(self.notes.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdateHealthRecordReq {
pub record_type: Option<String>,
pub record_date: Option<NaiveDate>,
pub source: Option<String>,
pub overall_assessment: Option<String>,
pub report_file_url: Option<String>,
pub notes: Option<String>,
}
impl UpdateHealthRecordReq {
pub fn sanitize(&mut self) {
self.source = sanitize_option(self.source.take());
self.overall_assessment = sanitize_option(self.overall_assessment.take());
self.notes = sanitize_option(self.notes.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct HealthRecordResp {
pub id: Uuid,
pub patient_id: Uuid,
pub record_type: String,
pub record_date: NaiveDate,
pub source: Option<String>,
pub overall_assessment: Option<String>,
pub report_file_url: Option<String>,
pub notes: Option<String>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub version: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct TrendResp {
pub id: Uuid,
pub patient_id: Uuid,
pub period_start: NaiveDate,
pub period_end: NaiveDate,
pub indicator_summary: Option<serde_json::Value>,
pub abnormal_items: Option<serde_json::Value>,
pub generation_type: String,
pub report_file_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct IndicatorTimeseriesResp {
pub indicator: String,
pub data: Vec<DataPoint>,
}
// ---------------------------------------------------------------------------
// 小程序趋势查询(通过当前用户关联 patient
// ---------------------------------------------------------------------------
/// 小程序趋势查询参数
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct MiniTrendQueryParams {
/// 指标名称,如 "blood_pressure_systolic", "heart_rate" 等
pub indicator: String,
/// 时间范围:"7d"(默认), "30d", "90d"
pub range: Option<String>,
}
/// 小程序趋势数据点
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct DataPoint {
/// 日期,格式 YYYY-MM-DD
pub date: String,
/// 指标数值
pub value: f64,
}
/// 小程序趋势响应
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct MiniTrendResp {
/// 指标名称
pub indicator: String,
/// 数据点列表(按日期升序)
pub data_points: Vec<DataPoint>,
}
// ---------------------------------------------------------------------------
// 小程序今日体征摘要
// ---------------------------------------------------------------------------
/// 单个指标摘要
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct IndicatorSummary {
/// 指标数值
pub value: f64,
/// 状态: "normal" | "high" | "low"
pub status: String,
/// 参考范围,如 "60-100"
pub reference_range: Option<String>,
/// 收缩压(仅血压指标)
pub systolic: Option<f64>,
/// 舒张压(仅血压指标)
pub diastolic: Option<f64>,
}
/// 小程序今日体征摘要响应
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct MiniTodayResp {
pub blood_pressure: Option<IndicatorSummary>,
pub heart_rate: Option<IndicatorSummary>,
pub blood_sugar: Option<IndicatorSummary>,
pub weight: Option<IndicatorSummary>,
}
#[derive(Debug, Clone, serde::Deserialize, ToSchema)]
pub struct ReviewLabReportReq {
pub doctor_notes: Option<String>,
pub items: Option<serde_json::Value>,
}
impl ReviewLabReportReq {
pub fn sanitize(&mut self) {
self.doctor_notes = sanitize_option(self.doctor_notes.take());
}
}