Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/Aida_Purchaser_Front
This commit is contained in:
@@ -41,15 +41,14 @@ export const GetShoppingCartList = (loading?: boolean) => {
|
||||
|
||||
/**
|
||||
* 从购物车移除商品
|
||||
* @param data - 包含邮箱的参数
|
||||
* @param data.listingId - 商品ID
|
||||
* @param data.listingIds - 商品ID列表
|
||||
* @param params - 包含邮箱的参数
|
||||
* @param params.listingId - 商品ID
|
||||
*/
|
||||
export const RemoveShoppingCartItem = (data, loading?: boolean) => {
|
||||
export const RemoveShoppingCartItem = (params, loading?: boolean) => {
|
||||
return request({
|
||||
url: '/buyer/buyer/cart/remove',
|
||||
method: 'delete',
|
||||
data,
|
||||
params,
|
||||
loading
|
||||
})
|
||||
}
|
||||
|
||||
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 |
@@ -41,7 +41,7 @@ service.interceptors.request.use(
|
||||
// Do something before request is sent
|
||||
const token = useUserInfoStore().state.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 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
const props = defineProps({
|
||||
email: { type: String, required: true },
|
||||
type: {
|
||||
type: String as () => 'LOGIN' | 'REGISTER' | 'FORGOT_PWD',
|
||||
type: String as () => 'LOGIN' | 'REGISTER' | 'FORGET_PWD',
|
||||
required: true
|
||||
},
|
||||
password: { type: String, default: '' },
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
:name="data.name"
|
||||
:email="data.email"
|
||||
:password="data.password"
|
||||
type="FORGOT_PWD"
|
||||
type="FORGET_PWD"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
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>
|
||||
<div class="profile-content">
|
||||
<div class="info">
|
||||
@@ -109,11 +111,6 @@
|
||||
icon: 'cart_0',
|
||||
active_icon: 'cart_1',
|
||||
path: '/shoppingCart'
|
||||
},
|
||||
{
|
||||
icon: 'user_0',
|
||||
active_icon: 'user_1',
|
||||
path: '/account'
|
||||
}
|
||||
])
|
||||
const onNavItemClick = (path: string) => {
|
||||
|
||||
7
src/views/shoppingCart/index.d.js
Normal file
7
src/views/shoppingCart/index.d.js
Normal file
@@ -0,0 +1,7 @@
|
||||
/** 商品状态 */
|
||||
export const SCART_STATUS = {
|
||||
/** 正常 */
|
||||
NORMAL: 1,
|
||||
/** 下架 */
|
||||
DISABLED: 0,
|
||||
}
|
||||
@@ -1,7 +1,14 @@
|
||||
<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" />
|
||||
<img :src="info.url" />
|
||||
{{ info.status }}
|
||||
<img :src="info.cover" />
|
||||
<div class="content">
|
||||
<div class="title">{{ info.title }}</div>
|
||||
<div class="brand">
|
||||
@@ -12,14 +19,20 @@
|
||||
<span v-for="tag in info.tags" :key="tag" class="tag">{{ tag }}</span>
|
||||
</div>
|
||||
<div class="date" v-if="showDate">
|
||||
<!-- <div class="icon"><svg-icon name="order-file" size="18" /></div> -->
|
||||
<div class="text">
|
||||
{{ FormatDate(info.date, 'SM D, YYYY, h:mm A') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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
|
||||
v-if="orderActionsLayout"
|
||||
class="download"
|
||||
@@ -44,10 +57,22 @@
|
||||
showDate: { type: Boolean, default: true },
|
||||
showRemove: { type: Boolean, default: true },
|
||||
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 = () => {
|
||||
emit('remove', props.info.id)
|
||||
emit('remove', props.info)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -76,7 +101,7 @@
|
||||
> .title {
|
||||
font-family: KaiseiOpti-Bold;
|
||||
font-size: var(--sc-item-title-font-size, 2.4rem);
|
||||
color: #232323;
|
||||
color: var(--sc-item-title-color, #232323);
|
||||
}
|
||||
> .brand {
|
||||
display: flex;
|
||||
@@ -85,11 +110,12 @@
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
margin-right: 1rem;
|
||||
color: var(--sc-item-brand-color, #232323);
|
||||
}
|
||||
> .text {
|
||||
font-size: var(--sc-item-brand-font-size, 1.6rem);
|
||||
text-decoration: underline;
|
||||
color: #232323;
|
||||
color: var(--sc-item-brand-color, #232323);
|
||||
}
|
||||
}
|
||||
> .tags {
|
||||
@@ -104,24 +130,17 @@
|
||||
font-size: var(--sc-item-tag-font-size, 1.4rem);
|
||||
padding: var(--sc-item-tag-padding, 0 1rem);
|
||||
text-align: center;
|
||||
color: #8f8f8f;
|
||||
background-color: #eee;
|
||||
color: var(--sc-item-tag-color, #8f8f8f);
|
||||
background-color: var(--sc-item-tag-bg-color, #eee);
|
||||
}
|
||||
}
|
||||
> .date {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> .icon {
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
margin-right: 1rem;
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
color: var(--sc-item-date-color, #808080);
|
||||
> .text {
|
||||
font-family: KaiseiOpti-Regular;
|
||||
font-size: 1.4rem;
|
||||
color: #808080;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,6 +152,26 @@
|
||||
align-items: var(--sc-item-right-align-items);
|
||||
height: var(--sc-item-right-height);
|
||||
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 {
|
||||
font-family: KaiseiOpti-Bold;
|
||||
font-size: var(--sc-item-amount-font-size, 2.2rem);
|
||||
@@ -147,7 +186,7 @@
|
||||
margin-top: var(--sc-item-remove-margin-top, 9rem);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: flex-end;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
> .icon {
|
||||
@@ -196,5 +235,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>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="left">
|
||||
<el-checkbox
|
||||
:model-value="allSelected"
|
||||
:indeterminate="selectedCount === 0 ? false : selectedCount < list.length"
|
||||
:indeterminate="selectedCount === 0 ? false : selectedCount < maxLength"
|
||||
@click="handleAllAllClick"
|
||||
/>
|
||||
<span class="count">{{ selectedCount }} Selected</span>
|
||||
@@ -45,15 +45,21 @@
|
||||
/>
|
||||
<sc-item
|
||||
v-for="v in list"
|
||||
:key="v.id"
|
||||
:key="v.cartId"
|
||||
:info="v"
|
||||
:show-tags="!isMini || isView"
|
||||
:show-date="!isMini"
|
||||
:show-remove="!isView"
|
||||
@remove="handleRemoveClick"
|
||||
:disabled="v.status === SCART_STATUS.DISABLED"
|
||||
>
|
||||
<template #checkbox>
|
||||
<el-checkbox v-model="v.checked" v-if="!isMini" @change="handleSelectedChange" />
|
||||
<template #checkbox v-if="!isMini">
|
||||
<el-checkbox
|
||||
disabled
|
||||
v-if="v.status === SCART_STATUS.DISABLED"
|
||||
style="opacity: 0; pointer-events: none"
|
||||
/>
|
||||
<el-checkbox v-else v-model="v.checked" @change="handleSelectedChange" />
|
||||
</template>
|
||||
</sc-item>
|
||||
</div>
|
||||
@@ -70,6 +76,9 @@
|
||||
</template>
|
||||
|
||||
<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 { FormatBytes, FormatDate } from '@/utils/tools'
|
||||
import scItem from './sc-item.vue'
|
||||
@@ -80,90 +89,74 @@
|
||||
isMini: { 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 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(() =>
|
||||
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([
|
||||
{
|
||||
label: 'Default',
|
||||
value: 'Default'
|
||||
label: 'Best Selling',
|
||||
value: 'BestSelling'
|
||||
},
|
||||
{
|
||||
label: 'Price: Low to High',
|
||||
value: 'PriceLowToHigh'
|
||||
},
|
||||
{
|
||||
label: 'Selected First',
|
||||
value: 'Selected First'
|
||||
value: 'SelectedFirst'
|
||||
},
|
||||
{
|
||||
label: 'Date Added',
|
||||
value: 'Date Added'
|
||||
value: 'DateAdded'
|
||||
}
|
||||
])
|
||||
|
||||
const list = ref([
|
||||
{
|
||||
id: 1,
|
||||
url: 'http://118.31.39.42:3000/falls/shopping-cart-1.png',
|
||||
title: 'North Outfit Set',
|
||||
brand: 'Roaming Clouds',
|
||||
date: '2026-5-20 5:20',
|
||||
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
|
||||
const list_ = ref([])
|
||||
const list = computed(() => {
|
||||
// if(sortBy.value === 'BestSelling') {
|
||||
// return list_.value.sort((a, b) => b.sales - a.sales)
|
||||
// }
|
||||
if (sortBy.value === 'PriceLowToHigh') {
|
||||
return list_.value.filter(() => true).sort((a, b) => a.amount - b.amount)
|
||||
}
|
||||
])
|
||||
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 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()
|
||||
}
|
||||
const handleSelectedChange = () => {
|
||||
@@ -176,9 +169,14 @@
|
||||
onMounted(() => {
|
||||
handleSelectedChange()
|
||||
})
|
||||
const handleRemoveClick = (id: number) => {
|
||||
list.value = list.value.filter((v) => v.id !== id)
|
||||
handleSelectedChange()
|
||||
const handleRemoveClick = (value: any) => {
|
||||
ElMessageBox.confirm('Are you sure to remove this item?')
|
||||
.then(() => {
|
||||
RemoveShoppingCartItem({ listingId: value.listingId }).then(() => {
|
||||
GetList()
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
const handleExploreClick = () => {
|
||||
console.log('探索')
|
||||
|
||||
Reference in New Issue
Block a user