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?;