import { defineStore } from 'pinia'; import yskUtils from 'ysk-utils' const { OrderPriceCalculator, BaseCartItem, BackendCoupon, ActivityConfig, OrderExtraConfig, MerchantReductionConfig, MerchantReductionType, GoodsType } = yskUtils import { ref, computed, reactive, watchEffect, watch } from 'vue'; import { productminiApphotsquery, APIgroupquery, } from "@/common/api/product/product.js"; export const useCartsStore = defineStore('cart', () => { // 店铺信息 const shopInfo = ref(uni.cache.get('shopInfo') || { isMemberPrice: 0, isTableFee: 1 }) const consumeDiscount=ref({}) // 适配工具库 BaseCartItem 接口的商品数据转换函数 const convertToBaseCartItem = (item) => { const skuData = item.skuData ? { id: item.skuData.id || item.sku_id, salePrice: item.skuData.salePrice || 0, memberPrice: item.skuData.memberPrice || 0 } : undefined; const goods = getProductDetails({ ...item, product_id: item.product_id || item.productId, sku_id:item.skuId||item.sku_id }) return { ...item, id: item.id, sku_id:item.skuId||item.sku_id, product_id: item.product_id || item.productId, salePrice: item.salePrice || item.price, number: item.number || item.num || 0, product_type: item.productType, is_temporary: !!(item.is_temporary || item.isTemporary), is_gift: !!(item.is_gift || item.isGift), returnNum: item.returnNum || 0, memberPrice: item.memberPrice || 0, discountSaleAmount: item.discount_sale_amount || item.discountSaleAmount || 0, packFee: item.packFee || (goods?goods.packFee:0) || 0, packNumber: item.pack_number || item.packNumber || 0, activityInfo: item.activityInfo ? { type: item.activityInfo.type, discountRate: OrderPriceCalculator.formatDiscountRate(item.activityInfo.discountRate), vipPriceShare: !!item.activityInfo.vipPriceShare } : undefined, skuData }; }; // 合并所有商品列表 const allGoods = ref([]) function getAllGoodsList() { const currentGoods = (carts.value).map(convertToBaseCartItem); const giftGoods = [].map(convertToBaseCartItem); // 扁平化历史订单商品 const oldOrderGoods = Object.values(oldOrder.value.detailMap || {}) .flat() .map(convertToBaseCartItem); return [...currentGoods, ...giftGoods, ...oldOrderGoods]; } // 就餐类型 'dine-in' | 'take-out' let dinnerType = ref('dine-in'); function setDinnerType(str) { dinnerType.value = str } //餐位费配置 const dinersNum = uni.cache.get('dinersNum') || 0 const seatFeeConfig = ref({ pricePerPerson: shopInfo.value.tableFee || 0, personCount: dinersNum||0, isEnabled: !shopInfo.value.isTableFee }) watch(() => shopInfo.value.isTableFee, (newval) => { seatFeeConfig.value.isEnabled = !shopInfo.value.isTableFee seatFeeConfig.value.pricePerPerson = shopInfo.value.tableFee||0 },{ deep:true }) function setSeatFeeConfig(key, val) { seatFeeConfig.value[key] = val; } watch(() => seatFeeConfig.value, (newval) => { console.log('seatFeeConfig', seatFeeConfig.value); }, { deep: true }) //积分规则 const pointDeductionRule = ref({ pointsPerYuan: 100, maxDeductionAmount: Infinity }) function setPointDeductionRule(pointsPerYuan, maxDeductionAmount) { pointDeductionRule.value.pointsPerYuan = pointsPerYuan pointDeductionRule.value.maxDeductionAmount = maxDeductionAmount } // 初始配置:默认无减免(固定金额 0 元) const merchantReductionConfig = ref({ type: 'fixed_amount', fixedAmount: 0 }); //使用积分数量 const userPoints = ref(0); function setUserPoints(newval) { userPoints.value = newval } //新客立减 const newUserDiscount = ref(0); // 订单额外配置 const orderExtraConfig = computed(() => ({ // 引用扩展后的商家减免配置 merchantReduction: merchantReductionConfig.value, additionalFee: 0, pointDeductionRule: pointDeductionRule.value, seatFeeConfig: seatFeeConfig.value, currentStoreId: '', userPoints: userPoints.value, isMember: useVipPrice.value, memberDiscountRate: 1, newUserDiscount: newUserDiscount.value })); // 营销活动列表 const activityList = computed(() => { return []; }); // 优惠券列表 const backendCoupons = ref([]) function setCoupons(cps) { console.log('setCoupons', cps); backendCoupons.value = cps; } // 商品加入购物车顺序 const cartOrder = ref({}); // 订单费用汇总 const orderCostSummary = computed(() => { allGoods.value = getAllGoodsList() console.log('allGoods.value',allGoods.value); const costSummary = OrderPriceCalculator.calculateOrderCostSummary( allGoods.value, dinnerType.value, backendCoupons.value, activityList.value, orderExtraConfig.value, cartOrder.value, new Date() ); return costSummary; }); const goodsIsloading = ref(true); //商品数据Map const goodsMap = reactive({}) //获取商品数据 async function goodsInit() { goodsIsloading.value = true; //获取招牌菜商品 const hotres = await productminiApphotsquery(); for (let product of hotres) { setGoodsMap(product.id, product) } //获取分组商品 const groupres = await APIgroupquery() for (let group of groupres) { for (let product of group.productList) { setGoodsMap(product.id, product) } } allGoods.value = getAllGoodsList() console.log('allGoods.value ',allGoods.value ); goodsIsloading.value = false } function setGoodsMap(product_id, data) { goodsMap[product_id] = data; } //websocket回执 const websocketsendMessage = (data) => { uni.$u.debounce(sendMessage(data), 500) } const isLoading = ref(true); function getProductDetails(v) { const goods = goodsMap[v.product_id] if (!goods) { return undefined } let skuData = undefined; skuData = goods?.skuList.find((sku) => sku.id == v.sku_id); if (skuData) { return { ...v, productId: v.product_id, salePrice: skuData ? skuData.salePrice : 0, price: skuData ? skuData.salePrice : 0, memberPrice: skuData ? skuData.memberPrice : 0, coverImg: goods.coverImg, productImg: goods.coverImg, name: goods.name, productName: goods.name, specInfo: skuData.specInfo, packFee: goods.packFee || 0, type: goods.type, skuData, skuName: skuData.name, num: v.number * 1 } } else { return undefined } } // 用于记录已经处理过的消息的 msg_id const processedMessageIds = new Set(); //购物车商品信息补全初始化 function cartsGoodsInfoInit(arr) { carts.value = arr.map(v => { return getProductDetails(v) }).filter(v => v) } //收到socket消息时对购物车进行处理 async function onMessage(Message) { if (Message) { // 心跳返回 过滤 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); const msgData = Message.data // 初始化 if (Message.operate_type == "init") { console.log('carts init', msgData); cartsGoodsInfoInit(msgData) uni.hideLoading(); isLoading.value = false; } // 清空购物车 if (Message.operate_type == 'cleanup') { carts.value = [] } // 删除除购物车 if (Message.operate_type == 'del' && Message.status == 1) { // 优化:使用可选链操作符避免报错 carts.value = carts.value.filter(item => item.id !== msgData?.id); } // 添加或者减少购物后返回 if (Message.operate_type == 'add' || Message.operate_type == 'edit') { const index = carts.value.findIndex((v => v.id == msgData.id)) if (index !== -1) { carts.value[index] = getProductDetails(msgData); } else { carts.value.push(getProductDetails(msgData)); } } // 历史订单 if (Message.operate_type == 'clearOrder') {} // 购物车数据更新从新请求 if (Message.type == 'product' && Message.data_type == 'product_update' && Message .operate_type == 'product_update') { await goodsInit() await cartsGoodsInfoInit() } // 提示 if (Message.status == 0 && Message.type != 'no_suit_num') { uni.showToast({ title: Message.msg, icon: "none" }) } if (Message.type == 'no_suit_num') { uni.showModal({ title: '提示', showCancel: false, content: '此商品库存不足起售数量!', success: async (data) => { } }); } } } //购物车数据 const carts = ref([]) //历史订单数据 const oldOrder = ref({ detailMap: {}, originAmount: 0 }) function setOldOrder(data) { oldOrder.value = data allGoods.value=getAllGoodsList() } // 会员信息 const orderVIP = ref(uni.cache.get('orderVIP') || { isVip: false }) function updateData(key, newval) { if (key === 'orderVIP') { uni.cache.set('orderVIP', newval) return orderVIP.value = newval } if (key === 'shopInfo') { uni.cache.set('shopInfo', newval) return shopInfo.value = newval } } //是否使用会员价 const useVipPrice = computed(() => { const isUse = (orderVIP.value.isVip && shopInfo.value.isMemberPrice) ? true : false return isUse }) function currentCalcMpneyNumber(item) { const n = item.number - (item.returnNum || 0) return n <= 0 ? 0 : n } //历史订单商品价格总和 const oldOrderMoney = computed(() => { let total = 0 for (let i in oldOrder.value.detailMap) { total += oldOrder.value.detailMap[i].reduce((prve, cur) => { if (cur.isGift) { return prve + 0 } const discount_sale_amount = cur.discount_sale_amount * 1 || 0 const memberPrice = cur.skuData ? (cur.skuData.memberPrice || cur.skuData .salePrice) : 0 const price = (discount_sale_amount || cur.salePrice || 0) const number = currentCalcMpneyNumber(cur) return prve + (number <= 0 ? 0 : number) * (discount_sale_amount || (useVipPrice .value ? memberPrice : price)) }, 0) } return total }) //当前购物车总价格 const totalPrice = computed(() => { const money = carts.value.reduce((prve, cur) => { const memberPrice = cur.memberPrice || cur.salePrice const price = useVipPrice.value ? memberPrice : cur.salePrice; const curMoney = price * currentCalcMpneyNumber(cur) return prve + curMoney }, 0) return money }) // 霸王餐购物车原价,不享受任何优惠 const totalOriginPrice = computed(() => { const money = carts.value.reduce((prve, cur) => { const curMoney = cur.salePrice * currentCalcMpneyNumber(cur) return prve + curMoney }, 0) return money }) //返回打包数量(称重商品打包数量最大为1) function returnCartPackNumber(cur) { const maxReturnNum = cur.number - (cur.returnNum || 0); let pack_number = cur.number; pack_number = (cur.product_type == 'weight' && pack_number > 1) ? 1 : pack_number; pack_number = Math.min(maxReturnNum, pack_number); pack_number = pack_number <= 0 ? 0 : pack_number return pack_number * 1 } //当前购物车打包费 const totalPackFee = computed(() => { const money = carts.value.reduce((prve, cur) => { const curMoney = (cur.packFee || 0) * currentCalcMpneyNumber(cur) return prve + curMoney }, 0) return money }) //打包费 const packFee = computed(() => { const nowPackFee = carts.value.reduce((acc, cur) => { return acc + (cur.packFee || 0) * returnCartPackNumber(cur) }, 0) let oldPackfee = 0; for (let i in oldOrder.value.detailMap) { oldPackfee += oldOrder.value.detailMap[i].reduce((prve, cur) => { return prve + (cur.packFee || 0) * returnCartPackNumber(cur) }, 0) } return nowPackFee + oldPackfee }) //购物车是否为空 const isEmpty = computed(() => { return !carts.value || carts.value.length <= 0 }) // 计算向上取整 const roundUpToTwoDecimals = (num, i) => { // 先将数字乘以 100 并转换为字符串保留足够的小数位 let temp = (num * 100).toFixed(10); // 向上取整 let rounded = null if (i == 'upward') { rounded = Math.ceil(parseFloat(temp)); } else { rounded = Math.floor(parseFloat(temp)); } // 再除以 100 得到保留两位小数的结果 return rounded / 100; }; // 精确计算函数 const preciseCalculation = (num1, num2) => { // 将数字转换为整数,乘以 100 以保留两位小数 const int1 = BigInt(Math.round(num1 * 100)); const int2 = BigInt(Math.round(num2 * 100)); // 执行乘法运算 const result = int1 * int2; // 再除以 10000 以还原为原来的小数 return Number(result) / 10000; }; // 计算购物车商品总价格 const getTotalTotalPrices = (matchedProducts, isBwc = true) => { if (!matchedProducts || !Array.isArray(matchedProducts)) { return 0; } // 购物车总数价格 console.log('isBwc'); console.log(isBwc); let cart = matchedProducts.reduce((total, item) => { if (isBwc === true) { return total + (parseFloat(item.price) * parseFloat(item.num - item.returnNum)); } // 是否启用会员价 0否1是 if (useVipPrice.value) { // memberPrice会员价 return total + (parseFloat(item.memberPrice || item.price) * parseFloat(item .num - item .returnNum)); } else { // salePrice销售价 return total + (parseFloat(item.price) * parseFloat(item.num - item.returnNum)); } }, 0); cart = cart.toFixed(2) console.log(parseFloat(cart)) return parseFloat(cart); }; // 计算商品卷所选择的总价格 const getTotalProductroll = (matchedProducts) => computed(() => { if (!matchedProducts || !Array.isArray(matchedProducts)) { return 0; } // 购物车总数价格 let cart = matchedProducts.reduce((total, item) => { // 是否启用会员价 0否1是 if (useVipPrice.value) { // memberPrice会员价 return total + parseFloat(item.memberPrice || item.price) } else { // salePrice销售价 return total + parseFloat(item.price) } }, 0); // 向上取整并保留两位小数 let result = roundUpToTwoDecimals(cart, 'upward') return result; }); // 桌位置 const getTotalSeatcharge = (seatNum) => computed(() => { // 是否免除桌位费 0 否 1 是 let cart = 0 if (uni.cache.get('ordershopUserInfo').isTableFee == 0 && seatNum) { cart = parseFloat(seatNum) * parseFloat(uni.cache.get('ordershopUserInfo').tableFee) } // 向下取整并保留两位小数 let result = roundUpToTwoDecimals(cart, 'downward') return result; }); // 计算购物车总打包费用(向下取整并保留两位小数) const getTotalPackFee = (cartList) => computed(() => { const total = cartList.reduce((sum, item) => { return sum + (parseFloat(item.packAmount) * (parseFloat(item.packNumber) || ( parseFloat(item.num) - parseFloat(item.returnNum)))); }, 0); // 向下取整并保留两位小数 let result = roundUpToTwoDecimals(total, 'downward') return result; }); function clearOrderConfig(){ console.log('clearOrderConfig'); backendCoupons.value=[]; allGoods.value=[]; carts.value=[] seatFeeConfig.value.personCount=uni.cache.get('dinersNum') || 0; dinnerType.value='dine-in'; userPoints.value=0 } return { getTotalPackFee, getTotalSeatcharge, getTotalTotalPrices, getTotalProductroll, carts, isEmpty, setGoodsMap, goodsMap, goodsIsloading, goodsInit, onMessage, totalPrice, totalPackFee, updateData, useVipPrice, totalOriginPrice, orderCostSummary, setCoupons, userPoints, setUserPoints, setPointDeductionRule, setOldOrder, //优惠券列表 backendCoupons, allGoods, //就餐类型 dinnerType, setDinnerType, setSeatFeeConfig, seatFeeConfig, shopInfo, //新客立减数据 consumeDiscount, //新客立减金额 newUserDiscount, getAllGoodsList, //清空配置 clearOrderConfig }; } );