From e0b299ccd466c0f09915c970dd61506072a5a401 Mon Sep 17 00:00:00 2001 From: iven Date: Sun, 26 Apr 2026 10:27:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(health):=20patient=20entity=20PII=20?= =?UTF-8?q?=E4=BC=B4=E7=94=9F=E5=AD=97=E6=AE=B5=20+=20content=5Fmanagement?= =?UTF-8?q?=20=E7=BC=96=E8=AF=91=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 迁移 m000064: patient 添加 emergency_contact_phone_hash + key_version - patient Entity 补充对应字段 - 修复 content_management 迁移: exec_stmt → execute_unprepared - 修复 article_service: 补全新字段 (status/slug/content_type 等) - 修复 article_article_tag: 复合主键注解 --- .../src/entity/article_article_tag.rs | 42 ++++++++++++++ crates/erp-health/src/entity/patient.rs | 4 ++ .../erp-health/src/service/article_service.rs | 22 ++++++++ .../erp-health/src/service/patient_service.rs | 2 + crates/erp-server/migration/src/lib.rs | 6 ++ ...m20260427_000064_add_patient_pii_fields.rs | 56 +++++++++++++++++++ 6 files changed, 132 insertions(+) create mode 100644 crates/erp-health/src/entity/article_article_tag.rs create mode 100644 crates/erp-server/migration/src/m20260427_000064_add_patient_pii_fields.rs diff --git a/crates/erp-health/src/entity/article_article_tag.rs b/crates/erp-health/src/entity/article_article_tag.rs new file mode 100644 index 0000000..af9e089 --- /dev/null +++ b/crates/erp-health/src/entity/article_article_tag.rs @@ -0,0 +1,42 @@ +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +/// 文章-标签关联表(复合主键) +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "article_article_tag")] +pub struct Model { + #[sea_orm(primary_key)] + pub article_id: Uuid, + #[sea_orm(primary_key)] + pub tag_id: Uuid, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::article::Entity", + from = "Column::ArticleId", + to = "super::article::Column::Id" + )] + Article, + #[sea_orm( + belongs_to = "super::article_tag::Entity", + from = "Column::TagId", + to = "super::article_tag::Column::Id" + )] + Tag, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Article.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Tag.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/crates/erp-health/src/entity/patient.rs b/crates/erp-health/src/entity/patient.rs index d105836..b1f158e 100644 --- a/crates/erp-health/src/entity/patient.rs +++ b/crates/erp-health/src/entity/patient.rs @@ -28,6 +28,10 @@ pub struct Model { pub emergency_contact_name: Option, #[sea_orm(skip_serializing_if = "Option::is_none")] pub emergency_contact_phone: Option, + #[sea_orm(skip_serializing_if = "Option::is_none")] + pub emergency_contact_phone_hash: Option, + #[sea_orm(skip_serializing_if = "Option::is_none")] + pub key_version: Option, pub status: String, pub verification_status: String, #[sea_orm(skip_serializing_if = "Option::is_none")] diff --git a/crates/erp-health/src/service/article_service.rs b/crates/erp-health/src/service/article_service.rs index 2cd9e9e..ff77fe0 100644 --- a/crates/erp-health/src/service/article_service.rs +++ b/crates/erp-health/src/service/article_service.rs @@ -87,6 +87,10 @@ fn model_to_list_item(m: article::Model) -> ArticleListItem { category: m.category, author: m.author, published_at: m.published_at, + status: m.status, + view_count: m.view_count, + category_id: None, + tags: vec![], } } @@ -100,6 +104,16 @@ fn model_to_resp(m: article::Model) -> ArticleResp { category: m.category, author: m.author, published_at: m.published_at, + status: m.status, + slug: m.slug, + content_type: m.content_type, + reviewed_by: m.reviewed_by, + reviewed_at: m.reviewed_at, + review_note: m.review_note, + view_count: m.view_count, + sort_order: m.sort_order, + category_id: None, + tags: vec![], created_at: m.created_at, updated_at: m.updated_at, version: m.version, @@ -128,6 +142,14 @@ pub async fn create_article( category: Set(req.category), author: Set(req.author), published_at: Set(req.published_at), + status: Set("draft".into()), + slug: Set(req.slug), + content_type: Set(req.content_type.unwrap_or_else(|| "rich_text".into())), + reviewed_by: Set(None), + reviewed_at: Set(None), + review_note: Set(None), + view_count: Set(0), + sort_order: Set(0), created_at: Set(now), updated_at: Set(now), created_by: Set(operator_id), diff --git a/crates/erp-health/src/service/patient_service.rs b/crates/erp-health/src/service/patient_service.rs index a747f76..20f6dfb 100644 --- a/crates/erp-health/src/service/patient_service.rs +++ b/crates/erp-health/src/service/patient_service.rs @@ -130,6 +130,8 @@ pub async fn create_patient( medical_history_summary: Set(req.medical_history_summary), emergency_contact_name: Set(req.emergency_contact_name), emergency_contact_phone: Set(req.emergency_contact_phone), + emergency_contact_phone_hash: Set(None), + key_version: Set(None), status: Set("active".to_string()), verification_status: Set("pending".to_string()), source: Set(req.source), diff --git a/crates/erp-server/migration/src/lib.rs b/crates/erp-server/migration/src/lib.rs index 505606a..cf89217 100644 --- a/crates/erp-server/migration/src/lib.rs +++ b/crates/erp-server/migration/src/lib.rs @@ -61,6 +61,9 @@ mod m20260426_000058_merge_daily_monitoring_into_vital_signs; mod m20260426_000059_seed_menus; mod m20260426_000060_create_critical_value_thresholds; mod m20260426_000061_create_consent; +mod m20260427_000062_create_tenant_crypto_keys; +mod m20260427_000063_content_management; +mod m20260427_000064_add_patient_pii_fields; pub struct Migrator; @@ -129,6 +132,9 @@ impl MigratorTrait for Migrator { Box::new(m20260426_000059_seed_menus::Migration), Box::new(m20260426_000060_create_critical_value_thresholds::Migration), Box::new(m20260426_000061_create_consent::Migration), + Box::new(m20260427_000062_create_tenant_crypto_keys::Migration), + Box::new(m20260427_000063_content_management::Migration), + Box::new(m20260427_000064_add_patient_pii_fields::Migration), ] } } diff --git a/crates/erp-server/migration/src/m20260427_000064_add_patient_pii_fields.rs b/crates/erp-server/migration/src/m20260427_000064_add_patient_pii_fields.rs new file mode 100644 index 0000000..4db44db --- /dev/null +++ b/crates/erp-server/migration/src/m20260427_000064_add_patient_pii_fields.rs @@ -0,0 +1,56 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Patient::Table) + .add_column(ColumnDef::new(Patient::EmergencyContactPhoneHash).string_len(64).null()) + .add_column(ColumnDef::new(Patient::KeyVersion).integer().null()) + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .name("idx_patient_emergency_phone_hash") + .table(Patient::Table) + .col(Patient::EmergencyContactPhoneHash) + .to_owned(), + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_index(Index::drop().name("idx_patient_emergency_phone_hash").to_owned()) + .await?; + + manager + .alter_table( + Table::alter() + .table(Patient::Table) + .drop_column(Patient::EmergencyContactPhoneHash) + .drop_column(Patient::KeyVersion) + .to_owned(), + ) + .await?; + + Ok(()) + } +} + +#[derive(DeriveIden)] +enum Patient { + Table, + EmergencyContactPhoneHash, + KeyVersion, +}