Files
orico-association/pagesMall/cart/index.vue
2026-03-25 15:53:37 +08:00

415 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- +----------------------------------------------------------------------
| 麦沃德科技赋能开发者助力商协会发展
+----------------------------------------------------------------------
| Copyright (c) 20172024 www.wdsxh.cn All rights reserved.
+----------------------------------------------------------------------
| 沃德商协会系统并不是自由软件不加密并不代表开源未经许可不可自由转售和商用
+----------------------------------------------------------------------
| Author: MY WORLD Team <bd@maiwd.cn> www.maiwd.cn
+----------------------------------------------------------------------
| 购物车 开发者: 麦沃德科技-半夏
+---------------------------------------------------------------------- -->
<template>
<page-meta :page-style="'overflow:' + (pageShow ? 'hidden' : 'visible')"></page-meta>
<view class="container" :style="{'--theme-color': themeColor}">
<!-- 标题栏 -->
<title-bar title="购物车"></title-bar>
<!-- 内容区 -->
<view class="container-main" v-if="loadEnd">
<view class="main-header flex justify-content-between align-items-center" v-if="cartList.length">
<view class="header-title">商品列表</view>
<view class="header-btn" @click="handleDelete()">清除购物车</view>
</view>
<view class="main-list">
<mall-cart :show-data="cartList" @changeSelect="changeSelect" @changeNumber="changeNumber" v-if="cartList.length"></mall-cart>
<empty top="30%" title="暂无商品," btnText="去购物" @callback="toShopping()" v-else></empty>
</view>
<view class="main-footer flex align-items-center" v-if="cartList.length">
<view class="footer-radio flex align-items-center" @click="toggleSelectAll()">
<view class="radio-input" :class="{active: allSelected}">
<image src="/static/tick.png" mode="aspectFit" v-if="allSelected"></image>
</view>
<view class="radio-label">全选</view>
</view>
<view class="footer-amount flex-item flex align-items-center justify-content-end">
<text class="label">合计</text>
<text class="amount text-ellipsis">{{totalPrice}}</text>
</view>
<view class="footer-btn" :class="{disabled: !selectedList.length}" @click="toSettlement()">去结算</view>
</view>
<view class="safe-padding" style="background: #FFF;"></view>
</view>
<!-- 选择数量弹窗 -->
<quantity-modal ref="quantityModal" @confirm="changeQuantity" @onChange="pageChange"></quantity-modal>
<!-- 底部导航 -->
<tab-bar></tab-bar>
</view>
</template>
<script>
import { mapState } from "vuex"
import mallCart from '@/pagesMall/component/mall/cart.vue'
import quantityModal from "@/pagesMall/component/modal/quantity.vue"
export default {
components: {
mallCart,
quantityModal,
},
data() {
return {
// 页面是否阻止滚动
pageShow: false,
// 加载完成
loadEnd: false,
// 购物车列表
cartList: [],
// 是否全选
allSelected: false,
}
},
computed: {
...mapState({
themeColor: state => state.app.themeColor,
}),
totalPrice() {
var result = this.cartList.filter(item => item.selected).reduce((sum, item) => sum + (parseFloat(item.price) * parseInt(item.number)), 0)
return parseFloat(result).toFixed(2);
},
selectedList() {
return this.cartList.filter(item => item.selected);
},
},
watch: {
cartList: {
handler() {
this.allSelected = this.cartList.every(item => item.selected);
},
immediate: true,
deep: true
}
},
onLoad() {
if (uni.getStorageSync("token")) {
uni.showLoading({
title: "加载中"
})
this.getCartList(() => {
this.loadEnd = true
uni.hideLoading()
})
} else {
this.loadEnd = true
}
},
onShow() {
if (this.loadEnd && uni.getStorageSync("token")) {
this.getCartList()
}
},
onPullDownRefresh() {
if (uni.getStorageSync("token")) {
this.getCartList(() => {
uni.stopPullDownRefresh();
})
} else {
uni.stopPullDownRefresh();
}
},
methods: {
// 改变页面滚动状态
pageChange(state) {
this.pageShow = state
},
// 获取购物车列表
getCartList(fn) {
this.$util.request("mall.cartList").then(res => {
if (fn) fn()
if (res.code == 1) {
var list = res.data || []
if (list.length && this.selectedList.length) {
list.forEach(item => {
if (this.selectedList.some(el => el.id === item.id)) {
this.$set(item, 'selected', true);
}
});
}
this.cartList = list
} else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
}).catch(error => {
if (fn) fn()
console.error('获取购物车列表', error)
})
},
// 去购物
toShopping() {
this.$util.toPage({
mode: 1,
path: "/pages/mall/index"
})
},
// 更改数量
changeNumber(index, type) {
var data = this.cartList[index]
if (type == 1) {
if (parseInt(data.number) > 1) {
data.number = parseInt(data.number) - 1
} else {
this.handleDelete(data.id)
return
}
} else if (type == 2) {
data.number = parseInt(data.number) + 1
} else if (type == 3) {
this.$refs.quantityModal.open(data.number, index)
return
}
this.updateCartNumber(data, () => {
this.$set(this.cartList, index, data)
})
},
// 选择数量弹窗回调
changeQuantity(number, index) {
var data = this.cartList[index]
data.number = number
this.updateCartNumber(data, () => {
this.$set(this.cartList, index, data)
})
},
// 更新购物车商品数量
updateCartNumber(data, fn) {
uni.showLoading({
title: "加载中",
mask: true,
})
this.$util.request("mall.updateCartNumber", {
goods_id: data.id,
number: data.number,
}).then(res => {
uni.hideLoading()
if (res.code == 1) {
if (fn) fn()
} else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
}).catch(error => {
uni.hideLoading()
console.error('更新购物车商品数量', error)
})
},
// 删除购物车商品
handleDelete(id) {
if (id) {
uni.showModal({
content: "确认删除该商品吗?",
confirmColor: this.themeColor,
success: (res) => {
if (res.confirm) {
this.deleteEvent(id)
}
}
})
} else {
if (this.selectedList.length) {
uni.showModal({
content: `确认要删除这${this.selectedList.length}种商品吗?`,
confirmColor: this.themeColor,
success: (res) => {
if (res.confirm) {
const idList = this.selectedList.map(item => item.id)
this.deleteEvent(idList.join())
}
}
})
} else {
uni.showToast({
icon: "none",
title: "请选择要删除的商品",
duration: 2000
})
}
}
},
// 删除事件
deleteEvent(ids) {
uni.showLoading({
title: "加载中",
mask: true,
})
this.$util.request("mall.deleteCart", {
goods_id: ids,
}).then(res => {
uni.hideLoading()
if (res.code == 1) {
uni.showToast({
icon: "success",
title: "删除成功",
duration: 2000
})
this.getCartList()
} else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
}).catch(error => {
uni.hideLoading()
console.error('删除事件', error)
})
},
// 更改选择
changeSelect(index) {
var data = this.cartList[index]
data.selected = !data.selected
this.$set(this.cartList, index, data)
},
// 切换全选状态
toggleSelectAll() {
this.cartList.forEach(item => {
this.$set(item, "selected", !this.allSelected)
});
this.$forceUpdate()
},
// 去结算
toSettlement() {
if (!this.selectedList.length) {
uni.showToast({
title: "请至少选择一件商品",
icon: "none",
duration: 2000
})
return;
}
var isDisabled = false;
for (var i in this.selectedList) {
if (this.selectedList[i].goods_status == 2) {
isDisabled = true
break;
}
}
if (isDisabled) {
uni.showToast({
title: "存在已下架商品",
icon: "none",
duration: 2000
})
return
}
this.$store.commit("app/setMallOrder", { isCartItem: true, list: this.selectedList })
this.$util.toPage({
mode: 1,
path: "/pagesMall/goods/order",
})
},
}
}
</script>
<style lang="scss">
page {
padding-bottom: 0;
}
.container {
height: 100vh;
display: flex;
flex-direction: column;
.container-main {
flex: 1;
display: flex;
flex-direction: column;
.main-header {
padding: 32rpx 32rpx 0;
.header-title {
color: #5A5B6E;
font-size: 32rpx;
font-weight: 600;
line-height: 44rpx;
}
.header-btn {
color: var(--theme-color);
font-size: 28rpx;
line-height: 40rpx;
}
}
.main-list {
flex: 1;
padding: 32rpx;
}
.main-footer {
padding: 32rpx;
background: #FFF;
.footer-radio {
.radio-input {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
background: #D6DBDE;
&.active {
background: var(--theme-color);
}
}
.radio-label {
margin-left: 16rpx;
color: #5A5B6E;
font-size: 28rpx;
line-height: 40rpx;
}
}
.footer-amount {
margin-left: 16rpx;
.label {
color: #C4C4C4;
font-size: 28rpx;
line-height: 40rpx;
white-space: nowrap;
}
.amount {
margin-left: 8rpx;
color: var(--theme-color);
font-size: 28rpx;
font-weight: 600;
line-height: 40rpx;
}
}
.footer-btn {
margin-left: 20rpx;
color: #FFF;
font-size: 28rpx;
line-height: 40rpx;
padding: 16rpx 32rpx;
min-width: 200rpx;
border-radius: 36rpx;
background: var(--theme-color);
text-align: center;
&.disabled {
background: #AAA;
}
}
}
}
}
</style>