feat: 加入购物车优化
This commit is contained in:
@@ -16,7 +16,8 @@ const saveCartItems = items => {
|
|||||||
|
|
||||||
export const useCartStore = defineStore('joyfulSelectionCart', {
|
export const useCartStore = defineStore('joyfulSelectionCart', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
items: []
|
items: [],
|
||||||
|
loaded: false
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
totalCount: state => state.items.reduce((total, item) => total + Number(item.count || 0), 0),
|
totalCount: state => state.items.reduce((total, item) => total + Number(item.count || 0), 0),
|
||||||
@@ -25,11 +26,17 @@ export const useCartStore = defineStore('joyfulSelectionCart', {
|
|||||||
actions: {
|
actions: {
|
||||||
loadCart() {
|
loadCart() {
|
||||||
this.items = readCartItems()
|
this.items = readCartItems()
|
||||||
|
this.loaded = true
|
||||||
},
|
},
|
||||||
persistCart() {
|
persistCart() {
|
||||||
saveCartItems(this.items)
|
saveCartItems(this.items)
|
||||||
|
this.loaded = true
|
||||||
},
|
},
|
||||||
addItem(item) {
|
addItem(item) {
|
||||||
|
if (!this.loaded) {
|
||||||
|
this.loadCart()
|
||||||
|
}
|
||||||
|
|
||||||
const index = this.items.findIndex(cartItem => cartItem.cartId === item.cartId)
|
const index = this.items.findIndex(cartItem => cartItem.cartId === item.cartId)
|
||||||
|
|
||||||
if (index > -1) {
|
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>
|
||||||
<van-goods-action-icon icon="chat-o" text="客服" dot />
|
<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-icon icon="star" text="已收藏" color="#ff5000" />
|
||||||
<van-goods-action-button type="warning" text="加入购物车" @click="$toast('已加入购物车')" />
|
<van-goods-action-button type="warning" text="加入购物车" @click="openSku('cart')" />
|
||||||
<van-goods-action-button type="danger" text="立即购买" @click="$router.push('/joyful-selection/checkout')" />
|
<van-goods-action-button type="danger" text="立即购买" @click="openSku('buy')" />
|
||||||
</van-goods-action>
|
</van-goods-action>
|
||||||
|
|
||||||
|
<joyful-sku-popup ref="skuPopup" @add-cart="loadCart" />
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { useCartStore } from '@/store/cart'
|
||||||
import { getJoyfulProduct } from '../product-data'
|
import { getJoyfulProduct } from '../product-data'
|
||||||
|
import JoyfulSkuPopup from '../components/JoyfulSkuPopup.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JoyfulSelectionProductDetail',
|
name: 'JoyfulSelectionProductDetail',
|
||||||
|
components: {
|
||||||
|
JoyfulSkuPopup
|
||||||
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
count: 1,
|
count: 1,
|
||||||
features: [
|
features: [
|
||||||
@@ -82,7 +90,20 @@ export default {
|
|||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState(useCartStore, ['totalCount']),
|
||||||
|
cartBadge() {
|
||||||
|
return this.totalCount > 0 ? this.totalCount : ''
|
||||||
|
},
|
||||||
product() { return getJoyfulProduct(this.$route.query.id) }
|
product() { return getJoyfulProduct(this.$route.query.id) }
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadCart()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useCartStore, ['loadCart']),
|
||||||
|
openSku(mode) {
|
||||||
|
this.$refs.skuPopup.open(this.product, mode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -47,25 +47,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<van-sku
|
<joyful-sku-popup ref="skuPopup" />
|
||||||
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"
|
|
||||||
/>
|
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Toast } from 'vant'
|
|
||||||
import { joyfulProducts } from '../product-data'
|
import { joyfulProducts } from '../product-data'
|
||||||
import { useCartStore } from '@/store/cart'
|
import JoyfulSkuPopup from '../components/JoyfulSkuPopup.vue'
|
||||||
|
|
||||||
const productImages = joyfulProducts.map(item => item.image)
|
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 {
|
export default {
|
||||||
name: 'JoyfulSelectionProductList',
|
name: 'JoyfulSelectionProductList',
|
||||||
|
components: {
|
||||||
|
JoyfulSkuPopup
|
||||||
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
selectedCategoryId: 'recommend',
|
selectedCategoryId: 'recommend',
|
||||||
showSku: false,
|
|
||||||
keyword: '',
|
keyword: '',
|
||||||
currentGoods: defaultGoods,
|
|
||||||
categories,
|
categories,
|
||||||
goods
|
goods
|
||||||
}),
|
}),
|
||||||
@@ -193,48 +169,6 @@ export default {
|
|||||||
return this.keyword
|
return this.keyword
|
||||||
? categoryGoods.filter(item => item.name.includes(this.keyword))
|
? categoryGoods.filter(item => item.name.includes(this.keyword))
|
||||||
: categoryGoods
|
: 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: {
|
methods: {
|
||||||
@@ -242,37 +176,7 @@ export default {
|
|||||||
this.$router.push({ path: '/joyful-selection/product-detail', query: { id: item.id } })
|
this.$router.push({ path: '/joyful-selection/product-detail', query: { id: item.id } })
|
||||||
},
|
},
|
||||||
openSku(item) {
|
openSku(item) {
|
||||||
this.currentGoods = item
|
this.$refs.skuPopup.open(item, 'cart')
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -532,13 +436,4 @@ export default {
|
|||||||
font-size: 20px;
|
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>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user