代客下单重构

This commit is contained in:
2025-04-29 10:33:00 +08:00
parent 1f59082bcb
commit 13ad5a0de4
15 changed files with 5345 additions and 1525 deletions

View File

@@ -260,10 +260,6 @@
</template>
<script setup>
import {
useCartsStore
} from '@/stores/carts.js';
const cartStore = useCartsStore()
import orderItemVue from './order-item.vue';
import {
ref,

View File

@@ -140,8 +140,8 @@
} from '@/common/api/shop/index.js'
import {
useCartsStore
} from '@/stores/carts.js';
import useWebSocket from '@/common/js/carts-websocket.js';
} from '@/stores/carts';
import useWebSocket from '@/common/js/carts-websocket';
const cartStore = useCartsStore()
let cartsSocket = null
watch(() => cartStore.goodsIsloading, (newValue) => {

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,6 @@
<up-popup :show="showCart" :round="20" :safeAreaInsetBottom="false" :zIndex="98" :overlayStyle="{ zIndex: 98 }"
@close="close">
<view class="cart-list-wrap">
<!-- <view class="cart-header flex-between">
<view class="num">已点 {{ cartLists_count }} </view>
<view class="clear" @click="cartclear">
<up-icon name="trash" color="#999"></up-icon>
<text class="t">清空</text>
</view>
</view> -->
<scroll-view scroll-y class="scroll-view">
<view class="list-wrap">
<view v-if="cartList.length>0">
@@ -29,15 +22,15 @@
<up-image :src="item.coverImg" width="80" radius="10" height="80"></up-image>
</view>
<view class="info">
<view class="name"> {{item.cartListinfo.is_temporary == 1?'临时菜' :item.name }}
<view class="name"> {{item.is_temporary == 1?'临时菜' :item.name }}
</view>
<view class="select-sku-wrap" v-if="item.type == 'sku'">
<text v-for="i in item.skuList" :key="i.id">
{{item.cartListinfo.sku_id == i.id? i.name:"" }}
<text >
{{item.skuData.name||''}}
</text>
</view>
<view class="select-sku-wrap" v-if="item.type == 'package'">
<view v-for="(a,b) in dataprocessing(item.cartListinfo)" :key="b">
<view v-for="(a,b) in dataprocessing(item)" :key="b">
<!-- <view>{{a.title}}</view> -->
<text v-for="i in a.goods" :key="i.proId" style="margin-left: 4rpx;">
{{i.proName }}
@@ -47,15 +40,14 @@
<view class="price-wrap" style="padding-top: 0;">
<view class="price">
<text class="i"></text>
<!-- 会员价与价格 -->
<text class="price" v-if="item.type == 'sku'">
<text v-for="i in item.skuList" :key="i.id">
<!-- -->
{{item.cartListinfo.sku_id == i.id?(shopInfo.isVip ==1 && shopInfo.isMemberPrice==1?(i.memberPrice || i.salePrice):i.salePrice):''}}
<!-- 会员价 -->
<text class="price" v-if="shopInfo.isVip ==1 && shopInfo.isMemberPrice==1">
<text >
{{item.memberPrice || item.salePrice}}
</text>
</text>
<text class="price" v-else>
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1?(item.memberPrice || item.salePrice):item.salePrice}}
{{item.salePrice}}
</text>
<!-- <text class="originalprice"
v-if="item.originPrice">¥{{item.originPrice}}</text>
@@ -66,16 +58,16 @@
<view class="operation-wrap">
<view class="btn">
<up-icon color="#E8AD7B" name="minus-circle" size="25"></up-icon>
<view class="btnClick" @click="cartListadd(item,'-')"></view>
<view class="btnClick" @click="changeNumber(-1,item)"></view>
</view>
<text class="num">{{ ifcartNumber(item) }}</text>
<text class="num">{{ item.number*1 }}</text>
<view class="btn" v-if="item.type !='package'">
<!-- <up-icon name="plus-circle-fill"
:color="{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1? '#CECECE' : '#E9AB7A'"
size="25"></up-icon> -->
<up-icon name="plus-circle-fill" color="#E8AD7B"
size="25"></up-icon>
<view class="btnClick" @click="cartListadd(item,'+')"></view>
<view class="btnClick" @click="changeNumber(1,item)"></view>
</view>
</view>
</view>
@@ -104,7 +96,7 @@
} from '@/stores/user.js';
// 定义自定义事件
const emits = defineEmits(['customevent', 'close', 'clickcancelOrder']);
const emits = defineEmits(['changeNumber', 'close', 'clearCarts']);
const props = defineProps({
cartList: {
@@ -127,54 +119,16 @@
});
const shopInfo = uni.cache.get('shopInfo')
// 定义 ifcartNumber 计算属性方法
const ifcartNumber = computed(() => {
return (item) => {
// 如果 item 为空或者 cartNumber 不是字符串类型,返回 0
if (!item || typeof item.cartNumber !== 'string') {
return 0;
}
let numValue = parseFloat(item.cartNumber);
if (isNaN(numValue)) {
// 如果转换结果是 NaN说明 cartNumber 不是有效的数字字符串,返回 0
return 0;
}
// type string 商品类型 single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券
if (item.type === 'weight') {
// 如果类型是称重重量,将值保留两位小数
return parseFloat(numValue.toFixed(2));
} else {
// 如果类型是整数,将值转换为整数
return Math.round(numValue);
}
// 如果类型不匹配,返回原始值
return item.cartNumber;
};
})
const close = () => {
emits("close", false)
}
// 购物车加减
const cartListadd = async (item, i) => {
// 是否起售 如果小于或者大于都是1
const cartNumberFloat = parseFloat(item.cartNumber);
const suitNum = item.suitNum >= cartNumberFloat && i == '-' ? item.cartNumber : 1;
function changeNumber(step,item){
emits("changeNumber", step, item);
emits('customevent', {
id: item.cartListId ? item.cartListId : '',
type: 'shopping',
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId'),
operate_type: calculateValue(item.cartNumber, i, suitNum) == 'del' ? 'del' : item.cartListId &&
item.cartNumber > 0 ? 'edit' : 'add',
product_id: item.id,
sku_id: item.skuId,
number: await calculateValue(item.cartNumber, i, suitNum),
is_print: 1,
suitNum: item.suitNum,
})
}
const dataprocessing = computed(() => {
return (item) => {
@@ -188,18 +142,6 @@
};
})
const clickcancelOrder = (i, key) => {
emits('clickcancelOrder', {
i,
key
})
emits('customevent', {
type: 'shopping',
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId'),
operate_type: 'clearOrder',
})
}
const calculateValue = (cartNumber, i, step = 1) => {
if (i == '+') {
@@ -212,30 +154,10 @@
}
}
// 菜品备注修改
const productBlur = (item) => {
let params = {
"skuId": item.skuId,
"num": item.number, //数量
"type": item.type,
"isVip": item.isVip,
"productId": item.productId, //商品id
"note": item.note,
"shopId": this.shopId,
"userId": uni.cache.get('userInfo').id,
"tableId": this.tableCode,
}
this.$emit("addCart", params)
}
// 清空购物车
const cartclear = () => {
emits('customevent', {
type: 'shopping',
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId'),
operate_type: 'cleanup',
})
emits('clearCarts')
}
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,7 @@
</view>
</view>
<!-- 本店招牌菜 -->
<view class="panelfour" v-if="shopProductList.hots && shopProductList.hots.length > 0">
<view class="panelfour" v-if="carts.hotgoods && carts.hotgoods.length > 0">
本店招牌菜
</view>
<view class="panelfive ">
@@ -41,7 +41,7 @@
<scroll-view :scroll-x="true" :scroll-with-animation="false">
<view class="panelfive_list">
<view class="panelfiveitem" @click="clickspecifications(item,index,index,'热销')"
v-for="(item,index) in shopProductList.hots" :key="index">
v-for="(item,index) in carts.hotgoods" :key="index">
<image class="panelfiveitemimage" :src="item.coverImg" mode="aspectFill"></image>
<view class="vifgoodsImg flex-center"
v-if="item.isSale == 0 || (item.isSaleTime == 0 && !item.isSaleTimeshow) || item.isSoldStock == 1 || (item.isStock == 1 && item.stockNumber <= 0)">
@@ -84,7 +84,7 @@
:class="shopInfo.isVip == 0 || shopInfo.isMemberPrice==0?'lineThrough':''">¥</text>
<!-- 会员价与价格 -->
<text class="price">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1?(item.memberPrice||item.salePrice):item.salePrice}}
{{carts.useVipPrice?(item.memberPrice||item.salePrice):item.salePrice}}
</text>
<!-- 单位 -->
<text class="unit" v-if="item.unitName">/{{item.unitName}}</text>
@@ -106,7 +106,7 @@
:class="shopInfo.isVip ==0 || shopInfo.isMemberPrice==0?'lineThrough':''">¥</text>
<!-- 会员价与价格 -->
<text class="price">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1?(item.memberPrice|| item.salePrice):item.salePrice}}
{{carts.useVipPrice?(item.memberPrice|| item.salePrice):item.salePrice}}
</text>
<text class="unit" v-if="item.unitName">/{{item.unitName}}</text>
<!-- <text v-if="item.suitNum>1 && item.type!= 'sku'"
@@ -153,14 +153,14 @@
<view class="left" :style="{top: `${store.height}px`}">
<scroll-view :scroll-into-view="leftIntoView" :scroll-with-animation="false" :scroll-y="true"
:style="{height:`${store.screenHeight - store.height}px`}" style="padding-bottom: 200rpx;">
<view class="item" v-for="(item,index) in shopProductList.productInfo" :key="index"
<view class="item" v-for="(item,index) in carts.groupGoods" :key="index"
:class="{ 'active':index==leftIndex }" :id="'left-'+index" :data-index="index"
@click="leftTap(index)"><text>{{item.name}}</text></view>
</scroll-view>
</view>
<view class="main">
<view>
<view class="item main-item" v-for="(item,index) in shopProductList.productInfo" :key="index"
<view class="item main-item" v-for="(item,index) in carts.groupGoods" :key="index"
:id="'item-'+index">
<view class="title">
<view>{{item.name}}</view>
@@ -175,19 +175,25 @@
src="https://czg-qr-order.oss-cn-beijing.aliyuncs.com/index/1.gif" mode="" v-else
:lazy-load="true">
</image>
<view class="vifgoodsImg"
v-if="item1.isSale == 0 || (item1.isSaleTime == 0 && !item1.isSaleTimeshow) || item1.isSoldStock == 1 || (item1.isStock == 1 && item1.stockNumber <= 0)">
<image v-if="item1.isSale == 0" src="@/static/ztt/icon_goods_yxj.svg"
style="width:200rpx; height: 100%;" mode=""></image>
<image v-else-if="(item1.isSaleTime == 0 && !item1.isSaleTimeshow)"
src="@/static/ztt/icon_goods_wks.svg" style="width:200rpx; height: 100%;"
mode=""></image>
<image v-else-if="item1.isSoldStock == 1" src="@/static/ztt/icon_goods_sq.svg"
style="width:200rpx; height: 100%;" mode=""></image>
<image v-else-if="item1.isStock == 1 && item1.stockNumber <= 0"
src="@/static/ztt/icon_goods_kcbz.svg" style="width:200rpx; height: 100%;"
mode=""></image>
</view>
<block>
<view class="vifgoodsImg" v-if="item1.isSale == 0">
<image src="@/static/ztt/icon_goods_yxj.svg" style="width:200rpx; height: 100%;"
mode=""></image>
</view>
<view class="vifgoodsImg"
v-else-if="item1.isSaleTime == 0 && !item1.isSaleTimeshow">
<image src="@/static/ztt/icon_goods_wks.svg" style="width:200rpx; height: 100%;"
mode=""></image>
</view>
<view class="vifgoodsImg" v-else-if="item1.isSoldStock == 1">
<image src="@/static/ztt/icon_goods_sq.svg" style="width:200rpx; height: 100%;"
mode=""></image>
</view>
<view class="vifgoodsImg" v-else-if="item1.isStock == 1 && item1.stockNumber <= 0">
<image src="@/static/ztt/icon_goods_kcbz.svg"
style="width:200rpx; height: 100%;" mode=""></image>
</view>
</block>
<view v-if="index=='0'" class="topSort" :class="'c'+(index1+1)">TOP{{index1+1}}</view>
<view class="goods_right" style="overflow: hidden;">
<view class="name">{{ item1.name }}</view>
@@ -205,8 +211,11 @@
<view class="money">
<view></view>
<text class="money_num" style="margin-right: 10rpx;">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1 ?(item1.memberPrice||item1.salePrice):item1.salePrice}}
{{carts.useVipPrice?(item1.memberPrice||item1.salePrice):item1.salePrice}}
</text>
<!-- <text class="money_num" style="margin-right: 10rpx;">
{{carts.useVipPrice ?(item1.memberPrice||item1.salePrice):item1.salePrice}}
</text> -->
<text v-if="item1.unitName">/{{item1.unitName}}</text>
</view>
<view class="flex-end">
@@ -221,7 +230,7 @@
<view class="money">
<view></view>
<text class="money_num">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1?(item1.memberPrice||item1.salePrice):item1.salePrice}}
{{carts.useVipPrice?(item1.memberPrice||item1.salePrice):item1.salePrice}}
</text>
<text class="money_num" v-if="item1.unitName">/{{item1.unitName}}</text>
<!-- <text v-if="item1.suitNum>1 && item1.type!= 'sku'"
@@ -267,21 +276,17 @@
</view>
<confirmorder ref="confirmorderref" :cartLists_count="cartLists_count" :cartList="matchedProducts"
:totalPrices='totalPrices' :confirmordershow="confirmordershow"
@close="confirmordershow = !confirmordershow" @customevent='websocketsendMessage' :orderinfo="orderinfo">
</confirmorder>
<!-- 店铺详情 -->
<shopindex ref="showShopInfoRef"></shopindex>
<!-- 购物车 -->
<shoppingCartes :cartLists_count="cartLists_count" :cartList="matchedProducts" :showCart="showCart"
@customevent='websocketsendMessage' @close="showCart = !showCart" :orderinfo="orderinfo"
@clickcancelOrder='clickcancelOrder' v-if="cartLists_count > 0">
<shoppingCartes :cartLists_count="carts.totalNumber" :cartList="carts.list" :showCart="showCart"
@clearCarts="clearCarts" @changeNumber="cartsChangeNumber" @close="showCart = !showCart"
:orderinfo="orderinfo" v-if="!carts.isEmpty">
</shoppingCartes>
<!-- 显示购物车栏 -->
<view class="cart-wrap" v-if="cartLists_count > 0 && !confirmordershow && isBusinessTime">
<view class="cart-wrap" v-if="!carts.isEmpty && isBusinessTime">
<view class="cart-content">
<view class="left">
<view class="iconBox">
@@ -289,11 +294,11 @@
src="https://czg-qr-order.oss-cn-beijing.aliyuncs.com/shopDetails/shopIcon.png"
mode="aspectFill" @click="Historicalorders(true)">
</image>
<text class="u-badge"> {{cartLists_count<99?cartLists_count:'99+'}} </text>
<text class="u-badge"> {{carts.totalNumber <99?carts.totalNumber:'99+'}} </text>
</view>
<text class="i"></text>
<text class="num">{{totalPrices}}</text>
<text class="num">{{carts.payMoney}}</text>
</view>
<view class="btn" @tap="$u.debounce(orderdetail, 500)">
<text class="t">结算</text>
@@ -366,7 +371,7 @@
<view class="price" v-if="specifications.item.type != 'package' && specifications.item.result">
<text class="i"></text>
<text
class="num">{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1? (specifications.item.result.memberPrice||specifications.item.result.salePrice):specifications.item.result.salePrice}}</text>
class="num">{{carts.useVipPrice? (specifications.item.result.memberPrice||specifications.item.result.salePrice):specifications.item.result.salePrice}}</text>
<text class="i" v-if="specifications.item.unitName">/{{specifications.item.unitName}}</text>
<text v-if="specifications.item.result.suitNum>1">
{{specifications.item.result.suitNum}}{{specifications.item.result.unitName}}起点
@@ -375,7 +380,7 @@
<view class="price" v-else>
<text class="i"></text>
<text class="num">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1? (specifications.item.memberPrice||specifications.item.salePrice):specifications.item.salePrice}}
{{carts.useVipPrice? (specifications.item.memberPrice||specifications.item.salePrice):specifications.item.salePrice}}
</text>
<text class="i" v-if="specifications.item.unitName">
/{{specifications.item.unitName}}
@@ -418,11 +423,36 @@
<image class="img" src="@/static/history.png" mode=""></image>
<text>已下单菜品</text>
</view>
<Loading :isLoading="isLoading" />
<Loading :isLoading="!carts.isLinkFinshed" />
</view>
</template>
<script setup>
import {productStore} from '@/stores/user'
import {
useCartsStore
} from '@/stores/carts'
//购物车
const carts = useCartsStore();
function cartsChangeNumber(step, item) {
carts.changeNumber(step * 1, item);
}
function clearCarts() {
carts.clear();
}
//用户信息
const userStore=productStore()
// 获取用户信息
userStore.actionsAPIuser(res=>{
console.log('userStore.actionsAPIuser');
console.log(res);
carts.changeUser(user)
})
import {
ref,
reactive,
@@ -445,7 +475,7 @@
import Nav from '@/components/CustomNavbar.vue';
import shopindex from './components/shopindex.vue'
import shoppingCartes from './components/shoppingCartes.vue'
import confirmorder from './components/confirmorder.vue'
// import confirmorder from './components/confirmorder.vue'
import Loading from '@/components/Loading.vue';
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween'
@@ -486,11 +516,6 @@
const storeMemberpay = Memberpay();
const store = useNavbarStore();
import {
productStore
} from '@/stores/user.js';
const userStore = productStore();
// 金额管理
import {
@@ -516,8 +541,7 @@
//店铺详情
const showShopInfoRef = ref(null)
// 初始加载中
const isLoading = ref(true);
//调用shop组件
const callChildMethod = () => {
@@ -541,7 +565,7 @@
// * 图片加载
const imageLoaded = (item, index, index1) => {
// shopProductList.productInfo[index].products[index1]['imgLoad'] = true;
// carts.groupGoods[index].products[index1]['imgLoad'] = true;
}
// 计算左侧位置
@@ -812,132 +836,6 @@
//添加购物车数量
const shopCartNumber = ref(0)
// 多规格 套餐添加数量
const shopCart = async (i) => {
if (i == '-' && shopCartNumber.value >= 0) {
shopCartNumber.value = 0
return false;
}
let res = await shoppingcart()
if (i == '-') {
if (!res && shopCartNumber.value == specifications.item.suitNum) {
uni.showToast({
title: `起点${specifications.item.suitNum}`,
icon: 'none'
})
return false;
} else {
shopCartNumber.value--;
}
} else {
if (!res && shopCartNumber.value < 1) {
console.log(res, specifications)
if (specifications.type == 'sku') {
shopCartNumber.value = parseFloat(specifications.item.result.suitNum);
} else {
shopCartNumber.value = parseFloat(specifications.item.suitNum);
}
} else {
shopCartNumber.value++;
}
}
}
// 套餐比较两个对象是否相等
function isObjectEqual(obj1, obj2) {
if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {
return obj1 === obj2;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
if (!isArrayEqual(obj1[key], obj2[key])) {
return false;
}
} else if (!isObjectEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
}
// 比较两个数组是否相等(忽略顺序)
function isArrayEqual(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
const usedIndices = new Array(arr2.length).fill(false);
for (const item1 of arr1) {
let found = false;
for (let i = 0; i < arr2.length; i++) {
if (!usedIndices[i] && isObjectEqual(item1, arr2[i])) {
usedIndices[i] = true;
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
// 根据购物车的数据匹配选中的商品查找是否有匹配的数组
const matchingProduct = async (data) => {
return matchedProducts.value.find((product, index) => {
if (specifications.type == 'package') {
// 套餐
let result = false;
try {
if (product.type == "package") {
let res = JSON.parse(product.cartListinfo.pro_group_info);
result = isArrayEqual(res, selectedGroupSnap.value);
}
} catch (error) {
//TODO handle the exception
}
// 直接返回布尔值
return result;
} else if (specifications.item.type == 'sku') {
// 多规格
return product.cartListinfo.sku_id == data.id && product.cartListinfo.product_id == data
.productId
} else {
// 其他
return product.skuId == data.skuId && product.id == data.id
}
});
}
// 判断多规格和套餐 商品是否在购物车有数据
const shoppingcart = async () => {
let res = null
if (specifications.item.type == "package") {
if (!allConditionsSatisfied.value) {
return false
}
// 是否是套餐package
selectedGroupSnap.value = specifications.item.groupSnap.map((setmenu, index) => {
return {
...setmenu,
goods: selectedOptions.value[index]
};
});
res = await matchingProduct(selectedGroupSnap.value)
} else {
if (!canSubmit.value) {
return false
}
res = await matchingProduct(specifications.item.result)
}
return res;
}
// 提交选择并执行下一步操作的方法
const submitSelection = async () => {
@@ -965,7 +863,7 @@
selectedGroupSnap.value = []
}
websocketsendMessage({
carts.add({
id: res ? res.cartListId : '',
type: 'shopping',
suitNum: specifications.productListitem.suitNum,
@@ -982,6 +880,24 @@
is_print: 1,
product_type: specifications.item.type
})
// websocketsendMessage({
// id: res ? res.cartListId : '',
// type: 'shopping',
// suitNum: specifications.productListitem.suitNum,
// table_code: uni.cache.get('tableCode'),
// shop_id: uni.cache.get('shopId'),
// operate_type: res ? 'edit' : 'add',
// product_id: specifications.product_id,
// sku_id: specifications.sku_id,
// number: res ? await calculateValue(res.cartNumber, '+', shopCartNumber.value) :
// shopCartNumber
// .value,
// pro_group_info: selectedGroupSnap.value,
// goods_type: specifications.item.type == "package" ? 'package' : '',
// is_print: 1,
// product_type: specifications.item.type
// })
// 清空套餐选中
selectedGroupSnap.value = []
showShopsku.value = false
@@ -1068,6 +984,18 @@
return isInRange;
}
function addCarts(item, isWeight = false) {
if (isWeight) {
carts.add({
...item
});
return;
}
carts.add({
...item
});
}
// 单规格
const singleclick = async (item, i) => {
if (!isProductAvailable(item.days, item.startTime, item.endTime)) {
@@ -1077,26 +1005,18 @@
return false;
}
// 判断购物车是否有该选中商品
let res = null
try {
res = matchedProducts.value.find((product, index) => {
return product.skuId == item.skuId && product.id == item.id
});
} catch (error) {
//TODO handle the exception
}
// 保存这次点击的
specifications.productListitem = item
// 是否起售 如果小于或者大于都是1
let suitNum = 1;
const cartNumberFloat = parseFloat(item.cartNumber);
if (!res && item.suitNum > cartNumberFloat) {
suitNum = item.suitNum;
} else if (item.suitNum >= cartNumberFloat && i === '-') {
suitNum = item.cartNumber;
}
console.log(item);
addCarts({
suitNum: item.suitNum || 1,
product_id: item.id,
sku_id: item.skuList[0].id,
number: item.skuList[0].suitNum || 1,
product_type: item.type,
});
return
websocketsendMessage({
id: res ? item.cartListId : '',
type: 'shopping',
@@ -1134,190 +1054,62 @@
shop_id: uni.cache.get('shopId')
}
}
const {
isConnected,
sendMessage,
closeSocket: manualClose,
receivedMessages,
closeExistingConnection,
onShowconnect,
initNetworkListener
} = useWebSocket(options);
try{
carts.init({
type: 'shopping',
operate_type: 'init',
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId')
}, {});
}catch(err){
console.error('购物车数据初始化失败')
}
function sendMessage() {}
function closeSocket() {}
function receivedMessages() {}
function closeExistingConnection() {}
function onShowconnect() {}
function initNetworkListener() {}
// const {
// isConnected,
// sendMessage,
// closeSocket: manualClose,
// receivedMessages,
// closeExistingConnection,
// onShowconnect,
// initNetworkListener
// } = useWebSocket(options);
//购物车显示
const showCart = ref(false)
// 提交订单显示
const confirmordershow = ref(false)
// 更新商品数量的方法
const updateProductQuantities = () => {
// 先将所有商品的 cartNumber 初始化为 0
shopProductList.hots.forEach((i) => {
i.cartNumber = 0
})
// 遍历商品列表二维数组
shopProductList.productInfo.forEach((group) => {
group.productList.forEach((product) => {
product.cartNumber = 0
});
});
// 再去更新数组的值
cartListFilter.value.forEach((cartItem) => {
shopProductList.productInfo.forEach((group) => {
group.productList.forEach((product) => {
if (product.id == cartItem.product_id && product.skuId == cartItem
.sku_id) {
product.cartNumber = cartItem.number
product.cartListId = cartItem.id
}
});
});
});
// 遍历购物车数组
cartListFilter.value.forEach((cartItem) => {
// 遍历商品列表二维数组
shopProductList.hots.forEach((group) => {
// 商品 id 匹配
if (group.id == cartItem.product_id) {
// 更新商品的数量
group.cartListId = cartItem.id
group.cartNumber = cartItem.number
}
});
});
}
//websocket产值
const websocketsendMessage = (data) => {
uni.$u.debounce(sendMessage(data), 500)
}
// 用于记录已经处理过的消息的 msg_id
const processedMessageIds = new Set();
// 监听接收到的消息变化
watchEffect(async () => {
if (isDataLoaded.value && receivedMessages.value) {
const Message = receivedMessages.value
if (Message) {
console.log(Message.data);
// 心跳返回 过滤
if (Message.type == "ping_interval" || Message.msg_id == "ping_interval") {
isLoading.value = false;
return false
}
// 检查消息是否已经处理过
if (processedMessageIds.has(Message.msg_id)) {
return;
}
processedMessageIds.add(Message.msg_id);
// 初始化
if (Message.operate_type == "init") {
cartStore.carts = Message.data
uni.hideLoading();
isLoading.value = false;
}
// 清空购物车
if (Message.operate_type == 'cleanup') {
cartStore.carts = []
setTimeout(() => {
Historicalorders()
}, 400)
showCart.value = false
}
// 删除除购物车
if (Message.operate_type == 'del' && Message.status == 1) {
// 优化:使用可选链操作符避免报错
cartStore.carts = cartStore.carts.filter(item => item.id !== Message.data?.id);
// cartStore.carts = cartStore.carts.filter(item => item.id != Message.data.id);
}
// 添加或者减少购物后返回
if (Message.operate_type == 'add' || Message.operate_type == 'edit') {
[Message.data].forEach((objA) => {
const index = cartStore.carts.findIndex((objB) => objB.id == objA.id);
if (index !== -1) {
cartStore.carts[index] = objA;
} else {
cartStore.carts.push(objA);
}
});
}
// 历史订单
if (Message.operate_type == 'clearOrder') {
Historicalorders()
}
// 购物车数据更新从新请求
if (Message.type == 'product' && Message.data_type == 'product_update' && Message
.operate_type == 'product_update') {
isDataLoaded.value = false;
productqueryProduct()
}
// 提示
if (Message.status == 0 && Message.type != 'no_suit_num') {
uni.showToast({
title: Message.msg,
icon: "none"
})
}
if (Message.type == 'no_suit_num') {
// console.log(specifications)
uni.showModal({
title: '提示',
showCancel: false,
content: '此商品库存不足起售数量!',
success: async (data) => {
await websocketsendMessage({
id: Message.id,
type: 'shopping',
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId'),
operate_type: 'del',
is_print: 1,
})
}
});
}
//除去p 每次返回都回执消息
await websocketsendMessage({
type: 'receipt',
msg_id: Message.msg_id
})
// 初始化商品数量
await updateProductQuantities()
}
}
})
// 更新购物车数据shopProductList.hots
// 更新购物车数据carts.hotgoods
const matchedProducts = computed(() => {
if (cartStore.carts.length > 0) {
if (carts.list.length > 0) {
let Specialstop = null
try {
Specialstop = [...[{
id: "",
name: "",
productList: shopProductList.hots
}], ...shopProductList.productInfo]
productList: carts.hotgoods
}], ...carts.groupGoods]
} catch (error) {
Specialstop = shopProductList.productInfo
Specialstop = carts.groupGoods
//TODO handle the exception
}
return cartStore.carts.flatMap((cartItem) => {
return carts.list.flatMap((cartItem) => {
for (const group of Specialstop) {
for (const product of group.productList) {
if (product.id == cartItem.product_id) {
@@ -1351,26 +1143,10 @@
})
//删除某一个待支付订单
const clickcancelOrder = async (data) => {
if (data.i == 'all') {
await APIcancelOrder({
shopId: uni.cache.get('shopId'),
orderId: orderinfo.value.id,
})
} else {
await APIrmPlaceOrder({
shopId: uni.cache.get('shopId'),
orderId: orderinfo.value.id,
placeNum: data.key
})
}
Historicalorders()
}
// 储存是否存在多次下单
const orderinfo = ref({})
const confirmorderref = ref(null)
// const confirmorderref = ref(null)
// 结账
const orderdetail = async () => {
@@ -1379,17 +1155,12 @@
.cache.get(
'shopId')
})
return
try {
await Historicalorders()
} catch (error) {}
confirmordershow.value = true
showCart.value = false
}
// 历史订单
const Historicalorders = async (W) => {
console.log('Historicalorders');
console.log(W);
if (W) {
showCart.value = !showCart.value
} else {
@@ -1404,89 +1175,6 @@
}
}
// 提取合并 orderinfo.detailMap 数组的逻辑
function combineOrderInfoDetailMap(orderinfo) {
if (!orderinfo) return [];
let combinedArray = [];
for (const key in orderinfo.detailMap) {
if (orderinfo.detailMap.hasOwnProperty(key)) {
let subArray = orderinfo.detailMap[key];
combinedArray = [...combinedArray, ...subArray];
}
}
return combinedArray;
}
// 计算购物车商品费用
const totalPrices = computed(() => {
// 待支付订单
let cartone = 0
if (orderinfo.value) {
let combinedArray = [];
for (const key in orderinfo.value.detailMap) {
if (orderinfo.value.detailMap.hasOwnProperty(key)) {
let subArray = orderinfo.value.detailMap[key];
combinedArray = [...combinedArray, ...subArray]
}
}
// 购物车总数价格
cartone = combinedArray.reduce((total, item) => {
// 是否启用会员价 0否1是
if (shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1) {
// memberPrice会员价
return total + (parseFloat(item.memberPrice || item.price) * parseFloat(item.num - item
.returnNum));
} else {
// salePrice销售价
return total + (parseFloat(item.price || 0) * parseFloat(item.num - item.returnNum));
}
}, 0);
}
// 购物车总数价格
let cart = 0
if (matchedProducts.value.length > 0) {
// 购物车总数价格
cart = matchedProducts.value.reduce((total, item) => {
if (item.type == 'sku') {
item.skuList.forEach((i, t) => {
if (item.cartListinfo.sku_id == i.id) {
item.memberPrice = i.memberPrice
item.salePrice = i.salePrice
}
})
}
// 是否启用会员价 0否1是
if (shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1) {
// memberPrice会员价
return total + parseFloat(item.memberPrice || item.salePrice) * parseFloat(item
.cartNumber);
} else {
// salePrice销售价
return total + parseFloat(item.salePrice || 0) * parseFloat(item.cartNumber);
}
}, 0);
}
cart = parseFloat(cart)
// 向上取整并保留两位小数
return parseFloat(cart.toFixed(2));
});
// 计算购物车商品总数量
const cartLists_count = computed(() => {
const combinedOrderInfo = combineOrderInfoDetailMap(orderinfo.value);
const orderInfoCount = combinedOrderInfo.reduce((sum, item) => {
return sum + parseFloat(item.num);
}, 0);
const matchedProductsCount = matchedProducts.value.reduce((sum, item) => {
const num = typeof item.cartNumber === 'string' ? parseFloat(item.cartNumber) : item
.cartNumber;
return sum + num;
}, 0);
const totalCount = matchedProductsCount;
return parseFloat(totalCount.toFixed(2));
});
// 定义 ifcartNumber 计算属性方法 展示数量
const ifcartNumber = computed(() => {
@@ -1513,31 +1201,6 @@
};
})
// 计算处理后的购物车列表 // 用于筛选后的购物车数组
const cartListFilter = computed(() => {
// 使用 reduce 方法对 cartList 进行处理
const grouped = cartStore.carts.reduce((acc, item) => {
const productId = item.product_id;
const num = parseFloat(item.number);
if (!acc[productId]) {
// 如果 acc 中还没有该 product_id 的记录,创建一个新对象
acc[productId] = {
...item,
number: num
};
} else {
// 如果已经有该 product_id 的记录,将当前对象的 number 值累加到已有记录的 number 属性上
acc[productId].number += num;
}
return acc;
}, {});
// 将累加结果保留两位小数,并将对象转换为数组
return Object.values(grouped).map(item => ({
...item,
number: item.number.toFixed(2)
}));
})
const endTimeref = reactive({
startTime: '',
@@ -1568,80 +1231,25 @@
return currentTime >= startTime && currentTime <= endTime;
});
// 列表请求
const productqueryProduct = async () => {
cartStore.goodsIsloading = false;
try {
shopProductList.hots = await productminiApphotsquery()
shopProductList.productInfo = await APIgroupquery()
} catch (error) {
uni.showToast({
title: '网络不稳定,请重新扫码进入',
icon: 'none'
})
setTimeout(() => {
uni.pro.switchTab('index/index')
}, 1000)
}
if (shopProductList.productInfo.length > 0 || shopProductList.hots.length > 0) {
//TODO handle the exception
//第一步:将所有商品的 cartNumber 初始化为 0
shopProductList.productInfo.forEach((group) => {
group.productList.forEach(async (product) => {
product.cartNumber = 0;
product.isSaleTimeshow = await isProductAvailable(product.days, product
.startTime, product.endTime)
cartStore.setGoodsMap(product.id, product)
});
});
shopProductList.hots.forEach(async (i) => {
i.cartNumber = 0
i.isSaleTimeshow = await isProductAvailable(i.days, i.startTime, i.endTime)
cartStore.setGoodsMap(i.id, i)
})
cartStore.goodsIsloading = true;
scrollTopSize.value = 0
topArr.value = []
// userStore.actionsAPIuser()
// 数据可以更新
isDataLoaded.value = true;
// 历史订单
Historicalorders()
} else {
uni.showToast({
title: '暂无列表数据,请重新扫码',
icon: "none"
});
isDataLoaded.value = false;
setTimeout(() => {
uni.pro.switchTab('index/index')
}, 1000)
return false;
}
}
onLoad(async (e) => {
await proxy.$onLaunched;
})
onShow(async() => {
onShow(async () => {
// 监听页面显示和隐藏
onShowconnect()
let res = await APIhistoryOrder({
tableCode: uni.cache.get('tableCode'),
})
if(res){
if (res) {
orderinfo.value = {
id: res.id,
detailMap: res.detailMap,
placeNum: res.placeNum
}
}else{
} else {
orderinfo.value = {
id:''
id: ''
}
}
})
@@ -1662,14 +1270,11 @@
tableCode: uni.cache.get('tableCode'),
})
await productqueryProduct()
if (res && res.id && shopInfo.registerType == "after") {
toHistory()
return
}
setTimeout(() => {
// 启动网络监听
initNetworkListener()
getElementTop()
}, 500)
})

View File

@@ -1,65 +1,29 @@
<template>
<view class="u-p-30">
<view>
<up-button type="warning" @click="popupShow">初始化</up-button>
</view>
<view class="u-m-t-30">
<up-button type="primary" @click="toCreate">去下单</up-button>
</view>
<up-popup :show="show" mode="bottom" close-on-click-overlay @close="resetForm">
<view class="u-p-30">
<up-form label-width="80" ref="refForm">
<up-form-item label="台桌码">
<up-input v-model="form.tableCode" placeholder="请输入台桌码"></up-input>
</up-form-item>
</up-form>
<view class="u-flex gap-20 u-m-t-30">
<up-button @click="show=false">取消</up-button>
<up-button type="primary" @click="scanCodehandle">确定</up-button>
</view>
</view>
</up-popup>
</view>
</template>
<script setup>
import {onLoad} from '@dcloudio/uni-app'
import { reactive,ref} from 'vue'
import {
productStore
} from '@/stores/user.js';
const store = productStore();
const scanCodehandle = async (i) => {
await store.scanCodeactions(form)
}
const show=ref(false);
const options=ref({})
function popupShow(){
show.value=true;
}
const refForm=ref(null);
const form=reactive({
tableCode:"40963902920"
ref
} from 'vue';
import {
useCartsStore
} from '@/stores/carts'
const carts = useCartsStore();
console.log(carts);
const table = ref({
tableCode: '40963902920',
})
function resetForm(){
form.tableCode=""
}
onLoad((opt)=>{
console.log(opt);
options.value=opt
})
function toCreate(){
uni.navigateTo({
url:'/pages/index/index'
})
}
carts.init({
table_code: table.value.tableCode,
shop_id:"29",
account:29
}, {});
</script>
<style lang="scss" scoped>
.gap-20{
.gap-20 {
gap: 20rpx;
}
</style>
</style>