<template> <view class="container"> <!-- 空白页 --> <view v-if="!hasLogin || empty === true" class="empty"> <image src="/static/error/emptyCart.png" class="emptyImg" mode="aspectFit"></image> <view v-if="hasLogin" class="empty-tips"> 空空如也 <navigator class="navigator" v-if="hasLogin" url="../index/index" open-type="switchTab">随便逛逛> </navigator> </view> <view v-else class="empty-tips"> 空空如也 <view class="navigator" @click="navToLogin">去登陆></view> </view> </view> <view v-else> <!-- 购物车头部 --> <view class="cart-hand flex"> <view class="hand-tit"> 购物车共 <text>{{ ' ' + cartList.length }} 件</text> 商品 </view> <view class="hand-btn" @click="clearCart()">清空购物车</view> </view> <!-- 列表 --> <view class="cart-list"> <block v-for="(item, index) in cartList" :key="item.id"> <view class="cart-item" :class="{ 'b-b': index !== cartList.length - 1 }"> <view class="image-wrapper"> <image :src="item.productInfo.image" :class="[item.loaded]" mode="aspectFill" lazy-load @load="onImageLoad('cartList', index)" @error="onImageError('cartList', index)"></image> <view class="iconfont iconroundcheckfill checkbox" :class="{ checked: item.checked }" @click="check('item', index)"></view> </view> <view class="item-right"> <text class="clamp title">{{ item.productInfo.store_name }}</text> <text class="attr">{{ item.productInfo.attrInfo.suk }}</text> <text class="price">¥{{ item.truePrice }}</text> <!-- <uni-number-box class="step" :min="1" :max="item.productInfo.stock" :value="item.cart_num > item.productInfo.stock ? item.productInfo.stock : item.cart_num" :isMax="item.cart_num >= item.productInfo.stock ? true : false" :isMin="item.cart_num === 1" :index="index" @eventChange="numberChange" ></uni-number-box> --> <view class="munbox flex"> <image src="../../static/icon/reduce.png" mode="" @click="reduce(item, index)"></image> <input type="number" :value="item.cart_num" disabled /> <image src="../../static/icon/add.png" mode="" @click="add(item)"></image> </view> </view> <!-- <text class="del-btn iconfont iconclose" @click="deleteCartItem(index)"></text> --> </view> </block> </view> <!-- 底部菜单栏 --> <view class="action-section"> <view class="checkbox"> <view class="iconfont iconroundcheckfill icon-checked-box" @click="check('all')" :class="{ 'icon-checked': allChecked }"></view> <!-- <view class="clear-btn" @click="allChecked ? clearCart() : ''" :class="{ show: allChecked }"><text>清空</text></view> --> </view> <view class="total-box"> <text class="price">¥{{ total }}</text> <!-- <text class="coupon"> 已优惠 <text>74.35</text> 元 </text> --> </view> <button type="primary" class="no-border confirm-btn" @click="createOrder">结算</button> </view> </view> </view> </template> <script> // #ifdef H5 import weixinObj from '@/plugin/jweixin-module/index.js'; // #endif import { getCartList, getCartNum, cartDel } from '@/api/user.js'; import { mapState } from 'vuex'; import uniNumberBox from '@/components/uni-number-box.vue'; import { saveUrl, interceptor } from '@/utils/loginUtils.js'; // #ifdef H5 import { shareLoad } from '@/utils/wxAuthorized'; // #endif export default { components: { uniNumberBox }, data() { return { current: 3, total: 0, //总价格 allChecked: false, //全选状态 true|false empty: false, //空白页现实 true|false cartList: [] }; }, onShow() { // 只有登录时才加载数据 if (this.hasLogin) { this.loadData(); } // #ifdef H5 weixinObj.hideAllNonBaseMenuItem(); shareLoad() // #endif }, watch: { //显示空白页 cartList(e) { let empty = e.length === 0 ? true : false; if (this.empty !== empty) { this.empty = empty; } } }, computed: { ...mapState('user', ['hasLogin']) }, methods: { reduce(item, index) { if (item.cart_num == 1) { uni.showModal({ content: '删除该商品?', success: e => { if (e.confirm) { this.deleteCartItem(index); } } }); } else { item.cart_num--; this.newNumberChange(item); } }, add(item) { console.log(item); if (item.productInfo.stock > item.cart_num) { item.cart_num++; this.newNumberChange(item); } else { return; } }, //请求数据 async loadData() { let obj = this; getCartList({}) .then(function(e) { // 获取当前购物车物品增加数量 let nub = obj.cartList.length; // 获取之前对象数组 let aArray = obj.cartList.reverse(); // 获取返回数据对象数组 let bArray = e.data.valid.reverse(); obj.cartList = bArray .map((item, ind) => { // 设置返回数据默认为勾选状态 item.checked = true; // 获取相同数组之前对象的数据 let carlist = aArray[ind]; // 判断之前是否已经加载完毕 if (carlist && carlist.loaded == 'loaded') { item.loaded = 'loaded'; } return item; }) .reverse(); obj.calcTotal(); //计算总价 }) .catch(function(e) { console.log(e); }); }, //监听image加载完成 onImageLoad(key, index) { // 修改载入完成后图片class样式 this.$set(this[key][index], 'loaded', 'loaded'); }, //监听image加载失败 onImageError(key, index) { this[key][index].image = '/static/error/errorImage.jpg'; }, // 跳转到登录页 navToLogin() { // 保存地址 saveUrl(); // 登录拦截 interceptor(); }, //选中状态处理 check(type, index) { if (type === 'item') { this.cartList[index].checked = !this.cartList[index].checked; } else { const checked = !this.allChecked; const list = this.cartList; list.forEach(item => { item.checked = checked; }); this.allChecked = checked; } this.calcTotal(type); }, //数量 numberChange(data) { let arr = this.cartList[data.index]; arr.cart_num = data.number; getCartNum({ id: arr.id, number: data.number }) .then(e => { console.log(e); }) .catch(function(e) { console.log(e); }); this.calcTotal(); }, newNumberChange(item) { getCartNum({ id: item.id, number: item.cart_num }) .then(e => { console.log(e); }) .catch(function(e) { console.log(e); }); this.calcTotal(); }, //删除 deleteCartItem(index) { let list = this.cartList; let row = list[index]; let id = row.id; cartDel({ ids: id }); this.cartList.splice(index, 1); uni.hideLoading(); this.calcTotal(); }, //清空 clearCart() { uni.showModal({ content: '清空购物车?', success: e => { if (e.confirm) { let st = this.cartList.map(e => { return e.id; }); cartDel({ ids: st.join(',') }).then(e => { console.log(e); }); this.cartList = []; } } }); }, //计算总价 calcTotal() { let list = this.cartList; if (list.length === 0) { this.empty = true; return; } let total = 0; let checked = true; list.forEach(item => { if (item.checked === true) { total += item.truePrice * item.cart_num; } else if (checked === true) { checked = false; } }); this.allChecked = checked; this.total = Number(total.toFixed(2)); }, //创建订单 createOrder() { let list = this.cartList; let goodsData = []; list.forEach(item => { if (item.checked) { goodsData.push(item.id); } }); uni.navigateTo({ url: '/pages/order/createOrder?id=' + goodsData.join(',') }); } } }; </script> <style lang="scss"> .container { padding-bottom: 134rpx; background-color: $page-color-base; /* 空白页 */ .empty { position: fixed; left: 0; top: 0; width: 100%; height: 100vh; padding-bottom: 100rpx; display: flex; justify-content: center; flex-direction: column; align-items: center; background: #fff; .emptyImg { width: 300rpx; height: 250rpx; margin-bottom: 30rpx; } .empty-tips { display: flex; font-size: $font-sm + 2rpx; color: $font-color-disabled; .navigator { color: $base-color; margin-left: 16rpx; } } } } /* 购物车列表项 */ .cart-item { width: 710rpx; height: 210rpx; background: #ffffff; box-shadow: 0px 0px 10rpx 0rpx rgba(0, 0, 0, 0.1); border-radius: 10rpx; margin: 20rpx auto; display: flex; position: relative; padding: 30rpx 26rpx 30rpx 80rpx; .image-wrapper { width: 150rpx; height: 150rpx; flex-shrink: 0; position: relative; image { border-radius: 8rpx; } } .checkbox { position: absolute; top: 0; bottom: 0; left: -65rpx; margin: auto 0; height: 50rpx; z-index: 8; font-size: 44rpx; line-height: 1; padding: 4rpx; color: $font-color-disabled; background: #fff; border-radius: 50px; } .item-right { display: flex; flex-direction: column; flex: 1; overflow: hidden; position: relative; padding-left: 30rpx; .munbox { width: 144rpx; height: 44rpx; position: absolute; bottom: 0; right: 0; input { display: inline-block; text-align: center; } image { flex-shrink: 0; width: 44rpx; height: 44rpx; } } .title, .price { font-size: $font-base + 2rpx; color: $font-color-dark; height: 40rpx; line-height: 40rpx; } .attr { font-size: $font-sm + 2rpx; color: $font-color-light; height: 50rpx; line-height: 50rpx; font-size: 26rpx; font-family: PingFang SC; font-weight: bold; color: #999999; } .price { // height: 50rpx; // line-height: 50rpx; padding-top: 20rpx; font-size: 34rpx; font-family: PingFang SC; font-weight: bold; color: $base-color; } .step { margin-top: 20rpx; } .title { font-size: 34rpx; font-family: PingFang SC; font-weight: bold; color: #333333; } } .del-btn { padding: 4rpx 10rpx; font-size: 34rpx; height: 50rpx; color: $font-color-light; } } /* 底部栏 */ .action-section { /* #ifdef H5 */ margin-bottom: 100rpx; /* #endif */ position: fixed; left: 30rpx; bottom: 30rpx; z-index: 95; display: flex; align-items: center; width: 690rpx; height: 100rpx; padding: 0 30rpx; background: rgba(255, 255, 255, 0.9); box-shadow: 0 0 20rpx 0 rgba(0, 0, 0, 0.5); border-radius: 16rpx; .checkbox { height: 52rpx; position: relative; .icon-checked-box { border-radius: 50rpx; background-color: #ffffff; width: 52rpx; height: 100%; position: relative; z-index: 5; font-size: 53rpx; line-height: 1; color: $font-color-light; } .icon-checked { color: $base-color; } } .clear-btn { position: absolute; left: 26rpx; top: 0; z-index: 4; width: 0; height: 52rpx; line-height: 52rpx; padding-left: 38rpx; font-size: $font-base; color: #fff; background: $font-color-disabled; border-radius: 0 50px 50px 0; opacity: 0; transition: 0.2s; &.show { opacity: 1; width: 120rpx; } } .total-box { flex: 1; display: flex; flex-direction: column; text-align: right; padding-right: 40rpx; .price { font-size: $font-lg; color: $font-color-dark; } .coupon { font-size: $font-sm; color: $font-color-light; text { color: $font-color-dark; } } } .confirm-btn { padding: 0 38rpx; margin: 0; border-radius: 100px; height: 76rpx; line-height: 76rpx; font-size: $font-base + 2rpx; background: $base-color; color: #fff; } } /* 复选框选中状态 */ .action-section .checkbox.checked, .cart-item .checkbox.checked { color: $base-color; } .cart-hand { width: 750rpx; height: 88rpx; background: #ffffff; font-size: 30rpx; font-family: PingFang SC; font-weight: bold; color: #333333; line-height: 88rpx; padding-left: 28rpx; padding-right: 26rpx; .hand-tit { text { color: $base-color; } } .hand-btn { width: 164rpx; height: 62rpx; border: 2rpx solid $base-color; border-radius: 31rpx; font-size: 26rpx; font-family: PingFang SC; font-weight: bold; color: $base-color; line-height: 62rpx; text-align: center; } } </style>