Compare commits
41 Commits
dev
...
gyq_zhuan_
| Author | SHA1 | Date | |
|---|---|---|---|
| 806a98aabd | |||
| 64ec515c01 | |||
| 44144c5ac7 | |||
| 5e4bce25fb | |||
| 5abb43cc49 | |||
| bbd99a1942 | |||
| 00172f75e7 | |||
| 608c41de4f | |||
| ddd67d0c0a | |||
| 75f32c7b3d | |||
| 14ce5cb468 | |||
| 456bcf83a5 | |||
| 8dfa5b7aac | |||
| 4b54fdaff1 | |||
| 0711d4b07d | |||
| 7c27372c4d | |||
| 96ab68f463 | |||
| 8f42ba8189 | |||
| 8935b9d2f2 | |||
| 773a2cf2c9 | |||
| 06a0d1d0fc | |||
| db8c41fd16 | |||
| 9d73a49a06 | |||
| 5805b1fd7c | |||
| b1272852d8 | |||
| 45999ef022 | |||
| 72cf926747 | |||
| cfd04625dd | |||
| 00c6a9a491 | |||
| 458b531757 | |||
| 9fb67bd8a2 | |||
| e17b12687f | |||
| 34f0b306c9 | |||
| d57cecd91d | |||
| 86c8ca6472 | |||
| 2d2a014bc4 | |||
| 3047fe0404 | |||
| fbfee69b25 | |||
| 48a3443c5f | |||
| b45793ffc9 | |||
| e4a82411ba |
@@ -1,7 +1,6 @@
|
||||
# 本地环境
|
||||
ENV = development
|
||||
|
||||
|
||||
# 正式ws
|
||||
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
|
||||
|
||||
@@ -26,8 +25,17 @@ VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||
# 鹏辉
|
||||
# VITE_API_URL = 'http://192.168.1.106:10589/cashier-client'
|
||||
|
||||
# 杰哥
|
||||
VITE_API_URL = 'http://192.168.2.181:10587/cashier-client'
|
||||
|
||||
# 测试
|
||||
# VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client'
|
||||
|
||||
# 预发布
|
||||
# VITE_API_URL = 'https://pre-cashierclient.sxczgkj.cn/cashier-client'
|
||||
|
||||
# 张松本地
|
||||
# VITE_API_URL = 'https://36z1017t45.goho.co/cashier-client'
|
||||
|
||||
# 正式
|
||||
VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'
|
||||
# VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'
|
||||
@@ -12,3 +12,6 @@ VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||
|
||||
# 线上环境接口地址
|
||||
VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client/'
|
||||
|
||||
# 预发布接口
|
||||
# VITE_API_URL = 'https://pre-cashierclient.sxczgkj.cn/cashier-client/'
|
||||
10
.env.test
10
.env.test
@@ -2,10 +2,10 @@
|
||||
ENV = test
|
||||
|
||||
#测试ws
|
||||
VITE_API_WSS = 'wss://wxcashiertest.sxczgkj.cn/client'
|
||||
# VITE_API_WSS = 'wss://wxcashiertest.sxczgkj.cn/client'
|
||||
|
||||
# 正式ws
|
||||
# VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
|
||||
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
|
||||
|
||||
# 正式 php
|
||||
VITE_API_PHP_URL = 'https://czgdoumei.sxczgkj.com/index.php/api'
|
||||
@@ -19,5 +19,11 @@ VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||
# 测试
|
||||
VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client'
|
||||
|
||||
# 预发布
|
||||
# VITE_API_URL = 'https://pre-cashierclient.sxczgkj.cn/cashier-client'
|
||||
|
||||
# 张松本地
|
||||
# VITE_API_URL = 'https://36z1017t45.goho.co/cashier-client'
|
||||
|
||||
# 正式
|
||||
# VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'
|
||||
15736
dist-electron/main.js
15736
dist-electron/main.js
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,10 @@
|
||||
import path from "path";
|
||||
import { app, BrowserWindow, ipcMain } from "electron";
|
||||
|
||||
import axios from "axios";
|
||||
import os from "os";
|
||||
// const SerialPort = require("serialport");
|
||||
import fs from "fs";
|
||||
import { exec } from "child_process";
|
||||
|
||||
let win;
|
||||
app.whenReady().then(() => {
|
||||
@@ -29,6 +32,54 @@ app.whenReady().then(() => {
|
||||
win.loadFile(path.resolve(__dirname, "../dist/index.html")); // 打包后使用文件路径访问应用
|
||||
}
|
||||
|
||||
const installExe = async (exePath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(`${exePath}`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(stdout);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ipcMain.on("downloadFile", async (event, arg) => {
|
||||
let _parmas = JSON.parse(arg);
|
||||
axios({
|
||||
url: _parmas.url,
|
||||
method: "get",
|
||||
responseType: "arraybuffer",
|
||||
onDownloadProgress: (propessEvent) => {
|
||||
// 更新进度条
|
||||
const propress = Math.round(
|
||||
(propessEvent.loaded / propessEvent.total) * 100
|
||||
);
|
||||
win.webContents.send("updateProgress", propress);
|
||||
},
|
||||
})
|
||||
.then(async (response) => {
|
||||
try {
|
||||
const tempFilePath = path.join(
|
||||
app.getPath("temp"),
|
||||
"temp-exe-file.exe"
|
||||
);
|
||||
fs.writeFileSync(tempFilePath, response.data);
|
||||
setTimeout(() => {
|
||||
win = null;
|
||||
app.exit();
|
||||
}, 1500);
|
||||
const installResult = await installExe(tempFilePath);
|
||||
console.log(`安装结果:${installResult}`);
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("下载失败", JSON.stringify(err));
|
||||
});
|
||||
});
|
||||
|
||||
app.on("activate", () => {
|
||||
// 在 macOS 系统内, 如果没有已开启的应用窗口
|
||||
// 点击托盘图标时通常会重新创建一个新窗口
|
||||
@@ -45,6 +96,7 @@ app.whenReady().then(() => {
|
||||
// 给渲染进程返回打印机列表
|
||||
ipcMain.on("getPrintList", () => {
|
||||
win.webContents.getPrintersAsync().then((res) => {
|
||||
// console.log("打印机列表", res);
|
||||
win.webContents.send("printList", res);
|
||||
});
|
||||
});
|
||||
@@ -62,16 +114,6 @@ app.whenReady().then(() => {
|
||||
win.webContents.send("getOSmacRes", mac);
|
||||
});
|
||||
|
||||
// ipcMain.on("getSerialPort", () => {
|
||||
// SerialPort.SerialPort.list().then(
|
||||
// (ports) => {
|
||||
// console.log(ports);
|
||||
// win.webContents.send("seriaportList", ports);
|
||||
// },
|
||||
// (err) => console.error(err)
|
||||
// );
|
||||
// });
|
||||
|
||||
// 创建打印小票子窗口
|
||||
// const printWin = new BrowserWindow({
|
||||
// show: false,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "vite-electron",
|
||||
"private": true,
|
||||
"version": "1.4.14",
|
||||
"version": "1.4.27",
|
||||
"main": "dist-electron/main.js",
|
||||
"scripts": {
|
||||
"dev": "chcp 65001 && vite",
|
||||
@@ -24,6 +24,7 @@
|
||||
"qrcode": "^1.5.3",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"serialport": "^12.0.0",
|
||||
"speak-tts": "^2.0.8",
|
||||
"swiper": "^11.1.1",
|
||||
"uuid": "^10.0.0",
|
||||
"vue": "^3.3.8",
|
||||
|
||||
@@ -47,6 +47,9 @@ body {
|
||||
}
|
||||
.print_view .header .logo {
|
||||
width: 90px;
|
||||
height: 30px;
|
||||
-o-object-fit: cover;
|
||||
object-fit: cover;
|
||||
}
|
||||
.print_view .header .title {
|
||||
margin-left: 6px;
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<div class="print_view">
|
||||
<div class="ewm" id="ewm"></div>
|
||||
<div class="header">
|
||||
<img class="logo" src="./logo.png" />
|
||||
<!-- <span class="title">双屿Pisces</span> -->
|
||||
<img class="logo" :src="data.ticketLogo || './logo.png'" />
|
||||
<!-- <span class="title">{{data.ticket_logo}}</span> -->
|
||||
</div>
|
||||
<div class="number_wrap">
|
||||
<div class="num" v-if="data.outNumber">{{data.outNumber}}</div>
|
||||
|
||||
@@ -38,6 +38,8 @@ body {
|
||||
.logo {
|
||||
$size: 90px;
|
||||
width: $size;
|
||||
height: 30px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.title {
|
||||
margin-left: 6px;
|
||||
|
||||
38
src/App.vue
38
src/App.vue
@@ -164,24 +164,6 @@ async function getBarCode(e) {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取网络状态
|
||||
const updateInfo = _.throttle(function () {
|
||||
let isOnLine = navigator.onLine
|
||||
// // 获取网络信息
|
||||
// let info = navigator.connection
|
||||
console.log(isOnLine);
|
||||
// console.log(info);
|
||||
if (store.userInfo && store.userInfo.shopId) {
|
||||
if (isOnLine) {
|
||||
console.log('有网了重新连接ws~');
|
||||
socket.init();
|
||||
} else {
|
||||
socket.close();
|
||||
console.log('网络连接失败~');
|
||||
}
|
||||
}
|
||||
}, 100, { leading: true, trailing: false })
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener("keydown", (e) => {
|
||||
getBarCode(e);
|
||||
@@ -200,14 +182,16 @@ onMounted(() => {
|
||||
.catch(() => { });
|
||||
})
|
||||
|
||||
// listnerCloseDialog()
|
||||
|
||||
// // 监听网络在线状态
|
||||
// window.addEventListener("onLine", updateInfo)
|
||||
// // 监听网络离线
|
||||
// window.addEventListener("offLine", updateInfo)
|
||||
// 监听网络信息变化
|
||||
// navigator.connection.addEventListener('change', updateInfo)
|
||||
window.addEventListener('online', function () {
|
||||
console.log('有网络了');
|
||||
this.location.reload()
|
||||
})
|
||||
|
||||
window.addEventListener('offline', function () {
|
||||
ElMessage.warning('网络异常')
|
||||
socket.close()
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -271,6 +255,10 @@ html {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.el-divider__text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.el-dialog__headerbtn {
|
||||
top: 10px !important;
|
||||
}
|
||||
|
||||
@@ -158,3 +158,87 @@ export function tglogout(data) {
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 美团团购核销
|
||||
* 绑定-获取绑定状态
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function thirdPartyCoupon_state(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "/meituan/searchstorestatus",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 美团团购核销
|
||||
* 绑定-获取绑定url
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function thirdPartyCoupon_bindUrl(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "/meituan/getuisdkurl",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 美团团购核销
|
||||
* 团购券-获取可用券
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function thirdPartyCoupon_list(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "/meituan/fulfilmentcertificateprepare",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 美团团购核销
|
||||
* 执行核销
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function certificateprepare(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "/meituan/certificateprepare",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 美团团购核销
|
||||
* 团购核销记录
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function meituan_orderlist(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "/meituan/orderlist",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 美团团购核销
|
||||
* 团购撤销
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function meituan_fulfilmentcertificatecancel(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "/meituan/fulfilmentcertificatecancel",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ export function queryMembermember(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "member/queryMember",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
export function createMembermember(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "member/createMember",
|
||||
data
|
||||
data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
@@ -28,7 +28,7 @@ export function memberqueryMemberAccount(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "member/queryMemberAccount",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
/**
|
||||
@@ -40,7 +40,7 @@ export function accountPaymember(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "member/accountPay",
|
||||
data
|
||||
data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
@@ -52,6 +52,19 @@ export function membermemberScanPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "member/memberScanPay",
|
||||
data
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值退款
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function returnFlow(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "member/returnFlow",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -101,3 +101,29 @@ export function getsendMessage(params) {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单详情
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function orderDetail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/orderDetail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取员工最大优惠点
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getStaffDiscount(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/pay/getOrderDiscount",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,53 +15,53 @@ export function queryPayType(params) {
|
||||
|
||||
/**
|
||||
* 付款
|
||||
* @param {*} params
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function payOrder(api, params) {
|
||||
export function payOrder(api, data) {
|
||||
return request({
|
||||
method: "get",
|
||||
method: "post",
|
||||
url: api,
|
||||
params,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码支付
|
||||
* @param {*} params
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function scanpay(params) {
|
||||
export function scanpay(data) {
|
||||
return request({
|
||||
method: "get",
|
||||
method: "post",
|
||||
url: "pay/scanpay",
|
||||
params,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 储值卡付款
|
||||
* @param {*} params
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function accountPay(params) {
|
||||
export function accountPay(data) {
|
||||
return request({
|
||||
method: "get",
|
||||
method: "post",
|
||||
url: "pay/accountPay",
|
||||
params,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 现金付款
|
||||
* @param {*} params
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function cashPay(params) {
|
||||
export function cashPay(data) {
|
||||
return request({
|
||||
method: "get",
|
||||
method: "post",
|
||||
url: "pay/cashPay",
|
||||
params,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -129,3 +129,42 @@ export function queryScanPay(params) {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员余额支付
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function vipPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/pay/vipPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂账人-分页
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function buyerPage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/credit/buyer/page",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂账支付
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function payCreditPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/pay/creditPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export function queryCategory(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "product/queryCategory",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export function productqueryCommodityInfo(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "product/queryCommodityInfo",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export function queryNewCommodityInfo(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "product/queryNewCommodityInfo",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ export function queryProductSku(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "product/queryProductSku",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export function createCart(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/createCart",
|
||||
data
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ export function queryCart(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "order/queryCart",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ export function createCode(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/createCode",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ export function packall(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/packall",
|
||||
data
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ export function delCart(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/delCart",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ export function cartStatus(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/cartStatus",
|
||||
data
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ export function getCartList(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/getCartList",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ export function clearCart(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/clearCart",
|
||||
data
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -165,8 +165,97 @@ export function createOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/createOrder",
|
||||
data
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 上下架售罄
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function productStatus(data) {
|
||||
return request({
|
||||
method: "PUT",
|
||||
url: "/product/productStatus",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改库存
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function productStock(data) {
|
||||
return request({
|
||||
method: "PUT",
|
||||
url: "/product/productStock",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加临时菜
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function temporaryDishes(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/temporaryDishes",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品单位列表获取
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getUnitList(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/unit",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 单品改价
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function updatePrice(data) {
|
||||
return request({
|
||||
method: "PUT",
|
||||
url: "/order/updatePrice",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 免厨打印
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function orderPrint(data) {
|
||||
return request({
|
||||
method: "PUT",
|
||||
url: "/order/print",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 转台/并台
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function orderSwitcht(data) {
|
||||
return request({
|
||||
method: "PUT",
|
||||
url: "/order/switch",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
134
src/api/queue.js
Normal file
134
src/api/queue.js
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 排队叫号
|
||||
*/
|
||||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 记录获取
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function callRecord(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/callTable/callRecord",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 桌型列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function callTable(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/callTable",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加桌型
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function addCallTable(data) {
|
||||
return request({
|
||||
method: data.id ? "put" : "post",
|
||||
url: "/callTable",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除桌型
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function delCallTable(data) {
|
||||
return request({
|
||||
method: "delete",
|
||||
url: "/callTable",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置信息 获取
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function callTableConfig(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/callTable/config",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置信息 修改
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function callTableConfigPut(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/callTable/config",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取号 排队列表获取
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function callTableQueue(params) {
|
||||
return request({
|
||||
method: "GET",
|
||||
url: "/callTable/queue",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取号 手动取号
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function takeNumber(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/callTable/takeNumber",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取号 修改叫号状态
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function updateState(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/callTable/updateState",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知叫号
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function callTableCall(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/callTable/call",
|
||||
data,
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import request from "@/utils/request.js"
|
||||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 查询台桌分类
|
||||
@@ -9,7 +9,7 @@ export function queryShopArea(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "shopInfo/queryShopArea",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,6 +22,32 @@ export function queryShopTable(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "shopInfo/queryShopTable",
|
||||
params
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清台
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function clearTable(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/shopInfo/clearTable",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择用餐人数
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function orderChoseCount(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/order/choseCount",
|
||||
data,
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import request from "@/utils/request.js";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
export function login(data) {
|
||||
return request({
|
||||
@@ -7,3 +8,74 @@ export function login(data) {
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本
|
||||
* @returns
|
||||
*/
|
||||
export function findVersion() {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "login/findVersion",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取是否显示密码
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryPwdInfo() {
|
||||
let userInfo = JSON.parse(localStorage.getItem("userInfo"));
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/shopInfo/queryPwdInfo",
|
||||
params: {
|
||||
shopId: userInfo.shopId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询店铺信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryShopInfo() {
|
||||
let userInfo = JSON.parse(localStorage.getItem("userInfo"));
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/shopInfo/queryShopInfo",
|
||||
params: {
|
||||
shopId: userInfo.shopId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询员工是否拥有权限
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export async function staffPermission(code) {
|
||||
let userInfo = JSON.parse(localStorage.getItem("userInfo"));
|
||||
if (userInfo.isStaff) {
|
||||
const res = await request({
|
||||
method: "get",
|
||||
url: "/staffPermission",
|
||||
params: {
|
||||
staffId: userInfo.staffId,
|
||||
code: code,
|
||||
},
|
||||
});
|
||||
|
||||
if (res) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
ElMessage.error("无权操作");
|
||||
return Promise.reject('无权操作');
|
||||
}
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/assets/icon_xq.png
Normal file
BIN
src/assets/icon_xq.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB |
@@ -59,7 +59,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<scanModal ref="scanModalRef" fast :amount="money" :selecttype="props.type" :orderId="props.userInfo.id"
|
||||
<scanModal ref="scanModalRef" fast :amount="money" :money="money" :selecttype="props.type" :orderId="props.userInfo.id"
|
||||
@success="scanCodeSuccess" />
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="支付密码" :type="2" input-type="password" placeholder="请输入支付密码"
|
||||
@success="passwordSuccess" />
|
||||
@@ -78,6 +78,7 @@ import { useUser } from "@/store/user.js";
|
||||
import { clearNoNum } from "@/utils";
|
||||
import md5 from "js-md5";
|
||||
|
||||
import { queryPwdInfo } from '@/api/user.js'
|
||||
import scanModal from "@/components/payCard/scanModal.vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import takeFoodCode from "@/components/takeFoodCode.vue";
|
||||
@@ -128,14 +129,14 @@ function payTypeChange(index, item) {
|
||||
}
|
||||
|
||||
// 获取支付密码
|
||||
async function passwordSuccess(e) {
|
||||
async function passwordSuccess(e = '') {
|
||||
try {
|
||||
payLoading.value = true;
|
||||
await accountPaymember({
|
||||
shopId: store.userInfo.shopId,
|
||||
memberId: props.userInfo.id,
|
||||
amount: money.value,
|
||||
pwd: md5(e),
|
||||
pwd: e ? md5(e) : '',
|
||||
});
|
||||
payLoading.value = false;
|
||||
ElMessage.success("支付成功");
|
||||
@@ -175,8 +176,15 @@ async function confirmOrder() {
|
||||
emit("paySuccess");
|
||||
} else {
|
||||
// 会员充值
|
||||
|
||||
let res = await queryPwdInfo()
|
||||
if (res.isMemberIn == 1) {
|
||||
takeFoodCodeRef.value.show();
|
||||
// passwordSuccess()
|
||||
} else {
|
||||
passwordSuccess()
|
||||
}
|
||||
// takeFoodCodeRef.value.show();
|
||||
// // passwordSuccess()
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="left_menu_wrap">
|
||||
<div class="item" :class="{ online: socketStore.online }" @click="connectWsHandle">
|
||||
<div class="item first" :class="{ online: socketStore.online }" @click="connectWsHandle">
|
||||
<el-icon class="icon">
|
||||
<Monitor />
|
||||
</el-icon>
|
||||
<el-text :type="socketStore.online ? 'success' : ''">
|
||||
<el-text :type="socketStore.online ? 'success' : 'danger'">
|
||||
<template v-if="socketStore.online">
|
||||
在线
|
||||
</template>
|
||||
@@ -87,6 +87,11 @@ const menus = ref([
|
||||
path: '/member',
|
||||
icon: 'User'
|
||||
},
|
||||
{
|
||||
label: '排队',
|
||||
path: '/queue',
|
||||
icon: 'Timer'
|
||||
},
|
||||
// {
|
||||
// label: '交班',
|
||||
// path: '/work',
|
||||
@@ -105,8 +110,8 @@ function openCall() {
|
||||
|
||||
// 手动重新连接ws
|
||||
function connectWsHandle() {
|
||||
if (socketStore.online) return
|
||||
window.onload()
|
||||
// if (socketStore.online) return
|
||||
location.reload()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
@@ -233,7 +238,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
&.more {
|
||||
margin-top: 120px;
|
||||
margin-top: 90px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import getLodop from "./LodopFuncs.js";
|
||||
import { formatDecimal } from "@/utils/index.js";
|
||||
|
||||
/**
|
||||
* 打印订单小票
|
||||
*/
|
||||
export default (data) => {
|
||||
console.log(data);
|
||||
console.log("data.deviceName===", data.deviceName);
|
||||
// console.log("需要打印的订单数据===", data);
|
||||
// console.log("data.deviceName===", data.deviceName);
|
||||
let LODOP = getLodop();
|
||||
LODOP.PRINT_INIT("打印小票");
|
||||
// 设置打印纸大小D
|
||||
@@ -23,6 +25,9 @@ export default (data) => {
|
||||
data.orderInfo.masterId ? data.orderInfo.masterId : ""
|
||||
}】
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
桌号:${data.orderInfo && data.orderInfo.tableName || ''}
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:20px;">
|
||||
${data.orderInfo.outNumber ? data.orderInfo.outNumber : ""}
|
||||
</div>
|
||||
@@ -49,23 +54,49 @@ export default (data) => {
|
||||
|
||||
let table = "";
|
||||
for (let item of data.carts) {
|
||||
if (item.proGroupInfo) {
|
||||
table += `
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:${t1}%" colspan="3">
|
||||
<div>${item.name}</div>
|
||||
</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">${item.totalAmount}</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
let proGroupInfo = JSON.parse(item.proGroupInfo);
|
||||
for (let item of proGroupInfo) {
|
||||
table += `
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:${t1}%;">
|
||||
<div>${item.name}</div>
|
||||
<div>>${item.proName}</div>
|
||||
${
|
||||
item.skuName
|
||||
? `<div class="sku">规格:${item.skuName}</div>`
|
||||
: ""
|
||||
}
|
||||
</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">0</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">${item.number}</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">0</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
} else {
|
||||
table += `
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:${t1}%;">
|
||||
<div>${item.name}</div>
|
||||
${item.skuName ? `<div class="sku">规格:${item.skuName}</div>` : ""}
|
||||
</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">${item.salePrice}</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">${item.number}</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">
|
||||
${item.totalAmount}
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
let str = `
|
||||
@@ -73,18 +104,27 @@ export default (data) => {
|
||||
<div style="margin-top: 6px;margin-bottom: 6px;width: 100%">
|
||||
<hr/>
|
||||
</div>
|
||||
<div style="margin-top: 6px; font-size: 22px;display:flex;justify-content: space-between;">
|
||||
<span>应收</span>
|
||||
<span>¥${data.amount}</span>
|
||||
<div style="margin-top: 6px; font-size: 12px;display:flex;justify-content: space-between;">
|
||||
<span>原价</span>
|
||||
<span>${data.amount}</span>
|
||||
</div>
|
||||
<div style="margin-top: 4px; font-size: 12px;">
|
||||
<span>余额:</span>
|
||||
<span>0.00</span>
|
||||
<div style="margin-top: 6px; font-size: 12px;display:flex;justify-content: space-between;">
|
||||
<span>折扣</span>
|
||||
<span>-${formatDecimal(data.amount - data.discountAmount)}</span>
|
||||
</div>
|
||||
<div style="margin-top: 6px;margin-bottom: 6px;width: 100%">
|
||||
<hr/>
|
||||
</div>
|
||||
<div style="margin-top: 4px; font-size: 16px;font-weight: bold;">备注:${data.remark}</div>
|
||||
<div style="margin-top: 6px; font-size: 22px;display:flex;justify-content: space-between;">
|
||||
<span>实付</span>
|
||||
<span>¥${data.discountAmount}</span>
|
||||
</div>
|
||||
<div style="margin-top: 6px;margin-bottom: 6px;width: 100%">
|
||||
<hr/>
|
||||
</div>
|
||||
<div style="margin-top: 4px; font-size: 16px;font-weight: bold;">备注:${
|
||||
data.remark
|
||||
}</div>
|
||||
<div style="margin-top: 4px; font-size: 12px;">
|
||||
打印时间:${data.printTime}
|
||||
</div>
|
||||
|
||||
@@ -19,6 +19,9 @@ export default (data) => {
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
退款单【${data.orderInfo.masterId ? data.orderInfo.masterId : ""}】
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
桌号:${data.orderInfo && data.orderInfo.tableName || ''}
|
||||
</div>
|
||||
<div style="margin-top: 30px;font-size: 12px;">
|
||||
订单号:${data.orderInfo && data.orderInfo.orderNo}
|
||||
</div>
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
<el-drawer size="60%" :with-header="false" direction="rtl" v-model="dialogVisible" style="padding: 0">
|
||||
<div class="drawerbox_box">
|
||||
<div class="drawerbox_bo_top">
|
||||
<div class="drawerbox_bo_top_left">
|
||||
<div class="drawerbox_bo_top_left" @click="computeExpired">
|
||||
<div class="drawerbox_bo_top_left_one" style="font-size: 24px;">
|
||||
{{ store.userInfo.shopName }}
|
||||
</div>
|
||||
<div class="tips" style="margin-top: 4px; color: var(--el-color-warning);"
|
||||
v-if="!showTips && store.userInfo.expireDate">注意:您的账号将于{{
|
||||
store.userInfo.expireDate }}后过期,请尽快续期!</div>
|
||||
<div class="drawerbox_bo_top_left_tow" style="margin-top: 10px">
|
||||
收银员:{{ store.userInfo.loginAccount }}
|
||||
</div>
|
||||
@@ -109,8 +112,21 @@ const screenref = ref(null);
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
const showTips = ref(false)
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true;
|
||||
computeExpired()
|
||||
}
|
||||
|
||||
// 计算是否小于过期时间30天
|
||||
function computeExpired() {
|
||||
// 当前日期
|
||||
let now = dayjs()
|
||||
// 到期时间
|
||||
let expired = dayjs(store.userInfo.expireDate).subtract(30, 'day')
|
||||
// 判断当前时间是否大于到期时间30天
|
||||
showTips.value = now.isBefore(expired)
|
||||
}
|
||||
|
||||
// 打开叫号弹窗
|
||||
@@ -208,7 +224,7 @@ defineExpose({
|
||||
|
||||
.drawerbox_bo_box_icon {
|
||||
border-radius: 6px;
|
||||
background: #2196f3;
|
||||
background-color: var(--primary-color);
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
display: flex;
|
||||
|
||||
@@ -3,26 +3,42 @@
|
||||
<div class="header">
|
||||
<div class="t1">
|
||||
<span class="title">应收:¥</span>
|
||||
<span class="num">{{ props.amount }}</span>
|
||||
<span class="num">{{ money }}</span>
|
||||
</div>
|
||||
<div class="t2">
|
||||
<span>已付:¥0.00</span>
|
||||
<span>优惠:¥0.00</span>
|
||||
<span>原价:¥{{ formatDecimal(props.amount) }}</span>
|
||||
<span style="margin-left: 20px;">优惠:¥{{ formatDecimal(props.amount - money) }}</span>
|
||||
<span style="margin-left: 20px;" v-if="props.discount" @click="cancelDiscount">折扣:{{
|
||||
formatDecimal(props.discount * 10, 1, true) }}折
|
||||
<el-icon style="margin-left: 6px;">
|
||||
<CircleClose />
|
||||
</el-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="number_wrap">
|
||||
<div class="menus">
|
||||
<div class="item" :class="{ active: payActive == index }" v-for="(item, index) in payList"
|
||||
:key="item.id" @click="payTypeChange(index, item)">
|
||||
<div class="item" :class="{ active: payActive == index, disabled: item.disabled }"
|
||||
v-for="(item, index) in payList" :key="item.id" @click="payTypeChange(index, item)">
|
||||
<div class="icon">
|
||||
<el-image :src="item.icon" class="img"></el-image>
|
||||
</div>
|
||||
<span class="title">{{ item.payName }}</span>
|
||||
</div>
|
||||
<div class="item" :class="{ active: payActive == 'buyer' }"
|
||||
@click="payTypeChange('buyer', { payType: 'buyer' })">
|
||||
<div class="icon">
|
||||
<div class="img"
|
||||
style="display: flex;align-items: center;justify-content: center;background-color: var(--el-color-danger);color: #fff;font-size: 24px;border-radius: 11px;">
|
||||
挂
|
||||
</div>
|
||||
</div>
|
||||
<span class="title">挂账</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input_wrap">
|
||||
<div class="input" style="flex: 1;">储值:¥{{ money }}</div>
|
||||
<div class="input" v-if="waitPayMoney > 0">待支付:¥{{ waitPayMoney }}</div>
|
||||
<!-- <div class="input" v-if="waitPayMoney > 0">待支付:¥{{ waitPayMoney }}</div> -->
|
||||
</div>
|
||||
<div class="blance">
|
||||
<!-- 可用余额:0.00 -->
|
||||
@@ -45,19 +61,99 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<scanModal ref="scanModalRef" :amount="props.amount" :orderId="props.orderId" :selecttype="props.selecttype"
|
||||
:payType="payType" @success="scanCodeSuccess" />
|
||||
<scanModal ref="scanModalRef" :amount="props.amount" :money="money" :orderId="props.orderId"
|
||||
:selecttype="props.selecttype" :payType="payType" @success="scanCodeSuccess" />
|
||||
<el-dialog :title="`选择会员`" top="3vh" v-model="showDialog" width="80%">
|
||||
<el-form inline>
|
||||
<el-form-item>
|
||||
<el-input placeholder="请输入手机号搜索会员" v-model="tableData.phone" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getMemberList">搜索</el-button>
|
||||
<el-button @click="resetTable">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="tableData.list" height="440px" border stripe v-loading="tableData.loading">
|
||||
<el-table-column prop="name" label="昵称" width="120px" />
|
||||
<el-table-column prop="telephone" label="手机" width="150px" />
|
||||
<el-table-column prop="code" label="编号" width="120px" />
|
||||
<el-table-column prop="level" label="等级" />
|
||||
<el-table-column prop="levelConsume" label="积分" />
|
||||
<el-table-column prop="amount" label="余额" width="100px">
|
||||
<template v-slot="scope">
|
||||
¥{{ formatDecimal(scope.row.amount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120px">
|
||||
<template v-slot="scope">
|
||||
<el-button type="primary" @click="toHomeMember(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination layout="prev, pager, next, total" background style="margin-top: 20px;"
|
||||
:total="Number(tableData.total)" v-model:current-page="tableData.page" @current-change="getMemberList" />
|
||||
</el-dialog>
|
||||
<!-- 选择挂账人员 -->
|
||||
<el-dialog title="挂账" top="3vh" v-model="showBuyer" width="90%" @closed="resetBuyerTable">
|
||||
<el-form inline>
|
||||
<el-form-item>
|
||||
<el-input placeholder="请输入挂账人或手机号搜索" v-model="buyerTable.keywords" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getBuyerList">搜索</el-button>
|
||||
<el-button @click="resetBuyerTable">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="buyerTable.list" height="440px" border stripe v-loading="buyerTable.loading">
|
||||
<el-table-column prop="debtor" label="挂账人" />
|
||||
<el-table-column prop="mobile" label="手机" width="150px" />
|
||||
<el-table-column prop="position" label="职位" width="120px" />
|
||||
<el-table-column prop="repaymentMethod" label="还款方式" width="160px">
|
||||
<template v-slot="scope">
|
||||
<template v-if="scope.row.repaymentMethod == 'total'">按总金额还款</template>
|
||||
<template v-if="scope.row.repaymentMethod == 'order'">按订单还款</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="creditAmount" label="挂账额度" width="160px">
|
||||
<template v-slot="scope">
|
||||
¥{{ formatDecimal(scope.row.creditAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remainingAmount" label="剩余挂账额度" width="160px">
|
||||
<template v-slot="scope">
|
||||
¥{{ formatDecimal(scope.row.remainingAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="accumulateAmount" label="累计挂账金额" width="160px">
|
||||
<template v-slot="scope">
|
||||
¥{{ formatDecimal(scope.row.accumulateAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120px" fixed="right">
|
||||
<template v-slot="scope">
|
||||
<el-button type="primary" @click="payCreditPayHandle(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination layout="prev, pager, next, total" background style="margin-top: 20px;"
|
||||
:total="Number(buyerTable.total)" v-model:current-page="buyerTable.page" @current-change="getBuyerList" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref, computed, watch } from 'vue'
|
||||
import { queryPayType, accountPay, cashPay } from '@/api/pay'
|
||||
import { onMounted, ref, computed, watch, reactive } from 'vue'
|
||||
import { queryPayType, accountPay, cashPay, vipPay, buyerPage, payCreditPay } from '@/api/pay'
|
||||
import { queryMembermember, createMembermember, membermemberScanPay, accountPaymember } from '@/api/member/index.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { clearNoNum } from '@/utils'
|
||||
import { clearNoNum, formatDecimal } from '@/utils'
|
||||
|
||||
import scanModal from '@/components/payCard/scanModal.vue'
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { staffPermission } from '@/api/user.js'
|
||||
import { fa } from 'element-plus/es/locale/index.mjs'
|
||||
|
||||
const global = useGlobal()
|
||||
|
||||
const store = useUser()
|
||||
|
||||
@@ -74,57 +170,148 @@ const props = defineProps({
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
member: {
|
||||
type: Object,
|
||||
default: {}
|
||||
discount: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['paySuccess'])
|
||||
const emit = defineEmits(['paySuccess', 'cancelDiscount'])
|
||||
|
||||
const money = ref('0')
|
||||
const scanModalRef = ref(null)
|
||||
|
||||
watch(props, (value) => {
|
||||
money.value = `${props.amount}`
|
||||
money.value = `${formatDecimal(props.amount)}`
|
||||
if (props.discount > 0) {
|
||||
money.value = `${formatDecimal(props.amount * props.discount)}`
|
||||
}
|
||||
})
|
||||
|
||||
const waitPayMoney = computed(() => {
|
||||
let num = JSON.stringify(props.amount - money.value)
|
||||
num = Math.floor(num * 100) / 100
|
||||
return num
|
||||
})
|
||||
// const waitPayMoney = computed(() => {
|
||||
// let num = JSON.stringify(props.amount - money.value)
|
||||
// num = Math.floor(num * 100) / 100
|
||||
// return num
|
||||
// })
|
||||
|
||||
const payActive = ref(0)
|
||||
const payType = ref('')
|
||||
const payList = ref([])
|
||||
const payLoading = ref(false)
|
||||
|
||||
// 挂账人 start
|
||||
const showBuyer = ref(false)
|
||||
const buyerTable = reactive({
|
||||
keywords: '',
|
||||
loading: false,
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
list: []
|
||||
})
|
||||
|
||||
// 显示挂账人
|
||||
function showBuyerHandle() {
|
||||
showBuyer.value = true
|
||||
getBuyerList()
|
||||
}
|
||||
|
||||
//
|
||||
function resetBuyerTable() {
|
||||
buyerTable.keywords = ''
|
||||
buyerTable.page = 1
|
||||
getBuyerList()
|
||||
}
|
||||
|
||||
// 获取挂账人列表
|
||||
async function getBuyerList() {
|
||||
try {
|
||||
buyerTable.loading = true
|
||||
const res = await buyerPage({
|
||||
page: buyerTable.page,
|
||||
size: buyerTable.size,
|
||||
shopId: store.userInfo.shopId,
|
||||
keywords: buyerTable.keywords,
|
||||
status: 1,
|
||||
responsiblePerson: '',
|
||||
repaymentStatus: ''
|
||||
})
|
||||
buyerTable.loading = false
|
||||
buyerTable.list = res.list
|
||||
buyerTable.total = res.total
|
||||
} catch (error) {
|
||||
buyerTable.loading = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 选择挂账人支付
|
||||
async function payCreditPayHandle(row) {
|
||||
try {
|
||||
payLoading.value = true
|
||||
buyerTable.loading = true
|
||||
const res = await payCreditPay({
|
||||
creditBuyerId: row.id,
|
||||
orderId: props.orderId,
|
||||
payAmount: props.discount > 0 ? money.value : '',
|
||||
discountAmount: props.discount > 0 ? formatDecimal(props.amount - money.value) : ''
|
||||
})
|
||||
showBuyer.value = false
|
||||
payLoading.value = false
|
||||
buyerTable.loading = false
|
||||
ElMessage.success('支付成功')
|
||||
emit('paySuccess')
|
||||
} catch (error) {
|
||||
buyerTable.loading = false
|
||||
payLoading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
// 显示选择挂账人 end
|
||||
|
||||
// 获得扫码值
|
||||
function scanCodeSuccess() {
|
||||
emit('paySuccess')
|
||||
}
|
||||
|
||||
// 切换支付类型
|
||||
function payTypeChange(index, item) {
|
||||
async function payTypeChange(index, item) {
|
||||
try {
|
||||
await staffPermission('yun_xu_shou_kuan')
|
||||
if (item.disabled) return
|
||||
payActive.value = index
|
||||
payType.value = item.payType
|
||||
if (item.payType == 'scanCode') {
|
||||
scanModalRef.value.show()
|
||||
}
|
||||
if (payList.value[payActive.value].payType == 'deposit' && !props.member.id) {
|
||||
if (item.payType == 'vipPay') {
|
||||
showDialog.value = true
|
||||
getMemberList()
|
||||
}
|
||||
if (item.payType == 'buyer') {
|
||||
showBuyerHandle()
|
||||
}
|
||||
if (payActive.value != 'buyer') {
|
||||
if (payList.value[payActive.value].payType == 'deposit' && !global.orderMemberInfo.id) {
|
||||
scanModalRef.value.show()
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 结算支付
|
||||
async function confirmOrder() {
|
||||
if (payLoading.value) return
|
||||
try {
|
||||
if (payList.value[payActive.value].payType == 'scanCode') {
|
||||
await staffPermission('yun_xu_shou_kuan')
|
||||
if (payLoading.value) return
|
||||
if (payActive.value == 'buyer') {
|
||||
showBuyerHandle()
|
||||
} else if (payList.value[payActive.value].payType == 'scanCode') {
|
||||
scanModalRef.value.show()
|
||||
} else {
|
||||
if (money.value < props.amount) return
|
||||
// if (money.value < props.amount) return
|
||||
payLoading.value = true
|
||||
switch (payList.value[payActive.value].payType) {
|
||||
case 'deposit'://储值卡
|
||||
@@ -133,10 +320,10 @@ async function confirmOrder() {
|
||||
// } else {
|
||||
|
||||
// }
|
||||
if (props.member.id) {
|
||||
if (global.orderMemberInfo.id) {
|
||||
await accountPay({
|
||||
orderId: props.orderId,
|
||||
memberId: props.member.id,
|
||||
memberId: global.orderMemberInfo.id,
|
||||
memberAccount: ''
|
||||
})
|
||||
} else {
|
||||
@@ -154,16 +341,18 @@ async function confirmOrder() {
|
||||
})
|
||||
} else {
|
||||
await cashPay({
|
||||
orderId: props.orderId
|
||||
orderId: props.orderId,
|
||||
payAmount: props.discount > 0 ? money.value : '',
|
||||
discountAmount: props.discount > 0 ? formatDecimal(props.amount - money.value) : ''
|
||||
})
|
||||
}
|
||||
break;
|
||||
case 'bank'://银行卡
|
||||
if (props.selecttype == 1) {//1 代表会员
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
case 'vipPay':
|
||||
// 会员支付
|
||||
console.log('使用会员id支付');
|
||||
payLoading.value = false
|
||||
showDialog.value = true
|
||||
return
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -203,8 +392,17 @@ async function queryPayTypeAjax() {
|
||||
const res = await queryPayType({
|
||||
shopId: store.userInfo.shopId
|
||||
})
|
||||
|
||||
res.map(item => {
|
||||
if (props.amount <= 0 && item.payType == 'scanCode') {
|
||||
item.disabled = true
|
||||
} else {
|
||||
item.disabled = false
|
||||
}
|
||||
})
|
||||
|
||||
payList.value = res
|
||||
if (res[0].payType == 'scanCode' || res[0].payType == 'deposit') {
|
||||
if ((res[0].payType == 'scanCode' && !res[0].disabled) || res[0].payType == 'deposit') {
|
||||
scanModalRef.value.show()
|
||||
payType.value = res[0].payType
|
||||
}
|
||||
@@ -213,8 +411,72 @@ async function queryPayTypeAjax() {
|
||||
}
|
||||
}
|
||||
|
||||
const showDialog = ref(false)
|
||||
const tableData = reactive({
|
||||
phone: '',
|
||||
loading: false,
|
||||
list: [],
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 重置表格
|
||||
function resetTable() {
|
||||
tableData.phone = ''
|
||||
tableData.page = 1
|
||||
getMemberList()
|
||||
}
|
||||
|
||||
// 获取会员列表
|
||||
async function getMemberList() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await queryMembermember({
|
||||
shopId: store.userInfo.shopId,
|
||||
phone: tableData.phone,
|
||||
page: tableData.page,
|
||||
pageSize: tableData.size,
|
||||
isFlag: 1
|
||||
})
|
||||
tableData.loading = false
|
||||
tableData.list = res.list
|
||||
tableData.total = res.total
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 选择会员去下单
|
||||
async function toHomeMember(row) {
|
||||
try {
|
||||
showDialog.value = false
|
||||
payLoading.value = true
|
||||
const res = await vipPay({
|
||||
orderId: props.orderId,
|
||||
vipUserId: row.id,
|
||||
payAmount: props.discount > 0 ? money.value : '',
|
||||
discountAmount: props.discount > 0 ? formatDecimal(props.amount - money.value) : ''
|
||||
})
|
||||
global.setOrderTable()
|
||||
global.setOrderMember()
|
||||
|
||||
payLoading.value = false
|
||||
ElMessage.success('支付成功')
|
||||
emit('paySuccess')
|
||||
} catch (error) {
|
||||
payLoading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 取消折扣
|
||||
function cancelDiscount() {
|
||||
emit('cancelDiscount')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
money.value = `${props.amount}`
|
||||
money.value = `${formatDecimal(props.amount)}`
|
||||
queryPayTypeAjax()
|
||||
})
|
||||
|
||||
@@ -248,9 +510,13 @@ onMounted(() => {
|
||||
|
||||
.t2 {
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
color: #999;
|
||||
padding-top: 10px;
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,6 +540,10 @@ onMounted(() => {
|
||||
position: relative;
|
||||
$lineHeight: 4px;
|
||||
|
||||
&.disabled {
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
&.active {
|
||||
&::after {
|
||||
content: "";
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="right" v-if="!userPayWait">
|
||||
<div class="amount">
|
||||
<span class="t">扫码支付</span>
|
||||
<span class="n">{{ props.amount }}</span>
|
||||
<span class="n">{{ props.money }}</span>
|
||||
</div>
|
||||
<div class="input">
|
||||
<el-input ref="inputRef" v-model="scanCode" style="height: calc(var(--el-component-size-large) + 30px)"
|
||||
@@ -52,11 +52,12 @@
|
||||
|
||||
<script setup>
|
||||
import _ from "lodash";
|
||||
import { ref } from "vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
import icon from "@/assets/icon_scan.png";
|
||||
import { scanpay, queryOrder, quickPay, queryQuickPayStatus, accountPay, queryScanPay } from "@/api/pay";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { formatDecimal } from '@/utils'
|
||||
const store = useUser();
|
||||
const global = useGlobal()
|
||||
import {
|
||||
@@ -88,6 +89,10 @@ const props = defineProps({
|
||||
payType: {
|
||||
type: [Number, String],
|
||||
default: "",
|
||||
},
|
||||
money: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
}
|
||||
});
|
||||
|
||||
@@ -112,6 +117,8 @@ async function submitHandle() {
|
||||
memberId: props.orderId,
|
||||
amount: props.amount,
|
||||
authCode: scanCode.value,
|
||||
// payAmount: props.money < props.amount ? props.money : '',
|
||||
// discountAmount: props.money < props.amount ? formatDecimal(props.amount - props.money) : ''
|
||||
});
|
||||
} else {
|
||||
if (props.fast) {
|
||||
@@ -125,13 +132,17 @@ async function submitHandle() {
|
||||
await scanpay({
|
||||
orderId: props.orderId,
|
||||
authCode: scanCode.value,
|
||||
payAmount: props.money < props.amount ? props.money : '',
|
||||
discountAmount: props.money < props.amount ? formatDecimal(props.amount - props.money) : ''
|
||||
});
|
||||
}
|
||||
if (props.payType == 'deposit') {
|
||||
await accountPay({
|
||||
orderId: props.orderId,
|
||||
memberId: '',
|
||||
memberAccount: scanCode.value
|
||||
memberAccount: scanCode.value,
|
||||
payAmount: props.money < props.amount ? props.money : '',
|
||||
discountAmount: props.money < props.amount ? formatDecimal(props.amount - props.money) : ''
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<!-- <div class="item" :class="{ active: val.active }" v-for="(val, i) in item.value" :key="i"
|
||||
@click="selectedSku(index, i)">{{ val.name }}</div> -->
|
||||
<el-button :plain="!val.active" type="primary" v-for="(val, i) in item.selectSpecResult
|
||||
" :key="i" @click="selectedSku(index, i)" class="btn">{{ val.name }}</el-button>
|
||||
" :key="i" :disabled="val.disabled" @click="selectedSku(index, i)" class="btn">{{ val.name }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -51,6 +51,8 @@ const goodsInfo = ref({})
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const selecSkuArray = ref([])
|
||||
|
||||
// 确认选择规格
|
||||
function submitSku() {
|
||||
dialogVisible.value = false
|
||||
@@ -67,10 +69,48 @@ function submitSku() {
|
||||
}
|
||||
|
||||
// 选择规格
|
||||
function selectedSku(index, i) {
|
||||
function selectedSku(index = 0, i = 0) {
|
||||
goods.value.selectSpec[index].selectSpecResult.map(item => {
|
||||
item.active = false
|
||||
})
|
||||
|
||||
|
||||
if (index == 0) {
|
||||
selecSkuArray.value = []
|
||||
}
|
||||
|
||||
|
||||
if (selecSkuArray.value.length - 1 > index) {
|
||||
// console.log(selecSkuArray.value.length - 1);
|
||||
// console.log(index);
|
||||
selecSkuArray.value.splice(index + 1, selecSkuArray.value.length)
|
||||
}
|
||||
|
||||
selecSkuArray.value[index] = goods.value.selectSpec[index].selectSpecResult[i].name
|
||||
|
||||
if (index < goods.value.selectSpec.length - 1) {
|
||||
selectedSkuNum.value = 0
|
||||
goods.value.selectSpec.map((item, idx) => {
|
||||
if (index < idx) {
|
||||
item.selectSpecResult.map(val => {
|
||||
val.disabled = true
|
||||
val.active = false
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
goods.value.selectSpec[index + 1].selectSpecResult.map(item => {
|
||||
goods.value.groundingSpecInfo.map(val => {
|
||||
// console.log(val);
|
||||
// console.log(`${selecSkuArray.value.join(',')},${item.name}`);
|
||||
// console.log(val.specSnap.indexOf(`${selecSkuArray.value.join(',')},${item.name}`));
|
||||
if (val.specSnap.indexOf(`${selecSkuArray.value.join(',')},${item.name}`) != -1 && val.isGrounding) {
|
||||
item.disabled = false
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (goods.value.selectSpec[index].selectSpecResult[i].active) {
|
||||
goods.value.selectSpec[index].selectSpecResult[i].active = false
|
||||
selectedSkuNum.value--
|
||||
@@ -78,6 +118,7 @@ function selectedSku(index, i) {
|
||||
goods.value.selectSpec[index].selectSpecResult[i].active = true
|
||||
selectedSkuNum.value++
|
||||
}
|
||||
|
||||
selectedSuccess()
|
||||
}
|
||||
|
||||
@@ -99,6 +140,8 @@ function selectedSuccess() {
|
||||
if (selectedSkuNum.value >= goods.value.selectSpec.length) {
|
||||
// 规格选完了
|
||||
queryProductSkuAjax()
|
||||
} else {
|
||||
goodsInfo.value = {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,14 +177,23 @@ function show(item, t = 'shop') {
|
||||
goods.value = item
|
||||
type.value = t
|
||||
goods.value.selectSpec = JSON.parse(goods.value.selectSpec)
|
||||
goods.value.selectSpec.map(item => {
|
||||
goods.value.selectSpec.map((item, index) => {
|
||||
let arr = []
|
||||
item.selectSpecResult.map(val => {
|
||||
switch (type.value) {
|
||||
case 'shop':
|
||||
let disabled = true
|
||||
if (index == 0) {
|
||||
goods.value.groundingSpecInfo.map(item => {
|
||||
if (item.specSnap.indexOf(val) != -1 && item.isGrounding) {
|
||||
disabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
arr.push({
|
||||
active: false,
|
||||
name: val
|
||||
name: val,
|
||||
disabled: index == 0 ? disabled : true
|
||||
})
|
||||
break;
|
||||
case 'cart':
|
||||
@@ -149,7 +201,8 @@ function show(item, t = 'shop') {
|
||||
const skus = goods.value.skuName.split(',')
|
||||
arr.push({
|
||||
active: !!skus.find(item => item === val),
|
||||
name: val
|
||||
name: val,
|
||||
disabled: true
|
||||
})
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button type="primary" style="width: 100%" @click="confirmHandle">确认</el-button>
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="confirmHandle">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -69,6 +69,7 @@ function delHandle() {
|
||||
number.value = number.value.substring(0, number.value.length - 1);
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
// 确认
|
||||
function confirmHandle() {
|
||||
if (!number.value) return
|
||||
@@ -77,8 +78,12 @@ function confirmHandle() {
|
||||
ElMessage.error('请输入正确的密码')
|
||||
return
|
||||
} else {
|
||||
loading.value = true
|
||||
emit("success", number.value);
|
||||
dialogVisible.value = false;
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
}
|
||||
} else {
|
||||
emit("success", number.value);
|
||||
|
||||
96
src/components/updateDialog.vue
Normal file
96
src/components/updateDialog.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" title="发现新版本" width="500" :close-on-click-modal="false"
|
||||
:close-on-press-escape="false" :show-close="false">
|
||||
<div class="message">
|
||||
{{ updataInfo.message }}
|
||||
</div>
|
||||
<div class="progress_wrap" style="padding-top: 20px;">
|
||||
<el-progress :percentage="uploadPro" :stroke-width="15" striped :striped-flow="uploadPro < 100" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="footer" style="padding: 0 20px 20px;">
|
||||
<el-button v-if="!updataInfo.isUp && !isUpload" @click="closeHandle">下次更新</el-button>
|
||||
<el-button type="primary" :loading="isUpload" @click="uplaodHandle">
|
||||
<template v-if="!uploadSucess">
|
||||
<template v-if="!isUpload">
|
||||
立即更新
|
||||
</template>
|
||||
<template v-else>
|
||||
下载中...
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
立即安装
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { findVersion } from '@/api/user.js'
|
||||
import packageData from "../../package.json";
|
||||
import { ipcRenderer } from 'electron'
|
||||
import useStorage from '@/utils/useStorage.js'
|
||||
|
||||
import { useUser } from "@/store/user.js";
|
||||
|
||||
const store = useUser()
|
||||
|
||||
const showDialog = ref(false)
|
||||
const updataInfo = ref({})
|
||||
const isUpload = ref(false)
|
||||
const uploadPro = ref(0)
|
||||
const uploadSucess = ref(false)
|
||||
const uploadResponse = ref({})
|
||||
const tempFilePath = ref('')
|
||||
|
||||
// 关闭更新弹窗,下次登录在提示
|
||||
function closeHandle() {
|
||||
showDialog.value = false
|
||||
useStorage.set('updateFlag', true)
|
||||
}
|
||||
|
||||
// 检查版本更新
|
||||
async function findVersionAjax() {
|
||||
try {
|
||||
let updateFlag = useStorage.get('updateFlag')
|
||||
const res = await findVersion()
|
||||
let reg = /\./g;
|
||||
if (res.version.replace(reg, '') > packageData.version.replace(reg, '') && res.url && !updateFlag) {
|
||||
showDialog.value = true
|
||||
updataInfo.value = res
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 下载新版本
|
||||
async function uplaodHandle() {
|
||||
try {
|
||||
if (!uploadSucess.value) {
|
||||
isUpload.value = true
|
||||
ipcRenderer.send('downloadFile', JSON.stringify({ url: updataInfo.value.url }))
|
||||
// await downloadFile(updataInfo.value.url)
|
||||
// isUpload.value = false
|
||||
// uploadSucess.value = true
|
||||
} else {
|
||||
// 安装文件
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (store.userInfo) {
|
||||
findVersionAjax()
|
||||
}
|
||||
ipcRenderer.on('updateProgress', (event, res) => {
|
||||
uploadPro.value = res
|
||||
})
|
||||
})
|
||||
</script>
|
||||
114
src/components/uploadImg.vue
Normal file
114
src/components/uploadImg.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<el-upload ref="uploadRef" v-model:file-list="fileList" :action="uploadUrl" :headers="headers" :list-type="listType"
|
||||
:multiple="multiple" :limit="limit" :on-exceed="handleExceed" :on-change="handleChange"
|
||||
:on-progress="handleProgress" :on-success="handleSuccess" :on-error="handleError" :before-upload="beforeUpload"
|
||||
:accept="accept" :disabled="disabled">
|
||||
<el-icon>
|
||||
<Plus />
|
||||
</el-icon>
|
||||
<template v-slot:tip>
|
||||
<div v-if="tip">{{ tip }}</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import useStorage from '@/utils/useStorage'
|
||||
import { ElUpload, ElMessage } from 'element-plus';
|
||||
|
||||
const fileList = ref([])
|
||||
|
||||
// 定义接收的外部属性
|
||||
const props = defineProps({
|
||||
uploadUrl: {
|
||||
type: String,
|
||||
default: import.meta.env.MODE == 'development' ? '/api/shopInfo/upload' : import.meta.env.VITE_API_URL + '/shopInfo/upload',
|
||||
},
|
||||
headers: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
token: useStorage.get("token"),
|
||||
loginName: useStorage.get("userInfo").loginName,
|
||||
clientType: 'pc'
|
||||
}),
|
||||
},
|
||||
listType: {
|
||||
type: String,
|
||||
default: 'picture-card',
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
tip: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
accept: {
|
||||
type: String,
|
||||
default: 'image/jpeg,image/png,image/gif',
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
// 内部引用上传组件实例
|
||||
const uploadRef = ref(null);
|
||||
|
||||
// 处理文件超出数量限制的情况
|
||||
const handleExceed = (files, fileList) => {
|
||||
ElMessage.warning(`超出最大允许上传图片数量:${props.limit}`);
|
||||
};
|
||||
|
||||
// 处理文件状态改变
|
||||
const handleChange = (file, fileList) => {
|
||||
console.log('图片文件状态改变', file, fileList);
|
||||
};
|
||||
|
||||
// 处理上传进度
|
||||
const handleProgress = (event, file, fileList) => {
|
||||
console.log('图片上传进度', event.percent);
|
||||
};
|
||||
|
||||
// 处理上传成功
|
||||
const handleSuccess = (response, file, fileList) => {
|
||||
ElMessage.success('图片上传成功');
|
||||
console.log('图片上传成功响应', response);
|
||||
emits('success', response.data)
|
||||
};
|
||||
|
||||
// 处理上传失败
|
||||
const handleError = (error, file, fileList) => {
|
||||
ElMessage.error('图片上传失败');
|
||||
console.error('图片上传失败原因', error);
|
||||
};
|
||||
|
||||
// 上传前校验,这里主要校验图片格式
|
||||
const beforeUpload = (file) => {
|
||||
const isImage = props.accept.split(',').some(format => file.type === format.trim());
|
||||
if (!isImage) {
|
||||
ElMessage.error('请选择正确格式的图片文件');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
function init(arr) {
|
||||
fileList.value = arr
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
init
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -57,6 +57,14 @@ const routes = [
|
||||
},
|
||||
component: () => import("@/views/member/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/queue",
|
||||
name: "queue",
|
||||
meta: {
|
||||
index: 1,
|
||||
},
|
||||
component: () => import("@/views/queue/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/work",
|
||||
name: "work",
|
||||
|
||||
@@ -5,11 +5,21 @@ export const useGlobal = defineStore({
|
||||
state: () => ({
|
||||
// 是否监听叫号
|
||||
isCallNumber: true,
|
||||
orderMemberInfo: {},
|
||||
tableInfo: {},
|
||||
}),
|
||||
actions: {
|
||||
// 更新状态
|
||||
updateData(state) {
|
||||
this.isCallNumber = state;
|
||||
},
|
||||
// 设置订单会员信息
|
||||
setOrderMember(obj) {
|
||||
this.orderMemberInfo = obj;
|
||||
},
|
||||
// 设置订单台桌信息
|
||||
setOrderTable(obj) {
|
||||
this.tableInfo = obj;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import { defineStore } from "pinia";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { bySubType } from "@/api/device";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useShop } from "@/store/shop.js";
|
||||
import dayjs from "dayjs";
|
||||
import receiptPrint from "@/components/lodop/receiptPrint.js";
|
||||
import lodopPrintWork from "@/components/lodop/lodopPrintWork.js";
|
||||
@@ -64,6 +65,8 @@ export const usePrint = defineStore({
|
||||
},
|
||||
// 打印标签小票
|
||||
labelPrint(props) {
|
||||
const shopInfo = useShop();
|
||||
|
||||
if (
|
||||
this.deviceLableList.length &&
|
||||
this.checkLocalPrint(this.deviceLableList[0].config.deviceName)
|
||||
@@ -97,6 +100,7 @@ export const usePrint = defineStore({
|
||||
createdAt: dayjs(props.createdAt).format("YYYY-MM-DD HH:mm:ss"),
|
||||
isPrint: false,
|
||||
count: `${count}/${sum}`,
|
||||
ticketLogo: shopInfo.info.ticketLogo,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -159,6 +163,9 @@ export const usePrint = defineStore({
|
||||
props.orderInfo.masterId = props.orderInfo.tableName;
|
||||
}
|
||||
props.orderInfo.outNumber = props.outNumber;
|
||||
if (!props.discountAmount) {
|
||||
props.discountAmount = props.amount;
|
||||
}
|
||||
|
||||
this.receiptList.push(props);
|
||||
this.startReceiptPrint();
|
||||
|
||||
22
src/store/shop.js
Normal file
22
src/store/shop.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { queryShopInfo } from "@/api/user";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
|
||||
export const useShop = defineStore({
|
||||
id: "shopInfo",
|
||||
state: () => ({
|
||||
info: useStorage.get("shopInfo"),
|
||||
}),
|
||||
actions: {
|
||||
// 获取店铺信息
|
||||
async queryShopInfo() {
|
||||
try {
|
||||
const res = await queryShopInfo();
|
||||
useStorage.set("shopInfo", res);
|
||||
this.info = useStorage.get("shopInfo");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -16,6 +16,7 @@ export const useSocket = defineStore({
|
||||
uuid: "", // 长连接唯一id
|
||||
heartbeatTimer: null, // 心跳计时器
|
||||
orderList: [],
|
||||
log: true,
|
||||
}),
|
||||
actions: {
|
||||
// 创建uuid
|
||||
@@ -33,7 +34,8 @@ export const useSocket = defineStore({
|
||||
},
|
||||
// 关闭ws
|
||||
close() {
|
||||
console.log("关闭ws");
|
||||
if (this.log) console.log("关闭ws");
|
||||
this.online = false;
|
||||
this.ws.close(1000);
|
||||
this.ws = null;
|
||||
this.clearHeartBeat();
|
||||
@@ -56,7 +58,7 @@ export const useSocket = defineStore({
|
||||
printStore.init();
|
||||
|
||||
if (this.ws == null) {
|
||||
console.log("创建新的ws连接");
|
||||
if (this.log) console.log("创建新的ws连接");
|
||||
|
||||
const protocols = []; // 可选的子协议数组
|
||||
const options = {
|
||||
@@ -66,17 +68,17 @@ export const useSocket = defineStore({
|
||||
};
|
||||
this.ws = new ReconnectingWebSocket(wsUrl, protocols, options);
|
||||
} else {
|
||||
console.log("重新连接ws");
|
||||
if (this.log) console.log("重新连接ws");
|
||||
this.wsReconnect();
|
||||
}
|
||||
|
||||
this.ws.addEventListener("open", (event) => {
|
||||
console.log("wss连接成功");
|
||||
if (this.log) console.log("wss连接成功");
|
||||
this.online = true;
|
||||
// 清除心跳
|
||||
this.clearHeartBeat();
|
||||
|
||||
console.log(this);
|
||||
if (this.log) console.log(this);
|
||||
|
||||
this.ws.send(
|
||||
JSON.stringify({
|
||||
@@ -91,7 +93,7 @@ export const useSocket = defineStore({
|
||||
this.ws.addEventListener("message", (e) => {
|
||||
let data = JSON.parse(e.data);
|
||||
if (data.type == "order") {
|
||||
console.log("接收消息", data);
|
||||
if (this.log) console.log("接收消息", data);
|
||||
this.ws.send(
|
||||
JSON.stringify({
|
||||
type: "send",
|
||||
@@ -111,18 +113,18 @@ export const useSocket = defineStore({
|
||||
}
|
||||
}
|
||||
} else if (data.type == "heartbeat") {
|
||||
console.log("接收心跳");
|
||||
if (this.log) console.log("接收心跳");
|
||||
}
|
||||
});
|
||||
|
||||
this.ws.addEventListener("error", () => {
|
||||
console.log("WebSocket连接发生错误");
|
||||
if (this.log) console.log("WebSocket连接发生错误");
|
||||
this.online = false;
|
||||
this.clearHeartBeat();
|
||||
});
|
||||
|
||||
this.ws.addEventListener("error", (e) => {
|
||||
console.log("ws关闭了", e);
|
||||
if (this.log) console.log("ws关闭了", e);
|
||||
this.online = false;
|
||||
this.clearHeartBeat();
|
||||
});
|
||||
@@ -130,7 +132,7 @@ export const useSocket = defineStore({
|
||||
// 启动心跳连接
|
||||
startheartbeat() {
|
||||
this.heartbeatTimer = setInterval(() => {
|
||||
console.log("发送心跳");
|
||||
if (this.log) console.log("发送心跳");
|
||||
this.ws.send(JSON.stringify({ type: "heartbeat" }));
|
||||
}, 10000);
|
||||
},
|
||||
|
||||
@@ -57,3 +57,42 @@ export function formatDecimal(num, decimal = 2, isInt = false) {
|
||||
return parseFloat(num).toFixed(decimal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤input只能输入整数
|
||||
* @param {*} value
|
||||
* @returns
|
||||
*/
|
||||
export function inputFilterInt(value) {
|
||||
if (!value) return;
|
||||
return value.replace(/[^\d]/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤input只能输入数字,并且最多输入两位小数
|
||||
* @param {*} value
|
||||
* @returns
|
||||
*/
|
||||
export function inputFilterFloat(value) {
|
||||
if (!value) return;
|
||||
// 去除首位小数点
|
||||
if (value.startsWith(".")) {
|
||||
value = value.slice(1);
|
||||
}
|
||||
// 清除非数字和小数点(除了第一个小数点)
|
||||
value = value.replace(/[^\d.]/g, "");
|
||||
// 确保最多只有一个小数点
|
||||
if (value.split(".").length > 2) {
|
||||
value = value.split(".").slice(0, 2).join(".");
|
||||
}
|
||||
// 限制小数位数为两位
|
||||
if (value.split(".")[1] && value.split(".")[1].length > 2) {
|
||||
value = value.split(".")[0] + "." + value.split(".")[1].slice(0, 2);
|
||||
}
|
||||
// 限制首位只能输入一个0
|
||||
if (value.startsWith("0") && value.length > 1 && value[1] === "0") {
|
||||
// 如果首位是0,且第二位也是0,将第二个0及之后的内容清空
|
||||
value = "0";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -179,6 +179,8 @@ const printData = reactive({
|
||||
}
|
||||
],
|
||||
amount: '30.00',
|
||||
discountAmount: '30.00',
|
||||
discount: 0,
|
||||
remark: '给我多放点辣椒,谢谢老板',
|
||||
orderInfo: {
|
||||
masterId: '#002',
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
<div class="print_view">
|
||||
<canvas class="ewm" ref="canvasRef"></canvas>
|
||||
<div class="header">
|
||||
<img class="logo" src="../../assets/prinnt_label_logo.png" />
|
||||
<img class="logo" :src="shopInfo.info.ticketLogo" />
|
||||
<!-- <span class="title">双屿Pisces</span> -->
|
||||
</div>
|
||||
<div class="number_wrap">
|
||||
@@ -122,6 +122,7 @@ import { Loading } from "element-plus/es/components/loading/src/service";
|
||||
import classify from "@/components/classify/index.vue";
|
||||
import QRCode from 'qrcode'
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { useShop } from "@/store/shop.js";
|
||||
|
||||
const printStore = usePrint();
|
||||
|
||||
@@ -129,6 +130,7 @@ const store = useUser();
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const shopInfo = useShop();
|
||||
|
||||
const classifyRef = ref(null);
|
||||
const printList = ref([]);
|
||||
@@ -159,10 +161,11 @@ const canvasRef = ref(null)
|
||||
const printData = ref({
|
||||
deviceName: '',
|
||||
outNumber: '123',
|
||||
name: '甜橙马黛茶',
|
||||
skuName: '加奶、加珍珠',
|
||||
name: '【测试勿管】甜橙马黛茶',
|
||||
skuName: '测试、加珍珠',
|
||||
masterId: '#A9',
|
||||
createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss')
|
||||
createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
ticketLogo: shopInfo.info.ticketLogo,
|
||||
})
|
||||
|
||||
// 获取打印机列表
|
||||
@@ -284,6 +287,8 @@ onMounted(() => {
|
||||
.logo {
|
||||
$size: 90px;
|
||||
width: $size;
|
||||
height: 30px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table ref="douyin_table" :data="groupDetail.goods" border v-if="props.type == 2">
|
||||
<el-table ref="douyin_table" :data="groupDetail.goods" border v-else>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="名称" prop="title"></el-table-column>
|
||||
<el-table-column label="价格" prop="amount"></el-table-column>
|
||||
@@ -100,7 +100,7 @@
|
||||
import _ from "lodash";
|
||||
import { ref } from "vue";
|
||||
import icon from "@/assets/icon_scan.png";
|
||||
import { groupOrderorderInfo, groupOrdergroupScan, douyinfulfilmentcertificateprepare, douyincertificateprepare } from '@/api/group'
|
||||
import { groupOrderorderInfo, groupOrdergroupScan, douyinfulfilmentcertificateprepare, douyincertificateprepare, thirdPartyCoupon_list, certificateprepare } from '@/api/group'
|
||||
import { useUser } from "@/store/user.js";
|
||||
import BindShop from './bindShop.vue'
|
||||
const BindShopRef = ref(null)
|
||||
@@ -173,6 +173,23 @@ async function groupOrdergroupScanHandle() {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// 美团团购
|
||||
{
|
||||
let encrypted_codes = douyin_table.value.getSelectionRows()
|
||||
if (encrypted_codes.length) {
|
||||
groupDetailLoading.value = true
|
||||
let arr = encrypted_codes.map(item => item.encrypted_code)
|
||||
const res = await certificateprepare({
|
||||
couponCode: groupDetail.value.couponCode,
|
||||
num: encrypted_codes.length
|
||||
})
|
||||
} else {
|
||||
ElMessage.error('请选择核销项目')
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -221,6 +238,23 @@ async function submitHandle() {
|
||||
}, 100)
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
const res = await thirdPartyCoupon_list({
|
||||
shopId: store.userInfo.shopId,
|
||||
code: scanCode.value
|
||||
});
|
||||
dialogVisible.value = false
|
||||
loading.value = false
|
||||
groupDetail.value = res
|
||||
detailVisible.value = true
|
||||
setTimeout(() => {
|
||||
groupDetail.value.goods.map(item => {
|
||||
douyin_table.value.toggleRowSelection(item)
|
||||
})
|
||||
}, 100)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
@click="resetHandle">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-button type="warning" :icon="FullScreen" @click="scanGroupRef.show()">核销团购券</el-button>
|
||||
<el-button type="warning" :icon="FullScreen" @click="showScanModalHandle">核销团购券</el-button>
|
||||
</div>
|
||||
<div class="tab_container">
|
||||
<el-table :data="tableData.list" height="540px" v-loading="tableData.loading"
|
||||
@@ -101,6 +101,24 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table height="540px" :data="tableData.list" v-loading="tableData.loading"
|
||||
v-if="tableData.type == 3">
|
||||
<el-table-column label="名称" prop="dealTitle"></el-table-column>
|
||||
<el-table-column label="总金额" prop="couponBuyPrice" width="100">
|
||||
<template v-slot="scope">
|
||||
<span style="color: var(--primary-color);">¥{{ scope.row.couponBuyPrice }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" prop="couponStatusDesc" width="150"></el-table-column>
|
||||
<el-table-column label="使用时间" prop="couponUseTime" width="200"></el-table-column>
|
||||
<el-table-column label="操作" prop="douyinCodeGoods" width="100">
|
||||
<template v-slot="scope">
|
||||
<el-button type="danger" size="small" @click="cacelMeittuanHandle(scope.row)">
|
||||
撤销
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<el-pagination v-model:current-page="tableData.page" v-model:page-size="tableData.size"
|
||||
@@ -112,11 +130,22 @@
|
||||
<scanGroup ref="scanGroupRef" :title="typeList.find(item => item.value == tableData.type).label"
|
||||
:type="tableData.type" @succcess="groupOrderlistAjax" />
|
||||
<refundDialog ref="refundDialogRef" @success="groupOrderlistAjax" />
|
||||
<el-dialog v-model="showMeituanUrlModal" title="注意">
|
||||
<span style="font-size: 18px;">您的店铺还未绑定美团,请绑定后操作!</span>
|
||||
<template #footer>
|
||||
<div class="dialog-footer" style="padding: 0 15px 15px;">
|
||||
<el-button @click="showMeituanUrlModal = false">取消</el-button>
|
||||
<el-button type="primary" @click="openMeituan">
|
||||
去绑定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { groupOrderlist, douyinorderlist, douyinfulfilmentcertificatecancel } from '@/api/group'
|
||||
import { groupOrderlist, douyinorderlist, douyinfulfilmentcertificatecancel, thirdPartyCoupon_state, thirdPartyCoupon_bindUrl, meituan_orderlist, meituan_fulfilmentcertificatecancel } from '@/api/group'
|
||||
import { Search, RefreshRight, FullScreen } from '@element-plus/icons-vue'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
import { ref, onMounted, reactive } from 'vue'
|
||||
@@ -124,6 +153,7 @@ import scanGroup from './components/scanGroup.vue'
|
||||
import refundDialog from './components/refundDialog.vue'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import BindShop from './components/bindShop.vue'
|
||||
import { shell } from 'electron'
|
||||
const store = useUser()
|
||||
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
@@ -144,7 +174,7 @@ function typeStatus(t) {
|
||||
const tableData = reactive({
|
||||
resetLoading: false,
|
||||
proName: '',
|
||||
type: 2,
|
||||
type: 3,
|
||||
status: '',
|
||||
loading: false,
|
||||
list: [],
|
||||
@@ -171,6 +201,10 @@ const typeList = reactive([
|
||||
{
|
||||
value: 2,
|
||||
label: '抖音'
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '美团'
|
||||
}
|
||||
])
|
||||
|
||||
@@ -229,6 +263,10 @@ function typeChange(e) {
|
||||
case 2:
|
||||
statusList.value = [...dmStatus]
|
||||
break;
|
||||
case 3:
|
||||
statusList.value = [...dmStatus]
|
||||
thirdPartyCoupon_state_ajax()
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -238,6 +276,54 @@ function typeChange(e) {
|
||||
groupOrderlistAjax()
|
||||
}
|
||||
|
||||
// 获取美团绑定状态
|
||||
const meituanStatus = ref(false)
|
||||
async function thirdPartyCoupon_state_ajax() {
|
||||
try {
|
||||
const res = await thirdPartyCoupon_state({
|
||||
shopId: store.userInfo.shopId
|
||||
})
|
||||
if (res.status == 0) {
|
||||
meituanStatus.value = false
|
||||
showMeituanUrlModal.value = true
|
||||
thirdPartyCoupon_bindUrl_ajax()
|
||||
} else {
|
||||
meituanStatus.value = true
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取美团绑定链接
|
||||
const meituanURL = ref('')
|
||||
const showMeituanUrlModal = ref(false)
|
||||
async function thirdPartyCoupon_bindUrl_ajax() {
|
||||
try {
|
||||
const res = await thirdPartyCoupon_bindUrl({
|
||||
shopId: store.userInfo.shopId
|
||||
})
|
||||
meituanURL.value = res
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 确认打开绑定美团链接
|
||||
function openMeituan() {
|
||||
showMeituanUrlModal.value = false
|
||||
shell.openExternal(meituanURL.value);
|
||||
}
|
||||
|
||||
function showScanModalHandle() {
|
||||
// 若果是美团并且没有绑定,则需要先绑定
|
||||
if (tableData.type == 3 && !meituanStatus.value) {
|
||||
showMeituanUrlModal.value = true
|
||||
return
|
||||
}
|
||||
scanGroupRef.value.show()
|
||||
}
|
||||
|
||||
// 状态
|
||||
function statusFilter(t) {
|
||||
return originStatus.find(item => item.value == t)?.label
|
||||
@@ -268,6 +354,21 @@ function cacelDouyinHandle(item) {
|
||||
}).catch(() => { })
|
||||
}
|
||||
|
||||
// 显示美团团购撤销
|
||||
function cacelMeittuanHandle(item) {
|
||||
ElMessageBox.confirm(
|
||||
'是否撤销该团购?',
|
||||
'注意').then(async () => {
|
||||
try {
|
||||
await meituan_fulfilmentcertificatecancel({ couponCode: item.couponCode })
|
||||
ElMessage.success('撤销成功')
|
||||
groupOrderlistAjax()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}).catch(() => { })
|
||||
}
|
||||
|
||||
// 获取团购订单数据
|
||||
async function groupOrderlistAjax() {
|
||||
try {
|
||||
@@ -300,6 +401,19 @@ async function groupOrderlistAjax() {
|
||||
tableData.list = res.list
|
||||
tableData.total = res.count
|
||||
break;
|
||||
case 3:
|
||||
// 获取美团购数据
|
||||
res = await meituan_orderlist({
|
||||
page: tableData.page,
|
||||
// status: tableData.status,
|
||||
// d_order_id: tableData.proName,
|
||||
date: ''
|
||||
})
|
||||
tableData.resetLoading = false
|
||||
tableData.loading = false
|
||||
tableData.list = res.list
|
||||
tableData.total = res.count
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6,18 +6,24 @@
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item number" @click="props.item.id && takeFoodCodeRef.show()">
|
||||
<el-text class="num">{{ props.item.number || 1 }}</el-text>
|
||||
<el-text class="num">{{ formatDecimal(props.item.number || 1, 2, true) }}</el-text>
|
||||
</div>
|
||||
<div class="item" @click="numberChange('add')">
|
||||
<el-icon class="icon add">
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item" :class="{ disabled: (props.item.id && !props.item.tbProductSpec) }" @click="showSkuModal">
|
||||
<!-- <div class="item" :class="{ disabled: (props.item.id && !props.item.tbProductSpec) }" @click="showSkuModal">
|
||||
<el-icon class="icon">
|
||||
<Filter />
|
||||
</el-icon>
|
||||
<el-text class="t">规格</el-text>
|
||||
</div> -->
|
||||
<div class="item" @click="showDiscountModalHandle">
|
||||
<el-icon class="icon">
|
||||
<PriceTag />
|
||||
</el-icon>
|
||||
<el-text class="t">打折</el-text>
|
||||
</div>
|
||||
<div class="item" :class="{ disabled: props.item.isGift == 'true' }" @click="giftPackHandle('isGift')">
|
||||
<el-icon class="icon">
|
||||
@@ -25,12 +31,19 @@
|
||||
</el-icon>
|
||||
<el-text class="t">赠送</el-text>
|
||||
</div>
|
||||
<div class="item" :class="{ disabled: props.item.isPack == 'true' }" @click="giftPackHandle('isPack')">
|
||||
<div class="item" :class="{ disabled: props.item.isPack == 'true' }" @click="giftPackHandle('isPack')"
|
||||
v-if="JSON.parse(shopStore.info.eatModel).some(item => item == 'take-out')">
|
||||
<el-icon class="icon">
|
||||
<Box />
|
||||
</el-icon>
|
||||
<el-text class="t">打包</el-text>
|
||||
</div>
|
||||
<div class="item" :class="{ disabled: props.item.isPrint == 0 }" @click="kitchenPrint">
|
||||
<el-icon class="icon">
|
||||
<DishDot />
|
||||
</el-icon>
|
||||
<el-text class="t">免厨</el-text>
|
||||
</div>
|
||||
<div class="item" @click="props.item.id && emit('delete', props.item)">
|
||||
<el-icon class="icon">
|
||||
<Delete />
|
||||
@@ -43,6 +56,13 @@
|
||||
</el-icon>
|
||||
<el-text class="t">挂单</el-text>
|
||||
</div>
|
||||
<div class="item" @click="tableMergingHandle"
|
||||
v-if="shopStore.info.registerType == 'restaurant' && props.item.tableId && props.item.orderId">
|
||||
<el-icon class="icon">
|
||||
<EditPen />
|
||||
</el-icon>
|
||||
<el-text class="t">转桌</el-text>
|
||||
</div>
|
||||
<div class="item" @click="props.item.id && emit('clearCart')">
|
||||
<el-icon class="icon">
|
||||
<RefreshRight />
|
||||
@@ -53,19 +73,58 @@
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="修改商品数量" placeholder="请输入商品数量" @success="updateNumber" />
|
||||
<!-- 购物车选择规格 -->
|
||||
<skuModal ref="skuModalRef" @success="skuConfirm" />
|
||||
<!-- 单品打折 -->
|
||||
<el-dialog v-model="showDiscountModal" title="单品打折" @open="resetDiscountForm = { ...discountForm }"
|
||||
@closed="discountModalClose">
|
||||
<div class="dialog">
|
||||
<div class="el-popover__title content">
|
||||
<el-form ref="discountFormRef" :model="discountForm" :rules="discountFormRules" label-width="100px"
|
||||
label-position="left">
|
||||
<el-form-item label="价格更改" prop="amount">
|
||||
<el-input v-model="discountForm.amount" placeholder="减8.88元请输入8.88" @input="priceInput">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="更改原因">
|
||||
<el-input v-model="discountForm.note" type="textarea" placeholder="请输入自定义备注" />
|
||||
<div class="remark_list">
|
||||
<div class="item" v-for="item in noteList" :key="item" @click="addNote(item)">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showDiscountModal = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :loading="discountFormLoading"
|
||||
@click="discountFormSubmit">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import takeFoodCode from '@/components/takeFoodCode.vue'
|
||||
import skuModal from '@/components/skuModal.vue'
|
||||
import { useShop } from '@/store/shop.js'
|
||||
import { inputFilterFloat, formatDecimal } from '@/utils/index.js'
|
||||
import { updatePrice, orderPrint } from '@/api/product.js'
|
||||
|
||||
const shopStore = useShop()
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['confirm', 'delete', 'pending', 'clearCart'])
|
||||
const emit = defineEmits(['confirm', 'delete', 'pending', 'clearCart', 'merging'])
|
||||
|
||||
const takeFoodCodeRef = ref(null)
|
||||
const skuModalRef = ref([])
|
||||
@@ -83,6 +142,8 @@ function giftPackHandle(key) {
|
||||
|
||||
// 加减修改数量
|
||||
function numberChange(t) {
|
||||
console.log(props.item);
|
||||
|
||||
if (!props.item.id) return
|
||||
switch (t) {
|
||||
case 'sub':
|
||||
@@ -118,6 +179,122 @@ function skuConfirm(e) {
|
||||
if (!props.item.id) return
|
||||
emit('confirm', e)
|
||||
}
|
||||
|
||||
/**单品打折 start */
|
||||
const showDiscountModal = ref(false)
|
||||
const resetDiscountForm = ref({})
|
||||
const discountFormRef = ref(null)
|
||||
const discountFormLoading = ref(false)
|
||||
const discountForm = ref({
|
||||
masterId: '',
|
||||
cartId: '',
|
||||
amount: '',
|
||||
note: '',
|
||||
shopId: ''
|
||||
})
|
||||
|
||||
function validateAmount(rule, value, callback) {
|
||||
if (value == '') {
|
||||
callback(new Error('请输入折扣价格'))
|
||||
} else if (value <= 0) {
|
||||
callback(new Error('输入价格有误'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const discountFormRules = ref({
|
||||
amount: [
|
||||
{
|
||||
required: true,
|
||||
validator: validateAmount,
|
||||
trigger: 'blur',
|
||||
}
|
||||
]
|
||||
})
|
||||
const noteList = ref([
|
||||
'顾客投诉质量...',
|
||||
'友情打折',
|
||||
'临时活动',
|
||||
])
|
||||
|
||||
// 显示
|
||||
function showDiscountModalHandle() {
|
||||
if (props.item.id) {
|
||||
showDiscountModal.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤价格输入
|
||||
function priceInput(e) {
|
||||
setTimeout(() => {
|
||||
discountForm.value.amount = inputFilterFloat(e)
|
||||
}, 50)
|
||||
}
|
||||
|
||||
// 关闭
|
||||
function discountModalClose() {
|
||||
discountForm.value = { ...resetDiscountForm.value }
|
||||
discountFormRef.value.resetFields()
|
||||
}
|
||||
|
||||
// 添加快捷备注
|
||||
function addNote(str) {
|
||||
if (!discountForm.value.note.length) {
|
||||
discountForm.value.note += str
|
||||
} else {
|
||||
discountForm.value.note += `,${str}`
|
||||
}
|
||||
}
|
||||
|
||||
// 提交
|
||||
function discountFormSubmit() {
|
||||
discountFormRef.value.validate(async valid => {
|
||||
try {
|
||||
if (valid) {
|
||||
discountFormLoading.value = true
|
||||
|
||||
discountForm.value.masterId = props.item.masterId
|
||||
discountForm.value.cartId = props.item.id
|
||||
discountForm.value.shopId = props.item.shopId
|
||||
|
||||
await updatePrice(discountForm.value)
|
||||
discountFormLoading.value = false
|
||||
|
||||
showDiscountModal.value = false
|
||||
ElMessage.success('操作成功')
|
||||
emit('confirm', { isTemporary: true })
|
||||
}
|
||||
} catch (error) {
|
||||
discountFormLoading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
/**单品打折 end */
|
||||
|
||||
/**免厨打印 start */
|
||||
async function kitchenPrint() {
|
||||
try {
|
||||
const res = await orderPrint({
|
||||
isPrint: props.item.isPrint ? 0 : 1,
|
||||
shopId: props.item.shopId,
|
||||
cartId: props.item.id
|
||||
})
|
||||
emit('confirm', { isTemporary: true })
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
/**免厨打印 end */
|
||||
|
||||
|
||||
// 显示合并转桌
|
||||
function tableMergingHandle() {
|
||||
if (props.item.id) {
|
||||
emit('merging')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -125,7 +302,7 @@ function skuConfirm(e) {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
gap: 10px;
|
||||
|
||||
.item {
|
||||
width: 70px;
|
||||
@@ -170,4 +347,33 @@ function skuConfirm(e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog {
|
||||
|
||||
.content {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.footer_wrap {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remark_list {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
|
||||
.item {
|
||||
padding: 0 10px;
|
||||
border: 1px solid #ddd;
|
||||
color: #999;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -26,29 +26,61 @@
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="search_wrap">
|
||||
<div class="left">
|
||||
<el-button :type="showEditor ? 'warning' : ''" @click="showEditorChange">
|
||||
{{ showEditor ? '关闭编辑' : '编辑' }}
|
||||
</el-button>
|
||||
<el-button type="warning" icon="Food" @click="showTemporaryDish = true">临时菜</el-button>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="input">
|
||||
<el-input placeholder="请输入商品名称查询" v-model="commdityName" clearable @focus="
|
||||
global.updateData(false)" @blur="global.updateData(true)" @input="inputChange"></el-input>
|
||||
</div>
|
||||
<el-button :loading="searchLoading" :icon="Search" @click="searchHandle">搜索</el-button>
|
||||
</div>
|
||||
<!-- <el-button :icon="shopListType == 'text' ? 'PictureRounded' : 'PriceTag'"
|
||||
@click="changeShopListType"></el-button> -->
|
||||
</div>
|
||||
<div class="shop_list" :class="{ img: shopListType == 'img' }" v-loading="loading">
|
||||
<!-- <swiper class="swiper_box" direction="vertical" @slideChange="onSlideChange"> -->
|
||||
<swiper class="swiper_box" direction="vertical" @slideChange="onSlideChange">
|
||||
<swiper ref="swiperRef" :loop="false" class="swiper_box" direction="vertical" @slideChange="onSlideChange">
|
||||
<swiper-slide class="slide_item" v-for="(goods, index) in goodsList" :key="index">
|
||||
<div class="item_wrap" v-for="item in goods" :key="item.id" @click="showSkuHandle(item)">
|
||||
<div class="item">
|
||||
<transition name="el-fade-in">
|
||||
<div class="more" v-if="item.showMore" @click.stop>
|
||||
<div class="ul">
|
||||
<template v-if="categorys[categorysActive].id == '-1'">
|
||||
<div class="li" @click.stop="showPutawayHandle(item)">上架</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="li" @click.stop="goodEditor(item, 0)">下架</div>
|
||||
<div class="li" @click.stop="goodEditor(item, 1)">售罄</div>
|
||||
<div class="li" @click.stop="goodStockNumberHandle(item)">修改库存</div>
|
||||
</template>
|
||||
<div class="li" @click.stop="item.showMore = false">取消</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<div class="dot" v-if="item.orderCount">{{ item.orderCount }}</div>
|
||||
<div class="cover" v-if="shopListType == 'img'">
|
||||
<el-image :src="`${item.coverImg}?x-oss-process=image/resize,m_lfit,w_150,h_150`"
|
||||
class="el_img" fit="cover"></el-image>
|
||||
<div class="sell_out" v-if="item.isPauseSale == 1">
|
||||
<img class="sell_out_icon" src="../../../assets/icon_xq.png">
|
||||
</div>
|
||||
<div class="weight" v-if="item.type == 'weigh'">称重</div>
|
||||
</div>
|
||||
<div class="name"><el-text line-clamp="1">{{ item.name }}</el-text></div>
|
||||
<div class="item_empty" v-if="shopListType == 'text'"></div>
|
||||
<div class="price">
|
||||
<el-text>¥{{ item.lowPrice }}</el-text>
|
||||
<div class="show_more_btn" v-if="showEditor">
|
||||
<el-icon>
|
||||
<MoreFilled />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,26 +92,156 @@
|
||||
</div>
|
||||
<!-- 选择规格 -->
|
||||
<skuModal ref="skuModalRef" @success="skuConfirm" />
|
||||
<!-- 编辑商品 -->
|
||||
<el-dialog v-model="showGoodEditor" :title="`${goodEditorEmun[goodEditorType]}商品`">
|
||||
<div class="dialog">
|
||||
<div class="el-popover__title content">
|
||||
确定要{{ `${goodEditorEmun[goodEditorType]}商品:${goodEditorItem.name}?` }}
|
||||
</div>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showGoodEditor = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :loading="goodEditorLoading"
|
||||
@click="goodEditorConfirm">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 修改库存 -->
|
||||
<el-dialog v-model="showGoodsEditorStock" title="修改库存" width="400px">
|
||||
<div class="dialog">
|
||||
<el-form>
|
||||
<el-form-item label="库存">
|
||||
<div>
|
||||
<el-input-number v-model="goodsEditorStockNumber" :min="0"></el-input-number>
|
||||
<div class="tips">修改前库存:{{ goodsEditorStockItem.stockNumber }}</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showGoodsEditorStock = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :loading="goodsEditorStockLoading"
|
||||
@click="goodsEditorStockConfirm">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 关闭售罄 -->
|
||||
<el-dialog v-model="showCloseSell" title="关闭售罄">
|
||||
<div class="dialog">
|
||||
<div class="el-popover__title content">
|
||||
确定要将{{ `【${goodEditorItem.name}】` }}关闭售罄吗?
|
||||
</div>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showCloseSell = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :loading="closeSellLoading"
|
||||
@click="closeSellHandle">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 上架商品 -->
|
||||
<el-dialog v-model="showPutaway" title="上架商品">
|
||||
<div class="dialog">
|
||||
<div class="el-popover__title content">
|
||||
确定要上架商品:{{ `${goodEditorItem.name}` }}吗?
|
||||
</div>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showPutaway = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :loading="showPutawayLoading"
|
||||
@click="putawayHandle">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 添加临时菜 -->
|
||||
<el-dialog v-model="showTemporaryDish" title="添加临时菜" top="3vh" @open="showTemporaryDishOpen"
|
||||
@closed="showTemporaryDishClosed">
|
||||
<div class="dialog">
|
||||
<div class="el-popover__title content">
|
||||
<el-form ref="temporaryFormRef" :model="temporaryForm" :rules="temporaryFormRules" label-width="100px"
|
||||
label-position="left">
|
||||
<el-form-item label="菜品名称" prop="name">
|
||||
<el-input v-model="temporaryForm.name" placeholder="请输入菜品名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="菜品分类" prop="categoryId">
|
||||
<el-select v-model="temporaryForm.categoryId" placeholder="请选择菜品分类">
|
||||
<el-option v-for="item in temporaryCategorys" :key="item.id" :label="item.name"
|
||||
:value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="价格" prop="price">
|
||||
<el-input v-model="temporaryForm.price" placeholder="请输入价格" @input="priceInput">
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="单位" prop="unit">
|
||||
<el-select v-model="temporaryForm.unit" placeholder="请选择单位">
|
||||
<el-option v-for="item in units" :key="item.id" :label="item.name"
|
||||
:value="item.name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="下单数量">
|
||||
<el-input-number v-model="temporaryForm.num" :min="1" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="temporaryForm.note" type="textarea" placeholder="请输入自定义备注" />
|
||||
<div class="remark_list">
|
||||
<div class="item" v-for="item in noteList" :key="item" @click="addNote(item)">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showTemporaryDish = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :loading="temporaryFormLoading"
|
||||
@click="temporaryFormSubmit">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 称重商品弹窗 -->
|
||||
<WeightModal ref="WeightModalRef" @success="skuConfirm" />
|
||||
<!-- 套餐商品弹窗 -->
|
||||
<GroupModal ref="GroupModalRef" @success="skuConfirm" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { nextTick, onMounted, ref } from 'vue'
|
||||
import _ from 'lodash'
|
||||
import useStorage from "@/utils/useStorage";
|
||||
|
||||
import skuModal from '@/components/skuModal.vue'
|
||||
|
||||
import { queryCategory, queryNewCommodityInfo, queryProductSku } from '@/api/product'
|
||||
import WeightModal from './weightModal.vue'
|
||||
import GroupModal from './groupModal.vue'
|
||||
import { queryCategory, queryNewCommodityInfo, queryProductSku, productStatus, productStock, getUnitList, temporaryDishes } from '@/api/product'
|
||||
import { useUser } from "@/store/user.js"
|
||||
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue'
|
||||
import "swiper/swiper-bundle.css";
|
||||
|
||||
|
||||
import { staffPermission } from '@/api/user.js'
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
const global = useGlobal()
|
||||
import { inputFilterFloat } from '@/utils/index.js'
|
||||
|
||||
const swiperRef = ref(null)
|
||||
|
||||
const global = useGlobal()
|
||||
|
||||
const store = useUser()
|
||||
|
||||
@@ -90,7 +252,7 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
const emit = defineEmits(['success', 'loading'])
|
||||
|
||||
const skuModalRef = ref(null)
|
||||
|
||||
@@ -116,6 +278,136 @@ const inputChange = _.debounce(function () {
|
||||
searchHandle()
|
||||
}, 500)
|
||||
|
||||
|
||||
/** 添加临时菜 start */
|
||||
const temporaryCategorys = ref([]) // 分类列表
|
||||
const showTemporaryDish = ref(false) // 显示添加临时菜
|
||||
const units = ref([]) // 单位列表
|
||||
const temporaryFormRef = ref(null)
|
||||
const resetTemporaryForm = ref({})
|
||||
const temporaryForm = ref({
|
||||
masterId: '',
|
||||
shopId: '',
|
||||
tableId: '',
|
||||
name: '',
|
||||
categoryId: '',
|
||||
price: '',
|
||||
unit: '',
|
||||
num: 1,
|
||||
note: '',
|
||||
vipUserId: ''
|
||||
})
|
||||
const temporaryFormLoading = ref(false)
|
||||
|
||||
const noteList = ref([
|
||||
'免葱',
|
||||
'免香菜',
|
||||
'不要辣',
|
||||
])
|
||||
|
||||
function priceInput(e) {
|
||||
setTimeout(() => {
|
||||
temporaryForm.value.price = inputFilterFloat(e)
|
||||
}, 50)
|
||||
}
|
||||
|
||||
// 添加快捷备注
|
||||
function addNote(str) {
|
||||
if (!temporaryForm.value.note.length) {
|
||||
temporaryForm.value.note += str
|
||||
} else {
|
||||
temporaryForm.value.note += `,${str}`
|
||||
}
|
||||
}
|
||||
|
||||
const temporaryFormRules = ref({
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜品名称',
|
||||
trigger: 'blur',
|
||||
}
|
||||
],
|
||||
categoryId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择菜品分类',
|
||||
trigger: 'change',
|
||||
}
|
||||
],
|
||||
price: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入价格',
|
||||
trigger: 'blur',
|
||||
}
|
||||
],
|
||||
unit: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择单位',
|
||||
trigger: 'change',
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
// 打开
|
||||
function showTemporaryDishOpen() {
|
||||
resetTemporaryForm.value = { ...temporaryForm.value }
|
||||
}
|
||||
|
||||
// 关闭
|
||||
function showTemporaryDishClosed() {
|
||||
temporaryForm.value = { ...resetTemporaryForm.value }
|
||||
temporaryFormRef.value.resetFields()
|
||||
}
|
||||
|
||||
// 获取单位列表
|
||||
async function getUnitListAjax() {
|
||||
try {
|
||||
const res = await getUnitList({
|
||||
shopId: store.userInfo.shopId,
|
||||
page: 1,
|
||||
size: 100,
|
||||
name: ''
|
||||
})
|
||||
units.value = res.records
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 提交临时菜
|
||||
function temporaryFormSubmit() {
|
||||
temporaryFormRef.value.validate(async valid => {
|
||||
try {
|
||||
if (valid) {
|
||||
temporaryFormLoading.value = true
|
||||
|
||||
temporaryForm.value.masterId = props.masterId
|
||||
temporaryForm.value.shopId = store.userInfo.shopId
|
||||
temporaryForm.value.tableId = global.tableInfo.qrcode
|
||||
|
||||
await temporaryDishes(temporaryForm.value)
|
||||
temporaryFormLoading.value = false
|
||||
|
||||
showTemporaryDish.value = false
|
||||
ElMessage.success('添加成功')
|
||||
emit('success', { isTemporary: true })
|
||||
}
|
||||
} catch (error) {
|
||||
temporaryFormLoading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 添加临时菜 end */
|
||||
|
||||
/** 套餐 start */
|
||||
const GroupModalRef = ref(null)
|
||||
/** 套餐 end */
|
||||
|
||||
// 搜索
|
||||
const searchLoading = ref(false)
|
||||
function searchHandle() {
|
||||
@@ -132,6 +424,7 @@ function searchHandle() {
|
||||
|
||||
// 确认选择规格回调
|
||||
function skuConfirm(params) {
|
||||
emit('loading')
|
||||
emit('success', params)
|
||||
}
|
||||
|
||||
@@ -140,15 +433,78 @@ function showMoreMenu() {
|
||||
showPopover.value = !showPopover.value
|
||||
}
|
||||
|
||||
// 显示/隐藏编辑
|
||||
async function showEditorChange() {
|
||||
try {
|
||||
await staffPermission('yun_xu_xiu_gai_shang_pin')
|
||||
if (showEditor.value) {
|
||||
showEditor.value = false
|
||||
goodsList.value.map(item => {
|
||||
item.map(val => {
|
||||
val.showMore = false
|
||||
})
|
||||
})
|
||||
} else {
|
||||
showEditor.value = true
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示sku
|
||||
const WeightModalRef = ref(null)
|
||||
function showSkuHandle(item) {
|
||||
if (showEditor.value) {
|
||||
if (item.isPauseSale == 1) {
|
||||
goodEditorItem.value = item
|
||||
showCloseSell.value = true
|
||||
} else {
|
||||
goodsList.value.map(item => {
|
||||
item.map(val => {
|
||||
val.showMore = false
|
||||
})
|
||||
})
|
||||
item.showMore = true
|
||||
}
|
||||
} else {
|
||||
if (item.isPauseSale == 1) {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: '该商品已售罄',
|
||||
showClose: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (categorys.value[categorysActive.value].id == '-1') {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: '该商品已下架,请上架后操作',
|
||||
showClose: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (item.type == 'normal') {
|
||||
if (item.typeEnum == 'sku') {
|
||||
// 多规格
|
||||
skuModalRef.value.show({ ...item })
|
||||
} else {
|
||||
// 单规格
|
||||
loading.value = true
|
||||
emit('loading')
|
||||
queryProductSkuAjax(item)
|
||||
}
|
||||
} else if (item.type == 'weigh') {
|
||||
WeightModalRef.value.show(item)
|
||||
} else if (item.type == 'package' && item.groupType == 1) {
|
||||
GroupModalRef.value.show(item)
|
||||
} else if (item.type == 'package' && item.groupType == 0) {
|
||||
// 固定套餐当做单规格处理
|
||||
loading.value = true
|
||||
emit('loading')
|
||||
queryProductSkuAjax(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通过选中的商品规格查询价格
|
||||
@@ -159,6 +515,7 @@ const queryProductSkuAjax = _.throttle(async function (goods) {
|
||||
productId: goods.id,
|
||||
spec_tag: ''
|
||||
})
|
||||
loading.value = false
|
||||
emit('success', res)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
@@ -223,27 +580,33 @@ async function queryCategoryAjax() {
|
||||
page: 1,
|
||||
pageSize: 100
|
||||
})
|
||||
temporaryCategorys.value = [...res.list]
|
||||
categorys.value = res.list
|
||||
categorys.value.unshift({
|
||||
name: '全部',
|
||||
id: ''
|
||||
})
|
||||
categorys.value.push({
|
||||
name: '已下架',
|
||||
id: '-1'
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 查询商品信息
|
||||
async function productqueryCommodityInfoAjax() {
|
||||
async function productqueryCommodityInfoAjax(page = goodsPage.value) {
|
||||
try {
|
||||
// loading.value = true
|
||||
const res = await queryNewCommodityInfo({
|
||||
shopId: store.userInfo.shopId,
|
||||
categoryId: categorys.value[categorysActive.value].id,
|
||||
commdityName: commdityName.value,
|
||||
page: goodsPage.value,
|
||||
page: page,
|
||||
pageSize: goodsPageSize.value,
|
||||
masterId: props.masterId
|
||||
masterId: props.masterId,
|
||||
tableId: global.tableInfo.qrcode || '',
|
||||
})
|
||||
if (res.list.length < goodsPageSize.value) {
|
||||
finish.value = true
|
||||
@@ -259,6 +622,9 @@ async function productqueryCommodityInfoAjax() {
|
||||
// clearInterval(loopTimer.value)
|
||||
// loopTimer.value = null
|
||||
// }
|
||||
res.list.map((val, index) => {
|
||||
val.showMore = false
|
||||
})
|
||||
return res
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
@@ -293,9 +659,7 @@ async function updataGoods() {
|
||||
}
|
||||
searchLoading.value = false
|
||||
} else {
|
||||
goodsPage.value = currentGoodsIndex.value + 1
|
||||
// console.log('更新第二页数据', goodsPage.value);
|
||||
const res = await productqueryCommodityInfoAjax()
|
||||
const res = await productqueryCommodityInfoAjax(currentGoodsIndex.value + 1)
|
||||
goodsList.value[currentGoodsIndex.value] = res.list
|
||||
searchLoading.value = false
|
||||
}
|
||||
@@ -305,7 +669,6 @@ async function updataGoods() {
|
||||
const onSlideChange = _.debounce(async function (e) {
|
||||
if (e.activeIndex == e.previousIndex) return
|
||||
if (e.activeIndex > e.previousIndex) {
|
||||
// console.log('向下滑动');
|
||||
{
|
||||
goodsPage.value++
|
||||
const res = await productqueryCommodityInfoAjax()
|
||||
@@ -317,24 +680,184 @@ const onSlideChange = _.debounce(async function (e) {
|
||||
const res = await productqueryCommodityInfoAjax()
|
||||
res.list.length && goodsList.value.push(res.list)
|
||||
}
|
||||
// goodsList.value.shift()
|
||||
} else {
|
||||
// console.log('向上滑动');
|
||||
// goodsPage.value--
|
||||
// const res = await productqueryCommodityInfoAjax()
|
||||
// goodsList.value.unshift(res)
|
||||
// goodsList.value.pop()
|
||||
}
|
||||
|
||||
currentGoodsIndex.value = e.activeIndex
|
||||
}, 500)
|
||||
|
||||
// 订单已结算,清楚商品所有数字
|
||||
// 订单已结算,清除商品所有数字
|
||||
function clearDot() {
|
||||
goodsList.value.map(item => {
|
||||
item.map(val => {
|
||||
val.orderCount = 0
|
||||
// goodsList.value.map(item => {
|
||||
// item.map(val => {
|
||||
// val.orderCount = 0
|
||||
// })
|
||||
// })
|
||||
updateData()
|
||||
}
|
||||
|
||||
const showEditor = ref(false)
|
||||
const goodEditorType = ref(0) // 0 上下架 1售罄
|
||||
const goodEditorItem = ref({})
|
||||
const goodEditorLoading = ref(false)
|
||||
const showGoodEditor = ref(false)
|
||||
|
||||
const goodEditorEmun = ref({
|
||||
0: '下架',
|
||||
1: '售罄'
|
||||
})
|
||||
|
||||
// 编辑商品
|
||||
async function goodEditor(item, t) {
|
||||
try {
|
||||
if (t == 0) {
|
||||
await staffPermission('yun_xu_shang_xia_jia_shang_pin')
|
||||
} else if (t == 1) {
|
||||
await staffPermission('yun_xu_shou_qing_shang_pin')
|
||||
}
|
||||
goodEditorItem.value = item
|
||||
if (item.isPauseSale == 1) {
|
||||
} else {
|
||||
goodEditorType.value = t
|
||||
showGoodEditor.value = true
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭售罄
|
||||
const showCloseSell = ref(false)
|
||||
const closeSellLoading = ref(false)
|
||||
async function closeSellHandle() {
|
||||
try {
|
||||
closeSellLoading.value = true
|
||||
const res = await productStatus({
|
||||
shopId: store.userInfo.shopId,
|
||||
productId: goodEditorItem.value.id,
|
||||
type: 1,
|
||||
state: 0
|
||||
})
|
||||
closeSellLoading.value = false
|
||||
showCloseSell.value = false
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '操作成功',
|
||||
showClose: true,
|
||||
})
|
||||
updateData()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 上架商品
|
||||
const showPutaway = ref(false)
|
||||
const showPutawayLoading = ref(false)
|
||||
|
||||
async function showPutawayHandle(item) {
|
||||
try {
|
||||
await staffPermission('yun_xu_shang_xia_jia_shang_pin')
|
||||
goodEditorItem.value = item
|
||||
showPutaway.value = true
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 确认上架操作
|
||||
async function putawayHandle(item) {
|
||||
try {
|
||||
showPutawayLoading.value = true
|
||||
const res = await productStatus({
|
||||
shopId: store.userInfo.shopId,
|
||||
productId: goodEditorItem.value.id,
|
||||
type: 0,
|
||||
state: 1
|
||||
})
|
||||
showPutawayLoading.value = false
|
||||
showPutaway.value = false
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '操作成功',
|
||||
showClose: true,
|
||||
})
|
||||
updateData()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 确认操作
|
||||
async function goodEditorConfirm() {
|
||||
try {
|
||||
goodEditorLoading.value = true
|
||||
const res = await productStatus({
|
||||
shopId: store.userInfo.shopId,
|
||||
productId: goodEditorItem.value.id,
|
||||
type: goodEditorType.value,
|
||||
state: goodEditorType.value == 0 ? 0 : 1
|
||||
})
|
||||
goodEditorLoading.value = false
|
||||
showGoodEditor.value = false
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '操作成功',
|
||||
showClose: true,
|
||||
})
|
||||
updateData()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示修改库存
|
||||
const goodsEditorStockItem = ref(0)
|
||||
const showGoodsEditorStock = ref(false)
|
||||
const goodsEditorStockNumber = ref(0)
|
||||
const goodsEditorStockLoading = ref(false)
|
||||
async function goodStockNumberHandle(item) {
|
||||
// if (item.isDistribute == 0 && item.typeEnum == 'sku') {
|
||||
// ElMessage({
|
||||
// type: 'warning',
|
||||
// message: '未开启共享库存无法修改',
|
||||
|
||||
// showClose: true,
|
||||
// })
|
||||
// } else {
|
||||
// goodsEditorStockItem.value = item
|
||||
// goodsEditorStockNumber.value = item.stockNumber
|
||||
// showGoodsEditorStock.value = true
|
||||
// }
|
||||
try {
|
||||
await staffPermission('yun_xu_xiu_gai_shang_pin_ku_cun')
|
||||
goodsEditorStockItem.value = item
|
||||
goodsEditorStockNumber.value = item.stockNumber
|
||||
showGoodsEditorStock.value = true
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 确认修改库存
|
||||
async function goodsEditorStockConfirm() {
|
||||
try {
|
||||
goodsEditorStockLoading.value = true
|
||||
const res = await productStock({
|
||||
shopId: store.userInfo.shopId,
|
||||
productId: goodsEditorStockItem.value.id,
|
||||
stock: goodsEditorStockNumber.value
|
||||
})
|
||||
goodsEditorStockLoading.value = false
|
||||
showGoodsEditorStock.value = false
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '操作成功',
|
||||
showClose: true,
|
||||
})
|
||||
updateData()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
@@ -344,8 +867,10 @@ defineExpose({
|
||||
|
||||
onMounted(async () => {
|
||||
localUpdateShopListType()
|
||||
getUnitListAjax()
|
||||
await updateCategoryActive()
|
||||
await queryCategoryAjax()
|
||||
updataGoods()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -380,6 +905,10 @@ onMounted(async () => {
|
||||
flex-wrap: wrap;
|
||||
gap: var(--el-font-size-base);
|
||||
padding: var(--el-font-size-base) 0;
|
||||
|
||||
:deep(.el-button) {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -456,9 +985,17 @@ onMounted(async () => {
|
||||
|
||||
.search_wrap {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
justify-content: space-between;
|
||||
padding: var(--el-font-size-base);
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.shop_list {
|
||||
@@ -489,6 +1026,38 @@ onMounted(async () => {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.more {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
background-color: rgba(0, 0, 0, .6);
|
||||
backdrop-filter: blur(2px);
|
||||
border-radius: 10px;
|
||||
|
||||
.ul {
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
.li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
padding: 8px 0;
|
||||
|
||||
&:last-child {
|
||||
border-top: 1px solid rgba(255 255 255 / 20%);
|
||||
color: #ececec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -510,6 +1079,17 @@ onMounted(async () => {
|
||||
height: 60%;
|
||||
position: relative;
|
||||
|
||||
.weight {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
bottom: 5px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
padding: 2px 6px;
|
||||
background-color: var(--el-color-danger);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.el_img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -518,6 +1098,27 @@ onMounted(async () => {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.sell_out {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
// backdrop-filter: blur(2px);
|
||||
z-index: 10;
|
||||
|
||||
.sell_out_icon {
|
||||
$size: 60px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
@@ -540,13 +1141,56 @@ onMounted(async () => {
|
||||
height: 20%;
|
||||
padding: 6px 10px;
|
||||
background-color: var(--primary-color);
|
||||
position: relative;
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.show_more_btn {
|
||||
width: 40px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog {
|
||||
|
||||
.content {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.footer_wrap {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remark_list {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
|
||||
.item {
|
||||
padding: 0 10px;
|
||||
border: 1px solid #ddd;
|
||||
color: #999;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
206
src/views/home/components/groupModal.vue
Normal file
206
src/views/home/components/groupModal.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<!-- 称重商品组件 -->
|
||||
<template>
|
||||
<el-dialog title="可选套餐" width="70%" :close-on-click-modal="false" v-model="dialogVisible" top="10vh">
|
||||
<div class="row" v-for="(item, index) in goodsItem.proGroupVo" :key="index">
|
||||
<div class="title_wrap">
|
||||
<div class="item">规格组名:{{ item.title }}</div>
|
||||
<div class="item"
|
||||
v-html="`本组菜品<span style='color: var(--el-color-danger)'>${item.count}</span>选<span style='color: var(--el-color-danger)'>${item.number}</span>`">
|
||||
</div>
|
||||
</div>
|
||||
<div class="error">
|
||||
<span v-if="item.isError">错误:请按规格组选择菜品</span>
|
||||
</div>
|
||||
<el-table border :data="item.goods" ref="tabRefs" @select="selectChange($event, index)"
|
||||
@select-all="selectChange($event, index)">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="名称" prop="proName"></el-table-column>
|
||||
<el-table-column label="规格" prop="skuName"></el-table-column>
|
||||
<el-table-column label="价格" prop="price">
|
||||
<template v-slot="scope">
|
||||
¥{{ formatDecimal(scope.row.price) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="数量" prop="number">
|
||||
<template v-slot="scope">
|
||||
{{ `${scope.row.number}${scope.row.unitName || ''}` }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button style="width: 100%" @click="dialogVisible = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" style="width: 100%" :disabled="disabled" @click="confirmHandle">
|
||||
{{ disabled ? '请选择菜品' : '确认' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { inputFilterFloat, formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const number = ref("");
|
||||
const goodsItem = ref({})
|
||||
|
||||
const emit = defineEmits(["success"]);
|
||||
|
||||
const tabRefs = ref([])
|
||||
|
||||
function show(item) {
|
||||
disabled.value = true
|
||||
dialogVisible.value = true;
|
||||
goodsItem.value = { ...item }
|
||||
goodsItem.value.proGroupVo.map(item => {
|
||||
item.isError = false
|
||||
})
|
||||
setTimeout(() => {
|
||||
tabRefs.value.map(item => {
|
||||
item.clearSelection()
|
||||
})
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 选择表格触发
|
||||
function selectChange($event, index) {
|
||||
let item = goodsItem.value.proGroupVo[index]
|
||||
let selectNum = tabRefs.value[index].getSelectionRows()
|
||||
|
||||
if (selectNum.length != item.number) {
|
||||
item.isError = true
|
||||
} else {
|
||||
item.isError = false
|
||||
}
|
||||
|
||||
let flags = []
|
||||
|
||||
goodsItem.value.proGroupVo.map((item, index) => {
|
||||
let selectNum = tabRefs.value[index].getSelectionRows()
|
||||
if (selectNum.length != item.number) {
|
||||
flags.push({ flag: false })
|
||||
} else {
|
||||
flags.push({ flag: true })
|
||||
}
|
||||
})
|
||||
|
||||
const arr = flags.find(item => !item.flag)
|
||||
|
||||
if (arr != undefined && !arr.flag) {
|
||||
disabled.value = true
|
||||
return
|
||||
}
|
||||
|
||||
disabled.value = false
|
||||
}
|
||||
|
||||
// 确认
|
||||
const disabled = ref(true)
|
||||
function confirmHandle() {
|
||||
let flags = []
|
||||
|
||||
goodsItem.value.proGroupVo.map((item, index) => {
|
||||
let selectNum = tabRefs.value[index].getSelectionRows()
|
||||
if (selectNum.length != item.number) {
|
||||
flags.push({ flag: false })
|
||||
} else {
|
||||
flags.push({ flag: true })
|
||||
}
|
||||
})
|
||||
|
||||
const arr = flags.find(item => !item.flag)
|
||||
|
||||
if (arr != undefined && !arr.flag) {
|
||||
disabled.value = true
|
||||
return
|
||||
}
|
||||
|
||||
disabled.value = false
|
||||
|
||||
let goodIds = []
|
||||
goodsItem.value.proGroupVo.map((item, index) => {
|
||||
let selectNum = tabRefs.value[index].getSelectionRows()
|
||||
goodIds.push(selectNum)
|
||||
})
|
||||
|
||||
// 将商品数据转为一维数组返回
|
||||
emit("success", {
|
||||
...goodsItem.value,
|
||||
productId: goodsItem.value.id,
|
||||
groupProductIdList: goodIds.flat().map(item => item.proId)
|
||||
});
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.keybord_wrap {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr 1fr 1fr;
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
:deep(.el-button--large) {
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.input_wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.price_item {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: var(--el-color-danger);
|
||||
padding: 15px 0;
|
||||
border-top: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.title_wrap {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
font-size: 16px;
|
||||
// padding-bottom: 10px;
|
||||
|
||||
.item {
|
||||
span {
|
||||
margin: 0 4px;
|
||||
font-weight: bold;
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
height: 20px;
|
||||
color: var(--el-color-danger);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- 结算订单 -->
|
||||
<template>
|
||||
<el-drawer size="100%" :with-header="false" direction="btt" v-model="dialogVisible">
|
||||
<el-drawer size="100%" :with-header="false" direction="btt" v-model="dialogVisible" @closed="drawerClose">
|
||||
<div class="drawer_wrap">
|
||||
<div class="cart_list">
|
||||
<div class="nav_wrap card">
|
||||
@@ -12,7 +12,9 @@
|
||||
<div class="info">
|
||||
<div class="master_id">
|
||||
<span>{{ props.masterId }}</span>
|
||||
<span class="member_info" v-if="memberInfo.telephone">会员:{{ memberInfo.telephone }}</span>
|
||||
<span class="member_info" v-if="global.orderMemberInfo.telephone">
|
||||
会员:{{ global.orderMemberInfo.telephone }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="btm">
|
||||
<span class="p">服务员:{{ store.userInfo.loginAccount || "暂无" }}</span>
|
||||
@@ -24,7 +26,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="list_wrap card" style="margin-top: var(--el-font-size-base)">
|
||||
<div class="item" v-for="item in props.cart" :key="item.id">
|
||||
<div class="item" v-for="item in cartList" :key="item.id">
|
||||
<div class="top">
|
||||
<span class="name">{{ item.name }}</span>
|
||||
<span class="n">x{{ item.number }}</span>
|
||||
@@ -54,14 +56,37 @@
|
||||
<el-checkbox v-model="isPrint" border label="打印结算小票" style="width: 100%" />
|
||||
</div>
|
||||
<div class="print">
|
||||
<el-button type="primary" v-loading="printLoading" @click="printHandle">打印预结单</el-button>
|
||||
<el-button type="warning" :loading="discountLoading" @click="showStaffDiscountHandle">添加折扣</el-button>
|
||||
</div>
|
||||
<div class="print">
|
||||
<el-button type="primary" :loading="printLoading" @click="printHandle">打印预结单</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pay_wrap">
|
||||
<payCard :amount="props.amount" :member="props.member" :orderId="props.orderInfo.id" @paySuccess="paySuccess" />
|
||||
<payCard :amount="props.amount" :discount="propsDiscount" :orderId="props.orderInfo.id" @paySuccess="paySuccess"
|
||||
@cancelDiscount="propsDiscount = 0" />
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="showStaffDiscount" title="员工折扣" @close="global.updateData(true)">
|
||||
<el-form>
|
||||
<el-form-item label="折扣比例">
|
||||
<div>
|
||||
<el-input-number v-model="discount" :min="staffDiscount" :max="0.99" :step="0.1"
|
||||
:disabled="staffDiscount == 0" />
|
||||
<div class="tips">最低折扣比例:{{ staffDiscount }}</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showStaffDiscount = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" @click="discountConfirm">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
@@ -71,15 +96,19 @@ import { onMounted, ref } from "vue";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import payCard from "@/components/payCard/payCard.vue";
|
||||
import { print } from "@/api/pay";
|
||||
import { orderfindOrder } from '@/api/order/index.js'
|
||||
import { orderfindOrder, getStaffDiscount } from '@/api/order/index.js'
|
||||
import { ElMessage } from "element-plus";
|
||||
import dayjs from "dayjs";
|
||||
import useStorage from '@/utils/useStorage'
|
||||
import { ipcRenderer } from "electron";
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
import receiptPrint from "@/components/lodop/receiptPrint.js";
|
||||
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { usePrint } from '@/store/print.js'
|
||||
|
||||
import { staffPermission } from '@/api/user.js'
|
||||
|
||||
const global = useGlobal()
|
||||
const printStore = usePrint()
|
||||
|
||||
const store = useUser();
|
||||
@@ -88,6 +117,11 @@ const emit = defineEmits("paySuccess");
|
||||
|
||||
const printLoading = ref(false);
|
||||
|
||||
const showStaffDiscount = ref(false)
|
||||
const staffDiscount = ref(0)
|
||||
const discount = ref(0)
|
||||
const propsDiscount = ref(0)
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const props = defineProps({
|
||||
cart: {
|
||||
@@ -116,8 +150,59 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const cartList = ref([])
|
||||
|
||||
const isPrint = ref(true);
|
||||
|
||||
|
||||
const discountLoading = ref(false)
|
||||
// 显示员工折扣
|
||||
async function showStaffDiscountHandle() {
|
||||
try {
|
||||
discountLoading.value = true
|
||||
await staffPermission('yun_xu_da_zhe')
|
||||
await getStaffDiscountAjax()
|
||||
discountLoading.value = false
|
||||
if (staffDiscount.value <= 0) {
|
||||
ElMessage.error('暂无折扣,请稍后再试')
|
||||
} else {
|
||||
showStaffDiscount.value = true
|
||||
discountLoading.value = false
|
||||
global.updateData(false)
|
||||
}
|
||||
} catch (error) {
|
||||
discountLoading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取员工折扣
|
||||
async function getStaffDiscountAjax() {
|
||||
try {
|
||||
const res = await getStaffDiscount({
|
||||
orderId: props.orderInfo.id,
|
||||
staffId: store.userInfo.staffId
|
||||
})
|
||||
staffDiscount.value = res
|
||||
discount.value = res
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 确认折扣
|
||||
function discountConfirm() {
|
||||
if (discount.value >= staffDiscount.value) {
|
||||
propsDiscount.value = discount.value
|
||||
}
|
||||
showStaffDiscount.value = false
|
||||
}
|
||||
|
||||
// 关闭结算弹窗
|
||||
function drawerClose() {
|
||||
propsDiscount.value = 0
|
||||
}
|
||||
|
||||
// 预打印操作
|
||||
const printHandle = _.throttle(async function () {
|
||||
try {
|
||||
@@ -127,8 +212,10 @@ const printHandle = _.throttle(async function () {
|
||||
shop_name: store.userInfo.shopName,
|
||||
loginAccount: store.userInfo.loginAccount,
|
||||
isBefore: true,
|
||||
carts: props.cart,
|
||||
amount: props.amount,
|
||||
carts: cartList.value,
|
||||
amount: formatDecimal(props.amount),
|
||||
discountAmount: propsDiscount.value > 0 ? formatDecimal(props.amount * propsDiscount.value) : formatDecimal(props.amount),
|
||||
discount: formatDecimal(propsDiscount.value * 10, 1, true),
|
||||
remark: props.remark,
|
||||
orderInfo: props.orderInfo,
|
||||
createdAt: dayjs(props.orderInfo.createdAt).format("YYYY-MM-DD HH:mm:ss"),
|
||||
@@ -172,7 +259,9 @@ async function printOrderLable() {
|
||||
shop_name: store.userInfo.shopName,
|
||||
loginAccount: store.userInfo.loginAccount,
|
||||
carts: [],
|
||||
amount: printLabelOrder.orderAmount,
|
||||
amount: formatDecimal(printLabelOrder.orderAmount),
|
||||
discountAmount: printLabelOrder.discountRatio > 0 ? formatDecimal(printLabelOrder.orderAmount - printLabelOrder.discountAmount) : formatDecimal(printLabelOrder.orderAmount),
|
||||
discount: formatDecimal(printLabelOrder.discountRatio * 10, 1, true) || 0,
|
||||
remark: printLabelOrder.remark,
|
||||
orderInfo: printLabelOrder,
|
||||
outNumber: printLabelOrder.outNumber,
|
||||
@@ -188,8 +277,9 @@ async function printOrderLable() {
|
||||
name: item.productName,
|
||||
number: item.num,
|
||||
skuName: item.productSkuName,
|
||||
salePrice: formatDecimal(item.priceAmount / item.num),
|
||||
totalAmount: formatDecimal(item.priceAmount)
|
||||
salePrice: formatDecimal(item.price),
|
||||
totalAmount: formatDecimal(item.num * item.price),
|
||||
proGroupInfo: item.proGroupInfo
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -215,37 +305,32 @@ async function printOrderLable() {
|
||||
|
||||
// 订单已支付
|
||||
function paySuccess() {
|
||||
useStorage.del('memberInfo')
|
||||
propsDiscount.value = 0
|
||||
dialogVisible.value = false;
|
||||
global.setOrderMember({})
|
||||
global.setOrderTable({})
|
||||
printOrderLable()
|
||||
|
||||
emit("paySuccess");
|
||||
}
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true;
|
||||
getLocalMemberInfo()
|
||||
cartList.value = []
|
||||
props.cart.map(item => {
|
||||
if (item.info && item.info.length) {
|
||||
item.info.map(item => {
|
||||
cartList.value.push({ ...item })
|
||||
})
|
||||
} else {
|
||||
cartList.value.push({ ...item })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
|
||||
|
||||
const memberInfo = ref('')
|
||||
|
||||
// 从本地获取会员信息
|
||||
function getLocalMemberInfo() {
|
||||
let localMemberInfo = useStorage.get('memberInfo')
|
||||
if (localMemberInfo && localMemberInfo.telephone) {
|
||||
memberInfo.value = localMemberInfo
|
||||
} else {
|
||||
memberInfo.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getLocalMemberInfo()
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -255,6 +340,15 @@ onMounted(() => {
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.footer_wrap {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer_wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -322,12 +416,13 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.list_wrap {
|
||||
padding: var(--el-font-size-base);
|
||||
padding: 0 var(--el-font-size-base);
|
||||
height: calc(100vh - 200px);
|
||||
overflow-y: auto;
|
||||
|
||||
.item {
|
||||
padding-bottom: var(--el-font-size-base);
|
||||
padding: var(--el-font-size-base) 0;
|
||||
border-bottom: 1px solid #ececec;
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
@@ -338,11 +433,12 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.n {
|
||||
margin-right: 50px;
|
||||
width: 50px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.p {
|
||||
width: 50px;
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
@@ -357,8 +453,6 @@ onMounted(() => {
|
||||
.tag_wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
.tag {
|
||||
padding: 2px 6px;
|
||||
|
||||
203
src/views/home/components/tableMerging.vue
Normal file
203
src/views/home/components/tableMerging.vue
Normal file
@@ -0,0 +1,203 @@
|
||||
<!-- 合并/转桌 -->
|
||||
<template>
|
||||
<el-dialog title="转桌/并桌" width="700px" v-model="visible" @closed="onClose" top="10vh">
|
||||
<div class="scroll_y">
|
||||
<el-form :model="form" ref="formRef" :rules="rules" label-position="top">
|
||||
<el-form-item label="转入台桌" prop="targetTableId">
|
||||
<el-select v-model="form.targetTableId" style="width: 200px;" placeholder="请选择目标台桌">
|
||||
<el-option :label="item.name" :value="item.qrcode" v-for="item in tableList"
|
||||
:key="item.qrcode"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="转入类型">
|
||||
<el-radio-group v-model="form.isFull">
|
||||
<el-radio :value="false" border>转桌(可将部分商品转入)</el-radio>
|
||||
<el-radio :value="true" border>并桌(并台会将全部购物车商品转入)</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="转入商品" prop="cartIds" v-if="!form.isFull">
|
||||
<div v-for="item in props.data" style="width: 100%;">
|
||||
<div>{{ `第${item.placeNum}次下单` }}</div>
|
||||
<el-table ref="tableRefs" :data="item.info" border>
|
||||
<el-table-column type="selection" align="center" width="50px"></el-table-column>
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="数量" prop="number"></el-table-column>
|
||||
<el-table-column label="规格" prop="skuName"></el-table-column>
|
||||
<el-table-column label="价格" prop="salePrice"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer" style="display: flex;">
|
||||
<el-button style="width: 100%" @click="visible = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="confirmHandle">
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { queryShopTable } from '@/api/table.js'
|
||||
import { orderSwitcht } from '@/api/product.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const store = useUser()
|
||||
const global = useGlobal()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
const props = reactive({
|
||||
data: []
|
||||
})
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const tableRefs = ref([])
|
||||
|
||||
const list = ref([])
|
||||
|
||||
const loading = ref(false)
|
||||
const formRef = ref(null)
|
||||
const resetForm = ref({})
|
||||
const form = ref({
|
||||
shopId: store.userInfo.shopId,
|
||||
masterId: '',
|
||||
orderId: '',
|
||||
cartIds: [],
|
||||
isFull: false,
|
||||
currentTableId: '',
|
||||
targetTableId: '',
|
||||
})
|
||||
|
||||
const rules = ref({
|
||||
targetTableId: [
|
||||
{
|
||||
required: true,
|
||||
message: ' ',
|
||||
trigger: 'change',
|
||||
}
|
||||
],
|
||||
cartIds: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
let arr = []
|
||||
props.data.map((item, index) => {
|
||||
arr.push(...tableRefs.value[index].getSelectionRows())
|
||||
})
|
||||
|
||||
if (!arr.length) {
|
||||
ElMessage.error('至少选择一个商品')
|
||||
callback(new Error('至少选择一个商品'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const tableList = ref([])
|
||||
// 获取台桌列表
|
||||
async function queryShopTableAjax() {
|
||||
try {
|
||||
const res = await queryShopTable({
|
||||
shopId: store.userInfo.shopId,
|
||||
areaId: '',
|
||||
status: '',
|
||||
page: 1,
|
||||
pageSize: 100
|
||||
})
|
||||
tableList.value = res.list.filter(item => item.qrcode != props.data[0].info[0].tableId && item.status == 'using')
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 提交
|
||||
function confirmHandle() {
|
||||
formRef.value.validate(async valid => {
|
||||
try {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
form.value.masterId = props.data[0].info[0].masterId
|
||||
form.value.orderId = props.data[0].info[0].orderId
|
||||
form.value.currentTableId = props.data[0].info[0].tableId
|
||||
|
||||
if (!form.value.isFull) {
|
||||
let arr = []
|
||||
props.data.map((item, index) => {
|
||||
arr.push(...tableRefs.value[index].getSelectionRows())
|
||||
})
|
||||
form.value.cartIds = arr.map(item => item.id)
|
||||
}
|
||||
|
||||
await orderSwitcht(form.value)
|
||||
loading.value = false
|
||||
|
||||
// 更新台桌信息
|
||||
global.setOrderTable(tableList.value.find(item => item.qrcode == form.value.targetTableId))
|
||||
|
||||
visible.value = false
|
||||
|
||||
emits('success', { isTemporary: true })
|
||||
}
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
form.value = { ...resetForm.value }
|
||||
formRef.value.resetFields()
|
||||
}
|
||||
|
||||
function show(data) {
|
||||
props.data = data
|
||||
visible.value = true
|
||||
queryShopTableAjax()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
resetForm.value = { ...form.value }
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$btmH: 50px;
|
||||
|
||||
.scroll_y {
|
||||
height: 50vh;
|
||||
overflow-y: auto;
|
||||
padding-bottom: $btmH;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
height: $btmH;
|
||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: $btmH*-1;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
131
src/views/home/components/weightModal.vue
Normal file
131
src/views/home/components/weightModal.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<!-- 称重商品组件 -->
|
||||
<template>
|
||||
<el-dialog title="称重商品" width="400" :close-on-click-modal="false" v-model="dialogVisible" top="10vh"
|
||||
@closed="reset">
|
||||
<div class="input_wrap">
|
||||
<div class="item">
|
||||
<div class="title">单价</div>
|
||||
<el-button type="primary" plain>¥{{ goodsItem.lowPrice }}/{{ goodsItem.unitName }}</el-button>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="title">重量</div>
|
||||
<el-input v-model="number" readonly placeholder="请输入">
|
||||
<template #append>{{ goodsItem.unitName }}</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="keybord_wrap">
|
||||
<div v-for="item in 9" :key="item">
|
||||
<el-button plain type="info" style="width: 100%" @click="inputHandle(item)">{{ item }}</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<el-button plain type="info" style="width: 100%" @click="inputHandle('.')">.</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<el-button plain type="info" style="width: 100%" @click="inputHandle(0)">0</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<el-button plain type="info" icon="CloseBold" style="width: 100%" @click="delHandle"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="price_item">
|
||||
¥{{ formatDecimal(goodsItem.lowPrice * number) }}
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button style="width: 100%" :loading="loading" @click="dialogVisible = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" :disabled="number <= 0"
|
||||
@click="confirmHandle">
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { inputFilterFloat, formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const number = ref("");
|
||||
const goodsItem = ref({})
|
||||
|
||||
const emit = defineEmits(["success"]);
|
||||
|
||||
function show(item) {
|
||||
dialogVisible.value = true;
|
||||
goodsItem.value = { ...item }
|
||||
}
|
||||
|
||||
function reset() {
|
||||
goodsItem.value = {}
|
||||
number.value = ''
|
||||
}
|
||||
|
||||
// 输入
|
||||
function inputHandle(n) {
|
||||
// number.value += n;
|
||||
number.value = inputFilterFloat(number.value += n)
|
||||
}
|
||||
|
||||
// 删除
|
||||
function delHandle() {
|
||||
if (!number.value) return;
|
||||
number.value = number.value.substring(0, number.value.length - 1);
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
// 确认
|
||||
function confirmHandle() {
|
||||
if (!number.value) return
|
||||
goodsItem.value.productId = goodsItem.value.id
|
||||
goodsItem.value.number = number.value
|
||||
|
||||
emit("success", goodsItem.value);
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.keybord_wrap {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr 1fr 1fr;
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
:deep(.el-button--large) {
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.input_wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.price_item {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: var(--el-color-danger);
|
||||
padding: 15px 0;
|
||||
border-top: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<div class="cart_wrap card">
|
||||
<div class="cart_wrap card" v-loading="cartLoading">
|
||||
<div class="menu_top">
|
||||
<div class="menu" @click="pendingCartModalRef.show()">
|
||||
<el-icon class="icon">
|
||||
@@ -11,7 +11,8 @@
|
||||
<div class="number" @click="takeFoodCodeRef.show()">
|
||||
<el-text class="t">{{ masterId }}</el-text>
|
||||
</div>
|
||||
<div class="select_user" @click="fastCashierRef.show()" v-if="!memberInfo.telephone">
|
||||
<div class="select_user" @click="quickCashHandle"
|
||||
v-if="!global.orderMemberInfo.telephone && !global.tableInfo.id">
|
||||
<div class="left">
|
||||
<el-icon class="icon">
|
||||
<WalletFilled />
|
||||
@@ -27,53 +28,81 @@
|
||||
<el-icon class="icon">
|
||||
<UserFilled />
|
||||
</el-icon>
|
||||
<el-text class="t">{{ memberInfo.telephone }}</el-text>
|
||||
<div class="t_wrap" :class="{ 'big_text': global.orderMemberInfo.telephone && global.tableInfo.id }">
|
||||
<div class="t" v-if="global.orderMemberInfo.telephone">
|
||||
会员:{{ global.orderMemberInfo.telephone }}
|
||||
</div>
|
||||
<div class="t" v-if="global.tableInfo.id">
|
||||
台桌:{{ global.tableInfo.name }}
|
||||
<span v-if="global.tableInfo.num">/{{ global.tableInfo.num }}人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-icon class="arrow">
|
||||
<Close />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shop_operation" v-loading="cartLoading">
|
||||
<div class="shop_operation">
|
||||
<div class="shop_list">
|
||||
<div class="item" :class="{ active: cartListActive == index }" v-for="(item, index) in cartList"
|
||||
:key="item.id" @click="selectCartItemHandle(item, index)">
|
||||
<template v-for="(arr, index) in cartList" :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)">
|
||||
<div class="name_wrap">
|
||||
<span>{{ item.name }}</span>
|
||||
<span>¥{{ item.salePrice }}</span>
|
||||
<div class="price">
|
||||
<span :class="{ dis: item.discountSaleAmount }">¥{{ item.salePrice }}</span>
|
||||
<span v-if="item.discountSaleAmount">
|
||||
¥{{ formatDecimal(item.salePrice - item.discountSaleAmount, 2, true) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sku_list" v-if="item.skuName">
|
||||
<div class="tag" v-for="item in item.skuName.split(',')">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grooup_wrap" v-if="item.proGroupInfo">
|
||||
{{ item.groupType == 0 ? '固定套餐:' : '自选套餐:' }}
|
||||
<span>{{ JSON.parse(item.proGroupInfo).map(item => item.proName).join('、') }}</span>
|
||||
</div>
|
||||
<div class="num">
|
||||
<div class="left">
|
||||
<div class="icon_item" v-if="item.isGift == 'true'" @click="giftPackHandle('isGift', item)">
|
||||
<el-icon class="icon">
|
||||
<ShoppingBag />
|
||||
</el-icon>
|
||||
<div class="icon_item zen" v-if="item.isGift == 'true'" @click="giftPackHandle('isGift', item)">
|
||||
<span class="t">赠</span>
|
||||
</div>
|
||||
<div class="icon_item" v-if="item.isPack == 'true'" @click="giftPackHandle('isPack', item)">
|
||||
<el-icon class="icon" style="color: var(--primary-color)">
|
||||
<Box />
|
||||
</el-icon>
|
||||
<div class="icon_item bao" v-if="item.isPack == 'true'" @click="giftPackHandle('isPack', item)">
|
||||
<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.isTemporary == 1">
|
||||
<span class="t">临</span>
|
||||
</div>
|
||||
<div class="icon_item zhe" v-if="item.discountSaleAmount">
|
||||
<span class="t">折</span>
|
||||
</div>
|
||||
<div class="icon_item chu" v-if="item.isPrint == 0">
|
||||
<span class="t">免厨打印</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-text class="t">X{{ item.number }}</el-text>
|
||||
<el-text class="t">X{{ formatDecimal(item.number, 2, true) }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="empty">
|
||||
<el-empty description="请选择商品" v-if="!cartList.length" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 购物车操作栏 -->
|
||||
<cartOperation :item="cartList[cartListActive]" @confirm="(res) => addCart(res, 'edit')" @delete="delCartHandle"
|
||||
@pending="pendingCart" @clearCart="clearCartHandle" />
|
||||
<cartOperation :item="cartListActiveItem" @confirm="(res) => addCart(res, 'edit')" @delete="delCartHandle"
|
||||
@pending="pendingCart" @clearCart="clearCartHandle" @merging="showTableMerging" />
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="top">
|
||||
<div class="left" @click="allSelectedHandle">
|
||||
<div class="left" @click="allSelectedHandle"
|
||||
v-if="JSON.parse(shopStore.info.eatModel).some(item => item == 'take-out')">
|
||||
<div class="selected">
|
||||
<div class="selected_round" v-if="!allSelected"></div>
|
||||
<el-icon class="icon" v-else>
|
||||
@@ -82,27 +111,40 @@
|
||||
</div>
|
||||
<el-text class="t">打包(¥{{ cartInfo.packAmount || 0 }})</el-text>
|
||||
</div>
|
||||
<div class="left" v-else></div>
|
||||
<div class="num-wrap">
|
||||
<el-text>共{{ cartInfo.productNum || 0 }}种商品,{{
|
||||
<!-- 共{{ cartInfo.productNum || 0 }}种商品 -->
|
||||
共<el-text>{{
|
||||
cartInfo.productSum || 0
|
||||
}}件</el-text>
|
||||
}}件</el-text>,¥{{ formatDecimal(cartInfo.totalAmount || 0) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="btm">
|
||||
<el-button icon="Edit" @click="remarkRef.show()"></el-button>
|
||||
<div class="button">
|
||||
<el-button type="primary" style="width: 100%" :disabled="!cartList.length" v-loading="createOrderLoading"
|
||||
@click="createOrderHandle">
|
||||
<span v-if="!createOrderLoading">结算(¥{{ cartInfo.totalAmount || 0 }})</span>
|
||||
<span v-else>下单中...</span>
|
||||
<div class="btn" v-if="shopStore.info.registerType == 'restaurant'">
|
||||
<el-button type="primary" style="width: 100%;" :disabled="!cartList.length" v-loading="createOrderLoading"
|
||||
@click="createOrderHandle(0)">
|
||||
<template v-if="!createOrderLoading">
|
||||
仅下单</template>
|
||||
<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)">
|
||||
<template v-if="!createOrderLoading">
|
||||
去结算</template>
|
||||
<template v-else>下单中...</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shop_manage card">
|
||||
<!-- 分类/商品列表 -->
|
||||
<goods ref="goodsRef" :masterId="masterId" @success="addCart" />
|
||||
<goods ref="goodsRef" :masterId="masterId" @success="addCart" @loading="cartLoading = true" />
|
||||
<!-- ©银收客 v{{ packageData.version }} -->
|
||||
</div>
|
||||
</div>
|
||||
@@ -116,11 +158,15 @@
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="修改取餐号" placeholder="请输入取餐号" @success="takeFoodCodeSuccess" />
|
||||
<!-- 结算订单 -->
|
||||
<settleAccount ref="settleAccountRef" :cart="cartList" :amount="cartInfo.totalAmount" :remark="remark"
|
||||
:masterId="masterId" :orderInfo="orderInfo" :member="memberInfo" @paySuccess="createCodeAjax(1)" />
|
||||
:masterId="masterId" :orderInfo="orderInfo" @paySuccess="createCodeAjax(1)" />
|
||||
<!-- 快捷收银 -->
|
||||
<fastCashier ref="fastCashierRef" type="0" />
|
||||
<!-- 挂起订单 -->
|
||||
<pendingCartModal ref="pendingCartModalRef" @select="pendingCartHandle" />
|
||||
<!-- 检查版本升级 -->
|
||||
<updateDialog />
|
||||
<!-- 合并/转桌 -->
|
||||
<tableMerging ref="tableMergingRef" @success="addCart" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -132,13 +178,18 @@ export default {
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
|
||||
import updateDialog from '@/components/updateDialog.vue'
|
||||
import remarkModal from "@/components/remarkModal.vue";
|
||||
import takeFoodCode from "@/components/takeFoodCode.vue";
|
||||
import cartOperation from "@/views/home/components/cartOperation.vue";
|
||||
import settleAccount from "@/views/home/components/settleAccount.vue";
|
||||
import fastCashier from "@/views/home/components/fastCashier.vue";
|
||||
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,
|
||||
@@ -151,9 +202,21 @@ import {
|
||||
createOrder,
|
||||
} from "@/api/product";
|
||||
|
||||
import { orderChoseCount } from '@/api/table.js'
|
||||
|
||||
import { queryShopInfo, staffPermission } from '@/api/user.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 global = useGlobal()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
@@ -165,11 +228,13 @@ const goodsRef = ref(null);
|
||||
const pendingCartModalRef = ref(null);
|
||||
const settleAccountRef = ref(null);
|
||||
const fastCashierRef = ref(null);
|
||||
const tableMergingRef = ref(null)
|
||||
|
||||
const allSelected = ref(false);
|
||||
|
||||
const remark = ref("");
|
||||
const cartListActive = ref(0);
|
||||
const cartListActiveItem = ref({})
|
||||
const cartList = ref([]);
|
||||
const cartInfo = ref({});
|
||||
const cartLoading = ref(false);
|
||||
@@ -177,26 +242,56 @@ const cartLoading = ref(false);
|
||||
const orderInfo = ref({});
|
||||
const createOrderLoading = ref(false);
|
||||
|
||||
const memberInfo = ref({})
|
||||
|
||||
// 取餐码
|
||||
const masterId = ref("");
|
||||
|
||||
// 挂单量
|
||||
const pendingCartNum = ref(0);
|
||||
|
||||
// 快捷收银
|
||||
async function quickCashHandle() {
|
||||
try {
|
||||
await staffPermission('yun_xu_shou_kuan')
|
||||
fastCashierRef.value.show()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 生成订单
|
||||
async function createOrderHandle() {
|
||||
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
|
||||
});
|
||||
orderInfo.value = res;
|
||||
settleAccountRef.value.show();
|
||||
createOrderLoading.value = false;
|
||||
|
||||
// 订单数据
|
||||
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;
|
||||
@@ -209,7 +304,9 @@ async function clearCartHandle() {
|
||||
await clearCart({
|
||||
shopId: store.userInfo.shopId,
|
||||
masterId: masterId.value,
|
||||
tableId: global.tableInfo.qrcode || ''
|
||||
});
|
||||
cartListActiveItem.value = {}
|
||||
queryCartAjax();
|
||||
|
||||
// 清除商品所有红点
|
||||
@@ -240,14 +337,22 @@ async function pendingCart(params, status = true) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -260,10 +365,12 @@ async function delCartHandle(params) {
|
||||
masterId: params.masterId,
|
||||
cartId: params.id,
|
||||
});
|
||||
cartListActiveItem.value = {}
|
||||
await queryCartAjax();
|
||||
cartLoading.value = false;
|
||||
cartListActive.value = 0;
|
||||
} catch (error) {
|
||||
cartLoading.value = false;
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
@@ -299,30 +406,57 @@ async function takeFoodCodeSuccess(code) {
|
||||
}
|
||||
|
||||
// 从购物车选择商品
|
||||
function selectCartItemHandle(item, index) {
|
||||
cartListActive.value = index;
|
||||
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") {
|
||||
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: 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;
|
||||
@@ -335,11 +469,36 @@ async function queryCartAjax() {
|
||||
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();
|
||||
// goodsRef.value.updateData();
|
||||
|
||||
let i = 0;
|
||||
res.list.map((item) => {
|
||||
@@ -357,6 +516,20 @@ async function queryCartAjax() {
|
||||
}
|
||||
}
|
||||
|
||||
// 增加点餐人数
|
||||
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 {
|
||||
@@ -368,13 +541,21 @@ async function createCodeAjax(type = "0") {
|
||||
// })
|
||||
// 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;
|
||||
queryCartAjax();
|
||||
getLocalMemberInfo()
|
||||
}
|
||||
|
||||
if (global.tableInfo.num) {
|
||||
await addTableNum()
|
||||
}
|
||||
await queryCartAjax();
|
||||
|
||||
if (type == 1) {
|
||||
// 结算订单 清楚商品所有红点
|
||||
@@ -385,25 +566,22 @@ async function createCodeAjax(type = "0") {
|
||||
}
|
||||
}
|
||||
|
||||
// 从本地获取会员信息
|
||||
function getLocalMemberInfo() {
|
||||
let localMemberInfo = useStorage.get('memberInfo')
|
||||
if (localMemberInfo && localMemberInfo.telephone) {
|
||||
memberInfo.value = localMemberInfo
|
||||
} else {
|
||||
memberInfo.value = {}
|
||||
}
|
||||
// 清除本地会员/台桌信息
|
||||
function clearMember() {
|
||||
global.setOrderMember({})
|
||||
global.setOrderTable({})
|
||||
createCodeAjax()
|
||||
}
|
||||
|
||||
// 清除本地会员
|
||||
function clearMember() {
|
||||
useStorage.del('memberInfo')
|
||||
getLocalMemberInfo()
|
||||
// 显示转桌/并桌
|
||||
function showTableMerging() {
|
||||
let data = cartList.value.filter(item => item.placeNum)
|
||||
tableMergingRef.value.show(data)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
createCodeAjax();
|
||||
getLocalMemberInfo()
|
||||
createCodeAjax()
|
||||
shopStore.queryShopInfo()
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -459,7 +637,7 @@ onMounted(() => {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: var(--el-color-info-light-8);
|
||||
padding: 0 var(--el-font-size-base);
|
||||
padding: 0 10px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
@@ -470,6 +648,18 @@ onMounted(() => {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.t_wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
&.big_text {
|
||||
.t {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.t {
|
||||
font-size: var(--el-font-size-base);
|
||||
margin-left: 4px;
|
||||
@@ -510,6 +700,13 @@ onMounted(() => {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: var(--el-font-size-base);
|
||||
|
||||
.dis {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
text-decoration: line-through;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.sku_list {
|
||||
@@ -526,6 +723,18 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.grooup_wrap {
|
||||
padding-top: 10px;
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
}
|
||||
|
||||
.num {
|
||||
padding-top: var(--el-font-size-base);
|
||||
display: flex;
|
||||
@@ -535,17 +744,52 @@ onMounted(() => {
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding-right: 10px;
|
||||
|
||||
.icon_item {
|
||||
$size: 30px;
|
||||
width: $size;
|
||||
$size: 20px;
|
||||
height: $size;
|
||||
border-radius: 4px;
|
||||
padding: 0 6px;
|
||||
border-radius: 2px;
|
||||
background-color: #e2e2e2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10px;
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
|
||||
&.zen {
|
||||
background-color: #FFB0B1;
|
||||
color: #FF4D4F;
|
||||
}
|
||||
|
||||
&.bao {
|
||||
background-color: #52C41A;
|
||||
}
|
||||
|
||||
&.tui {
|
||||
background-color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
&.lin {
|
||||
background-color: var(--el-color-warning);
|
||||
}
|
||||
|
||||
&.zhe {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
&.chu {
|
||||
background-color: #ffe7ba;
|
||||
color: #e69f1c;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,6 +862,12 @@ onMounted(() => {
|
||||
|
||||
.button {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.js {
|
||||
.t {
|
||||
|
||||
@@ -1,290 +1,83 @@
|
||||
<template>
|
||||
<!-- <el-button @click="chooseSerial">获取串口列表</el-button> -->
|
||||
<el-button @click="initWebSocket()">连接ws</el-button>
|
||||
<el-button @click="dakai()"></el-button>
|
||||
<!-- 打印二维码 -->
|
||||
<rintermodelindex ref="rintermodelindexref" :form="form" @somethingDone="handleSomethingDone"></rintermodelindex>
|
||||
<el-dialog v-model="showDialog" title="发现新版本" width="500" :close-on-click-modal="false"
|
||||
:close-on-press-escape="false" :show-close="false">
|
||||
<div class="message">
|
||||
{{ updataInfo.message }}
|
||||
</div>
|
||||
<div class="progress_wrap" style="padding-top: 20px;">
|
||||
<el-progress :percentage="uploadPro" :stroke-width="15" striped :striped-flow="uploadPro < 100" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="footer" style="padding: 0 20px 20px;">
|
||||
<el-button v-if="!updataInfo.isUp">下次更新</el-button>
|
||||
<el-button type="primary" :loading="isUpload" @click="uplaodHandle">
|
||||
<template v-if="!uploadSucess">
|
||||
<template v-if="!isUpload">
|
||||
立即更新
|
||||
</template>
|
||||
<template v-else>
|
||||
下载中...
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
立即安装
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import _ from 'lodash'
|
||||
import { bySubType } from "@/api/device";
|
||||
import { ElMessage } from "element-plus";
|
||||
import dayjs from 'dayjs'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { findVersion } from '@/api/user.js'
|
||||
import packageData from "../../../package.json";
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useUser } from "@/store/user.js";
|
||||
import useStorage from '@/utils/useStorage'
|
||||
import rintermodelindex from '@/components/lodop/index.vue'
|
||||
const store = useUser();
|
||||
|
||||
const rintermodelindexref = ref()//打印机ref
|
||||
// 打印成功回调
|
||||
const handleSomethingDone = () => {
|
||||
console.log('打印成功回调成功')
|
||||
}
|
||||
const form = ref({
|
||||
article: '1',
|
||||
type: '2',
|
||||
const showDialog = ref(false)
|
||||
const updataInfo = ref({})
|
||||
const isUpload = ref(false)
|
||||
const uploadPro = ref(0)
|
||||
const uploadSucess = ref(false)
|
||||
const uploadResponse = ref({})
|
||||
const tempFilePath = ref('')
|
||||
|
||||
})
|
||||
const dakai = () => {
|
||||
rintermodelindexref.value.centerDialogVisibleshow() //打开二维码打印
|
||||
rintermodelindexref.value.initialization()
|
||||
}
|
||||
|
||||
// 小票打印机列表
|
||||
const printList = ref([]);
|
||||
// 标签打印机列表
|
||||
const printLabelList = ref([]);
|
||||
const localPrintList = ref([])
|
||||
|
||||
// 获取打印机状态
|
||||
async function bySubTypeAjax() {
|
||||
// 检查版本更新
|
||||
async function findVersionAjax() {
|
||||
try {
|
||||
const res1 = await bySubType({
|
||||
shopId: store.userInfo.shopId,
|
||||
contentType: "local",
|
||||
subType: "cash",
|
||||
});
|
||||
const res2 = await bySubType({
|
||||
shopId: store.userInfo.shopId,
|
||||
contentType: "local",
|
||||
subType: "label",
|
||||
});
|
||||
printList.value = res1;
|
||||
printLabelList.value = res2;
|
||||
const res = await findVersion()
|
||||
let reg = /\./g;
|
||||
if (res.version.replace(reg, '') > packageData.version.replace(reg, '') && res.url) {
|
||||
showDialog.value = true
|
||||
updataInfo.value = res
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取本地打印机列表
|
||||
function getPrintList() {
|
||||
ipcRenderer.send("getPrintList");
|
||||
ipcRenderer.on("printList", (event, arg) => {
|
||||
localPrintList.value = arg;
|
||||
// console.log(localPrintList.value);
|
||||
});
|
||||
}
|
||||
|
||||
// 检查本地打印机是否能正常使用
|
||||
function checkLocalPrint(deviceName) {
|
||||
let print = ''
|
||||
for (let item of localPrintList.value) {
|
||||
if (item.name == deviceName) {
|
||||
print = item
|
||||
}
|
||||
}
|
||||
|
||||
if (!print.name) {
|
||||
return false
|
||||
// 下载新版本
|
||||
async function uplaodHandle() {
|
||||
try {
|
||||
if (!uploadSucess.value) {
|
||||
isUpload.value = true
|
||||
ipcRenderer.send('downloadFile', JSON.stringify({ url: updataInfo.value.url }))
|
||||
// await downloadFile(updataInfo.value.url)
|
||||
// isUpload.value = false
|
||||
// uploadSucess.value = true
|
||||
} else {
|
||||
return true
|
||||
// 安装文件
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 打印小票
|
||||
function printBill(props) {
|
||||
if (!checkLocalPrint(printLabelList.value[0].config.deviceName)) {
|
||||
ElMessage.error("本地打印机无法使用,请检查打印机是否正确连接");
|
||||
} else {
|
||||
const data = {
|
||||
shop_name: store.userInfo.merchantName,
|
||||
carts: props.carts,
|
||||
amount: props.amount,
|
||||
remark: props.remark,
|
||||
orderInfo: props.orderInfo,
|
||||
deviceName: printList.value[0].config.deviceName,
|
||||
createdAt: dayjs(props.orderInfo.createdAt).format(
|
||||
"YYYY-MM-DD HH:mm:ss"
|
||||
),
|
||||
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
};
|
||||
ipcRenderer.send("printerInfoSync", JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
// 检测是否打印标签小票
|
||||
function checkLabelPrint(props) {
|
||||
if (!checkLocalPrint(printLabelList.value[0].config.deviceName)) {
|
||||
ElMessage.error("本地打印机无法使用,请检查打印机是否正确连接");
|
||||
} else {
|
||||
let pids = printLabelList.value[0].config.categoryList.map(item => item.id)
|
||||
let labelList = []
|
||||
props.carts.map(item => {
|
||||
if (pids.some(el => el == item.categoryId)) {
|
||||
for (let i = 0; i < item.number; i++) {
|
||||
labelList.push(
|
||||
{
|
||||
outNumber: props.outNumber,
|
||||
name: item.name,
|
||||
skuName: item.skuName,
|
||||
masterId: props.orderInfo.tableName,
|
||||
deviceName: printLabelList.value[0].config.deviceName,
|
||||
createdAt: dayjs(props.createdAt).format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
printLabel(labelList)
|
||||
}
|
||||
}
|
||||
|
||||
// 打印标签
|
||||
let labelCount = ref(0)
|
||||
let labelPrintTimer = ref(null)
|
||||
function printLabel(list) {
|
||||
console.log(list);
|
||||
if (!checkLocalPrint(printLabelList.value[0].config.deviceName)) {
|
||||
ElMessage.error("本地打印机无法使用,请检查打印机是否正确连接");
|
||||
} else {
|
||||
labelPrintTimer.value = setInterval(() => {
|
||||
// console.log('labelCount', labelCount.value);
|
||||
list[labelCount.value].count = `${list.length - labelCount.value}/${list.length}`
|
||||
ipcRenderer.send('printerTagSync', JSON.stringify(list[labelCount.value]))
|
||||
labelCount.value++
|
||||
if (labelCount.value > list.length - 1) {
|
||||
clearInterval(labelPrintTimer.value)
|
||||
labelPrintTimer.value = null
|
||||
labelCount.value = 0
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
let ws = ref(null)
|
||||
let wsIsClose = ref(false)
|
||||
// 初始化websocket
|
||||
function initWebSocket(wsUrl = 'wss://wxcashiertest.sxczgkj.cn/client') {
|
||||
ws.value = new WebSocket(wsUrl);
|
||||
console.log("websocket:", ws.value);
|
||||
|
||||
ws.value.onopen = function () {
|
||||
console.log('wss连接成功');
|
||||
// 清除心跳
|
||||
clearInterval(heartbeatTimer.value)
|
||||
heartbeatTimer.value = null
|
||||
startheartbeat()
|
||||
|
||||
// 清除重连
|
||||
clearInterval(reConnectTimer.value)
|
||||
reConnectTimer.value = null
|
||||
reConnectCount.value = 0
|
||||
|
||||
ws.value.send(JSON.stringify({
|
||||
type: "connect",
|
||||
shopId: store.userInfo.shopId,
|
||||
clientId: useStorage.get('uuid')
|
||||
}))
|
||||
};
|
||||
|
||||
// 接收消息
|
||||
ws.value.onmessage = function (e) {
|
||||
// websocketonmessage(e);
|
||||
let data = JSON.parse(e.data)
|
||||
if (data.type == 'order') {
|
||||
console.log('接收消息', data);
|
||||
// 接收订单消息,打印小票
|
||||
// printBill(data)
|
||||
|
||||
// 检测是否需要打印标签小票
|
||||
checkLabelPrint(data)
|
||||
}
|
||||
};
|
||||
|
||||
// 连接发生错误
|
||||
ws.value.onerror = function () {
|
||||
console.log("WebSocket连接发生错误");
|
||||
|
||||
// 清除心跳
|
||||
clearInterval(heartbeatTimer.value)
|
||||
heartbeatTimer.value = null
|
||||
|
||||
// 手动关闭后不在执行自动连接任务
|
||||
if (!wsIsClose.value) reConnect(wsUrl);
|
||||
};
|
||||
|
||||
// 关闭
|
||||
ws.value.onclose = function (e) {
|
||||
console.log('ws关闭了', e);
|
||||
|
||||
// 清除心跳
|
||||
clearInterval(heartbeatTimer.value)
|
||||
heartbeatTimer.value = null
|
||||
|
||||
// 手动关闭后不在执行自动连接任务
|
||||
if (!wsIsClose.value) reConnect(wsUrl);
|
||||
};
|
||||
}
|
||||
|
||||
// 启动心跳连接
|
||||
let heartbeatTimer = ref(null)
|
||||
function startheartbeat() {
|
||||
heartbeatTimer.value = setInterval(() => {
|
||||
ws.value.send(JSON.stringify({ type: 'heartbeat' }))
|
||||
}, 10000)
|
||||
}
|
||||
|
||||
// 重连最大次数5次
|
||||
let reConnectCount = ref(0)
|
||||
let reConnectTimer = ref(null)
|
||||
function reConnect(wsUrl) {
|
||||
if (reConnectTimer.value != null) return
|
||||
reConnectTimer.value = setInterval(() => {
|
||||
// 自动连接超过5次不在连接,需手动出发
|
||||
console.log('reConnectCount.value===', reConnectCount.value);
|
||||
if (reConnectCount.value >= 5) {
|
||||
console.log('重连超过5次,不在连接');
|
||||
clearInterval(reConnectTimer.value)
|
||||
reConnectTimer.value = null
|
||||
reConnectCount.value = 0
|
||||
wsIsClose.value = true
|
||||
ws.value.close()
|
||||
} else {
|
||||
reConnectCount.value++
|
||||
initWebSocket(wsUrl)
|
||||
}
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 打印标签小票
|
||||
const printTag = () => {
|
||||
ipcRenderer.send('printerTagSync', JSON.stringify({
|
||||
deviceName: 'Xprinter XP-365B123'
|
||||
}))
|
||||
}
|
||||
|
||||
//选择串口设备
|
||||
const chooseSerial = async () => {
|
||||
// let printNum = localStorage.getItem('printNum')
|
||||
// if (!printNum) {
|
||||
// printNum = 1
|
||||
// localStorage.setItem('printNum', printNum)
|
||||
// } else {
|
||||
// printNum++
|
||||
// localStorage.setItem('printNum', printNum)
|
||||
// }
|
||||
// ipcRenderer.send('printStart', printNum)
|
||||
// ipcRenderer.send('getSerialPort')
|
||||
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
ipcRenderer.on('seriaportList', (e, a) => {
|
||||
console.log('seriaportList', a);
|
||||
findVersionAjax()
|
||||
ipcRenderer.on('updateProgress', (event, res) => {
|
||||
// console.log('updateProgress===', event, res);
|
||||
uploadPro.value = res
|
||||
})
|
||||
|
||||
getPrintList();
|
||||
bySubTypeAjax();
|
||||
initWebSocket()
|
||||
})
|
||||
</script>
|
||||
@@ -73,8 +73,11 @@ import { douyincheckIn } from "@/api/group";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useSocket } from "@/store/socket.js";
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { useShop } from '@/store/shop.js'
|
||||
const global = useGlobal()
|
||||
|
||||
const shopInfo = useShop()
|
||||
|
||||
const store = useUser();
|
||||
const socket = useSocket();
|
||||
|
||||
@@ -123,8 +126,11 @@ const submitHandle = () => {
|
||||
store
|
||||
.userlogin(form)
|
||||
.then(async (res) => {
|
||||
// 登录成功后保存商户号
|
||||
useStorage.set('merchantLoginAccount', form.merchantName)
|
||||
ElMessage.success("登录成功");
|
||||
socket.init();
|
||||
await shopInfo.queryShopInfo()
|
||||
setTimeout(() => {
|
||||
router.replace({
|
||||
name: "home",
|
||||
@@ -155,6 +161,11 @@ const logout = () => {
|
||||
|
||||
onMounted(() => {
|
||||
global.updateData(false)
|
||||
|
||||
let merchantLoginAccount = useStorage.get('merchantLoginAccount')
|
||||
if (merchantLoginAccount) {
|
||||
form.merchantName = merchantLoginAccount
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<el-dialog v-model="visableDialog" title="余额明细" width="500">
|
||||
<div class="box">
|
||||
<div class="dialog_footer" v-for="(item, index) in props.flowingwater.list" :key="index">
|
||||
<div class="box1" v-loading="tableData.loading">
|
||||
<div class="dialog_footer" v-for="(item, index) in tableData.list" :key="index">
|
||||
<div class="dialog_footer_left">
|
||||
<span>{{ item.biz_name }}</span>
|
||||
<span>{{ dayjs(item.create_time).format("YYYY-MM-DD HH:mm:ss") }}</span>
|
||||
@@ -13,28 +15,179 @@
|
||||
</span>
|
||||
<span>余额:¥{{ formatDecimal(item.balance) }}</span>
|
||||
</div>
|
||||
<div class="btm" style="width: 80px;">
|
||||
<el-button type="primary"
|
||||
v-if="item.biz_code == 'scanMemberIn' || item.biz_code == 'cashMemberIn'"
|
||||
@click="showRefundHandle(item)" :disabled="item.is_return == 1">
|
||||
<template v-if="item.is_return == 0">退款</template>
|
||||
<template v-if="item.is_return == 1">已退</template>
|
||||
</el-button>
|
||||
</div>
|
||||
<el-empty description="暂无数据" v-if="!props.flowingwater.list.length" />
|
||||
</div>
|
||||
<el-empty description="暂无数据" v-if="!tableData.list.length" />
|
||||
</div>
|
||||
<div class="page_wrap">
|
||||
<el-pagination v-model:current-page="tableData.page" background layout="prev, pager, next, total"
|
||||
:total="tableData.total" @current-change="memberqueryMemberAccountAjax" />
|
||||
</div>
|
||||
<el-dialog v-model="showDialog" title="会员充值退款">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
|
||||
<el-form-item label="退款金额" prop="amount">
|
||||
<el-input-number v-model="form.amount" :min="1" :max="refundItem.amount"
|
||||
placeholder="请输入退款金额" />
|
||||
</el-form-item>
|
||||
<el-form-item label="退款说明">
|
||||
<el-input v-model="form.remark" placeholder="请输入退款说明" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div style="padding: 0 20px 20px;">
|
||||
<el-button @click="showDialog = false">取消</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="refundHandle">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="退款密码" :type="2" input-type="password" placeholder="请输入退款密码"
|
||||
@success="passwordSuccess" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { dayjs } from 'element-plus'
|
||||
import md5 from "js-md5";
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { dayjs, ElMessage } from 'element-plus'
|
||||
import { formatDecimal } from '@/utils/index'
|
||||
import { returnFlow, memberqueryMemberAccount } from '@/api/member/index.js'
|
||||
import { queryPwdInfo, staffPermission } from '@/api/user.js'
|
||||
import takeFoodCode from "@/components/takeFoodCode.vue";
|
||||
|
||||
const props = defineProps({
|
||||
flowingwater: {
|
||||
type: Object,
|
||||
default: {}
|
||||
const memberId = ref('')
|
||||
|
||||
const visableDialog = ref(false)
|
||||
|
||||
const tableData = reactive({
|
||||
page: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
list: []
|
||||
})
|
||||
|
||||
// 会员流水
|
||||
async function memberqueryMemberAccountAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
let res = await memberqueryMemberAccount({
|
||||
memberId: memberId.value,
|
||||
page: tableData.page,
|
||||
pageSize: 10
|
||||
})
|
||||
tableData.loading = false
|
||||
tableData.total = res.total
|
||||
tableData.list = res.list
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const emits = defineEmits(['refund'])
|
||||
|
||||
const takeFoodCodeRef = ref(null)
|
||||
const showDialog = ref(false)
|
||||
const form = reactive({
|
||||
amount: 1,
|
||||
remark: ''
|
||||
})
|
||||
const rules = reactive({
|
||||
amount: [
|
||||
{
|
||||
trigger: 'blur',
|
||||
required: true,
|
||||
message: '请输入退款金额'
|
||||
}
|
||||
]
|
||||
})
|
||||
const loading = ref(false)
|
||||
const refundItem = ref({})
|
||||
const formRef = ref(null)
|
||||
|
||||
async function showRefundHandle(item) {
|
||||
try {
|
||||
await staffPermission('yun_xu_tui_kuan')
|
||||
refundItem.value = item
|
||||
form.amount = item.amount
|
||||
showDialog.value = true
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 线上充值退款
|
||||
function refundHandle() {
|
||||
formRef.value.validate(async valid => {
|
||||
try {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
let res = await queryPwdInfo()
|
||||
loading.value = false
|
||||
if (res.isMemberReturn == 1) {
|
||||
takeFoodCodeRef.value.show();
|
||||
} else {
|
||||
passwordSuccess()
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 得到退款密码
|
||||
async function passwordSuccess(e = '') {
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await returnFlow({
|
||||
flowId: refundItem.value.id,
|
||||
remark: form.remark,
|
||||
amount: form.amount,
|
||||
pwd: e ? md5(e) : '',
|
||||
})
|
||||
ElMessage.success('退款成功')
|
||||
form.amount = 1
|
||||
form.remark = ''
|
||||
showDialog.value = false
|
||||
loading.value = false
|
||||
emits('refund')
|
||||
memberqueryMemberAccountAjax()
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function show(id) {
|
||||
memberId.value = id
|
||||
visableDialog.value = true
|
||||
memberqueryMemberAccountAjax()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
height: 400px;
|
||||
overflow: auto;
|
||||
|
||||
.box1 {
|
||||
height: 350px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.page_wrap {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.dialog_footer:nth-child(1) {
|
||||
margin-top: 0;
|
||||
@@ -43,12 +196,12 @@ const props = defineProps({
|
||||
.dialog_footer {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ececec;
|
||||
padding-bottom: 6px;
|
||||
|
||||
.dialog_footer_left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
@@ -67,9 +220,11 @@ const props = defineProps({
|
||||
}
|
||||
|
||||
.dialog_footer_right {
|
||||
width: 150px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
padding-right: 20px;
|
||||
|
||||
span:nth-child(1) {
|
||||
font-size: 16px;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="demo_tabs_div">
|
||||
<el-input v-model="tableData.phone" placeholder="请输入手机号" @input="inputChange" clearable @focus="
|
||||
global.updateData(false)" @blur="global.updateData(true)" />
|
||||
<el-button style="margin-left: 10px;" type="primary" @click="memberaddshow = true">添加</el-button>
|
||||
<el-button style="margin-left: 10px;" type="primary" @click="addMemberHandle">添加</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="tableData.list" style="width: 100%;margin-top: 10px;height:80%;"
|
||||
@@ -48,7 +48,7 @@
|
||||
<div class="orderbox_right_top_item_tow">{{ tableData.list.length != 0 ?
|
||||
tableData.list[datarow].levelConsume : '无' }}</div>
|
||||
</div>
|
||||
<div class="orderbox_right_top_item" @click="stored = true">
|
||||
<div class="orderbox_right_top_item" @click="dialogRef.show(tableData.list[datarow].id)">
|
||||
<div class="orderbox_right_top_item_one">
|
||||
<el-icon :size="24" style="color:#00b58d ;">
|
||||
<Box />
|
||||
@@ -83,9 +83,9 @@
|
||||
</div>
|
||||
<keyboard v-if="props.membershow == '1'" @consumeFees="consumeFees"></keyboard>
|
||||
<div class="orderbox_right_button" v-if="props.membershow == '0'">
|
||||
<el-button style="width: 100%;" @click="toHome">创建订单</el-button>
|
||||
<!-- <el-button style="width: 100%;" @click="toHome">创建订单</el-button> -->
|
||||
<!-- <el-button style="width: 60%;" type="primary" @click="recharge = true">账户充值</el-button> -->
|
||||
<el-button style="width: 60%;" type="primary" @click="userChargeRef.show()">账户充值</el-button>
|
||||
<el-button style="width: 100%;" type="primary" @click="menberAddNnum">账户充值</el-button>
|
||||
</div>
|
||||
<div class="orderbox_right_button" v-if="props.membershow == '1'">
|
||||
<router-link to="/" style="width: 35%;">
|
||||
@@ -94,10 +94,7 @@
|
||||
<el-button style="width: 60%;" type="primary">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="stored" title="余额明细" width="500" :before-close="handleClose">
|
||||
<add :flowingwater='flowingwater' />
|
||||
</el-dialog>
|
||||
<add ref="dialogRef" @refund="refundSuccess" @page-change="MemberAccount" />
|
||||
<el-dialog v-model="memberaddshow" title="添加会员" width="600" :before-close="memberaddshowclose"
|
||||
@open="membrform = { ...resetMembrform }">
|
||||
<el-form ref="formRef" :rules="rules" :model="membrform" label-width="70px" hide-required-asterisk>
|
||||
@@ -179,6 +176,7 @@ import payCard from '@/components/payCard/payCard.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import useStorage from '@/utils/useStorage'
|
||||
import userCharge from './components/userCharge.vue'
|
||||
import { staffPermission } from '@/api/user.js'
|
||||
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
const global = useGlobal()
|
||||
@@ -194,6 +192,9 @@ const stored = ref(false)//储值余额
|
||||
const handleClose = async () => {
|
||||
stored.value = !stored.value
|
||||
}
|
||||
|
||||
const dialogRef = ref(null)
|
||||
|
||||
const emit = defineEmits('paySuccess')
|
||||
|
||||
function paySuccess() {
|
||||
@@ -238,6 +239,32 @@ const payCarddialogVisible = ref(false)
|
||||
|
||||
const orderId = ref('')
|
||||
|
||||
// 添加会员
|
||||
async function addMemberHandle() {
|
||||
try {
|
||||
await staffPermission('yun_xu_guan_li_hui_yuan_xin_xi')
|
||||
memberaddshow.value = true
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 账户充值
|
||||
async function menberAddNnum() {
|
||||
try {
|
||||
await staffPermission('yun_xu_xiu_gai_hui_yuan_yu_e')
|
||||
userChargeRef.value.show()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 退款成功
|
||||
function refundSuccess() {
|
||||
asyncqueryMembermember()
|
||||
MemberAccount()
|
||||
}
|
||||
|
||||
const confirmEvent = async () => {//子组件 确认按钮
|
||||
orderId.value = tableData.list[datarow.value].id
|
||||
payCarddialogVisible.value = true
|
||||
@@ -262,15 +289,15 @@ const confirmEvent = async () => {//子组件 确认按钮
|
||||
// }
|
||||
}
|
||||
|
||||
const MemberAccount = async () => {//获取流水
|
||||
const MemberAccount = async (page = 1) => {//获取流水
|
||||
try {
|
||||
let res = await memberqueryMemberAccount({
|
||||
memberId: tableData.list[datarow.value].id,
|
||||
page: 1,
|
||||
page: page,
|
||||
pageSize: 10
|
||||
})
|
||||
flowingwater.total = res.total
|
||||
flowingwater.list = res.list
|
||||
// flowingwater.list = res.list
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
@@ -302,7 +329,8 @@ const asyncqueryMembermember = async () => {//会员列表数据
|
||||
shopId: store.userInfo.shopId,
|
||||
page: tableData.page,
|
||||
pageSize: 10,
|
||||
phone: tableData.phone
|
||||
phone: tableData.phone,
|
||||
isFlag: 0
|
||||
})
|
||||
if (res) {
|
||||
setTimeout(() => {
|
||||
@@ -418,8 +446,10 @@ const createMembermemberSubmit = async () => { ///添加会员
|
||||
}
|
||||
const moneys = ref('')// 钱数
|
||||
|
||||
// 创建会员订单
|
||||
const toHome = () => {
|
||||
useStorage.set('memberInfo', tableData.list[datarow.value])
|
||||
// useStorage.set('memberInfo', tableData.list[datarow.value])
|
||||
global.setOrderMember(tableData.list[datarow.value])
|
||||
router.push({
|
||||
name: 'home'
|
||||
})
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
<div class="demo_tabs_boxitem_one">
|
||||
<div class=""
|
||||
style="width: 100px; height: 70px;border-radius: 4px; background:rgb(186 200 239); display: flex; justify-content: center; align-items: center;">
|
||||
<div>{{ item.tableName || "pos" }}</div>
|
||||
<div>{{ item.tableName || "POS" }}</div>
|
||||
</div>
|
||||
<!-- <el-image style="width: 100px; height: 70px;border-radius: 10px;" :src="item.imgUrl" fit="scale-down" /> -->
|
||||
<div class="demo_tabs_boxitem_oneone">
|
||||
<div>
|
||||
{{ dayjs(item.createAt).format(" HH:mm:ss") }}
|
||||
{{ dayjs(item.createAt).format("HH:mm:ss") }}
|
||||
</div>
|
||||
<div style="color: #757575;">
|
||||
{{ dayjs(item.createAt).format("YYYY-MM-DD") }}
|
||||
@@ -20,15 +20,25 @@
|
||||
</div>
|
||||
<div class="demo_tabs_boxitem_onetow">
|
||||
<div style="font-size: 16px; color: #757575;">{{ item.orderNo }}</div>
|
||||
<div>
|
||||
<span>{{ item.names && item.names[0] }} </span>
|
||||
<div class="order_info">
|
||||
<span class="sp1">{{
|
||||
item.names &&
|
||||
item.names[0] }} </span>
|
||||
<span style="margin-left: 6px;">{{ item.names && item.names.length }}项</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo_tabs_boxitem_tow">
|
||||
<div>
|
||||
¥{{ item.orderAmount }}
|
||||
<template v-if="item.discountAmount <= 0">
|
||||
¥{{ formatDecimal(item.orderAmount) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>¥{{ formatDecimal(item.orderAmount - item.discountAmount) }}</span>
|
||||
<span style="text-decoration: line-through;color: #999;font-size: 14px;">
|
||||
¥{{ formatDecimal(item.orderAmount) }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
<div style="color:#ff9e01;">
|
||||
<span v-if="item.status == 'pending'">挂单</span>
|
||||
@@ -44,6 +54,7 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { dayjs } from 'element-plus'
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const props = defineProps({
|
||||
ordereData: {
|
||||
@@ -115,6 +126,19 @@ const clickitemboxshow = (e) => {
|
||||
justify-content: space-around;
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
|
||||
.order_info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.sp1 {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,9 +80,23 @@
|
||||
<div class="orderbox_right_item">
|
||||
<span class="span">流水号:</span><span class="nunber">{{ orderDetaildata.masterId }}</span>
|
||||
</div>
|
||||
<div class="orderbox_right_item" v-if="orderDetaildata.discountAmount > 0">
|
||||
<span class="span">折扣:</span><span class="nunber">{{ formatDecimal(orderDetaildata.discountRatio *
|
||||
10, 1, true) }}折</span>
|
||||
</div>
|
||||
<div class="orderbox_right_top" style="margin-top: 20px; border-bottom: 2px solid #ccc">
|
||||
<span>合计:</span>
|
||||
<span>¥{{ orderDetaildata.orderAmount }}</span>
|
||||
<div>
|
||||
<template v-if="orderDetaildata.discountAmount <= 0">
|
||||
¥{{ formatDecimal(orderDetaildata.orderAmount) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>¥{{ formatDecimal(orderDetaildata.orderAmount - orderDetaildata.discountAmount) }}</span>
|
||||
<span style="text-decoration: line-through;color: #999;font-size: 14px;">
|
||||
¥{{ formatDecimal(orderDetaildata.orderAmount) }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="orderbox_right_top" style="margin-top: 20px; border-bottom: 2px solid #ccc">
|
||||
<span style="font-size: 16px" v-if="orderDetaildata.status == 'pending'">挂单</span>
|
||||
@@ -108,6 +122,7 @@
|
||||
</div>
|
||||
<div class="orderbox_right_list_item" style="margin-top: 20px"
|
||||
v-for="(item, index) in orderDetaildata.detailList" :key="index">
|
||||
<div class="orderbox_right_list_item_row" style="display:flex;">
|
||||
<div>{{ item.productName }} {{ item.productSkuName }}</div>
|
||||
<div style="text-align: center">{{ item.num }}</div>
|
||||
<div style="text-align: center">{{ item.price }}</div>
|
||||
@@ -116,6 +131,16 @@
|
||||
</div>
|
||||
<div v-else>{{ item.priceAmount }}</div>
|
||||
</div>
|
||||
<div class="pro" v-if="item.proGroupInfo" v-for="(val, idx) in JSON.parse(item.proGroupInfo)" :key="idx">
|
||||
<div>
|
||||
<span>>{{ val.proName }}</span>
|
||||
<span v-if="val.skuName">规格:{{ val.skuName }}</span>
|
||||
</div>
|
||||
<div>{{ val.number }}</div>
|
||||
<div>0</div>
|
||||
<div>0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :style="{ height: reforderboxrightbuttonheight + 'px' }"></div>
|
||||
</div>
|
||||
|
||||
@@ -134,7 +159,7 @@
|
||||
orderDetaildata.orderType != 'return' &&
|
||||
(orderDetaildata.status == 'refund' ||
|
||||
orderDetaildata.status == 'closed')
|
||||
" type="primary" @click="recharge = true">退单</el-button>
|
||||
" type="primary" @click="returnOrderHandle">退单</el-button>
|
||||
</div>
|
||||
<div class="orderbox_right_buttonbutton">
|
||||
<el-button style="flex: 1" :loading="invoiceLoading" @click="invoiveHandle" v-if="
|
||||
@@ -292,7 +317,8 @@
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="支付密码" type="password" placeholder="请输入支付密码" @success="passwordSuccess" />
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="支付密码" type="2" inputType="password" placeholder="请输入支付密码"
|
||||
@success="passwordSuccess" />
|
||||
<invoice ref="invoiceRef" @load-complete="invoiceLoading = false" />
|
||||
</template>
|
||||
|
||||
@@ -309,6 +335,7 @@ import {
|
||||
cloudPrinterprint,
|
||||
sendMessage,
|
||||
} from "@/api/order/index.js";
|
||||
import { queryPwdInfo, staffPermission } from '@/api/user.js'
|
||||
import add from "@/views/order/components/add.vue";
|
||||
import cashTable from "@/views/order/components/cashTable.vue";
|
||||
import { clearNoNum, formatDecimal } from "@/utils";
|
||||
@@ -369,6 +396,16 @@ function dateConfirm(time) {
|
||||
asyncorderfindOrder();
|
||||
}
|
||||
|
||||
// 显示退单
|
||||
async function returnOrderHandle() {
|
||||
try {
|
||||
await staffPermission('yun_xu_tui_kuan')
|
||||
recharge.value = true
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 是否线上退款
|
||||
const isOnline = ref(true)
|
||||
// 获取支付密码
|
||||
@@ -390,15 +427,15 @@ async function passwordSuccess(pwd) {
|
||||
return item && item;
|
||||
});
|
||||
if (arr.length != 0) {
|
||||
// await payreturnOrder(arr, md5(pwd));
|
||||
await payreturnOrder(arr, '', isOnline.value);
|
||||
// await payreturnOrder(arr, md5(pwd), isOnline.value);
|
||||
await payreturnOrder(arr, pwd ? md5(pwd) : '', isOnline.value);
|
||||
changechecked.value = false;
|
||||
recharge.value = false;
|
||||
itemboxshow.value = false;
|
||||
refundamount.value = 0;
|
||||
ElMessage.success("退款成功!");
|
||||
buttonloading.value = false;
|
||||
asyncorderfindOrder();
|
||||
await asyncorderfindOrder();
|
||||
} else {
|
||||
buttonloading.value = false;
|
||||
ElMessage.error("没有退款项目!");
|
||||
@@ -418,8 +455,13 @@ const payreturnOrderclick = lodash.debounce(
|
||||
ElMessage.error("退款金额不能为0!");
|
||||
return false;
|
||||
}
|
||||
// takeFoodCodeRef.value.show();
|
||||
|
||||
let res = await queryPwdInfo()
|
||||
if (res.isReturn == 1) {
|
||||
takeFoodCodeRef.value.show();
|
||||
} else {
|
||||
passwordSuccess()
|
||||
}
|
||||
},
|
||||
500,
|
||||
{ leading: true, trailing: false }
|
||||
@@ -463,7 +505,9 @@ const print = lodash.throttle(
|
||||
shop_name: store.userInfo.shopName,
|
||||
loginAccount: store.userInfo.loginAccount,
|
||||
carts: [],
|
||||
amount: printLabelOrder.value.orderAmount,
|
||||
amount: formatDecimal(printLabelOrder.value.orderAmount),
|
||||
discountAmount: printLabelOrder.value.discountAmount > 0 ? formatDecimal(printLabelOrder.value.orderAmount - printLabelOrder.value.discountAmount) : formatDecimal(printLabelOrder.value.orderAmount),
|
||||
discount: printLabelOrder.value.discountRatio ? formatDecimal(printLabelOrder.value.discountRatio * 10, 1, true) : 0,
|
||||
remark: printLabelOrder.value.remark,
|
||||
orderInfo: printLabelOrder.value,
|
||||
outNumber: printLabelOrder.value.outNumber,
|
||||
@@ -479,8 +523,9 @@ const print = lodash.throttle(
|
||||
name: item.productName,
|
||||
number: item.num,
|
||||
skuName: item.productSkuName,
|
||||
salePrice: formatDecimal(item.priceAmount / item.num),
|
||||
totalAmount: formatDecimal(item.priceAmount)
|
||||
salePrice: formatDecimal(item.price),
|
||||
totalAmount: formatDecimal(item.num * item.price),
|
||||
proGroupInfo: item.proGroupInfo
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -502,6 +547,7 @@ const print = lodash.throttle(
|
||||
}
|
||||
} else if (e == 'refund') {
|
||||
if (printStore.deviceNoteList.length) {
|
||||
console.log('本地打退票');
|
||||
normalPrintLoading.value = true
|
||||
const data = {
|
||||
shop_name: store.userInfo.shopName,
|
||||
@@ -533,6 +579,8 @@ const print = lodash.throttle(
|
||||
normalPrintLoading.value = false
|
||||
}, 1000)
|
||||
} else {
|
||||
console.log('云打退票');
|
||||
|
||||
// 云打票
|
||||
await cloudPrinterprint({
|
||||
type: 'normal',
|
||||
@@ -559,7 +607,7 @@ const printLabelOrder = ref("");
|
||||
|
||||
const emititemboxshow = async (e) => {
|
||||
//接收子组件值 并赋值给父组件
|
||||
// console.log('emititemboxshow', e);
|
||||
console.log('emititemboxshow', e);
|
||||
printLabelOrder.value = e;
|
||||
|
||||
loadingboxshow.value = true;
|
||||
@@ -1062,6 +1110,41 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.orderbox_right_list_item {
|
||||
.pro {
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 10px;
|
||||
|
||||
div:nth-child(1) {
|
||||
text-align: left;
|
||||
width: 45%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
|
||||
div:nth-child(2) {
|
||||
width: 15%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
div:nth-child(3) {
|
||||
width: 15%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
div:nth-child(4) {
|
||||
width: 25%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.orderbox_right_list_item_row {
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
justify-content: space-between;
|
||||
@@ -1088,11 +1171,12 @@ onMounted(() => {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tableDataclass {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
height: 90%;
|
||||
overflow-y: auto;
|
||||
height: 70%;
|
||||
|
||||
.orderbox_right_item {
|
||||
margin-top: 6px;
|
||||
|
||||
139
src/views/queue/components/addTab.vue
Normal file
139
src/views/queue/components/addTab.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<el-dialog v-model="showAddTable" :title="addTabForm.id ? '编辑桌型' : '新增桌型'" top="10vh" @closed="addTabFormReset">
|
||||
<el-form ref="AddTabFormRef" :model="addTabForm" :rules="addTabFormRules" label-position="left"
|
||||
label-width="100">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="addTabForm.name" placeholder="请输入名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" prop="note">
|
||||
<el-input v-model="addTabForm.note" placeholder="请输入描述,例如1-2人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="等待时间" prop="waitTime">
|
||||
<el-input v-model="addTabForm.waitTime" placeholder="0">
|
||||
<template #append>分钟/1桌</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="号码前缀" prop="prefix">
|
||||
<el-input v-model="addTabForm.prefix" placeholder="请输入英文字母,不支持中文" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开始号码" prop="start">
|
||||
<el-input v-model="addTabForm.start" placeholder="请输入开始号码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="过号保留">
|
||||
<el-input v-model="addTabForm.nearNum" :disabled="!addTabForm.isPostpone" placeholder="临近几桌提醒">
|
||||
<template #prepend>
|
||||
<el-checkbox v-model="addTabForm.isPostpone" :true-value="1" :false-value="0" label="开启顺延" />
|
||||
</template>
|
||||
<template #append>桌</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="footer" style="display: flex;">
|
||||
<el-button style="width: 100%" @click="showAddTable = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" style="width: 100%" :loading="addTabFormLoading" @click="addTabConfirmHandle">
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { addCallTable } from '@/api/queue.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const showAddTable = ref(false)
|
||||
const addTabFormLoading = ref(false)
|
||||
const AddTabFormRef = ref(null)
|
||||
const resetAddTabForm = ref({})
|
||||
const addTabForm = ref({
|
||||
name: '',
|
||||
note: '',
|
||||
waitTime: '',
|
||||
prefix: '',
|
||||
start: '',
|
||||
isPostpone: 0,
|
||||
nearNum: ''
|
||||
})
|
||||
|
||||
const addTabFormRules = ref({
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: ' ',
|
||||
trigger: 'blur',
|
||||
}
|
||||
],
|
||||
waitTime: [
|
||||
{
|
||||
required: true,
|
||||
message: ' ',
|
||||
trigger: 'blur',
|
||||
}
|
||||
],
|
||||
prefix: [
|
||||
{
|
||||
required: true,
|
||||
message: ' ',
|
||||
trigger: 'blur',
|
||||
}
|
||||
],
|
||||
start: [
|
||||
{
|
||||
required: true,
|
||||
message: ' ',
|
||||
trigger: 'blur',
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
// 初始化
|
||||
function addTabFormReset() {
|
||||
addTabForm.value = { ...resetAddTabForm.value }
|
||||
AddTabFormRef.value.resetFields()
|
||||
}
|
||||
|
||||
// 提交
|
||||
function addTabConfirmHandle() {
|
||||
AddTabFormRef.value.validate(async valid => {
|
||||
try {
|
||||
if (valid) {
|
||||
addTabFormLoading.value = true
|
||||
addTabForm.value.shopId = store.userInfo.shopId
|
||||
if (addTabForm.value.id) {
|
||||
addTabForm.value.callTableId = addTabForm.value.id
|
||||
}
|
||||
const res = await addCallTable(addTabForm.value)
|
||||
addTabFormLoading.value = false
|
||||
showAddTable.value = false
|
||||
ElMessage.success(addTabForm.value.id ? '编辑成功' : '添加成功')
|
||||
emits('success')
|
||||
}
|
||||
} catch (error) {
|
||||
addTabFormLoading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function show(obj) {
|
||||
if (obj && obj.id) {
|
||||
addTabForm.value = { ...obj }
|
||||
}
|
||||
showAddTable.value = true
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
resetAddTabForm.value = { ...addTabForm.value }
|
||||
})
|
||||
</script>
|
||||
108
src/views/queue/components/getNumber.vue
Normal file
108
src/views/queue/components/getNumber.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<!-- 取号 -->
|
||||
<template>
|
||||
<el-dialog title="取号" v-model="visible" @closed="onClose">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||
<el-form-item label="选择桌型">
|
||||
<el-radio-group v-model="form.callTableId">
|
||||
<el-radio :value="item.id" border v-for="item in list" :key="item.id">{{ item.name
|
||||
}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码" prop="phone">
|
||||
<el-input v-model="form.phone" placeholder="请填写手机号" style="width: 60%;" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="footer" style="display: flex;padding-top: 30px;">
|
||||
<el-button style="width: 100%" @click="visible = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="confirmHandle">
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { takeNumber } from '@/api/queue.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
const list = ref([])
|
||||
|
||||
const loading = ref(false)
|
||||
const formRef = ref(null)
|
||||
const resetForm = ref({})
|
||||
const form = ref({
|
||||
callTableId: '',
|
||||
shopId: '',
|
||||
phone: '',
|
||||
note: '',
|
||||
name: ''
|
||||
})
|
||||
|
||||
const rules = ref({
|
||||
phone: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
let reg = /^(?:(?:\+|00)86)?1\d{10}$/
|
||||
if (!reg.test(form.value.phone)) {
|
||||
callback(new Error('手机号码不正确'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 提交
|
||||
function confirmHandle() {
|
||||
formRef.value.validate(async vaild => {
|
||||
try {
|
||||
if (vaild) {
|
||||
loading.value = true
|
||||
form.value.shopId = store.userInfo.shopId
|
||||
form.value.note = list.value.find(item => item.id == form.value.callTableId).note
|
||||
form.value.name = list.value.find(item => item.id == form.value.callTableId).name
|
||||
await takeNumber(form.value)
|
||||
loading.value = false
|
||||
ElMessage.success('取号成功')
|
||||
emits('success')
|
||||
visible.value = false
|
||||
}
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化
|
||||
function onClose() {
|
||||
form.value = { ...resetForm.value }
|
||||
formRef.value.resetFields()
|
||||
}
|
||||
|
||||
function show(arr) {
|
||||
visible.value = true
|
||||
list.value = [...arr]
|
||||
form.value.callTableId = list.value[0].id
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
resetForm.value = { ...form }
|
||||
})
|
||||
</script>
|
||||
99
src/views/queue/components/record.vue
Normal file
99
src/views/queue/components/record.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<!-- 叫号记录 -->
|
||||
<template>
|
||||
<el-dialog v-model="dialogVisible" title="叫号记录" @closed="reset" width="80vw">
|
||||
<el-table :data="tableData.list" border style="height: 84%;" height="50vh">
|
||||
<el-table-column label="桌号" prop="name"></el-table-column>
|
||||
<el-table-column label="桌型" prop="note"></el-table-column>
|
||||
<el-table-column label="手机号" prop="phone"></el-table-column>
|
||||
<el-table-column label="状态" prop="state">
|
||||
<template v-slot="scope">
|
||||
{{ statusList[scope.row.state].text }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="时间" prop="callTime" width="200">
|
||||
<template v-slot="scope">{{ dayjs(scope.row.callTime).format('YYYY-MM-DD HH:mm:ss') }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination" style="padding-top:15px;display: flex;justify-content: flex-end;">
|
||||
<el-pagination v-model:current-page="tableData.page" v-model:page-size="tableData.size"
|
||||
layout="total, prev, pager, next" :total="tableData.total" background @current-change="paginationChange"
|
||||
@size-change="paginationChange">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { dayjs } from 'element-plus'
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { callRecord } from '@/api/queue.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const tableData = reactive({
|
||||
loading: false,
|
||||
list: [],
|
||||
page: 1,
|
||||
size: 20,
|
||||
total: 0
|
||||
})
|
||||
const statusList = {
|
||||
'-1': {
|
||||
type: 'warning',
|
||||
text: '已取消'
|
||||
},
|
||||
0: {
|
||||
type: 'danger',
|
||||
text: '排队中'
|
||||
},
|
||||
1: {
|
||||
type: 'success',
|
||||
text: '叫号中'
|
||||
},
|
||||
2: {
|
||||
type: 'success',
|
||||
text: '已入座'
|
||||
},
|
||||
3: {
|
||||
type: 'success',
|
||||
text: '已过号'
|
||||
}
|
||||
}
|
||||
|
||||
// 分页变化
|
||||
function paginationChange(e) {
|
||||
callRecordAjax()
|
||||
}
|
||||
|
||||
// 记录数据
|
||||
async function callRecordAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await callRecord({
|
||||
callTableId: '',
|
||||
shopId: store.userInfo.shopId,
|
||||
page: tableData.page,
|
||||
size: tableData.size
|
||||
})
|
||||
tableData.loading = false
|
||||
tableData.list = res.records
|
||||
tableData.total = res.total
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
tableData.page = 1
|
||||
}
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true
|
||||
callRecordAjax()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
75
src/views/queue/components/resultModal.vue
Normal file
75
src/views/queue/components/resultModal.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<!-- 播报结果 -->
|
||||
<template>
|
||||
<el-dialog title="提示" v-model="visible">
|
||||
<div class="content">
|
||||
<div style="font-size: 18px;">正在叫号,请稍等</div>
|
||||
<el-alert :title="statusList[item.status].text" :type="statusList[item.status].type" :closable="false" />
|
||||
</div>
|
||||
<div class="footer" style="display: flex;">
|
||||
<el-button style="width: 100%" @click="confirmHandle(2)">完成</el-button>
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="confirmHandle(3)">过号</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { updateState } from '@/api/queue.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const visible = ref(false)
|
||||
const item = ref({})
|
||||
const loading = ref(false)
|
||||
const statusList = {
|
||||
'-1': {
|
||||
type: 'warning',
|
||||
text: '用户未订阅'
|
||||
},
|
||||
0: {
|
||||
type: 'danger',
|
||||
text: '失败'
|
||||
},
|
||||
1: {
|
||||
type: 'success',
|
||||
text: '成功'
|
||||
}
|
||||
}
|
||||
|
||||
// 过号修改状态
|
||||
async function confirmHandle(state) {
|
||||
try {
|
||||
await updateState({
|
||||
shopId: store.userInfo.shopId,
|
||||
callQueueId: item.value.id,
|
||||
state: state
|
||||
})
|
||||
visible.value = false
|
||||
emits('success')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function show(obj) {
|
||||
visible.value = true
|
||||
item.value = { ...obj }
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
233
src/views/queue/components/setting.vue
Normal file
233
src/views/queue/components/setting.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<el-dialog v-model="dialogVisible" title="基本设置" width="90vw" top="5vh" @closed="emits('success')">
|
||||
<div class="scroll_y">
|
||||
<el-form ref="formRef" :model="form" label-position="left" label-width="140">
|
||||
<el-form-item label="排队页面地址">{{ config.pageAddress }}</el-form-item>
|
||||
<el-form-item label="线上取号">
|
||||
<el-switch v-model="form.isOnline" :active-value="1" :inactive-value="0"></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item label="背景图片">
|
||||
<UploadImg ref="UploadImgRef" @success="e => form.bgCover = e" />
|
||||
</el-form-item>
|
||||
<el-form-item label="桌型">
|
||||
<el-table :data="tableData.list" border v-loading="tableData.loading">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="描述" prop="note"></el-table-column>
|
||||
<el-table-column label="等待时间[桌]" prop="waitTime"></el-table-column>
|
||||
<el-table-column label="号码前缀" prop="prefix"></el-table-column>
|
||||
<el-table-column label="开始号码" prop="start"></el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template #header>
|
||||
<el-button type="primary" @click="AddTabRef.show()">添加</el-button>
|
||||
</template>
|
||||
<template v-slot="scope">
|
||||
<div style="display: flex;gap: 10px;">
|
||||
<el-text type="primary" @click="AddTabRef.show(scope.row)">编辑</el-text>
|
||||
<el-text type="danger" @click="delCallTableHandle(scope.row)">删除</el-text>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
<div class="title" style="padding-bottom: 20px;">通知模板</div>
|
||||
<el-form-item label="排队成功提醒">
|
||||
<el-input disabled style="width: 50%;" v-model="config.successMsg"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="排队即将排到通知">
|
||||
<div style="display: flex;flex-direction: column;">
|
||||
<el-input disabled style="width: 50%;" v-model="config.nearMsg"></el-input>
|
||||
<el-input v-model="config.nearNum" disabled style="margin-top: 10px;">
|
||||
<template #prepend>前面等待</template>
|
||||
<template #append>桌时提醒</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="排队到号提醒">
|
||||
<el-input disabled style="width: 50%;" v-model="config.callingMsg"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button style="width: 100%" @click="dialogVisible = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="confirmHandle">
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<AddTab ref="AddTabRef" @success="getTableAjax" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import UploadImg from '@/components/uploadImg.vue'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
import AddTab from './addTab.vue'
|
||||
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { callTable, delCallTable, callTableConfig, callTableConfigPut } from '@/api/queue.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
|
||||
const AddTabRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
const loading = ref(false)
|
||||
const form = ref({
|
||||
isOnline: 1,
|
||||
bgCover: '',
|
||||
nearNum: '',
|
||||
})
|
||||
|
||||
function beforeAvatarUpload(file) {
|
||||
console.log(2, file);
|
||||
}
|
||||
|
||||
// 桌型
|
||||
const tableData = reactive({
|
||||
loading: false,
|
||||
list: []
|
||||
})
|
||||
|
||||
// 显示基本配置
|
||||
function show() {
|
||||
dialogVisible.value = true
|
||||
|
||||
getTableAjax()
|
||||
callTableConfigAjax()
|
||||
}
|
||||
|
||||
// 删除桌型
|
||||
function delCallTableHandle(row) {
|
||||
ElMessageBox.confirm('确认要删除吗?', '注意').then(async () => {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await delCallTable({
|
||||
shopId: store.userInfo.shopId,
|
||||
callTableId: row.id
|
||||
})
|
||||
getTableAjax()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}).catch(() => { })
|
||||
}
|
||||
|
||||
// 获取桌型列表
|
||||
async function getTableAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await callTable({
|
||||
page: 1,
|
||||
size: 100,
|
||||
shopId: store.userInfo.shopId,
|
||||
callTableId: '',
|
||||
state: ''
|
||||
})
|
||||
tableData.loading = false
|
||||
tableData.list = res.records
|
||||
} catch (error) {
|
||||
tableData.loading = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取配置信息
|
||||
const config = ref({})
|
||||
const UploadImgRef = ref(null)
|
||||
async function callTableConfigAjax() {
|
||||
try {
|
||||
const res = await callTableConfig({ shopId: store.userInfo.shopId })
|
||||
config.value = res
|
||||
form.value.nearNum = res.nearNum
|
||||
if (res.bgCover) {
|
||||
UploadImgRef.value.init([{ url: res.bgCover }])
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 提交
|
||||
const emits = defineEmits(['success'])
|
||||
async function confirmHandle() {
|
||||
try {
|
||||
loading.value = true
|
||||
form.value.shopId = store.userInfo.shopId
|
||||
const res = await callTableConfigPut(form.value)
|
||||
loading.value = false
|
||||
ElMessage.success('保存成功')
|
||||
dialogVisible.value = false
|
||||
emits('success')
|
||||
} catch (error) {
|
||||
loading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed var(--el-border-color);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: var(--el-transition-duration-fast);
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.el-icon.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.avatar-uploader .avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
$btmH: 50px;
|
||||
|
||||
.scroll_y {
|
||||
height: 65vh;
|
||||
overflow-y: auto;
|
||||
padding-bottom: $btmH;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
padding: 0 100px 0;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
height: $btmH;
|
||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: $btmH*-1;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
282
src/views/queue/index.vue
Normal file
282
src/views/queue/index.vue
Normal file
@@ -0,0 +1,282 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<div class="card" style="flex: 1;">
|
||||
<div class="tab_head">
|
||||
<el-radio-group v-model="tabActive" @change="callTableQueueAjax">
|
||||
<el-radio-button label="全部" value=""></el-radio-button>
|
||||
<el-radio-button :label="item.name" :value="item.id" v-for="item in tabHeader"
|
||||
:key="item.id"></el-radio-button>
|
||||
</el-radio-group>
|
||||
<div class="btns">
|
||||
<el-button type="danger" @click="GetNumberRef.show(tabHeader)">取号</el-button>
|
||||
<el-button type="warning" @click="RecordRef.show()">叫号记录</el-button>
|
||||
<el-button type="primary" @click="SettingRef.show()">基本设置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="queue_list" v-loading="queueList.loading">
|
||||
<div class="item" v-for="item in queueList.list" :key="item.id">
|
||||
<div class="head">
|
||||
<div class="row">
|
||||
<div class="row_item">用户</div>
|
||||
<div class="row_item">号码</div>
|
||||
<div class="row_item">桌型</div>
|
||||
<div class="row_item">等待</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="row_item">{{ item.phone }}</div>
|
||||
<div class="row_item">{{ item.callNum }}</div>
|
||||
<div class="row_item">{{ item.name }}</div>
|
||||
<div class="row_item">{{ item.waitingCount }}分钟</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btm">
|
||||
<el-button @click="cancaleHandle(item)">取消</el-button>
|
||||
<el-button type="primary" @click="callHandle(item)">播报</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="empty">
|
||||
<el-empty description="暂无数据~" v-if="!queueList.list.length" style="width: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<el-pagination v-model:current-page="queueList.page" v-model:page-size="queueList.size"
|
||||
layout="total, prev, pager, next" :total="queueList.total" background
|
||||
@current-change="queueListChange" @size-change="queueListChange">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 基本设置 -->
|
||||
<Setting ref="SettingRef" @success="callTableAjax" />
|
||||
<!-- 叫号记录 -->
|
||||
<Record ref="RecordRef" />
|
||||
<!-- 取号 -->
|
||||
<GetNumber ref="GetNumberRef" @success="callTableQueueAjax" />
|
||||
<!-- 播报状态 -->
|
||||
<ResultModal ref="ResultModalRef" @success="callTableQueueAjax" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Speech from 'speak-tts'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
import Setting from './components/setting.vue'
|
||||
import Record from './components/record.vue'
|
||||
import GetNumber from './components/getNumber.vue'
|
||||
import ResultModal from './components/resultModal.vue'
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { callRecord, callTable, callTableQueue, updateState, callTableCall } from '@/api/queue.js'
|
||||
import { useUser } from "@/store/user.js"
|
||||
const store = useUser()
|
||||
|
||||
const SettingRef = ref(null)
|
||||
const RecordRef = ref(null)
|
||||
const GetNumberRef = ref(null)
|
||||
const ResultModalRef = ref(null)
|
||||
|
||||
// 获取桌型列表
|
||||
const tabHeader = ref([])
|
||||
const tabActive = ref('')
|
||||
async function callTableAjax() {
|
||||
try {
|
||||
const res = await callTable({
|
||||
page: 1,
|
||||
size: 100,
|
||||
shopId: store.userInfo.shopId,
|
||||
callTableId: '',
|
||||
state: ''
|
||||
})
|
||||
tabHeader.value = res.records
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 取号 排队列表获取 start
|
||||
const queueList = reactive({
|
||||
loading: false,
|
||||
list: [],
|
||||
page: 1,
|
||||
size: 8,
|
||||
total: 0
|
||||
})
|
||||
|
||||
function queueListChange() {
|
||||
callTableQueueAjax()
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
async function callTableQueueAjax() {
|
||||
try {
|
||||
queueList.loading = true
|
||||
const res = await callTableQueue({
|
||||
page: queueList.page,
|
||||
size: queueList.size,
|
||||
shopId: store.userInfo.shopId,
|
||||
callTableId: tabActive.value,
|
||||
state: ''
|
||||
})
|
||||
queueList.loading = false
|
||||
queueList.list = res.records
|
||||
queueList.total = res.total
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
queueList.loading = false
|
||||
}
|
||||
}
|
||||
// 取号 排队列表获取 end
|
||||
|
||||
// 取消排队
|
||||
function cancaleHandle(item) {
|
||||
ElMessageBox.confirm('确定要取消排队吗?', '注意').then(async () => {
|
||||
try {
|
||||
await updateState({
|
||||
shopId: store.userInfo.shopId,
|
||||
callQueueId: item.id,
|
||||
state: '-1'
|
||||
})
|
||||
ElMessage.success('已取消')
|
||||
callTableQueueAjax()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}).catch(() => { })
|
||||
}
|
||||
|
||||
// 播报
|
||||
async function callHandle(item) {
|
||||
try {
|
||||
startSpeech(`请${item.callNum}用餐`)
|
||||
const res = await callTableCall({
|
||||
shopId: store.userInfo.shopId,
|
||||
callQueueId: item.id,
|
||||
})
|
||||
ResultModalRef.value.show({
|
||||
...item,
|
||||
status: res.state
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 播放声音
|
||||
const speech = new Speech()
|
||||
function speechInit(params) {
|
||||
speech.init({
|
||||
volume: 1, // 音量
|
||||
lang: 'zh-CN', // 语言
|
||||
rate: 1, // 语速1正常语速,2倍语速就写2
|
||||
pitch: 1, // 音调
|
||||
splitSentences: true, // 在句子结束时暂停
|
||||
listeners: {
|
||||
// 事件
|
||||
onvoiceschanged: voices => {
|
||||
// console.log('事件声音已更改', voices);
|
||||
},
|
||||
},
|
||||
}).then(data => {
|
||||
console.log('语音已准备好,声音可用', data);
|
||||
}).catch(err => {
|
||||
console.log('初始化发生错误', err);
|
||||
})
|
||||
}
|
||||
|
||||
// 开始播报
|
||||
function startSpeech(text) {
|
||||
speech.speak({
|
||||
text: text, //这里使用文字或者i18n 都可以 看自己需求
|
||||
queue: true,
|
||||
listeners: {
|
||||
// 开始播放
|
||||
onstart: () => {
|
||||
console.log('Start utterance')
|
||||
},
|
||||
// 判断播放是否完毕
|
||||
onend: () => {
|
||||
console.log('End utterance')
|
||||
},
|
||||
// 恢复播放
|
||||
onresume: () => {
|
||||
console.log('Resume utterance')
|
||||
},
|
||||
}
|
||||
}).then(() => {
|
||||
console.log('成功!');
|
||||
}).catch(e => {
|
||||
console.error('发生错误:', e);
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
callTableAjax()
|
||||
callTableQueueAjax()
|
||||
|
||||
if (speech.hasBrowserSupport()) {
|
||||
console.log('语音播报加载成功,支持播报');
|
||||
speechInit()
|
||||
} else {
|
||||
console.log('当前浏览器不支持语音播报');
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card {
|
||||
padding: 15px;
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.tab_head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.queue_list {
|
||||
height: 80vh;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-template-rows: repeat(4, 1fr);
|
||||
grid-column-gap: 15px;
|
||||
grid-row-gap: 15px;
|
||||
padding: 15px 0;
|
||||
position: relative;
|
||||
|
||||
.empty {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.item {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
|
||||
.head {
|
||||
.row {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.row_item {
|
||||
flex: 1;
|
||||
|
||||
&:last-child {
|
||||
flex: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btm {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -15,24 +15,92 @@
|
||||
</el-icon>
|
||||
<span class="t">{{ status[props.tableInfo.status] }}</span>
|
||||
</div>
|
||||
<div class="place_order">
|
||||
<router-link class="btn" :to="{ name: 'home', query: { table_code: 1 } }">
|
||||
<div class="cart" v-loading="payLoading" v-if="props.tableInfo.status == 'using'">
|
||||
<div class="cart_list">
|
||||
<div class="item" v-for="item in cartList" :key="item.id">
|
||||
<div class="top">
|
||||
<span class="name">{{ item.name }}</span>
|
||||
<span class="n">x{{ item.number }}</span>
|
||||
<span class="p">¥{{ item.salePrice }}</span>
|
||||
</div>
|
||||
<div class="tag_wrap" v-if="item.skuName">
|
||||
<div class="tag" v-for="item in item.skuName.split(',')">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn_container">
|
||||
<div class="btn_wrap">
|
||||
<el-button type="success" style="width: 100%;" @click="toOrderMeal(1)">加菜/管理</el-button>
|
||||
</div>
|
||||
<div class="btn_wrap">
|
||||
<el-button type="primary" style="width: 100%;" @click="showPayHandle">结算(¥{{
|
||||
orderInfo.orderAmount || 0 }})</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="place_order" v-else>
|
||||
<div class="btn">
|
||||
<div class="top">
|
||||
<el-icon class="icon">
|
||||
<TakeawayBox />
|
||||
</el-icon>
|
||||
<span class="t">点单</span>
|
||||
<!-- <span class="t">点单</span> -->
|
||||
</div>
|
||||
<span class="tips">开始新订单</span>
|
||||
</router-link>
|
||||
<!-- <span class="tips">开始新订单</span> -->
|
||||
<div class="btn_wrap" v-if="props.tableInfo.status == 'idle'">
|
||||
<el-button type="primary" style="width: 100%;" @click="showPeopleNumHandle">开始新订单</el-button>
|
||||
</div>
|
||||
<div class="btn_wrap" v-if="props.tableInfo.status == 'cleaning'">
|
||||
<el-button type="primary" style="width: 100%;" @click="clearTableStatus">清理完成</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<transition name="el-fade-in">
|
||||
<div class="people_num_wrap" v-show="showPeopleNum">
|
||||
<div class="title">应选择就餐人数</div>
|
||||
<div class="num_btns">
|
||||
<div class="item" :class="{ active: peopleNum == item }"
|
||||
v-for="item in props.tableInfo.maxCapacity" @click="peopleNum = item">{{ item }}人</div>
|
||||
<!-- <div class="item" :class="{ active: peopleNum == 'custom' }">
|
||||
<input class="ipt" @focus="inputFocus" placeholder="自定义" v-model="peopleNumInputValue"
|
||||
@change="" />
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;"
|
||||
:disabled="(!peopleNum && !peopleNumInputValue) || (peopleNum == 'custom' && !peopleNumInputValue)"
|
||||
@click="orderDownHandle">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<!-- 结算订单 -->
|
||||
<settleAccount ref="settleAccountRef" :cart="cartList" :amount="orderInfo.orderAmount"
|
||||
:remark="orderInfo.remark" :masterId="orderInfo.masterId" :orderInfo="orderInfo" @paySuccess="paySuccess" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, reactive, onMounted, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { queryMembermember } from '@/api/member/index.js'
|
||||
import { orderDetail } from '@/api/order/index.js'
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
import settleAccount from "@/views/home/components/settleAccount.vue";
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { clearTable } from '@/api/table.js'
|
||||
import { useShop } from '@/store/shop.js'
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
const shopStore = useShop()
|
||||
|
||||
const router = useRouter()
|
||||
const global = useGlobal()
|
||||
const store = useUser()
|
||||
|
||||
const emits = defineEmits(['close', 'success'])
|
||||
|
||||
const props = defineProps({
|
||||
tableInfo: {
|
||||
@@ -41,17 +109,145 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const showPeopleNum = ref(false)
|
||||
const peopleNum = ref(0)
|
||||
const peopleNumInputValue = ref('')
|
||||
|
||||
watch(props, () => {
|
||||
getOrderDetail()
|
||||
})
|
||||
|
||||
// 自定义人数输入获得焦点
|
||||
function inputFocus() {
|
||||
peopleNum.value = 'custom'
|
||||
}
|
||||
|
||||
const settleAccountRef = ref(null)
|
||||
const orderInfo = ref({})
|
||||
const cartList = ref([])
|
||||
|
||||
const status = ref({
|
||||
'subscribe': '预定',
|
||||
'closed': '关台',
|
||||
'opening': '开台中',
|
||||
'idle': '空闲',
|
||||
'using': '开台中',
|
||||
'pending': '挂单中',
|
||||
'paying': '结算中',
|
||||
'cleaning': '台桌清理中'
|
||||
})
|
||||
|
||||
const payLoading = ref(false)
|
||||
|
||||
// 显示结算页面
|
||||
function showPayHandle() {
|
||||
settleAccountRef.value.show()
|
||||
}
|
||||
|
||||
// 显示就就餐人数
|
||||
function showPeopleNumHandle() {
|
||||
if (shopStore.info.isTableFee == 1) {
|
||||
orderDownHandle()
|
||||
} else {
|
||||
showPeopleNum.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 清理桌台
|
||||
const clearLoading = ref(false)
|
||||
async function clearTableStatus() {
|
||||
try {
|
||||
clearLoading.value = true
|
||||
const res = await clearTable({
|
||||
shopId: store.userInfo.shopId,
|
||||
tableId: props.tableInfo.qrcode
|
||||
})
|
||||
clearLoading.value = false
|
||||
emits('success')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取订单详情
|
||||
async function getOrderDetail() {
|
||||
try {
|
||||
if (props.tableInfo.orderId) {
|
||||
payLoading.value = true
|
||||
const res = await orderDetail({
|
||||
shopId: store.userInfo.shopId,
|
||||
id: props.tableInfo.orderId
|
||||
})
|
||||
payLoading.value = false
|
||||
orderInfo.value = res
|
||||
|
||||
cartList.value = res.detailList.map(item => {
|
||||
let obj = {
|
||||
name: item.productName,
|
||||
number: item.num,
|
||||
salePrice: item.price,
|
||||
skuName: item.productSkuName
|
||||
}
|
||||
return obj
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
payLoading.value = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭
|
||||
function close() {
|
||||
emit('close')
|
||||
emits('close')
|
||||
}
|
||||
|
||||
// 判断数字是不是正整数
|
||||
function isPositiveInteger(num) {
|
||||
return Number.isInteger(num) && num > 0;
|
||||
}
|
||||
|
||||
// 选择人数后确认下单
|
||||
function orderDownHandle() {
|
||||
// if (peopleNum.value == 'custom') {
|
||||
// if (!isPositiveInteger(parseFloat(peopleNumInputValue.value))) {
|
||||
// ElMessage.error('请输入有效的就餐人数')
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// 直接点单
|
||||
global.setOrderTable({
|
||||
...props.tableInfo,
|
||||
num: peopleNum.value
|
||||
})
|
||||
router.push({
|
||||
name: 'home',
|
||||
})
|
||||
}
|
||||
|
||||
// 点单
|
||||
function toOrderMeal(t) {
|
||||
if (t == 1) {
|
||||
// 直接点单
|
||||
global.setOrderTable(props.tableInfo)
|
||||
router.push({
|
||||
name: 'home',
|
||||
})
|
||||
} else {
|
||||
// 选择会员点单
|
||||
showDialog.value = true
|
||||
getMemberList()
|
||||
}
|
||||
}
|
||||
|
||||
function paySuccess() {
|
||||
getOrderDetail()
|
||||
emits('success')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getOrderDetail()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -97,6 +293,74 @@ function close() {
|
||||
}
|
||||
}
|
||||
|
||||
.cart {
|
||||
height: calc(100vh - 160px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.cart_list {
|
||||
flex: 1;
|
||||
border-radius: 6px;
|
||||
background-color: #efefef;
|
||||
padding: 0 var(--el-font-size-base);
|
||||
overflow-y: auto;
|
||||
|
||||
.item {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.top {
|
||||
|
||||
display: flex;
|
||||
padding-bottom: 6px;
|
||||
|
||||
.name {
|
||||
flex: 1;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.n {
|
||||
width: 50px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.p {
|
||||
width: 50px;
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.tag_wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.tag {
|
||||
padding: 2px 6px;
|
||||
background-color: var(--el-color-danger);
|
||||
color: #fff;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.btn_container {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
||||
.btn_wrap {
|
||||
flex: 1;
|
||||
padding-top: var(--el-font-size-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.place_order {
|
||||
background-color: #efefef;
|
||||
height: calc(100vh - 160px);
|
||||
@@ -104,17 +368,21 @@ function close() {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
$size: 150px;
|
||||
|
||||
.top {
|
||||
background-color: var(--el-color-danger);
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -135,6 +403,81 @@ function close() {
|
||||
color: #999;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.btn_wrap {
|
||||
width: $size;
|
||||
}
|
||||
}
|
||||
|
||||
.people_num_wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9;
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
backdrop-filter: blur(10px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
padding-bottom: 40px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.num_btns {
|
||||
width: 80%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: 40px 40px 40px;
|
||||
gap: 20px;
|
||||
|
||||
.item {
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
background-color: var(--el-color-danger);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
transition: all .1s ease-in-out;
|
||||
|
||||
&.active {
|
||||
font-size: 14px;
|
||||
background-color: #e96565;
|
||||
box-shadow: inset 0 4px 5px rgba(0, 0, 0, 0.3);
|
||||
|
||||
.ipt {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.ipt {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
outline: none;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
transition: all .1s ease-in-out;
|
||||
|
||||
&::-webkit-input-placeholder {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 80%;
|
||||
padding-top: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,26 @@
|
||||
</div>
|
||||
<div class="overflow_y" v-loading="loading">
|
||||
<div class="tab_list">
|
||||
<div class="item" :class="{ active: tableItemActive == index }"
|
||||
<div class="item"
|
||||
:class="{ active: tableItemActive == index, using: item.status == 'using', closed: item.status == 'closed' }"
|
||||
v-for="(item, index) in tableList" :key="item.id" @click="slectTableHandle(index, item)">
|
||||
<div class="tab_title" :class="`${item.status}`">
|
||||
<span>{{ item.name }}</span>
|
||||
<span>0/{{ item.maxCapacity }}</span>
|
||||
</div>
|
||||
<div class="tab_cont">
|
||||
<el-icon class="icon">
|
||||
<el-icon class="icon" v-if="item.status != 'using'">
|
||||
<CircleClose />
|
||||
</el-icon>
|
||||
<div class="using" v-else>
|
||||
<div class="t1">开台中</div>
|
||||
<!-- <div class="t2">
|
||||
<el-icon>
|
||||
<Timer />
|
||||
</el-icon>
|
||||
<span>{{ countTime(item.updatedAt) }}</span>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,7 +55,7 @@
|
||||
<!-- 台桌统计 -->
|
||||
<countCard v-if="!slectTable.id" />
|
||||
<!-- 台桌信息 -->
|
||||
<tableInfo v-else :tableInfo="slectTable" @close="slectTableClose" />
|
||||
<tableInfo v-else :tableInfo="slectTable" @close="slectTableClose" @success="paySuccess" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -58,6 +68,7 @@ import tableInfo from '@/views/table/components/tableInfo.vue'
|
||||
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { dayjs } from 'element-plus'
|
||||
const store = useUser()
|
||||
|
||||
|
||||
@@ -65,15 +76,15 @@ const tabActive = ref(0)
|
||||
const tabAreas = ref([
|
||||
{
|
||||
label: '全部',
|
||||
type: 0,
|
||||
type: '',
|
||||
},
|
||||
{
|
||||
label: '空闲',
|
||||
type: 1,
|
||||
type: 'idle',
|
||||
},
|
||||
{
|
||||
label: '使用中',
|
||||
type: 2,
|
||||
type: 'using'
|
||||
},
|
||||
// {
|
||||
// label: '已预订',
|
||||
@@ -96,6 +107,19 @@ const slectTable = ref('')
|
||||
// 切换类型
|
||||
function tabChange(item, index) {
|
||||
tabActive.value = index
|
||||
queryShopTableAjax()
|
||||
}
|
||||
|
||||
// 计算当前的时间差
|
||||
function countTime(t) {
|
||||
let ctime = dayjs().valueOf()
|
||||
return dayjs(ctime - t).format('H小时m分')
|
||||
}
|
||||
|
||||
// 支付成功,刷新状态
|
||||
async function paySuccess() {
|
||||
await queryShopTableAjax()
|
||||
slectTableHandle(tableItemActive.value, tableList.value[tableItemActive.value])
|
||||
}
|
||||
|
||||
// 选择台桌
|
||||
@@ -134,7 +158,7 @@ async function queryShopTableAjax() {
|
||||
const res = await queryShopTable({
|
||||
shopId: store.userInfo.shopId,
|
||||
areaId: area.value,
|
||||
status: '',
|
||||
status: tabAreas.value[tabActive.value].type,
|
||||
page: 1,
|
||||
pageSize: 500
|
||||
})
|
||||
@@ -230,13 +254,52 @@ onMounted(() => {
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
.item {
|
||||
background-color: #efefef;
|
||||
$closedColor: #aeb8c9;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border: 2px solid #fff;
|
||||
padding: 2px;
|
||||
background-color: var(--primary-color);
|
||||
|
||||
&.active {
|
||||
border-color: var(--primary-color);
|
||||
background-color: var(--primary-color);
|
||||
|
||||
.tab_cont {
|
||||
.icon {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.t1 {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.using {
|
||||
background-color: var(--el-color-success);
|
||||
|
||||
.tab_cont {
|
||||
.icon {
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
|
||||
.t1 {
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.closed {
|
||||
background-color: $closedColor;
|
||||
|
||||
.tab_cont {
|
||||
.icon {
|
||||
color: $closedColor;
|
||||
}
|
||||
|
||||
.t1 {
|
||||
color: $closedColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -250,22 +313,6 @@ onMounted(() => {
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
color: #fff;
|
||||
|
||||
&.subscribe {
|
||||
background-color: var(--el-color-success);
|
||||
}
|
||||
|
||||
&.closed {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
&.opening {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
&.cleaning {
|
||||
background-color: var(--el-color-danger);
|
||||
}
|
||||
}
|
||||
|
||||
.tab_cont {
|
||||
@@ -273,12 +320,39 @@ onMounted(() => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #efefef;
|
||||
border-radius: 4px;
|
||||
|
||||
.icon {
|
||||
color: #555;
|
||||
color: var(--primary-color);
|
||||
font-size: 30px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.using {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 10px;
|
||||
|
||||
.t1 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.t2 {
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 2px;
|
||||
|
||||
span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
</el-icon>
|
||||
<div style="margin-left: 4px;">返回</div>
|
||||
</div>
|
||||
<router-link to='/workrecord' class="box_top_right">
|
||||
<div class="box_top_right" @click="checkRecord">
|
||||
交班记录
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_content">
|
||||
<div class="box_content_left">
|
||||
@@ -146,6 +146,8 @@ import { useUser } from "@/store/user.js";
|
||||
import { useSocket } from "@/store/socket.js";
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { staffPermission } from '@/api/user.js'
|
||||
|
||||
const printStore = usePrint();
|
||||
|
||||
const socket = useSocket();
|
||||
@@ -161,10 +163,21 @@ const loading = ref(false);
|
||||
|
||||
const isPrint = ref(true)
|
||||
|
||||
// 查看交班记录
|
||||
async function checkRecord() {
|
||||
try {
|
||||
const res = await staffPermission('yun_xu_cha_kan_suo_you_jiao_ban_ji_lu')
|
||||
router.push('/workrecord')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 开始交班
|
||||
const exit = async () => {
|
||||
try {
|
||||
await staffPermission('yun_xu_jiao_ban')
|
||||
|
||||
let data = {}
|
||||
// 获取交班打印小票数据
|
||||
data = await handoverData({
|
||||
@@ -187,6 +200,7 @@ const exit = async () => {
|
||||
useStorage.del('token')
|
||||
useStorage.del('douyin')
|
||||
useStorage.del('categorysActive')
|
||||
useStorage.del('updateFlag')
|
||||
|
||||
ElMessage.success("交班成功");
|
||||
setTimeout(() => {
|
||||
@@ -217,6 +231,7 @@ const exit = async () => {
|
||||
useStorage.del('token')
|
||||
useStorage.del('douyin')
|
||||
useStorage.del('categorysActive')
|
||||
useStorage.del('updateFlag')
|
||||
ElMessage.success("交班成功");
|
||||
setTimeout(() => {
|
||||
router.replace({
|
||||
|
||||
@@ -7,6 +7,8 @@ import path from "path";
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ command, mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), "");
|
||||
// console.log(env.ENV);
|
||||
|
||||
return {
|
||||
server: {
|
||||
proxy: {
|
||||
@@ -40,7 +42,7 @@ export default defineConfig(({ command, mode }) => {
|
||||
},
|
||||
},
|
||||
esbuild: {
|
||||
drop: ["console"],
|
||||
drop: env.ENV == "production" ? ["console"] : [],
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user