feat(health): 护理计划实体与服务 — Phase 1 关怀引擎 MVP 第一步
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

新增护理计划(Care Plan)完整 CRUD:3 张表(care_plans / care_plan_items /
care_plan_outcomes)、3 个 SeaORM Entity、15 个 API 端点、4 个事件常量、
2 个权限码。支持透析/慢性/预防/康复计划类型,条目分干预/监测/目标/教育四类,
预后测量含基线/目标/当前值追踪。
This commit is contained in:
iven
2026-05-04 18:40:22 +08:00
parent c35ea83799
commit ef422f354d
16 changed files with 1662 additions and 2 deletions

View File

@@ -0,0 +1,64 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "care_plans")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: Uuid,
pub tenant_id: Uuid,
pub patient_id: Uuid,
pub plan_type: String,
pub status: String,
pub title: String,
pub goals: serde_json::Value,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub start_date: Option<chrono::NaiveDate>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub end_date: Option<chrono::NaiveDate>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
pub created_at: DateTimeUtc,
pub updated_at: DateTimeUtc,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub created_by: Option<Uuid>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub updated_by: Option<Uuid>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub deleted_at: Option<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,
#[sea_orm(has_many = "super::care_plan_item::Entity")]
Items,
#[sea_orm(has_many = "super::care_plan_outcome::Entity")]
Outcomes,
}
impl Related<super::patient::Entity> for Entity {
fn to() -> RelationDef {
Relation::Patient.def()
}
}
impl Related<super::care_plan_item::Entity> for Entity {
fn to() -> RelationDef {
Relation::Items.def()
}
}
impl Related<super::care_plan_outcome::Entity> for Entity {
fn to() -> RelationDef {
Relation::Outcomes.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@@ -0,0 +1,47 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "care_plan_items")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: Uuid,
pub tenant_id: Uuid,
pub plan_id: Uuid,
pub item_type: String,
pub title: String,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub status: String,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub schedule: Option<String>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub sort_order: Option<i32>,
pub created_at: DateTimeUtc,
pub updated_at: DateTimeUtc,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub created_by: Option<Uuid>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub updated_by: Option<Uuid>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub deleted_at: Option<DateTimeUtc>,
pub version: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::care_plan::Entity",
from = "Column::PlanId",
to = "super::care_plan::Column::Id"
)]
CarePlan,
}
impl Related<super::care_plan::Entity> for Entity {
fn to() -> RelationDef {
Relation::CarePlan.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@@ -0,0 +1,61 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "care_plan_outcomes")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: Uuid,
pub tenant_id: Uuid,
pub plan_id: Uuid,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub item_id: Option<Uuid>,
pub metric: String,
pub baseline_value: String,
pub target_value: String,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub current_value: Option<String>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub measured_at: Option<DateTimeUtc>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
pub created_at: DateTimeUtc,
pub updated_at: DateTimeUtc,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub created_by: Option<Uuid>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub updated_by: Option<Uuid>,
#[sea_orm(skip_serializing_if = "Option::is_none")]
pub deleted_at: Option<DateTimeUtc>,
pub version: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::care_plan::Entity",
from = "Column::PlanId",
to = "super::care_plan::Column::Id"
)]
CarePlan,
#[sea_orm(
belongs_to = "super::care_plan_item::Entity",
from = "Column::ItemId",
to = "super::care_plan_item::Column::Id"
)]
CarePlanItem,
}
impl Related<super::care_plan::Entity> for Entity {
fn to() -> RelationDef {
Relation::CarePlan.def()
}
}
impl Related<super::care_plan_item::Entity> for Entity {
fn to() -> RelationDef {
Relation::CarePlanItem.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@@ -43,5 +43,8 @@ pub mod offline_event_registration;
pub mod medication_record;
pub mod medication_reminder;
pub mod vital_signs;
pub mod care_plan;
pub mod care_plan_item;
pub mod care_plan_outcome;
pub mod vital_signs_daily;
pub mod vital_signs_hourly;