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.

917 lines
25 KiB

3 weeks ago
<template>
<view class="page">
<view class="page-header" :style="{ paddingTop: geStatusBarHeight() + 'px'}">
<view :class="['title', carts.length > 0 ? '' : 'text-center']">购物车</view>
<block v-if="carts.length > 0">
<view class="edit" v-if="btnType === 'edit'" @click="$u.throttle(btnTool('edit'), 2000)"></view>
<view class="edit" v-if="btnType === 'done'" @click="$u.throttle(btnTool('done'), 2000)"></view>
</block>
</view>
<view class="cart-top"></view>
<!-- 购物车商品 -->
<view class="cart-list" v-if="cartnum > 0" v-for="(cell,ii) in carts" :key="ii+'shop'">
<view class="cart-shop">
<u-checkbox @change="checkedcell(ii)" v-model="cell.check" size="40" shape="circle" active-color="#89965f" class="checkall"></u-checkbox>
<view class="cart-shop-name">
{{cell.storeName}}
</view>
</view>
<view class="cart-box">
<u-swipe-action
v-for="(item, index) in cell.cartList"
:index="index"
:show="item.show"
:disabled="swipeAction"
:key="item.productId+'-'+index"
@click="$u.throttle(actionClick($event,ii), 2000)"
@open="actionOpen(index,ii)"
:options="options"
v-if="item.status==1"
btn-width="160"
>
<view class="item u-border-bottom">
<u-checkbox-group @change="checkboxChange(index,ii)" width="40rpx">
<u-checkbox v-model="item.check" size="40" shape="circle" active-color="#89965f" class="checkbox"></u-checkbox>
</u-checkbox-group>
<view class="cart-img">
<image class="cimg" mode="widthFix" :src="getimgRemoteFile(item.pic)" @click.stop="$u.throttle(gotoDetail(item.productId), 2000)"></image>
</view>
<view class="title-wrap" @click.stop="$u.throttle(gotoDetail(item.productId), 2000)">
<view class="title u-line-1 ">{{ item.productName }}</view>
<view class="sku">{{ retSku(item.spData) }}</view>
<view class="price">
<text style="color: #ed2a28;">¥</text>
<text class="large">{{ item.price }}</text>
{{ item.unit?' /'+item.unit:'' }}
</view>
</view>
<view class="u-numberbox">
<uni-number-box :width="50" :min="1" :max="item.stock" v-model="item.quantity" @change="valChange($event,item,index,ii)" @click.native.stop="tostop" />
</view>
</view>
</u-swipe-action>
</view>
</view>
<!-- 购物车时效商品 -->
<view class="cart-lose-con bg-white" v-if="loseNum>0">
<view class="cart-lose">
<view class="cart-lose-left">{{loseNum}}件失效商品</view>
<view class="cart-lose-btn" @click="losedel"></view>
</view>
<block v-for="(cell,ii) in carts" :key="ii+'lose'">
<view class="lose-item" v-for="(item,jj) in cell.cartList" :key="jj+'losesp'" v-if="item.status==0">
<view class="cart-img">
<image class="cimg" mode="widthFix" :src="getimgRemoteFile(item.pic)"></image>
<view class="losetip">已失效</view>
</view>
<view class="title-wrap">
<view class="title u-line-1 ">{{ item.productName }}</view>
<view class="sku">{{ retSku(item.spData) }}</view>
<view class="price">
<text style="color: #ed2a28;">¥</text>
<text class="large">{{ item.price }}</text>
{{ item.unit?' /'+item.unit:'' }}
</view>
</view>
</view>
</block>
</view>
<view class="cart-bottom" v-if="carts.length>0"></view>
<view class="page-box" v-if="carts.length <= 0">
<view>
<view class="emputy">
<image src="../../static/image/empty.png"></image>
<view class="explain">
购物车为空
<view class="tips">赶紧慰劳一下自己吧</view>
</view>
<view class="btn" @click="$u.throttle(gotoHome, 2000)">随便逛逛</view>
</view>
</view>
</view>
<view class="bottom" v-if="carts.length > 0">
<u-checkbox @change="checkedAll" v-model="checked" size="40" shape="circle" active-color="#89965f" class="checkall"><span>全选</span></u-checkbox>
<text class="price fill" v-if="btnType === 'edit'">
<text class="sml">合计:</text>
{{ totalPrice }}
</text>
<u-button
throttle-time="2000"
v-if="btnType === 'edit'"
@click="$u.throttle(btnClick('order'), 2000)"
size="medium"
:ripple="true"
ripple-bg-color="#FEBABD"
shape="circle"
:customStyle="customStyle"
>
结算
<text v-if="totalCount > 0">{{ '(' + totalCount + ')' }}</text>
</u-button>
<u-button
throttle-time="2000"
v-if="btnType === 'done'"
size="medium"
:ripple="true"
ripple-bg-color="#ccc"
shape="circle"
:customStyle="customStyle2"
@click="$u.throttle(btnClick('del'), 2000)"
>
删除
</u-button>
</view>
<u-modal
v-model="showModal"
:title="title"
:content="content"
:title-style="titleStyle"
:content-style="contentStyle"
:confirm-style="confirmStyle"
:show-cancel-button="true"
@confirm="confirm"
></u-modal>
<u-toast ref="uToast" />
<!-- 是否登录 -->
<openlogin ref="loginId" @getPhoneNumber="getPhoneNumber"></openlogin>
</view>
</template>
<script>
import { myCache,getcartNum,getcartLoseNum,getRemoteFile } from '../../utils/utils.js';
import openlogin from "../components/openlogin.vue";
export default {
components: {
openlogin
},
data() {
return {
cartnum: getcartNum(),// 购物车数量
loseNum: getcartLoseNum(),// 购物车数量
loadStatus: 'loadmore',
carts: myCache("carts"), //购物车列表
showModal: false, //modal弹窗
title: '提示', //弹窗标题
content: '确认删除商品?', //弹窗内容
delId: '', //删除id,
options: [
{
text: '删除',
style: {
backgroundColor: '#ed2a28'
}
}
], //u-swipe-action样式
btnType: 'edit', //按钮类型
checked: false, //是否全选
swipeAction: false, //是否禁止滑动
// u-button样式
customStyle: {
color: '#fff',
backgroundColor: '#89965f',
margin: '0',
padding: '0 20rpx',
width: '200rpx',
fontSize: '32rpx'
},
customStyle2: {
color: '#333',
backgroundColor: 'rgba(0,0,0, 0)',
margin: '0',
padding: '0 20rpx',
border: 'none',
width: '200rpx',
fontSize: '32rpx'
},
// 模态窗样式
titleStyle: {
fontSize: '36rpx'
},
contentStyle: {
fontSize: '36rpx'
},
confirmStyle: {
color: '#000',
backgroundColor: '#fff'
}
};
},
mounted() {
if(this.userid==""||this.userid=="0"){
this.$refs.loginId.open();
}
},
onShow() {
console.log('onShow');
this.openId = myCache('openId');
var user = myCache('user');
this.userid = user.userid? user.userid:'';
this.phone = user.userphone;
this.checked = false;
this.getapicart();
},
computed: {
// 价格合计
totalPrice() {
let sumPrice = 0, items = this.carts;
items.forEach(cell => {
cell.cartList.forEach(val => {
let priceVal = parseFloat(val.price),
salesVal = parseFloat(val.quantity);
if (val.check&&val.status==1) {
sumPrice += priceVal * salesVal;
}
});
});
// sumPrice = sumPrice == 0 ? 0 : sumPrice.toFixed(2);
let tofixNum = sumPrice.toFixed(2);
return parseFloat(tofixNum);
},
// 数量统计
totalCount() {
let totalNumber = 0, items = this.carts;
items.forEach(cell => {
cell.cartList.forEach(val => {
if (val.check&&val.status==1) {
totalNumber += val.quantity;
}
});
});
return totalNumber;
},
},
methods: {
getPhoneNumber(e){
if(e.phone){
this.phone = e.phone
}
if(e.userid){
this.userid = e.userid
}
},
retSku(spData){
var sels=[];
if(spData){
var suk= JSON.parse(spData);
var keys=Object.keys(suk);
keys.forEach(dd=>{
sels.push(dd+":"+suk[dd])
});
}
return sels.join(',');
},
getimgRemoteFile(img){
if(img){
return img
// return getRemoteFile(img)
}
else{
return require("@/static/image/nopic.png")
}
},
// 购物车列表
async getapicart(){
try{
const {data: res } = await uni.$http.get('/api/cart/list');
if (res&&res.length>0) {
var carts=[];
res.forEach((cell,idx)=>{
cell["check"]=this.getcheck1(cell.storeNmae);
cell.cartList.forEach((ii,idx1)=>{
cell.cartList[idx1]["show"]=false; // 是否显示管理
cell.cartList[idx1]["check"]=this.getcheck2(ii.id);
if(!cell.cartList[idx1]["unit"]){
cell.cartList[idx1]["unit"]='个';
}
if(cell.cartList[idx1]["stock"]!==0&&!cell.cartList[idx1]["stock"]){
cell.cartList[idx1]["stock"]=10;
}
});
carts.push(cell)
});
this.carts=carts;
this.$forceUpdate();
myCache("carts",this.carts);
}
else{
this.carts=[];
this.$forceUpdate();
myCache("carts",this.carts);
}
console.log(this.carts)
}
catch(e){
// console.log(e);
this.carts=[];
this.$forceUpdate();
myCache("carts",this.carts);
}
this.cartnum=getcartNum();
if(this.cartnum>0){
// 底部菜单消息角标
uni.setTabBarBadge({
//显示未读消息条数
index: 4,
text: this.cartnum+''
});
}
else{
uni.removeTabBarBadge({
index: 4
})
}
this.loseNum=getcartLoseNum();
this.$forceUpdate();
},
getcheck1(id){
var fcarts=myCache("carts");
var ret = false;
fcarts.forEach((cell)=>{
if(id==cell.storeNmae){
ret=cell["check"];
return;
}
});
return ret;
},
getcheck2(id){
var fcarts=myCache("carts");
var ret = false;
fcarts.forEach((cell)=>{
cell.cartList.forEach((ii)=>{
if(ii.id==id){
ret=ii["check"];
return;
}
});
});
return ret;
},
gotoHome() {
uni.switchTab({
url: '/pages/product/list'
});
},
// 管理按钮
btnTool(type) {
switch (type) {
case 'edit':
this.btnType = 'done';
this.swipeAction = true;
let items = this.carts;
items.forEach(item => {
item.cartList.forEach(val => {
val.show = false;
});
});
break;
case 'done':
this.btnType = 'edit';
this.swipeAction = false;
break;
}
},
// 删除
actionClick(index, ii) {
// console.log(index, ii);
this.showModal = true;
var cartList=this.carts[ii].cartList;
this.delId = cartList[index]["id"];
// console.log(this.delId)
this.$forceUpdate();
},
// 删除确认
async confirm() {
let delArr = [],
type = this.btnType,
items = this.carts;
if (type === 'edit') {
delArr.push(this.delId);
} else {
items.forEach(item => {
item.cartList.forEach(val => {
if (val.check) {
delArr.push(val.id);
}
});
});
this.btnType = 'edit';
}
var param={
ids:delArr
};
const {data: res} = await uni.$http.delete('/api/cart/remove',param);
if (res) {
// 购物车缓存
this.$refs.uToast.show({
title: '商品已删除',
type: 'success',
duration: 2000
});
// 重新获取购物车
this.getapicart();
}
else{
this.$refs.uToast.show({
title: '商品删除失败!请重试!',
type: 'error',
duration: 2000
});
}
},
// 删除失效购物车商品
losedel(){
var ids=[];
this.carts.forEach(item=>{
item.cartList.forEach(cell=>{
if(cell.status == 0){
ids.push(cell.id);
}
})
})
if(ids.length>0){
var _this=this;
uni.showModal({
title: '提示',
content: '确定清空失效商品吗?',
cancelText: '我再想想',
confirmText: '删除',
success: ress => {
if (ress.confirm) {
_this.losedelDo(ids);
}
}
});
}
},
async losedelDo(ids){
var param={
ids:ids
};
const {data: res} = await uni.$http.delete('/api/cart/remove',param);
if (res) {
// 购物车无效商品清空
this.$refs.uToast.show({
title: '无效商品已清空',
type: 'success',
duration: 2000
});
this.$forceUpdate();
// 重新获取购物车
this.getapicart();
}
},
// 重新设置购物车
cartSetDo(type){
myCache("carts",this.carts);
// console.log(myCache("carts"))
if(type==1){
// 设置购物车数量
this.cartnum=getcartNum();
if(this.cartnum>0){
// 底部菜单消息角标
uni.setTabBarBadge({
//显示未读消息条数
index: 4,
text: this.cartnum+''
});
}
else{
uni.removeTabBarBadge({
index: 4
})
}
}
},
// 如果打开一个的时候,不需要关闭其他,则无需实现本方法
actionOpen(index,ii) {
// 先将正在被操作的swipeAction标记为打开状态否则由于props的特性限制
// 原本为'false',再次设置为'false'会无效
let items = this.carts[ii].cartList;
items[index].show = true;
items.forEach((val, idx) => {
if (index != idx) {
items[idx].show = false;
}
});
},
// 跳转详情
gotoDetail(id) {
// console.log(id);
uni.navigateTo({
url: '/pages/product/detail?id=' + id
})
},
tostop(e) {
e.stopPropagation(); // 阻止事件冒泡
},
// 数量增减
async valChange(e,item,index,ii) {
console.log("valChange")
console.log(e,item,index,ii);
var param={
id:item.id,
quantity:item.quantity
};
const {data: res} = await uni.$http.post('/api/cart/modify',param);
if (res) {
// 重新获取购物车
this.getapicart();
}
else{
this.$refs.uToast.show({
title: '数量修改失败!',
icon: false
});
}
},
// 选中商品
checkboxChange(index,ii) {
let items = this.carts;
let checkall = true;
items.forEach(cell => {
let childcheckall = true;
cell.cartList.forEach(val => {
if (!val.check) {
childcheckall=false;
}
});
cell["check"]=childcheckall;
if(!childcheckall){
checkall=false;
}
});
this.checked = checkall;
// 重新设置购物车
this.cartSetDo(0);
},
checkedcell(index) {
let checkall = true;
this.carts[index].check = !this.carts[index].check ;
let flag = this.carts[index].check,items = this.cartList;
this.carts[index].cartList.forEach(val => {
val.check=flag;
});
if(!this.carts[index].check){
checkall=false;
}
this.checked = checkall;
// 重新设置购物车
this.cartSetDo(0);
},
// 全选
checkedAll() {
this.checked = !this.checked;
let flag = this.checked,items = this.carts;
items.forEach(cell => {
cell["check"]=flag;
cell.cartList.forEach(val => {
val.check=flag;
})
});
// 重新设置购物车
this.cartSetDo(0);
},
// 结算
btnClick(type) {
let _self = this;
switch (type) {
case 'order':
let items = _self.carts;
let checkedArr = [];
items.forEach(item => {
item.cartList.forEach(val => {
if (val.check) {
checkedArr.push(val.id);
}
});
});
let goodIds = checkedArr.toString();
if (!goodIds) {
_self.$refs.uToast.show({
title: '请选择要结算的商品!',
icon: false
});
return;
}
console.log(goodIds);
uni.navigateTo({
url: '/pages/product/order?type=cart'
});
break;
case 'del':
if (!_self.totalCount) {
_self.$refs.uToast.show({
title: '请选择要删除的商品!',
icon: false
});
return;
}
_self.showModal = true;
break;
}
},
// 获取状态栏高度
geStatusBarHeight(){
return uni.getSystemInfoSync()['statusBarHeight'];
},
// 获取导航栏高度
getNavBarHeight(){
return 45+uni.getSystemInfoSync()['statusBarHeight'];
},
}
};
</script>
<style lang="scss" scoped>
.page {
padding: 0;
position: relative;
background-image: url('@/static/image/bg.jpg');
background-attachment: fixed;
background-size: cover;
background-position: center center;
min-height: calc(100vh - var(--window-top) - var(--window-bottom));
}
// 状态栏占位
.status_bar {
background-color: #89965f;
}
.page-header {
position: fixed;
width: 100%;
z-index: 99;
padding: 30rpx 30rpx;
display: flex;
color: #fff;
font-size: 36rpx;
background-color: #89965f;
align-items: center;
.text-center {
width: 100%;
text-align: center;
}
.edit {
position: absolute;
top: 30rpx;
transform: translateY(-50%);
right: 20rpx;
font-size: 32rpx;
}
}
.cart-bottom{
width: 100%;
height: 1rpx;
margin-bottom: 140rpx;
/* #ifdef H5 */
margin-bottom: calc( var(--window-bottom) + 40rpx);
/* #endif */
}
.cart-top{
width: 100%;
height: 1rpx;
margin-top: 166rpx;
/* #ifdef H5 */
margin-top: calc( var(--window-top) + 105rpx);
/* #endif */
}
.cart-list{
display: flex;
flex-direction: column;
}
.cart-lose-con{
margin-top: 20rpx;
display: flex;
flex-direction: column;
}
.cart-lose{
display: flex;
justify-content: space-between;
padding: 20rpx;
}
.cart-lose-left{
font-weight: 600;
font-size: 30rpx;
color: #333;
}
.cart-lose-btn{
font-size: 26rpx;
color: #89965f;
}
.cart-shop{
display: flex;
flex-direction: row;
padding: 20rpx;
background: #fff;
font-weight: 600;
font-size: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.cart-shop-name{
margin-left: 20rpx;
}
.cart-box{
}
.item {
display: flex;
justify-content: space-between;
padding: 20rpx;
align-items: center;
.cart-img {
width: 180rpx;
border-radius: 12rpx;
overflow: hidden;
.cimg {
width: 100%;
height: 100%;
}
}
.title-wrap {
width: 440rpx;
.sku {
margin: 20rpx 0;
font-size: 28rpx;
color: #666;
}
.price {
font-size: 32rpx;
color: #333;
.large {
margin-left: 6rpx;
font-size: 40rpx;
font-weight: bold;
color: #ed2a28;
}
}
.clamp {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
}
.title {
text-align: left;
font-size: 30rpx;
color: #333;
// margin-top: 20rpx;
line-height: 46rpx;
}
}
.u-numberbox {
position: absolute;
bottom: 20rpx;
right: 20rpx;
}
}
.lose-item {
display: flex;
justify-content: space-between;
padding: 20rpx;
align-items: center;
opacity: 0.5;
background-color: #f0f0f0;
.cart-img {
width: 180rpx;
height: 150rpx;
position: relative;
overflow: hidden;
.cimg {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.losetip{
position: absolute;
top:70rpx;
left: 30rpx;
height: 40rpx;
line-height: 40rpx;
width: 90rpx;
color: #fff;
font-size: 24rpx;
font-weight: 500;
background-color: #333;
opacity: 0.8;
text-align: center;
border-radius: 6rpx;
}
}
.title-wrap {
width: 440rpx;
.sku {
margin: 20rpx 0;
font-size: 28rpx;
color: #666;
}
.price {
font-size: 28rpx;
color: #333;
.large {
margin-left: 6rpx;
font-size: 40rpx;
font-weight: bold;
color: #ed2a28;
}
}
.clamp {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
}
.title {
text-align: left;
font-size: 26rpx;
color: #333;
// margin-top: 20rpx;
line-height: 36rpx;
}
}
.u-numberbox {
position: absolute;
bottom: 20rpx;
right: 20rpx;
}
}
.emputy {
display: flex;
flex-direction: column;
height: calc(100vh - var(--window-top) - var(--window-bottom) - 120rpx );
justify-content: center;
align-items: center;
text-align: center;
margin: 10rpx auto;
font-size: 32rpx;
image {
width: 200rpx;
height: 128rpx;
margin-bottom: 20rpx;
}
.tips {
font-size: 24rpx;
color: #999999;
margin-top: 20rpx;
}
.btn {
margin: 80rpx auto;
width: 200rpx;
border-radius: 32rpx;
line-height: 64rpx;
color: #ffffff;
font-size: 26rpx;
background: -webkit-linear-gradient(to right, rgba(137, 150, 95, 0.3) 0%, rgba(137, 150, 95, 1) 100%);
background: linear-gradient(to right, rgba(137, 150, 95, 0.3) 0%, rgba(137, 150, 95, 1) 100%);
}
}
.bottom {
padding: 0 20rpx;
width: 100%;
position: fixed;
left: 0;
bottom: var(--window-bottom);
display: flex;
align-items: center;
justify-content: flex-end;
z-index: 99;
height: 118rpx;
background-color: #fff;
box-sizing: border-box;
box-shadow: 0 0 10rpx 6rpx rgba(0, 0, 0, 0.1);
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.checkall {
position: absolute;
left: 20rpx;
top: 50%;
transform: translateY(-50%);
span {
color: #999;
font-size: 32rpx;
}
}
.price {
margin-right: 20rpx;
color: #ed2a28;
font-size: 40rpx;
.sml {
margin-right: 10rpx;
color: #666;
font-size: 30rpx;
}
}
}
</style>