Files
akmon/GLOBAL_CONFIG_MIGRATION_GUIDE.md
2026-01-20 08:04:15 +08:00

8.6 KiB
Raw Permalink Blame History

全局配置表迁移实施指南

概述

当前 comindex.uvue 使用的是 key 后缀方式的全局配置(如 company_name_zh),需要迁移到新的主表+翻译表设计。

当前状态分析

当前使用的表结构

-- 原有设计key后缀方式
ak_global_configs (
    config_key VARCHAR,  -- 如: company_name_zh, company_name_en
    config_value TEXT,
    config_type VARCHAR,
    is_active BOOLEAN
)

新设计的表结构

-- 新设计(主表+翻译表)
ak_global_config (
    id UUID,
    config_key VARCHAR,     -- 如: company_name
    config_category VARCHAR,
    is_translatable BOOLEAN,
    default_value TEXT
)

ak_global_config_translations (
    config_id UUID,
    language_code VARCHAR,  -- zh, en, tw, ja
    translated_value TEXT
)

迁移步骤

1. 数据库迁移

Step 1: 创建新表结构

# 执行新表结构创建脚本
psql -h your-host -U your-user -d your-db -f improved_global_config_with_translation.sql

Step 2: 数据迁移脚本

创建数据迁移脚本:

-- migrate_global_config_data.sql
DO $$
DECLARE
    config_record RECORD;
    zh_value TEXT;
    en_value TEXT;
    tw_value TEXT;
    ja_value TEXT;
BEGIN
    -- 迁移公司名称
    SELECT config_value INTO zh_value FROM ak_global_configs WHERE config_key = 'company_name_zh' AND is_active = true;
    SELECT config_value INTO en_value FROM ak_global_configs WHERE config_key = 'company_name_en' AND is_active = true;
    SELECT config_value INTO tw_value FROM ak_global_configs WHERE config_key = 'company_name_tw' AND is_active = true;
    SELECT config_value INTO ja_value FROM ak_global_configs WHERE config_key = 'company_name_ja' AND is_active = true;
    
    -- 插入主配置
    INSERT INTO ak_global_config (config_key, config_category, is_translatable, sort_order)
    VALUES ('company_name', 'company', true, 1)
    ON CONFLICT (config_key) DO NOTHING;
    
    -- 获取配置ID并插入翻译
    SELECT id INTO config_record FROM ak_global_config WHERE config_key = 'company_name';
    
    IF zh_value IS NOT NULL THEN
        INSERT INTO ak_global_config_translations (config_id, language_code, translated_value)
        VALUES (config_record.id, 'zh', zh_value)
        ON CONFLICT (config_id, language_code) DO UPDATE SET translated_value = EXCLUDED.translated_value;
    END IF;
    
    IF en_value IS NOT NULL THEN
        INSERT INTO ak_global_config_translations (config_id, language_code, translated_value)
        VALUES (config_record.id, 'en', en_value)
        ON CONFLICT (config_id, language_code) DO UPDATE SET translated_value = EXCLUDED.translated_value;
    END IF;
    
    IF tw_value IS NOT NULL THEN
        INSERT INTO ak_global_config_translations (config_id, language_code, translated_value)
        VALUES (config_record.id, 'tw', tw_value)
        ON CONFLICT (config_id, language_code) DO UPDATE SET translated_value = EXCLUDED.translated_value;
    END IF;
    
    IF ja_value IS NOT NULL THEN
        INSERT INTO ak_global_config_translations (config_id, language_code, translated_value)
        VALUES (config_record.id, 'ja', ja_value)
        ON CONFLICT (config_id, language_code) DO UPDATE SET translated_value = EXCLUDED.translated_value;
    END IF;
    
    -- 迁移公司标语
    SELECT config_value INTO zh_value FROM ak_global_configs WHERE config_key = 'company_slogan_zh' AND is_active = true;
    SELECT config_value INTO en_value FROM ak_global_configs WHERE config_key = 'company_slogan_en' AND is_active = true;
    SELECT config_value INTO tw_value FROM ak_global_configs WHERE config_key = 'company_slogan_tw' AND is_active = true;
    SELECT config_value INTO ja_value FROM ak_global_configs WHERE config_key = 'company_slogan_ja' AND is_active = true;
    
    INSERT INTO ak_global_config (config_key, config_category, is_translatable, sort_order)
    VALUES ('company_slogan', 'company', true, 2)
    ON CONFLICT (config_key) DO NOTHING;
    
    SELECT id INTO config_record FROM ak_global_config WHERE config_key = 'company_slogan';
    
    IF zh_value IS NOT NULL THEN
        INSERT INTO ak_global_config_translations (config_id, language_code, translated_value)
        VALUES (config_record.id, 'zh', zh_value)
        ON CONFLICT (config_id, language_code) DO UPDATE SET translated_value = EXCLUDED.translated_value;
    END IF;
    
    IF en_value IS NOT NULL THEN
        INSERT INTO ak_global_config_translations (config_id, language_code, translated_value)
        VALUES (config_record.id, 'en', en_value)
        ON CONFLICT (config_id, language_code) DO UPDATE SET translated_value = EXCLUDED.translated_value;
    END IF;
    
    IF tw_value IS NOT NULL THEN
        INSERT INTO ak_global_config_translations (config_id, language_code, translated_value)
        VALUES (config_record.id, 'tw', tw_value)
        ON CONFLICT (config_id, language_code) DO UPDATE SET translated_value = EXCLUDED.translated_value;
    END IF;
    
    IF ja_value IS NOT NULL THEN
        INSERT INTO ak_global_config_translations (config_id, language_code, translated_value)
        VALUES (config_record.id, 'ja', ja_value)
        ON CONFLICT (config_id, language_code) DO UPDATE SET translated_value = EXCLUDED.translated_value;
    END IF;
    
    -- 继续迁移其他配置项...
    -- (公司地址、热门搜索等,按照相同模式)
    
    RAISE NOTICE '数据迁移完成!';
