You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

436 lines
11 KiB

<template>
<view class="app">
<mescroll-body
ref="mescrollRef"
@init="mescrollInit"
:top="0"
@down="downCallback"
:up="upOption"
@up="loadList"
>
<!-- 列表 -->
<uni-swipe-action>
<uni-swipe-action-item v-for="(item, index) in list" :key="item._id" :options="options" @click="remove($event,index)" >
<view class="item row">
<text class="mix-icon icon-xuanzhong" :class="{active: item.checked}" @click.stop.prevent="checkRow(item)"></text>
<view class="image-wrapper lazyload lazypic" :class="{loaded: item.loaded}" @click="navTo('/pages/product/detail?id='+item.product_id)">
<image :src="item.image" mode="aspectFill" lazy-load="true" @load="imageOnLoad(item)" ></image>
</view>
<view class="right column">
<text class="title clamp">{{item.title}}</text>
<text class="sku">{{item.sku.name}}</text>
<text class="price">¥{{item.price || ''}}</text>
<view class="number-box" @click.stop.prevent="stopPrevent">
<mix-number-box :min="1" :max="item.stock" :value="item.number" :isMax="item.number >= item.stock" :isMin="item.number === 1" :index="index" @eventChange="onNumberChange" ></mix-number-box>
</view>
</view>
</view>
</uni-swipe-action-item>
</uni-swipe-action>
<!-- 失效商品 -->
<view v-if="invalidList.length > 0" class="invalid">
<view class="invalid-header row" style=" height: 72rpx; padding: 0 24rpx 0 22rpx; font-size: 24rpx; color: #333; background-color: #f5f5f5; ">
<text class="mix-icon icon-tishi"></text>
<text class="fill">商品调整、库存不足等原因会导致商品失效</text>
<view class="btn center" @click="clearInvalid">
<text class="mix-icon icon-lajitong"></text>
<text>清除</text>
</view>
</view>
<view v-for="(item, index) in invalidList" :key="item._id" class="item row">
<text class="mix-icon icon-xuanzhong"></text>
<view class="image-wrapper lazyload lazypic" :class="{loaded: item.loaded}">
<image :src="item.image" mode="aspectFill" lazy-load="true" @load="imageOnLoad(item)" ></image>
</view>
<view class="right column">
<text class="title clamp">{{item.title}}</text>
<text class="sku">{{item.sku.name}}</text>
<view class="row">
<text class="price fill">¥{{item.price || ''}}</text>
<view class="tag">失效</view>
</view>
</view>
</view>
</view>
<!-- 底部栏 -->
<view class="bot-fill-view"></view>
</mescroll-body>
<view v-if="loaded && (list.length > 0 || invalidList.length > 0)" class="bottom row">
<text class="mix-icon icon-xuanzhong" :class="{active: allChecked}" @click="checkAll"></text>
<text v-if="!allChecked" class="check-tip">全选</text>
<view class="del-btn center" :class="{active: allChecked}" @click="showPopup('mixModal')">
<text>清空</text>
</view>
<text class="price fill">¥{{ totalPrice | price(2) }}</text>
<view class="btn center" @click="createOrder">
<text>去结算{{ confirmNumber > 0 ? '(' + confirmNumber + ')' : '' }}</text>
</view>
</view>
<!-- 缺省 -->
<mix-empty v-else-if="loaded" type="cart"></mix-empty>
<!-- 加载 -->
<mix-loading v-if="isLoading" :type="loaded ? 1 : 2" :mask="true"></mix-loading>
<!-- 确认对话框 -->
<mix-modal ref="mixModal" title="删除提示" text="挑了这么久,真的要狠心清空吗" confirmText="清空" @onConfirm="clear"></mix-modal>
</view>
</template>
<script>
import tabbarMixin from './mixin/tabbar'
import MescrollMixin from "@/components/mescroll-uni/mescroll-mixins.js";
export default {
mixins: [tabbarMixin, MescrollMixin],
data() {
return {
options: [{
text: '删除',
style: {
backgroundColor: '#ff536f'
}
}],
upOption:{
auto: false, // 是否自动加载
page: {
num: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始
size: 15 // 每页数据的数量
},
empty: {
onShow: false,
},
noMoreSize: 50,
},
list: [],
invalidList: [],
totalPrice: 0,
}
},
computed: {
allChecked(){
return this.list.length > 0 && this.list.every(item=> item.checked);
},
confirmNumber(){
return this.list.filter(item=> item.checked).length;
},
},
watch: {
list(){
this.calcTotalPrice();
}
},
onLoad() {
uni.$on('refreshCart', ()=>{
this.list = [];
this.invalidList = [];
this.mescroll.resetUpScroll(false)
})
},
onShow() {
this.mescroll && this.mescroll.resetUpScroll(false)
},
methods: {
async loadList(type){
const res = await this.$request('cart', 'get');
const list = res.map(item=> {
return {
loaded: this.loaded,
...item
}
})
this.list = list.filter(item=> item.invalid === false);
this.invalidList = list.filter(item=> item.invalid);
this.mescroll.endSuccess(list.length); //结束加载状态
},
mescrollInit(mescroll){
this.isLoading = true;
this.mescroll = mescroll;
this.mescroll.resetUpScroll(false)
},
//去结算 创建订单
createOrder(){
const ids = this.list.filter(item=> item.checked).map(item=> item._id);
if(ids.length === 0){
this.$util.msg('请选择结算商品');
return;
}
this.navTo('/pages/order/createOrder?type=cart&ids='+ids);
},
//数量修改
onNumberChange(e){
this.$util.debounce(async ()=>{
const res = await this.$request('cart', 'updateNumber', {
id: this.list[e.index]._id,
number: e.number
})
if(res.status == 1){
this.list[e.index].number = e.number
this.calcTotalPrice();
}else{
this.$util.msg('数量更新失败');
}
}, 500)
},
//单选
checkRow(item){
if(this.chenageChecked([item._id], !item.checked)){
item.checked = !item.checked;
this.calcTotalPrice();
}
},
//全选
checkAll(){
const ids = this.list.map(item=> item._id);
const allChecked = !this.allChecked;
if(this.chenageChecked(ids, allChecked)){
this.list.forEach(item=> {
item.checked = allChecked;
})
this.calcTotalPrice();
}
},
//修改选中状态
async chenageChecked(ids, checked){
this.$request('cart', 'updateCheck', {
ids,
checked
}, {showLoading: true}).then(res=>{
if(res.status === 1){
return true;
}else{
this.$util.msg('修改失败');
return false;
}
})
},
//删除
remove(e, index){
this.$util.throttle(async ()=>{
const res = await this.$request('cart', 'remove', {
ids: [this.list[index]._id]
}, {
showLoading: true
})
this.$util.msg(res.msg);
if(res.status === 1){
this.list.splice(index, 1);
this.$store.dispatch('getCartCount');//更新数量
}
})
},
//清空失效
clearInvalid(){
this.$util.throttle(async ()=>{
const res = await this.$request('cart', 'remove', {
ids: this.invalidList.map(item=> item._id)
}, {
showLoading: true
})
this.$util.msg(res.msg);
if(res.status === 1){
this.invalidList = [];
this.$store.dispatch('getCartCount');//更新数量
}
})
},
//清空商品
clear(){
this.$util.throttle(async ()=>{
const res = await this.$request('cart', 'removeAll', {}, {
showLoading: true
})
this.$util.msg(res.msg);
if(res.status === 1){
this.list = [];
this.$store.dispatch('getCartCount');//更新数量
}
})
},
//计算总价
calcTotalPrice(){
const checkedList = this.list.filter(item=> item.checked);
let total = 0;
checkedList.forEach(item=> {
console.log(item);
total += item.price * item.number
})
this.totalPrice = total;
}
}
}
</script>
<style scoped lang="scss">
.app{
/deep/ .uni-swipe{
padding: 24rpx 0;
}
}
.item{
width: 100%;
padding-right: 30rpx;
overflow: hidden;
.icon-xuanzhong{
padding: 60rpx 20rpx;
font-size: 36rpx;
color: #ddd;
&.active{
color: $base-color;
}
}
.image-wrapper{
flex-shrink: 0;
width: 170rpx;
height: 170rpx;
margin-right: 20rpx;
border-radius: 10rpx;
overflow: hidden;
image{
width: 100%;
height: 100%;
}
}
.right{
flex: 1;
overflow: hidden;
}
.title{
font-size: 30rpx;
line-height: 42rpx;
}
.sku{
min-height: 20rpx;
margin: 20rpx 0 28rpx;
font-size: 24rpx;
color: #999;
}
.price{
margin-bottom: 4rpx;
font-size: 30rpx;
color: #333;
}
.number-box{
position: absolute;
right: 0;
bottom: 0;
padding: 20rpx 30rpx 0;
}
/deep/{
.uni-numbox-minus, .uni-numbox-value, .uni-numbox-plus{
height: 48rpx;
}
}
}
.invalid{
.item{
padding: 24rpx 24rpx 24rpx 0;
opacity: 0.5;
}
.invalid-header{
height: 72rpx;
padding: 0 24rpx 0 22rpx;
font-size: 24rpx;
color: #333;
background-color: #f5f5f5;
}
.icon-tishi{
margin-right: 10rpx;
font-size: 32rpx;
color: $base-color;
}
.btn{
padding: 8rpx 16rpx;
font-size: 24rpx;
color: #666;
}
.icon-lajitong{
margin-right: 8rpx;
font-size: 32rpx;
}
.tag{
padding: 6rpx 18rpx;
font-size: 24rpx;
color: #fff;
border-radius: 100rpx;
background-color: #555;
}
}
.bot-fill-view{
width: 100%;
height: 110rpx;
box-sizing: content-box;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.bottom{
position: fixed;
left: 0;
bottom: var(--window-bottom);
z-index: 90;
width: 100%;
height: 100rpx;
background-color: #fff;
box-shadow: 0 -2rpx 10rpx 0 rgba(0,0,0,.06);
box-sizing: content-box;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.icon-xuanzhong{
margin-left: 20rpx;
font-size: 48rpx;
color: #ddd;
position: relative;
z-index: 10;
background-color: #fff;
border-radius: 100rpx;
&.active{
color: $base-color;
}
}
.check-tip{
position: absolute;
left: 80rpx;
font-size: 28rpx;
color: #333;
}
.del-btn{
width: 0rpx;
height: 44rpx;
padding-left: 14rpx;
font-size: 28rpx;
color: #fff;
background-color: #C0C4CC;
border-radius: 0 100rpx 100rpx 0;
position: relative;
left: -24rpx;
transition: width .2s;
&.active{
width: 110rpx;
}
}
.price{
margin-right: 30rpx;
font-size: 34rpx;
color: $base-color;
font-weight: 700;
text-align: right;
}
.btn{
min-width: 180rpx;
height: 70rpx;
padding: 0 26rpx;
margin-right: 20rpx;
border-radius: 100rpx;
background-color: $base-color;
font-size: 30rpx;
color: #fff;
}
}
</style>