TakeOutShop/pages/cart/cart.vue
2025-04-11 17:49:34 +08:00

503 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<page-meta :page-style="'overflow:'+(show?'hidden':'visible')"></page-meta>
<view class="main">
<!-- 头部区域 -->
<view class="head" :style="{'padding-top':headerHeight+'px'}" >
<view class="head_location" :class="storeName?'head_location_active':''" @click="location()"><text class="location_title">{{storeName||'正在获取定位'}}</text></view>
<view class="head_ul">
<view class="head_l">
<view class="head_q">购物车</view>
<view class="head_w">我常买</view>
</view>
<view class="head_r">
<view class="head_li" @click.stop="OpenCoupon()">优惠券(3</view>
<view class="head_li" :class="showEdit?'head_edit':''" @click.stop="edit">{{showEdit?'退出管理':'管理'}}</view>
</view>
</view>
</view>
<view class="cont">
<view class="head_fixed" :style="{'height':75+headerHeight+'px'}">下拉刷新...</view>
<view class="cart">
<view style="height: 10rpx;"></view>
<template v-if="cartList.length">
<uni-swipe-action>
<uni-swipe-action-item v-for="(item,index) in cartList" :key="index" :right-options="options" @click="removeCart(1,item)">
<view class="cart_item">
<view class="cart_selected" @click="checkedShop(item)">
<view :class="item.isSelect === 1?'cart_selected_true':'cart_selected_false'">
<image v-if="item.isSelect" src="../../static/selected.png"></image>
</view>
</view>
<view class="cart_shop">
<image class="cart_shop_img" :src="item.image" mode="widthFix"></image>
</view>
<view class="cart_shop_cont">
<view class="cart_title"><text class="cart_text">{{item.storeName}}</text></view>
<view class="cart_desc">{{item.desc}}</view>
<view class="cart_bottom">
<view class="cart_price price">{{item.price}}<!--<text class="market_name prices">59.9</text>--></view>
<view class="cart_counter" v-if="showEdit" @click="removeCart(1,item)">
<view class="cart_remove">删除</view>
</view>
<view class="cart_counter" v-else>
<view class="cart_counter_btn border_l" @click="editAmount(1,item)">
<image class="cart_counter_btn_img" src="https://zhkj1.oss-cn-shanghai.aliyuncs.com/zhscMerchant/minus.png" mode="widthFix"></image>
</view>
<view class="cart_counter_center">{{item.cartNum}}</view>
<view class="cart_counter_btn border_r" @click="editAmount(2,item)">
<image class="cart_counter_btn_img" src="https://zhkj1.oss-cn-shanghai.aliyuncs.com/zhscMerchant/add.png" mode="widthFix"></image>
</view>
</view>
</view>
</view>
</view>
<!-- <view class="cart_items" v-if="item.type == 2">
<view class="cart_t">
<view class="cart_selected">
<view :class="item.isSelect?'cart_selected_true':'cart_selected_false'">
<image v-if="item.isSelect" src="../../static/selected.png"></image>
</view>
</view>
<view class="cart_view_scroll">
<view class="cart_scroll">
<scroll-view class="cart_scroll_ul" :scroll-with-animation="true" :enhanced="true" :show-scrollbar="false" scroll-x="true">
<view class="cart_scroll_li" v-for="(i,index) in item.list">
<view class="cart_scroll_img">
<image class="cart_scroll_img_url" :src="i.imgUrl" mode="widthFix"></image>
</view>
<view class="cart_scroll_title">{{i.title}}</view>
<view class="cart_scroll_price price">{{i.price}}<text class="market_name prices">59.9</text></view>
</view>
</scroll-view>
</view>
<view class="cart_bottom">
<view class=""></view>
<view class="cart_counter" v-if="showEdit" @click="removeCart(1,item)">
<view class="cart_remove">删除</view>
</view>
<view class="cart_counter" v-else>
<view class="cart_counter_btn border_l">
<image class="cart_counter_btn_img" src="https://zhkj1.oss-cn-shanghai.aliyuncs.com/zhscMerchant/minus.png" mode="widthFix"></image>
</view>
<view class="cart_counter_center">1</view>
<view class="cart_counter_btn border_r">
<image class="cart_counter_btn_img" src="https://zhkj1.oss-cn-shanghai.aliyuncs.com/zhscMerchant/add.png" mode="widthFix"></image>
</view>
</view>
</view>
</view>
</view>
</view> -->
</uni-swipe-action-item>
</uni-swipe-action>
</template>
<!-- 失效商品 -->
<view class="cart_lose" v-if="cartList_invalid.length">
<view class="cart_lose_top">
<view class="cart_lose_top_l">共{{cartList_invalid.length}}款失效商品</view>
<view class="cart_lose_top_r">一键清空</view>
</view>
<view class="cart_lose_bottom" v-for="(item,index) in cartList_invalid" :key="index">
<view class="cart_lose_img">
<view class="cart_lose_bcg">
<view class="cart_lose_text">商品已下架</view>
</view>
<image class="cart_lose_img_url" :src="item.image" mode="widthFix"></image>
</view>
<view class="cart_lose_ly">
<view class="cart_lose_title">{{item.storeName}}</view>
<view class="cart_lose_desc">商品下架了</view>
</view>
</view>
</view>
<view class="empty" v-if="iscartShow && !cartList.length && !cartList_invalid.length">
<view class="empty_cont">
<image class="empty_cont_img" src="../../static/Empty/cart.png" mode="widthFix"></image>
<view class="empty_cont_title">购物车还是空的,快去加购吧</view>
<view class="empty_cont_btn">去逛逛</view>
</view>
</view>
</view>
</view>
<template>
<recomGoods v-if="iscartListLoaded" :apiType="5" @updatecart="cartType"></recomGoods>
</template>
<view style="height: 200rpx;"></view>
<view class="footer" v-if="cartList.length">
<view class="footer_l">
<view class="footer_selected" @click="allChecked">
<view :class="allCheckedShow?'footer_selected_true':'footer_selected_false'">
<image v-if="allCheckedShow" src="../../static/selected.png"></image>
</view>
<view class="footer_text">全选</view>
</view>
</view>
<view class="footer_r">
<view class="footer_edit" v-if="showEdit">
<view class="footer_edit_li footer_edit_li_border" @click="removeCart(2)">一键清空</view>
<view class="footer_edit_li" @click="removeCart(3)">删除</view>
</view>
<block v-else>
<view class="footer_v">
<view class="footer_text">合计:</view>
<view class="footer_price">{{totalPrice}}</view>
</view>
<view class="footer_btn" :class="!totalPrice?'opy':''" @click="orderConfirm">去结算</view>
</block>
</view>
</view>
<uni-popup ref="couponPopup" type="bottom" @change="changeCoupon">
<view class="shop_open shop_open_bcg">
<view class="shop_open_title">优惠券<view class="shop_open_close" @click="OpenCoupon()"><image src="../../static/order/close.png" mode="widthFix"></image></view></view>
<view class="shop_open_desc">可使用券(2)</view>
<view class="coupon_cont">
<view class="coupon_item">
<view class="coupon_item_l">
<view class="coupon_item_absolute"></view>
<view class="coupon_item_v">
<view class="coupon_item_price">5</view>
<view class="coupon_item_desc">满39可用</view>
</view>
</view>
<view class="coupon_item_border"></view>
<view class="coupon_item_r">
<view class="coupon_item_r_l">
<view class="coupon_item_name">新人限时券</view>
<view class="coupon_item_time">今日23:59到期</view>
</view>
<view class="coupon_item_r_r">领取</view>
</view>
</view>
<view class="coupon_item">
<view class="coupon_item_l">
<view class="coupon_item_absolute"></view>
<view class="coupon_item_v">
<view class="coupon_item_price">10</view>
<view class="coupon_item_desc">满59可用</view>
</view>
</view>
<view class="coupon_item_border"></view>
<view class="coupon_item_r">
<view class="coupon_item_r_l">
<view class="coupon_item_name">新人限时券</view>
<view class="coupon_item_time">今日23:59到期</view>
</view>
<view class="coupon_item_r_r">领取</view>
</view>
</view>
</view>
</view>
</uni-popup>
<!-- 获取定位失败小组件提示 -->
<locationOpen></locationOpen>
</view>
</template>
<script setup>
import NP from 'number-precision';
import { loads } from '@/utils/index.js'
import recomGoods from '@/components/recomGoods/recomGoods.vue';
import { ref,computed } from 'vue';
import { useCounterStore } from '@/store/counter'; // 引入Pinia Store
import { storeToRefs } from 'pinia';//实现解构付值
import { onLoad,onShow,onPullDownRefresh,onReachBottom } from "@dcloudio/uni-app"
import { cartlist,cartnum,cartdelete,preorder,optForCart } from "@/server/api.js"
const counterStore = useCounterStore(); // 使用 Store
//使用piniastoreToRefs方法包裹(保持响应式更新,不使用视图无法更新)
const {statusHeight,headerHeight,token,storeName,storeId,latitude,longitude,locationShow } = storeToRefs(counterStore);
const couponPopup = ref(null);
const couponShow = ref(false);
const show = ref(false);
const showEdit = ref(false);
const cartList = ref([]);
const cartList_invalid = ref([]);
const allCheckedShow = ref(false)
const cartpages = ref(0);
const cartdecs = ref("");
const iscartListLoaded = ref(false)
const iscartShow = ref(false);
const carttotal = ref(0)
const options = ref([
{
text: '删除',
style: {
backgroundColor: '#FD4955'
}
}
]);
const OpenCoupon =() =>{
couponShow.value ? couponPopup.value.close():couponPopup.value.open()
};
const changeCoupon = (e)=>{
couponShow.value = e.show;
show.value = e.show;
};
const edit = (e)=>{
showEdit.value ? showEdit.value = false:showEdit.value = true;
};
const cartType = (type)=>{
api_cartlist(true);
}
const goDetail= ()=>{
uni.navigateTo({
url:`/shopProDetail/detail/detail`
})
}
//购物车有效商品
const api_cartlist = (e) =>{
if(e){
// cartList.value = [];
// cartdecs.value = '';
// cartpages.value = 0;
iscartShow.value = false;
}
cartdecs.value = "—— 加载中... ——";
// cartpages.value = cartpages.value + 1;
loads('', true)
const params = {isValid:"1",page:'1',limit:'100'}
return cartlist(params).then(({data})=>{
uni.hideLoading()
cartdecs.value = '—— 上拉加载更多 ——'
if(data.list.length < 10){
cartdecs.value = '—— 嗷呜,已经到底啦 ——';
}
//更改全选状态
const allSelected = data.list.every(item => item.isSelect === 1);
if(allSelected){
allCheckedShow.value = true;
}else{
allCheckedShow.value = false;
}
cartList.value = data.list;
carttotal.value = data.total;
})
.then(()=>{
if(e){api_cartlist_invalid(true)}
})
.catch(({message}) => {
uni.hideLoading()
img_err.value = "../../static/Empty/err.png"
cartdecs.value = `—— ${message||'网络异常'} ——`;
})
}
//购物车无效商品
const api_cartlist_invalid = (empty) =>{
// if(empty){
// cartList_invalid.value = [];
// }
const params = {isValid:"0",page:'1',limit:'50'}
return cartlist(params).then(({data})=>{
uni.hideLoading()
cartList_invalid.value = data.list;
iscartListLoaded.value = true
iscartShow.value = true
})
.catch(({message}) => {
uni.hideLoading()
uni.showModal({
content:message,
showCancel: false
})
})
}
//编辑购物车商品数量
const editAmount=(type,data)=>{
console.log('data',data);
let { id,cartNum } = data;
//加/减数量
if(cartNum == 1 && type == 1) return false;
let number = type == 1 ? cartNum - 1 : cartNum + 1;
loads('', true)
return cartnum(id,number).then(({message})=>{
uni.hideLoading()
cartList.value.forEach(item=>{
if(id == item.id){
item.cartNum = type == 1 ? item.cartNum - 1 : item.cartNum + 1;
}
})
}).catch(({message}) => {
uni.hideLoading()
uni.showModal({
content:message,
showCancel: false
})
})
};
//全选
const allChecked=()=>{
let cartType = "";
if(allCheckedShow.value){
cartType = "no"
}else{
cartType = "yes"
}
api_optForCart(2,0,cartType);
};
//商品选中未选中
const checkedShop=(e)=>{
let cartType = ""
if(e.isSelect){
cartType = "no"
}else{
cartType = "yes"
}
api_optForCart(1,e.id,cartType);
};
const api_optForCart=(type,cartIds,cartType)=>{
const params = {cartType}
if(type == 1){
params.cartIds = cartIds
}
loads('', true)
return optForCart(params).then(({data})=>{
uni.hideLoading()
if(type == 1){
//更改单商品选中状态
cartList.value.forEach((item,index)=>{
if(cartIds == item.id){
item.isSelect = item.isSelect === 1 ? 0 : 1
}
})
//更改全选状态
const allSelected = cartList.value.every(item => item.isSelect === 1);
allCheckedShow.value =allSelected ? true : false;
}else{
allCheckedShow.value = cartType == "yes" ? true : false;
cartList.value.forEach((item,index)=>{
item.isSelect = cartType == "yes" ? 1 : 0;
})
}
})
.catch(({message}) => {
uni.hideLoading()
uni.showModal({
content:message,
showCancel: false
})
})
}
//计算总价
const totalPrice = computed(() => {
//过滤出选中的对象
const selectedItems = cartList.value.filter(item => item.isSelect === 1);
//计算总价(考虑数量)
return selectedItems.reduce((sum, item) => NP.round(NP.plus(sum,NP.times(item.price,item.cartNum)),2), 0);
});
//选中多少数件
const selectedAmount = computed(() => {
//过滤出选中的对象
const selectedItems = cartList.value.filter(item => item.isSelect === 1);
return selectedItems.length
});
const removeCart=(type,item)=>{
let content = '';
if(type == 1){
content = "确定要删除此商品吗?"
}else if(type == 2){
content = "确定要清空购物车所有商品吗?"
}else{
content = `确定要删除购物车选中的${selectedAmount.value}种商品吗?`
}
uni.showModal({
content:content,
confirmText:type == 2?'清空':'删除',
confirmColor:'#F14D48',
success: ({confirm}) => {
if (confirm) {
if(type == 1){
api_cartdelete(type,item.id);
}else if(type == 2){
const ids = cartList.value.map(item => item.id);
api_cartdelete(type,ids)
}else{
//过滤出选中的对象
const ids = cartList.value.filter(item => item.isSelect === 1).map(item => item.id);
api_cartdelete(type,ids)
}
}
}
})
};
const api_cartdelete = (type,ids) => {
loads('', true)
return cartdelete(ids).then(({message})=>{
uni.hideLoading()
if(type == 1){
cartList.value = cartList.value.filter(item => item.id !== ids);
}else{
cartList.value = cartList.value.filter(item => !ids.includes(item.id));
}
if(showEdit.value){ showEdit.value = false }
})
.catch(({message}) => {
uni.hideLoading()
uni.showModal({
content:message,
showCancel: false
})
})
}
//预下单
const orderConfirm = () => {
const orderDetails = cartList.value.filter(item => item.isSelect === 1).map(item => ({shoppingCartId:item.id}));
if(!orderDetails.length){
uni.showToast({
title:'请选中商品后,在结算',
icon:'none'
})
return false
}
loads('', true)
let params = {
merId:storeId.value,
orderDetails,
preOrderType:'shoppingCart'
};
return preorder(params).then(({data})=>{
uni.hideLoading();
uni.navigateTo({
url:`/order/orderConfirm/orderConfirm?preOrderNo=${data.preOrderNo}`
})
})
.catch(({message}) => {
uni.hideLoading()
uni.showModal({
content:message,
showCancel: false
})
})
}
const location=()=>{
if(locationShow.value) return false;
uni.navigateTo({
url:`/userserve/location/location`
})
}
//使用 uni.onLoad 监听页面加载
onLoad((options) => {});
onShow(() => {
api_cartlist(true);
});
onPullDownRefresh(()=>{
api_cartlist(true);
uni.stopPullDownRefresh();
})
onReachBottom(()=>{
// api_cartlist(false);
})
</script>
<style lang="scss">
@import './style.scss';
.uni-swipe{
margin: 0rpx 20rpx 0rpx 20rpx !important;
margin-bottom: 20rpx !important;
border-radius: 25rpx !important;
background-color: #fff !important;
}
</style>