feat: 资料更新
This commit is contained in:
@@ -1,34 +1,90 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export interface WardrobeItem {
|
export interface WardrobeItem {
|
||||||
buyerId: number
|
buyerId: number
|
||||||
categories: string[]
|
categories: string[]
|
||||||
designFor: 'female' | 'male' | 'all'
|
designFor: 'female' | 'male' | 'all'
|
||||||
page: number
|
page: number
|
||||||
size: number
|
size: number
|
||||||
}
|
}
|
||||||
|
// 获取我的衣橱assets
|
||||||
export const fetchMyWardrobe = (data: WardrobeItem): Promise<ApiResponse> => {
|
export const fetchMyWardrobe = (data: WardrobeItem): Promise<ApiResponse> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/buyer/buyer/order/assets/page',
|
url: '/buyer/buyer/order/assets/page',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderItem {
|
export interface OrderItem {
|
||||||
status?: number // 0未支付 1已支付 2已取消 不传查全部
|
status?: number // 0未支付 1已支付 2已取消 不传查全部
|
||||||
page: number
|
page: number
|
||||||
size: number
|
size: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrdersPageResponse {
|
export interface OrdersPageResponse {
|
||||||
content: any[]
|
content: any[]
|
||||||
|
}
|
||||||
|
// 获取我的衣橱 orders
|
||||||
|
export const fetchMyOrders = (data: OrderItem): Promise<OrdersPageResponse> => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/buyer/order/page',
|
||||||
|
method: 'get',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchMyOrders = (data: OrderItem): Promise<OrdersPageResponse> => {
|
export interface Download {
|
||||||
return request({
|
ids: string[]
|
||||||
url: '/buyer/buyer/order/page',
|
}
|
||||||
method: 'get',
|
// 下载资源
|
||||||
params: data
|
export const fetchDownloadItemsByGet = (params: Download): Promise<ApiResponse> => {
|
||||||
})
|
return request({
|
||||||
|
url: '/buyer/listing/mall/main-product/download',
|
||||||
|
method: 'get',
|
||||||
|
responseType: 'blob',
|
||||||
|
params,
|
||||||
|
paramsSerializer: (p: any) => {
|
||||||
|
const usp = new URLSearchParams()
|
||||||
|
if (p && p.ids && Array.isArray(p.ids)) {
|
||||||
|
p.ids.forEach((id: any) => usp.append('ids', String(id)))
|
||||||
|
} else if (p) {
|
||||||
|
Object.keys(p).forEach((k) => {
|
||||||
|
const v = (p as any)[k]
|
||||||
|
if (Array.isArray(v)) {
|
||||||
|
v.forEach((x) => usp.append(k, String(x)))
|
||||||
|
} else if (v !== undefined && v !== null) {
|
||||||
|
usp.append(k, String(v))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return usp.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserProfile {
|
||||||
|
firstName: string
|
||||||
|
lastName: string
|
||||||
|
username: string
|
||||||
|
roles: string[]
|
||||||
|
region: string
|
||||||
|
language: string
|
||||||
|
email: string
|
||||||
|
}
|
||||||
|
// 获取用户信息
|
||||||
|
export const fetchUserProfile = (): Promise<ApiResponse> => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/profile/getProfile',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置用户信息
|
||||||
|
export const updateUserProfile = (data: UserProfile): Promise<ApiResponse> => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/profile/setProfile',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,18 +46,21 @@ export default {
|
|||||||
submit: 'Submit',
|
submit: 'Submit',
|
||||||
enterNewPassword: 'Enter a new password for<br/><span>{email}</span>',
|
enterNewPassword: 'Enter a new password for<br/><span>{email}</span>',
|
||||||
passwordsDoNotMatch: 'Passwords do not match',
|
passwordsDoNotMatch: 'Passwords do not match',
|
||||||
logOffTip: 'Are you sure to log off?',
|
logOffTip: 'Are you sure to log off?'
|
||||||
},
|
},
|
||||||
RegisterSuccess: {
|
RegisterSuccess: {
|
||||||
title1: 'Welcome to Stylish Parade!',
|
title1: 'Welcome to Stylish Parade!',
|
||||||
title2: 'Please switch to the Login tab to log in.',
|
title2: 'Please switch to the Login tab to log in.',
|
||||||
title3: 'What awaits you in Stylish Parade',
|
title3: 'What awaits you in Stylish Parade',
|
||||||
item1title: 'Behind the design',
|
item1title: 'Behind the design',
|
||||||
item1tip: 'Discover how designers bring ideas to life with AiDA — from first sketch to final look.',
|
item1tip:
|
||||||
|
'Discover how designers bring ideas to life with AiDA — from first sketch to final look.',
|
||||||
item2title: 'Creative digital works',
|
item2title: 'Creative digital works',
|
||||||
item2tip: 'Unlock a growing library of inspiring digital works to refresh your creative mind.',
|
item2tip:
|
||||||
|
'Unlock a growing library of inspiring digital works to refresh your creative mind.',
|
||||||
item3title: 'A fashion community',
|
item3title: 'A fashion community',
|
||||||
item3tip: 'Join a space where fashion speaks — exchange ideas and connect with creators worldwide.',
|
item3tip:
|
||||||
|
'Join a space where fashion speaks — exchange ideas and connect with creators worldwide.'
|
||||||
},
|
},
|
||||||
Settings: {
|
Settings: {
|
||||||
title: 'Settings',
|
title: 'Settings',
|
||||||
@@ -73,7 +76,7 @@ export default {
|
|||||||
usernamePlaceholder: 'Username',
|
usernamePlaceholder: 'Username',
|
||||||
usernameTip: 'Your public username on Stylish Parade.',
|
usernameTip: 'Your public username on Stylish Parade.',
|
||||||
role: 'ROLE',
|
role: 'ROLE',
|
||||||
roleTip: 'Select up to 2 labels that suit you.',
|
roleTip: 'Select up to 2 labels that suit you.'
|
||||||
},
|
},
|
||||||
security: {
|
security: {
|
||||||
title: 'Security',
|
title: 'Security',
|
||||||
@@ -139,7 +142,7 @@ export default {
|
|||||||
},
|
},
|
||||||
languages: {
|
languages: {
|
||||||
english: 'English',
|
english: 'English',
|
||||||
chinese: 'Chinese',
|
chinese: 'Chinese'
|
||||||
},
|
},
|
||||||
regions: {
|
regions: {
|
||||||
hongKongSar: 'Hong Kong SAR',
|
hongKongSar: 'Hong Kong SAR',
|
||||||
@@ -152,7 +155,7 @@ export default {
|
|||||||
title: 'My Wardrobe',
|
title: 'My Wardrobe',
|
||||||
subtitle: 'Your digital pieces, all in one place',
|
subtitle: 'Your digital pieces, all in one place',
|
||||||
common: {
|
common: {
|
||||||
all: 'All',
|
all: 'All'
|
||||||
},
|
},
|
||||||
tabs: {
|
tabs: {
|
||||||
ariaLabel: 'Wardrobe tabs',
|
ariaLabel: 'Wardrobe tabs',
|
||||||
@@ -226,33 +229,33 @@ export default {
|
|||||||
info3: 'This architecture is designed to elevate your exposure through profound "propositional expression," ensuring that soulful, story-driven designs achieve higher market premiums and superior sales conversion.'
|
info3: 'This architecture is designed to elevate your exposure through profound "propositional expression," ensuring that soulful, story-driven designs achieve higher market premiums and superior sales conversion.'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
footer:{
|
footer: {
|
||||||
About: 'About',
|
About: 'About',
|
||||||
PrivacyPolicy: 'Privacy Policy',
|
PrivacyPolicy: 'Privacy Policy',
|
||||||
TermsOfUse: 'Terms of Use',
|
TermsOfUse: 'Terms of Use',
|
||||||
Disclaimer: 'Disclaimer',
|
Disclaimer: 'Disclaimer',
|
||||||
SiteMap: 'Site Map',
|
SiteMap: 'Site Map'
|
||||||
},
|
},
|
||||||
brand:{
|
brand: {
|
||||||
title: 'Brand',
|
title: 'Brand',
|
||||||
description: "Every brand, every story — discover who's behind the collections.",
|
description: "Every brand, every story — discover who's behind the collections.",
|
||||||
search: 'Search brand',
|
search: 'Search brand',
|
||||||
noFound: 'Brand No Found',
|
noFound: 'Brand No Found',
|
||||||
noFoundTip: 'Try using another keywords.',
|
noFoundTip: 'Try using another keywords.',
|
||||||
searchHistory: 'Searching History',
|
searchHistory: 'Searching History',
|
||||||
brandItem:{
|
brandItem: {
|
||||||
viewProfile: 'View Profile',
|
viewProfile: 'View Profile'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
brandDetail:{
|
brandDetail: {
|
||||||
addShoppingTip: 'Please log in first.',
|
addShoppingTip: 'Please log in first.',
|
||||||
merchantInfo: {
|
merchantInfo: {
|
||||||
Contact: 'Contact',
|
Contact: 'Contact',
|
||||||
About: 'About',
|
About: 'About'
|
||||||
},
|
},
|
||||||
All: 'All',
|
All: 'All'
|
||||||
},
|
},
|
||||||
digitalItem:{
|
digitalItem: {
|
||||||
BestSelling: 'Best Selling',
|
BestSelling: 'Best Selling',
|
||||||
Price: 'Price: Low to High',
|
Price: 'Price: Low to High',
|
||||||
SelectedFirst: 'Selected First',
|
SelectedFirst: 'Selected First',
|
||||||
@@ -267,11 +270,11 @@ export default {
|
|||||||
Filters: 'Filters',
|
Filters: 'Filters',
|
||||||
Clear: 'Clear',
|
Clear: 'Clear',
|
||||||
Categories: 'Categories',
|
Categories: 'Categories',
|
||||||
Gender: 'Gender',
|
Gender: 'Gender'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
checked: {
|
checked: {
|
||||||
All: 'All',
|
All: 'All'
|
||||||
},
|
},
|
||||||
MainHeader: {
|
MainHeader: {
|
||||||
Home: 'Home',
|
Home: 'Home',
|
||||||
@@ -281,7 +284,7 @@ export default {
|
|||||||
HiName: 'Hi, {name}',
|
HiName: 'Hi, {name}',
|
||||||
MyWardrobe: 'My Wardrobe',
|
MyWardrobe: 'My Wardrobe',
|
||||||
Notifications: 'Notifications',
|
Notifications: 'Notifications',
|
||||||
Settings: 'Settings',
|
Settings: 'Settings'
|
||||||
},
|
},
|
||||||
ShoppingCart: {
|
ShoppingCart: {
|
||||||
title: 'Shopping Cart',
|
title: 'Shopping Cart',
|
||||||
@@ -300,9 +303,9 @@ export default {
|
|||||||
selected: 'Selected',
|
selected: 'Selected',
|
||||||
brands: 'Brands',
|
brands: 'Brands',
|
||||||
item: 'item',
|
item: 'item',
|
||||||
checkoutSelected: 'Checkout Selected',
|
checkoutSelected: 'Checkout Selected'
|
||||||
},
|
},
|
||||||
digitalDetail:{
|
digitalDetail: {
|
||||||
Sketch: 'Sketch',
|
Sketch: 'Sketch',
|
||||||
Illustration: 'Illustration',
|
Illustration: 'Illustration',
|
||||||
Product: 'Product',
|
Product: 'Product',
|
||||||
@@ -311,13 +314,30 @@ export default {
|
|||||||
ReleaseIn: 'Release in',
|
ReleaseIn: 'Release in',
|
||||||
CopyrightLicenseNotice: 'Copyright & License Notice',
|
CopyrightLicenseNotice: 'Copyright & License Notice',
|
||||||
LicenseIncludedInAsset: 'License Included in Asset',
|
LicenseIncludedInAsset: 'License Included in Asset',
|
||||||
LicenseIncludedInAssetInfo: 'All products on this platform are digital assets, not physical goods. Purchase grants a usage license only; copyright and intellectual property rights remain with the original creator, unless otherwise stated.',
|
LicenseIncludedInAssetInfo:
|
||||||
|
'All products on this platform are digital assets, not physical goods. Purchase grants a usage license only; copyright and intellectual property rights remain with the original creator, unless otherwise stated.',
|
||||||
BuyNow: 'Buy Now',
|
BuyNow: 'Buy Now',
|
||||||
AddToCart: 'Add to Cart',
|
AddToCart: 'Add to Cart'
|
||||||
},
|
},
|
||||||
addShoppingCart:{
|
addShoppingCart: {
|
||||||
title: 'Added to your Shopping Cart',
|
title: 'Added to your Shopping Cart',
|
||||||
statement: 'Digital Assets Only. No physical product included.',
|
statement: 'Digital Assets Only. No physical product included.',
|
||||||
button: 'Set Shopping Cart',
|
button: 'Set Shopping Cart'
|
||||||
|
},
|
||||||
|
area: {
|
||||||
|
chinaMainland: 'China Mainland',
|
||||||
|
hongKongSar: 'Hong Kong SAR',
|
||||||
|
macauSar: 'Macau SAR',
|
||||||
|
taiwan: 'Taiwan',
|
||||||
|
japan: 'Japan',
|
||||||
|
southKorea: 'South Korea',
|
||||||
|
singapore: 'Singapore',
|
||||||
|
unitedStates: 'United States',
|
||||||
|
unitedKingdom: 'United Kingdom',
|
||||||
|
france: 'France',
|
||||||
|
italy: 'Italy',
|
||||||
|
germany: 'Germany',
|
||||||
|
australia: 'Australia',
|
||||||
|
canada: 'Canada'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ export default {
|
|||||||
submit: '提交',
|
submit: '提交',
|
||||||
enterNewPassword: '请输入新密码<br/><span>{email}</span>',
|
enterNewPassword: '请输入新密码<br/><span>{email}</span>',
|
||||||
passwordsDoNotMatch: '两次输入密码不一致',
|
passwordsDoNotMatch: '两次输入密码不一致',
|
||||||
logOffTip: '确定退出登录吗?',
|
logOffTip: '确定退出登录吗?'
|
||||||
},
|
},
|
||||||
RegisterSuccess: {
|
RegisterSuccess: {
|
||||||
title1: '欢迎来到 Stylish Parade!',
|
title1: '欢迎来到 Stylish Parade!',
|
||||||
@@ -57,7 +57,7 @@ export default {
|
|||||||
item2title: '创意数字作品',
|
item2title: '创意数字作品',
|
||||||
item2tip: '解锁一个增长的数字作品库,刷新你的创意。',
|
item2tip: '解锁一个增长的数字作品库,刷新你的创意。',
|
||||||
item3title: '时尚社区',
|
item3title: '时尚社区',
|
||||||
item3tip: '加入一个全球的时尚社区,与设计师分享创意。',
|
item3tip: '加入一个全球的时尚社区,与设计师分享创意。'
|
||||||
},
|
},
|
||||||
Settings: {
|
Settings: {
|
||||||
title: '设置',
|
title: '设置',
|
||||||
@@ -73,7 +73,7 @@ export default {
|
|||||||
usernamePlaceholder: '请输入用户名',
|
usernamePlaceholder: '请输入用户名',
|
||||||
usernameTip: '这是你在 Stylish Parade 上公开显示的用户名。',
|
usernameTip: '这是你在 Stylish Parade 上公开显示的用户名。',
|
||||||
role: '身份标签',
|
role: '身份标签',
|
||||||
roleTip: '最多选择 2 个符合你的标签。',
|
roleTip: '最多选择 2 个符合你的标签。'
|
||||||
},
|
},
|
||||||
security: {
|
security: {
|
||||||
title: '安全',
|
title: '安全',
|
||||||
@@ -139,7 +139,7 @@ export default {
|
|||||||
},
|
},
|
||||||
languages: {
|
languages: {
|
||||||
english: '英文',
|
english: '英文',
|
||||||
chinese: '中文',
|
chinese: '中文'
|
||||||
},
|
},
|
||||||
regions: {
|
regions: {
|
||||||
hongKongSar: '中国香港特别行政区',
|
hongKongSar: '中国香港特别行政区',
|
||||||
@@ -152,7 +152,7 @@ export default {
|
|||||||
title: '我的衣橱',
|
title: '我的衣橱',
|
||||||
subtitle: '你的数字单品尽在此处',
|
subtitle: '你的数字单品尽在此处',
|
||||||
common: {
|
common: {
|
||||||
all: '全部',
|
all: '全部'
|
||||||
},
|
},
|
||||||
tabs: {
|
tabs: {
|
||||||
ariaLabel: '衣橱标签页',
|
ariaLabel: '衣橱标签页',
|
||||||
@@ -216,62 +216,62 @@ export default {
|
|||||||
},
|
},
|
||||||
collectionStory: {
|
collectionStory: {
|
||||||
back: '返回首页',
|
back: '返回首页',
|
||||||
title: "我们在寻找",
|
title: '我们在寻找',
|
||||||
description: "值得被听见的时尚之声",
|
description: '值得被听见的时尚之声',
|
||||||
button: "如有兴趣,请联系我们",
|
button: '如有兴趣,请联系我们',
|
||||||
joinUs: {
|
joinUs: {
|
||||||
title: '加入我们的设计师社区,',
|
title: '加入我们的设计师社区,',
|
||||||
info: "加入我们的远见者社区,发表你的系列故事。",
|
info: '加入我们的远见者社区,发表你的系列故事。',
|
||||||
info2: "我们目前正在寻找深度整合 AiDA 创意工作流程的系列作品,特别是那些通过强大的核心理念和富有感染力的灵感而产生共鸣的作品。",
|
info2: '我们目前正在寻找深度整合 AiDA 创意工作流程的系列作品,特别是那些通过强大的核心理念和富有感染力的灵感而产生共鸣的作品。',
|
||||||
info3: "这一架构旨在通过深刻的‘命题式表达’提升你的曝光度,确保那些有灵魂、由故事驱动的设计能获得更高的市场溢价和卓越的销售转化率。"
|
info3: '这一架构旨在通过深刻的‘命题式表达’提升你的曝光度,确保那些有灵魂、由故事驱动的设计能获得更高的市场溢价和卓越的销售转化率。'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
footer:{
|
footer: {
|
||||||
About: '关于我们',
|
About: '关于我们',
|
||||||
PrivacyPolicy: '隐私政策',
|
PrivacyPolicy: '隐私政策',
|
||||||
TermsOfUse: '条款与条件',
|
TermsOfUse: '条款与条件',
|
||||||
Disclaimer: '免责声明',
|
Disclaimer: '免责声明',
|
||||||
SiteMap: '地图',
|
SiteMap: '地图'
|
||||||
},
|
},
|
||||||
brand:{
|
brand: {
|
||||||
title: "品牌",
|
title: '品牌',
|
||||||
description: "每一个品牌,每一个故事 — 发现系列作品背后的缔造者。",
|
description: '每一个品牌,每一个故事 — 发现系列作品背后的缔造者。',
|
||||||
search: "搜索品牌",
|
search: '搜索品牌',
|
||||||
noFound: "未找到品牌",
|
noFound: '未找到品牌',
|
||||||
noFoundTip: "请尝试使用其他关键词。",
|
noFoundTip: '请尝试使用其他关键词。',
|
||||||
searchHistory: "搜索历史",
|
searchHistory: '搜索历史',
|
||||||
brandItem: {
|
brandItem: {
|
||||||
viewProfile: "查看简介"
|
viewProfile: '查看简介'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
brandDetail:{
|
brandDetail: {
|
||||||
addShoppingTip: "请先登录。",
|
addShoppingTip: '请先登录。',
|
||||||
merchantInfo: {
|
merchantInfo: {
|
||||||
Contact: "联系方式",
|
Contact: '联系方式',
|
||||||
About: "关于我们"
|
About: '关于我们'
|
||||||
},
|
},
|
||||||
All: "全部"
|
All: '全部'
|
||||||
},
|
},
|
||||||
digitalItem: {
|
digitalItem: {
|
||||||
BestSelling: "畅销优先",
|
BestSelling: '畅销优先',
|
||||||
Price: "价格:从低到高",
|
Price: '价格:从低到高',
|
||||||
SelectedFirst: "已选优先",
|
SelectedFirst: '已选优先',
|
||||||
DateAdded: "添加日期",
|
DateAdded: '添加日期',
|
||||||
NewestFirst: "最新优先",
|
NewestFirst: '最新优先',
|
||||||
title: "数字藏品",
|
title: '数字藏品',
|
||||||
info: "收藏于个人档案中的虚拟时装作品",
|
info: '收藏于个人档案中的虚拟时装作品',
|
||||||
sortBy: "排序方式",
|
sortBy: '排序方式',
|
||||||
noData: "暂无数字藏品",
|
noData: '暂无数字藏品',
|
||||||
noDataTip: "请尝试调整筛选条件或刷新页面。",
|
noDataTip: '请尝试调整筛选条件或刷新页面。',
|
||||||
MerchantInfo: {
|
MerchantInfo: {
|
||||||
Filters: "筛选",
|
Filters: '筛选',
|
||||||
Clear: "清空",
|
Clear: '清空',
|
||||||
Categories: "分类",
|
Categories: '分类',
|
||||||
Gender: "适用性别"
|
Gender: '适用性别'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
checked: {
|
checked: {
|
||||||
All: "全部"
|
All: '全部'
|
||||||
},
|
},
|
||||||
MainHeader: {
|
MainHeader: {
|
||||||
Home: '首页',
|
Home: '首页',
|
||||||
@@ -281,7 +281,7 @@ export default {
|
|||||||
HiName: '你好,{name}',
|
HiName: '你好,{name}',
|
||||||
MyWardrobe: '我的衣橱',
|
MyWardrobe: '我的衣橱',
|
||||||
Notifications: '通知',
|
Notifications: '通知',
|
||||||
Settings: '设置',
|
Settings: '设置'
|
||||||
},
|
},
|
||||||
ShoppingCart: {
|
ShoppingCart: {
|
||||||
title: '购物车',
|
title: '购物车',
|
||||||
@@ -300,24 +300,41 @@ export default {
|
|||||||
selected: '已选',
|
selected: '已选',
|
||||||
brands: '品牌',
|
brands: '品牌',
|
||||||
item: '数字藏品',
|
item: '数字藏品',
|
||||||
checkoutSelected: '结账已选',
|
checkoutSelected: '结账已选'
|
||||||
},
|
},
|
||||||
digitalDetail:{
|
digitalDetail: {
|
||||||
Sketch: "草图",
|
Sketch: '草图',
|
||||||
Illustration: "插画",
|
Illustration: '插画',
|
||||||
Product: "产品",
|
Product: '产品',
|
||||||
EditorialVisual: "编辑视觉",
|
EditorialVisual: '编辑视觉',
|
||||||
Back: "返回",
|
Back: '返回',
|
||||||
ReleaseIn: "发布于",
|
ReleaseIn: '发布于',
|
||||||
CopyrightLicenseNotice: "版权与许可声明",
|
CopyrightLicenseNotice: '版权与许可声明',
|
||||||
LicenseIncludedInAsset: "资产包含许可",
|
LicenseIncludedInAsset: '资产包含许可',
|
||||||
LicenseIncludedInAssetInfo: "本平台所有产品均为数字资产,非实物商品。购买仅授予使用许可;版权及知识产权仍归原作者所有,除非另有说明。",
|
LicenseIncludedInAssetInfo:
|
||||||
BuyNow: "立即购买",
|
'本平台所有产品均为数字资产,非实物商品。购买仅授予使用许可;版权及知识产权仍归原作者所有,除非另有说明。',
|
||||||
AddToCart: "加入购物车"
|
BuyNow: '立即购买',
|
||||||
|
AddToCart: '加入购物车'
|
||||||
},
|
},
|
||||||
addShoppingCart:{
|
addShoppingCart: {
|
||||||
title: "已添加到您的购物车",
|
title: '已添加到您的购物车',
|
||||||
statement: "仅限数字资产。不包含实体产品。",
|
statement: '仅限数字资产。不包含实体产品。',
|
||||||
button: "去购物车"
|
button: '去购物车'
|
||||||
|
},
|
||||||
|
area: {
|
||||||
|
chinaMainland: '中国大陆',
|
||||||
|
hongKongSar: '中国香港特别行政区',
|
||||||
|
macauSar: '中国澳门特别行政区',
|
||||||
|
taiwan: '中国台湾',
|
||||||
|
japan: '日本',
|
||||||
|
southKorea: '韩国',
|
||||||
|
singapore: '新加坡',
|
||||||
|
unitedStates: '美国',
|
||||||
|
unitedKingdom: '英国',
|
||||||
|
france: '法国',
|
||||||
|
italy: '意大利',
|
||||||
|
germany: '德国',
|
||||||
|
australia: '澳大利亚',
|
||||||
|
canada: '加拿大'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
86
src/utils/area.ts
Normal file
86
src/utils/area.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
key: 'chinaMainland',
|
||||||
|
name: 'China Mainland',
|
||||||
|
label: 'China Mainland',
|
||||||
|
value: 'China Mainland'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'hongKongSar',
|
||||||
|
name: 'Hong Kong SAR',
|
||||||
|
label: 'Hong Kong SAR',
|
||||||
|
value: 'Hong Kong SAR'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'macauSar',
|
||||||
|
name: 'Macau SAR',
|
||||||
|
label: 'Macau SAR',
|
||||||
|
value: 'Macau SAR'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'taiwan',
|
||||||
|
name: 'Taiwan',
|
||||||
|
label: 'Taiwan',
|
||||||
|
value: 'Taiwan'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'japan',
|
||||||
|
name: 'Japan',
|
||||||
|
label: 'Japan',
|
||||||
|
value: 'Japan'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'southKorea',
|
||||||
|
name: 'South Korea',
|
||||||
|
label: 'South Korea',
|
||||||
|
value: 'South Korea'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'singapore',
|
||||||
|
name: 'Singapore',
|
||||||
|
label: 'Singapore',
|
||||||
|
value: 'Singapore'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'unitedStates',
|
||||||
|
name: 'United States',
|
||||||
|
label: 'United States',
|
||||||
|
value: 'United States'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'unitedKingdom',
|
||||||
|
name: 'United Kingdom',
|
||||||
|
label: 'United Kingdom',
|
||||||
|
value: 'United Kingdom'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'france',
|
||||||
|
name: 'France',
|
||||||
|
label: 'France',
|
||||||
|
value: 'France'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'italy',
|
||||||
|
name: 'Italy',
|
||||||
|
label: 'Italy',
|
||||||
|
value: 'Italy'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'germany',
|
||||||
|
name: 'Germany',
|
||||||
|
label: 'Germany',
|
||||||
|
value: 'Germany'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'australia',
|
||||||
|
name: 'Australia',
|
||||||
|
label: 'Australia',
|
||||||
|
value: 'Australia'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'canada',
|
||||||
|
name: 'Canada',
|
||||||
|
label: 'Canada',
|
||||||
|
value: 'Canada'
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -65,6 +65,16 @@ service.interceptors.response.use(
|
|||||||
if (response.config.url.includes('llm/streamChat')) {
|
if (response.config.url.includes('llm/streamChat')) {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
// 如果是二进制下载(blob/arraybuffer),直接返回原始 response 以便调用方处理文件
|
||||||
|
if (
|
||||||
|
response.config.responseType === 'blob' ||
|
||||||
|
response.config.responseType === 'arraybuffer' ||
|
||||||
|
response.headers['content-type'] === 'application/octet-stream'
|
||||||
|
) {
|
||||||
|
removePending(response.config)
|
||||||
|
if (response.config.loading) closeLoading()
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
// 已完成请求的删除请求中数组
|
// 已完成请求的删除请求中数组
|
||||||
removePending(response.config)
|
removePending(response.config)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<div class="region-row">
|
<div class="region-row">
|
||||||
<div class="security-label">{{ t('Settings.region.region') }}</div>
|
<div class="security-label">{{ t('Settings.region.region') }}</div>
|
||||||
<div v-show="!isEditing" class="security-static field-box">
|
<div v-show="!isEditing" class="security-static field-box">
|
||||||
{{ displayRegionLabel }}
|
{{ t(`area.${displayRegionLabel}`) }}
|
||||||
</div>
|
</div>
|
||||||
<div v-show="isEditing" class="outlined-field select-field">
|
<div v-show="isEditing" class="outlined-field select-field">
|
||||||
<el-select
|
<el-select
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<el-option
|
<el-option
|
||||||
v-for="item in regionOptions"
|
v-for="item in regionOptions"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="item.label"
|
:label="t(`area.${item.key}`)"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|||||||
@@ -23,14 +23,14 @@
|
|||||||
:placeholder="t('Settings.security.newEmailPlaceholder')"
|
:placeholder="t('Settings.security.newEmailPlaceholder')"
|
||||||
@update:model-value="emit('update:newEmail', String($event))"
|
@update:model-value="emit('update:newEmail', String($event))"
|
||||||
/>
|
/>
|
||||||
<button
|
<!-- <button
|
||||||
type="button"
|
type="button"
|
||||||
class="verify-btn"
|
class="verify-btn"
|
||||||
:class="{ verified: isEmailVerified }"
|
:class="{ verified: isEmailVerified }"
|
||||||
@click="emit('verify-email')"
|
@click="emit('verify-email')"
|
||||||
>
|
>
|
||||||
{{ isEmailVerified ? t('Settings.security.verified') : t('Settings.security.verify') }}
|
{{ isEmailVerified ? t('Settings.security.verified') : t('Settings.security.verify') }}
|
||||||
</button>
|
</button> -->
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isEmailVerified" class="security-tip verified-tip">
|
<div v-if="isEmailVerified" class="security-tip verified-tip">
|
||||||
{{ t('Settings.security.verifiedTip') }}
|
{{ t('Settings.security.verifiedTip') }}
|
||||||
|
|||||||
@@ -1,159 +1,165 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="setting-wrapper mini-scrollbar">
|
<div class="setting-wrapper mini-scrollbar">
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
<div class="title">{{ t('Settings.title') }}</div>
|
<div class="title">{{ t('Settings.title') }}</div>
|
||||||
<div class="slogan">{{ t('Settings.slogan') }}</div>
|
<div class="slogan">{{ t('Settings.slogan') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-content">
|
<div class="setting-content">
|
||||||
<ProfileSection
|
<ProfileSection
|
||||||
v-model:first-name="draftData.firstName"
|
v-model:first-name="draftData.firstName"
|
||||||
v-model:last-name="draftData.lastName"
|
v-model:last-name="draftData.lastName"
|
||||||
v-model:username="draftData.username"
|
v-model:username="draftData.username"
|
||||||
v-model:role-model="roleModel"
|
v-model:role-model="roleModel"
|
||||||
:display-data="displayData"
|
:display-data="displayData"
|
||||||
:full-name="fullName"
|
:full-name="fullName"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
:role-options="roleList"
|
:role-options="roleList"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="gap" />
|
<div class="gap" />
|
||||||
|
|
||||||
<SecuritySection
|
<SecuritySection
|
||||||
v-model:new-email="securityDraft.newEmail"
|
v-model:new-email="securityDraft.newEmail"
|
||||||
v-model:new-password="securityDraft.newPassword"
|
v-model:new-password="securityDraft.newPassword"
|
||||||
v-model:current-password="securityDraft.currentPassword"
|
v-model:current-password="securityDraft.currentPassword"
|
||||||
:email="displayData.email"
|
:email="displayData.email"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
:is-email-verified="isEmailVerified"
|
:is-email-verified="isEmailVerified"
|
||||||
@reset-email="resetSecurityEmail"
|
@reset-email="resetSecurityEmail"
|
||||||
@reset-password="resetSecurityPassword"
|
@reset-password="resetSecurityPassword"
|
||||||
@verify-email="handleVerifyEmail"
|
@verify-email="handleVerifyEmail"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="gap" />
|
<div class="gap" />
|
||||||
|
|
||||||
<RegionSection
|
<RegionSection
|
||||||
v-model:language="draftData.language"
|
v-model:language="draftData.language"
|
||||||
v-model:region="draftData.region"
|
v-model:region="draftData.region"
|
||||||
:display-language-label="displayLanguageLabel"
|
:display-language-label="displayLanguageLabel"
|
||||||
:display-region-label="displayRegionLabel"
|
:display-region-label="displayRegionLabel"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
:language-options="languageList"
|
:language-options="languageList"
|
||||||
:region-options="regionList"
|
:region-options="regionList"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="gap bottom-gap" />
|
<div class="gap bottom-gap" />
|
||||||
|
|
||||||
<SettingsActions
|
<SettingsActions
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
:saving="saving"
|
:saving="saving"
|
||||||
@edit="handleEdit"
|
@edit="handleEdit"
|
||||||
@save="handleSave"
|
@save="handleSave"
|
||||||
@discard="handleDiscard"
|
@discard="handleDiscard"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
||||||
<EmailVerificationDialog
|
<EmailVerificationDialog
|
||||||
:visible="isVerificationDialogVisible"
|
:visible="isVerificationDialogVisible"
|
||||||
:email="verificationTargetEmail"
|
:email="verificationTargetEmail"
|
||||||
:saving="saving"
|
:saving="saving"
|
||||||
@close="closeVerificationDialog"
|
@close="closeVerificationDialog"
|
||||||
@resend="handleSendVerifyCode"
|
@resend="handleSendVerifyCode"
|
||||||
@submit="handleVerificationSubmit"
|
@submit="handleVerificationSubmit"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from 'vue-i18n'
|
import { ref, onMounted } from 'vue'
|
||||||
import EmailVerificationDialog from './components/EmailVerificationDialog.vue'
|
import { useI18n } from 'vue-i18n'
|
||||||
import ProfileSection from './components/ProfileSection.vue'
|
import EmailVerificationDialog from './components/EmailVerificationDialog.vue'
|
||||||
import RegionSection from './components/RegionSection.vue'
|
import ProfileSection from './components/ProfileSection.vue'
|
||||||
import SecuritySection from './components/SecuritySection.vue'
|
import RegionSection from './components/RegionSection.vue'
|
||||||
import SettingsActions from './components/SettingsActions.vue'
|
import SecuritySection from './components/SecuritySection.vue'
|
||||||
import { useSettingsForm } from './useSettingsForm'
|
import SettingsActions from './components/SettingsActions.vue'
|
||||||
|
import { useSettingsForm } from './useSettingsForm'
|
||||||
|
|
||||||
const { t, locale } = useI18n({ useScope: 'global' })
|
const { t, locale } = useI18n({ useScope: 'global' })
|
||||||
|
|
||||||
const {
|
const {
|
||||||
draftData,
|
draftData,
|
||||||
securityDraft,
|
securityDraft,
|
||||||
isEditing,
|
isEditing,
|
||||||
saving,
|
saving,
|
||||||
isVerificationDialogVisible,
|
isVerificationDialogVisible,
|
||||||
verificationTargetEmail,
|
verificationTargetEmail,
|
||||||
roleList,
|
roleList,
|
||||||
languageList,
|
languageList,
|
||||||
regionList,
|
regionList,
|
||||||
displayData,
|
displayData,
|
||||||
isEmailVerified,
|
isEmailVerified,
|
||||||
displayLanguageLabel,
|
displayLanguageLabel,
|
||||||
displayRegionLabel,
|
displayRegionLabel,
|
||||||
fullName,
|
fullName,
|
||||||
roleModel,
|
roleModel,
|
||||||
handleEdit,
|
handleEdit,
|
||||||
handleDiscard,
|
handleDiscard,
|
||||||
handleSave,
|
handleSave,
|
||||||
resetSecurityEmail,
|
resetSecurityEmail,
|
||||||
resetSecurityPassword,
|
resetSecurityPassword,
|
||||||
handleVerifyEmail,
|
handleVerifyEmail,
|
||||||
handleSendVerifyCode,
|
handleSendVerifyCode,
|
||||||
handleVerificationSubmit,
|
handleVerificationSubmit,
|
||||||
closeVerificationDialog
|
closeVerificationDialog,
|
||||||
} = useSettingsForm({ t, locale })
|
loadUserProfile
|
||||||
|
} = useSettingsForm({ t, locale })
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadUserProfile()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.setting-wrapper {
|
.setting-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner {
|
.banner {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 14.8rem;
|
height: 14.8rem;
|
||||||
row-gap: 1.2rem;
|
row-gap: 1.2rem;
|
||||||
background: linear-gradient(rgba(255, 255, 255, 0.91), rgba(255, 255, 255, 0.91)),
|
background: linear-gradient(rgba(255, 255, 255, 0.91), rgba(255, 255, 255, 0.91)),
|
||||||
linear-gradient(90deg, #f2eee8 0%, #fbfaf8 40%, #f1ede7 100%);
|
linear-gradient(90deg, #f2eee8 0%, #fbfaf8 40%, #f1ede7 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-family: 'KaiseiOpti-Bold';
|
font-family: 'KaiseiOpti-Bold';
|
||||||
font-size: 4rem;
|
font-size: 4rem;
|
||||||
line-height: 3.6rem;
|
line-height: 3.6rem;
|
||||||
color: #232323;
|
color: #232323;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slogan {
|
.slogan {
|
||||||
font-family: 'KaiseiOpti-Regular';
|
font-family: 'KaiseiOpti-Regular';
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
line-height: 2.4rem;
|
line-height: 2.4rem;
|
||||||
color: #585858;
|
color: #585858;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-content {
|
.setting-content {
|
||||||
padding: 4rem 18rem 7rem;
|
padding: 4rem 18rem 7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gap {
|
.gap {
|
||||||
height: 0.05rem;
|
height: 0.05rem;
|
||||||
margin-top: 6rem;
|
margin-top: 6rem;
|
||||||
margin-bottom: 4rem;
|
margin-bottom: 4rem;
|
||||||
background-color: #c4c4c4;
|
background-color: #c4c4c4;
|
||||||
|
|
||||||
&.bottom-gap {
|
&.bottom-gap {
|
||||||
margin-top: 4rem;
|
margin-top: 4rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-select-dropdown__item) {
|
:deep(.el-select-dropdown__item) {
|
||||||
padding: 0 2rem !important;
|
padding: 0 2rem !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -13,20 +13,19 @@ export const roleValues = [
|
|||||||
] as const
|
] as const
|
||||||
|
|
||||||
export const languageValues = ['english', 'chinese'] as const
|
export const languageValues = ['english', 'chinese'] as const
|
||||||
export const regionValues = ['hongKongSar', 'mainlandChina', 'singapore', 'unitedKingdom'] as const
|
|
||||||
|
|
||||||
export type RoleValue = (typeof roleValues)[number]
|
export type RoleValue = (typeof roleValues)[number]
|
||||||
export type LanguageValue = (typeof languageValues)[number]
|
export type LanguageValue = (typeof languageValues)[number]
|
||||||
export type RegionValue = (typeof regionValues)[number]
|
|
||||||
|
|
||||||
export interface SettingsData {
|
export interface SettingsData {
|
||||||
firstName: string
|
firstName: string
|
||||||
lastName: string
|
lastName: string
|
||||||
email: string
|
email: string
|
||||||
username: string
|
username: string
|
||||||
role: RoleValue[]
|
roles: RoleValue[]
|
||||||
language: LanguageValue
|
language: LanguageValue | ''
|
||||||
region: RegionValue
|
region: string | ''
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SecurityDraft {
|
export interface SecurityDraft {
|
||||||
|
|||||||
@@ -1,288 +1,335 @@
|
|||||||
import { computed, ref, shallowRef, watch, type Ref } from 'vue'
|
import { computed, ref, shallowRef, watch, type Ref } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { fetchUserProfile, type UserProfile, updateUserProfile } from '@/api/user'
|
||||||
|
import regionList from '@/utils/area'
|
||||||
import {
|
import {
|
||||||
languageValues,
|
languageValues,
|
||||||
regionValues,
|
roleValues,
|
||||||
roleValues,
|
type LanguageValue,
|
||||||
type LanguageValue,
|
type RoleValue,
|
||||||
type RegionValue,
|
type SecurityDraft,
|
||||||
type RoleValue,
|
type SettingsData
|
||||||
type SecurityDraft,
|
|
||||||
type SettingsData
|
|
||||||
} from './types'
|
} from './types'
|
||||||
|
|
||||||
type Translate = (key: string, ...args: unknown[]) => string
|
type Translate = (key: string, ...args: unknown[]) => string
|
||||||
|
|
||||||
interface UseSettingsFormOptions {
|
interface UseSettingsFormOptions {
|
||||||
t: Translate
|
t: Translate
|
||||||
locale: Ref<string>
|
locale: Ref<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
const languageLocaleMap: Record<LanguageValue, 'ENGLISH' | 'CHINESE_SIMPLIFIED'> = {
|
const languageLocaleMap: Record<LanguageValue, 'ENGLISH' | 'CHINESE_SIMPLIFIED'> = {
|
||||||
english: 'ENGLISH',
|
english: 'ENGLISH',
|
||||||
chinese: 'CHINESE_SIMPLIFIED'
|
chinese: 'CHINESE_SIMPLIFIED'
|
||||||
}
|
}
|
||||||
|
|
||||||
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||||
|
|
||||||
const createDefaultData = (): SettingsData => ({
|
const createDefaultData = (): SettingsData => ({
|
||||||
firstName: 'Alexandra',
|
firstName: '',
|
||||||
lastName: 'Chen',
|
lastName: '',
|
||||||
email: 'alex.chen@gmail.com',
|
email: '',
|
||||||
username: '@alexandra_chen',
|
username: '',
|
||||||
role: ['student', 'graphicDesigner'],
|
roles: [] as RoleValue[],
|
||||||
language: 'english',
|
language: '',
|
||||||
region: 'hongKongSar'
|
region: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const cloneSettingsData = (data: SettingsData): SettingsData => ({
|
const cloneSettingsData = (data: SettingsData): SettingsData => ({
|
||||||
firstName: data.firstName,
|
firstName: data.firstName,
|
||||||
lastName: data.lastName,
|
lastName: data.lastName,
|
||||||
email: data.email,
|
email: data.email,
|
||||||
username: data.username,
|
username: data.username,
|
||||||
role: [...data.role],
|
roles: [...data.roles],
|
||||||
language: data.language,
|
language: data.language,
|
||||||
region: data.region
|
region: data.region
|
||||||
|
})
|
||||||
|
|
||||||
|
const normalizeLanguage = (language: string | null | undefined): LanguageValue => {
|
||||||
|
if (!language) {
|
||||||
|
return '' as LanguageValue
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = language.trim().toLowerCase()
|
||||||
|
return normalized.includes('chinese') ? 'chinese' : 'english'
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildSettingsDataFromProfile = (profile: Partial<UserProfile>): SettingsData => ({
|
||||||
|
firstName: profile.firstName || '',
|
||||||
|
lastName: profile.lastName || '',
|
||||||
|
username: profile.username || '',
|
||||||
|
email: profile.email || '',
|
||||||
|
roles: profile.roles || [],
|
||||||
|
language: normalizeLanguage(profile.language),
|
||||||
|
region: profile.region
|
||||||
})
|
})
|
||||||
|
|
||||||
const createEmptySecurityDraft = (): SecurityDraft => ({
|
const createEmptySecurityDraft = (): SecurityDraft => ({
|
||||||
newEmail: '',
|
newEmail: '',
|
||||||
newPassword: '',
|
newPassword: '',
|
||||||
currentPassword: ''
|
currentPassword: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
|
||||||
const sourceData = ref<SettingsData>(createDefaultData())
|
const sourceData = ref<SettingsData>(createDefaultData())
|
||||||
const draftData = ref<SettingsData>(cloneSettingsData(sourceData.value))
|
const draftData = ref<SettingsData>(cloneSettingsData(sourceData.value))
|
||||||
const securityDraft = ref<SecurityDraft>(createEmptySecurityDraft())
|
const securityDraft = ref<SecurityDraft>(createEmptySecurityDraft())
|
||||||
const isEditing = shallowRef(false)
|
const isEditing = shallowRef(false)
|
||||||
const saving = shallowRef(false)
|
const saving = shallowRef(false)
|
||||||
const isVerificationDialogVisible = shallowRef(false)
|
const isVerificationDialogVisible = shallowRef(false)
|
||||||
const verificationTargetEmail = shallowRef('')
|
const verificationTargetEmail = shallowRef('')
|
||||||
const verifiedEmail = shallowRef('')
|
const verifiedEmail = shallowRef('')
|
||||||
|
|
||||||
const roleList = computed(() =>
|
const roleList = computed(() =>
|
||||||
roleValues.map((value) => ({
|
roleValues.map((value) => ({
|
||||||
name: t(`Settings.roles.${value}`),
|
name: t(`Settings.roles.${value}`),
|
||||||
value
|
value
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
|
||||||
const languageList = computed(() =>
|
const languageList = computed(() =>
|
||||||
languageValues.map((value) => ({
|
languageValues.map((value) => ({
|
||||||
label: t(`Settings.languages.${value}`),
|
label: t(`Settings.languages.${value}`),
|
||||||
value
|
value
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
|
||||||
const regionList = computed(() =>
|
const displayData = computed(() => (isEditing.value ? draftData.value : sourceData.value))
|
||||||
regionValues.map((value) => ({
|
const normalizedNewEmail = computed(() => securityDraft.value.newEmail.trim())
|
||||||
label: t(`Settings.regions.${value}`),
|
const hasNewEmailChange = computed(
|
||||||
value
|
() =>
|
||||||
}))
|
normalizedNewEmail.value.length > 0 &&
|
||||||
)
|
normalizedNewEmail.value !== sourceData.value.email
|
||||||
|
)
|
||||||
|
const isEmailVerified = computed(
|
||||||
|
() => hasNewEmailChange.value && verifiedEmail.value === normalizedNewEmail.value
|
||||||
|
)
|
||||||
|
const displayLanguageLabel = computed(() =>
|
||||||
|
displayData.value.language ? t(`Settings.languages.${displayData.value.language}`) : ''
|
||||||
|
)
|
||||||
|
const displayRegionLabel = computed(() => {
|
||||||
|
if (displayData.value.region) {
|
||||||
|
const regionItem = regionList.find((item) => item.value === displayData.value.region)
|
||||||
|
return regionItem.key
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const displayData = computed(() => (isEditing.value ? draftData.value : sourceData.value))
|
const fullName = computed(() => {
|
||||||
const normalizedNewEmail = computed(() => securityDraft.value.newEmail.trim())
|
const data = displayData.value
|
||||||
const hasNewEmailChange = computed(
|
return `${data.firstName} ${data.lastName}`.trim()
|
||||||
() => normalizedNewEmail.value.length > 0 && normalizedNewEmail.value !== sourceData.value.email
|
})
|
||||||
)
|
|
||||||
const isEmailVerified = computed(
|
|
||||||
() => hasNewEmailChange.value && verifiedEmail.value === normalizedNewEmail.value
|
|
||||||
)
|
|
||||||
const displayLanguageLabel = computed(() => t(`Settings.languages.${displayData.value.language}`))
|
|
||||||
const displayRegionLabel = computed(() => t(`Settings.regions.${displayData.value.region}`))
|
|
||||||
|
|
||||||
const fullName = computed(() => {
|
const roleModel = computed<RoleValue[]>({
|
||||||
const data = displayData.value
|
get: () => displayData.value.roles,
|
||||||
return `${data.firstName} ${data.lastName}`.trim()
|
set: (value) => {
|
||||||
})
|
if (isEditing.value) {
|
||||||
|
draftData.value.roles = value
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const roleModel = computed<RoleValue[]>({
|
sourceData.value.roles = value
|
||||||
get: () => displayData.value.role,
|
}
|
||||||
set: (value) => {
|
})
|
||||||
if (isEditing.value) {
|
|
||||||
draftData.value.role = value
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceData.value.role = value
|
const resetEmailVerificationState = () => {
|
||||||
}
|
isVerificationDialogVisible.value = false
|
||||||
})
|
verificationTargetEmail.value = ''
|
||||||
|
verifiedEmail.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
const resetEmailVerificationState = () => {
|
const syncAppLanguage = (language: LanguageValue) => {
|
||||||
isVerificationDialogVisible.value = false
|
const nextLocale = languageLocaleMap[language]
|
||||||
verificationTargetEmail.value = ''
|
locale.value = nextLocale
|
||||||
verifiedEmail.value = ''
|
localStorage.setItem('language', nextLocale)
|
||||||
}
|
}
|
||||||
|
|
||||||
const syncAppLanguage = (language: LanguageValue) => {
|
const loadUserProfile = async () => {
|
||||||
const nextLocale = languageLocaleMap[language]
|
try {
|
||||||
locale.value = nextLocale
|
const profile = (await fetchUserProfile()) as Partial<UserProfile>
|
||||||
localStorage.setItem('language', nextLocale)
|
const nextData = buildSettingsDataFromProfile(profile)
|
||||||
}
|
sourceData.value = cloneSettingsData(nextData)
|
||||||
|
draftData.value = cloneSettingsData(sourceData.value)
|
||||||
|
|
||||||
const resetDraftState = () => {
|
if (sourceData.value.language) {
|
||||||
draftData.value = cloneSettingsData(sourceData.value)
|
syncAppLanguage(sourceData.value.language as LanguageValue)
|
||||||
securityDraft.value = createEmptySecurityDraft()
|
}
|
||||||
resetEmailVerificationState()
|
} catch (error) {
|
||||||
}
|
console.warn(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleEdit = () => {
|
const resetDraftState = () => {
|
||||||
resetDraftState()
|
draftData.value = cloneSettingsData(sourceData.value)
|
||||||
isEditing.value = true
|
securityDraft.value = createEmptySecurityDraft()
|
||||||
}
|
resetEmailVerificationState()
|
||||||
|
}
|
||||||
|
|
||||||
const resetSecurityEmail = () => {
|
const handleEdit = () => {
|
||||||
securityDraft.value.newEmail = ''
|
resetDraftState()
|
||||||
resetEmailVerificationState()
|
isEditing.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetSecurityPassword = () => {
|
const resetSecurityEmail = () => {
|
||||||
securityDraft.value.newPassword = ''
|
securityDraft.value.newEmail = ''
|
||||||
securityDraft.value.currentPassword = ''
|
resetEmailVerificationState()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDiscard = () => {
|
const resetSecurityPassword = () => {
|
||||||
resetDraftState()
|
securityDraft.value.newPassword = ''
|
||||||
isEditing.value = false
|
securityDraft.value.currentPassword = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeVerificationDialog = () => {
|
const handleDiscard = () => {
|
||||||
isVerificationDialogVisible.value = false
|
resetDraftState()
|
||||||
verificationTargetEmail.value = ''
|
isEditing.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleVerifyEmail = () => {
|
const closeVerificationDialog = () => {
|
||||||
const nextEmail = normalizedNewEmail.value
|
isVerificationDialogVisible.value = false
|
||||||
|
verificationTargetEmail.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
if (!nextEmail) {
|
const handleVerifyEmail = () => {
|
||||||
ElMessage.warning(t('Settings.messages.enterNewEmailFirst'))
|
const nextEmail = normalizedNewEmail.value
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!emailPattern.test(nextEmail)) {
|
if (!nextEmail) {
|
||||||
ElMessage.warning(t('Settings.messages.invalidEmail'))
|
ElMessage.warning(t('Settings.messages.enterNewEmailFirst'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextEmail === sourceData.value.email) {
|
if (!emailPattern.test(nextEmail)) {
|
||||||
ElMessage.warning(t('Settings.messages.sameEmail'))
|
ElMessage.warning(t('Settings.messages.invalidEmail'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verifiedEmail.value === nextEmail) {
|
if (nextEmail === sourceData.value.email) {
|
||||||
ElMessage.success(t('Settings.messages.alreadyVerified'))
|
ElMessage.warning(t('Settings.messages.sameEmail'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationTargetEmail.value = nextEmail
|
if (verifiedEmail.value === nextEmail) {
|
||||||
handleSendVerifyCode()
|
ElMessage.success(t('Settings.messages.alreadyVerified'))
|
||||||
isVerificationDialogVisible.value = true
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSendVerifyCode = () => {
|
verificationTargetEmail.value = nextEmail
|
||||||
ElMessage.success(t('Settings.messages.verificationCodeSent'))
|
handleSendVerifyCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleVerificationSubmit = (code: string) => {
|
const handleSendVerifyCode = () => {
|
||||||
if (code.length !== 6) {
|
// AccountSendVerifyCode({
|
||||||
ElMessage.warning(t('Settings.messages.enterVerificationCode'))
|
// email: verificationTargetEmail.value,
|
||||||
return
|
// operationType: 'FORGET_PWD'
|
||||||
}
|
// }).then((res) => {
|
||||||
|
// console.log(res)
|
||||||
|
// ElMessage.success(t('Settings.messages.verificationCodeSent'))
|
||||||
|
// isVerificationDialogVisible.value = true
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
verifiedEmail.value = verificationTargetEmail.value
|
const handleVerificationSubmit = (code: string) => {
|
||||||
closeVerificationDialog()
|
if (code.length !== 6) {
|
||||||
ElMessage.success(t('Settings.messages.verificationCompleted'))
|
ElMessage.warning(t('Settings.messages.enterVerificationCode'))
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const buildNextData = (): SettingsData => {
|
verifiedEmail.value = verificationTargetEmail.value
|
||||||
const nextEmail = securityDraft.value.newEmail.trim() || draftData.value.email
|
closeVerificationDialog()
|
||||||
|
ElMessage.success(t('Settings.messages.verificationCompleted'))
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
const buildNextData = (): SettingsData => {
|
||||||
firstName: draftData.value.firstName.trim(),
|
const nextEmail = securityDraft.value.newEmail.trim() || draftData.value.email
|
||||||
lastName: draftData.value.lastName.trim(),
|
|
||||||
username: draftData.value.username.trim(),
|
|
||||||
email: nextEmail,
|
|
||||||
role: [...draftData.value.role],
|
|
||||||
language: draftData.value.language,
|
|
||||||
region: draftData.value.region
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSave = async () => {
|
return {
|
||||||
if (hasNewEmailChange.value && !isEmailVerified.value) {
|
firstName: draftData.value.firstName.trim(),
|
||||||
ElMessage.warning(t('Settings.messages.verifyEmailBeforeSave'))
|
lastName: draftData.value.lastName.trim(),
|
||||||
return
|
username: draftData.value.username.trim(),
|
||||||
}
|
email: nextEmail,
|
||||||
|
roles: [...draftData.value.roles],
|
||||||
|
language: draftData.value.language,
|
||||||
|
region: draftData.value.region
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const nextData = buildNextData()
|
const handleSave = async () => {
|
||||||
const previousLanguage = sourceData.value.language
|
if (hasNewEmailChange.value && !isEmailVerified.value) {
|
||||||
saving.value = true
|
ElMessage.warning(t('Settings.messages.verifyEmailBeforeSave'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
const nextData = buildNextData()
|
||||||
sourceData.value = cloneSettingsData(nextData)
|
const previousLanguage = sourceData.value.language
|
||||||
|
saving.value = true
|
||||||
|
|
||||||
if (nextData.language !== previousLanguage) {
|
try {
|
||||||
syncAppLanguage(nextData.language)
|
await updateUserProfile(nextData)
|
||||||
}
|
sourceData.value = cloneSettingsData(nextData)
|
||||||
|
console.log(nextData)
|
||||||
|
|
||||||
draftData.value = cloneSettingsData(sourceData.value)
|
if (nextData.language && nextData.language !== previousLanguage) {
|
||||||
securityDraft.value = createEmptySecurityDraft()
|
syncAppLanguage(nextData.language as LanguageValue)
|
||||||
resetEmailVerificationState()
|
}
|
||||||
isEditing.value = false
|
|
||||||
ElMessage.success(t('Settings.messages.settingsUpdated'))
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(error)
|
|
||||||
} finally {
|
|
||||||
saving.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
draftData.value = cloneSettingsData(sourceData.value)
|
||||||
() => securityDraft.value.newEmail,
|
securityDraft.value = createEmptySecurityDraft()
|
||||||
(value) => {
|
resetEmailVerificationState()
|
||||||
const trimmedValue = value.trim()
|
isEditing.value = false
|
||||||
|
ElMessage.success(t('Settings.messages.settingsUpdated'))
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error)
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (verifiedEmail.value && trimmedValue !== verifiedEmail.value) {
|
watch(
|
||||||
verifiedEmail.value = ''
|
() => securityDraft.value.newEmail,
|
||||||
}
|
(value) => {
|
||||||
|
const trimmedValue = value.trim()
|
||||||
|
|
||||||
if (
|
if (verifiedEmail.value && trimmedValue !== verifiedEmail.value) {
|
||||||
isVerificationDialogVisible.value &&
|
verifiedEmail.value = ''
|
||||||
verificationTargetEmail.value &&
|
}
|
||||||
trimmedValue !== verificationTargetEmail.value
|
|
||||||
) {
|
|
||||||
closeVerificationDialog()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
if (
|
||||||
sourceData,
|
isVerificationDialogVisible.value &&
|
||||||
draftData,
|
verificationTargetEmail.value &&
|
||||||
securityDraft,
|
trimmedValue !== verificationTargetEmail.value
|
||||||
isEditing,
|
) {
|
||||||
saving,
|
closeVerificationDialog()
|
||||||
isVerificationDialogVisible,
|
}
|
||||||
verificationTargetEmail,
|
}
|
||||||
roleList,
|
)
|
||||||
languageList,
|
|
||||||
regionList,
|
return {
|
||||||
displayData,
|
sourceData,
|
||||||
isEmailVerified,
|
draftData,
|
||||||
displayLanguageLabel,
|
securityDraft,
|
||||||
displayRegionLabel,
|
isEditing,
|
||||||
fullName,
|
saving,
|
||||||
roleModel,
|
isVerificationDialogVisible,
|
||||||
handleEdit,
|
verificationTargetEmail,
|
||||||
handleDiscard,
|
roleList,
|
||||||
handleSave,
|
languageList,
|
||||||
resetSecurityEmail,
|
regionList,
|
||||||
resetSecurityPassword,
|
displayData,
|
||||||
handleVerifyEmail,
|
isEmailVerified,
|
||||||
handleSendVerifyCode,
|
displayLanguageLabel,
|
||||||
handleVerificationSubmit,
|
displayRegionLabel,
|
||||||
closeVerificationDialog
|
fullName,
|
||||||
}
|
roleModel,
|
||||||
|
handleEdit,
|
||||||
|
handleDiscard,
|
||||||
|
handleSave,
|
||||||
|
resetSecurityEmail,
|
||||||
|
resetSecurityPassword,
|
||||||
|
handleVerifyEmail,
|
||||||
|
handleSendVerifyCode,
|
||||||
|
handleVerificationSubmit,
|
||||||
|
closeVerificationDialog,
|
||||||
|
loadUserProfile
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
<div class="amount" v-show="!disabled">${{ info.amount }}<span> HKD</span></div>
|
<div class="amount" v-show="!disabled">${{ info.amount }}<span> HKD</span></div>
|
||||||
<SvgIcon
|
<SvgIcon
|
||||||
v-if="showDownload"
|
v-if="showDownload"
|
||||||
|
@click.stop="emit('download', info)"
|
||||||
class="download"
|
class="download"
|
||||||
name="download"
|
name="download"
|
||||||
size="32"
|
size="32"
|
||||||
@@ -52,7 +53,7 @@
|
|||||||
import { FormatDate } from '@/utils/tools'
|
import { FormatDate } from '@/utils/tools'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const emit = defineEmits(['remove'])
|
const emit = defineEmits(['remove', 'download'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
showTags: { type: Boolean, default: true },
|
showTags: { type: Boolean, default: true },
|
||||||
showDate: { type: Boolean, default: true },
|
showDate: { type: Boolean, default: true },
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
<div
|
<div
|
||||||
class="assets-toolbar__download flex flex-center"
|
class="assets-toolbar__download flex flex-center"
|
||||||
:class="{ disabled: selectedCount < 1 }"
|
:class="{ disabled: selectedCount < 1 }"
|
||||||
|
v-loading="downloadingSelected"
|
||||||
@click="handleDownloadSelected"
|
@click="handleDownloadSelected"
|
||||||
>
|
>
|
||||||
<SvgIcon name="downloadBtn" color="#fff" />
|
<SvgIcon name="downloadBtn" color="#fff" />
|
||||||
@@ -66,6 +67,7 @@
|
|||||||
download
|
download
|
||||||
:url="item.thumbnailUrl"
|
:url="item.thumbnailUrl"
|
||||||
:name="item.listingName"
|
:name="item.listingName"
|
||||||
|
@download.stop="handleDownloadSelected(item)"
|
||||||
:showPrice="false"
|
:showPrice="false"
|
||||||
></CommodityItem>
|
></CommodityItem>
|
||||||
</div>
|
</div>
|
||||||
@@ -92,7 +94,7 @@
|
|||||||
import { useClothesCategories } from '@/utils/ClothesCategory'
|
import { useClothesCategories } from '@/utils/ClothesCategory'
|
||||||
import Empty from './Empty.vue'
|
import Empty from './Empty.vue'
|
||||||
import FilterSidebar from './FilterSidebar.vue'
|
import FilterSidebar from './FilterSidebar.vue'
|
||||||
import { fetchMyWardrobe } from '@/api/user'
|
import { fetchMyWardrobe, fetchDownloadItemsByGet } from '@/api/user'
|
||||||
import { useUserInfoStore } from '@/stores'
|
import { useUserInfoStore } from '@/stores'
|
||||||
|
|
||||||
import { debounce } from 'lodash-es'
|
import { debounce } from 'lodash-es'
|
||||||
@@ -320,9 +322,37 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDownloadSelected = () => {
|
const downloadingSelected = ref(false)
|
||||||
const items = dataList.value.filter((item) => item.checked)
|
const handleDownloadSelected = (assets) => {
|
||||||
console.log(items)
|
const items = assets ? [assets] : dataList.value.filter((item) => item.checked)
|
||||||
|
|
||||||
|
downloadingSelected.value = true
|
||||||
|
const ids = items.map((item) => item.listingId)
|
||||||
|
fetchDownloadItemsByGet({ ids })
|
||||||
|
.then((res) => {
|
||||||
|
const disposition = res.headers['content-disposition']
|
||||||
|
const fileName =
|
||||||
|
disposition?.split('filename=')[1]?.replace(/"/g, '') || 'download.zip'
|
||||||
|
const blob = res.data
|
||||||
|
const url = window.URL.createObjectURL(blob)
|
||||||
|
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
|
||||||
|
const timestamp = new Date().getTime()
|
||||||
|
link.download = fileName || `wardrobe_download_${timestamp}.zip`
|
||||||
|
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
|
||||||
|
document.body.removeChild(link)
|
||||||
|
window.URL.revokeObjectURL(url)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Download failed:', error)
|
||||||
|
}).finally(() => {
|
||||||
|
downloadingSelected.value = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAssetsScroll = () => {
|
const handleAssetsScroll = () => {
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
:show-brand="false"
|
:show-brand="false"
|
||||||
is-order
|
is-order
|
||||||
order-actions-layout
|
order-actions-layout
|
||||||
|
@download="handleDownload(order)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -96,7 +97,7 @@
|
|||||||
import { computed, onMounted, ref, shallowRef } from 'vue'
|
import { computed, onMounted, ref, shallowRef } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { fetchMyOrders } from '@/api/user'
|
import { fetchMyOrders ,fetchDownloadItemsByGet} from '@/api/user'
|
||||||
import ScItem from '@/views/shoppingCart/sc-item.vue'
|
import ScItem from '@/views/shoppingCart/sc-item.vue'
|
||||||
import Empty from './Empty.vue'
|
import Empty from './Empty.vue'
|
||||||
|
|
||||||
@@ -181,14 +182,10 @@
|
|||||||
return t('Wardrobe.orders.actions.buyAgain')
|
return t('Wardrobe.orders.actions.buyAgain')
|
||||||
}
|
}
|
||||||
|
|
||||||
const getOrderStatusValue = (status: unknown): ActualOrderStatus => {
|
|
||||||
if (status === 0 || status === '0' || status === 'unpaid') return 'unpaid'
|
|
||||||
if (status === 2 || status === '2' || status === 'cancelled') return 'cancelled'
|
|
||||||
return 'paid'
|
|
||||||
}
|
|
||||||
|
|
||||||
const getOrderStatus = (order: OrderRecord) => {
|
const getOrderStatus = (order: OrderRecord) => {
|
||||||
return getOrderStatusValue(order.status)
|
if (Number(order.status) === 0) return 'unpaid'
|
||||||
|
if (Number(order.status) === 2) return 'cancelled'
|
||||||
|
if (Number(order.status) === 1) return 'paid'
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatOrderUpdateTime = (dateStr: string) => {
|
const formatOrderUpdateTime = (dateStr: string) => {
|
||||||
@@ -221,7 +218,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getOrderItemInfo = (item: OrderItem, order: OrderRecord) => ({
|
const getOrderItemInfo = (item: OrderItem, order: OrderRecord) => ({
|
||||||
status: item.status,
|
status: order.status,
|
||||||
title: item.listingName,
|
title: item.listingName,
|
||||||
brand: order.shopName,
|
brand: order.shopName,
|
||||||
tags: item.productCategory,
|
tags: item.productCategory,
|
||||||
@@ -230,6 +227,43 @@
|
|||||||
cover: item.thumbnailUrl
|
cover: item.thumbnailUrl
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const resetOrders = () => {
|
||||||
|
ordersRequestId.value += 1
|
||||||
|
orders.value = []
|
||||||
|
expandedOrderId.value = ''
|
||||||
|
isLoadingOrders.value = false
|
||||||
|
hasMoreOrders.value = true
|
||||||
|
orderParams.value.page = 1
|
||||||
|
|
||||||
|
if (ordersScrollRef.value) {
|
||||||
|
ordersScrollRef.value.scrollTop = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setActiveStatus = (status: OrderStatus) => {
|
||||||
|
activeStatus.value = status
|
||||||
|
resetOrders()
|
||||||
|
fetchAllOrders()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOrdersScroll = () => {
|
||||||
|
const el = ordersScrollRef.value
|
||||||
|
if (!el) return
|
||||||
|
|
||||||
|
const reachBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 120
|
||||||
|
if (reachBottom) {
|
||||||
|
fetchAllOrders()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDownload = (order) => {
|
||||||
|
console.log(order)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRouteBrand = (order: OrderRecord) => {
|
||||||
|
ROUTER.push(`/brand/${order.sellerId}`)
|
||||||
|
}
|
||||||
|
|
||||||
const fetchAllOrders = async () => {
|
const fetchAllOrders = async () => {
|
||||||
if (isLoadingOrders.value || !hasMoreOrders.value) return
|
if (isLoadingOrders.value || !hasMoreOrders.value) return
|
||||||
|
|
||||||
@@ -267,39 +301,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetOrders = () => {
|
|
||||||
ordersRequestId.value += 1
|
|
||||||
orders.value = []
|
|
||||||
expandedOrderId.value = ''
|
|
||||||
isLoadingOrders.value = false
|
|
||||||
hasMoreOrders.value = true
|
|
||||||
orderParams.value.page = 1
|
|
||||||
|
|
||||||
if (ordersScrollRef.value) {
|
|
||||||
ordersScrollRef.value.scrollTop = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const setActiveStatus = (status: OrderStatus) => {
|
|
||||||
activeStatus.value = status
|
|
||||||
resetOrders()
|
|
||||||
fetchAllOrders()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleOrdersScroll = () => {
|
|
||||||
const el = ordersScrollRef.value
|
|
||||||
if (!el) return
|
|
||||||
|
|
||||||
const reachBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 120
|
|
||||||
if (reachBottom) {
|
|
||||||
fetchAllOrders()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleRouteBrand = (order: OrderRecord) => {
|
|
||||||
ROUTER.push(`/brand/${order.sellerId}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchAllOrders()
|
fetchAllOrders()
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user