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,207 @@
use chrono::{NaiveDate, Utc};
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use uuid::Uuid;
use erp_core::sanitize::{sanitize_option, sanitize_string};
// ---------------------------------------------------------------------------
// CarePlan
// ---------------------------------------------------------------------------
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct CarePlanResp {
pub id: Uuid,
pub patient_id: Uuid,
pub plan_type: String,
pub status: String,
pub title: String,
pub goals: serde_json::Value,
pub start_date: Option<NaiveDate>,
pub end_date: Option<NaiveDate>,
pub notes: Option<String>,
pub created_at: chrono::DateTime<Utc>,
pub updated_at: chrono::DateTime<Utc>,
pub version: i32,
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct CreateCarePlanReq {
pub patient_id: Uuid,
pub plan_type: String,
pub title: String,
pub goals: Option<serde_json::Value>,
pub start_date: Option<NaiveDate>,
pub end_date: Option<NaiveDate>,
pub notes: Option<String>,
}
impl CreateCarePlanReq {
pub fn sanitize(&mut self) {
self.title = sanitize_string(&self.title);
self.notes = sanitize_option(self.notes.take());
}
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct UpdateCarePlanReq {
pub plan_type: Option<String>,
pub title: Option<String>,
pub status: Option<String>,
pub goals: Option<serde_json::Value>,
pub start_date: Option<NaiveDate>,
pub end_date: Option<NaiveDate>,
pub notes: Option<String>,
}
impl UpdateCarePlanReq {
pub fn sanitize(&mut self) {
if let Some(ref mut v) = self.title {
*v = sanitize_string(v);
}
if let Some(ref mut v) = self.notes {
*v = sanitize_option(Some(std::mem::take(v))).unwrap_or_default();
}
}
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct UpdateCarePlanWithVersion {
#[serde(flatten)]
pub data: UpdateCarePlanReq,
pub version: i32,
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct ListCarePlansParams {
pub patient_id: Option<Uuid>,
pub plan_type: Option<String>,
pub status: Option<String>,
pub page: Option<u64>,
pub page_size: Option<u64>,
}
// ---------------------------------------------------------------------------
// CarePlanItem
// ---------------------------------------------------------------------------
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct CarePlanItemResp {
pub id: Uuid,
pub plan_id: Uuid,
pub item_type: String,
pub title: String,
pub description: Option<String>,
pub status: String,
pub schedule: Option<String>,
pub sort_order: Option<i32>,
pub created_at: chrono::DateTime<Utc>,
pub updated_at: chrono::DateTime<Utc>,
pub version: i32,
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct CreateCarePlanItemReq {
pub item_type: String,
pub title: String,
pub description: Option<String>,
pub schedule: Option<String>,
pub sort_order: Option<i32>,
}
impl CreateCarePlanItemReq {
pub fn sanitize(&mut self) {
self.title = sanitize_string(&self.title);
self.description = sanitize_option(self.description.take());
self.schedule = sanitize_option(self.schedule.take());
}
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct UpdateCarePlanItemReq {
pub item_type: Option<String>,
pub title: Option<String>,
pub description: Option<String>,
pub status: Option<String>,
pub schedule: Option<String>,
pub sort_order: Option<i32>,
}
impl UpdateCarePlanItemReq {
pub fn sanitize(&mut self) {
if let Some(ref mut v) = self.title {
*v = sanitize_string(v);
}
if let Some(ref mut v) = self.description {
*v = sanitize_option(Some(std::mem::take(v))).unwrap_or_default();
}
}
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct UpdateCarePlanItemWithVersion {
#[serde(flatten)]
pub data: UpdateCarePlanItemReq,
pub version: i32,
}
// ---------------------------------------------------------------------------
// CarePlanOutcome
// ---------------------------------------------------------------------------
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct CarePlanOutcomeResp {
pub id: Uuid,
pub plan_id: Uuid,
pub item_id: Option<Uuid>,
pub metric: String,
pub baseline_value: String,
pub target_value: String,
pub current_value: Option<String>,
pub measured_at: Option<chrono::DateTime<Utc>>,
pub notes: Option<String>,
pub created_at: chrono::DateTime<Utc>,
pub updated_at: chrono::DateTime<Utc>,
pub version: i32,
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct CreateCarePlanOutcomeReq {
pub item_id: Option<Uuid>,
pub metric: String,
pub baseline_value: String,
pub target_value: String,
pub current_value: Option<String>,
pub measured_at: Option<chrono::DateTime<Utc>>,
pub notes: Option<String>,
}
impl CreateCarePlanOutcomeReq {
pub fn sanitize(&mut self) {
self.metric = sanitize_string(&self.metric);
self.notes = sanitize_option(self.notes.take());
}
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct UpdateCarePlanOutcomeReq {
pub current_value: Option<String>,
pub target_value: Option<String>,
pub measured_at: Option<chrono::DateTime<Utc>>,
pub notes: Option<String>,
}
impl UpdateCarePlanOutcomeReq {
pub fn sanitize(&mut self) {
if let Some(ref mut v) = self.notes {
*v = sanitize_option(Some(std::mem::take(v))).unwrap_or_default();
}
}
}
#[derive(Debug, Deserialize, ToSchema)]
pub struct UpdateCarePlanOutcomeWithVersion {
#[serde(flatten)]
pub data: UpdateCarePlanOutcomeReq,
pub version: i32,
}

View File

@@ -1,5 +1,6 @@
pub mod appointment_dto;
pub mod alert_dto;
pub mod care_plan_dto;
pub mod article_dto;
pub mod consent_dto;
pub mod consultation_dto;