From 577d2a32b1734138903ff1599f1766c9c673996c Mon Sep 17 00:00:00 2001 From: iven Date: Fri, 1 May 2026 08:04:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(db):=20=E6=B7=BB=E5=8A=A0=20ai=5Fsuggestio?= =?UTF-8?q?n=20=E5=92=8C=20ai=5Frisk=5Fthreshold=20=E8=A1=A8=E8=BF=81?= =?UTF-8?q?=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ai_suggestion: AI 建议记录表,含 tenant_id、analysis_id、suggestion_type、 risk_level、status、params、baseline_snapshot 等字段 - ai_risk_threshold: 租户级风险阈值配置表,按 metric_name + tenant_id 唯一索引 - 两表均包含标准审计字段和 version_lock 乐观锁 --- crates/erp-server/migration/src/lib.rs | 4 + .../m20260501_000098_create_ai_suggestion.rs | 98 +++++++++++++++++++ ...0260501_000099_create_ai_risk_threshold.rs | 74 ++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 crates/erp-server/migration/src/m20260501_000098_create_ai_suggestion.rs create mode 100644 crates/erp-server/migration/src/m20260501_000099_create_ai_risk_threshold.rs diff --git a/crates/erp-server/migration/src/lib.rs b/crates/erp-server/migration/src/lib.rs index 12fe4aa..7e1fd2b 100644 --- a/crates/erp-server/migration/src/lib.rs +++ b/crates/erp-server/migration/src/lib.rs @@ -97,6 +97,8 @@ mod m20260429_000094_device_readings_unique_constraint; mod m20260429_000095_seed_alert_device_menus; mod m20260430_000096_create_medication_reminder; mod m20260501_000097_seed_menu_permissions; +mod m20260501_000098_create_ai_suggestion; +mod m20260501_000099_create_ai_risk_threshold; pub struct Migrator; @@ -201,6 +203,8 @@ impl MigratorTrait for Migrator { Box::new(m20260429_000095_seed_alert_device_menus::Migration), Box::new(m20260430_000096_create_medication_reminder::Migration), Box::new(m20260501_000097_seed_menu_permissions::Migration), + Box::new(m20260501_000098_create_ai_suggestion::Migration), + Box::new(m20260501_000099_create_ai_risk_threshold::Migration), ] } } diff --git a/crates/erp-server/migration/src/m20260501_000098_create_ai_suggestion.rs b/crates/erp-server/migration/src/m20260501_000098_create_ai_suggestion.rs new file mode 100644 index 0000000..d0a3880 --- /dev/null +++ b/crates/erp-server/migration/src/m20260501_000098_create_ai_suggestion.rs @@ -0,0 +1,98 @@ +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 + .create_table( + Table::create() + .table(Alias::new("ai_suggestion")) + .col( + ColumnDef::new(Alias::new("id")) + .uuid() + .not_null() + .primary_key() + .default(Expr::cust("gen_random_uuid()")), + ) + .col(ColumnDef::new(Alias::new("tenant_id")).uuid().not_null()) + .col(ColumnDef::new(Alias::new("analysis_id")).uuid().not_null()) + .col( + ColumnDef::new(Alias::new("suggestion_type")) + .string_len(20) + .not_null(), + ) + .col( + ColumnDef::new(Alias::new("risk_level")) + .string_len(10) + .not_null(), + ) + .col(ColumnDef::new(Alias::new("params")).json_binary().not_null()) + .col( + ColumnDef::new(Alias::new("status")) + .string_len(20) + .not_null() + .default("pending"), + ) + .col(ColumnDef::new(Alias::new("workflow_instance_id")).uuid()) + .col(ColumnDef::new(Alias::new("action_result")).json_binary()) + .col(ColumnDef::new(Alias::new("baseline_snapshot")).json_binary()) + .col(ColumnDef::new(Alias::new("reanalysis_id")).uuid()) + .col( + ColumnDef::new(Alias::new("created_at")) + .timestamp_with_time_zone() + .default(Expr::cust("NOW()")), + ) + .col( + ColumnDef::new(Alias::new("updated_at")) + .timestamp_with_time_zone() + .default(Expr::cust("NOW()")), + ) + .col(ColumnDef::new(Alias::new("created_by")).uuid()) + .col(ColumnDef::new(Alias::new("updated_by")).uuid()) + .col( + ColumnDef::new(Alias::new("deleted_at")).timestamp_with_time_zone(), + ) + .col( + ColumnDef::new(Alias::new("version_lock")) + .integer() + .not_null() + .default(1), + ) + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .name("idx_ai_suggestion_tenant_analysis") + .table(Alias::new("ai_suggestion")) + .col(Alias::new("tenant_id")) + .col(Alias::new("analysis_id")) + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .name("idx_ai_suggestion_tenant_status") + .table(Alias::new("ai_suggestion")) + .col(Alias::new("tenant_id")) + .col(Alias::new("status")) + .to_owned(), + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(Alias::new("ai_suggestion")).to_owned()) + .await + } +} diff --git a/crates/erp-server/migration/src/m20260501_000099_create_ai_risk_threshold.rs b/crates/erp-server/migration/src/m20260501_000099_create_ai_risk_threshold.rs new file mode 100644 index 0000000..99e2057 --- /dev/null +++ b/crates/erp-server/migration/src/m20260501_000099_create_ai_risk_threshold.rs @@ -0,0 +1,74 @@ +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 + .create_table( + Table::create() + .table(Alias::new("ai_risk_threshold")) + .col( + ColumnDef::new(Alias::new("id")) + .uuid() + .not_null() + .primary_key() + .default(Expr::cust("gen_random_uuid()")), + ) + .col(ColumnDef::new(Alias::new("tenant_id")).uuid().not_null()) + .col( + ColumnDef::new(Alias::new("metric_name")) + .string_len(50) + .not_null(), + ) + .col(ColumnDef::new(Alias::new("low_threshold")).json_binary()) + .col(ColumnDef::new(Alias::new("medium_threshold")).json_binary()) + .col(ColumnDef::new(Alias::new("high_threshold")).json_binary()) + .col( + ColumnDef::new(Alias::new("created_at")) + .timestamp_with_time_zone() + .default(Expr::cust("NOW()")), + ) + .col( + ColumnDef::new(Alias::new("updated_at")) + .timestamp_with_time_zone() + .default(Expr::cust("NOW()")), + ) + .col(ColumnDef::new(Alias::new("created_by")).uuid()) + .col(ColumnDef::new(Alias::new("updated_by")).uuid()) + .col( + ColumnDef::new(Alias::new("deleted_at")).timestamp_with_time_zone(), + ) + .col( + ColumnDef::new(Alias::new("version_lock")) + .integer() + .not_null() + .default(1), + ) + .to_owned(), + ) + .await?; + + manager + .create_index( + Index::create() + .name("idx_ai_risk_threshold_tenant_metric") + .table(Alias::new("ai_risk_threshold")) + .col(Alias::new("tenant_id")) + .col(Alias::new("metric_name")) + .unique() + .to_owned(), + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(Alias::new("ai_risk_threshold")).to_owned()) + .await + } +}