END $$;

2. 前端代码更新

当前代码问题

// 当前使用的旧方式
const result = await supa
  .from('ak_global_configs')  // 复数表名
  .select('*')
  .eq('is_active', true)

// 基于语言后缀的配置获取
const nameConfig = companyConfigMap.value.get(`company_name${langSuffix}`)

解决方案

我已经在 comindex.uvue 中添加了新的配置加载函数,它支持:

  1. 主方法: 使用 RPC 函数 get_config_by_language
  2. 备用方法: 查询视图 vw_global_config_multilingual
  3. 兜底方案: 使用硬编码的默认值

迁移验证

// 测试新配置加载
const testNewConfig = async () => {
  try {
    const { data, error } = await supa
      .rpc('get_config_by_language', { lang_code: 'zh' })
    
    console.log('新配置系统测试:', data)
    
    if (error) {
      console.error('RPC调用失败:', error)
      
      // 测试备用方法
      const { data: fallbackData } = await supa
        .from('vw_global_config_multilingual')
        .select('*')
        .eq('language_code', 'zh')
        .eq('is_active', true)
      
      console.log('备用方法测试:', fallbackData)
    }
  } catch (e) {
    console.error('配置测试失败:', e)
  }
}

3. 渐进式迁移策略

阶段1: 并行运行

  • 保持原有 ak_global_configs 表不变
  • 新建 ak_global_configak_global_config_translations
  • 前端代码支持两种方式,优先使用新方式

阶段2: 数据同步

  • 将原有数据迁移到新表结构
  • 验证数据完整性和功能正常性
  • 监控性能和错误

阶段3: 完全切换

  • 前端代码移除旧方式的兼容代码
  • 删除或重命名原有表(如有需要)

4. 验证清单

数据验证

  • 所有配置项都已迁移到新表
  • 多语言翻译完整且正确
  • 配置分类和排序正确
  • 非翻译配置项的默认值正确

功能验证

  • 页面加载时配置正确显示
  • 语言切换时配置正确更新
  • 错误处理和默认值生效
  • 性能满足要求

兼容性验证

  • 新旧系统可以并行运行
  • 备用方案正常工作
  • 数据回滚方案可行

5. 回滚计划

如果迁移出现问题,可以:

  1. 立即回滚: 在前端代码中禁用新配置方式
  2. 数据回滚: 从备份恢复原有表数据
  3. 配置回滚: 重新启用旧的配置获取逻辑

6. 监控和优化

性能监控

  • 配置加载时间
  • 数据库查询性能
  • 错误率和成功率

优化建议

  • 配置数据缓存
  • 批量查询优化
  • 索引优化

部署建议

测试环境部署

  1. 执行 improved_global_config_with_translation.sql
  2. 执行数据迁移脚本
  3. 部署更新后的前端代码
  4. 进行功能测试

生产环境部署

  1. 维护窗口期间执行数据库迁移
  2. 部署前端代码更新
  3. 监控系统运行状况
  4. 准备快速回滚方案

总结

新的全局配置系统提供了:

  • 更科学的数据结构设计
  • 更易维护的多语言支持
  • 更好的扩展性和灵活性
  • 向后兼容的迁移方案

通过渐进式迁移,可以确保业务连续性,同时升级到更现代化的配置管理方案。