Compare commits
26 Commits
09909552bc
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3de38d2856 | ||
|
|
2f1cc8d55d | ||
|
|
5d0de56c1a | ||
|
|
1b32002af5 | ||
|
|
59803cf2ea | ||
| d772cae6bc | |||
|
|
8c080d3e22 | ||
|
|
4be692bb29 | ||
|
|
7bfae7d024 | ||
|
|
e7957532e8 | ||
| 338ee24da2 | |||
| 81b907562e | |||
|
|
31de24cc2b | ||
|
|
c18b424f99 | ||
|
|
b9be27ab85 | ||
| 5476a1f69d | |||
| 9f620ab9d5 | |||
|
|
e418bf80ad | ||
|
|
2346e079a1 | ||
|
|
6772bf0e90 | ||
|
|
26dfbd9bb5 | ||
|
|
8c8ec7846d | ||
|
|
8d441766c5 | ||
|
|
bf907a1378 | ||
|
|
de6295f2af | ||
|
|
3e0a7b8928 |
@@ -1,3 +1 @@
|
|||||||
# VITE_APP_URL = http://192.168.31.82:8771
|
VITE_APP_URL = http://192.168.31.82:10094
|
||||||
# VITE_APP_URL = http://18.167.251.121:10095
|
|
||||||
VITE_APP_URL = https://www.lc-api.aida.com.hk
|
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
VITE_APP_URL = https://www.lc-api.aida.com.hk
|
VITE_APP_URL = http://192.168.31.82:10094
|
||||||
# VITE_APP_URL = http://18.167.251.121:10095
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
import ShoppingDrawer from '@/views/shopping-drawer.vue'
|
import ShoppingDrawer from '@/views/shopping-drawer.vue'
|
||||||
const globalStore = useGlobalStore()
|
const globalStore = useGlobalStore()
|
||||||
const loading = computed(() => globalStore.state.loading)
|
const loading = computed(() => globalStore.state.loading)
|
||||||
|
globalStore.setLoading(false)
|
||||||
const viewRef = ref()
|
const viewRef = ref()
|
||||||
const viewStyle = ref({
|
const viewStyle = ref({
|
||||||
'--app-view-width': '',
|
'--app-view-width': '',
|
||||||
@@ -52,10 +53,9 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
// background-color: rgba(0, 0, 0, 0.3);
|
--el-mask-color: rgba(0, 0, 0, 0.3);
|
||||||
// display: flex;
|
--el-color-primary: #007bff;
|
||||||
// align-items: center;
|
--el-loading-spinner-size: 9rem;
|
||||||
// justify-content: center;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
122
src/api/account.ts
Normal file
122
src/api/account.ts
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录发送验证码
|
||||||
|
* @param data - 包含邮箱的参数
|
||||||
|
* @param data.email - 邮箱
|
||||||
|
* @param data.password - 密码
|
||||||
|
*/
|
||||||
|
export const AccountSendLoginCode = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/account/preLogin',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
* @param data - 包含邮箱的参数
|
||||||
|
* @param data.email - 邮箱
|
||||||
|
* @param data.password - 密码
|
||||||
|
* @param data.emailVerifyCode - 验证码
|
||||||
|
*/
|
||||||
|
export const AccountLogin = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/account/login',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
* @param data - 包含注册信息的参数
|
||||||
|
* @param data.email - 邮箱
|
||||||
|
* @param data.password - 密码
|
||||||
|
* @param data.username - 用户名
|
||||||
|
* @param data.emailVerifyCode - 验证码
|
||||||
|
*/
|
||||||
|
export const AccountRegister = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/account/register',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 注册||忘记密码:发送邮箱验证码
|
||||||
|
* @param data - 包含邮箱的参数
|
||||||
|
* @param data.email - 邮箱
|
||||||
|
* @param data.operationType - 操作类型:FORGET_PWD, REGISTER
|
||||||
|
*/
|
||||||
|
export const AccountSendVerifyCode = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/account/sendCode',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 忘记密码:重置密码
|
||||||
|
* @param data - 包含邮箱的参数
|
||||||
|
* @param data.email - 邮箱
|
||||||
|
* @param data.password - 密码
|
||||||
|
* @param data.emailVerifyCode - 验证码
|
||||||
|
*/
|
||||||
|
export const AccountResetPassword = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/account/resetPassword',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 通用验证码校验
|
||||||
|
* @param data - 包含邮箱的参数
|
||||||
|
* @param data.email - 邮箱
|
||||||
|
* @param data.emailVerifyCode - 验证码
|
||||||
|
* @param data.operationType - 操作类型:FORGET_PWD, BIND_MAILBOX
|
||||||
|
*/
|
||||||
|
export const AccountVerifyCode = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/account/verifyCode',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变更邮箱:发送新邮箱验证码
|
||||||
|
* @param data - 包含邮箱的参数
|
||||||
|
* @param data.oldEmail - 旧邮箱
|
||||||
|
* @param data.newEmail - 新邮箱
|
||||||
|
*/
|
||||||
|
export const AccountSendEmailChangeCode = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/account/sendEmailChangeCode',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 变更邮箱:绑定新邮箱
|
||||||
|
* @param data - 包含邮箱的参数
|
||||||
|
* @param data.oldEmail - 旧邮箱
|
||||||
|
* @param data.newEmail - 新邮箱
|
||||||
|
* @param data.emailVerifyCode - 验证码
|
||||||
|
*/
|
||||||
|
export const AccountBindEmail = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/account/bindEmail',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading: true
|
||||||
|
})
|
||||||
|
}
|
||||||
35
src/api/brand.ts
Normal file
35
src/api/brand.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
/**
|
||||||
|
* 获取店铺列表
|
||||||
|
* @param data 获取店铺列表的参数
|
||||||
|
* @param data.keyword 模糊查询店铺
|
||||||
|
* @returns 获取店铺列表
|
||||||
|
*/
|
||||||
|
export interface designerListData {
|
||||||
|
keyword: string
|
||||||
|
}
|
||||||
|
export const getDesignerList = (data:designerListData,loading?:boolean) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/designer/search',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取店铺详情
|
||||||
|
* @param data 获取店铺详情的参数
|
||||||
|
* @param data.sellerId 店铺 id
|
||||||
|
* @returns 获取店铺详情
|
||||||
|
*/
|
||||||
|
export interface designerDetailData {
|
||||||
|
sellerId?: string
|
||||||
|
}
|
||||||
|
export const getDesignerDetail = (data:designerDetailData,loading?:boolean) => {
|
||||||
|
return request({
|
||||||
|
url: `/buyer/designer/shop/${data.sellerId}`,
|
||||||
|
method: 'get',
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
70
src/api/listing.ts
Normal file
70
src/api/listing.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
/**
|
||||||
|
* 获取店铺商品列表
|
||||||
|
* @param data 获取店铺商品列表的参数
|
||||||
|
* @param data.sellerId 店铺id
|
||||||
|
* @param data.designFor 查询类型 female/male/all
|
||||||
|
* @param data.pageNum 页码
|
||||||
|
* @param data.pageSize 页面大小
|
||||||
|
* @returns 获取店铺商品列表
|
||||||
|
*/
|
||||||
|
export interface listingListData {
|
||||||
|
sellerId?: string
|
||||||
|
designFor?: string
|
||||||
|
pageNum?: number
|
||||||
|
pageSize?: number
|
||||||
|
}
|
||||||
|
export const getlistingListApi = (data:listingListData,loading?:boolean) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/listing/shop/seller',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取商品详情
|
||||||
|
* @param data 获取商品详情的参数
|
||||||
|
* @param data.id 商品 id
|
||||||
|
* @returns 获取商品详情
|
||||||
|
*/
|
||||||
|
export interface listingDetailData {
|
||||||
|
id?: string
|
||||||
|
}
|
||||||
|
export const getListingDetailApi = (data:listingDetailData,loading?:boolean) => {
|
||||||
|
return request({
|
||||||
|
url: `/buyer/listing/mall/detail`,
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取资产数字商品列表
|
||||||
|
* @param data 获取资产数字商品列表的参数
|
||||||
|
* @param data.designFor 查询类型 female/male/all
|
||||||
|
* @param data.categories 商品分类
|
||||||
|
* @param data.sortField 排序字段 price/salesVolume/updateTime/viewCount/createTime,默认 updateTime
|
||||||
|
* @param data.sortOrder 排序顺序:asc/desc,默认 desc
|
||||||
|
* @param data.pageNum 页码
|
||||||
|
* @param data.pageSize 页面大小
|
||||||
|
* @returns 获取资产数字商品列表
|
||||||
|
*/
|
||||||
|
export interface listingMallData {
|
||||||
|
designFor: string,
|
||||||
|
categories: string[],
|
||||||
|
sortField: string,
|
||||||
|
sortOrder: string,
|
||||||
|
pageNum: number,
|
||||||
|
pageSize: number
|
||||||
|
}
|
||||||
|
export const getListingMallListApi = (data:listingMallData,loading?:boolean) => {
|
||||||
|
return request({
|
||||||
|
url: `/buyer/listing/mall`,
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
import request from '@/utils/request'
|
|
||||||
|
|
||||||
interface LoginParamsType {
|
|
||||||
name?: string // 姓名
|
|
||||||
email: string // 邮箱
|
|
||||||
password?: string // 密码
|
|
||||||
operationType: 'REGISTER' | 'LOGIN' | 'FORGET_PWD'
|
|
||||||
verifyCode?: string // 验证码
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送验证码
|
|
||||||
export const precheckEmail = (params: { email: string }): Promise<ApiResponse> => {
|
|
||||||
return request({
|
|
||||||
url: '/api/auth/precheckEmail',
|
|
||||||
method: 'get',
|
|
||||||
params
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetchRegisterOrLogin = (data: LoginParamsType): Promise<LoginResponse> => {
|
|
||||||
return request({
|
|
||||||
url: '/api/auth/registerOrLogin',
|
|
||||||
method: 'post',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const resetPassword = (data: LoginParamsType): Promise<ApiResponse> => {
|
|
||||||
return request({
|
|
||||||
url: '/api/auth/forgotPwd',
|
|
||||||
method: 'post',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const checkLoginStatus = (): Promise<ApiResponse<LoginResponse>> => {
|
|
||||||
return request({
|
|
||||||
url: '/api/auth/checkLoginStatus',
|
|
||||||
method: 'get',
|
|
||||||
meta: { responseAll: true }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const LogOut = (): Promise<ApiResponse> => {
|
|
||||||
return request({
|
|
||||||
url: '/api/auth/logout',
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Google登录/注册参数类型
|
|
||||||
interface GoogleAuthParamsType {
|
|
||||||
accessToken?: string // Google ID Token (用于One Tap登录)
|
|
||||||
}
|
|
||||||
export const googleAuth = (data: GoogleAuthParamsType): Promise<LoginResponse> => {
|
|
||||||
return request({
|
|
||||||
url: '/api/auth/parseGoogleAccessToken',
|
|
||||||
method: 'get',
|
|
||||||
params: data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** 更改用户信息
|
|
||||||
* @param data 包含用户信息的对象
|
|
||||||
* @param data.username 用户名
|
|
||||||
* @param data.email 邮箱
|
|
||||||
* @param data.password 密码
|
|
||||||
* @returns 包含更新后的用户信息的对象
|
|
||||||
*/
|
|
||||||
export const updateUserInfo = (data: any) => {
|
|
||||||
return request({
|
|
||||||
url: '/api/auth/updateUserInfo',
|
|
||||||
method: 'post',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
69
src/api/shoppingCart.ts
Normal file
69
src/api/shoppingCart.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入购物车
|
||||||
|
* @param data - 包含邮箱的参数
|
||||||
|
* @param data.listingId - 商品ID
|
||||||
|
* @param data.listingIds - 商品ID列表
|
||||||
|
*/
|
||||||
|
export const AddShoppingCart = (data, loading?: boolean) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/buyer/cart/add',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空购物车
|
||||||
|
*/
|
||||||
|
export const ClearShoppingCart = (loading?: boolean) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/buyer/cart/clear',
|
||||||
|
method: 'delete',
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取购物车列表
|
||||||
|
* @param loading - 是否显示loading
|
||||||
|
* @returns 购物车列表数据
|
||||||
|
*/
|
||||||
|
export const GetShoppingCartList = (loading?: boolean) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/buyer/cart/list',
|
||||||
|
method: 'get',
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从购物车移除商品
|
||||||
|
* @param params - 包含邮箱的参数
|
||||||
|
* @param params.listingId - 商品ID
|
||||||
|
*/
|
||||||
|
export const RemoveShoppingCartItem = (params, loading?: boolean) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/buyer/cart/remove',
|
||||||
|
method: 'delete',
|
||||||
|
params,
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建订单
|
||||||
|
* @param { Array } data - 商品id数组
|
||||||
|
* @param loading - 是否显示loading
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const CreateOrder = (data, loading?: boolean) => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/buyer/order/create',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
loading
|
||||||
|
})
|
||||||
|
}
|
||||||
30
src/api/user.ts
Normal file
30
src/api/user.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export interface WardrobeItem {
|
||||||
|
buyerId: number
|
||||||
|
categories: string[]
|
||||||
|
designFor: 'female' | 'male' | 'all'
|
||||||
|
page: number
|
||||||
|
size: number
|
||||||
|
}
|
||||||
|
export const fetchMyWardrobe = (data: WardrobeItem): Promise<ApiResponse> => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/buyer/order/assets/page',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderItem {
|
||||||
|
status: number // 0未支付 1已支付 2已取消 不穿查全部
|
||||||
|
page: number
|
||||||
|
size: number
|
||||||
|
}
|
||||||
|
export const fetchMyOrders = (data: OrderItem): Promise<ApiResponse> => {
|
||||||
|
return request({
|
||||||
|
url: '/buyer/buyer/order/page',
|
||||||
|
method: 'get',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
5
src/assets/icons/order/warning.svg
Normal file
5
src/assets/icons/order/warning.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 20C8.02219 20 6.08879 19.4135 4.4443 18.3147C2.79981 17.2159 1.51809 15.6541 0.761209 13.8268C0.00433286 11.9996 -0.193701 9.98891 0.192152 8.0491C0.578004 6.10929 1.53041 4.32746 2.92894 2.92894C4.32746 1.53041 6.10929 0.578004 8.0491 0.192152C9.98891 -0.193701 11.9996 0.00433286 13.8268 0.761209C15.6541 1.51809 17.2159 2.79981 18.3147 4.4443C19.4135 6.08879 20 8.02219 20 10C19.9971 12.6513 18.9426 15.1932 17.0679 17.0679C15.1932 18.9426 12.6513 19.9971 10 20ZM10 1.66667C8.35183 1.66667 6.74066 2.15541 5.37025 3.07109C3.99984 3.98677 2.93174 5.28826 2.30101 6.81098C1.67028 8.33369 1.50525 10.0092 1.82679 11.6258C2.14834 13.2423 2.94201 14.7271 4.10745 15.8926C5.27289 17.058 6.75774 17.8517 8.37425 18.1732C9.99076 18.4948 11.6663 18.3297 13.189 17.699C14.7118 17.0683 16.0132 16.0002 16.9289 14.6298C17.8446 13.2593 18.3333 11.6482 18.3333 10C18.3309 7.79061 17.4522 5.67241 15.8899 4.11013C14.3276 2.54785 12.2094 1.6691 10 1.66667Z" fill="#232323"/>
|
||||||
|
<path d="M11.6654 15.8333H9.9987V9.99998H8.33203V8.33331H9.9987C10.4407 8.33331 10.8646 8.50891 11.1772 8.82147C11.4898 9.13403 11.6654 9.55795 11.6654 9.99998V15.8333Z" fill="#232323"/>
|
||||||
|
<path d="M10 6.66666C10.6904 6.66666 11.25 6.10701 11.25 5.41666C11.25 4.7263 10.6904 4.16666 10 4.16666C9.30964 4.16666 8.75 4.7263 8.75 5.41666C8.75 6.10701 9.30964 6.66666 10 6.66666Z" fill="#232323"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
5
src/assets/icons/shop.svg
Normal file
5
src/assets/icons/shop.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 6.4C20 5.3 19.1 4 18 4H7.5C7.4 4 7.2 4 7.1 4C5.9 4.2 5 5.2 5 6.4L4 9C4 10.4 5.1 11.5 6.5 11.5C7.9 11.5 8.1 11.1 8.5 10.5C8.9 11.1 9.7 11.5 10.5 11.5C11.3 11.5 12.1 11.1 12.5 10.5C12.9 11.1 13.7 11.5 14.5 11.5C15.3 11.5 16.1 11.1 16.5 10.5C16.9 11.1 17.7 11.5 18.5 11.5C19.9 11.5 21 10.4 21 9M5.9 6.4C5.9 5.6 6.5 5 7.2 4.9C7.2 4.9 7.3 4.9 7.4 4.9H17.9C18.5 4.9 19 5.8 19 6.4C19 7 20 9.1 20 9.1C20 10 19.3 10.7 18.4 10.7C17.5 10.7 16.8 10 16.8 9.1V7.6H15.9V9.1C15.9 10 15.2 10.7 14.3 10.7C13.4 10.7 12.7 10 12.7 9.1V7.6H11.8V9.1C11.8 10 11.1 10.7 10.2 10.7C9.3 10.7 8.6 10 8.6 9.1V7.6H7.7V9.1C7.7 10 7.50938 10.7 6.60938 10.7C5.48438 10.7 4.9 9.9 4.9 9L5.9 6.4Z" fill="#232323"/>
|
||||||
|
<path d="M6 11.2V19.3C6 19.9 6.4 20.3 7 20.3H18C18.6 20.3 19 19.9 19 19.3V13.5" stroke="#232323" stroke-width="0.75" stroke-linecap="round"/>
|
||||||
|
<path d="M17 15.5V13.5C17 13.2239 16.7761 13 16.5 13C16.2239 13 16 13.2239 16 13.5V15.5C16 15.7761 16.2239 16 16.5 16C16.7761 16 17 15.7761 17 15.5Z" fill="#232323"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
4
src/assets/icons/statement.svg
Normal file
4
src/assets/icons/statement.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.32919 0C3.73406 0 0 3.7382 0 8.33333C0 12.9285 3.7382 16.6667 8.32919 16.6667C12.9202 16.6667 16.6584 12.9285 16.6584 8.33333C16.6584 3.7382 12.9243 0 8.32919 0ZM8.32919 15.7352C4.24739 15.7352 0.927306 12.4151 0.927306 8.33333C0.927306 4.25153 4.24739 0.931445 8.32919 0.931445C12.411 0.931445 15.7311 4.25153 15.7311 8.33333C15.7311 12.4151 12.411 15.7352 8.32919 15.7352Z" fill="#979797"/>
|
||||||
|
<path d="M8.84744 7.50551C8.84744 7.21972 8.61576 6.98804 8.32997 6.98804C8.04418 6.98804 7.8125 7.21972 7.8125 7.50551V12.4732C7.8125 12.759 8.04418 12.9907 8.32997 12.9907C8.61576 12.9907 8.84744 12.759 8.84744 12.4732V7.50551Z" fill="#979797"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 756 B |
@@ -47,7 +47,7 @@ const {} = toRefs(data)
|
|||||||
<div class="name">
|
<div class="name">
|
||||||
{{ props.name }}
|
{{ props.name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="price" :class="{ 'is-download': download }" v-if="props.showPrice">
|
<div class="price" :class="{ 'is-download': download }" v-if="props.showPrice && props.price">
|
||||||
{{ props.price }}
|
{{ props.price }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
'update:selected'
|
'update:selected','change'
|
||||||
])
|
])
|
||||||
const checkList = computed(()=>{
|
const checkList = computed(()=>{
|
||||||
if(props.selected[0] === ''){
|
if(props.selected[0] === ''){
|
||||||
@@ -22,16 +22,18 @@ const checkList = computed(()=>{
|
|||||||
})
|
})
|
||||||
const handleChange = (val) => {
|
const handleChange = (val) => {
|
||||||
emit('update:selected', val)
|
emit('update:selected', val)
|
||||||
|
emit('change', val)
|
||||||
}
|
}
|
||||||
const checkAll = computed(()=>{
|
const checkAll = computed(()=>{
|
||||||
return checkList.value.length === props.list.length
|
return checkList.value.length === props.list.length
|
||||||
})
|
})
|
||||||
const handleCheckAllChange = (val) => {
|
const handleCheckAllChange = (val) => {
|
||||||
|
let data = []
|
||||||
if(val){
|
if(val){
|
||||||
emit('update:selected', props.list.map(item => item.value))
|
data = props.list.map(item => item.value)
|
||||||
}else{
|
|
||||||
emit('update:selected', [])
|
|
||||||
}
|
}
|
||||||
|
emit('update:selected', data)
|
||||||
|
emit('change', data)
|
||||||
}
|
}
|
||||||
let data = reactive({
|
let data = reactive({
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -127,5 +127,73 @@ export default {
|
|||||||
singapore: 'Singapore',
|
singapore: 'Singapore',
|
||||||
unitedKingdom: 'United Kingdom'
|
unitedKingdom: 'United Kingdom'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Wardrobe: {
|
||||||
|
title: 'My Wardrobe',
|
||||||
|
subtitle: 'Your digital pieces, all in one place',
|
||||||
|
common: {
|
||||||
|
all: 'All',
|
||||||
|
currencyHkd: 'HKD'
|
||||||
|
},
|
||||||
|
tabs: {
|
||||||
|
ariaLabel: 'Wardrobe tabs',
|
||||||
|
assets: 'Assets',
|
||||||
|
orders: 'Orders'
|
||||||
|
},
|
||||||
|
sort: {
|
||||||
|
label: 'Sort by',
|
||||||
|
placeholder: 'Select',
|
||||||
|
default: 'Default',
|
||||||
|
dateAdded: 'Date Added',
|
||||||
|
selectedFirst: 'Selected First'
|
||||||
|
},
|
||||||
|
assets: {
|
||||||
|
filters: 'Filters',
|
||||||
|
clear: 'Clear',
|
||||||
|
categories: 'Categories',
|
||||||
|
gender: 'Gender',
|
||||||
|
selectedCount: '{count} Selected',
|
||||||
|
selectAll: 'Select All',
|
||||||
|
deselectAll: 'Deselect All',
|
||||||
|
downloadSelected: 'Download Selected',
|
||||||
|
genders: {
|
||||||
|
male: 'Male',
|
||||||
|
female: 'Female'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
orders: {
|
||||||
|
moreItems: '+{count} more',
|
||||||
|
statuses: {
|
||||||
|
all: 'All',
|
||||||
|
paid: 'Paid',
|
||||||
|
unpaid: 'Unpaid',
|
||||||
|
cancelled: 'Canceled'
|
||||||
|
},
|
||||||
|
statusBadges: {
|
||||||
|
paid: 'PAID',
|
||||||
|
unpaid: 'UNPAID',
|
||||||
|
cancelled: 'CANCELED'
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
invoice: 'Invoice',
|
||||||
|
completePayment: 'Complete Payment',
|
||||||
|
buyAgain: 'Buy Again'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
empty: {
|
||||||
|
title: 'Nothing in Wardrobe yet',
|
||||||
|
description: 'Explore the digital item and add pieces to your collection.',
|
||||||
|
action: 'Explore Digital Items'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ClothesCategories: {
|
||||||
|
blouses: 'Blouse',
|
||||||
|
dress: 'Dress',
|
||||||
|
trousers: 'Trousers',
|
||||||
|
skirt: 'Skirt',
|
||||||
|
tops: 'Tops',
|
||||||
|
bottoms: 'Bottoms',
|
||||||
|
outwear: 'Outwear',
|
||||||
|
others: 'Others'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,5 +127,73 @@ export default {
|
|||||||
singapore: '新加坡',
|
singapore: '新加坡',
|
||||||
unitedKingdom: '英国'
|
unitedKingdom: '英国'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Wardrobe: {
|
||||||
|
title: '我的衣橱',
|
||||||
|
subtitle: '你的数字单品尽在此处',
|
||||||
|
common: {
|
||||||
|
all: '全部',
|
||||||
|
currencyHkd: 'HKD'
|
||||||
|
},
|
||||||
|
tabs: {
|
||||||
|
ariaLabel: '衣橱标签页',
|
||||||
|
assets: '资产',
|
||||||
|
orders: '订单'
|
||||||
|
},
|
||||||
|
sort: {
|
||||||
|
label: '排序',
|
||||||
|
placeholder: '请选择',
|
||||||
|
default: '默认',
|
||||||
|
dateAdded: '添加日期',
|
||||||
|
selectedFirst: '已选优先'
|
||||||
|
},
|
||||||
|
assets: {
|
||||||
|
filters: '筛选',
|
||||||
|
clear: '清除',
|
||||||
|
categories: '类别',
|
||||||
|
gender: '性别',
|
||||||
|
selectedCount: '已选择 {count} 件',
|
||||||
|
selectAll: '全选',
|
||||||
|
deselectAll: '取消全选',
|
||||||
|
downloadSelected: '下载已选',
|
||||||
|
genders: {
|
||||||
|
male: '男',
|
||||||
|
female: '女'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
orders: {
|
||||||
|
moreItems: '还有 {count} 件',
|
||||||
|
statuses: {
|
||||||
|
all: '全部',
|
||||||
|
paid: '已支付',
|
||||||
|
unpaid: '待支付',
|
||||||
|
cancelled: '已取消'
|
||||||
|
},
|
||||||
|
statusBadges: {
|
||||||
|
paid: '已支付',
|
||||||
|
unpaid: '待支付',
|
||||||
|
cancelled: '已取消'
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
invoice: '发票',
|
||||||
|
completePayment: '完成付款',
|
||||||
|
buyAgain: '再次购买'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
empty: {
|
||||||
|
title: '衣橱暂无内容',
|
||||||
|
description: '探索数字单品,并添加到你的收藏。',
|
||||||
|
action: '探索数字单品'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ClothesCategories: {
|
||||||
|
blouses: '衬衫',
|
||||||
|
dress: '连衣裙',
|
||||||
|
trousers: '裤子',
|
||||||
|
skirt: '短裙',
|
||||||
|
tops: '上装',
|
||||||
|
bottoms: '下装',
|
||||||
|
outwear: '外套',
|
||||||
|
others: '其他'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,67 +4,48 @@ import { ref, computed } from 'vue'
|
|||||||
import { removeLocal, setLocal } from '@/utils/local'
|
import { removeLocal, setLocal } from '@/utils/local'
|
||||||
import MyEvent from '@/utils/myEvent'
|
import MyEvent from '@/utils/myEvent'
|
||||||
export const useUserInfoStore = defineStore('userInfo', () => {
|
export const useUserInfoStore = defineStore('userInfo', () => {
|
||||||
const state = ref({
|
const state = ref({
|
||||||
userInfo: {},
|
userInfo: {
|
||||||
token: '',
|
userId: "",
|
||||||
generateParams: {
|
email: "",
|
||||||
stylist: '',
|
username: "",
|
||||||
sex: '',
|
accessToken: "",
|
||||||
stylistImage: ''
|
expiresIn: "",
|
||||||
}
|
},
|
||||||
})
|
token: ''
|
||||||
|
})
|
||||||
|
|
||||||
// getters
|
// actions
|
||||||
const getUserInfo = computed(() => state.value.userInfo)
|
const setUserInfo = (data: any) => {
|
||||||
|
state.value.userInfo = data
|
||||||
|
setToken(data.accessToken)
|
||||||
|
}
|
||||||
|
|
||||||
// actions
|
const setToken = (data: string) => {
|
||||||
const setUserInfo = (data: any) => {
|
state.value.token = data
|
||||||
state.value.userInfo = data
|
setLocal(data, 'token')
|
||||||
}
|
}
|
||||||
|
|
||||||
const setToken = (data: string) => {
|
const logout = () => {
|
||||||
state.value.token = data
|
// 处理退出登录的一些逻辑
|
||||||
setLocal(data, 'token')
|
return new Promise((resolve) => {
|
||||||
}
|
state.value.userInfo = {
|
||||||
|
userId: "",
|
||||||
|
email: "",
|
||||||
|
username: "",
|
||||||
|
accessToken: "",
|
||||||
|
expiresIn: "",
|
||||||
|
}
|
||||||
|
state.value.token = ''
|
||||||
|
removeLocal('token')
|
||||||
|
resolve('')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const getGenerateParams = () => {
|
return {
|
||||||
return state.value.generateParams
|
state,
|
||||||
}
|
setToken,
|
||||||
|
setUserInfo,
|
||||||
const setGenerateParams = (data: any) => {
|
logout
|
||||||
state.value.generateParams = data
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const resetGenerateParams = () => {
|
|
||||||
state.value.generateParams = {
|
|
||||||
stylist: '',
|
|
||||||
sex: '',
|
|
||||||
stylistImage: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const logOut = () => {
|
|
||||||
// 处理退出登录的一些逻辑
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
state.value.token = ''
|
|
||||||
state.value.userInfo = {}
|
|
||||||
removeLocal('token')
|
|
||||||
resetGenerateParams()
|
|
||||||
MyEvent.emit('clear-generate-state')
|
|
||||||
MyEvent.emit('clear-client-state')
|
|
||||||
MyEvent.emit('clearAllCache')
|
|
||||||
resolve('')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
state,
|
|
||||||
getUserInfo,
|
|
||||||
setToken,
|
|
||||||
setUserInfo,
|
|
||||||
setGenerateParams,
|
|
||||||
getGenerateParams,
|
|
||||||
resetGenerateParams,
|
|
||||||
logOut
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|||||||
71
src/utils/ClothesCategory.ts
Normal file
71
src/utils/ClothesCategory.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import i18n from '@/lang'
|
||||||
|
|
||||||
|
type Translate = (key: string) => string
|
||||||
|
|
||||||
|
const clothesCategoryConfigs = [
|
||||||
|
{
|
||||||
|
key: 'blouses',
|
||||||
|
value: 'blouses'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dress',
|
||||||
|
value: 'dress'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'trousers',
|
||||||
|
value: 'trousers'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'skirt',
|
||||||
|
value: 'skirt'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'tops',
|
||||||
|
value: 'tops'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'bottoms',
|
||||||
|
value: 'bottoms'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'outwear',
|
||||||
|
value: 'outwear'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'others',
|
||||||
|
value: 'others'
|
||||||
|
}
|
||||||
|
] as const
|
||||||
|
|
||||||
|
export type ClothesCategoryValue = (typeof clothesCategoryConfigs)[number]['value']
|
||||||
|
|
||||||
|
export interface ClothesCategory {
|
||||||
|
name: string
|
||||||
|
label: string
|
||||||
|
value: ClothesCategoryValue
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createClothesCategories = (t: Translate = i18n.global.t): ClothesCategory[] =>
|
||||||
|
clothesCategoryConfigs.map(({ key, value }) => ({
|
||||||
|
name: t(`ClothesCategories.${key}`),
|
||||||
|
label: t(`ClothesCategories.${key}`),
|
||||||
|
value
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const ClothesCategories: ClothesCategory[] = clothesCategoryConfigs.map(({ key, value }) => ({
|
||||||
|
get name() {
|
||||||
|
return i18n.global.t(`ClothesCategories.${key}`)
|
||||||
|
},
|
||||||
|
get label() {
|
||||||
|
return i18n.global.t(`ClothesCategories.${key}`)
|
||||||
|
},
|
||||||
|
value
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const useClothesCategories = () => {
|
||||||
|
const { t } = useI18n({ useScope: 'global' })
|
||||||
|
|
||||||
|
return computed(() => createClothesCategories(t))
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ service.interceptors.request.use(
|
|||||||
// Do something before request is sent
|
// Do something before request is sent
|
||||||
const token = useUserInfoStore().state.token
|
const token = useUserInfoStore().state.token
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers.Authorization = 'Bearer ' + token // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
config.headers.Authorization = token // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
||||||
// config.headers['X-Token'] = getLocal('token') // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
// config.headers['X-Token'] = getLocal('token') // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
@@ -75,9 +75,10 @@ service.interceptors.response.use(
|
|||||||
const res = response.data
|
const res = response.data
|
||||||
// 处理异常的情况
|
// 处理异常的情况
|
||||||
// console.log(res)
|
// console.log(res)
|
||||||
if (res.code != 200) {
|
if (res.errCode != 0) {
|
||||||
ElMessage.error(res.message)
|
let msg = res.errMsg || res.message || 'error'
|
||||||
return Promise.reject(new Error(res.errMsg || res.message || 'error'))
|
ElMessage.error(msg)
|
||||||
|
return Promise.reject(new Error(msg))
|
||||||
} else {
|
} else {
|
||||||
// 默认只返回data,不返回状态码和message
|
// 默认只返回data,不返回状态码和message
|
||||||
// 通过 meta 中的 responseAll 配置来取决后台是否返回所有数据(包括状态码,message和data)
|
// 通过 meta 中的 responseAll 配置来取决后台是否返回所有数据(包括状态码,message和data)
|
||||||
@@ -109,8 +110,7 @@ service.interceptors.response.use(
|
|||||||
message: 'Please log in and try again.',
|
message: 'Please log in and try again.',
|
||||||
duration: 5000
|
duration: 5000
|
||||||
})
|
})
|
||||||
router.push('/login')
|
useUserInfoStore().logout()
|
||||||
useUserInfoStore().logOut(false)
|
|
||||||
return Promise.reject(false)
|
return Promise.reject(false)
|
||||||
}
|
}
|
||||||
error.config && removePending(error.config)
|
error.config && removePending(error.config)
|
||||||
|
|||||||
@@ -25,25 +25,25 @@ const {} = toRefs(data);
|
|||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="portrait">
|
<div class="portrait">
|
||||||
<img :src="item.portrait" alt="">
|
<img :src="item.avatar" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div class="name">{{ item.name }}</div>
|
<div class="name">{{ item.shopName }}</div>
|
||||||
<div class="collection">
|
<div class="collection">
|
||||||
{{ item.collectionsName }} |
|
{{ item.ownerName }} |
|
||||||
{{ item?.collections?.length || 0 }} Collections
|
{{ item?.listingTotal || 0 }} Collections
|
||||||
</div>
|
</div>
|
||||||
<div class="view-profile" @click="viewProfile(item)">View Profile</div>
|
<div class="view-profile" @click="viewProfile(item)">View Profile</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="img-list">
|
<div class="img-list">
|
||||||
<div class="img-item" v-for="itemImg in item?.collections?.slice(0,5)" :key="item.id">
|
<div class="img-item" v-for="itemImg in item?.covers" :key="itemImg">
|
||||||
<img :src="itemImg" alt="">
|
<img :src="itemImg" alt="">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="more">
|
<div class="more">
|
||||||
<div class="icon" v-show="item?.collections?.length > 5">
|
<div class="icon" v-show="item?.covers?.length == 5">
|
||||||
<svgIcon name="brand-more" size="24" />
|
<svgIcon name="brand-more" size="24" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { useRouter } from "vue-router";
|
|||||||
import myEvent from '@/utils/myEvent'
|
import myEvent from '@/utils/myEvent'
|
||||||
import scListNull from '@/views/shoppingCart/sc-list-null.vue'
|
import scListNull from '@/views/shoppingCart/sc-list-null.vue'
|
||||||
import brandItem from '@/views/brand/brand-item.vue'
|
import brandItem from '@/views/brand/brand-item.vue'
|
||||||
|
import { getDesignerList } from '@/api/brand'
|
||||||
|
|
||||||
|
|
||||||
import img from '@/assets/images/collectionStory/Rectangle.png'
|
import img from '@/assets/images/collectionStory/Rectangle.png'
|
||||||
//const props = defineProps({
|
//const props = defineProps({
|
||||||
@@ -23,87 +25,89 @@ const getMerchantData = reactive({
|
|||||||
isShowMark:false,
|
isShowMark:false,
|
||||||
isNoData:false,
|
isNoData:false,
|
||||||
})
|
})
|
||||||
const list = ref([
|
const searchHistory = ref([
|
||||||
' 1',
|
|
||||||
'Brand 2',
|
|
||||||
'Brand 3',
|
|
||||||
'1213123 4',
|
|
||||||
'Brand 4',
|
|
||||||
'2222 4',
|
|
||||||
'B23rand 4',
|
|
||||||
'Bran112222d 4',
|
|
||||||
' 4',
|
|
||||||
])
|
])
|
||||||
|
|
||||||
let changeSearchBrandTime = null
|
let changeSearchBrandTime = null
|
||||||
const changeSearchBrand = () => {
|
const changeSearchBrand = () => {
|
||||||
clearTimeout(changeSearchBrandTime)
|
clearTimeout(changeSearchBrandTime)
|
||||||
changeSearchBrandTime = setTimeout(()=>{
|
getDesignerList({
|
||||||
getMerchantData.pageNum = 1
|
keyword: searchBrand.value,
|
||||||
|
}).then((res)=>{
|
||||||
merchantList.value = []
|
merchantList.value = []
|
||||||
getMerchantData.isShowMark = false
|
merchantList.value.push(...res)
|
||||||
getMerchantData.isNoData = false
|
})
|
||||||
},300)
|
// changeSearchBrandTime = setTimeout(()=>{
|
||||||
|
// getMerchantData.pageNum = 1
|
||||||
|
// getMerchantData.isShowMark = false
|
||||||
|
// getMerchantData.isNoData = false
|
||||||
|
// },300)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getBrandList = async () => {
|
// const getBrandList = async () => {
|
||||||
if(getMerchantData.isShowMark && !getMerchantData.isNoData)return
|
// if(getMerchantData.isShowMark && !getMerchantData.isNoData)return
|
||||||
getMerchantData.isShowMark = true
|
// getMerchantData.isShowMark = true
|
||||||
let value = {
|
// let value = {
|
||||||
pageSize: getMerchantData.pageSize,
|
// pageSize: getMerchantData.pageSize,
|
||||||
pageNum: getMerchantData.pageNum,
|
// pageNum: getMerchantData.pageNum,
|
||||||
status: 1,
|
// status: 1,
|
||||||
}
|
// }
|
||||||
setTimeout(()=>{
|
// setTimeout(()=>{
|
||||||
if(merchantList.value.length >= 5){
|
// if(merchantList.value.length >= 5){
|
||||||
getMerchantData.isNoData = true
|
// getMerchantData.isNoData = true
|
||||||
merchantList.value = []
|
// merchantList.value = []
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
getMerchantData.pageNum += 1
|
// getMerchantData.pageNum += 1
|
||||||
merchantList.value.push({
|
// merchantList.value.push({
|
||||||
name:'Roaming Clouds',
|
// name:'Roaming Clouds',
|
||||||
portrait: img,
|
// portrait: img,
|
||||||
collectionsName:'by Lian Su ',
|
// collectionsName:'by Lian Su ',
|
||||||
collections:[
|
// collections:[
|
||||||
img,img,img,
|
// img,img,img,
|
||||||
],
|
// ],
|
||||||
})
|
// })
|
||||||
getMerchantData.isShowMark = false
|
// getMerchantData.isShowMark = false
|
||||||
},1000)
|
// },1000)
|
||||||
// await getPublishList(value).then((res)=>{
|
// // await getPublishList(value).then((res)=>{
|
||||||
// if(res.content.length == 0)getMerchantData.isNoData = true
|
// // if(res.content.length == 0)getMerchantData.isNoData = true
|
||||||
// getMerchantData.pageNum += 1
|
// // getMerchantData.pageNum += 1
|
||||||
// list.value.push(...res.content)
|
// // list.value.push(...res.content)
|
||||||
// })
|
// // })
|
||||||
}
|
// }
|
||||||
const vObserve = {
|
// const vObserve = {
|
||||||
mounted (el,binding) {
|
// mounted (el,binding) {
|
||||||
getMerchantData.isShowMark = false
|
// getMerchantData.isShowMark = false
|
||||||
getMerchantData.isNoData = false
|
// getMerchantData.isNoData = false
|
||||||
new IntersectionObserver(
|
// new IntersectionObserver(
|
||||||
(entries, observer) => {
|
// (entries, observer) => {
|
||||||
// 如果不是相交,则直接返回
|
// // 如果不是相交,则直接返回
|
||||||
// console.log(entries[0]);
|
// // console.log(entries[0]);
|
||||||
if (!entries[0].intersectionRatio) return;
|
// if (!entries[0].intersectionRatio) return;
|
||||||
getMerchantData.pageNum += 1
|
// getMerchantData.pageNum += 1
|
||||||
binding.value()
|
// binding.value()
|
||||||
},
|
// },
|
||||||
// { root:worksPage }
|
// // { root:worksPage }
|
||||||
).observe(el);
|
// ).observe(el);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
const deleteHistory = (item) => {
|
const deleteHistory = (item) => {
|
||||||
list.value = list.value.filter((i) => i != item)
|
searchHistory.value = searchHistory.value.filter((i) => i != item)
|
||||||
|
localStorage.setItem('brandSearchHistory', JSON.stringify(searchHistory.value));
|
||||||
}
|
}
|
||||||
const viewProfile = (item) => {
|
const viewProfile = (item) => {
|
||||||
|
if(!searchHistory.value.includes(searchBrand.value))searchHistory.value.push(searchBrand.value)
|
||||||
|
localStorage.setItem('brandSearchHistory', JSON.stringify(searchHistory.value));
|
||||||
router.push({
|
router.push({
|
||||||
path:'/brand/1',
|
path:'/brand/'+item.sellerId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
|
const value = localStorage.getItem('brandSearchHistory');
|
||||||
|
if(value)searchHistory.value = JSON.parse(value)
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
})
|
})
|
||||||
@@ -129,10 +133,10 @@ const {} = toRefs(data);
|
|||||||
<div class="merchantList" v-if="searchBrand.length > 0">
|
<div class="merchantList" v-if="searchBrand.length > 0">
|
||||||
<brand-item v-for="item in merchantList" :key="item.name" :item="item" @viewProfile="viewProfile"></brand-item>
|
<brand-item v-for="item in merchantList" :key="item.name" :item="item" @viewProfile="viewProfile"></brand-item>
|
||||||
<div class="end" v-show="!getMerchantData.isNoData && !getMerchantData.isShowMark">- The End-</div>
|
<div class="end" v-show="!getMerchantData.isNoData && !getMerchantData.isShowMark">- The End-</div>
|
||||||
<div v-show="!getMerchantData.isNoData" class="material_content_list_loding">
|
<!-- <div v-show="!getMerchantData.isNoData" class="material_content_list_loding">
|
||||||
<span class="page_loading" v-show="!getMerchantData.isShowMark" v-observe="getBrandList"></span>
|
<span class="page_loading" v-show="!getMerchantData.isShowMark" v-observe="getBrandList"></span>
|
||||||
<img v-if="getMerchantData.isShowMark" src="@/assets/images/brand/brandLoading.gif" alt="">
|
<img v-if="getMerchantData.isShowMark" src="@/assets/images/brand/brandLoading.gif" alt="">
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<div class="merchantListNull" v-if="getMerchantData.isNoData && searchBrand.length > 0">
|
<div class="merchantListNull" v-if="getMerchantData.isNoData && searchBrand.length > 0">
|
||||||
<sc-list-null
|
<sc-list-null
|
||||||
@@ -151,7 +155,7 @@ const {} = toRefs(data);
|
|||||||
<span>Searching History</span>
|
<span>Searching History</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="history">
|
<div class="history">
|
||||||
<div v-for="item in list" :key="item" @click.stop="searchBrand = item" class="item">
|
<div v-for="item in searchHistory" :key="item" @click.stop="searchBrand = item" class="item">
|
||||||
<span>{{item}}</span>
|
<span>{{item}}</span>
|
||||||
<div class="icon" @click.stop="deleteHistory(item)">
|
<div class="icon" @click.stop="deleteHistory(item)">
|
||||||
<SvgIcon name="brand-delete" size="18" />
|
<SvgIcon name="brand-delete" size="18" />
|
||||||
|
|||||||
@@ -1,54 +1,70 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
||||||
import img from "@/assets/images/collectionStory/Rectangle.png";
|
import img from "@/assets/images/collectionStory/Rectangle.png";
|
||||||
//const props = defineProps({
|
import { getlistingListApi } from "@/api/listing";
|
||||||
//})
|
|
||||||
const emit = defineEmits([
|
const props = defineProps({
|
||||||
'addShopping'
|
id: {
|
||||||
])
|
type: String,
|
||||||
let data = reactive({
|
default: ''
|
||||||
})
|
|
||||||
const list = ref([
|
|
||||||
{
|
|
||||||
url: img,
|
|
||||||
title: "Windswept Burden",
|
|
||||||
price: "$100.00",
|
|
||||||
},{
|
|
||||||
url: img,
|
|
||||||
title: "Windswept Burden",
|
|
||||||
price: "$100.00",
|
|
||||||
},{
|
|
||||||
url: img,
|
|
||||||
title: "Windswept Burden",
|
|
||||||
price: "$100.00",
|
|
||||||
},{
|
|
||||||
url: img,
|
|
||||||
title: "Windswept Burden",
|
|
||||||
price: "$100.00",
|
|
||||||
},{
|
|
||||||
url: img,
|
|
||||||
title: "Windswept Burden",
|
|
||||||
price: "$100.00",
|
|
||||||
},{
|
|
||||||
url: img,
|
|
||||||
title: "Windswept Burden",
|
|
||||||
price: "$100.00",
|
|
||||||
},{
|
|
||||||
url: img,
|
|
||||||
title: "Windswept Burden",
|
|
||||||
price: "$100.00",
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits([
|
||||||
|
'addShopping','openDetail'
|
||||||
])
|
])
|
||||||
const type = ref('All')
|
const getMerchantData = reactive({
|
||||||
|
pageSize: 10,
|
||||||
|
pageNum: 1,
|
||||||
|
isShowMark:false,
|
||||||
|
isNoData:false,
|
||||||
|
})
|
||||||
|
const listingList = ref([
|
||||||
|
])
|
||||||
|
const type = ref('all')
|
||||||
const addShopping = (item) => {
|
const addShopping = (item) => {
|
||||||
emit('addShopping', item)
|
emit('addShopping', item)
|
||||||
}
|
}
|
||||||
|
const setType = (val) => {
|
||||||
|
type.value = val
|
||||||
|
getMerchantData.pageNum = 1
|
||||||
|
getMerchantData.isShowMark = false
|
||||||
|
getMerchantData.isNoData = false
|
||||||
|
}
|
||||||
|
const vObserve = {
|
||||||
|
mounted (el,binding) {
|
||||||
|
getMerchantData.isShowMark = false
|
||||||
|
getMerchantData.isNoData = false
|
||||||
|
new IntersectionObserver(
|
||||||
|
(entries, observer) => {
|
||||||
|
// 如果不是相交,则直接返回
|
||||||
|
// console.log(entries[0]);
|
||||||
|
if (!entries[0].intersectionRatio) return;
|
||||||
|
binding.value()
|
||||||
|
getMerchantData.pageNum += 1
|
||||||
|
},
|
||||||
|
// { root:worksPage }
|
||||||
|
).observe(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getListingList = () => {
|
||||||
|
getMerchantData.isShowMark = true
|
||||||
|
getMerchantData.isNoData = false
|
||||||
|
getlistingListApi({
|
||||||
|
sellerId: props.id,
|
||||||
|
designFor: type.value,
|
||||||
|
pageNum: getMerchantData.pageNum,
|
||||||
|
pageSize: getMerchantData.pageSize,
|
||||||
|
}).then((res)=>{
|
||||||
|
if(res.content.length == 0)getMerchantData.isNoData = true
|
||||||
|
listingList.value.push(...res.content)
|
||||||
|
getMerchantData.isShowMark = false
|
||||||
|
})
|
||||||
|
}
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
})
|
})
|
||||||
defineExpose({})
|
defineExpose({})
|
||||||
const {} = toRefs(data);
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="commodityList">
|
<div class="commodityList">
|
||||||
@@ -57,14 +73,18 @@ const {} = toRefs(data);
|
|||||||
Items
|
Items
|
||||||
</div>
|
</div>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div :class="{'active': type === 'All'}" @click="type = 'All'">All</div>
|
<div :class="{'active': type === 'all'}" @click="setType('all')">All</div>
|
||||||
<div :class="{'active': type === 'Male'}" @click="type = 'Male'">Male</div>
|
<div :class="{'active': type === 'male'}" @click="setType('male')">Male</div>
|
||||||
<div :class="{'active': type === 'Female'}" @click="type = 'Female'">Female</div>
|
<div :class="{'active': type === 'female'}" @click="setType('female')">Female</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<div class="item" v-for="item in list" :key="item.url">
|
<div class="item" v-for="item in listingList" :key="item.url">
|
||||||
<CommodityItem :url="item.url" :name="item.title" :price="item.price" @addShopping="addShopping(item)"></CommodityItem>
|
<CommodityItem :url="item.cover" :name="item.title" :price="item.price" @addShopping="addShopping(item)" @openDetail="$emit('openDetail', item)"></CommodityItem>
|
||||||
|
</div>
|
||||||
|
<div v-show="!getMerchantData.isNoData" class="material_content_list_loding">
|
||||||
|
<span class="page_loading" v-show="!getMerchantData.isShowMark" v-observe="getListingList"></span>
|
||||||
|
<img v-if="getMerchantData.isShowMark" src="@/assets/images/brand/brandLoading.gif" alt="">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -145,6 +165,25 @@ const {} = toRefs(data);
|
|||||||
margin-right: -1px;
|
margin-right: -1px;
|
||||||
margin-bottom: -1px;
|
margin-bottom: -1px;
|
||||||
}
|
}
|
||||||
|
> .material_content_list_loding{
|
||||||
|
width: 100%;
|
||||||
|
height: 5rem;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
justify-content: center;
|
||||||
|
> .page_loading{
|
||||||
|
width: 5rem;
|
||||||
|
height: 5rem;
|
||||||
|
}
|
||||||
|
> img{
|
||||||
|
width: 5rem;
|
||||||
|
height: 5rem;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -2,39 +2,66 @@
|
|||||||
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
||||||
import CommodityList from "./commodity-list.vue";
|
import CommodityList from "./commodity-list.vue";
|
||||||
import MerchantInfo from "./merchant-info.vue";
|
import MerchantInfo from "./merchant-info.vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter, useRoute } from "vue-router";
|
||||||
import myEvent from '@/utils/myEvent'
|
import myEvent from '@/utils/myEvent'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { getDesignerDetail } from '@/api/brand'
|
||||||
|
import { AddShoppingCart } from '@/api/shoppingCart'
|
||||||
|
|
||||||
//const props = defineProps({
|
//const props = defineProps({
|
||||||
//})
|
//})
|
||||||
//const emit = defineEmits([
|
//const emit = defineEmits([
|
||||||
//])
|
//])
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
let data = reactive({
|
const route = useRoute()
|
||||||
|
|
||||||
|
const designerDetail = ref({
|
||||||
|
avatar: '',
|
||||||
|
brandBanner: '',
|
||||||
|
description: '',
|
||||||
|
email: '',
|
||||||
|
mobile: '',
|
||||||
|
ownerName: '',
|
||||||
|
shopName: '',
|
||||||
|
socialLinks: '[]',
|
||||||
})
|
})
|
||||||
|
|
||||||
const addShopping = (item) => {
|
const addShopping = (item) => {
|
||||||
myEvent.emit('addShopping', item)
|
if(!item.price) return ElMessage.warning('Please log in first.')
|
||||||
|
AddShoppingCart({listingIds:[item.id]}).then((res)=>{
|
||||||
|
item.shopName = designerDetail.value.shopName
|
||||||
|
myEvent.emit('addShopping', item)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const openDetail = (item) => {
|
const openDetail = (item) => {
|
||||||
router.push({name: 'digitalDetail', params: {id: item.id}})
|
router.push({name: 'digitalItemDetail', params: {id: item.id}})
|
||||||
|
}
|
||||||
|
const getDetail = ()=>{
|
||||||
|
let data = {
|
||||||
|
sellerId: route.params.id,
|
||||||
|
}
|
||||||
|
getDesignerDetail(data,true).then((res)=>{
|
||||||
|
designerDetail.value = res
|
||||||
|
})
|
||||||
}
|
}
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
|
getDetail()
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
})
|
})
|
||||||
defineExpose({})
|
defineExpose({})
|
||||||
const {} = toRefs(data);
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="brand">
|
<div class="brand">
|
||||||
<div class="header-img">
|
<div class="header-img">
|
||||||
<img src="@/assets/images/brand/brandDetailBg.png" alt="">
|
<img :src="designerDetail.brandBanner || '@/assets/images/brand/brandDetailBg.png'" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="merchant-info">
|
<div class="merchant-info">
|
||||||
<MerchantInfo></MerchantInfo>
|
<MerchantInfo :designerDetail="designerDetail"></MerchantInfo>
|
||||||
</div>
|
</div>
|
||||||
<div class="commodity-list">
|
<div class="commodity-list">
|
||||||
<CommodityList @addShopping="addShopping" @openDetail="openDetail"></CommodityList>
|
<CommodityList :id="route.params.id" @addShopping="addShopping" @openDetail="openDetail"></CommodityList>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
@@ -55,7 +82,7 @@ const {} = toRefs(data);
|
|||||||
.content{
|
.content{
|
||||||
display: flex;
|
display: flex;
|
||||||
height: auto;
|
height: auto;
|
||||||
align-items: flex-start;
|
// align-items: flex-start;
|
||||||
.merchant-info{
|
.merchant-info{
|
||||||
width: 40rem;
|
width: 40rem;
|
||||||
padding-left: 12.7rem;
|
padding-left: 12.7rem;
|
||||||
|
|||||||
@@ -1,7 +1,22 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
||||||
//const props = defineProps({
|
const props = defineProps({
|
||||||
//})
|
designerDetail: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
avatar: '',
|
||||||
|
brandBanner: '',
|
||||||
|
description: '',
|
||||||
|
email: '',
|
||||||
|
mobile: '',
|
||||||
|
ownerName: '',
|
||||||
|
shopName: '',
|
||||||
|
socialLinks: '[]',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
//const emit = defineEmits([
|
//const emit = defineEmits([
|
||||||
//])
|
//])
|
||||||
let data = reactive({
|
let data = reactive({
|
||||||
@@ -16,12 +31,12 @@ const {} = toRefs(data);
|
|||||||
<template>
|
<template>
|
||||||
<div class="merchantInfo">
|
<div class="merchantInfo">
|
||||||
<div class="profile">
|
<div class="profile">
|
||||||
<img src="@/assets/images/collectionStory/Rectangle.png" alt="">
|
<img :src="designerDetail.avatar || '@/assets/images/collectionStory/Rectangle.png'" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<div class="name">Lian Su</div>
|
<div class="name">{{ designerDetail.ownerName }}</div>
|
||||||
<div class="title">Roaming Clouds</div>
|
<div class="title">{{ designerDetail.shopName }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="contact">
|
<div class="contact">
|
||||||
<div class="title">Contact</div>
|
<div class="title">Contact</div>
|
||||||
@@ -29,30 +44,26 @@ const {} = toRefs(data);
|
|||||||
<div class="icon">
|
<div class="icon">
|
||||||
<svg-icon name="brand-email" size="24" />
|
<svg-icon name="brand-email" size="24" />
|
||||||
</div>
|
</div>
|
||||||
<div>lian.su@urieworweoo.com</div>
|
<div>{{ designerDetail.email }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="phone label">
|
<div class="phone label">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<svg-icon name="brand-call" size="24" />
|
<svg-icon name="brand-call" size="24" />
|
||||||
</div>
|
</div>
|
||||||
<div>+86 139 4829 7710</div>
|
<div>{{ designerDetail.mobile }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="address label">
|
<div class="address label" v-for="value in JSON.parse(designerDetail.socialLinks)">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<svg-icon name="brand-link" size="24" />
|
<svg-icon name="brand-link" size="24" />
|
||||||
</div>
|
</div>
|
||||||
<div>746312432</div>
|
<div>{{value}}</div>
|
||||||
</div>
|
|
||||||
<div class="website label">
|
|
||||||
<div class="icon">
|
|
||||||
<svg-icon name="brand-link" size="24" />
|
|
||||||
</div>
|
|
||||||
<div>https://urieworweoo.com</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="about">
|
<div class="about">
|
||||||
<div class="title">About</div>
|
<div class="title">About</div>
|
||||||
<div class="content">Lian Su’s work weaves understated ethnic influences into contemporary minimalism. She explores materials and silhouettes that bridge heritage and modern sensibilities. Her designs reflect a quiet dialogue between cultural memory and forward-looking innovation.</div>
|
<div class="content">
|
||||||
|
{{ designerDetail.description }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ const {} = toRefs(data);
|
|||||||
display: flex;
|
display: flex;
|
||||||
height: calc(100vh - var(--header-height) - var(--footer-height));
|
height: calc(100vh - var(--header-height) - var(--footer-height));
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
overflow: hidden;
|
||||||
> div{
|
> div{
|
||||||
// height: 100%;
|
// height: 100%;
|
||||||
}
|
}
|
||||||
@@ -119,8 +120,8 @@ const {} = toRefs(data);
|
|||||||
border-right: 0.5px solid #585858;
|
border-right: 0.5px solid #585858;
|
||||||
// overflow-y: auto;
|
// overflow-y: auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
// height: 100%;
|
height: 100%;
|
||||||
height: auto;
|
// height: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
.line{
|
.line{
|
||||||
border: 0.5px solid #58585899;
|
border: 0.5px solid #58585899;
|
||||||
@@ -141,6 +142,7 @@ const {} = toRefs(data);
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4rem;
|
gap: 4rem;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
height: 100%;
|
||||||
&::-webkit-scrollbar{
|
&::-webkit-scrollbar{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,24 +3,41 @@ import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
|||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import img from "@/assets/images/collectionStory/Rectangle.png";
|
import img from "@/assets/images/collectionStory/Rectangle.png";
|
||||||
import myEvent from '@/utils/myEvent'
|
import myEvent from '@/utils/myEvent'
|
||||||
|
import { getListingDetailApi } from '@/api/listing'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
//const props = defineProps({
|
//const props = defineProps({
|
||||||
//})
|
//})
|
||||||
//const emit = defineEmits([
|
//const emit = defineEmits([
|
||||||
//])
|
//])
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
let data = reactive({
|
let detail:any = ref({
|
||||||
|
description: '',
|
||||||
|
title: '',
|
||||||
|
price: '',
|
||||||
|
shopName: '',
|
||||||
|
updateTime: '',
|
||||||
|
gender: '',
|
||||||
})
|
})
|
||||||
const addShopping = (item) => {
|
const addShopping = (item) => {
|
||||||
myEvent.emit('addShopping', item)
|
myEvent.emit('addShopping', item)
|
||||||
}
|
}
|
||||||
|
const getListingDetail = ()=>{
|
||||||
|
getListingDetailApi({
|
||||||
|
id:route.params.id + '',
|
||||||
|
}).then((res)=>{
|
||||||
|
console.log(res)
|
||||||
|
if(res)detail.value = res
|
||||||
|
})
|
||||||
|
}
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
|
getListingDetail()
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
})
|
})
|
||||||
defineExpose({})
|
defineExpose({})
|
||||||
const {} = toRefs(data);
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="digitalItemDetail">
|
<div class="digitalItemDetail">
|
||||||
@@ -52,22 +69,22 @@ const {} = toRefs(data);
|
|||||||
<span>Back</span>
|
<span>Back</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="img-info">
|
<div class="img-info">
|
||||||
<div class="img-type">FEMALE / skirt, blouse, Outwear</div>
|
<div class="img-type">{{ detail.gender.toUpperCase() }} / skirt, blouse, Outwear</div>
|
||||||
<div class="img-name">Heritage Layered Set</div>
|
<div class="img-name">{{ detail.title }}</div>
|
||||||
<div class="img-price">$100 <span class="mini-scrollbar">HKD</span></div>
|
<div class="img-price" v-if="detail.price">¥{{ detail.price }} <span class="mini-scrollbar">HKD</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="commodity">
|
<div class="commodity">
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<img class="profile" :src="img" alt="">
|
<img class="profile" :src="img" alt="">
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<div class="name">Roaming Clouds</div>
|
<div class="name">{{ detail.shopName }}</div>
|
||||||
<div class="release-time">
|
<div class="release-time">
|
||||||
<span>Release in Feb 26, 2026</span>
|
<span>Release in {{ detail.updateTime }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="introduce">
|
<div class="introduce">
|
||||||
This ensemble artfully merges traditional folk heritage with contemporary tailoring, creating a timeless silhouette that honors ancestral craftsmanship while embracing modern sophistication.
|
{{ detail.description }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="notice">
|
<div class="notice">
|
||||||
|
|||||||
@@ -3,10 +3,16 @@ import { ref, onMounted, onUnmounted, reactive, toRefs, onActivated } from "vue"
|
|||||||
import CommodityList from "./commodity-list.vue";
|
import CommodityList from "./commodity-list.vue";
|
||||||
import MerchantInfo from "./merchant-info.vue";
|
import MerchantInfo from "./merchant-info.vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
import scListNull from '@/views/shoppingCart/sc-list-null.vue'
|
||||||
|
import { getListingMallListApi } from '@/api/listing'
|
||||||
|
|
||||||
// 定义组件名称
|
// 定义组件名称
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'digitalItem'
|
name: 'digitalItem'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const categories = ref([''])
|
||||||
|
const gender = ref([''])
|
||||||
//const props = defineProps({
|
//const props = defineProps({
|
||||||
//})
|
//})
|
||||||
//const emit = defineEmits([
|
//const emit = defineEmits([
|
||||||
@@ -14,10 +20,8 @@ defineOptions({
|
|||||||
const digitalItemRef = ref(null)
|
const digitalItemRef = ref(null)
|
||||||
const scrollTop = ref(0)
|
const scrollTop = ref(0)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
let data = reactive({
|
|
||||||
})
|
|
||||||
|
|
||||||
const categoriesList = ref([
|
const searechTypeList = ref([
|
||||||
{
|
{
|
||||||
value:'Best Selling',
|
value:'Best Selling',
|
||||||
label:'Best Selling'
|
label:'Best Selling'
|
||||||
@@ -29,7 +33,7 @@ const categoriesList = ref([
|
|||||||
label:'Newest First'
|
label:'Newest First'
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
const categories = ref('Newest First')
|
const searechType = ref('Newest First')
|
||||||
const addShopping = (item) => {}
|
const addShopping = (item) => {}
|
||||||
const openDetail = (item) => {
|
const openDetail = (item) => {
|
||||||
scrollTop.value = digitalItemRef.value.scrollTop
|
scrollTop.value = digitalItemRef.value.scrollTop
|
||||||
@@ -37,6 +41,17 @@ const openDetail = (item) => {
|
|||||||
path: '/digitalItem/' + 123,
|
path: '/digitalItem/' + 123,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const handleChange = (val) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
const getListingMallList = ()=>{
|
||||||
|
let data = {
|
||||||
|
// designFor
|
||||||
|
}
|
||||||
|
// getListingMallListApi().then(res => {
|
||||||
|
|
||||||
|
// })
|
||||||
|
}
|
||||||
onActivated(()=>{
|
onActivated(()=>{
|
||||||
digitalItemRef.value.scrollTop = scrollTop.value
|
digitalItemRef.value.scrollTop = scrollTop.value
|
||||||
})
|
})
|
||||||
@@ -45,7 +60,6 @@ onMounted(()=>{
|
|||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
})
|
})
|
||||||
defineExpose({})
|
defineExpose({})
|
||||||
const {} = toRefs(data);
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="digitalItem" ref="digitalItemRef">
|
<div class="digitalItem" ref="digitalItemRef">
|
||||||
@@ -74,10 +88,18 @@ const {} = toRefs(data);
|
|||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="merchant-info">
|
<div class="merchant-info">
|
||||||
<MerchantInfo></MerchantInfo>
|
<MerchantInfo @change="handleChange"></MerchantInfo>
|
||||||
</div>
|
</div>
|
||||||
<div class="commodity-list">
|
<div class="commodity-list">
|
||||||
<CommodityList @addShopping="addShopping" @openDetail="openDetail"></CommodityList>
|
<CommodityList v-if="true" @addShopping="addShopping" @openDetail="openDetail"></CommodityList>
|
||||||
|
<div v-else class="null">
|
||||||
|
<sc-list-null
|
||||||
|
nullImage="shopping-cart"
|
||||||
|
:showButton="false"
|
||||||
|
title="Nothing in Digital Item"
|
||||||
|
tip="Try adjusting your filters or refreshing the page."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
@@ -178,7 +200,7 @@ const {} = toRefs(data);
|
|||||||
> .content{
|
> .content{
|
||||||
display: flex;
|
display: flex;
|
||||||
height: auto;
|
height: auto;
|
||||||
align-items: flex-start;
|
// align-items: flex-start;
|
||||||
border-top: 0.5px solid #585858;
|
border-top: 0.5px solid #585858;
|
||||||
.merchant-info{
|
.merchant-info{
|
||||||
width: 38.5rem;
|
width: 38.5rem;
|
||||||
@@ -197,6 +219,10 @@ const {} = toRefs(data);
|
|||||||
border-left: 0.5px solid #585858;
|
border-left: 0.5px solid #585858;
|
||||||
border-right: 0.5px solid #585858;
|
border-right: 0.5px solid #585858;
|
||||||
margin-right: 9rem;
|
margin-right: 9rem;
|
||||||
|
display: flex;
|
||||||
|
.null{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,20 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
import { ref, onMounted, onUnmounted, computed, toRefs } from "vue";
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useClothesCategories } from '@/utils/ClothesCategory'
|
||||||
//const props = defineProps({
|
//const props = defineProps({
|
||||||
//})
|
//})
|
||||||
//const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
//])
|
'change'
|
||||||
let data = reactive({
|
])
|
||||||
})
|
|
||||||
const categoriesList = ref([
|
const { t } = useI18n()
|
||||||
{
|
|
||||||
label: 'Outwear',
|
const categoriesList = useClothesCategories();
|
||||||
value: 'Outwear'
|
|
||||||
},
|
const genderList = computed(() => [
|
||||||
{
|
{ label: t('Wardrobe.assets.genders.male'), value: 'male' },
|
||||||
label: 'Dress',
|
{ label: t('Wardrobe.assets.genders.female'), value: 'female' }
|
||||||
value: 'Dress'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Trousers',
|
|
||||||
value: 'Trousers'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Blouse',
|
|
||||||
value: 'Blouse'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Skirt',
|
|
||||||
value: 'Skirt'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Accessories',
|
|
||||||
value: 'Accessories'
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const genderList = ref([
|
|
||||||
{
|
|
||||||
label: 'Male',
|
|
||||||
value: 'Male'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Female',
|
|
||||||
value: 'Female'
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
const categories = ref([''])
|
const categories = ref([''])
|
||||||
const gender = ref([''])
|
const gender = ref([''])
|
||||||
@@ -48,13 +22,16 @@ const gender = ref([''])
|
|||||||
const clearFilters = () => {
|
const clearFilters = () => {
|
||||||
categories.value = ['']
|
categories.value = ['']
|
||||||
gender.value = ['']
|
gender.value = ['']
|
||||||
|
handleChange()
|
||||||
|
}
|
||||||
|
const handleChange = () => {
|
||||||
|
emit('change', {categories:categories.value, gender:gender.value})
|
||||||
}
|
}
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
})
|
})
|
||||||
defineExpose({})
|
defineExpose({})
|
||||||
const {} = toRefs(data);
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
@@ -65,12 +42,12 @@ const {} = toRefs(data);
|
|||||||
<div class="categories">Categories</div>
|
<div class="categories">Categories</div>
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
<div class="multiple">
|
<div class="multiple">
|
||||||
<checked :list="categoriesList" v-model:selected="categories" />
|
<checked :list="categoriesList" @change="handleChange" v-model:selected="categories" />
|
||||||
</div>
|
</div>
|
||||||
<div class="categories">Gender</div>
|
<div class="categories">Gender</div>
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
<div class="multiple">
|
<div class="multiple">
|
||||||
<checked :list="genderList" v-model:selected="gender" />
|
<checked :list="genderList" @change="handleChange" v-model:selected="gender" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
email: { type: String, required: true },
|
email: { type: String, required: true },
|
||||||
type: {
|
type: {
|
||||||
type: String as () => 'LOGIN' | 'REGISTER' | 'FORGOT_PWD',
|
type: String as () => 'LOGIN' | 'REGISTER' | 'FORGET_PWD',
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
password: { type: String, default: '' },
|
password: { type: String, default: '' },
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
:name="data.name"
|
:name="data.name"
|
||||||
:email="data.email"
|
:email="data.email"
|
||||||
:password="data.password"
|
:password="data.password"
|
||||||
type="FORGOT_PWD"
|
type="FORGET_PWD"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -55,6 +55,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
AccountSendLoginCode,
|
||||||
|
AccountLogin,
|
||||||
|
AccountRegister,
|
||||||
|
AccountSendVerifyCode
|
||||||
|
} from '@/api/account'
|
||||||
import { computed, ref, markRaw, watch, onBeforeUnmount } from 'vue'
|
import { computed, ref, markRaw, watch, onBeforeUnmount } from 'vue'
|
||||||
import md5 from 'md5'
|
import md5 from 'md5'
|
||||||
import login from './login.vue'
|
import login from './login.vue'
|
||||||
@@ -63,6 +69,8 @@
|
|||||||
import registerSuccess from './register-success.vue'
|
import registerSuccess from './register-success.vue'
|
||||||
import retrievePassword from './retrieve-password.vue'
|
import retrievePassword from './retrieve-password.vue'
|
||||||
import myEvent from '@/utils/myEvent'
|
import myEvent from '@/utils/myEvent'
|
||||||
|
import { useUserInfoStore } from '@/stores/userInfo'
|
||||||
|
const userStore = useUserInfoStore()
|
||||||
const data = ref({
|
const data = ref({
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
@@ -121,22 +129,42 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
const onLogin = (res: any) => {
|
const onLogin = (res: any) => {
|
||||||
data.value = res
|
AccountSendLoginCode({
|
||||||
data.value.type = TabNames.login
|
email: res.email,
|
||||||
currentTab.value = TabNames.email_verify
|
password: md5(res.password)
|
||||||
|
}).then((v) => {
|
||||||
|
data.value = res
|
||||||
|
data.value.type = TabNames.login
|
||||||
|
currentTab.value = TabNames.email_verify
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const onRegister = (res: any) => {
|
const onRegister = (res: any) => {
|
||||||
data.value = res
|
const value = {
|
||||||
data.value.type = TabNames.register
|
email: res.email,
|
||||||
currentTab.value = TabNames.email_verify
|
operationType: 'REGISTER'
|
||||||
|
}
|
||||||
|
AccountSendVerifyCode(value).then((v) => {
|
||||||
|
data.value = res
|
||||||
|
data.value.type = TabNames.register
|
||||||
|
currentTab.value = TabNames.email_verify
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const onSubmitEmailCode = (code: string) => {
|
const onSubmitEmailCode = (code: string) => {
|
||||||
|
const value = {
|
||||||
|
email: data.value.email,
|
||||||
|
password: md5(data.value.password),
|
||||||
|
emailVerifyCode: code
|
||||||
|
}
|
||||||
if (data.value.type === TabNames.login) {
|
if (data.value.type === TabNames.login) {
|
||||||
console.log('登录', code)
|
AccountLogin(value).then((v) => {
|
||||||
show.value = false
|
userStore.setUserInfo(v)
|
||||||
|
show.value = false
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
console.log('注册', code)
|
value['username'] = data.value.name
|
||||||
currentTab.value = TabNames.register_success
|
AccountRegister(value).then((v) => {
|
||||||
|
currentTab.value = TabNames.register_success
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { AccountSendVerifyCode, AccountVerifyCode, AccountResetPassword } from '@/api/account'
|
||||||
import md5 from 'md5'
|
import md5 from 'md5'
|
||||||
import { computed, reactive, ref } from 'vue'
|
import { computed, reactive, ref } from 'vue'
|
||||||
import { validateEmail, validatePass } from './tools'
|
import { validateEmail, validatePass } from './tools'
|
||||||
@@ -103,22 +104,12 @@
|
|||||||
const onSubmit1 = () => {
|
const onSubmit1 = () => {
|
||||||
form1Ref.value?.validate?.((valid) => {
|
form1Ref.value?.validate?.((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
index.value = 1
|
AccountSendVerifyCode({
|
||||||
} else {
|
|
||||||
console.warn('error submit!')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const onSubmit2 = () => {
|
|
||||||
form2Ref.value?.validate?.((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
const data = {
|
|
||||||
email: formData.email,
|
email: formData.email,
|
||||||
code: formData.code,
|
operationType: 'FORGOT_PWD'
|
||||||
password: md5(formData.password)
|
}).then(() => {
|
||||||
}
|
index.value = 1
|
||||||
console.log(data)
|
})
|
||||||
emit('back')
|
|
||||||
} else {
|
} else {
|
||||||
console.warn('error submit!')
|
console.warn('error submit!')
|
||||||
}
|
}
|
||||||
@@ -126,8 +117,30 @@
|
|||||||
}
|
}
|
||||||
const onVerifyCode = (code: string) => {
|
const onVerifyCode = (code: string) => {
|
||||||
if (!code) return
|
if (!code) return
|
||||||
formData.code = code
|
AccountVerifyCode({
|
||||||
index.value = 2
|
email: formData.email,
|
||||||
|
emailVerifyCode: code,
|
||||||
|
operationType: 'FORGOT_PWD'
|
||||||
|
}).then(() => {
|
||||||
|
formData.code = code
|
||||||
|
index.value = 2
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onSubmit2 = () => {
|
||||||
|
form2Ref.value?.validate?.((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
const data = {
|
||||||
|
email: formData.email,
|
||||||
|
password: md5(formData.password),
|
||||||
|
emailVerifyCode: formData.code
|
||||||
|
}
|
||||||
|
AccountResetPassword(data).then(() => {
|
||||||
|
emit('back')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.warn('error submit!')
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,9 @@
|
|||||||
v-for="v in navList1"
|
v-for="v in navList1"
|
||||||
:key="v.path"
|
:key="v.path"
|
||||||
class="nav-item"
|
class="nav-item"
|
||||||
:class="{ active: activePath === v.path }"
|
:class="{
|
||||||
|
active: v.path === '/' ? activePath === v.path : new RegExp(`^${v.path}`).test(activePath)
|
||||||
|
}"
|
||||||
@click="onNavItemClick(v.path)"
|
@click="onNavItemClick(v.path)"
|
||||||
>
|
>
|
||||||
<span>{{ v.name }}</span>
|
<span>{{ v.name }}</span>
|
||||||
@@ -19,27 +21,29 @@
|
|||||||
class="icon"
|
class="icon"
|
||||||
v-for="v in navList2"
|
v-for="v in navList2"
|
||||||
:key="v.path"
|
:key="v.path"
|
||||||
:class="{ active: activePath === v.path }"
|
:class="{ active: new RegExp(`^${v.path}`).test(activePath) }"
|
||||||
@click="onNavItemClick(v.path)"
|
@click="onNavItemClick(v.path)"
|
||||||
>
|
>
|
||||||
<svg-icon :name="activePath === v.path ? v.active_icon : v.icon" size="22" />
|
<svg-icon :name="activePath === v.path ? v.active_icon : v.icon" size="22" />
|
||||||
</div>
|
</div>
|
||||||
<div class="login" @click="onLogin">Login</div>
|
|
||||||
<el-popover
|
<el-popover
|
||||||
ref="profilePopover"
|
ref="profilePopover"
|
||||||
placement="bottom-end"
|
placement="bottom-end"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
:show-arrow="false"
|
:show-arrow="false"
|
||||||
popper-style="width: 24rem; padding: 0; border-radius: 0; right: 2rem; top: 10rem;"
|
popper-style="width: 24rem; padding: 0; border-radius: 0; right: 2rem; top: 10rem;"
|
||||||
|
v-if="userInfo.userId"
|
||||||
>
|
>
|
||||||
<template #reference><div class="profile"></div></template>
|
<template #reference>
|
||||||
|
<div class="icon"><svg-icon name="user_0" size="22" /></div>
|
||||||
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="profile-content">
|
<div class="profile-content">
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<img src="@/assets/images/profile-content-bg.jpg" alt="" />
|
<img src="@/assets/images/profile-content-bg.jpg" alt="" />
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="profile"></div>
|
<div class="profile"></div>
|
||||||
<div class="name">Hi, Alexandra_chen</div>
|
<div class="name">Hi, {{ userInfo.username }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-item" @click="onMyWardrobe">
|
<div class="nav-item" @click="onMyWardrobe">
|
||||||
@@ -62,6 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
|
<div class="login" @click="onLogin" v-else>Login</div>
|
||||||
<div class="language" @click="onLanguageClick">
|
<div class="language" @click="onLanguageClick">
|
||||||
<span :class="{ active: locale === 'CHINESE_SIMPLIFIED' }">中</span> /
|
<span :class="{ active: locale === 'CHINESE_SIMPLIFIED' }">中</span> /
|
||||||
<span :class="{ active: locale === 'ENGLISH' }">ENG</span>
|
<span :class="{ active: locale === 'ENGLISH' }">ENG</span>
|
||||||
@@ -71,13 +76,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import myEvent from '@/utils/myEvent'
|
import myEvent from '@/utils/myEvent'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useUserInfoStore } from '@/stores/userInfo'
|
||||||
const { t, locale } = useI18n()
|
const { t, locale } = useI18n()
|
||||||
|
const userInfoStore = useUserInfoStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const userInfo = computed(() => userInfoStore.state.userInfo)
|
||||||
const activePath = computed(() => route.path)
|
const activePath = computed(() => route.path)
|
||||||
const navList1 = ref([
|
const navList1 = ref([
|
||||||
{
|
{
|
||||||
@@ -102,11 +111,6 @@
|
|||||||
icon: 'cart_0',
|
icon: 'cart_0',
|
||||||
active_icon: 'cart_1',
|
active_icon: 'cart_1',
|
||||||
path: '/shoppingCart'
|
path: '/shoppingCart'
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'user_0',
|
|
||||||
active_icon: 'user_1',
|
|
||||||
path: '/account'
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
const onNavItemClick = (path: string) => {
|
const onNavItemClick = (path: string) => {
|
||||||
@@ -135,7 +139,12 @@
|
|||||||
}
|
}
|
||||||
const onLogout = () => {
|
const onLogout = () => {
|
||||||
hideProfilePopover()
|
hideProfilePopover()
|
||||||
console.log('logout')
|
ElMessageBox.confirm('Are you sure to log off?')
|
||||||
|
.then(() => {
|
||||||
|
userInfoStore.logout()
|
||||||
|
router.go(0)
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
}
|
}
|
||||||
const onLanguageClick = () => {
|
const onLanguageClick = () => {
|
||||||
locale.value = locale.value === 'ENGLISH' ? 'CHINESE_SIMPLIFIED' : 'ENGLISH'
|
locale.value = locale.value === 'ENGLISH' ? 'CHINESE_SIMPLIFIED' : 'ENGLISH'
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
||||||
import myEvent from '@/utils/myEvent'
|
import myEvent from '@/utils/myEvent'
|
||||||
import scList from '@/views/shoppingCart/sc-list.vue'
|
// import scList from '@/views/shoppingCart/sc-list.vue'
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import img from '@/assets/images/brand-null.png'
|
||||||
|
|
||||||
//const props = defineProps({
|
//const props = defineProps({
|
||||||
//})
|
//})
|
||||||
@@ -9,15 +11,28 @@ import scList from '@/views/shoppingCart/sc-list.vue'
|
|||||||
//])
|
//])
|
||||||
let data = reactive({
|
let data = reactive({
|
||||||
})
|
})
|
||||||
|
const cover = ref('')
|
||||||
|
const price = ref('')
|
||||||
|
const shopName = ref('')
|
||||||
|
const commodityName = ref('')
|
||||||
|
const router = useRouter()
|
||||||
const isShoppingShow = ref(false)
|
const isShoppingShow = ref(false)
|
||||||
const shoppingClose = () => {
|
const shoppingClose = () => {
|
||||||
isShoppingShow.value = false
|
isShoppingShow.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const goShopping = () => {
|
||||||
|
router.push({path: '/shoppingCart'})
|
||||||
|
isShoppingShow.value = false
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
myEvent.add('addShopping', (item) => {
|
myEvent.add('addShopping', (item) => {
|
||||||
isShoppingShow.value = true
|
isShoppingShow.value = true
|
||||||
console.log(item)
|
cover.value = item.cover || ''
|
||||||
|
price.value = item.price || ''
|
||||||
|
shopName.value = item.shopName || ''
|
||||||
|
commodityName.value = item.title || ''
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
@@ -27,14 +42,182 @@ defineExpose({})
|
|||||||
const {} = toRefs(data);
|
const {} = toRefs(data);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<el-drawer v-model="isShoppingShow" width="50rem" :close-on-click-modal="false" title="I am the title" :with-header="false">
|
<el-drawer v-model="isShoppingShow" width="50rem" class="addShoppingDrawer" :close-on-click-modal="false" title="I am the title" :with-header="false">
|
||||||
<sc-list is-mini style="flex: 0.6;" @close="shoppingClose"/>
|
<div class="addShoppingInfo">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">Added to your Shopping Cart</div>
|
||||||
|
<span class="close" @click="shoppingClose"
|
||||||
|
><svg-icon name="close" size="13"
|
||||||
|
/></span>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="img-list">
|
||||||
|
<div class="img-box">
|
||||||
|
<img :src="img" alt="">
|
||||||
|
</div>
|
||||||
|
<div class="img-box">
|
||||||
|
<img :src="img" alt="">
|
||||||
|
</div>
|
||||||
|
<div class="img-box">
|
||||||
|
<img :src="cover" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="inf-box">
|
||||||
|
<div class="name">{{ commodityName }}</div>
|
||||||
|
<div class="shopping-name">
|
||||||
|
<div class="icon">
|
||||||
|
<SvgIcon name="shop" size="24" />
|
||||||
|
</div>
|
||||||
|
{{ shopName }}
|
||||||
|
</div>
|
||||||
|
<div class="price">${{ price }} <span class="currency">HKD</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="statement">
|
||||||
|
<div class="icon">
|
||||||
|
<SvgIcon name="statement" size="16.6" />
|
||||||
|
</div>
|
||||||
|
Digital Assets Only. No physical product included.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button" @click="goShopping">
|
||||||
|
SeE Shopping Cart
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <sc-list is-mini style="flex: 0.6;" @close="shoppingClose"/> -->
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</template>
|
</template>
|
||||||
|
<style lang="less">
|
||||||
|
.el-drawer.addShoppingDrawer{
|
||||||
|
--el-drawer-padding-primary: 2.4rem 3.4rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.homeNavBox{
|
|
||||||
|
.addShoppingInfo{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
> .header{
|
||||||
|
border-bottom: 0.1rem solid #c4c4c4;
|
||||||
|
display: flex;
|
||||||
|
padding-bottom: 2.4rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
> .title{
|
||||||
|
font-family: KaiseiOpti-Bold;
|
||||||
|
font-size: 2rem;
|
||||||
|
line-height: 120%;
|
||||||
|
color: #121212;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
> .close{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .content{
|
||||||
|
flex: 1;
|
||||||
|
padding-top: 9.6rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
> .img-list{
|
||||||
|
height: 37.5rem;
|
||||||
|
width: 33.7rem;
|
||||||
|
position: relative;
|
||||||
|
> .img-box{
|
||||||
|
position: absolute;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 26.9rem;
|
||||||
|
height: 34.1rem;
|
||||||
|
border: 1px solid #EFEFEF;
|
||||||
|
top: 1.7rem;
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
transform-origin: bottom;
|
||||||
|
box-shadow: 1rem .8rem 2.4rem 0px #4D4D4D0A;
|
||||||
|
> img{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
&:nth-child(1){
|
||||||
|
transform: rotate(-8deg);
|
||||||
|
background-color: #eaeaea;
|
||||||
|
right: 2rem;
|
||||||
|
}
|
||||||
|
&:nth-child(2){
|
||||||
|
transform: rotate(-4deg);
|
||||||
|
background-color: #eeeeee;
|
||||||
|
right: 1rem;
|
||||||
|
}
|
||||||
|
&:nth-child(3){
|
||||||
|
transform: rotate(0);
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .inf-box{
|
||||||
|
margin-top: 5.18rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
> .name{
|
||||||
|
font-family: KaiseiOpti-Bold;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 2.4rem;
|
||||||
|
line-height: 140%;
|
||||||
|
}
|
||||||
|
> .shopping-name{
|
||||||
|
margin-top: 1.3rem;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
line-height: 140%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
> .icon{
|
||||||
|
margin-right: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .price{
|
||||||
|
margin-top: 1.2rem;
|
||||||
|
font-family: KaiseiOpti-Bold;
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: Bold;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
line-height: 140%;
|
||||||
|
> .currency{
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 140%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .statement{
|
||||||
|
margin-top: 5rem;
|
||||||
|
font-family: KaiseiOpti-Regular;
|
||||||
|
color: #979797;
|
||||||
|
display: flex;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 140%;
|
||||||
|
> .icon{
|
||||||
|
margin-right: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .button{
|
||||||
|
font-family: KaiseiOpti-Regular;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 4.6rem;
|
||||||
|
letter-spacing: 3%;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #232323;
|
||||||
|
margin-bottom: calc(6rem - 2.4rem);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
5
src/views/shoppingCart/index.d.js
Normal file
5
src/views/shoppingCart/index.d.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/** 商品状态 */
|
||||||
|
export const SCART_STATUS = {
|
||||||
|
/** 正常 */
|
||||||
|
NORMAL: 1,
|
||||||
|
}
|
||||||
@@ -34,6 +34,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { FormatBytes, FormatDate } from '@/utils/tools'
|
import { FormatBytes, FormatDate } from '@/utils/tools'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { CreateOrder } from '@/api/shoppingCart'
|
||||||
|
const router = useRouter()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
list: {
|
list: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@@ -57,7 +60,12 @@
|
|||||||
})
|
})
|
||||||
const totalAmount = computed(() => props.list.reduce((pre, cur) => pre + cur.amount, 0).toFixed(2))
|
const totalAmount = computed(() => props.list.reduce((pre, cur) => pre + cur.amount, 0).toFixed(2))
|
||||||
const handleCheckout = () => {
|
const handleCheckout = () => {
|
||||||
console.log('购买:', props.list)
|
const ids = props.list.map((v: any) => v.listingId)
|
||||||
|
if (ids.length === 0) return
|
||||||
|
console.log('购买:', ids)
|
||||||
|
CreateOrder(ids, true).then((res) => {
|
||||||
|
router.go(0)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="sc-item" :class="{ 'is-order-actions-layout': orderActionsLayout }">
|
<div
|
||||||
|
class="sc-item"
|
||||||
|
:class="{
|
||||||
|
'is-order-actions-layout': orderActionsLayout,
|
||||||
|
disabled
|
||||||
|
}"
|
||||||
|
>
|
||||||
<slot name="checkbox" />
|
<slot name="checkbox" />
|
||||||
<img :src="info.url" />
|
<img :src="info.cover" />
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="title">{{ info.title }}</div>
|
<div class="title">{{ info.title }}</div>
|
||||||
<div class="brand">
|
<div class="brand">
|
||||||
@@ -12,14 +18,20 @@
|
|||||||
<span v-for="tag in info.tags" :key="tag" class="tag">{{ tag }}</span>
|
<span v-for="tag in info.tags" :key="tag" class="tag">{{ tag }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="date" v-if="showDate">
|
<div class="date" v-if="showDate">
|
||||||
<!-- <div class="icon"><svg-icon name="order-file" size="18" /></div> -->
|
|
||||||
<div class="text">
|
<div class="text">
|
||||||
{{ FormatDate(info.date, 'SM D, YYYY, h:mm A') }}
|
{{ FormatDate(info.date, 'SM D, YYYY, h:mm A') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="amount">${{ info.amount }}<span> HKD</span></div>
|
<div class="unshelve" v-show="disabled">
|
||||||
|
<div class="title">
|
||||||
|
<span><svg-icon name="order-warning" size="20" /></span>
|
||||||
|
No Longer Available
|
||||||
|
</div>
|
||||||
|
<div class="tip">Delisted from marketplace</div>
|
||||||
|
</div>
|
||||||
|
<div class="amount" v-show="!disabled">${{ info.amount }}<span> HKD</span></div>
|
||||||
<SvgIcon
|
<SvgIcon
|
||||||
v-if="orderActionsLayout"
|
v-if="orderActionsLayout"
|
||||||
class="download"
|
class="download"
|
||||||
@@ -44,10 +56,22 @@
|
|||||||
showDate: { type: Boolean, default: true },
|
showDate: { type: Boolean, default: true },
|
||||||
showRemove: { type: Boolean, default: true },
|
showRemove: { type: Boolean, default: true },
|
||||||
orderActionsLayout: { type: Boolean, default: false },
|
orderActionsLayout: { type: Boolean, default: false },
|
||||||
info: { type: Object, default: () => {} }
|
info: {
|
||||||
|
type: Object as () => {
|
||||||
|
status: number
|
||||||
|
title: string
|
||||||
|
brand: string
|
||||||
|
tags: string[]
|
||||||
|
date: string
|
||||||
|
amount: number
|
||||||
|
cover: string
|
||||||
|
},
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
disabled: { type: Boolean, default: false }
|
||||||
})
|
})
|
||||||
const onRemove = () => {
|
const onRemove = () => {
|
||||||
emit('remove', props.info.id)
|
emit('remove', props.info)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -76,7 +100,7 @@
|
|||||||
> .title {
|
> .title {
|
||||||
font-family: KaiseiOpti-Bold;
|
font-family: KaiseiOpti-Bold;
|
||||||
font-size: var(--sc-item-title-font-size, 2.4rem);
|
font-size: var(--sc-item-title-font-size, 2.4rem);
|
||||||
color: #232323;
|
color: var(--sc-item-title-color, #232323);
|
||||||
}
|
}
|
||||||
> .brand {
|
> .brand {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -85,11 +109,12 @@
|
|||||||
width: 2.4rem;
|
width: 2.4rem;
|
||||||
height: 2.4rem;
|
height: 2.4rem;
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
|
color: var(--sc-item-brand-color, #232323);
|
||||||
}
|
}
|
||||||
> .text {
|
> .text {
|
||||||
font-size: var(--sc-item-brand-font-size, 1.6rem);
|
font-size: var(--sc-item-brand-font-size, 1.6rem);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: #232323;
|
color: var(--sc-item-brand-color, #232323);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
> .tags {
|
> .tags {
|
||||||
@@ -104,24 +129,17 @@
|
|||||||
font-size: var(--sc-item-tag-font-size, 1.4rem);
|
font-size: var(--sc-item-tag-font-size, 1.4rem);
|
||||||
padding: var(--sc-item-tag-padding, 0 1rem);
|
padding: var(--sc-item-tag-padding, 0 1rem);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #8f8f8f;
|
color: var(--sc-item-tag-color, #8f8f8f);
|
||||||
background-color: #eee;
|
background-color: var(--sc-item-tag-bg-color, #eee);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
> .date {
|
> .date {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
> .icon {
|
color: var(--sc-item-date-color, #808080);
|
||||||
width: 2.4rem;
|
|
||||||
height: 2.4rem;
|
|
||||||
margin-right: 1rem;
|
|
||||||
color: #808080;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .text {
|
> .text {
|
||||||
font-family: KaiseiOpti-Regular;
|
font-family: KaiseiOpti-Regular;
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
color: #808080;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,6 +151,26 @@
|
|||||||
align-items: var(--sc-item-right-align-items);
|
align-items: var(--sc-item-right-align-items);
|
||||||
height: var(--sc-item-right-height);
|
height: var(--sc-item-right-height);
|
||||||
margin-top: var(--sc-item-right-margin-top);
|
margin-top: var(--sc-item-right-margin-top);
|
||||||
|
> .unshelve {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
> .title {
|
||||||
|
margin-bottom: 0.8rem;
|
||||||
|
font-family: KaiseiOpti-Bold;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
color: #000;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.8rem;
|
||||||
|
}
|
||||||
|
> .tip {
|
||||||
|
font-family: KaiseiOpti-Regular;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
color: #585858;
|
||||||
|
}
|
||||||
|
}
|
||||||
> .amount {
|
> .amount {
|
||||||
font-family: KaiseiOpti-Bold;
|
font-family: KaiseiOpti-Bold;
|
||||||
font-size: var(--sc-item-amount-font-size, 2.2rem);
|
font-size: var(--sc-item-amount-font-size, 2.2rem);
|
||||||
@@ -147,7 +185,7 @@
|
|||||||
margin-top: var(--sc-item-remove-margin-top, 9rem);
|
margin-top: var(--sc-item-remove-margin-top, 9rem);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: flex-end;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
> .icon {
|
> .icon {
|
||||||
@@ -196,5 +234,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.disabled {
|
||||||
|
--sc-item-title-color: #cbcbcb;
|
||||||
|
--sc-item-brand-color: #cbcbcb;
|
||||||
|
--sc-item-date-color: #cbcbcb;
|
||||||
|
--sc-item-tag-color: #cbcbcb;
|
||||||
|
> img {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<div class="left">
|
<div class="left">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
:model-value="allSelected"
|
:model-value="allSelected"
|
||||||
:indeterminate="selectedCount === 0 ? false : selectedCount < list.length"
|
:indeterminate="selectedCount === 0 ? false : selectedCount < maxLength"
|
||||||
@click="handleAllAllClick"
|
@click="handleAllAllClick"
|
||||||
/>
|
/>
|
||||||
<span class="count">{{ selectedCount }} Selected</span>
|
<span class="count">{{ selectedCount }} Selected</span>
|
||||||
@@ -45,15 +45,21 @@
|
|||||||
/>
|
/>
|
||||||
<sc-item
|
<sc-item
|
||||||
v-for="v in list"
|
v-for="v in list"
|
||||||
:key="v.id"
|
:key="v.cartId"
|
||||||
:info="v"
|
:info="v"
|
||||||
:show-tags="!isMini || isView"
|
:show-tags="!isMini || isView"
|
||||||
:show-date="!isMini"
|
:show-date="!isMini"
|
||||||
:show-remove="!isView"
|
:show-remove="!isView"
|
||||||
@remove="handleRemoveClick"
|
@remove="handleRemoveClick"
|
||||||
|
:disabled="v.status !== SCART_STATUS.NORMAL"
|
||||||
>
|
>
|
||||||
<template #checkbox>
|
<template #checkbox v-if="!isMini">
|
||||||
<el-checkbox v-model="v.checked" v-if="!isMini" @change="handleSelectedChange" />
|
<el-checkbox
|
||||||
|
disabled
|
||||||
|
v-if="v.status !== SCART_STATUS.NORMAL"
|
||||||
|
style="opacity: 0; pointer-events: none"
|
||||||
|
/>
|
||||||
|
<el-checkbox v-else v-model="v.checked" @change="handleSelectedChange" />
|
||||||
</template>
|
</template>
|
||||||
</sc-item>
|
</sc-item>
|
||||||
</div>
|
</div>
|
||||||
@@ -70,6 +76,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
import { SCART_STATUS } from './index.d'
|
||||||
|
import { GetShoppingCartList, RemoveShoppingCartItem } from '@/api/shoppingCart'
|
||||||
import { computed, ref, onMounted } from 'vue'
|
import { computed, ref, onMounted } from 'vue'
|
||||||
import { FormatBytes, FormatDate } from '@/utils/tools'
|
import { FormatBytes, FormatDate } from '@/utils/tools'
|
||||||
import scItem from './sc-item.vue'
|
import scItem from './sc-item.vue'
|
||||||
@@ -80,90 +89,74 @@
|
|||||||
isMini: { type: Boolean, default: false },
|
isMini: { type: Boolean, default: false },
|
||||||
isView: { type: Boolean, default: false }
|
isView: { type: Boolean, default: false }
|
||||||
})
|
})
|
||||||
const allTotalSize = computed(() => {
|
|
||||||
const total = list.value.reduce((pre, cur) => pre + cur.fileSize, 0)
|
|
||||||
const str = FormatBytes(total, { unitBig: true })
|
|
||||||
return {
|
|
||||||
size: str.split(' ')[0],
|
|
||||||
unit: str.split(' ')[1]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const allAmount = computed(() => list.value.reduce((pre, cur) => pre + cur.amount, 0).toFixed(2))
|
const allAmount = computed(() => list.value.reduce((pre, cur) => pre + cur.amount, 0).toFixed(2))
|
||||||
const selectedCount = computed(() => list.value.filter((v) => v.checked).length)
|
const selectedCount = computed(() => list.value.filter((v) => v.checked).length)
|
||||||
|
const maxLength = computed(() => list.value.filter((v) => v.status === SCART_STATUS.NORMAL).length)
|
||||||
const allSelected = computed(() =>
|
const allSelected = computed(() =>
|
||||||
list.value.length === 0 ? false : list.value.every((v) => v.checked)
|
list.value.length === 0
|
||||||
|
? false
|
||||||
|
: list.value.filter((v) => v.status === SCART_STATUS.NORMAL).every((v) => v.checked)
|
||||||
)
|
)
|
||||||
const sortBy = ref('')
|
const sortBy = ref('DateAdded')
|
||||||
const sortByOptions = ref([
|
const sortByOptions = ref([
|
||||||
{
|
{
|
||||||
label: 'Default',
|
label: 'Best Selling',
|
||||||
value: 'Default'
|
value: 'BestSelling'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Price: Low to High',
|
||||||
|
value: 'PriceLowToHigh'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Selected First',
|
label: 'Selected First',
|
||||||
value: 'Selected First'
|
value: 'SelectedFirst'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Date Added',
|
label: 'Date Added',
|
||||||
value: 'Date Added'
|
value: 'DateAdded'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const list = ref([
|
const list_ = ref([])
|
||||||
{
|
const list = computed(() => {
|
||||||
id: 1,
|
// if(sortBy.value === 'BestSelling') {
|
||||||
url: 'http://118.31.39.42:3000/falls/shopping-cart-1.png',
|
// return list_.value.sort((a, b) => b.sales - a.sales)
|
||||||
title: 'North Outfit Set',
|
// }
|
||||||
brand: 'Roaming Clouds',
|
if (sortBy.value === 'PriceLowToHigh') {
|
||||||
date: '2026-5-20 5:20',
|
return list_.value.filter(() => true).sort((a, b) => a.amount - b.amount)
|
||||||
amount: 49.99,
|
|
||||||
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
|
||||||
checked: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
url: 'http://118.31.39.42:3000/falls/shopping-cart-2.png',
|
|
||||||
title: 'Weekend Drift Co-ord',
|
|
||||||
brand: 'Urban Line Edit',
|
|
||||||
date: '2026-5-21 13:14',
|
|
||||||
amount: 9.99,
|
|
||||||
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
|
||||||
checked: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
url: 'http://118.31.39.42:3000/falls/shopping-cart-3.png',
|
|
||||||
title: 'Static Street Suit',
|
|
||||||
brand: 'Off Grid Apparel',
|
|
||||||
date: '2026-5-21 13:14',
|
|
||||||
amount: 12,
|
|
||||||
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
|
||||||
checked: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
url: 'http://118.31.39.42:3000/falls/shopping-cart-4.png',
|
|
||||||
title: 'Maison Contour Suit',
|
|
||||||
brand: 'Ivory Muse Studio',
|
|
||||||
date: '2026-5-21 13:14',
|
|
||||||
amount: 18,
|
|
||||||
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
|
||||||
checked: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
url: 'http://118.31.39.42:3000/falls/shopping-cart-5.png',
|
|
||||||
title: 'Prime Atelier Set',
|
|
||||||
brand: 'Ivory Muse Studio',
|
|
||||||
date: '2026-5-21 13:14',
|
|
||||||
amount: 20,
|
|
||||||
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
|
||||||
checked: false
|
|
||||||
}
|
}
|
||||||
])
|
if (sortBy.value === 'SelectedFirst') {
|
||||||
|
return list_.value.filter(() => true).sort((a, b) => (b.checked ? 1 : 0) - (a.checked ? 1 : 0))
|
||||||
|
}
|
||||||
|
if (sortBy.value === 'DateAdded') {
|
||||||
|
return list_.value.filter(() => true).sort((a, b) => b.date - a.date)
|
||||||
|
}
|
||||||
|
return list_.value.filter(() => true)
|
||||||
|
})
|
||||||
|
const GetList = () => {
|
||||||
|
GetShoppingCartList(true).then((res: any) => {
|
||||||
|
const arr = []
|
||||||
|
res?.forEach((v, i) => {
|
||||||
|
const obj = {
|
||||||
|
cartId: v.cartId, //购物车ID
|
||||||
|
listingId: v.listingId, //资产ID
|
||||||
|
title: v.title, //标题
|
||||||
|
cover: v.cover, //封面
|
||||||
|
amount: v.price, //价格
|
||||||
|
status: v.status, //状态
|
||||||
|
date: v.addTime, //添加时间
|
||||||
|
checked: false
|
||||||
|
}
|
||||||
|
arr.push(obj)
|
||||||
|
})
|
||||||
|
list_.value = arr
|
||||||
|
handleSelectedChange()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
GetList()
|
||||||
const handleAllAllClick = (checked?: boolean) => {
|
const handleAllAllClick = (checked?: boolean) => {
|
||||||
const checked_ = typeof checked === 'boolean' ? checked : !allSelected.value
|
const checked_ = typeof checked === 'boolean' ? checked : !allSelected.value
|
||||||
list.value.forEach((v) => (v.checked = checked_))
|
list.value.forEach((v) => (v.checked = v.status === SCART_STATUS.NORMAL ? checked_ : false))
|
||||||
handleSelectedChange()
|
handleSelectedChange()
|
||||||
}
|
}
|
||||||
const handleSelectedChange = () => {
|
const handleSelectedChange = () => {
|
||||||
@@ -176,9 +169,14 @@
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
handleSelectedChange()
|
handleSelectedChange()
|
||||||
})
|
})
|
||||||
const handleRemoveClick = (id: number) => {
|
const handleRemoveClick = (value: any) => {
|
||||||
list.value = list.value.filter((v) => v.id !== id)
|
ElMessageBox.confirm('Are you sure to remove this item?')
|
||||||
handleSelectedChange()
|
.then(() => {
|
||||||
|
RemoveShoppingCartItem({ listingId: value.listingId }).then(() => {
|
||||||
|
GetList()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
}
|
}
|
||||||
const handleExploreClick = () => {
|
const handleExploreClick = () => {
|
||||||
console.log('探索')
|
console.log('探索')
|
||||||
|
|||||||
@@ -3,12 +3,14 @@
|
|||||||
<aside class="wardrobe-assets__filters">
|
<aside class="wardrobe-assets__filters">
|
||||||
<div class="filters-card">
|
<div class="filters-card">
|
||||||
<div class="filters-card__heading">
|
<div class="filters-card__heading">
|
||||||
<h2 class="filters-card__title">Filters</h2>
|
<h2 class="filters-card__title">{{ t('Wardrobe.assets.filters') }}</h2>
|
||||||
<button class="filters-card__clear" type="button" @click="clearFilters">Clear</button>
|
<button class="filters-card__clear" type="button" @click="clearFilters">
|
||||||
|
{{ t('Wardrobe.assets.clear') }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="filter-group">
|
<section class="filter-group">
|
||||||
<h3 class="filter-group__title">Categories</h3>
|
<h3 class="filter-group__title">{{ t('Wardrobe.assets.categories') }}</h3>
|
||||||
<div class="filter-group__line"></div>
|
<div class="filter-group__line"></div>
|
||||||
<div class="filter-group__options">
|
<div class="filter-group__options">
|
||||||
<button
|
<button
|
||||||
@@ -28,7 +30,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="filter-group">
|
<section class="filter-group">
|
||||||
<h3 class="filter-group__title">Gender</h3>
|
<h3 class="filter-group__title">{{ t('Wardrobe.assets.gender') }}</h3>
|
||||||
<div class="filter-group__line"></div>
|
<div class="filter-group__line"></div>
|
||||||
<div class="filter-group__options">
|
<div class="filter-group__options">
|
||||||
<button
|
<button
|
||||||
@@ -57,10 +59,16 @@
|
|||||||
<div class="assets-toolbar__selection">
|
<div class="assets-toolbar__selection">
|
||||||
<div class="select-count flex align-center">
|
<div class="select-count flex align-center">
|
||||||
<img src="@/assets/images/wardrobe/select.png" />
|
<img src="@/assets/images/wardrobe/select.png" />
|
||||||
<span class="assets-toolbar__count">{{ selectedCount }} Selected</span>
|
<span class="assets-toolbar__count">
|
||||||
|
{{ t('Wardrobe.assets.selectedCount', { count: selectedCount }) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="assets-toolbar__link" @click="handleSelectAll(true)">
|
||||||
|
{{ t('Wardrobe.assets.selectAll') }}
|
||||||
|
</div>
|
||||||
|
<div class="assets-toolbar__link" @click="handleSelectAll(false)">
|
||||||
|
{{ t('Wardrobe.assets.deselectAll') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="assets-toolbar__link" @click="handleSelectAll(true)">Select All</div>
|
|
||||||
<div class="assets-toolbar__link" @click="handleSelectAll(false)">Deselect All</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="assets-toolbar__actions">
|
<div class="assets-toolbar__actions">
|
||||||
@@ -70,7 +78,7 @@
|
|||||||
@click="handleDownloadSelected"
|
@click="handleDownloadSelected"
|
||||||
>
|
>
|
||||||
<SvgIcon name="downloadBtn" color="#fff" />
|
<SvgIcon name="downloadBtn" color="#fff" />
|
||||||
<span>Download Selected</span>
|
<span>{{ t('Wardrobe.assets.downloadSelected') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,7 +114,9 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, shallowRef, watch } from 'vue'
|
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, shallowRef, watch } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
import { useClothesCategories } from '@/utils/ClothesCategory'
|
||||||
import img from '@/assets/images/collectionStory/Rectangle.png'
|
import img from '@/assets/images/collectionStory/Rectangle.png'
|
||||||
import Empty from './Empty.vue'
|
import Empty from './Empty.vue'
|
||||||
|
|
||||||
@@ -116,26 +126,26 @@ interface FilterOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const { t } = useI18n({ useScope: 'global' })
|
||||||
|
const clothesCategories = useClothesCategories()
|
||||||
|
|
||||||
const categories: FilterOption[] = [
|
const categories = computed<FilterOption[]>(() => [
|
||||||
{ label: 'All', value: 'all' },
|
{ label: t('Wardrobe.common.all'), value: 'all' },
|
||||||
{ label: 'Outerwear', value: 'outerwear' },
|
...clothesCategories.value.map((option) => ({
|
||||||
{ label: 'Dress', value: 'dress' },
|
label: option.label,
|
||||||
{ label: 'Trousers', value: 'trousers' },
|
value: option.value
|
||||||
{ label: 'Blouse', value: 'blouse' },
|
}))
|
||||||
{ label: 'Skirt', value: 'skirt' },
|
])
|
||||||
{ label: 'Accessories', value: 'accessories' }
|
|
||||||
]
|
|
||||||
|
|
||||||
const genders: FilterOption[] = [
|
const genders = computed<FilterOption[]>(() => [
|
||||||
{ label: 'All', value: 'all' },
|
{ label: t('Wardrobe.common.all'), value: 'all' },
|
||||||
{ label: 'Male', value: 'male' },
|
{ label: t('Wardrobe.assets.genders.male'), value: 'male' },
|
||||||
{ label: 'Female', value: 'female' }
|
{ label: t('Wardrobe.assets.genders.female'), value: 'female' }
|
||||||
]
|
])
|
||||||
|
|
||||||
const categoryValues = categories
|
const categoryValues = computed(() =>
|
||||||
.filter((option) => option.value !== 'all')
|
categories.value.filter((option) => option.value !== 'all').map((option) => option.value)
|
||||||
.map((option) => option.value)
|
)
|
||||||
|
|
||||||
const filters = reactive({
|
const filters = reactive({
|
||||||
categories: ['skirt'] as string[],
|
categories: ['skirt'] as string[],
|
||||||
@@ -209,8 +219,8 @@ const selectedCount = computed(() => {
|
|||||||
})
|
})
|
||||||
const allCategoriesSelected = computed(() => {
|
const allCategoriesSelected = computed(() => {
|
||||||
return (
|
return (
|
||||||
filters.categories.length === categoryValues.length &&
|
filters.categories.length === categoryValues.value.length &&
|
||||||
categoryValues.every((value) => filters.categories.includes(value))
|
categoryValues.value.every((value) => filters.categories.includes(value))
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -224,7 +234,7 @@ const isCategoryActive = (value: string) => {
|
|||||||
|
|
||||||
const toggleCategory = (value: string) => {
|
const toggleCategory = (value: string) => {
|
||||||
if (value === 'all') {
|
if (value === 'all') {
|
||||||
filters.categories = allCategoriesSelected.value ? [] : [...categoryValues]
|
filters.categories = allCategoriesSelected.value ? [] : [...categoryValues.value]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +251,7 @@ const setGender = (value: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const clearFilters = () => {
|
const clearFilters = () => {
|
||||||
filters.categories = [...categoryValues]
|
filters.categories = [...categoryValues.value]
|
||||||
filters.gender = 'all'
|
filters.gender = 'all'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,9 +466,9 @@ onUnmounted(() => {
|
|||||||
font-family: 'KaiseiOpti-Regular';
|
font-family: 'KaiseiOpti-Regular';
|
||||||
.select-count {
|
.select-count {
|
||||||
column-gap: 1.2rem;
|
column-gap: 1.2rem;
|
||||||
img{
|
img {
|
||||||
width: 2.4rem;
|
width: 2.4rem;
|
||||||
height: 2.4rem ;
|
height: 2.4rem;
|
||||||
}
|
}
|
||||||
.assets-toolbar__count {
|
.assets-toolbar__count {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -544,7 +554,6 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n({ useScope: 'global' })
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: 'explore'): void
|
(event: 'explore'): void
|
||||||
}>()
|
}>()
|
||||||
@@ -8,12 +12,12 @@ const emit = defineEmits<{
|
|||||||
<div class="wardrobe-empty flex flex-col flex-center">
|
<div class="wardrobe-empty flex flex-col flex-center">
|
||||||
<img src="@/assets/images/wardrobe/empty-wardrobe.png" class="wardrobe-empty__image" alt="" />
|
<img src="@/assets/images/wardrobe/empty-wardrobe.png" class="wardrobe-empty__image" alt="" />
|
||||||
|
|
||||||
<h2 class="wardrobe-empty__title">Nothing in Wardrobe yet</h2>
|
<h2 class="wardrobe-empty__title">{{ t('Wardrobe.empty.title') }}</h2>
|
||||||
<p class="wardrobe-empty__description">
|
<p class="wardrobe-empty__description">
|
||||||
Explore the digital item and add pieces to your collection.
|
{{ t('Wardrobe.empty.description') }}
|
||||||
</p>
|
</p>
|
||||||
<button class="wardrobe-empty__button" type="button" @click="emit('explore')">
|
<button class="wardrobe-empty__button" type="button" @click="emit('explore')">
|
||||||
Explore Digital Items
|
{{ t('Wardrobe.empty.action') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -33,17 +33,17 @@
|
|||||||
:style="{ backgroundColor: item.color }"
|
:style="{ backgroundColor: item.color }"
|
||||||
></span>
|
></span>
|
||||||
<span v-if="getExtraCount(order)" class="order-card__extra">
|
<span v-if="getExtraCount(order)" class="order-card__extra">
|
||||||
+{{ getExtraCount(order) }} more
|
{{ t('Wardrobe.orders.moreItems', { count: getExtraCount(order) }) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="order-card__status" :class="`is-${order.status}`">
|
<div class="order-card__status" :class="`is-${order.status}`">
|
||||||
{{ order.status.toUpperCase() }}
|
{{ getStatusBadgeLabel(order.status) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="order-card__amount">
|
<div class="order-card__amount">
|
||||||
<span>${{ order.amount }}</span>
|
<span>${{ order.amount }}</span>
|
||||||
<small>HKD</small>
|
<small>{{ t('Wardrobe.common.currencyHkd') }}</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@@ -52,9 +52,7 @@
|
|||||||
:class="{ 'is-primary': order.status === 'unpaid' }"
|
:class="{ 'is-primary': order.status === 'unpaid' }"
|
||||||
>
|
>
|
||||||
<svg-icon v-if="order.status === 'paid'" name="Invoice" size="20" color="#232323" />
|
<svg-icon v-if="order.status === 'paid'" name="Invoice" size="20" color="#232323" />
|
||||||
<span v-if="order.status === 'paid'">Invoice</span>
|
<span>{{ getOrderActionLabel(order.status) }}</span>
|
||||||
<span v-else-if="order.status === 'unpaid'">Complete Payment</span>
|
|
||||||
<span v-else>Buy Again</span>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -76,7 +74,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, shallowRef } from 'vue'
|
import { computed, shallowRef, onMounted,ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { fetchMyOrders } from '@/api/user'
|
||||||
import ScItem from '@/views/shoppingCart/sc-item.vue'
|
import ScItem from '@/views/shoppingCart/sc-item.vue'
|
||||||
|
|
||||||
type OrderStatus = 'all' | 'paid' | 'unpaid' | 'cancelled'
|
type OrderStatus = 'all' | 'paid' | 'unpaid' | 'cancelled'
|
||||||
@@ -109,13 +109,14 @@ interface OrderRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const placeholderImage = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='
|
const placeholderImage = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='
|
||||||
|
const { t } = useI18n({ useScope: 'global' })
|
||||||
|
|
||||||
const statusOptions: StatusOption[] = [
|
const statusOptions = computed<StatusOption[]>(() => [
|
||||||
{ key: 'all', label: 'All' },
|
{ key: 'all', label: t('Wardrobe.orders.statuses.all') },
|
||||||
{ key: 'paid', label: 'Paid' },
|
{ key: 'paid', label: t('Wardrobe.orders.statuses.paid') },
|
||||||
{ key: 'unpaid', label: 'Unpaid' },
|
{ key: 'unpaid', label: t('Wardrobe.orders.statuses.unpaid') },
|
||||||
{ key: 'cancelled', label: 'Canceled' }
|
{ key: 'cancelled', label: t('Wardrobe.orders.statuses.cancelled') }
|
||||||
]
|
])
|
||||||
|
|
||||||
const createOrderItem = (
|
const createOrderItem = (
|
||||||
id: number,
|
id: number,
|
||||||
@@ -201,6 +202,30 @@ const toggleOrder = (orderId: string) => {
|
|||||||
const getExtraCount = (order: OrderRecord) => {
|
const getExtraCount = (order: OrderRecord) => {
|
||||||
return Math.max(order.items.length - 2, 0)
|
return Math.max(order.items.length - 2, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getStatusBadgeLabel = (status: ActualOrderStatus) => {
|
||||||
|
return t(`Wardrobe.orders.statusBadges.${status}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOrderActionLabel = (status: ActualOrderStatus) => {
|
||||||
|
if (status === 'paid') return t('Wardrobe.orders.actions.invoice')
|
||||||
|
if (status === 'unpaid') return t('Wardrobe.orders.actions.completePayment')
|
||||||
|
return t('Wardrobe.orders.actions.buyAgain')
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderParams =ref({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
status: ''
|
||||||
|
})
|
||||||
|
const fetchAllOrders = () => {
|
||||||
|
fetchMyOrders(orderParams.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchAllOrders()
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="wardrobe-page">
|
<div class="wardrobe-page">
|
||||||
<div class="wardrobe-hero flex flex-col flex-center">
|
<div class="wardrobe-hero flex flex-col flex-center">
|
||||||
<div class="wardrobe-hero__title">My Wardrobe</div>
|
<div class="wardrobe-hero__title">{{ t('Wardrobe.title') }}</div>
|
||||||
<div class="wardrobe-hero__subtitle">Your digital pieces, all in one place</div>
|
<div class="wardrobe-hero__subtitle">{{ t('Wardrobe.subtitle') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wardrobe-shell">
|
<div class="wardrobe-shell">
|
||||||
<div class="wardrobe-tabs">
|
<div class="wardrobe-tabs">
|
||||||
<div class="wardrobe-tabs__nav" role="tablist" aria-label="Wardrobe tabs">
|
<div class="wardrobe-tabs__nav" role="tablist" :aria-label="t('Wardrobe.tabs.ariaLabel')">
|
||||||
<button
|
<button
|
||||||
v-for="tab in tabs"
|
v-for="tab in tabs"
|
||||||
:key="tab.key"
|
:key="tab.key"
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="activeTab === 'assets'" class="wardrobe-tabs__sort">
|
<div v-if="activeTab === 'assets'" class="wardrobe-tabs__sort">
|
||||||
<div class="wardrobe-tabs__sort-label">Sort by</div>
|
<div class="wardrobe-tabs__sort-label">{{ t('Wardrobe.sort.label') }}</div>
|
||||||
<el-select v-model="activeSort" placeholder="Select">
|
<el-select v-model="activeSort" :placeholder="t('Wardrobe.sort.placeholder')">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="option in sortOptions"
|
v-for="option in sortOptions"
|
||||||
:key="option.value"
|
:key="option.value"
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, shallowRef } from 'vue'
|
import { computed, shallowRef } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import Assets from './Assets.vue'
|
import Assets from './Assets.vue'
|
||||||
import Orders from './Orders.vue'
|
import Orders from './Orders.vue'
|
||||||
|
|
||||||
@@ -57,31 +58,33 @@ interface SortOption {
|
|||||||
value: number
|
value: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabs: TabItem[] = [
|
const { t } = useI18n({ useScope: 'global' })
|
||||||
|
|
||||||
|
const tabs = computed<TabItem[]>(() => [
|
||||||
{
|
{
|
||||||
key: 'assets',
|
key: 'assets',
|
||||||
label: 'Assets'
|
label: t('Wardrobe.tabs.assets')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'orders',
|
key: 'orders',
|
||||||
label: 'Orders'
|
label: t('Wardrobe.tabs.orders')
|
||||||
}
|
}
|
||||||
]
|
])
|
||||||
|
|
||||||
const sortOptions: SortOption[] = [
|
const sortOptions = computed<SortOption[]>(() => [
|
||||||
{
|
{
|
||||||
label: 'Default',
|
label: t('Wardrobe.sort.default'),
|
||||||
value: 0
|
value: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Date Added',
|
label: t('Wardrobe.sort.dateAdded'),
|
||||||
value: 1
|
value: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Selected First',
|
label: t('Wardrobe.sort.selectedFirst'),
|
||||||
value: 2
|
value: 2
|
||||||
}
|
}
|
||||||
]
|
])
|
||||||
|
|
||||||
const activeTab = shallowRef<WardrobeTab>('assets')
|
const activeTab = shallowRef<WardrobeTab>('assets')
|
||||||
const activeSort = shallowRef(1)
|
const activeSort = shallowRef(1)
|
||||||
|
|||||||
@@ -66,11 +66,10 @@ export default defineConfig(({ mode }) => {
|
|||||||
overlay: true
|
overlay: true
|
||||||
},
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/buyer': {
|
||||||
//'/api'是自行设置的请求前缀
|
|
||||||
target: env.VITE_APP_URL,
|
target: env.VITE_APP_URL,
|
||||||
changeOrigin: true, //用于控制请求头中的host值
|
changeOrigin: true, //用于控制请求头中的host值
|
||||||
rewrite: (path) => path.replace(/^\/api/, '/api') //路径重写,(正则)匹配以api开头的路径为空(将请求前缀删除)
|
rewrite: (path) => path.replace(/^\/buyer/, '/buyer') //路径重写,(正则)匹配以api开头的路径为空(将请求前缀删除)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user