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

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