feat: 商品提交列表
This commit is contained in:
@@ -0,0 +1,324 @@
|
||||
<template>
|
||||
<section class="cart-panel" :class="{ 'cart-panel--page': pageMode }">
|
||||
<van-notice-bar v-if="showNotice" text="满 199 元包邮,快去凑单吧~" left-icon="info-o" />
|
||||
<section class="cart-list">
|
||||
<van-empty v-if="!items.length" description="购物车还是空的" />
|
||||
<template v-else>
|
||||
<article
|
||||
v-for="item in items"
|
||||
:key="item.cartId"
|
||||
class="cart-item"
|
||||
>
|
||||
<van-checkbox
|
||||
:value="isItemChecked(item)"
|
||||
class="item-check"
|
||||
checked-color="#ff5b20"
|
||||
@input="toggleItem(item, $event)"
|
||||
/>
|
||||
<van-image class="item-thumb" :src="item.image" fit="cover" />
|
||||
<div class="item-info">
|
||||
<h3>{{ item.name }}</h3>
|
||||
<p class="item-desc">{{ item.desc }}</p>
|
||||
<van-tag class="item-tag" plain type="danger">{{ item.tag }}</van-tag>
|
||||
<div class="item-bottom">
|
||||
<b>¥{{ item.price }}</b>
|
||||
<van-stepper
|
||||
v-model="item.count"
|
||||
class="quantity-stepper"
|
||||
integer
|
||||
min="0"
|
||||
button-size="30"
|
||||
input-width="36"
|
||||
@change="onCountChange(item, $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
</section>
|
||||
<van-submit-bar
|
||||
:fixed="fixedSubmit"
|
||||
:price="selectedTotalPrice"
|
||||
:button-text="submitText"
|
||||
@submit="$emit('checkout', selectedItems)"
|
||||
>
|
||||
<van-checkbox
|
||||
:value="isAllChecked"
|
||||
:indeterminate="isPartChecked"
|
||||
checked-color="#ff5b20"
|
||||
@input="toggleAll"
|
||||
>全选</van-checkbox>
|
||||
</van-submit-bar>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulCartPanel',
|
||||
props: {
|
||||
fixedSubmit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
pageMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showNotice: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
selectedIds: []
|
||||
}),
|
||||
computed: {
|
||||
...mapState(useCartStore, ['items']),
|
||||
cartIds() {
|
||||
return this.items.map(item => item.cartId)
|
||||
},
|
||||
selectedItems() {
|
||||
return this.items.filter(item => this.selectedIds.includes(item.cartId))
|
||||
},
|
||||
selectedTotalCount() {
|
||||
return this.selectedItems.reduce((total, item) => total + Number(item.count || 0), 0)
|
||||
},
|
||||
selectedTotalPrice() {
|
||||
return this.selectedItems.reduce((total, item) => total + Math.round(Number(item.price) * 100) * Number(item.count || 0), 0)
|
||||
},
|
||||
isAllChecked() {
|
||||
return this.items.length > 0 && this.selectedIds.length === this.items.length
|
||||
},
|
||||
isPartChecked() {
|
||||
return this.selectedIds.length > 0 && this.selectedIds.length < this.items.length
|
||||
},
|
||||
submitText() {
|
||||
return `去结算(${this.selectedTotalCount})`
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
cartIds(newIds, oldIds) {
|
||||
const wasAllChecked = oldIds.length > 0 && oldIds.every(cartId => this.selectedIds.includes(cartId))
|
||||
const validSelectedIds = this.selectedIds.filter(cartId => newIds.includes(cartId))
|
||||
|
||||
this.selectedIds = wasAllChecked ? newIds : validSelectedIds
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadCart()
|
||||
this.selectAllItems()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useCartStore, ['loadCart', 'persistCart', 'removeItems']),
|
||||
selectAllItems() {
|
||||
this.selectedIds = this.items.map(item => item.cartId)
|
||||
},
|
||||
isItemChecked(item) {
|
||||
return this.selectedIds.includes(item.cartId)
|
||||
},
|
||||
toggleItem(item, checked) {
|
||||
if (checked && !this.isItemChecked(item)) {
|
||||
this.selectedIds = [...this.selectedIds, item.cartId]
|
||||
return
|
||||
}
|
||||
|
||||
if (!checked) {
|
||||
this.selectedIds = this.selectedIds.filter(cartId => cartId !== item.cartId)
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.selectedIds = checked ? this.items.map(item => item.cartId) : []
|
||||
},
|
||||
onCountChange(item, count) {
|
||||
if (Number(count) < 1) {
|
||||
this.removeItems([item.cartId])
|
||||
return
|
||||
}
|
||||
|
||||
this.persistCart()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.cart-panel {
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-panel--page {
|
||||
min-height: calc(100vh - 46px);
|
||||
padding-bottom: 108px;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-notice-bar {
|
||||
height: 34px;
|
||||
flex: none;
|
||||
color: #ff7a38;
|
||||
background: #fff3ea;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.cart-list {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 0 16px 12px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
display: flex;
|
||||
min-height: 128px;
|
||||
align-items: center;
|
||||
padding: 16px 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-item + .cart-item {
|
||||
border-top: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.item-check {
|
||||
flex: none;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-checkbox__icon--checked .van-icon {
|
||||
border-color: #ff5b20;
|
||||
background-color: #ff5b20;
|
||||
}
|
||||
|
||||
.item-thumb {
|
||||
width: 94px;
|
||||
height: 94px;
|
||||
flex: none;
|
||||
overflow: hidden;
|
||||
border-radius: 5px;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
min-height: 94px;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.item-info h3 {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
margin: 0 0 4px;
|
||||
color: #222;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
overflow: hidden;
|
||||
margin: 0 0 6px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-tag {
|
||||
width: fit-content;
|
||||
color: #ff5b20;
|
||||
border-color: #ff9b73;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.item-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.item-bottom b {
|
||||
color: #ff5b20;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.quantity-stepper {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__minus,
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__plus,
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__input {
|
||||
height: 30px;
|
||||
margin: 0;
|
||||
border: 1px solid #edf0f4;
|
||||
background: #fff;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__minus {
|
||||
width: 32px;
|
||||
border-radius: 6px 0 0 6px;
|
||||
color: #9aa0a6;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__input {
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__plus {
|
||||
width: 32px;
|
||||
border-radius: 0 6px 6px 0;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-submit-bar {
|
||||
position: relative;
|
||||
height: 58px;
|
||||
flex: none;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-panel--page ::v-deep .van-submit-bar {
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-submit-bar__bar {
|
||||
height: 58px;
|
||||
padding: 0 18px;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-submit-bar__price {
|
||||
color: #ff5b20;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-submit-bar__button {
|
||||
width: 104px;
|
||||
height: 40px;
|
||||
border-radius: 22px;
|
||||
background: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user