luban-mall/components/shopping-carts/cart-slide.vue

602 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view>
<view class="cart-admin" v-if="listData.length>0" @tap="showDel=!showDel"><text>购物车信息</text>{{showDel?'取消':'管理'}}</view>
<view class="slide-list">
<view class="slide-item" v-for="(item, index) in listData" :key="index">
<view class="slide-item-li" @click="clickItemMethod(item)">
<label class="radio"><radio :checked="item.ifcheck" @tap.stop="chooseEv(index)" color="#0073bc"/></label>
<view class="shop-img " @tap="goDetail(item.spuId,item.is_series)">
<image :src="item.image" mode="widthFix"></image>
</view>
<view class="shop-txt">
<view class="shop-txt-top">
<view class="title clips2">{{item.title}}</view>
<view class="specs clips2">规格{{item.customTitle==''?item.skuName:item.customTitle}}</view>
</view>
<view class="shop-txt-bottom">
<!-- 商品价格 -->
<view class="price">{{vipPrice?item.price:item.original_price}}</view>
<!-- 商品数量 -->
<view class="num">
<!-- 减数量 -->
<i class="icon icon-cut count-btn" @tap.stop="addCutEv(index,0)" :style="{backgroundColor: item.num==minNum || item.slide_x!=0 ? '#d3d3d3' : '#0073bc'}"></i>
<!-- 实际数量 -->
<input class="input" type="digit" @blur="blurEv(index,$event)" @focus="focusEv(item.num)" :disabled="item.slide_x!=0" v-model="item.num">
<!-- -->
<i class="icon icon-add count-btn" @tap.stop="addCutEv(index,1)" :style="{backgroundColor: item.num==maxNum || item.slide_x!=0 ? '#d3d3d3' : '#0073bc'}"></i>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 全选 -->
<view class="change-all">
<label class="label" @tap="chooseAll"><radio :checked="allChoose" color="#0073bc" style="transform: scale(.8);margin-left: -6rpx;"/><text>全选</text></label>
<view class="all-price" v-if="showDel">
<view class="btn" style="background-color: #f83030;" @tap="delShopEv"></view>
</view>
<view class="all-price" v-else>
<view class="price">合计<span>{{allPrice}}</span></view>
<view class="btn" :style="{background: !buyNum ? '#cccccc' : '#0073bc'}" @tap="submitEv">{{allPrice==0 ? '' : ` (${buyNum})`}}</view>
</view>
</view>
<view v-if="listData.length!=0 && total==listData.length"><pitera textStr="—— 到底啦 ——"></pitera></view>
<nothing-page v-if="!ifLoading && !listData.length" content="您的购物车,空空如也(*^▽^*)"></nothing-page>
</view>
</template>
<script>
import { mapState,mapGetters,mapMutations } from 'vuex'//引入mapState
import pitera from '@/components/nothing/pitera';
import {getCartNum} from '@/jsFile/public-api.js';
export default {
components:{
pitera
},
name: 'cart-slide',
props: {
list: { //数据list
type: Array,
default () {
return [];
}
},
button: { //按钮数据list
type: Array,
default () {
return [
// {title: '分享',background: '#c4c7cd'},
{title: '删除',background: 'linear-gradient(to right,#ff3771 0%,#fd5549 100%)'}
];
}
},
customB:{
type:String,
default:'0'
},
skuId:{
type:String,
default:0
}
},
data() {
return {
listData: [],
start_slide_x: 0,
btnWidth: 0,
startX: 0,
LastX: 0,
startTime: 0,
itemIndex: 0,
originalNum:0,//当前输入框原值
maxNum:99999,//最大可输入数量
minNum:1,//最小可输入数量
ifLoading:true,
page:1,
size:10,
total:0,
vipPrice:false,// 是否显示会员价
showDel:false, //显示删除按钮
delIds:'', //删除ids
};
},
mounted() {
this.listData = this.list;
this.getList();
},
onShow() {
},
computed: {
windowWidth() {
return uni.getSystemInfoSync().windowWidth;
},
// 总价及合计
allPrice() {
let allPrice = 0;
this.listData.forEach(item=>{
if(item.ifcheck) {
if(this.vipPrice){
allPrice += item.price*item.num;
}else{
allPrice += item.original_price*item.num;
}
}
})
return this.$toolAll.tools.addXiaoShu(allPrice);
// return allPrice;
},
// 要删除的数量
buyNum() {
let buyNum = 0;
this.listData.forEach(item=>{
if(item.ifcheck) {
buyNum += 1;
}
})
return buyNum;
},
// 全选
allChoose() {
let ifAll = false;
if(this.listData.length) {
let temparr = this.listData.filter(item=>{return item.ifcheck==false})
temparr.length==0 ? ifAll = true : ifAll = false;
let delTemparr = this.listData.filter(item=>{return item.ifcheck==true})
let delArr = [];
delTemparr.forEach(item=>{
delArr.push(item.id)
})
// 删除购物车
this.delIds = delArr.join(',');
}
return ifAll
},
...mapState({
footHeight: state => state.moduleA.footHeight,
}),
},
methods: {
getList(){
uni.showLoading();
this.total = 0;
let params = {
page:this.page,
size:this.size
}
this.$requst.post('/api/order/shopping-cart',params).then(res=>{
if(res.code==0){
if(uni.getStorageSync('business_code')!==''){
this.vipPrice = true;
}
this.total = res.data.total;
console.log(res,'购物车列表')
if(this.page==1) this.listData = [];
if(res.data.list.length){
res.data.list.forEach(item=>{
let obj = {
id: item.id,
spuId:item.spu.id,
skuId:item.sku_id,
coding:item.sku.coding,
image: item.spu.spu_cover,
title: item.spu.spu_name,
content: item.spu.unit,
customTitle: item.sku.custom_title,
skuName: item.sku.sku_name,
is_series:item.spu.is_series,
slide_x: 0,
price:item.sku.sku_price,
original_price: item.sku.sku_original_price,
num:item.num,
ifcheck:this.skuId==item.sku_id ? true : false,
ifExit:true,
ifShow:true,
}
this.listData.push(obj);
console.log(this.listData);
})
}
}
this.ifLoading = false;
uni.hideLoading();
})
// for (let i = 0; i < 10; i++) {
// this.listData.push({id: 1,image: 'https://s6.jpg.cm/2022/02/14/L4oDhy.jpg',title: '标题',content: '描述描述描述描述描述描述',slide_x: 0,price:199,num:1,ifcheck:false,ifExit:true,ifShow:true})
// }
},
// 选中事件
chooseEv(index) {
this.listData[index].ifcheck = !this.listData[index].ifcheck;
},
// 全选事件
chooseAll(){
let exit = this.listData.filter(item=>item.ifcheck==false);
if(exit.length){
this.listData.forEach(item=>item.ifcheck = true);
} else {
this.listData.forEach(item=>{item.ifcheck = false});
}
},
// 去购物、去结算、删除
submitEv(){
if(this.allPrice==0) {
// 去购物
uni.reLaunch({
url:`/pages/tabbar/cate/cate`
})
} else {
// 去结算
let buyList = [];
this.listData.forEach(item=>{
if(item.ifcheck) {
let obj = {
sku_coding: item.coding,
num: item.num
}
buyList.push(obj);
}
})
uni.setStorageSync('buyList',buyList);
uni.navigateTo({
url:'/pagesA/cart/settlement'
})
}
},
// 数量加减事件
addCutEv(index,num) {
if(this.listData[index].slide_x==0){
if(num) {
// 加 ,如果当前商品数量不等于最大值
if(this.listData[index].num != this.maxNum) {
this.listData[index].num++;
}
} else {
// 减 ,如果当前商品数量大于最小值
if(this.listData[index].num > this.minNum) {
this.listData[index].num--;
}
}
this.$requst.post('/api/order/shopping-cart-change-num',{id:this.listData[index].id,num:this.listData[index].num}).then(res=>{
if(res.code!=0){
this.$toolAll.tools.showToast(res.msg);
}
})
}
},
// 删除商品
delShopEv(){
if(this.delIds!==''){
uni.showModal({
title: '提示',
content: '是否删除选中商品?',
success: (res)=> {
if (res.confirm) {
// 确认删除
this.confirmDel();
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
}
},
// 确认删除
confirmDel(){
this.$requst.post('/api/order/shopping-cart-del',{id:this.delIds.toString()}).then(res=>{
if(res.code==0){
this.$toolAll.tools.showToast('删除成功');
this.getList();
}else{
this.$toolAll.tools.showToast(res.msg)
}
})
},
// 查看商品详情
goDetail(id,type) {
if(type == 0){
uni.navigateTo({
url:`/pagesA/shop/detail?id=${id}&source=shop`
})
}
if(type == 1){
uni.navigateTo({
url:`/pages/tabbar/kit/detail?id=${id}`
})
}
},
// 输入框获取焦点事件
focusEv(num) {
// 储存当前商品的原始数值
this.originalNum = num;
},
// 输入框失去焦点事件
blurEv(index,e) {
// 失去焦点时,获取当前输入框里的数值
let currentNum = e.detail.value*1;
// 如果当前输入框的值不等于0或空并且当前输入框的值大于最大值当前商品的数量 = 最大值, 否则为当前输入框输入的值
this.listData[index].num = currentNum ? currentNum > this.maxNum ? this.maxNum : currentNum : this.originalNum;
},
clone(data) {
const type = typeof data
let obj;
if (type === 'array') {
obj = [];
} else if (type === 'object') {
obj = {};
} else {
// 不再具有下一层次
return data;
}
if (type === 'array') {
for (let i = 0, len = data.length; i < len; i++) {
obj.push(this.clone(data[i]));
}
} else if (type === 'object') {
// 对原型上的方法也拷贝了....
for (const key in data) {
obj[key] = this.clone(data[key]);
}
}
return obj;
},
// 滑动开始
touchStart(e, index) {
if (this.itemIndex == index) {
this.itemIndex = index
}
//记录手指放上去的时间
this.startTime = e.timeStamp;
//记录滑块的初始位置
this.start_slide_x = this.listData[index].slide_x;
// 按钮宽度
//#ifdef MP-WEIXIN
uni.createSelectorQuery().in(this).selectAll('.group-btn').boundingClientRect(res => {
if (res != null) {
this.btnWidth = res[index].width * -1;
}
}).exec();
//#endif
//#ifdef H5 || APP-PLUS
uni.createSelectorQuery()
.selectAll('.group-btn')
.boundingClientRect()
.exec(res => {
if (res[0] != null) {
this.btnWidth = res[0][index].width * -1;
}
});
//#endif
// 记录上一次开始时手指所处位置
this.startX = e.touches[0].pageX;
// 记录上一次手指位置
this.lastX = this.startX;
//初始化非当前滑动消息列的位置
for (var i in this.listData) {
if (index != i) {
this.listData[i].slide_x = 0;
}
}
},
// 滑动中
touchMove(e, index) {
const endX = e.touches[0].pageX;
const distance = endX - this.lastX;
// 预测滑块所处位置
const duang = this.listData[index].slide_x + distance;
// 如果在可行区域内
if (duang <= 0 && duang >= this.btnWidth) {
this.listData[index].slide_x = duang;
}
// 此处手指所处位置将成为下次手指移动时的上一次位置
this.lastX = endX;
},
// 滑动结束
touchEnd(e, index) {
let distance = 10;
const endTime = e.timeStamp;
const x_end_distance = this.startX - this.lastX;
if (Math.abs(endTime - this.startTime) > 200) {
distance = this.btnWidth / -2;
}
// 判断手指最终位置与手指开始位置的位置差距
if (x_end_distance > distance) {
this.listData[index].slide_x = this.btnWidth;
} else if (x_end_distance < distance * -1) {
this.listData[index].slide_x = 0;
} else {
this.listData[index].slide_x = this.start_slide_x;
}
},
// 点击回复原状
recover(index) {
this.listData[index].slide_x = 0;
},
/**
* 点击按钮触发事件
* @param {Object} item 列表数据
* @param {Object} buttonItem 按钮数据
* @param {Object} index 列表数据key
*/
clickMethod(item, buttonItem, index,key) {
// this.$emit("change", item, buttonItem, index);
// if(key) {
// 进入删除
// 修改为不存在的商品
this.$requst.post('/api/order/shopping-cart-del',{id:this.listData[index].id}).then(res=>{
if(res.code==0){
this.listData[index].ifExit = false;
// 修改该商品不被选中
this.listData[index].ifcheck = false;
setTimeout(()=>{
// 隐藏该商品
this.listData[index].ifShow = false;
},1000)
setTimeout(()=>{
// 重构数组列表,去除不存在的商品
this.listData = this.listData.filter(item=>item.ifExit==true);
},1000)
getCartNum();
}
})
// }
},
/**
* 点击按钮触发事件
* @param {Object} item 列表数据
*/
clickItemMethod(item) {
this.$emit("click", item)
}
}
};
</script>
<style scoped>
.cart-admin{
box-sizing: border-box;
display: flex;
justify-content: space-between;
padding: 20rpx 30rpx;
font-size: 30rpx;
background-color: #FFFFFF;
border-bottom: 2rpx solid #eaeaea;
margin-top: 20rpx;
color: #666666;
}
.cart-admin>text{
color: #000000;
}
.slide-item{
margin-top: 30rpx;
}
.slide-list .slide-item:first-child{
margin-top: 0;
}
.slide-item-li{
box-sizing: border-box;
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background-color: #FFFFFF;
}
.slide-item-li .radio>radio{
transform: scale(.8);
margin-left: -6rpx;
}
.slide-item-li .shop-img{
width: 230rpx;
height: 150rpx;
border-radius: 10rpx;
margin: 0 24rpx 0 6rpx;
overflow: hidden;
}
.slide-item-li .shop-img image{
width: 230rpx;
min-height: 150rpx;
}
.slide-item-li .shop-txt{
width: calc(100% - 300rpx);
}
.shop-txt-top{
min-height: 100rpx;
}
.shop-txt-top .title{
font-size: 30rpx;
line-height: 1.5;
color: #000000;
font-weight: bold;
}
.shop-txt-top .specs{
font-size: 24rpx;
line-height: 1.5;
color: #8c8c9b;
margin: 3rpx;
}
.shop-txt-bottom{
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 50rpx;
}
.shop-txt-bottom .price{
font-size: 30rpx;
line-height: 1.5;
color: #f81c1c;
}
.shop-txt-bottom .num{
display: flex;
justify-content: space-between;
align-items: center;
width: 170rpx;
font-size: 24rpx;
}
.shop-txt-bottom .num>.count-btn{
display: flex;
justify-content: center;
align-items: center;
font-size: 24rpx;
width: 40rpx;
height: 40rpx;
background-color: #000000;
color: #FFFFFF;
border-radius: 10rpx;
}
.shop-txt-bottom .num>.input{
box-sizing: border-box;
width: 78rpx;
height: 40rpx;
border: 2rpx solid #d3d3d3;
border-radius: 10rpx;
text-align: center;
}
.change-all{
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
width: 100vw;
height: 130rpx;
padding: 0 30rpx;
position: fixed;
left: 0;
bottom: 0;
background-color: #FFFFFF;
}
.change-all .label{
display: flex;
align-items: center;
font-size: 24rpx;
}
.all-price{
display: flex;
align-items: center;
}
.all-price .price{
font-size: 24rpx;
margin-right: 25rpx;
color: #000000;
}
.all-price .btn{
line-height: 84rpx;
padding: 0 30rpx;
border-radius: 10rpx;
font-size: 32rpx;
color: #FFFFFF;
}
</style>