feat: 购物车+分类页面优化
This commit is contained in:
parent
ca7506f903
commit
0baa476aee
@ -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
116
components/toast/index.vue
Normal 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>
|
||||
|
||||
15
core/app.js
15
core/app.js
@ -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,
|
||||
|
||||
@ -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) }))
|
||||
// 清除checkedIds中无效的ID
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -39,7 +39,6 @@
|
||||
this.onRefreshPage()
|
||||
},
|
||||
onShow() {
|
||||
|
||||
// 监听query参数
|
||||
store.dispatch('OnceQueryParam')
|
||||
.then(res => {
|
||||
|
||||
@ -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"
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user