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
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>
|