Merge branch 'main' of http://18.167.251.121:10003/aidlab/Aida_Purchaser_Front
This commit is contained in:
@@ -146,7 +146,9 @@ export const getUserLanguage = (): Promise<ApiResponse> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置语言
|
// 设置语言
|
||||||
export const setUserLanguage = (language: string): Promise<ApiResponse> => {
|
export const setUserLanguage = (
|
||||||
|
language: 'ENGLISH' | 'CHINESE_SIMPLIFIED'
|
||||||
|
): Promise<ApiResponse> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/buyer/profile/setLanguage',
|
url: '/buyer/profile/setLanguage',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export default {
|
|||||||
avatarCrop: {
|
avatarCrop: {
|
||||||
title: 'Crop Avatar',
|
title: 'Crop Avatar',
|
||||||
confirm: 'Confirm',
|
confirm: 'Confirm',
|
||||||
processing: 'Processing...',
|
processing: 'Processing...'
|
||||||
},
|
},
|
||||||
security: {
|
security: {
|
||||||
title: 'Security',
|
title: 'Security',
|
||||||
@@ -159,8 +159,8 @@ export default {
|
|||||||
other: 'Other'
|
other: 'Other'
|
||||||
},
|
},
|
||||||
languages: {
|
languages: {
|
||||||
english: 'English',
|
ENGLISH: 'English',
|
||||||
chinese: 'Chinese'
|
CHINESE_SIMPLIFIED: 'Chinese Simplified'
|
||||||
},
|
},
|
||||||
regions: {
|
regions: {
|
||||||
hongKongSar: 'Hong Kong SAR',
|
hongKongSar: 'Hong Kong SAR',
|
||||||
@@ -338,34 +338,41 @@ export default {
|
|||||||
AddToCart: 'Add to Cart'
|
AddToCart: 'Add to Cart'
|
||||||
},
|
},
|
||||||
Home: {
|
Home: {
|
||||||
IndexTitle: 'We’re Seeking<br /><span>Fashion Voice</span><br /><span class="small">Worth Featuring.</span>',
|
IndexTitle:
|
||||||
IndexTip: 'Discover collections through the stories behind their creation. A curated space connecting designers, narratives, and fashion commerce.',
|
'We’re Seeking<br /><span>Fashion Voice</span><br /><span class="small">Worth Featuring.</span>',
|
||||||
|
IndexTip:
|
||||||
|
'Discover collections through the stories behind their creation. A curated space connecting designers, narratives, and fashion commerce.',
|
||||||
DesignerTitle: 'Designer Community',
|
DesignerTitle: 'Designer Community',
|
||||||
DesignerTip: 'Discover the designers shaping AiDA’s creative landscape. <br />Each month, we will showcase a curated selection of their most distinguished works.',
|
DesignerTip:
|
||||||
|
'Discover the designers shaping AiDA’s creative landscape. <br />Each month, we will showcase a curated selection of their most distinguished works.',
|
||||||
SearchBrands: 'Search Brands',
|
SearchBrands: 'Search Brands',
|
||||||
AidaTitle: 'Design with AiDA',
|
AidaTitle: 'Design with AiDA',
|
||||||
AidaTip: 'Each garment on this platform is where designer vision blooms through AiDA. A tool that nurtures your creativity, never overshadows it. Let your ideas flourish.',
|
AidaTip:
|
||||||
|
'Each garment on this platform is where designer vision blooms through AiDA. A tool that nurtures your creativity, never overshadows it. Let your ideas flourish.',
|
||||||
TryNow: 'Try Now',
|
TryNow: 'Try Now',
|
||||||
DigitalItems: 'Digital Items',
|
DigitalItems: 'Digital Items',
|
||||||
DigitalItemsTip1: 'AiDA captures your boldest thoughts and transforms them into vivid<br/>digital visions—a virtual realm where creativity collides and evolves.',
|
DigitalItemsTip1:
|
||||||
DigitalItemsTip2: 'AiDA accelerates style innovation, shaping daily pieces that keep<br/>your wardrobe in sync with modern fashion’s rhythm.',
|
'AiDA captures your boldest thoughts and transforms them into vivid<br/>digital visions—a virtual realm where creativity collides and evolves.',
|
||||||
FooterTip: "Stylish Parade is a commerce platform for designers, serving as AiDA's commercial extension.",
|
DigitalItemsTip2:
|
||||||
FooterAidaTip: "Bloom your Creativity with AiDA!",
|
'AiDA accelerates style innovation, shaping daily pieces that keep<br/>your wardrobe in sync with modern fashion’s rhythm.',
|
||||||
Help: "Help",
|
FooterTip:
|
||||||
FAQ: "FAQ",
|
"Stylish Parade is a commerce platform for designers, serving as AiDA's commercial extension.",
|
||||||
MyAccount: "My Account",
|
FooterAidaTip: 'Bloom your Creativity with AiDA!',
|
||||||
MyOrders: "My Orders",
|
Help: 'Help',
|
||||||
PaymentInvoices: "Payment and Invoices",
|
FAQ: 'FAQ',
|
||||||
CopyrightLicense: "Copyright Licence",
|
MyAccount: 'My Account',
|
||||||
Polices: "Policies",
|
MyOrders: 'My Orders',
|
||||||
Legal: "Legal",
|
PaymentInvoices: 'Payment and Invoices',
|
||||||
PrivacyPolicy: "Privacy Policy",
|
CopyrightLicense: 'Copyright Licence',
|
||||||
CookiesSettings: "Cookies Settings",
|
Polices: 'Policies',
|
||||||
PurchaseConditions: "Purchase Conditions",
|
Legal: 'Legal',
|
||||||
Company: "Company",
|
PrivacyPolicy: 'Privacy Policy',
|
||||||
AboutUs: "About Us",
|
CookiesSettings: 'Cookies Settings',
|
||||||
Offices: "Offices",
|
PurchaseConditions: 'Purchase Conditions',
|
||||||
JoinWithUs: "Join with Us",
|
Company: 'Company',
|
||||||
|
AboutUs: 'About Us',
|
||||||
|
Offices: 'Offices',
|
||||||
|
JoinWithUs: 'Join with Us'
|
||||||
},
|
},
|
||||||
addShoppingCart: {
|
addShoppingCart: {
|
||||||
title: 'Added to your Shopping Cart',
|
title: 'Added to your Shopping Cart',
|
||||||
@@ -394,18 +401,22 @@ export default {
|
|||||||
OrderSummary: 'Order Summary',
|
OrderSummary: 'Order Summary',
|
||||||
PaymentDetails: 'Payment Details',
|
PaymentDetails: 'Payment Details',
|
||||||
CreditDebitCard: 'Credit / Debit Card',
|
CreditDebitCard: 'Credit / Debit Card',
|
||||||
AgreementText: 'I agree to the <span onclick="{onTermsClick}">Terms & Conditions</span> and <span onclick="{onPrivacyClick}">Privacy Policy</span>. All digital item sales are final and non-refundable.',
|
AgreementText:
|
||||||
|
'I agree to the <span onclick="{onTermsClick}">Terms & Conditions</span> and <span onclick="{onPrivacyClick}">Privacy Policy</span>. All digital item sales are final and non-refundable.',
|
||||||
PayWithStripe: 'Pay with Stripe',
|
PayWithStripe: 'Pay with Stripe',
|
||||||
PayWith: 'Pay with',
|
PayWith: 'Pay with',
|
||||||
Cancel: 'Cancel',
|
Cancel: 'Cancel',
|
||||||
IHaveCompletedPayment: 'I Have Completed payment',
|
IHaveCompletedPayment: 'I Have Completed payment',
|
||||||
Back: 'Back',
|
Back: 'Back',
|
||||||
PayTip1: "You'll be redirected to a Stripe popup to log in and confirm. No card details are shared with Stylish Parade — Stripe handles all payment security.",
|
PayTip1:
|
||||||
PayTip2: "Please keep the window open until the payment is completed. If you are to open the payment window, please check your browser settings to see if pop-ups are being blocked. Points may be delayed after successful payment. Please wait 1-3 minutes and click the credits refresh button.",
|
"You'll be redirected to a Stripe popup to log in and confirm. No card details are shared with Stylish Parade — Stripe handles all payment security.",
|
||||||
PurchaseSuccessful: "Purchase Successful",
|
PayTip2:
|
||||||
PurchaseSuccessfulTip: "Your digital items are now available and have been saved in Personal Center → My Wardrobe.",
|
'Please keep the window open until the payment is completed. If you are to open the payment window, please check your browser settings to see if pop-ups are being blocked. Points may be delayed after successful payment. Please wait 1-3 minutes and click the credits refresh button.',
|
||||||
DownloadAllAssets: "download all Assets",
|
PurchaseSuccessful: 'Purchase Successful',
|
||||||
ExportInvoice: "Export Invoice",
|
PurchaseSuccessfulTip:
|
||||||
ContinueShopping: "Continue Shopping"
|
'Your digital items are now available and have been saved in Personal Center → My Wardrobe.',
|
||||||
|
DownloadAllAssets: 'download all Assets',
|
||||||
|
ExportInvoice: 'Export Invoice',
|
||||||
|
ContinueShopping: 'Continue Shopping'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export default {
|
|||||||
avatarCrop: {
|
avatarCrop: {
|
||||||
title: '裁剪头像',
|
title: '裁剪头像',
|
||||||
confirm: '确认',
|
confirm: '确认',
|
||||||
processing: '处理中...',
|
processing: '处理中...'
|
||||||
},
|
},
|
||||||
security: {
|
security: {
|
||||||
title: '安全',
|
title: '安全',
|
||||||
@@ -154,8 +154,8 @@ export default {
|
|||||||
other: '其他'
|
other: '其他'
|
||||||
},
|
},
|
||||||
languages: {
|
languages: {
|
||||||
english: '英文',
|
ENGLISH: '英文',
|
||||||
chinese: '中文'
|
CHINESE_SIMPLIFIED: '简体中文'
|
||||||
},
|
},
|
||||||
regions: {
|
regions: {
|
||||||
hongKongSar: '中国香港特别行政区',
|
hongKongSar: '中国香港特别行政区',
|
||||||
@@ -393,18 +393,21 @@ export default {
|
|||||||
OrderSummary: '订单信息',
|
OrderSummary: '订单信息',
|
||||||
PaymentDetails: '支付详情',
|
PaymentDetails: '支付详情',
|
||||||
CreditDebitCard: '信用卡/借记卡',
|
CreditDebitCard: '信用卡/借记卡',
|
||||||
AgreementText: '我同意 <span onclick="{onTermsClick}">使用条款与条件</span> 和 <span onclick="{onPrivacyClick}">隐私政策</span>。所有数字资产销售均为最终销售,不可退款。',
|
AgreementText:
|
||||||
|
'我同意 <span onclick="{onTermsClick}">使用条款与条件</span> 和 <span onclick="{onPrivacyClick}">隐私政策</span>。所有数字资产销售均为最终销售,不可退款。',
|
||||||
PayWithStripe: '使用 Stripe 支付',
|
PayWithStripe: '使用 Stripe 支付',
|
||||||
PayWith: '支付',
|
PayWith: '支付',
|
||||||
Cancel: '取消',
|
Cancel: '取消',
|
||||||
IHaveCompletedPayment: '我已完成支付',
|
IHaveCompletedPayment: '我已完成支付',
|
||||||
Back: '返回',
|
Back: '返回',
|
||||||
PayTip1: "您将被重定向到 Stripe 弹窗以登录并确认支付。您的信用卡信息不会被 Stylish Parade 收集。Stripe 处理所有支付安全。",
|
PayTip1:
|
||||||
PayTip2: "请保持窗口打开,直到支付完成。如果您打开支付窗口,请检查浏览器设置以查看是否已阻止弹窗。支付完成后,积分可能会有延迟。请等待 1-3 分钟并点击积分刷新按钮。",
|
'您将被重定向到 Stripe 弹窗以登录并确认支付。您的信用卡信息不会被 Stylish Parade 收集。Stripe 处理所有支付安全。',
|
||||||
PurchaseSuccessful: "购买成功",
|
PayTip2:
|
||||||
PurchaseSuccessfulTip: "您的数字资产已保存在个人中心的我的衣橱中。",
|
'请保持窗口打开,直到支付完成。如果您打开支付窗口,请检查浏览器设置以查看是否已阻止弹窗。支付完成后,积分可能会有延迟。请等待 1-3 分钟并点击积分刷新按钮。',
|
||||||
DownloadAllAssets: "下载所有资产",
|
PurchaseSuccessful: '购买成功',
|
||||||
ExportInvoice: "导出发票",
|
PurchaseSuccessfulTip: '您的数字资产已保存在个人中心的我的衣橱中。',
|
||||||
ContinueShopping: "继续购物"
|
DownloadAllAssets: '下载所有资产',
|
||||||
|
ExportInvoice: '导出发票',
|
||||||
|
ContinueShopping: '继续购物'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,12 +175,11 @@
|
|||||||
const onLanguageClick = () => {
|
const onLanguageClick = () => {
|
||||||
locale.value = locale.value === 'ENGLISH' ? 'CHINESE_SIMPLIFIED' : 'ENGLISH'
|
locale.value = locale.value === 'ENGLISH' ? 'CHINESE_SIMPLIFIED' : 'ENGLISH'
|
||||||
localStorage.setItem('language', locale.value)
|
localStorage.setItem('language', locale.value)
|
||||||
console.log(locale.value)
|
|
||||||
const localeMap: Record<string, string> = {
|
setUserLanguage(locale.value).then((res) => {
|
||||||
ENGLISH: 'en',
|
userInfoStore.setToken(res)
|
||||||
CHINESE_SIMPLIFIED: 'zh-CN'
|
location.reload()
|
||||||
}
|
})
|
||||||
setUserLanguage(localeMap[locale.value])
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import EmailVerificationDialog from './components/EmailVerificationDialog.vue'
|
import EmailVerificationDialog from './components/EmailVerificationDialog.vue'
|
||||||
import ProfileSection from './components/ProfileSection.vue'
|
import ProfileSection from './components/ProfileSection.vue'
|
||||||
@@ -119,6 +119,10 @@
|
|||||||
loadUserProfile
|
loadUserProfile
|
||||||
} = useSettingsForm({ t, locale })
|
} = useSettingsForm({ t, locale })
|
||||||
|
|
||||||
|
// watch(locale, () => {
|
||||||
|
// loadUserProfile()
|
||||||
|
// })
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadUserProfile()
|
loadUserProfile()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const roleValues = [
|
|||||||
'other'
|
'other'
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export const languageValues = ['english', 'chinese'] as const
|
export const languageValues = ['ENGLISH', 'CHINESE_SIMPLIFIED'] as const
|
||||||
|
|
||||||
|
|
||||||
export type RoleValue = (typeof roleValues)[number]
|
export type RoleValue = (typeof roleValues)[number]
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import {
|
|||||||
type UserProfile,
|
type UserProfile,
|
||||||
updateUserProfile,
|
updateUserProfile,
|
||||||
verifyEmailCode,
|
verifyEmailCode,
|
||||||
fetchVerifyCode
|
fetchVerifyCode,
|
||||||
|
setUserLanguage
|
||||||
} from '@/api/user'
|
} from '@/api/user'
|
||||||
import regionList from '@/utils/area'
|
import regionList from '@/utils/area'
|
||||||
import {
|
import {
|
||||||
@@ -18,6 +19,9 @@ import {
|
|||||||
type SettingsData
|
type SettingsData
|
||||||
} from './types'
|
} from './types'
|
||||||
import { validateCase, validateLength, validateSpecial } from '@/views/login/tools'
|
import { validateCase, validateLength, validateSpecial } from '@/views/login/tools'
|
||||||
|
import {useUserInfoStore} from '@/stores'
|
||||||
|
|
||||||
|
const userInfoStore = useUserInfoStore()
|
||||||
|
|
||||||
type Translate = (key: string, ...args: unknown[]) => string
|
type Translate = (key: string, ...args: unknown[]) => string
|
||||||
|
|
||||||
@@ -26,24 +30,6 @@ interface UseSettingsFormOptions {
|
|||||||
locale: Ref<string>
|
locale: Ref<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
// 前端 UI 使用的语言值(用于下拉选择)
|
|
||||||
const languageLocaleMap: Record<LanguageValue, 'ENGLISH' | 'CHINESE_SIMPLIFIED'> = {
|
|
||||||
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 emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||||
|
|
||||||
const isRoleValue = (value: string): value is RoleValue =>
|
const isRoleValue = (value: string): value is RoleValue =>
|
||||||
@@ -75,15 +61,10 @@ const normalizeLanguage = (language: string | null | undefined): LanguageValue =
|
|||||||
if (!language) {
|
if (!language) {
|
||||||
return '' as LanguageValue
|
return '' as LanguageValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// 后端返回 'en' 或 'zh-CN'
|
|
||||||
const trimmed = language.trim()
|
const trimmed = language.trim()
|
||||||
if (trimmed === 'en') {
|
if (trimmed === 'ENGLISH' || trimmed === 'CHINESE_SIMPLIFIED') {
|
||||||
return 'english'
|
return trimmed as LanguageValue
|
||||||
} else if (trimmed === 'zh-CN') {
|
|
||||||
return 'chinese'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return '' as LanguageValue
|
return '' as LanguageValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,9 +163,8 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const syncAppLanguage = (language: LanguageValue) => {
|
const syncAppLanguage = (language: LanguageValue) => {
|
||||||
const nextLocale = languageLocaleMap[language]
|
locale.value = language
|
||||||
locale.value = nextLocale
|
localStorage.setItem('language', language)
|
||||||
localStorage.setItem('language', nextLocale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadUserProfile = async () => {
|
const loadUserProfile = async () => {
|
||||||
@@ -334,12 +314,8 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将前端语言值转换为后端格式
|
// 前端语言值直接作为后端格式
|
||||||
let backendLanguage = ''
|
const backendLanguage = draftData.value.language || ''
|
||||||
if (draftData.value.language) {
|
|
||||||
const i18nLocale = languageLocaleMap[draftData.value.language as LanguageValue]
|
|
||||||
backendLanguage = backendLanguageMap[i18nLocale]
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextData: UserProfile = {
|
const nextData: UserProfile = {
|
||||||
firstName: draftData.value.firstName.trim(),
|
firstName: draftData.value.firstName.trim(),
|
||||||
@@ -370,10 +346,8 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|||||||
try {
|
try {
|
||||||
await updateUserProfile(nextData)
|
await updateUserProfile(nextData)
|
||||||
|
|
||||||
// 将后端返回的语言值转换为前端格式
|
// 后端返回的语言值直接作为前端格式
|
||||||
const frontendLanguage = backendLanguage
|
const frontendLanguage = backendLanguage as LanguageValue
|
||||||
? backendToFrontendLanguage[backendLanguage as 'en' | 'zh-CN']
|
|
||||||
: ''
|
|
||||||
|
|
||||||
const settingsData: SettingsData = {
|
const settingsData: SettingsData = {
|
||||||
firstName: nextData.firstName,
|
firstName: nextData.firstName,
|
||||||
@@ -388,7 +362,12 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
|||||||
console.log(nextData)
|
console.log(nextData)
|
||||||
|
|
||||||
if (frontendLanguage && frontendLanguage !== previousLanguage) {
|
if (frontendLanguage && frontendLanguage !== previousLanguage) {
|
||||||
syncAppLanguage(frontendLanguage as LanguageValue)
|
// syncAppLanguage(frontendLanguage as LanguageValue)
|
||||||
|
setUserLanguage(frontendLanguage).then((res) => {
|
||||||
|
// console.log(res)
|
||||||
|
userInfoStore.setToken(res)
|
||||||
|
location.reload()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
draftData.value = cloneSettingsData(sourceData.value)
|
draftData.value = cloneSettingsData(sourceData.value)
|
||||||
|
|||||||
Reference in New Issue
Block a user