feat: 加入购物车优化
This commit is contained in:
@@ -16,7 +16,8 @@ const saveCartItems = items => {
|
||||
|
||||
export const useCartStore = defineStore('joyfulSelectionCart', {
|
||||
state: () => ({
|
||||
items: []
|
||||
items: [],
|
||||
loaded: false
|
||||
}),
|
||||
getters: {
|
||||
totalCount: state => state.items.reduce((total, item) => total + Number(item.count || 0), 0),
|
||||
@@ -25,11 +26,17 @@ export const useCartStore = defineStore('joyfulSelectionCart', {
|
||||
actions: {
|
||||
loadCart() {
|
||||
this.items = readCartItems()
|
||||
this.loaded = true
|
||||
},
|
||||
persistCart() {
|
||||
saveCartItems(this.items)
|
||||
this.loaded = true
|
||||
},
|
||||
addItem(item) {
|
||||
if (!this.loaded) {
|
||||
this.loadCart()
|
||||
}
|
||||
|
||||
const index = this.items.findIndex(cartItem => cartItem.cartId === item.cartId)
|
||||
|
||||
if (index > -1) {
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<van-sku
|
||||
v-model="show"
|
||||
:sku="sku"
|
||||
:goods="skuGoods"
|
||||
:goods-id="currentGoods.id"
|
||||
:initial-sku="initialSku"
|
||||
:hide-stock="sku.hide_stock"
|
||||
:show-add-cart-btn="mode === 'cart'"
|
||||
:show-buy-btn="mode === 'buy'"
|
||||
:preview-on-click-image="true"
|
||||
add-cart-text="加入购物车"
|
||||
buy-text="立即购买"
|
||||
@add-cart="onAddCartClicked"
|
||||
@buy-clicked="onBuyClicked"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Toast } from 'vant'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
|
||||
const colorOptions = [
|
||||
{ id: 'cream', name: '奶油白' },
|
||||
{ id: 'blue', name: '雾霾蓝' },
|
||||
{ id: 'orange', name: '暖橙色' }
|
||||
]
|
||||
|
||||
const sizeOptions = [
|
||||
{ id: 'standard', name: '标准款' },
|
||||
{ id: 'plus', name: '升级款' }
|
||||
]
|
||||
|
||||
const emptyGoods = {
|
||||
id: '',
|
||||
name: '',
|
||||
price: '0.00',
|
||||
image: '',
|
||||
tag: '赠品'
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSkuPopup',
|
||||
data: () => ({
|
||||
show: false,
|
||||
mode: 'cart',
|
||||
currentGoods: emptyGoods
|
||||
}),
|
||||
computed: {
|
||||
skuGoods() {
|
||||
return {
|
||||
title: this.currentGoods.name,
|
||||
picture: this.currentGoods.image
|
||||
}
|
||||
},
|
||||
initialSku() {
|
||||
return {
|
||||
s1: colorOptions[0].id,
|
||||
s2: sizeOptions[0].id
|
||||
}
|
||||
},
|
||||
sku() {
|
||||
const price = Math.round(Number(this.currentGoods.price) * 100)
|
||||
|
||||
return {
|
||||
tree: [
|
||||
{
|
||||
k: '颜色',
|
||||
k_s: 's1',
|
||||
v: colorOptions
|
||||
},
|
||||
{
|
||||
k: '尺寸',
|
||||
k_s: 's2',
|
||||
v: sizeOptions
|
||||
}
|
||||
],
|
||||
list: colorOptions.flatMap(color =>
|
||||
sizeOptions.map(size => ({
|
||||
id: `${this.currentGoods.id}-${color.id}-${size.id}`,
|
||||
s1: color.id,
|
||||
s2: size.id,
|
||||
price,
|
||||
stock_num: 99
|
||||
}))
|
||||
),
|
||||
price: this.currentGoods.price,
|
||||
stock_num: 99,
|
||||
none_sku: false,
|
||||
hide_stock: true
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(goods, mode = 'cart') {
|
||||
this.currentGoods = goods
|
||||
this.mode = mode
|
||||
this.show = true
|
||||
},
|
||||
getCartPayload(data) {
|
||||
const selectedSku = data.selectedSkuComb || {}
|
||||
const selectedColor = colorOptions.find(item => item.id === selectedSku.s1) || colorOptions[0]
|
||||
const selectedSize = sizeOptions.find(item => item.id === selectedSku.s2) || sizeOptions[0]
|
||||
const count = data.selectedNum || 1
|
||||
|
||||
return {
|
||||
cartId: selectedSku.id || `${this.currentGoods.id}-${selectedColor.id}-${selectedSize.id}`,
|
||||
id: this.currentGoods.id,
|
||||
name: this.currentGoods.name,
|
||||
desc: `${selectedColor.name} / ${selectedSize.name}`,
|
||||
price: this.currentGoods.price,
|
||||
image: this.currentGoods.image,
|
||||
tag: this.currentGoods.tag,
|
||||
count,
|
||||
sku: {
|
||||
color: selectedColor.name,
|
||||
size: selectedSize.name
|
||||
}
|
||||
}
|
||||
},
|
||||
addCart(data) {
|
||||
const cartStore = useCartStore()
|
||||
cartStore.addItem(this.getCartPayload(data))
|
||||
},
|
||||
onAddCartClicked(data) {
|
||||
this.addCart(data)
|
||||
Toast('已加入购物车')
|
||||
this.show = false
|
||||
this.$emit('add-cart')
|
||||
},
|
||||
onBuyClicked(data) {
|
||||
this.addCart(data)
|
||||
this.show = false
|
||||
this.$emit('buy')
|
||||
this.$router.push('/joyful-selection/checkout')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
::v-deep .van-sku-header {
|
||||
min-height: 118px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-header__img-wrap {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-header__goods-info {
|
||||
min-height: 110px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku__goods-name {
|
||||
color: #111;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku__price-symbol,
|
||||
::v-deep .van-sku__price-num {
|
||||
color: #ff5b20;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-row__item--active {
|
||||
color: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-actions .van-button--danger {
|
||||
background: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
}
|
||||
</style>
|
||||
@@ -59,19 +59,27 @@
|
||||
|
||||
<van-goods-action>
|
||||
<van-goods-action-icon icon="chat-o" text="客服" dot />
|
||||
<van-goods-action-icon icon="cart-o" text="购物车" badge="5" @click="$router.push('/joyful-selection/cart')" />
|
||||
<van-goods-action-icon icon="cart-o" text="购物车" :badge="cartBadge" @click="$router.push('/joyful-selection/cart')" />
|
||||
<van-goods-action-icon icon="star" text="已收藏" color="#ff5000" />
|
||||
<van-goods-action-button type="warning" text="加入购物车" @click="$toast('已加入购物车')" />
|
||||
<van-goods-action-button type="danger" text="立即购买" @click="$router.push('/joyful-selection/checkout')" />
|
||||
<van-goods-action-button type="warning" text="加入购物车" @click="openSku('cart')" />
|
||||
<van-goods-action-button type="danger" text="立即购买" @click="openSku('buy')" />
|
||||
</van-goods-action>
|
||||
|
||||
<joyful-sku-popup ref="skuPopup" @add-cart="loadCart" />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
import { getJoyfulProduct } from '../product-data'
|
||||
import JoyfulSkuPopup from '../components/JoyfulSkuPopup.vue'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionProductDetail',
|
||||
components: {
|
||||
JoyfulSkuPopup
|
||||
},
|
||||
data: () => ({
|
||||
count: 1,
|
||||
features: [
|
||||
@@ -82,7 +90,20 @@ export default {
|
||||
]
|
||||
}),
|
||||
computed: {
|
||||
...mapState(useCartStore, ['totalCount']),
|
||||
cartBadge() {
|
||||
return this.totalCount > 0 ? this.totalCount : ''
|
||||
},
|
||||
product() { return getJoyfulProduct(this.$route.query.id) }
|
||||
},
|
||||
created() {
|
||||
this.loadCart()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useCartStore, ['loadCart']),
|
||||
openSku(mode) {
|
||||
this.$refs.skuPopup.open(this.product, mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -47,25 +47,13 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-sku
|
||||
v-model="showSku"
|
||||
:sku="sku"
|
||||
:goods="skuGoods"
|
||||
:goods-id="currentGoods.id"
|
||||
:initial-sku="initialSku"
|
||||
:hide-stock="sku.hide_stock"
|
||||
buy-text="立即购买"
|
||||
add-cart-text="加入购物车"
|
||||
@buy-clicked="onBuyClicked"
|
||||
@add-cart="onAddCartClicked"
|
||||
/>
|
||||
<joyful-sku-popup ref="skuPopup" />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Toast } from 'vant'
|
||||
import { joyfulProducts } from '../product-data'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
import JoyfulSkuPopup from '../components/JoyfulSkuPopup.vue'
|
||||
|
||||
const productImages = joyfulProducts.map(item => item.image)
|
||||
|
||||
@@ -162,26 +150,14 @@ const goods = productCategories.flatMap(category =>
|
||||
}))
|
||||
)
|
||||
|
||||
const colorOptions = [
|
||||
{ id: 'cream', name: '奶油白' },
|
||||
{ id: 'blue', name: '雾霾蓝' },
|
||||
{ id: 'orange', name: '暖橙色' }
|
||||
]
|
||||
|
||||
const sizeOptions = [
|
||||
{ id: 'standard', name: '标准款' },
|
||||
{ id: 'plus', name: '升级款' }
|
||||
]
|
||||
|
||||
const defaultGoods = goods[0]
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionProductList',
|
||||
components: {
|
||||
JoyfulSkuPopup
|
||||
},
|
||||
data: () => ({
|
||||
selectedCategoryId: 'recommend',
|
||||
showSku: false,
|
||||
keyword: '',
|
||||
currentGoods: defaultGoods,
|
||||
categories,
|
||||
goods
|
||||
}),
|
||||
@@ -193,48 +169,6 @@ export default {
|
||||
return this.keyword
|
||||
? categoryGoods.filter(item => item.name.includes(this.keyword))
|
||||
: categoryGoods
|
||||
},
|
||||
skuGoods() {
|
||||
return {
|
||||
title: this.currentGoods.name,
|
||||
picture: this.currentGoods.image
|
||||
}
|
||||
},
|
||||
initialSku() {
|
||||
return {
|
||||
s1: colorOptions[0].id,
|
||||
s2: sizeOptions[0].id
|
||||
}
|
||||
},
|
||||
sku() {
|
||||
const price = Math.round(Number(this.currentGoods.price) * 100)
|
||||
return {
|
||||
tree: [
|
||||
{
|
||||
k: '颜色',
|
||||
k_s: 's1',
|
||||
v: colorOptions
|
||||
},
|
||||
{
|
||||
k: '尺寸',
|
||||
k_s: 's2',
|
||||
v: sizeOptions
|
||||
}
|
||||
],
|
||||
list: colorOptions.flatMap(color =>
|
||||
sizeOptions.map(size => ({
|
||||
id: `${this.currentGoods.id}-${color.id}-${size.id}`,
|
||||
s1: color.id,
|
||||
s2: size.id,
|
||||
price,
|
||||
stock_num: 99
|
||||
}))
|
||||
),
|
||||
price: this.currentGoods.price,
|
||||
stock_num: 99,
|
||||
none_sku: false,
|
||||
hide_stock: true
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -242,37 +176,7 @@ export default {
|
||||
this.$router.push({ path: '/joyful-selection/product-detail', query: { id: item.id } })
|
||||
},
|
||||
openSku(item) {
|
||||
this.currentGoods = item
|
||||
this.showSku = true
|
||||
},
|
||||
onBuyClicked() {
|
||||
Toast('请选择规格后购买')
|
||||
},
|
||||
onAddCartClicked(data) {
|
||||
const selectedSku = data.selectedSkuComb || {}
|
||||
const selectedColor = colorOptions.find(item => item.id === selectedSku.s1) || colorOptions[0]
|
||||
const selectedSize = sizeOptions.find(item => item.id === selectedSku.s2) || sizeOptions[0]
|
||||
const count = data.selectedNum || 1
|
||||
|
||||
const cartStore = useCartStore()
|
||||
|
||||
cartStore.addItem({
|
||||
cartId: selectedSku.id || `${this.currentGoods.id}-${selectedColor.id}-${selectedSize.id}`,
|
||||
id: this.currentGoods.id,
|
||||
name: this.currentGoods.name,
|
||||
desc: `${selectedColor.name} / ${selectedSize.name}`,
|
||||
price: this.currentGoods.price,
|
||||
image: this.currentGoods.image,
|
||||
tag: this.currentGoods.tag,
|
||||
count,
|
||||
sku: {
|
||||
color: selectedColor.name,
|
||||
size: selectedSize.name
|
||||
}
|
||||
})
|
||||
|
||||
Toast('已加入购物车')
|
||||
this.showSku = false
|
||||
this.$refs.skuPopup.open(item, 'cart')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -532,13 +436,4 @@ export default {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.product-page ::v-deep .van-sku-actions .van-button--danger {
|
||||
background: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
}
|
||||
|
||||
.product-page ::v-deep .van-sku-row__item--active {
|
||||
color: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user