268 lines
8.6 KiB
Markdown
268 lines
8.6 KiB
Markdown
# 全局配置表迁移实施指南
|
||
|
||
## 概述
|
||
当前 `comindex.uvue` 使用的是 key 后缀方式的全局配置(如 `company_name_zh`),需要迁移到新的主表+翻译表设计。
|
||
|
||
## 当前状态分析
|
||
|
||
### 当前使用的表结构
|
||
```sql
|
||
-- 原有设计(key后缀方式)
|
||
ak_global_configs (
|
||
config_key VARCHAR, -- 如: company_name_zh, company_name_en
|
||
config_value TEXT,
|
||
config_type VARCHAR,
|
||
is_active BOOLEAN
|
||
)
|
||
```
|
||
|
||
### 新设计的表结构
|
||
```sql
|
||
-- 新设计(主表+翻译表)
|
||
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: 创建新表结构
|
||
```bash
|
||
# 执行新表结构创建脚本
|
||
psql -h your-host -U your-user -d your-db -f improved_global_config_with_translation.sql
|
||
```
|
||
|
||
#### Step 2: 数据迁移脚本
|
||
创建数据迁移脚本:
|
||
|
||
```sql
|
||
-- 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. 前端代码更新
|
||
|
||
#### 当前代码问题
|
||
```javascript
|
||
// 当前使用的旧方式
|
||
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. **兜底方案**: 使用硬编码的默认值
|
||
|
||
#### 迁移验证
|
||
```javascript
|
||
// 测试新配置加载
|
||
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_config` 和 `ak_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. 准备快速回滚方案
|
||
|
||
## 总结
|
||
|
||
新的全局配置系统提供了:
|
||
- ✅ 更科学的数据结构设计
|
||
- ✅ 更易维护的多语言支持
|
||
- ✅ 更好的扩展性和灵活性
|
||
- ✅ 向后兼容的迁移方案
|
||
|
||
通过渐进式迁移,可以确保业务连续性,同时升级到更现代化的配置管理方案。
|