import { computed, reactive, ref } from "vue"; import WebSocketManager, { type ApifoxModel, msgType } from "@/common/js/carts-websocket"; import { productminiApphotsquery, APIgroupquery, APIminiAppinfo, APIminiAppskuinfo } from "@/common/api/product/product.js"; const shopInfo = uni.cache.get('shopInfo') || { isMemberPrice: false } export interface CartsState { id : string | number; [property : string] : any; } import { defineStore } from 'pinia' import { isProductAvailable, goodsInitParamsFull } from '@/utils/product.js' function ElMessage() { } export const useCartsStore = defineStore("carts", () => { //选择用户 const vipUser = ref<{ id ?: string | number, isVip ?: boolean }>(uni.cache.get('orderVIP') || {}); function changeUser(user : any) { vipUser.value = user; } //就餐类型 dine-in take-out let dinnerType = ref('dine-in'); //是否启用会员价 const useVipPrice = computed(() => { return (shopInfo.isMemberPrice && vipUser.value.id && vipUser.value.isVip) ? true : false }) //台桌id // const table_code = useStorage('Instead_table_code', ''); const table_code = ref('') //购物车是否初始化连接加载完成 const isLinkFinshed = ref(false) //当前购物车数据 const list = ref([]); //历史订单数据 // const oldOrder = useStorage("Instead_olold_order", { // detailMap: [], // originAmount: 0 // }); const oldOrder = ref({ detailMap: [], originAmount: 0 }) //代客下单页面全部商品缓存,包括招牌菜和分组 const goods = ref([]) const hotgoods = ref([]) const groupGoods = ref([]) async function getGoods(query : any) { // 招牌菜 const hotsRes = await productminiApphotsquery({ ...query, }); //分组 const groupGoodsRes = await APIgroupquery({ ...query, }); hotgoods.value = hotsRes.map(product => { return goodsInitParamsFull(product) }) groupGoods.value = groupGoodsRes.map(v => { return { ...v, productList: v.productList.map(product => { return goodsInitParamsFull(product) }) } }) goods.value = [...hotsRes, ...groupGoodsRes.reduce((prve, cur) => { prve.push(...cur.productList) return prve }, [])] setGoodsMap(goods.value) } function setGoodsMap(goods : any[]) { for (let item of goods) { goodsMap[item.id] = item; } } //赠菜 const giftList = ref([]) let goodsMap : { [key : string] : any } = reactive({}); //当前选中cart let selListIndex = ref(-1); //当前选中商品是否是赠菜 const isSelGift = ref(false); //当前选中是否是历史订单 const isOldOrder = ref(false); //选中历史订单中的第几次下单 const selPlaceNum = ref(-1); const defaultCart = { id: '', number: 0, } //购物车是否为空 const isEmpty = computed(() => { return list.value.length === 0 && giftList.value.length === 0 }) //当前购物车选中数据 const selCart = computed(() => { if (isOldOrder.value && selPlaceNum.value >= 0) { return oldOrder.value.detailMap[selPlaceNum.value][selListIndex.value] } if (isSelGift.value) { return giftList.value[selListIndex.value] || defaultCart } return list.value[selListIndex.value] || defaultCart }) //当前购物车选中对应商品数据 const selGoods = computed(() => { return goodsMap[selCart.value.product_id] }) //当前选中购物车数据是否是可选套餐商品 const isCanSelectGroup = computed(() => { if (!selGoods.value) { return false } return selGoods.value.type == 'package' && selGoods.value.groupType == 1 }) function returnOneGoodsTotalMoney(cur : any) { const memberPrice = cur.memberPrice || cur.salePrice const total = cur.number * (useVipPrice.value ? memberPrice : cur.salePrice) if (cur.type == 'weight') { return customTruncateToTwoDecimals(total) } else { return total } } //赠菜总价 const giftMoney = computed(() => { let oldGiftMoney = 0 for (let i in oldOrder.value.detailMap) { oldGiftMoney += oldOrder.value.detailMap[i].filter((v : any) => v.isGift).reduce((prve : number, cur : any) => { const memberPrice = cur.memberPrice || cur.salePrice return prve + cur.number * (useVipPrice.value ? memberPrice : cur.salePrice) }, 0) } const nowTotal = giftList.value.reduce((acc : number, cur : any) => { const memberPrice = cur.memberPrice || cur.salePrice return acc + cur.number * (useVipPrice.value ? memberPrice : cur.salePrice) }, 0) return (nowTotal + oldGiftMoney) }) //返回打包数量(称重商品打包数量最大为1) function returnCartPackNumber(cur : any) { const maxReturnNum = cur.number - (cur.returnNum || 0); let pack_number = (dinnerType.value == 'take-out' ? cur.number : cur.pack_number * 1); 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 packNum = computed(() => { const nowCartNumber = list.value.reduce((acc : number, cur : any) => { return acc + returnCartPackNumber(cur) }, 0) const giftNumber = giftList.value.reduce((acc : number, cur : any) => { return acc + returnCartPackNumber(cur) }, 0) let oldNumber = 0 for (let i in oldOrder.value.detailMap) { oldNumber += oldOrder.value.detailMap[i].reduce((prve : number, cur : any) => { return prve + returnCartPackNumber(cur) }, 0) } return nowCartNumber + giftNumber + oldNumber }) //打包费 const packFee = computed(() => { const nowPackFee = list.value.reduce((acc : number, cur : any) => { return acc + (cur.packFee || 0) * returnCartPackNumber(cur) }, 0) const giftPackFee = giftList.value.reduce((acc : number, cur : any) => { 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 : number, cur : any) => { return prve + (cur.packFee || 0) * returnCartPackNumber(cur) }, 0) } return nowPackFee + giftPackFee + oldPackfee }) //会员优惠 const vipDiscount = computed(() => { if (!useVipPrice.value) { return 0 } const listTotal = list.value.reduce((acc : number, cur : any) => { const n = (cur.salePrice * 1 - cur.memberPrice * 1) * cur.number return acc + (n <= 0 ? 0 : n) }, 0) const giftTotal = giftList.value.reduce((acc : number, cur : any) => { const n = (cur.salePrice * 1 - cur.memberPrice * 1) * cur.number return acc + (n <= 0 ? 0 : n) }, 0) let oldTotal = 0; for (let i in oldOrder.value.detailMap) { oldTotal += oldOrder.value.detailMap[i].reduce((prve : number, cur : any) => { const n = (cur.salePrice * 1 - cur.memberPrice * 1) * cur.number return prve + (n <= 0 ? 0 : n) }, 0) } return listTotal + giftTotal + oldTotal }) //单品改价优惠 const singleDiscount = computed(() => { const listTotal = list.value.reduce((acc : number, cur : any) => { if (cur.discount_sale_amount * 1 <= 0) { return acc + 0 } const originPrice = useVipPrice.value ? (cur.memberPrice || cur.salePrice) : cur.salePrice const n = (originPrice * 1 - cur.discount_sale_amount * 1) * cur.number return acc + (n <= 0 ? 0 : n) }, 0) return listTotal }) // 优惠 const yiyouhui = computed(() => { const youhui = giftMoney.value * 1 + vipDiscount.value * 1 + singleDiscount.value * 1 if (youhui > 0) { return '已优惠¥' + youhui.toFixed(2) } return '' }) //历史订单价格 const oldOrderMoney = computed(() => { let total = 0 for (let i in oldOrder.value.detailMap) { total += oldOrder.value.detailMap[i].reduce((prve : number, cur : any) => { 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 = (cur.number - cur.returnNum) return prve + (number <= 0 ? 0 : number) * (discount_sale_amount || (useVipPrice.value ? memberPrice : price)) }, 0) } return total }) //支付总价 const payMoney = computed(() => { const money = list.value.reduce((acc : number, cur : any) => { const discount_sale_amount = cur.discount_sale_amount * 1 || 0 const memberPrice = cur.skuData ? (cur.skuData.memberPrice || cur.skuData.salePrice) : 0 const price = (cur.discount_sale_amount * 1 || cur.salePrice || 0) return acc + cur.number * (discount_sale_amount || (useVipPrice.value ? memberPrice : price)) }, 0) return (money + packFee.value * 1 + oldOrderMoney.value * 1).toFixed(2) }) //只算商品的总价 const goodsTotal = computed(() => { const money = list.value.reduce((acc : number, cur : any) => { const discount_sale_amount = cur.discount_sale_amount * 1 || 0 const memberPrice = cur.skuData ? (cur.skuData.memberPrice || cur.skuData.salePrice) : 0 const price = (cur.discount_sale_amount * 1 || cur.salePrice || 0) return acc + cur.number * (discount_sale_amount || (useVipPrice.value ? memberPrice : price)) }, 0) return (money + oldOrderMoney.value * 1).toFixed(2) }) //总计数量 const totalNumber = computed(() => { const cartNumber = list.value.reduce((acc : number, cur : any) => { return acc + cur.number * 1 }, 0) const giftNumber = giftList.value.reduce((acc : number, cur : any) => { return acc + cur.number * 1 }, 0) let oldNumber = 0 for (let i in oldOrder.value.detailMap) { oldNumber += oldOrder.value.detailMap[i].reduce((prve : number, cur : any) => { return prve + cur.number * 1 }, 0) } return cartNumber + giftNumber + oldNumber }) function changeNumber(step : number, item : CartsState) { if (item.number * 1 + step <= 0) { del(item); return; } const newNumber = item.number * 1 + step * 1; let pack_number = newNumber < item.pack_number ? (item.pack_number * 1 + step * 1) : item.pack_number * 1; if (dinnerType.value == 'take-out') { pack_number = newNumber } if (item.product_type == 'weight' && item.pack_number * 1 >= 1) { pack_number = 1 } update({ ...item, number: newNumber, pack_number }); } function changeSelCart(cart : CartsState) { console.log(cart) if (!cart.id) { return } if (cart.placeNum) { selPlaceNum.value = cart.placeNum isOldOrder.value = true console.log(oldOrder.value.detailMap[cart.placeNum]) selListIndex.value = oldOrder.value.detailMap[cart.placeNum].findIndex((item : CartsState) => { return item.id == cart.id }) return } selPlaceNum.value = -1; isOldOrder.value = false; if (cart.is_gift) { isSelGift.value = true selListIndex.value = giftList.value.findIndex((item : CartsState) => item.id === cart.id); console.log(selListIndex.value) } else { isSelGift.value = false selListIndex.value = list.value.findIndex((item : CartsState) => item.id === cart.id); } } const basic_msg = { number: 1, is_gift: 0, is_temporary: 0, discount_sale_amount: 0, discount_sale_note: "", is_print: 1, pro_group_info: '', is_wait_call: 0, product_name: "", remark: "", sku_id: '', product_type: '', suitNum: 1 } //当前购物车直接添加 function cartsPush(data : any) { sendMessage('add', { ...basic_msg, ...data }); } function add(data : any) { const msg = { ...basic_msg, ...data } const hasCart = list.value.find((cartItem) => { return cartItem.product_id == msg.product_id && cartItem.sku_id == msg.sku_id; }); if (hasCart) { update({ ...hasCart, ...msg, number: hasCart.number * 1 + msg.number * 1 }) } else { console.log(msg); sendMessage('add', msg); } } // 换桌 function changeTable(newVal : string | undefined) { table_code.value = `${newVal}`; $initParams.table_code = newVal concocatSocket() } //转桌 function rotTable(newVal : string | number, cart_id = []) { sendMessage('rottable', { new_table_code: newVal, table_code: table_code.value, cart_id }); } //清空历史订单 function clearHistory() { sendMessage('clearOrder', {}); } function del(data : any) { sendMessage('del', { id: data.id }); } function update(data : any) { console.log(data); const suitNum = data.skuData ? (data.skuData.suitNum || 1) : 1; if (data.number * 1 < suitNum * 1) { return sendMessage('del', data); } const pack_number = dinnerType.value == 'take-out' ? data.number : data.pack_number sendMessage('edit', { ...data, suitNum, pack_number }); } function updateTag(key : string, val : any, cart : CartsState = selCart.value) { const skuData = cart.skuData || { suitNum: 1 } if (cart.number * 1 < skuData.suitNum * 1) { return sendMessage('del', cart); } console.log(key, val) if (key == 'discount_sale_amount' && val * 1 <= 0) { // ElMessage.error('价格不能为0!') return } const msg = { ...cart, [key]: val } if (key == 'number' && dinnerType.value == 'take-out') { msg.pack_number == val msg.suitNum == skuData.suitNum } sendMessage('edit', msg); } // 更改全部商品打包状态 function changePack(is_pack : number | string) { if (!isEmpty.value) { sendMessage('batch', { is_pack }); } } function clear() { sendMessage('cleanup', {}); } function dataReset() { selListIndex.value = -1; selPlaceNum.value = 1 isOldOrder.value = false isSelGift.value = false list.value = []; giftList.value = []; oldOrder.value = { detailMap: [], originAmount: 0 } vipUser.value = {} } function nowCartsClear() { if (selPlaceNum.value == 1) { selListIndex.value = -1; } list.value = []; giftList.value = []; } // 寻找套餐商品sku interface GroupSnap { goods : { [key : string] : any }[]; } function findInGroupSnapSku(groupSnap : GroupSnap[], sku_id : string | number) { for (let i in groupSnap) { const sku = groupSnap[i].goods.find(v => v.sku_id == sku_id) if (sku) { return sku } } } //获取历史订单 async function getOldOrder(table_code : string | number) { const res = await orderApi.getHistoryList({ tableCode: table_code }) console.log('getOldOrder'); console.log(res); if (res) { setOldOrder(res) } else { oldOrder.value = { detailMap: [], originAmount: 0 } } } function getProductDetails(v : { product_id : string, sku_id : string }) { const goods = goodsMap[v.product_id] if (!goods) { return undefined } let skuData = undefined; skuData = goods?.skuList.find((sku : { id : string, salePrice : number }) => sku.id == v.sku_id); // if (goods.type == 'package') { // //套餐商品 // const SnapSku = findInGroupSnapSku(goods.groupSnap, v.sku_id) // skuData = { ...SnapSku, salePrice: SnapSku ? SnapSku.price : 0 } // } else { // skuData = goods?.skuList.find((sku: { id: string, salePrice: number }) => sku.id == v.sku_id); // } skuData = goods?.skuList.find((sku : { id : string, salePrice : number }) => sku.id == v.sku_id); if (skuData) { return { salePrice: skuData ? skuData.salePrice : 0, memberPrice: skuData ? skuData.memberPrice : 0, coverImg: goods.coverImg, name: goods.name, specInfo: skuData.specInfo, packFee: goods.packFee || 0, type: goods.type, skuData } } else { return undefined } } function returnDetailMap(data : any) { const newData : { [key : string] : any } = {} for (let i in data) { newData[i] = data[i].map((v : any) => { const skuData = getProductDetails({ product_id: v.productId, sku_id: v.skuId }) console.log(skuData) console.log(v) return { ...v, ...skuData, skuData: { ...skuData, salePrice: v.price, memberPrice: v.memberPrice }, placeNum: v.placeNum, number: v.num, id: v.id, salePrice: v.price, memberPrice: v.memberPrice, pack_number: v.packNumber, discount_sale_amount: v.discountSaleAmount * 1 || 0, is_print: v.isPrint, is_wait_call: v.isWaitCall, is_gift: v.isGift, is_temporary: v.isTemporary, discount_sale_note: v.discountSaleNote, product_name: v.productName, sku_name: v.skuName, sku_id: v.skuId, product_type: v.productType, packFee: v.packAmount, } }) } console.log('newData', newData) return newData } function setOldOrder(data : any) { oldOrder.value = { ...data, detailMap: returnDetailMap(data.detailMap) } } let $initParams = {} as ApifoxModel /** * * @param initParams 购物车初始化参数 * @param $goodsMap 商品id对应的map * @param oldOrder 历史订单数据 */ async function init(initParams : ApifoxModel, $oldOrder : any | undefined) { // 商品id对应的数据map await getGoods({}) if ($oldOrder) { setOldOrder($oldOrder) } else { oldOrder.value = { detailMap: [], originAmount: 0 } } // console.log('oldOrder.detailMap', oldOrder.value.detailMap) // const cache_table_code = localStorage.getItem('cache_table_code'); // const randomTableCode = cache_table_code ? cache_table_code : ('APC' + (1000 + Math.floor(Math.random() * 9000))) if (initParams) { initParams.table_code = initParams.table_code ? initParams.table_code : '' table_code.value = initParams.table_code $initParams = initParams; } console.log($initParams) // localStorage.setItem('cache_table_code', table_code.value); concocatSocket($initParams) } function concocatSocket(initParams = $initParams) { console.log("初始化参数", initParams); WebSocketManager.subscribeToTopic(initParams, (msg) => { console.log("收到消息:", msg); if (msg.hasOwnProperty('status') && msg.status != 1) { if (msg.type === 'no_suit_num' && selListIndex.value != -1) { return uni.showModal({ title: '提示', showCancel: false, content: `${list.value[selListIndex.value].name}库存不足`, success() { if (res.confirm) { list.value.splice(selListIndex.value, 1) } } }) } uni.showToast({ title: msg.message || msg.msg || '操作失败', icon: 'none' }) return } if (msg && msg.data) { if (Array.isArray(msg.data) && msg.data.length && msg.data[0].table_code) { table_code.value = msg.data[0].table_code } if (msg.data.table_code) { table_code.value = table_code.value ? table_code.value : msg.data.table_code } if (msg.table_code) { table_code.value = table_code.value ? table_code.value : msg.table_code } } // 初始化 if (msg.operate_type === "init") { isLinkFinshed.value = true // 设置单价 list.value = msg.data.filter((v : Record) => { if (v.is_temporary) { return v } const skuData = getProductDetails({ product_id: v.product_id, sku_id: v.sku_id }) if (skuData) { (Object.keys(skuData) as (keyof typeof skuData)[]).forEach((key) => { v[key] = skuData[key]; }); } else { // del({ id: v.id }) return false } return !v.is_gift }) giftList.value = msg.data.filter((v : Record) => { if (v.is_temporary) { return v && v.is_gift } const skuData = getProductDetails({ product_id: v.product_id, sku_id: v.sku_id }) if (skuData) { (Object.keys(skuData) as (keyof typeof skuData)[]).forEach((key) => { v[key] = skuData[key]; }); } else { del({ id: v.id }) return false } return v.is_gift }) } //广播 if (msg.type === "bc") { msg.operate_type = 'shopping_' + msg.operate_type } if (msg.operate_type === "add") { if (list.value.find(v => v.id == msg.data.id)) { console.error('该商品已存在') // ElMessage.warning(msg.message || '该商品已存在') return } const skuData = getProductDetails({ product_id: msg.data.product_id, sku_id: msg.data.sku_id }) if (skuData || msg.data.is_temporary) { const newGoods = { ...skuData, ...msg.data } console.log('新增商品', newGoods) list.value.push(newGoods) console.log('添加成功') // ElMessage.success(msg.message || '添加成功') return }else{ console.error('未找到对应商品'); } } if (msg.operate_type === "edit") { const newCart = msg.data const index = list.value.findIndex((item) => item.id === newCart.id) const giftIndex = giftList.value.findIndex((item) => item.id === newCart.id) const cartItem = list.value[index] || { is_gift: false }; const giftItem = giftList.value[giftIndex]; if (giftItem) { //操作赠菜 if (!newCart.is_gift) { giftList.value.splice(giftIndex, 1) list.value.push({ ...giftItem, ...newCart }) selListIndex.value = -1 } else { giftList.value[giftIndex] = { ...giftItem, ...newCart } } } if (cartItem) { //操作非赠菜 if (newCart.is_gift) { list.value.splice(index, 1) giftList.value.push({ ...cartItem, ...newCart }) selListIndex.value = -1 } else { list.value[index] = { ...cartItem, ...newCart } } } // ElMessage.success(msg.message || '修改成功') } if (msg.operate_type === "del") { const cartId = Array.isArray(msg.data) ? msg.data[0].id : msg.data.id const listIndex = list.value.findIndex((item) => item.id == cartId) if (listIndex > -1) { list.value.splice(listIndex, 1) } const giftIndex = giftList.value.findIndex((item) => item.id == cartId) if (giftIndex > -1) { giftList.value.splice(giftIndex, 1) } // ElMessage.success(msg.message || '删除成功') return } if (msg.operate_type === "cleanup") { nowCartsClear() getOldOrder(msg.data.table_code) } if (msg.operate_type === "batch") { concocatSocket({ ...$initParams, table_code: table_code.value }) } if (msg.operate_type === "clearOrder") { getOldOrder(msg.data.table_code) } if (msg.operate_type === "product_update") { console.log('商品更新') init($initParams, oldOrder.value) } }); } function disconnect() { sendMessage('disconnect', undefined) } const delArr = ['skuData', 'coverImg', 'specInfo', 'placeNum', 'update_time', 'create_time', 'packFee', 'memberPrice', 'type'] function sendMessage(operate_type : msgType, message : any) { const msg = { ...message, operate_type: operate_type, table_code: table_code.value } for (let i in delArr) { delete msg[delArr[i]] } console.log('send msg', msg) WebSocketManager.sendMessage(msg); } return { clearHistory, disconnect, dinnerType, changePack, giftMoney, goodsTotal, isLinkFinshed, setOldOrder, singleDiscount, vipDiscount, dataReset, useVipPrice, changeUser, packNum, packFee, isOldOrder, oldOrder, isCanSelectGroup, goods, selGoods, cartsPush, table_code, updateTag, list, add, del, update, init, changeNumber, isEmpty, selCart, totalNumber, changeSelCart, payMoney, clear, yiyouhui, giftList, changeTable, rotTable, getGoods, setGoodsMap, hotgoods, groupGoods }; });