feat(health): 积分规则查重 — 同租户同事件类型不可重复创建

- 新增迁移 m20260526_000163:points_rule (tenant_id, event_type) 部分唯一索引(排除软删除行)
- 后端 create_rule 添加 event_type 查重,重复时返回 400 Validation 错误
- 前端 PointsRuleList 提取后端错误消息展示给用户
This commit is contained in:
iven
2026-05-26 01:09:21 +08:00
parent 8027cdd1d9
commit d7fb5da873
4 changed files with 60 additions and 2 deletions

View File

@@ -169,6 +169,7 @@ mod m20260521_000164_reorganize_menus_scheme_b;
mod m20260522_000160_article_add_is_public;
mod m20260522_000161_patient_points_manage_perm;
mod m20260522_000162_seed_patient_miniprogram_permissions;
mod m20260526_000163_points_rule_unique_event_type;
pub struct Migrator;
@@ -345,6 +346,7 @@ impl MigratorTrait for Migrator {
Box::new(m20260522_000160_article_add_is_public::Migration),
Box::new(m20260522_000161_patient_points_manage_perm::Migration),
Box::new(m20260522_000162_seed_patient_miniprogram_permissions::Migration),
Box::new(m20260526_000163_points_rule_unique_event_type::Migration),
]
}
}

View File

@@ -0,0 +1,41 @@
use sea_orm_migration::prelude::*;
/// 为 points_rule 添加 (tenant_id, event_type) 唯一索引(排除软删除行)
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();
// 删除旧的非唯一索引
db.execute_unprepared("DROP INDEX IF EXISTS idx_points_rule_event_type")
.await?;
// 创建部分唯一索引(仅对未软删除的行生效)
db.execute_unprepared(
r#"
CREATE UNIQUE INDEX IF NOT EXISTS uq_points_rule_tenant_event
ON points_rule (tenant_id, event_type)
WHERE deleted_at IS NULL
"#,
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();
db.execute_unprepared("DROP INDEX IF EXISTS uq_points_rule_tenant_event")
.await?;
db.execute_unprepared(
"CREATE INDEX IF NOT EXISTS idx_points_rule_event_type ON points_rule (event_type)",
)
.await?;
Ok(())
}
}