Files
cashier-ipad-new/pagesCreateOrder/table-order/index.vue
2025-12-01 10:50:08 +08:00

764 lines
17 KiB
Vue
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.
<template>
<view class="u-font-28">
<up-sticky offsetTop="0" customNavHeight="0">
<view class="navbar">
<view class="u-flex" style="margin-left: 100rpx" @click="back">
<up-icon name="arrow-left" size="32rpx" color="#333"></up-icon>
<text class="u-m-l-16">返回</text>
</view>
<text class="font-700 u-font-40 color-333"
>{{ returnAreaName }} {{ returnTableName }}</text
>
<view class="u-flex navbar-right" style="gap: 134rpx">
<up-icon
name="scan"
size="64rpx"
color="#999"
@click="saomaShangCai"
></up-icon>
</view>
</view>
</up-sticky>
<view class="container">
<view class="goods-list">
<goodsList v-model:selCart="selCart"></goodsList>
<view style="height: 200rpx"></view>
<view class="bottom u-flex u-row-between">
<view>
<text>合计</text>
<text class="color-red u-font-40"
>¥{{ cartStore.orderCostSummary.finalPayAmount }}</text
>
</view>
<view class="u-flex" style="gap: 94rpx">
<view class="btn" @click="back">继续加菜</view>
<view class="btn success" @click="toPay">结算</view>
</view>
</view>
</view>
<view class="controls">
<controls @btnClick="btnClick" v-model:selCart="selCart"></controls>
</view>
</view>
<model-discount
title="菜品减免"
:ref="setModel"
name="discount"
:price="modelData.data.salePrice"
@confirm="discountconfirm"
></model-discount>
<!-- 转桌 -->
<Modal
v-model="modalData.show"
:width="modalData.key == 'btnClick' ? '800rpx' : ''"
:title="modalData.title"
confirmText="确定"
@confirm="modalConfirm"
>
<template v-if="modalData.key == 'editPersonCount'">
<view class="u-p-40 u-font-32 color-333 u-flex u-flex-x-center">
<up-number-box
v-model="modalData.form.personCount"
integer
:min="0"
:max="100"
inputWidth="200"
></up-number-box>
</view>
</template>
<template v-if="modalData.key == 'pack'">
<view class="u-p-40 u-font-32 color-333 u-flex u-flex-x-center">
<up-number-box
v-model="modalData.form.packNumber"
integer
:min="0"
:max="packNumberMax"
inputWidth="200"
></up-number-box>
</view>
</template>
<template v-if="modalData.key == 'btnClick'">
<view class="u-p-40 u-font-32 color-333">
<view class="u-flex">
<text class="font-bold u-m-r-52" style="min-width: 128rpx"
>转桌到</text
>
<view class="u-flex-1">
<chooseTables
v-model="modalData.form.targetTableCode"
></chooseTables>
</view>
</view>
<template v-if="modalData.form.type == 1">
<!-- <view class="u-flex u-m-t-44">
<text class="font-bold u-m-r-52">转入类型</text>
<up-radio-group v-model="modalData.form.type" placement="row">
<up-radio
:key="1"
label="转桌(部分商品转入)"
:name="1"
></up-radio>
<up-radio
:key="2"
label="并桌(全部商品转入)"
:name="2"
></up-radio>
</up-radio-group>
</view> -->
<view class="u-flex u-m-t-44">
<text class="font-bold u-m-r-52">购物车商品</text>
</view>
<view class="u-m-t-44">
<u-table2
:data="cartStore.oldCartList"
:columns="modalData.form.columns"
row-key="id"
@selection-change="handleSelectionChange"
/>
</view>
</template>
</view>
</template>
</Modal>
</view>
</template>
<script setup>
import Modal from "@/components/my-components/modal.vue";
import chooseTables from "./components/choose-tables.vue";
import { onLoad } from "@dcloudio/uni-app";
import goodsList from "./components/goods-list.vue";
import modelDiscount from "./components/discount";
import controls from "./components/controls.vue";
import { useCartStore } from "@/stores/cart.js";
import { useAccountStore } from "@/stores/account.js";
import * as orderApi from "@/http/api/order.js";
import * as tableApi from "@/http/api/table.js";
import * as areaApi from "@/http/api/area.js";
import yskUtils from "ysk-utils";
import go from "@/commons/utils/go.js";
import { reactive, ref, provide, computed, inject } from "vue";
const websocketUtil = inject("websocketUtil");
const cartStore = useCartStore();
const accountStore = useAccountStore();
cartStore.shopInfo = accountStore.shopInfo;
websocketUtil.offMessage();
websocketUtil.onMessage((data) => {
cartStore.onMessage(data);
});
const modalData = reactive({
show: false,
key: "",
title: "",
form: {
packNumber: 0,
personCount: 0,
targetTableCode: "",
checks: [],
type: 1,
columns: [
{ type: "selection", width: "50px" },
{ title: "商品名称", key: "productName" },
{
title: "数量",
key: "num",
style: { "justify-content": "center", "text-align": "cnter" },
},
],
},
});
function handleSelectionChange(e) {
console.log(e);
modalData.form.checks = e;
}
async function transferTable() {
if (!modalData.form.targetTableCode) {
uni.showToast({
title: "请选择目标台桌",
icon: "none",
});
return;
}
if (modalData.form.type == 1 && modalData.form.checks.length <= 0) {
uni.showToast({
title: "请选择商品",
icon: "none",
});
return;
}
let detailIds = cartStore.oldCartList.map((v) => v.id);
if (modalData.form.type == 1) {
detailIds = modalData.form.checks.map((v) => v.id);
}
const res = await orderApi.mergeOrder({
sourceOrderId: cartStore.order.id,
targetOrderId: "",
targetTableCode: modalData.form.targetTableCode,
detailIds,
});
if (!res) {
uni.showModal({
title: "转桌失败",
icon: "none",
});
return;
}
uni.showToast({
title: "转桌成功",
icon: "none",
});
if (modalData.form.type == 2) {
await orderApi.cancelOrder({
orderId: cartStore.order.id,
shopId: cartStore.order.shopId,
});
const tableRes = await tableApi.getShopTableDetail({
tableCode: modalData.form.targetTableCode,
});
if (tableRes && tableRes.id) {
uni.$emit("choose-table", tableRes);
}
const orderRes = await orderApi.getHistoryOrder({
tableCode: modalData.form.targetTableCode,
});
if (orderRes) {
options.orderId = orderRes.id;
}
}
getOrderById();
modalData.show = false;
modalData.form.targetTableCode = [];
modalData.form.checks = [];
modalData.form.type = 1;
}
async function editPersonCount() {
cartStore.personCount = modalData.form.personCount;
modalData.show = false;
}
function editPackNumber() {
const par = {
id: selCart.value.id,
product_id: selCart.value.product_id,
sku_id: selCart.value.sku_id,
pack_number: modalData.form.packNumber,
};
modalData.show = false;
modalData.form.packNumber = 0;
updateCart(par);
}
async function modalConfirm(key) {
if (modalData.key == "btnClick") {
transferTable();
}
if (modalData.key == "editPersonCount") {
editPersonCount();
}
if (modalData.key == "pack") {
editPackNumber();
}
}
provide("cartStore", cartStore);
provide("yskUtils", yskUtils);
provide("accountStore", accountStore);
const selCart = ref(null);
const packNumberMax = computed(() => {
if (selCart.value) {
return selCart.value.num;
}
return 0;
});
function back() {
uni.navigateBack();
}
function toPay() {
go.to("PAGES_ORDER_PAY", {
orderId: cartStore.order.id,
isNowPay: true,
dinnerType: cartStore.currentDinnerType,
personCount: cartStore.personCount,
});
}
const areaList = ref([]);
async function getArea() {
const res = await areaApi.getShopArea({ size: 999 });
areaList.value = res.records;
}
async function getOrderById() {
const res = await orderApi.getOrderById({ orderId: options.orderId });
const tableRes = await tableApi.getShopTableDetail({
tableCode: res.tableCode,
});
if (tableRes) {
cartStore.table = tableRes;
} else {
cartStore.table = {
tableCode: res.tableCode,
};
}
cartStore.setOrder(res);
cartStore.sendMessage({
operate_type: "init",
});
}
const options = {};
onLoad(async (opt) => {
Object.assign(options, opt);
console.log("options", options);
getTablelist();
await getArea();
getOrderById();
});
const tableList = ref([]);
async function getTablelist() {
const res = await tableApi.getShopTable({ size: 999 });
tableList.value = res.records || [];
}
async function shopTableClear() {
const res = await orderApi.cancelOrder({
orderId: cartStore.order.id,
shopId: accountStore.shopInfo.id,
});
if (res) {
uni.showToast({
title: "清台成功",
icon: "none",
});
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
}
async function btnClick(type) {
if (type == "editPersonCount") {
console.log(modalData.form);
modalData.form.personCount = cartStore.personCount;
modalData.title = "就餐人数";
modalData.key = "editPersonCount";
modalData.show = true;
return;
}
modalData.key = "btnClick";
if (type == "clearTable") {
uni.showModal({
title: "提示",
content: "该操作会取消未支付的订单,且无法恢复,是否确认清空该桌订单",
success(res) {
if (res.confirm) {
console.log("清空该桌订单");
shopTableClear();
}
},
});
}
if (type == "transfer") {
modalData.form.type = 1;
modalData.title = "转桌";
modalData.show = true;
}
if (type == "changeTable") {
modalData.form.type = 2;
modalData.title = "转桌";
modalData.show = true;
}
if (type == "serveAll") {
await orderApi.upOrderDetail({
orderId: cartStore.order.id,
type: 1,
});
getOrderById();
return;
}
if (!selCart.value) {
return;
}
selCart.value = cartStore.allCartList.find((v) => v.id == selCart.value.id);
if (type === "pack") {
modalData.title = "打包";
modalData.key = "pack";
modalData.show = true;
console.log(selCart.value);
modalData.form.packNumber = selCart.value.packNumber;
}
if (type == "changePrice") {
showModel("discount");
return;
}
if (type == "gift") {
updateCart({
id: selCart.value.id,
product_id: selCart.value.product_id,
sku_id: selCart.value.sku_id,
unit_price: 0,
is_gift: 1,
});
return;
}
if (type == "startCooking") {
await orderApi.upOrderDetail({
orderDetailId: selCart.value.id,
type: 0,
});
getOrderById();
return;
}
if (type == "serve") {
await orderApi.upOrderDetail({
orderDetailId: selCart.value.id,
type: 1,
});
getOrderById();
return;
}
}
const models = new Map();
const modelData = reactive({
data: {},
});
/**
* 设置弹窗信息
* @param {Object} el
*/
function setModel(el) {
if (el && el.$attrs["name"]) {
models.set(el.$attrs["name"], el);
}
}
/**
* 打开弹窗
* @param {Object} key
* @param {Object} index
*/
function showModel(key) {
modelData.data = selCart.value;
const item = selCart.value;
const model = models.get(key);
console.log("弹窗数据===", modelData.data);
if (key == "packNumber") {
if (modelData.data.type == "weight" && item.pack_number <= 0) {
let par = {
id: modelData.data.id,
product_id: modelData.data.product_id,
sku_id: modelData.data.sku_id,
pack_number: 1,
};
updateCart(par);
return false;
}
if (item.pack_number > 0) {
let par = {
id: modelData.data.id,
product_id: modelData.data.product_id,
sku_id: modelData.data.sku_id,
pack_number: 0,
};
updateCart(par);
return false;
}
model &&
model.open({
number: item.number,
});
} else {
model &&
model.open({
packNumber: modelData.data.remark || "",
});
}
}
/**
* 单品打折
* @param {Object} form
*/
async function discountconfirm(form) {
if (form.discountMoney != ".") {
let str = "";
if (form.notes) {
form.notes.forEach((ele) => {
if (ele.checked) {
str = str + ele.name + ",";
}
});
}
let discount_sale_amount = modelData.data.is_gift ? 0 : form.discountMoney;
let par = {
id: modelData.data.id,
product_id: modelData.data.product_id,
sku_id: modelData.data.sku_id,
discount_sale_amount: discount_sale_amount,
// discount_sale_note: str + form.note,
};
updateCart(par);
}
}
/**
* 购物车数据修改
* @param {Object} par
*/
function updateCart(par) {
console.log(selCart.value);
if (selCart.value.isHistory) {
cartStore.sendMessage({
type: "onboc",
operate_type: "bulk_edit",
data: {
history: [par],
cart: [],
},
});
return;
}
cartStore.sendMessage({
type: "onboc",
operate_type: "edit",
...par,
});
getCart();
}
/**
* 更新购物车和历史订单数据
*/
function uodateCartAndHistory() {
let newData = {
history: [],
cart: [],
};
websocketUtil.send(
JSON.stringify({
type: "onboc",
operate_type: "bulk_edit",
data: newData,
})
);
}
/**
* 获取购物车数据
*/
function getCart() {
// 初始化购物车
cartStore.sendMessage({
type: "onboc",
operate_type: "init",
}),
false;
}
const returnAreaName = computed(() => {
if (!cartStore.table) {
return "";
}
if (!cartStore.table.areaId) {
return "";
}
const item = areaList.value.find((v) => v.id == cartStore.table.areaId);
return item ? item.name : "";
});
const returnTableName = computed(() => {
if (!cartStore.table) {
return "";
}
return cartStore.table.name || "";
});
/**
* 扫码上传
*/
async function saomaShangCai() {
uni.scanCode({
success: async (res) => {
console.log("条码类型:" + res.scanType);
console.log("条码内容:" + res.result);
console.log("orderDetailId", res.result.split(":")[1]);
await orderApi.upOrderDetail({
orderDetailId: res.result.split(":")[1],
type: 1,
});
getOrderById();
},
});
}
</script>
<style lang="scss" scoped>
.line {
width: 1px;
height: 20rpx;
background-color: #e5e5e5;
margin-left: 8rpx;
margin-right: 16rpx;
}
.my-radio {
.circle {
background: #ffffff;
width: 18px;
height: 18px;
&.active {
background-color: $my-main-color;
border-color: $my-main-color;
}
border: 1px solid #707070;
border-radius: 50%;
overflow: hidden;
&.square {
border-radius: 8rpx;
}
}
}
.area {
padding: 2px 28rpx 24rpx 28rpx;
}
.scale7 {
transform: scale(0.7);
}
::v-deep .uni-searchbar {
padding: 0 !important;
}
.search {
padding: 20rpx 28rpx 20rpx 28rpx;
.icon-saoma {
margin-left: 20rpx;
width: 34rpx;
height: 32rpx;
}
}
.list {
padding: 38rpx 28rpx;
display: grid;
grid-template-columns: repeat(6, 1fr);
column-gap: 50rpx;
row-gap: 62rpx;
.no-choose {
padding: 36rpx 30rpx 36rpx 24rpx;
}
.item {
color: #fff;
padding: 18rpx 14rpx;
border-radius: 16rpx;
overflow: hidden;
.bottom {
padding: 26rpx 14rpx 38rpx 14rpx;
background-color: #fff;
border-radius: 6rpx;
}
.diancan {
padding: 18rpx 18rpx;
border-radius: 8rpx;
text-align: center;
}
}
}
.icon-people {
width: 30rpx;
height: 34rpx;
}
.exit {
width: 48rpx;
height: 48rpx;
margin-left: 100rpx;
}
.navbar {
background-color: #fff;
display: flex;
justify-content: space-between;
padding: 32rpx 0;
padding-top: calc(var(--status-bar-height) + 32rpx);
}
.navbar-right {
margin-right: 86rpx;
}
.status-list {
background-color: #fff;
display: flex;
padding: 32rpx 72rpx;
}
.status-list {
display: flex;
flex-wrap: wrap;
gap: 68rpx;
.circle {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
}
}
.container {
display: flex;
}
$control-width: 800rpx;
.goods-list {
flex: 1;
position: relative;
border-right: 1px solid #e5e5e5;
min-height: calc(100vh - 100px);
.bottom {
position: fixed;
border-right: 1px solid #e5e5e5;
bottom: calc(env(safe-area-inset-bottom));
left: 0;
right: $control-width;
padding: 32rpx 102rpx;
background-color: #f9f9f9;
}
}
.controls {
width: $control-width;
}
.btn {
padding: 18rpx 76rpx;
border-radius: 8rpx;
border: 1px solid $my-main-color;
color: $my-main-color;
&.success {
background-color: $my-main-color;
color: #fff;
}
}
:deep(.u-table-cell:last-child) {
justify-content: center;
}
</style>