feat(ai): Prompt 管理 Phase 2 — analysis_type 后端选择键 + 筛选修复

- 新增 ai_prompt.analysis_type 列作为后端按链路选择 Prompt 的唯一键
- name 回归显示标识符用途,不再承担选择键角色
- 迁移 000164: 新增 analysis_type 列 + 从 name 回填 + 索引
- 迁移 000165: 修复旧数据从 category 错误回填的问题
- AiPromptList 页面重构: 分析类型/调用链路列、详情抽屉、新建表单
- DrawerForm 组件新增 onValuesChange 回调支持跨字段联动
- 新建表单选择分析类型后自动填充标识符
- 筛选过滤器改为按 analysis_type 而非 category 过滤(后端+前端同步)
- 停用/激活/回滚/删除操作完整可用
This commit is contained in:
iven
2026-05-26 17:04:26 +08:00
parent 3972db4f98
commit 3c7b48b6f6
10 changed files with 549 additions and 165 deletions

View File

@@ -170,6 +170,8 @@ 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;
mod m20260526_000164_ai_prompt_add_analysis_type;
mod m20260526_000165_ai_prompt_fix_analysis_type;
pub struct Migrator;
@@ -347,6 +349,8 @@ impl MigratorTrait for Migrator {
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),
Box::new(m20260526_000164_ai_prompt_add_analysis_type::Migration),
Box::new(m20260526_000165_ai_prompt_fix_analysis_type::Migration),
]
}
}

View File

@@ -0,0 +1,47 @@
use sea_orm_migration::prelude::*;
/// ai_prompt 新增 analysis_type 列作为后端选择键name 回归显示名
#[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();
// 1. 新增 analysis_type 列(先允许 NULL 以便回填)
db.execute_unprepared(
"ALTER TABLE ai_prompt ADD COLUMN IF NOT EXISTS analysis_type VARCHAR(64)",
)
.await?;
// 2. 用 name 值回填 analysis_typename 在旧数据中就是后端选择键)
db.execute_unprepared(
"UPDATE ai_prompt SET analysis_type = name WHERE analysis_type IS NULL AND deleted_at IS NULL",
)
.await?;
// 3. 设置 NOT NULL 约束
db.execute_unprepared("ALTER TABLE ai_prompt ALTER COLUMN analysis_type SET NOT NULL")
.await?;
// 4. 为 analysis_type 创建索引(后端按此列查询激活 Prompt
db.execute_unprepared(
"CREATE INDEX IF NOT EXISTS idx_ai_prompt_analysis_type ON ai_prompt (tenant_id, analysis_type, is_active) 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 idx_ai_prompt_analysis_type")
.await?;
db.execute_unprepared("ALTER TABLE ai_prompt DROP COLUMN IF EXISTS analysis_type")
.await?;
Ok(())
}
}

View File

@@ -0,0 +1,23 @@
use sea_orm_migration::prelude::*;
/// 修复 ai_prompt.analysis_type 回填数据:从 name真正的后端选择键而非 category泛化标签
#[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(
"UPDATE ai_prompt SET analysis_type = name WHERE analysis_type != name AND deleted_at IS NULL",
)
.await?;
Ok(())
}
async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
Ok(())
}
}