对接购物车

This commit is contained in:
gyq
2025-02-26 18:06:37 +08:00
parent 44144c5ac7
commit d3ed4ec8e6
27 changed files with 2589 additions and 1629 deletions

View File

@@ -8,20 +8,20 @@
</el-icon>
<el-text class="t">({{ pendingCartNum }})</el-text>
</div>
<div class="number" @click="takeFoodCodeRef.show()">
<el-text class="t">{{ masterId }}</el-text>
<div class="number" @click="SelectVipUserRef.show()">
<el-icon class="icon">
<UserFilled />
</el-icon>
<el-text class="t">选择会员</el-text>
</div>
<div class="select_user" @click="quickCashHandle"
v-if="!global.orderMemberInfo.telephone && !global.tableInfo.id">
<div class="left">
<el-icon class="icon">
<el-icon class="icon" style="color: var(--el-color-warning);">
<WalletFilled />
</el-icon>
<el-text class="t">快捷收银</el-text>
</div>
<el-icon class="arrow">
<ArrowRight />
</el-icon>
</div>
<div class="select_user" v-else @click="clearMember">
<div class="left">
@@ -45,7 +45,89 @@
</div>
<div class="shop_operation">
<div class="shop_list">
<template v-for="(arr, index) in cartList" :key="index">
<div class="table_info" v-if="goodsStore.tableInfo.name">
<div class="left">
<span>台桌{{ goodsStore.tableInfo.name }}</span>
<span>{{ goodsStore.tableInfo.num }}</span>
</div>
<div class="close" @click="goodsStore.selectTable()">
<el-icon class="icon">
<Close />
</el-icon>
</div>
</div>
<div class="item" :class="{ active: item.active }" v-for="(item, index) in goodsStore.cartList" :key="item.id"
@click="selectCartItemHandle(index)">
<div class="name_wrap">
<span>{{ item.product_name }}</span>
<template v-if="item.is_gift">
<div class="price">
<span class="dis" v-if="item.is_temporary">
{{ formatDecimal(+item.discount_sale_amount, 2, true) }}
</span>
<span class="dis" v-else>
{{ formatDecimal(+item.lowPrice, 2, true) }}
</span>
<span v-if="item.discount_sale_amount">
0.00
</span>
</div>
</template>
<template v-else>
<div class="price" v-if="item.is_temporary">
<span>
{{ formatDecimal(+item.discount_sale_amount, 2, true) }}
</span>
</div>
<div class="price" v-else>
<template v-if="+item.discount_sale_amount">
<span class="dis">
{{ formatDecimal(item.lowPrice, 2, true) }}
</span>
<span>
{{ formatDecimal(+item.discount_sale_amount, 2, true) }}
</span>
</template>
<span v-else>
{{ formatDecimal(+item.lowPrice, 2, true) }}
</span>
</div>
</template>
</div>
<div class="sku_list" v-if="item.sku_name">
<div class="tag" v-for="item in item.sku_name.split(',')">
{{ item }}
</div>
</div>
<div class="grooup_wrap" v-if="item.goods_type == 'package'">
{{ item.group_type == 0 ? '固定套餐' : '自选套餐' }}
<span>{{ item.group_text }}</span>
</div>
<div class="num">
<div class="left">
<div class="icon_item zen" v-if="item.is_gift">
<span class="t"></span>
</div>
<div class="icon_item bao" v-if="item.is_pack">
<span class="t"></span>
</div>
<!-- <div class="icon_item tui" v-if="item.status == 'return'">
<span class="t">退</span>
</div> -->
<div class="icon_item lin" v-if="item.is_temporary == 1">
<span class="t"></span>
</div>
<div class="icon_item zhe" v-if="item.discount_sale_amount > 0 && !item.is_temporary">
<span class="t"></span>
</div>
<div class="icon_item chu" v-if="item.is_print == 0">
<span class="t">免厨打印</span>
</div>
</div>
<el-text class="t">x{{ formatDecimal(+item.number, 2, true) }}</el-text>
</div>
</div>
<template v-for="(arr, index) in goodsStore.orderList" :key="index">
<el-divider v-if="arr.placeNum">{{ `${arr.placeNum}次下单` }}</el-divider>
<div class="item" :class="{ active: item.active }" :key="item.id" v-for="(item, i) in arr.info"
@click="selectCartItemHandle(item, index, i)">
@@ -64,14 +146,14 @@
</div>
<div class="grooup_wrap" v-if="item.proGroupInfo">
{{ item.groupType == 0 ? '固定套餐' : '自选套餐' }}
<span>{{ JSON.parse(item.proGroupInfo).map(item => item.proName).join('、') }}</span>
<span>{{JSON.parse(item.proGroupInfo).map(item => item.proName).join('、')}}</span>
</div>
<div class="num">
<div class="left">
<div class="icon_item zen" v-if="item.isGift == 'true'" @click="giftPackHandle('isGift', item)">
<div class="icon_item zen" v-if="item.is_gift" @click="giftPackHandle('isGift', item)">
<span class="t"></span>
</div>
<div class="icon_item bao" v-if="item.isPack == 'true'" @click="giftPackHandle('isPack', item)">
<div class="icon_item bao" v-if="item.is_pack" @click="giftPackHandle('isPack', item)">
<span class="t"></span>
</div>
<div class="icon_item tui" v-if="item.status == 'return'">
@@ -92,17 +174,16 @@
</div>
</template>
<div class="empty">
<el-empty description="请选择商品" v-if="!cartList.length" />
<el-empty description="请选择商品" v-if="!goodsStore.cartList.length" />
</div>
</div>
<!-- 购物车操作栏 -->
<cartOperation :item="cartListActiveItem" @confirm="(res) => addCart(res, 'edit')" @delete="delCartHandle"
@pending="pendingCart" @clearCart="clearCartHandle" @merging="showTableMerging" />
<cartOperation :item="cartListActiveItem" @confirm="" @delete="delCartHandle" @pending="pendingCart"
@merging="showTableMerging" @showPackage="e => goodsRef.showPackage(e)" />
</div>
<div class="footer">
<div class="top">
<div class="left" @click="allSelectedHandle"
v-if="JSON.parse(shopStore.info.eatModel).some(item => item == 'take-out')">
<div class="left" @click="allSelectedHandle" v-if="store.shopInfo.eatModel == 'take-out'">
<div class="selected">
<div class="selected_round" v-if="!allSelected"></div>
<el-icon class="icon" v-else>
@@ -113,16 +194,27 @@
</div>
<div class="left" v-else></div>
<div class="num-wrap">
<!-- {{ cartInfo.productNum || 0 }}种商品 -->
<el-text>{{
cartInfo.productSum || 0
}}</el-text>{{ formatDecimal(cartInfo.totalAmount || 0) }}
<div class="num_wrap_top">
<el-text>
{{ goodsStore.cartInfo.total }}
</el-text>{{ formatDecimal(goodsStore.cartInfo.totalAmount || 0) }}
</div>
<div class="num_wrap_btm">
<span v-if="goodsStore.cartInfo.gifNumberAmount">赠送{{ formatDecimal(goodsStore.cartInfo.gifNumberAmount
|| 0, 2, true)
}}</span>
<span v-if="goodsStore.cartInfo.gifNumberAmount && goodsStore.cartInfo.saleNumberAmount"></span>
<span v-if="goodsStore.cartInfo.saleNumberAmount">改价优惠{{
formatDecimal(goodsStore.cartInfo.saleNumberAmount
|| 0, 2, true)
}}</span>
</div>
</div>
</div>
<div class="btm">
<el-button icon="Edit" @click="remarkRef.show()"></el-button>
<div class="button">
<div class="btn" v-if="shopStore.info.registerType == 'restaurant'">
<div class="btn" v-if="store.shopInfo.registerType == 'restaurant'">
<el-button type="primary" style="width: 100%;" :disabled="!cartList.length" v-loading="createOrderLoading"
@click="createOrderHandle(0)">
<template v-if="!createOrderLoading">
@@ -130,9 +222,9 @@
<template v-else>下单中...</template>
</el-button>
</div>
<div class="btn" v-if="shopStore.info.registerType != 'restaurant' || cartList.length">
<el-button type="primary" style="width: 100%;" :disabled="!cartList.length" v-loading="createOrderLoading"
@click="createOrderHandle(1)">
<div class="btn" v-if="store.shopInfo.registerType != 'restaurant' || goodsStore.cartList.length">
<el-button type="primary" style="width: 100%;" :disabled="!goodsStore.cartList.length"
v-loading="createOrderLoading" @click="createOrderHandle(1)">
<template v-if="!createOrderLoading">
去结算</template>
<template v-else>下单中...</template>
@@ -144,7 +236,7 @@
</div>
<div class="shop_manage card">
<!-- 分类/商品列表 -->
<goods ref="goodsRef" :masterId="masterId" @success="addCart" @loading="cartLoading = true" />
<goods ref="goodsRef" @loading="cartLoading = true" />
<!-- ©银收客 v{{ packageData.version }} -->
</div>
</div>
@@ -155,10 +247,10 @@
<el-drawer v-model="membershow" :with-header="true" size="90%" title="选择会员">
<member :membershow="'1'"></member>
</el-drawer>
<takeFoodCode ref="takeFoodCodeRef" title="修改取餐号" placeholder="请输入取餐号" @success="takeFoodCodeSuccess" />
<!-- <takeFoodCode ref="takeFoodCodeRef" title="修改取餐号" placeholder="请输入取餐号" @success="takeFoodCodeSuccess" /> -->
<!-- 结算订单 -->
<settleAccount ref="settleAccountRef" :cart="cartList" :amount="cartInfo.totalAmount" :remark="remark"
:masterId="masterId" :orderInfo="orderInfo" @paySuccess="createCodeAjax(1)" />
:orderInfo="orderInfo" @paySuccess="createCodeAjax(1)" />
<!-- 快捷收银 -->
<fastCashier ref="fastCashierRef" type="0" />
<!-- 挂起订单 -->
@@ -166,7 +258,9 @@
<!-- 检查版本升级 -->
<updateDialog />
<!-- 合并/转桌 -->
<tableMerging ref="tableMergingRef" @success="addCart" />
<tableMerging ref="tableMergingRef" @success="" />
<!-- 选择会员 -->
<SelectVipUser ref="SelectVipUserRef" />
</template>
<script>
@@ -176,10 +270,10 @@ export default {
</script>
<script setup>
import { onMounted, ref } from "vue";
import { useRoute } from 'vue-router'
import { useUser } from "@/store/user.js";
import { useGlobal } from '@/store/global.js'
import SelectVipUser from "@/components/selectVipUser.vue";
import updateDialog from '@/components/updateDialog.vue'
import remarkModal from "@/components/remarkModal.vue";
import takeFoodCode from "@/components/takeFoodCode.vue";
@@ -190,35 +284,25 @@ import pendingCartModal from "@/views/home/components/pendingCartModal.vue";
import tableMerging from '@/views/home/components/tableMerging.vue'
import useStorage from '@/utils/useStorage'
import { formatDecimal } from '@/utils/index.js'
import {
createCart,
queryCart,
createCode,
packall,
delCart,
cartStatus,
clearCart,
createOrder,
} from "@/api/product";
import { orderChoseCount } from '@/api/table.js'
import { useGoods } from '@/store/goods.js'
import { queryShopInfo, staffPermission } from '@/api/user.js'
import { createOrder } from '@/api/order.js'
// 商品列表
import goods from "@/views/home/components/goods.vue";
import member from "@/views/member/index.vue";
import { ElMessage } from "element-plus";
import { useShop } from '@/store/shop.js'
import TableMerging from "./components/tableMerging.vue";
const shopStore = useShop()
const SelectVipUserRef = ref(null)
const goodsStore = useGoods()
const global = useGlobal()
const route = useRoute()
const membershow = ref(false);
const store = useUser();
@@ -242,8 +326,6 @@ const cartLoading = ref(false);
const orderInfo = ref({});
const createOrderLoading = ref(false);
// 取餐码
const masterId = ref("");
// 挂单量
const pendingCartNum = ref(0);
@@ -262,99 +344,35 @@ async function quickCashHandle() {
async function createOrderHandle(t = 0) {
try {
createOrderLoading.value = true;
await staffPermission('yun_xu_xia_dan')
const res = await createOrder({
masterId: masterId.value,
shopId: store.userInfo.shopId,
remark: remark.value,
vipUserId: global.orderMemberInfo.id || '',
tableId: global.tableInfo.qrcode || '',
type: t,
seatNum: global.tableInfo.num
});
createOrderLoading.value = false;
orderId: goodsStore.orderList.length ? goodsStore.orderList[0].id : '', // 订单id
shopId: store.shopInfo.id, // 店铺id
seatNum: goodsStore.tableInfo.num || 0, // 用餐人数
packFee: 0, // 打包费
originAmount: formatDecimal(goodsStore.cartInfo.totalAmount, 2, true), // 订单原金额(包含打包费+餐位费) 不含折扣价格
tableCode: goodsStore.cartList[0].table_code, // 台桌号
dineMode: store.shopInfo.eatModel, // 用餐方式
remark: remark.value, // 备注
placeNumplaceNum: goodsStore.orderList.length, // 下单次数
waitCall: 0,//是否叫号
userId: '', // 会员用户id
vipPrice: 0, // 会员价
})
// 订单数据
orderInfo.value = res;
if (shopStore.info.registerType == 'restaurant' && t == 0) {
ElMessage.success('下单成功')
queryCartAjax()
} else {
settleAccountRef.value.show();
}
// if (global.tableInfo.id && t == 0) {
// ElMessage.success('下单成功')
// global.setOrderTable({})
// createCodeAjax(1)
// } else {
// orderInfo.value = res;
// settleAccountRef.value.show();
// }
} catch (error) {
console.log(error);
createOrderLoading.value = false;
}
}
// 清空购物车
async function clearCartHandle() {
try {
await clearCart({
shopId: store.userInfo.shopId,
masterId: masterId.value,
tableId: global.tableInfo.qrcode || ''
});
cartListActiveItem.value = {}
queryCartAjax();
// 清除商品所有红点
goodsRef.value.clearDot()
goodsStore.orderInfo = res
settleAccountRef.value.show()
} catch (error) {
console.log(error);
}
createOrderLoading.value = false;
}
// 恢复挂单
async function pendingCartHandle(item) {
const nItem = { ...item };
if (cartList.value.length) {
// 当购物车有数据时,先挂起当前购物车
await pendingCart({ masterId: masterId.value });
}
masterId.value = nItem.masterId;
await pendingCart(nItem, false);
await queryCartAjax();
}
// 挂单
async function pendingCart(params, status = true) {
try {
cartLoading.value = true;
await cartStatus({
shopId: store.userInfo.shopId,
masterId: params.masterId,
status: status,
uuid: params.uuid,
vipUserId: global.orderMemberInfo.id || '',
tableId: global.tableInfo.qrcode || '',
orderId: params.orderId
});
if (status && cartList.value.length) {
await createCodeAjax();
setTimeout(() => {
cartLoading.value = false;
}, 500);
} else {
setTimeout(() => {
cartLoading.value = false;
}, 500);
}
} catch (error) {
cartLoading.value = false;
console.log(error);
}
}
// 删除购物车
@@ -362,7 +380,6 @@ async function delCartHandle(params) {
try {
cartLoading.value = true;
await delCart({
masterId: params.masterId,
cartId: params.id,
});
cartListActiveItem.value = {}
@@ -388,189 +405,19 @@ const allSelectedHandle = async () => {
await packall({
shopId: store.userInfo.shopId,
status: allSelected.value,
masterId: masterId.value,
});
queryCartAjax();
// 这里需要更新购物车
};
// 确认取餐号
async function takeFoodCodeSuccess(code) {
if (cartList.value.length) {
await pendingCart({
masterId: masterId.value,
uuid: cartList.value[0].uuid,
});
}
masterId.value = `#${code}`;
queryCartAjax();
}
// 从购物车选择商品
function selectCartItemHandle(row, index, i) {
cartList.value.map(item => {
item.info.map(val => {
if (val.id == row.id) {
val.active = true
cartListActiveItem.value = val
} else {
val.active = false
}
})
})
}
// 选择完规格开始添加购物车
async function addCart(params = {}, type = "add") {
console.log(params);
try {
cartLoading.value = true;
if (params.isTemporary) {
await createCodeAjax()
cartLoading.value = false;
} else {
let skuId = ''
if (params.skuList && params.skuList.length) {
skuId = params.skuList[0].id
} else {
skuId = type == "add" ? params.id : params.skuId
}
const res = await createCart({
productId: params.productId,
masterId: masterId.value,
tableId: global.tableInfo.qrcode || '',
vipUserId: global.orderMemberInfo.id || '',
shopId: store.userInfo.shopId,
// skuId: type == "add" ? params.id : params.skuId,
skuId: skuId,
number: params.number || 1,
isPack: params.isPack || "false",
isGift: params.isGift || "false",
cartId: type == "add" ? "" : params.id,
uuid: params.uuid || store.userInfo.uuid,
type: type,
groupProductIdList: params.groupProductIdList || []
});
cartLoading.value = false;
masterId.value = res;
goodsRef.value.updateData();
queryCartAjax();
}
} catch (error) {
console.log(error);
cartLoading.value = false;
}
}
// 获取购物车商品
async function queryCartAjax() {
try {
const res = await queryCart({
masterId: masterId.value,
shopId: store.userInfo.shopId,
tableId: global.tableInfo.qrcode || '',
vipUserId: global.orderMemberInfo.id || ''
});
if (!res.list.length) {
cartListActiveItem.value = {}
}
res.list.map((item, index) => {
item.info.map((val, i) => {
if (i == 0 && index == 0) {
val.active = true
if (!cartListActiveItem.value.id) {
cartListActiveItem.value = val
}
} else {
val.active = false
}
})
})
cartList.value = res.list;
if (cartListActiveItem.value.id) {
selectCartItemHandle(cartListActiveItem.value)
}
cartInfo.value = res.amount;
pendingCartNum.value = res.num;
// goodsRef.value.updateData();
let i = 0;
res.list.map((item) => {
if (item.isPack == "true") {
i++;
}
});
if (i == res.list.length) {
allSelected.value = true;
} else {
allSelected.value = false;
}
} catch (error) {
console.log("获取购物车商品", error);
}
}
// 增加点餐人数
async function addTableNum() {
try {
const res = await orderChoseCount({
masterId: masterId.value,
shopId: store.userInfo.shopId,
tableId: global.tableInfo.qrcode,
num: global.tableInfo.num
})
} catch (error) {
console.log(error);
}
}
// 获取取餐码
async function createCodeAjax(type = "0") {
try {
// if (!process.env.VITE_DEV_SERVER_URL) {
// masterId.value = '#20'
// } else {
// const res = await createCode({
// shopId: store.userInfo.shopId
// })
// masterId.value = res.code
// }
if (global.tableInfo.masterId) {
masterId.value = global.tableInfo.masterId
} else {
const res = await createCode({
shopId: store.userInfo.shopId,
type: type,
tableId: global.tableInfo.qrcode || '',
});
masterId.value = res.code;
}
if (global.tableInfo.num) {
await addTableNum()
}
await queryCartAjax();
if (type == 1) {
// 结算订单 清楚商品所有红点
goodsRef.value.clearDot()
}
} catch (error) {
console.log(error);
}
// 购物车选中
function selectCartItemHandle(index) {
goodsStore.selectCartItemHandle(index)
}
// 清除本地会员/台桌信息
function clearMember() {
global.setOrderMember({})
global.setOrderTable({})
createCodeAjax()
}
// 显示转桌/并桌
@@ -578,11 +425,6 @@ function showTableMerging() {
let data = cartList.value.filter(item => item.placeNum)
tableMergingRef.value.show(data)
}
onMounted(() => {
createCodeAjax()
shopStore.queryShopInfo()
});
</script>
<style scoped lang="scss">
@@ -619,15 +461,20 @@ onMounted(() => {
}
.number {
width: 50px;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--el-color-info-light-7);
// padding-left: var(--el-font-size-base);
.icon {
color: var(--el-color-primary);
font-size: 20px;
}
.t {
font-size: var(--el-font-size-base);
margin-left: 4px;
}
}
@@ -681,10 +528,47 @@ onMounted(() => {
.shop_list {
flex: 1;
height: calc(100vh - 40px - 60px - 80px);
height: calc(100vh - 40px - 60px - 90px);
overflow-y: auto;
border-right: 1px solid #ececec;
.table_info {
height: 40px;
border-bottom: 1px solid #ececec;
font-size: 14px;
color: #999;
display: flex;
.left {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 var(--el-font-size-base);
}
.close {
width: 40px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
.icon {
font-size: 16px;
}
&::after {
content: "";
height: 15px;
border-left: 1px solid #ddd;
position: absolute;
left: 0;
top: 12.5px;
}
}
}
.item {
padding: var(--el-font-size-base);
@@ -803,7 +687,7 @@ onMounted(() => {
}
.footer {
padding: var(--el-font-size-base);
padding: 10px var(--el-font-size-base);
border-top: 1px solid #ececec;
.left {
@@ -837,6 +721,26 @@ onMounted(() => {
}
}
.num-wrap {
height: 40px;
display: flex;
flex-direction: column;
.num_wrap_top {
flex: 1;
display: flex;
justify-content: flex-end;
}
.num_wrap_btm {
flex: 1;
display: flex;
justify-content: flex-end;
font-size: 12px;
color: #999;
}
}
.top {
display: flex;
justify-content: space-between;
@@ -846,7 +750,7 @@ onMounted(() => {
$h: 70px;
display: flex;
height: $h;
padding-top: var(--el-font-size-base);
padding-top: 10px;
gap: var(--el-font-size-base);
.editor {