cashier-web/src/store/modules/carts.ts

727 lines
22 KiB
TypeScript
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.

import { store } from "@/store";
import WebSocketManager, { type ApifoxModel, msgType } from "@/utils/websocket";
import orderApi from "@/api/order/order";
import { useUserStoreHook } from "@/store/modules/user";
import { customTruncateToTwoDecimals } from '@/utils/tools'
import productApi from "@/api/product/index";
const shopUser = useUserStoreHook();
export interface CartsState {
id: string | number;
[property: string]: any;
}
export const useCartsStore = defineStore("carts", () => {
//选择用户
const vipUser = ref<{ id?: string | number, isVip?: boolean }>({});
function changeUser(user: any) {
vipUser.value = user;
}
//就餐类型 dine-in take-out
let dinnerType = ref<string>('dine-in');
//是否启用会员价
const useVipPrice = computed(() => {
return (shopUser.userInfo.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 = useStorage<any[]>("carts", []);
//历史订单数据
const oldOrder = useStorage<any>("Instead_olold_order", {
detailMap: [],
originAmount: 0
});
//代客下单页面商品缓存
const goods = useStorage<any[]>("Instead_goods", []);
async function getGoods(query: any) {
const res = await productApi.getPage({
page: 1,
size: 999,
status: "on_sale",
...query,
});
goods.value = res.records;
setGoodsMap(goods.value)
}
function setGoodsMap(goods: any[]) {
for (let item of goods) {
goodsMap[item.id] = item;
}
}
//赠菜
const giftList = useStorage<any[]>("giftList", []);
let goodsMap: { [key: string]: any } = useStorage('Instead_goods_map', {});
//当前选中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)
})
//打包数量
const packNum = computed(() => {
const nowCartNumber = list.value.reduce((acc: number, cur: any) => {
return acc + cur.pack_number * 1
}, 0)
const giftNumber = giftList.value.reduce((acc: number, cur: any) => {
return acc + cur.pack_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.pack_number
}, 0)
}
return nowCartNumber + giftNumber + oldNumber
})
//打包费
const packFee = computed(() => {
const nowPackFee = list.value.reduce((acc: number, cur: any) => {
return acc + (cur.packFee || 0) * cur.pack_number
}, 0)
const giftPackFee = giftList.value.reduce((acc: number, cur: any) => {
return acc + (cur.packFee || 0) * cur.pack_number
}, 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) * cur.pack_number
}, 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 + 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 = list.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;
if (dinnerType.value == 'take-out') {
pack_number = newNumber
}
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
}
if (cart.is_gift) {
isSelGift.value = true
} else {
isSelGift.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: '',
}
//当前购物车直接添加
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 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, 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) {
return ElMessage.error('价格不能为0')
}
const msg = { ...cart, [key]: val }
if (key == 'number' && dinnerType.value == 'take-out') {
msg.pack_number == val
}
sendMessage('edit', msg);
}
// 更改全部商品打包状态
function changePack(is_pack: number | string) {
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 })
if (res) {
setOldOrder(res)
}
}
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 })
return {
...v,
...skuData,
placeNum: v.placeNum,
number: v.num,
id: v.id,
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
}
})
}
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: [] }
}
// 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) {
return ElMessage.error(msg.message || '操作失败')
}
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 === "manage_init") {
isLinkFinshed.value = true
// 设置单价
list.value = msg.data.filter((v: Record<string, any>) => {
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<string, any>) => {
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 = 'manage_' + msg.operate_type
}
if (msg.operate_type === "manage_add") {
if (list.value.find(v => v.id == msg.data.id)) {
return ElMessage.warning(msg.message || '该商品已存在')
}
const skuData = getProductDetails({ product_id: msg.data.product_id, sku_id: msg.data.sku_id })
const newGoods = { ...skuData, ...msg.data }
console.log('newGoods', newGoods)
list.value.push(newGoods)
return ElMessage.success(msg.message || '添加成功')
}
if (msg.operate_type === "manage_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 === "manage_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)
}
return ElMessage.success(msg.message || '删除成功')
}
if (msg.operate_type === "manage_cleanup") {
nowCartsClear()
getOldOrder(msg.data.table_code)
}
if (msg.operate_type === "batch") {
concocatSocket({ ...$initParams, table_code: table_code.value })
}
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 {
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
};
});
export function useCartsStoreHook() {
return useCartsStore(store);
}