diff --git a/src/api/user.ts b/src/api/user.ts index 815fac8..9e7da8c 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -108,3 +108,20 @@ export const verifyEmailCode = (verifyCode: string): Promise => { data: { verifyCode } }) } + +// 获取用户语言设置 +export const getUserLanguage = (): Promise => { + return request({ + url: '/buyer/profile/getLanguage', + method: 'post' + }) +} + +// 设置语言 +export const setUserLanguage = (language: string): Promise => { + return request({ + url: '/buyer/profile/setLanguage', + method: 'post', + data: { language } + }) +} \ No newline at end of file diff --git a/src/router/index.ts b/src/router/index.ts index 288abb4..e166ef3 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,4 +1,16 @@ import { createRouter, createWebHistory } from 'vue-router' +import { useUserInfoStore } from '@/stores/userInfo' +import { getUserLanguage } from '@/api/user' +import i18n from '@/lang/index' + +// 语言映射:后端格式 -> i18n 格式 +const backendToI18nLanguage: Record = { + 'en': 'ENGLISH', + 'zh-CN': 'CHINESE_SIMPLIFIED' +} + +// 语言同步状态缓存(避免每次路由切换都请求) +let languageSynced = false /** * 路由缓存机制: @@ -83,6 +95,52 @@ router.beforeEach((to, from, next) => { next() }) -router.afterEach(() => {}) +router.afterEach(async () => { + // 检查用户是否已登录 + const userInfoStore = useUserInfoStore() + const token = userInfoStore.state.token + + if (!token) { + languageSynced = false // 未登录时重置同步状态 + return + } + + // 如果已经同步过,跳过 + if (languageSynced) { + return + } + + try { + // 获取用户语言设置 + const response = await getUserLanguage() + const userLanguage = (response as any)?.language // 后端返回 'en' 或 'zh-CN' + + if (!userLanguage) { + return + } + + // 转换为 i18n 格式 + const i18nLanguage = backendToI18nLanguage[userLanguage] + + if (!i18nLanguage) { + return + } + + // 获取当前 i18n 语言 + const currentLocale = i18n.global.locale.value + + // 如果用户语言和本地 i18n 不一致,更新 i18n + if (i18nLanguage !== currentLocale) { + i18n.global.locale.value = i18nLanguage as 'ENGLISH' | 'CHINESE_SIMPLIFIED' + localStorage.setItem('language', i18nLanguage) + } + + // 标记已同步 + languageSynced = true + } catch (error) { + // 静默失败,不影响页面正常加载 + console.warn('Failed to sync user language:', error) + } +}) export default router diff --git a/src/views/main-header.vue b/src/views/main-header.vue index 1eaf69f..fe65e9d 100644 --- a/src/views/main-header.vue +++ b/src/views/main-header.vue @@ -87,6 +87,8 @@ import myEvent from '@/utils/myEvent' import { useI18n } from 'vue-i18n' import { useUserInfoStore } from '@/stores/userInfo' + import { setUserLanguage } from '@/api/user' + const { t, locale } = useI18n() const userInfoStore = useUserInfoStore() const router = useRouter() @@ -153,6 +155,12 @@ const onLanguageClick = () => { locale.value = locale.value === 'ENGLISH' ? 'CHINESE_SIMPLIFIED' : 'ENGLISH' localStorage.setItem('language', locale.value) + console.log(locale.value) + const localeMap: Record = { + ENGLISH: 'en', + CHINESE_SIMPLIFIED: 'zh-CN' + } + setUserLanguage(localeMap[locale.value]) } diff --git a/src/views/setting/useSettingsForm.ts b/src/views/setting/useSettingsForm.ts index ddf0777..76ea11c 100644 --- a/src/views/setting/useSettingsForm.ts +++ b/src/views/setting/useSettingsForm.ts @@ -26,11 +26,24 @@ interface UseSettingsFormOptions { locale: Ref } +// 前端 UI 使用的语言值(用于下拉选择) const languageLocaleMap: Record = { english: 'ENGLISH', chinese: 'CHINESE_SIMPLIFIED' } +// 后端 API 使用的语言值 +const backendLanguageMap: Record<'ENGLISH' | 'CHINESE_SIMPLIFIED', 'en' | 'zh-CN'> = { + ENGLISH: 'en', + CHINESE_SIMPLIFIED: 'zh-CN' +} + +// 后端语言值转换为前端语言值 +const backendToFrontendLanguage: Record<'en' | 'zh-CN', LanguageValue> = { + en: 'english', + 'zh-CN': 'chinese' +} + const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ const createDefaultData = (): SettingsData => ({ @@ -58,8 +71,15 @@ const normalizeLanguage = (language: string | null | undefined): LanguageValue = return '' as LanguageValue } - const normalized = language.trim().toLowerCase() - return normalized.includes('chinese') ? 'chinese' : 'english' + // 后端返回 'en' 或 'zh-CN' + const trimmed = language.trim() + if (trimmed === 'en') { + return 'english' + } else if (trimmed === 'zh-CN') { + return 'chinese' + } + + return '' as LanguageValue } const buildSettingsDataFromProfile = (profile: Partial): SettingsData => ({ @@ -308,14 +328,20 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) { return } - const nextEmail = securityDraft.value.newEmail.trim() || draftData.value.email || '' + // 将前端语言值转换为后端格式 + let backendLanguage = '' + if (draftData.value.language) { + const i18nLocale = languageLocaleMap[draftData.value.language as LanguageValue] + backendLanguage = backendLanguageMap[i18nLocale] + } + const nextData: UserProfile = { firstName: draftData.value.firstName.trim(), lastName: draftData.value.lastName.trim(), username: draftData.value.username.trim(), - email: nextEmail, + email: securityDraft.value.newEmail.trim(), roles: draftData.value.roles as string[], - language: draftData.value.language, + language: backendLanguage, // 发送后端格式:'en' 或 'zh-CN' region: draftData.value.region, newPassword: '', oldPassword: '', @@ -337,26 +363,34 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) { try { await updateUserProfile(nextData) + + // 将后端返回的语言值转换为前端格式 + const frontendLanguage = backendLanguage + ? backendToFrontendLanguage[backendLanguage as 'en' | 'zh-CN'] + : '' + const settingsData: SettingsData = { firstName: nextData.firstName, lastName: nextData.lastName, username: nextData.username, email: nextData.email, roles: nextData.roles as RoleValue[], - language: nextData.language as LanguageValue | '', + language: frontendLanguage, region: nextData.region as any } sourceData.value = cloneSettingsData(settingsData) console.log(nextData) - if (nextData.language && nextData.language !== previousLanguage) { - syncAppLanguage(nextData.language as LanguageValue) + if (frontendLanguage && frontendLanguage !== previousLanguage) { + syncAppLanguage(frontendLanguage as LanguageValue) } draftData.value = cloneSettingsData(sourceData.value) securityDraft.value = createEmptySecurityDraft() resetEmailVerificationState() isEditing.value = false + isEditingEmail.value = false + isEditingPassword.value = false ElMessage.success(t('Settings.messages.settingsUpdated')) } catch (error) { console.warn(error)