feat: 新增多语言文案、优化导航及工具函数,修复部分业务逻辑

1. 新增多语言资源文件,覆盖文章、预约日期、会员信息、优惠券、表单、购物车、积分商城、分销、AI聊天等多个模块
2. 优化底部导航组件,使用多语言配置替代硬编码文案
3. 重构工具函数,新增从后端数据提取多语言文案的工具方法
4. 修复邀请好友页面的保存提示文案,替换为多语言版本
5. 修复商品SKU组件的提示文案,使用多语言配置
6. 重构AI聊天页面的帮助文档和回复模板,使用多语言配置
7. 优化空状态组件,支持多语言默认文案
8. 修复跳转逻辑,补全参数传递
9. 新增本地开发环境配置
This commit is contained in:
2026-06-25 18:15:31 +08:00
parent ca4e7fd170
commit 2d8846c64c
82 changed files with 3497 additions and 1062 deletions

View File

@@ -161,6 +161,52 @@ function applyLangParams(value, args) {
return result;
}
/**
* 从后端数据中提取当前语言的文案(向后兼容)
*
* 优先使用多语言 map(如 title_map / text_map),格式:
* { "zh-cn": "标题", "en-us": "Title" }
*
* 如果没有 map,回退到二元模式(兼容旧数据):
* field = 'title' → 取 title / en_title
* field = 'text' → 取 text / en_text
*
* @param {Object} data 后端数据对象
* @param {string} field 基础字段名(如 'title'、'text'、'goods_name')
* @param {string} [locale] 目标语言,默认取当前语言
* @returns {string} 对应语言的文案,找不到返回空串
*/
function getI18nField(data, field, locale) {
if (!data || !field) return '';
const lang = locale || getCurrentLocale();
// 1) 优先尝试多语言 map: title_map / text_map / goods_name_map
const mapKey = field + '_map';
const map = data[mapKey];
if (map && typeof map === 'object' && !Array.isArray(map)) {
// 精确匹配当前语言
if (map[lang] !== undefined && map[lang] !== null && map[lang] !== '') {
return String(map[lang]);
}
// 兜底:取第一个非空值
for (const k of Object.keys(map)) {
if (map[k] !== undefined && map[k] !== null && map[k] !== '') {
return String(map[k]);
}
}
}
// 2) 回退到二元模式: field / en_field
const enKey = 'en_' + field;
if (lang === 'en-us' && data[enKey] !== undefined && data[enKey] !== '') {
return String(data[enKey]);
}
if (data[field] !== undefined && data[field] !== '') {
return String(data[field]);
}
return '';
}
// 远端覆写:内存缓存
// shape: { [app_lang]: { version, map, ts, global_version } }
// key 格式 `${appType}_${lang}`,天然按平台 + 语种二维隔离,避免多端 cache 串味
@@ -487,6 +533,23 @@ export default {
*/
getCurrentLocale,
/**
* 从后端数据中提取当前语言的文案(向后兼容)
* 优先使用 xxx_map 多语言 map,没有则回退到 xxx / en_xxx 二元模式
*
* 用法:
* this.$langConfig.getField(item, 'title') // 取标题
* this.$langConfig.getField(item, 'text') // 取 tabBar 文案
* this.$langConfig.getField(item, 'goods_name') // 取商品名
*
* @param {Object} data 后端数据对象
* @param {string} field 基础字段名
* @returns {string}
*/
getField(data, field) {
return getI18nField(data, field);
},
/**
* 当前租户 id
*/