feat: 购物车+分类页面优化

This commit is contained in:
zc 2025-12-08 18:17:12 +08:00
parent ca7506f903
commit 0baa476aee
7 changed files with 197 additions and 37 deletions

View File

@ -1,8 +1,13 @@
<template>
<goods-sku-popup :modelValue="visible" @input="onChangeValue" border-radius="20" :localdata="localdata" :mode="2" :maskCloseAble="true"
:priceColor="appTheme.mainBg" :buyNowBackgroundColor="appTheme.mainBg" :addCartColor="appTheme.viceText" :addCartBackgroundColor="appTheme.viceBg"
:activedStyle="{ color: appTheme.mainBg, borderColor: appTheme.mainBg, backgroundColor: activedBtnBackgroundColor }"
@add-cart="addCart" buyNowText="立即购买" />
<view>
<goods-sku-popup :modelValue="visible" @input="onChangeValue" border-radius="20" :localdata="localdata" :mode="2" :maskCloseAble="true"
:priceColor="appTheme.mainBg" :buyNowBackgroundColor="appTheme.mainBg" :addCartColor="appTheme.viceText" :addCartBackgroundColor="appTheme.viceBg"
:activedStyle="{ color: appTheme.mainBg, borderColor: appTheme.mainBg, backgroundColor: activedBtnBackgroundColor }"
@add-cart="addCart" buyNowText="立即购买" />
<!-- 自定义Toast提示 -->
<custom-toast ref="customToast" />
</view>
</template>
<script>
@ -12,10 +17,12 @@
import * as CartApi from '@/api/cart'
import * as GoodsApi from '@/api/goods'
import GoodsSkuPopup from '@/components/goods-sku-popup'
import CustomToast from '@/components/toast'
export default {
components: {
GoodsSkuPopup
GoodsSkuPopup,
CustomToast
},
props: {
// 1 2 3
@ -152,12 +159,17 @@
const { goods_sku_id, buy_num } = selectShop
GoodsApi.apiAddCart({ skuId: goods_sku_id, num: buy_num })
.then(result => {
//
app.$toast(result.msg, 1000, false)
// Toast
app.$refs.customToast.show({
text: '添加成功',
icon: 'checkmark-circle-fill',
iconColor: app.appTheme.mainBg,
duration: 1000
})
//
app.onChangeValue(false)
//
const cartTotal = result.data.cartTotal
const cartTotal = (uni.getStorageSync('cartTotalNum') || 0) + 1
//
setCartTotalNum(cartTotal)
//

116
components/toast/index.vue Normal file
View File

@ -0,0 +1,116 @@
<template>
<view v-if="visible" class="custom-toast" :style="{ animationDuration: duration + 'ms' }">
<view class="toast-content">
<view class="toast-icon">
<u-icon :name="icon" :color="iconColor" :size="iconSize"></u-icon>
</view>
<view class="toast-text">{{ text }}</view>
</view>
</view>
</template>
<script>
export default {
name: 'CustomToast',
data() {
return {
visible: false,
text: '添加成功',
icon: 'checkmark-circle-fill',
iconColor: '#4CD964',
iconSize: 60,
duration: 1000,
timer: null
}
},
methods: {
// Toast
show(options = {}) {
const app = this
//
if (app.timer) {
clearTimeout(app.timer)
app.timer = null
}
//
app.text = options.text || '添加成功'
app.icon = options.icon || 'checkmark-circle-fill'
app.iconColor = options.iconColor || '#4CD964'
app.iconSize = options.iconSize || 60
app.duration = options.duration || 1000
// Toast
app.visible = true
//
app.timer = setTimeout(() => {
app.hide()
}, app.duration)
},
// Toast
hide() {
const app = this
app.visible = false
if (app.timer) {
clearTimeout(app.timer)
app.timer = null
}
}
}
}
</script>
<style lang="scss" scoped>
.custom-toast {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 9999;
pointer-events: none;
animation: fadeInOut 1s ease-in-out;
}
.toast-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.7);
border-radius: 16rpx;
padding: 40rpx 60rpx;
min-width: 200rpx;
}
.toast-icon {
margin-bottom: 20rpx;
display: flex;
align-items: center;
justify-content: center;
}
.toast-text {
color: #fff;
font-size: 28rpx;
line-height: 1.5;
text-align: center;
}
@keyframes fadeInOut {
0% {
opacity: 0;
transform: translate(-50%, -50%) scale(0.8);
}
20% {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
80% {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
100% {
opacity: 0;
transform: translate(-50%, -50%) scale(0.8);
}
}
</style>

View File

@ -2,6 +2,7 @@ import store from '@/store'
import * as util from '@/utils/util'
import { paginate } from '@/common/constant'
import Config from './config'
import * as OrderApi from '@/api/order'
/**
* 显示成功提示框
@ -148,11 +149,13 @@ export const getCurrentPage = () => {
/**
* 获取购物车商品总数量
* @param {*} value
*/
export const getCartTotalNum = (value) => {
const cartTotal = uni.getStorageSync('cartTotalNum') || 0
return checkLogin() ? cartTotal : 0
export const getCartTotalNum = async () => {
let cartTotal = uni.getStorageSync('cartTotalNum') || 0
await OrderApi.apiGetCartList({page: 1, pageSize: 10000 }).then(res => {
cartTotal = res.data.total
})
return cartTotal
}
/**
@ -167,9 +170,9 @@ export const setCartTotalNum = (value) => {
* 设置购物车tabbar的角标
* 该方法只能在tabbar页面中调用, 其他页面调用会报错
*/
export const setCartTabBadge = () => {
export const setCartTabBadge = async (val) => {
const cartTabbarIndex = 2
const cartTotal = getCartTotalNum()
const cartTotal = val || await getCartTotalNum()
if (cartTotal > 0) {
uni.setTabBarBadge({
index: cartTabbarIndex,

View File

@ -41,7 +41,7 @@
<text class="value">{{ item.singlePrice }}</text>
</view>
<view class="stepper">
<u-number-box :min="1" :modelValue="item.num" :step="1" @change="onChangeStepper($event, item)" />
<u-number-box v-model="item.num" :step="1" @change="onChangeStepper($event, item)" />
</view>
</view>
</view>
@ -124,7 +124,7 @@
total(val) {
//
setCartTotalNum(val)
setCartTabBadge()
setCartTabBadge(val)
}
},
onShow() {
@ -154,7 +154,7 @@
getCartList() {
const app = this
app.isLoading = true
OrderApi.apiGetCartList({}).then(res => {
OrderApi.apiGetCartList({ page: 1, pageSize: 10000 }).then(res => {
app.total = res.data.total
app.list = res.data.rows.map(item => ({ ...item, skuInfo: JSON.parse(item.skuInfo) }))
// checkedIdsID
@ -177,8 +177,24 @@
//
onChangeStepper({ value }, item) {
//
if (item.num == value) return
if (value < 1) {
uni.showModal({
title: '提示',
content: '确定要删除这个商品吗?',
confirmText: '确定',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
//
this.deleteCartItem(item)
} else if (res.cancel) {
item.num = 1
this.onCalcTotalPrice()
}
}
})
return
}
//
if (!item.debounceHandle) {
item.oldValue = item.num
@ -267,6 +283,13 @@
}
})
},
deleteCartItem(item) {
const app = this
app.list = app.list.filter(i => i.id !== item.id)
OrderApi.apiDeleteCart({ shoppingCartIds: [item.id] }).then(res => {
app.$toast('删除成功')
})
},
//
onClearCart() {
const app = this

View File

@ -117,12 +117,20 @@
// query
query: {
handler({ categoryId1, categoryId2 }) {
if (!this.list.length) return
this.curIndex = this.findCateIndex(categoryId1)
this.curIndex2 = this.findCateIndex(categoryId2, this.curIndex)
this.showSubCate = false
this.onRefreshList()
},
immediate: true
}
},
list: {
handler(val) {
this.curIndex = this.findCateIndex(this.query.categoryId1)
this.curIndex2 = this.findCateIndex(this.query.categoryId2, this.curIndex)
this.showSubCate = false
this.onRefreshList()
}
}
},
computed: {
@ -135,7 +143,6 @@
}
},
methods: {
// ID
findCateIndex(cateId, pIndex = -1) {
if (!cateId) return -1

View File

@ -39,7 +39,6 @@
this.onRefreshPage()
},
onShow() {
// query
store.dispatch('OnceQueryParam')
.then(res => {

View File

@ -58,13 +58,12 @@ export default [
"imgUrl": "https://heyuimage.ihzhy.com/prd/202512/f377422a4bf2982c.png",
"imgName": "icon-2.jpg",
"link": {
"title": "商品列表页",
"title": "商品分类页",
"type": "PAGE",
"param": {
"path": "pages/goods/list",
"path": "pages/category/index",
"query": {
"categoryId": "10085",
"search": ""
"categoryId1": "59"
}
},
},
@ -74,13 +73,12 @@ export default [
"imgUrl": "https://heyuimage.ihzhy.com/prd/202512/a29b7b8d2c94a6c5.png",
"imgName": "icon-3.jpg",
"link": {
"title": "商品列表页",
"title": "商品分类页",
"type": "PAGE",
"param": {
"path": "pages/goods/list",
"path": "pages/category/index",
"query": {
"categoryId": "10001",
"search": ""
"categoryId1": "46"
}
},
},
@ -90,10 +88,13 @@ export default [
"imgUrl": "https://heyuimage.ihzhy.com/prd/202512/076083dffbf723e3.png",
"imgName": "icon-1.png",
"link": {
"title": "领券中心",
"title": "商品分类页",
"type": "PAGE",
"param": {
"path": "pages/coupon/index"
"path": "pages/category/index",
"query": {
"categoryId1": "49"
}
}
},
"text": "耳部饰品"
@ -102,13 +103,12 @@ export default [
"imgUrl": "https://heyuimage.ihzhy.com/prd/202512/d60d74363bdd1e6e.png",
"imgName": "icon-4.jpg",
"link": {
"title": "商品列表页",
"title": "商品分类页",
"type": "PAGE",
"param": {
"path": "pages/goods/list",
"path": "pages/category/index",
"query": {
"categoryId": "10088",
"search": ""
"categoryId1": "48"
}
},
},