From d2a0c8efc0ae8b14da19a26848c32abca8bcea08 Mon Sep 17 00:00:00 2001 From: iven Date: Tue, 14 Apr 2026 18:35:24 +0800 Subject: [PATCH] =?UTF-8?q?fix(saas):=20=E5=90=AF=E5=8A=A8=E5=B4=A9?= =?UTF-8?q?=E6=BA=83=E4=BF=AE=E5=A4=8D=20=E2=80=94=20config=5Fitems=20?= =?UTF-8?q?=E7=BA=A6=E6=9D=9F=20+=20industry=20=E7=B1=BB=E5=9E=8B=E5=8C=B9?= =?UTF-8?q?=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - db.rs: config_items INSERT ON CONFLICT (id) → (category, key_path) 匹配实际唯一约束 - db.rs: fix_seed_data category 重命名前先删除冲突行,避免唯一约束冲突 - migration/service.rs: seed_default_config_items + sync push INSERT 同步修复 ON CONFLICT - industry/types.rs: keywords_count i64→i32 匹配 PostgreSQL INT4 列类型 Co-Authored-By: Claude Opus 4.6 --- crates/zclaw-saas/src/db.rs | 12 ++++++++++-- crates/zclaw-saas/src/industry/types.rs | 2 +- crates/zclaw-saas/src/migration/service.rs | 6 ++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/zclaw-saas/src/db.rs b/crates/zclaw-saas/src/db.rs index 848f438..5846b81 100644 --- a/crates/zclaw-saas/src/db.rs +++ b/crates/zclaw-saas/src/db.rs @@ -742,7 +742,7 @@ async fn seed_demo_data(pool: &PgPool) -> SaasResult<()> { let id = format!("cfg-{}-{}", cat, key); sqlx::query( "INSERT INTO config_items (id, category, key_path, value_type, current_value, default_value, source, description, created_at, updated_at) - VALUES ($1, $2, $3, $4, $5, $6, 'local', $7, $8, $8) ON CONFLICT (id) DO NOTHING" + VALUES ($1, $2, $3, $4, $5, $6, 'local', $7, $8, $8) ON CONFLICT (category, key_path) DO NOTHING" ).bind(&id).bind(cat).bind(key).bind(vtype).bind(current).bind(default).bind(desc).bind(&ts) .execute(pool).await?; } @@ -854,6 +854,7 @@ async fn fix_seed_data(pool: &PgPool) -> SaasResult<()> { let admin_ids: Vec = admins.into_iter().map(|(id,)| id).collect(); // 2. 更新 config_items 分类名(旧 → 新) + // 先删除目标 (category, key_path) 已存在的旧 category 行,避免唯一约束冲突 let category_mappings = [ ("server", "general"), ("llm", "model"), @@ -862,6 +863,13 @@ async fn fix_seed_data(pool: &PgPool) -> SaasResult<()> { ("security", "rate_limit"), ]; for (old_cat, new_cat) in &category_mappings { + // 删除旧 category 中与目标 category key_path 冲突的行 + sqlx::query( + "DELETE FROM config_items WHERE category = $1 AND key_path IN \ + (SELECT key_path FROM config_items WHERE category = $2)" + ).bind(old_cat).bind(new_cat) + .execute(pool).await?; + let result = sqlx::query( "UPDATE config_items SET category = $1, updated_at = $2 WHERE category = $3" ).bind(new_cat).bind(&now).bind(old_cat) @@ -889,7 +897,7 @@ async fn fix_seed_data(pool: &PgPool) -> SaasResult<()> { let id = format!("cfg-{}-{}", cat, key); sqlx::query( "INSERT INTO config_items (id, category, key_path, value_type, current_value, default_value, source, description, created_at, updated_at) - VALUES ($1, $2, $3, $4, $5, $6, 'local', $7, $8, $8) ON CONFLICT (id) DO NOTHING" + VALUES ($1, $2, $3, $4, $5, $6, 'local', $7, $8, $8) ON CONFLICT (category, key_path) DO NOTHING" ).bind(&id).bind(cat).bind(key).bind(vtype).bind(current).bind(default).bind(desc).bind(&now) .execute(pool).await?; } diff --git a/crates/zclaw-saas/src/industry/types.rs b/crates/zclaw-saas/src/industry/types.rs index 56f49ed..e1f76d4 100644 --- a/crates/zclaw-saas/src/industry/types.rs +++ b/crates/zclaw-saas/src/industry/types.rs @@ -29,7 +29,7 @@ pub struct IndustryListItem { pub description: String, pub status: String, pub source: String, - pub keywords_count: i64, + pub keywords_count: i32, pub created_at: chrono::DateTime, pub updated_at: chrono::DateTime, } diff --git a/crates/zclaw-saas/src/migration/service.rs b/crates/zclaw-saas/src/migration/service.rs index 06de888..52d5bb7 100644 --- a/crates/zclaw-saas/src/migration/service.rs +++ b/crates/zclaw-saas/src/migration/service.rs @@ -258,7 +258,8 @@ pub async fn seed_default_config_items(db: &PgPool) -> SaasResult { let id = uuid::Uuid::new_v4().to_string(); sqlx::query( "INSERT INTO config_items (id, category, key_path, value_type, current_value, default_value, source, description, requires_restart, created_at, updated_at) - VALUES ($1, $2, $3, $4, $5, $6, 'local', $7, false, $8, $8)" + VALUES ($1, $2, $3, $4, $5, $6, 'local', $7, false, $8, $8) + ON CONFLICT (category, key_path) DO NOTHING" ) .bind(&id).bind(category).bind(key_path).bind(value_type) .bind(current_value).bind(default_value).bind(description).bind(&now) @@ -374,7 +375,8 @@ pub async fn sync_config( let category = parts.first().unwrap_or(&"general").to_string(); sqlx::query( "INSERT INTO config_items (id, category, key_path, value_type, current_value, default_value, source, description, requires_restart, created_at, updated_at) - VALUES ($1, $2, $3, 'string', $4, $4, 'local', '客户端推送', false, $5, $5)" + VALUES ($1, $2, $3, 'string', $4, $4, 'local', '客户端推送', false, $5, $5) + ON CONFLICT (category, key_path) DO NOTHING" ) .bind(&id).bind(&category).bind(key).bind(val).bind(&now) .execute(db).await?;