Compare commits
309 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
25ae5a7b80 | |
|
|
125365f3dc | |
|
|
8e3bc9cc3b | |
|
|
aa82851361 | |
|
|
aabbeced98 | |
|
|
b3b788d8d4 | |
|
|
ec5ae0e7d4 | |
|
|
2ba61eab19 | |
|
|
4d939b2889 | |
|
|
ca3b0eddbc | |
|
|
3a11828f3c | |
|
|
47ccfd0544 | |
|
|
b5773cf78c | |
|
|
694cb154a6 | |
|
|
0a0f672a02 | |
|
|
f466bdc9f4 | |
|
|
e443b5b51e | |
|
|
ebf912ecd8 | |
|
|
429283e542 | |
|
|
117df7d7bd | |
|
|
0c45fd9de1 | |
|
|
e13727e6ff | |
|
|
48280f92df | |
|
|
dd6189b51b | |
|
|
95ab7730f5 | |
|
|
4245b5a098 | |
|
|
3e84edbb6c | |
|
|
a914adc9f8 | |
|
|
87e8976353 | |
|
|
a101cc4fb7 | |
|
|
177d987769 | |
|
|
64f539623f | |
|
|
d08a629b0a | |
|
|
745b8675ea | |
|
|
cfe9f7bb36 | |
|
|
48c9f24d4c | |
|
|
1e66b2ad1f | |
|
|
3df0cce9ec | |
|
|
5cf2355d28 | |
|
|
db3fc1f6dc | |
|
|
573dd88b24 | |
|
|
d3ed4ec8e6 | |
|
|
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 | |
|
|
0f522fa9d2 | |
|
|
efb7dd3e57 | |
|
|
ac469cbc32 | |
|
|
f8c5c9bf59 | |
|
|
6e2e7f9719 | |
|
|
b4872fec16 | |
|
|
804b677174 | |
|
|
367b49c68a | |
|
|
f393299f0f | |
|
|
49cabfed21 | |
|
|
b2e450fd52 | |
|
|
4fb34a4235 | |
|
|
fdacaab44a | |
|
|
b33086ba04 | |
|
|
fd6410f742 | |
|
|
ea0c01bb2b | |
|
|
4eb5df7668 | |
|
|
2c58c99d1e | |
|
|
9e57753323 | |
|
|
d2183eec37 | |
|
|
a282636266 | |
|
|
c155e8a805 | |
|
|
aa25c6be3b | |
|
|
4543854d0a | |
|
|
5e7935bb53 | |
|
|
38366601d4 | |
|
|
e00feb82ec | |
|
|
815b6e0a25 | |
|
|
8c1e1d3fbc | |
|
|
bb554a28d2 | |
|
|
2a09a3fd5b | |
|
|
a70fa744b2 | |
|
|
91670a440b | |
|
|
d101ecea41 | |
|
|
de8c5e20f4 | |
|
|
8e69969c0e | |
|
|
105e38c726 | |
|
|
1f20c18384 | |
|
|
c7758f66d7 | |
|
|
78672a0cf9 | |
|
|
105ad4ee52 | |
|
|
89b078daae | |
|
|
b5356d8370 | |
|
|
f3dfd4a121 | |
|
|
87627e7b35 | |
|
|
408e0e44c4 | |
|
|
c4cb307275 | |
|
|
ed8b593c1a | |
|
|
776523c1ea | |
|
|
328b512411 | |
|
|
44495c3ee7 | |
|
|
0b2b4b44d0 | |
|
|
c86fff9691 | |
|
|
1439f12ee5 | |
|
|
fde0ed0eaf | |
|
|
883eb268f3 | |
|
|
0b42be9964 | |
|
|
a1c8757aaf | |
|
|
b6030331ff | |
|
|
ffb6807a90 | |
|
|
69a74cc416 | |
|
|
bcdf4a5b73 | |
|
|
4e954e42d5 | |
|
|
a5e04e3f97 | |
|
|
1f5f910e99 | |
|
|
c9dc11fa93 | |
|
|
3b0e6513c7 | |
|
|
bf0614e10b | |
|
|
69482f81a7 | |
|
|
6d7db2d743 | |
|
|
c54304f3d6 | |
|
|
6c1e34be7a | |
|
|
b8ea253d6e | |
|
|
6df40c8423 | |
|
|
d08ef6f271 | |
|
|
94fb2d2c8e | |
|
|
443f9ed305 | |
|
|
5c56f5a277 | |
|
|
dbc7444e78 | |
|
|
6f378cc3c0 | |
|
|
43ccf82177 | |
|
|
e26049593f | |
|
|
f5974bf482 | |
|
|
5bb73cb3b3 | |
|
|
3ed7f77508 | |
|
|
51fe3266ce | |
|
|
f1982a73f6 | |
|
|
ca4eec636a | |
|
|
0f9dd3ea66 | |
|
|
84c6ef4aae | |
|
|
a57b45160e | |
|
|
07d7df0416 | |
|
|
fae65b2e2a | |
|
|
810efcb381 | |
|
|
da00851195 | |
|
|
ddd0c8dba8 | |
|
|
6456832019 | |
|
|
8a9889d188 | |
|
|
154a362af6 | |
|
|
5e3d3c91f1 | |
|
|
56e28681f6 | |
|
|
7f8831c3cd | |
|
|
fa923f3db5 | |
|
|
f36af706d6 | |
|
|
d222e76576 | |
|
|
9a45998a65 | |
|
|
19b71d754f | |
|
|
426e1d59a9 | |
|
|
f430eee3c2 | |
|
|
ae2137f468 | |
|
|
e9e2f03acf | |
|
|
e1756b1a69 | |
|
|
910194a509 | |
|
|
b9004476ec | |
|
|
fc6aa68ea3 | |
|
|
cb1e356aeb | |
|
|
34a04442ac | |
|
|
03c6079301 | |
|
|
10ea9d4f68 | |
|
|
b7d35e5a6a | |
|
|
5dc8848432 | |
|
|
4c6e0cc38a | |
|
|
1450681d77 | |
|
|
1dec68b589 | |
|
|
2b8910f6a1 | |
|
|
2176ca3ab1 | |
|
|
ba7efac5d1 | |
|
|
861e62ce15 | |
|
|
e112137239 | |
|
|
cacbda0424 | |
|
|
1068fae037 | |
|
|
3b5d04bc30 | |
|
|
c094b1d673 | |
|
|
286f6206f1 | |
|
|
ba6f1cdc49 | |
|
|
8d8b2f79b5 | |
|
|
d5942f5453 | |
|
|
dc306aeff0 | |
|
|
d83b593db1 | |
|
|
c68b36740f | |
|
|
ec1fe43f3d | |
|
|
e058c97016 | |
|
|
5e5d854849 | |
|
|
ef18990451 | |
|
|
4ea6ece75a | |
|
|
c1d4405d0e | |
|
|
4adbc125b2 | |
|
|
83a25a2253 | |
|
|
8339506c93 | |
|
|
0fbc614c61 | |
|
|
d407cb81be | |
|
|
11290d1505 | |
|
|
6e3a4c5ce3 | |
|
|
f0b7169a29 | |
|
|
58993e00ee | |
|
|
fc810fd02f | |
|
|
7dc27dbeef | |
|
|
31ef882431 | |
|
|
d648781ea3 | |
|
|
4a5b52fa45 | |
|
|
396d237710 | |
|
|
dc2d7124d0 | |
|
|
b550cf3fd8 | |
|
|
5d96435125 | |
|
|
91ce993270 | |
|
|
d29d8b7f93 | |
|
|
48d6583a03 | |
|
|
8c42d09f38 | |
|
|
0d04bfc3d2 | |
|
|
4983ae1664 | |
|
|
d00612da5a | |
|
|
b42588ca1c | |
|
|
0fa0d56558 | |
|
|
27721ca096 | |
|
|
4facc5cc99 | |
|
|
6e796c1855 | |
|
|
120c478b86 | |
|
|
c0caecf0fa | |
|
|
2e783aa36c | |
|
|
e925948dcd | |
|
|
f8521dad84 | |
|
|
d2689b226c | |
|
|
7d30a42cb8 | |
|
|
5deec59c38 | |
|
|
6faf1474bd | |
|
|
e0ade277dc | |
|
|
c198f81483 | |
|
|
1aa33cab00 | |
|
|
fcf14d27fe | |
|
|
d65e3db7c0 | |
|
|
56f9d83447 | |
|
|
2ac2a3209a | |
|
|
1525bb1bf9 | |
|
|
276e65e9a3 | |
|
|
9aa6eee67a | |
|
|
8e819051b0 | |
|
|
9e3e411b7f | |
|
|
9bbd463852 | |
|
|
4a052300d5 | |
|
|
2a0f839988 | |
|
|
aa16193d4f | |
|
|
bf1428b205 | |
|
|
91e2f2ff33 | |
|
|
5bdc900719 | |
|
|
1f59f300d0 | |
|
|
158ea7c55a | |
|
|
eeac3e3541 | |
|
|
a662ae5c01 | |
|
|
6b6caa451e | |
|
|
9a060cbfc7 | |
|
|
a1b6f3d030 | |
|
|
1667091380 | |
|
|
33225b0aef | |
|
|
9744a968bb | |
|
|
b37811ced5 | |
|
|
08597b3c9f | |
|
|
b69be492d7 | |
|
|
3cb4828476 | |
|
|
d99575b2b7 | |
|
|
5298ff2569 | |
|
|
42bf301417 | |
|
|
1d3ca787ed | |
|
|
d151647906 | |
|
|
1117cba7de | |
|
|
1dc82a11aa | |
|
|
9ff98ba4d2 | |
|
|
5250c581ab | |
|
|
b0828cc1c0 |
|
|
@ -0,0 +1,29 @@
|
|||
# 本地环境
|
||||
ENV = development
|
||||
|
||||
# 测试ws
|
||||
# VITE_API_WSS = 'wss://sockets.sxczgkj.com/wss'
|
||||
|
||||
# 正式ws
|
||||
# VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
|
||||
|
||||
# 本地ws
|
||||
VITE_API_WSS = 'ws://192.168.1.42:2348'
|
||||
|
||||
# 正式 php
|
||||
VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
|
||||
|
||||
# 测试 php 开票
|
||||
# VITE_API_KP_URL = 'http://192.168.1.13:8888/api'
|
||||
|
||||
# 正式 php 开票
|
||||
VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||
|
||||
# 本地调试连接
|
||||
VITE_API_URL = 'http://192.168.1.42/'
|
||||
|
||||
# 线上测试
|
||||
# VITE_API_URL = 'https://tapi.cashier.sxczgkj.cn'
|
||||
|
||||
# 线上正式
|
||||
# VITE_API_URL = 'https://cashier.sxczgkj.com'
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# 线上环境
|
||||
ENV = production
|
||||
|
||||
# 正式ws
|
||||
VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
|
||||
|
||||
# 正式 php
|
||||
VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
|
||||
|
||||
# 正式 php 开票
|
||||
VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||
|
||||
# 线上环境接口地址
|
||||
VITE_API_URL = 'https://cashier.sxczgkj.com/'
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# 测试环境
|
||||
ENV = test
|
||||
|
||||
# 测试ws
|
||||
VITE_API_WSS = 'ws://192.168.1.42:2348'
|
||||
|
||||
# 测试ws
|
||||
# VITE_API_WSS = 'wss://sockets.sxczgkj.com/wss'
|
||||
|
||||
# 正式ws
|
||||
# VITE_API_WSS = 'wss://czgeatws.sxczgkj.com/wss'
|
||||
|
||||
# 正式 php
|
||||
VITE_API_PHP_URL = 'https://newblockwlx.sxczgkj.cn/index.php/api'
|
||||
|
||||
# 测试 php 开票
|
||||
# VITE_API_KP_URL = 'http://192.168.1.13:8888/api'
|
||||
|
||||
# 正式 php 开票
|
||||
VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||
|
||||
# 测试Java
|
||||
# VITE_API_URL = 'https://fv901fw8033.vicp.fun/'
|
||||
|
||||
# 正式Java
|
||||
# VITE_API_URL = 'https://cashier.sxczgkj.com/'
|
||||
|
||||
# 本地调试连接
|
||||
VITE_API_URL = 'http://192.168.1.42/'
|
||||
|
|
@ -8,6 +8,8 @@ pnpm-debug.log*
|
|||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
release
|
||||
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
# Vue 3 + Vite
|
||||
|
||||
npm install
|
||||
|
||||
npm install @element-plus/icons-vue
|
||||
|
||||
npm run dev
|
||||
|
||||
npm run build
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
//npm run build打包前执行此段代码
|
||||
const fs = require('fs')
|
||||
|
||||
//返回package的json数据
|
||||
function getPackageJson() {
|
||||
let data = fs.readFileSync('./package.json');//fs读取文件
|
||||
return JSON.parse(data);//转换为json对象
|
||||
}
|
||||
|
||||
let packageData = getPackageJson();//获取package的json
|
||||
let arr = packageData.version.split('.');//切割后的版本号数组
|
||||
arr[2] = parseInt(arr[2]) + 1;
|
||||
packageData.version = arr.join('.');//转换为以"."分割的字符串
|
||||
//用packageData覆盖package.json内容
|
||||
fs.writeFile(
|
||||
'./package.json',
|
||||
JSON.stringify(packageData, null, "\t"
|
||||
),
|
||||
(err) => { }
|
||||
);
|
||||
281
electron/main.js
|
|
@ -1,14 +1,21 @@
|
|||
import path from "path";
|
||||
import { app, BrowserWindow, ipcMain } from "electron";
|
||||
|
||||
import axios from "axios";
|
||||
import os from "os";
|
||||
import fs from "fs";
|
||||
import { exec } from "child_process";
|
||||
|
||||
let win;
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow({
|
||||
title: "Main window",
|
||||
width: 1200,
|
||||
height: 800,
|
||||
win = new BrowserWindow({
|
||||
title: "银收客",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
fullscreenable: true,
|
||||
fullscreen: false,
|
||||
fullscreen: process.env.VITE_DEV_SERVER_URL ? false : true,
|
||||
simpleFullscreen: true,
|
||||
frame: true,
|
||||
frame: process.env.VITE_DEV_SERVER_URL ? true : false,
|
||||
webPreferences: {
|
||||
// 集成网页和 Node.js,也就是在渲染进程中,可以调用 Node.js 方法
|
||||
nodeIntegration: true,
|
||||
|
|
@ -19,23 +26,273 @@ app.whenReady().then(() => {
|
|||
// You can use `process.env.VITE_DEV_SERVER_URL` when the vite command is called `serve`
|
||||
if (process.env.VITE_DEV_SERVER_URL) {
|
||||
win.loadURL(process.env.VITE_DEV_SERVER_URL);
|
||||
// 使用vite开发服务的url路径访问应用
|
||||
// win.webContents.openDevTools();
|
||||
} else {
|
||||
// Load your file
|
||||
win.loadFile("dist/index.html");
|
||||
win.loadFile(path.resolve(__dirname, "../dist/index.html")); // 打包后使用文件路径访问应用
|
||||
}
|
||||
win.webContents.openDevTools();
|
||||
|
||||
// 安装最新版本的exe文件
|
||||
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 系统内, 如果没有已开启的应用窗口
|
||||
// 点击托盘图标时通常会重新创建一个新窗口
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on("quitHandler", (_, msg) => {
|
||||
console.log(msg);
|
||||
app.quit();
|
||||
win = null;
|
||||
app.exit();
|
||||
});
|
||||
|
||||
// 给渲染进程返回打印机列表
|
||||
ipcMain.on("getPrintList", () => {
|
||||
win.webContents.getPrintersAsync().then((res) => {
|
||||
// console.log("打印机列表", res);
|
||||
win.webContents.send("printList", res);
|
||||
});
|
||||
});
|
||||
|
||||
// 获取本机mac
|
||||
ipcMain.on("getOSmacSync", () => {
|
||||
let mac = "";
|
||||
if (os.networkInterfaces().WLAN) {
|
||||
mac = os.networkInterfaces().WLAN[0].mac;
|
||||
console.log("wlan.mac===", mac);
|
||||
} else {
|
||||
mac = os.networkInterfaces()["以太网"][0].mac;
|
||||
console.log("以太网.mac===", mac);
|
||||
}
|
||||
win.webContents.send("getOSmacRes", mac);
|
||||
});
|
||||
|
||||
// 创建打印小票子窗口
|
||||
// const printWin = new BrowserWindow({
|
||||
// show: false,
|
||||
// width: 464,
|
||||
// height: 1726,
|
||||
// webPreferences: {
|
||||
// // 集成网页和 Node.js,也就是在渲染进程中,可以调用 Node.js 方法
|
||||
// nodeIntegration: true,
|
||||
// contextIsolation: false,
|
||||
// },
|
||||
// });
|
||||
|
||||
// if (process.env.VITE_DEV_SERVER_URL) {
|
||||
// // 加载打印的html文件
|
||||
// printWin.loadFile(path.join(__dirname, "../public/print.html"));
|
||||
// } else {
|
||||
// printWin.loadFile(path.resolve(__dirname, "../dist/print.html")); // 打包后使用文件路径访问应用
|
||||
// }
|
||||
|
||||
// // 接收订单页面发过来的参数发送给打印页
|
||||
// ipcMain.on("printerInfoSync", (event, arg) => {
|
||||
// printWin.webContents.send("getParams", arg);
|
||||
// });
|
||||
|
||||
// // 执行打印操作
|
||||
// ipcMain.on("printStart", (event, arg) => {
|
||||
// console.log(arg);
|
||||
// const _parmas = JSON.parse(arg);
|
||||
// // console.log(_parmas)
|
||||
// let name = _parmas.deviceName;
|
||||
// printWin.webContents.print({
|
||||
// silent: true,
|
||||
// deviceName: name,
|
||||
// pageSize: {
|
||||
// width: 58000,
|
||||
// height: 216000,
|
||||
// },
|
||||
// scaleFactor: 80,
|
||||
// landscape: false,
|
||||
// margins: {
|
||||
// marginType: "none",
|
||||
// top: 0,
|
||||
// bottom: 0,
|
||||
// left: 0,
|
||||
// right: 0,
|
||||
// },
|
||||
// dpi: {
|
||||
// horizontal: 203,
|
||||
// vertical: 203,
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// // 交班小票的窗口
|
||||
// const workPrintWin = new BrowserWindow({
|
||||
// show: false,
|
||||
// width: 464,
|
||||
// height: 1726,
|
||||
// webPreferences: {
|
||||
// nodeIntegration: true,
|
||||
// contextIsolation: false,
|
||||
// },
|
||||
// });
|
||||
|
||||
// if (process.env.VITE_DEV_SERVER_URL) {
|
||||
// // 加载打印的html文件
|
||||
// workPrintWin.loadFile(path.join(__dirname, "../public/work_print.html"));
|
||||
// } else {
|
||||
// workPrintWin.loadFile(path.resolve(__dirname, "../dist/work_print.html")); // 打包后使用文件路径访问应用
|
||||
// }
|
||||
|
||||
// // 接收渲染进程发送的数据
|
||||
// ipcMain.on("printerWorkSync", (event, arg) => {
|
||||
// workPrintWin.webContents.send("getParams", arg);
|
||||
// });
|
||||
|
||||
// // 执行交班小票的打印操作
|
||||
// ipcMain.on("printWorkStart", (event, arg) => {
|
||||
// // console.log(arg);
|
||||
// const _parmas = JSON.parse(arg);
|
||||
// // console.log(_parmas)
|
||||
// let name = _parmas.deviceName;
|
||||
// workPrintWin.webContents.print({
|
||||
// silent: true,
|
||||
// deviceName: name,
|
||||
// pageSize: {
|
||||
// width: 58000,
|
||||
// height: 216000,
|
||||
// },
|
||||
// scaleFactor: 80,
|
||||
// landscape: false,
|
||||
// margins: {
|
||||
// marginType: "none",
|
||||
// top: 0,
|
||||
// bottom: 0,
|
||||
// left: 0,
|
||||
// right: 0,
|
||||
// },
|
||||
// dpi: {
|
||||
// horizontal: 203,
|
||||
// vertical: 203,
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// 标签小票的窗口
|
||||
const tagPrintWin = new BrowserWindow({
|
||||
show: false,
|
||||
width: 360,
|
||||
height: 240,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
},
|
||||
});
|
||||
|
||||
if (process.env.VITE_DEV_SERVER_URL) {
|
||||
// 加载打印的html文件
|
||||
tagPrintWin.loadFile(path.join(__dirname, "../public/tag_print.html"));
|
||||
} else {
|
||||
tagPrintWin.loadFile(path.resolve(__dirname, "../dist/tag_print.html")); // 打包后使用文件路径访问应用
|
||||
}
|
||||
|
||||
// 接收渲染进程发送的数据
|
||||
ipcMain.on("printerTagSync", (event, arg) => {
|
||||
console.log(arg);
|
||||
tagPrintWin.webContents.send("getParams", arg);
|
||||
});
|
||||
|
||||
// 执行标签小票的打印操作
|
||||
ipcMain.on("printTagStart", (event, arg) => {
|
||||
// console.log(arg);
|
||||
const _parmas = JSON.parse(arg);
|
||||
// console.log(_parmas)
|
||||
let name = _parmas.deviceName;
|
||||
tagPrintWin.webContents.print({
|
||||
silent: true,
|
||||
deviceName: name,
|
||||
pageSize: {
|
||||
width: 45000,
|
||||
height: 30000,
|
||||
},
|
||||
scaleFactor: 80,
|
||||
landscape: false,
|
||||
margins: {
|
||||
marginType: "none",
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
},
|
||||
dpi: {
|
||||
horizontal: 203,
|
||||
vertical: 203,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
if (!gotTheLock) {
|
||||
app.quit();
|
||||
} else {
|
||||
app.on("second-instance", (event, commandLine, workingDirectory) => {
|
||||
// 当运行第二个实例时,将会聚焦到mainWindow这个窗口
|
||||
if (win) {
|
||||
if (win.isMinimized()) win.restore();
|
||||
win.focus();
|
||||
win.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 阻止默认关闭
|
||||
win.on("close", (e) => {
|
||||
e.preventDefault();
|
||||
win.webContents.send("showCloseDialog");
|
||||
});
|
||||
});
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") app.quit();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" id="html">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue</title>
|
||||
<meta http-equiv="Content-Security-Policy" />
|
||||
<title>银收客</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
|
|||
61
package.json
|
|
@ -1,23 +1,42 @@
|
|||
{
|
||||
"name": "vite-electron",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"version": "2.0.7",
|
||||
"main": "dist-electron/main.js",
|
||||
"scripts": {
|
||||
"dev": "chcp 65001 && vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"build": "node ./addVersion.js && vite build && electron-builder",
|
||||
"build:test": "vite build --mode test && electron-builder",
|
||||
"preview": "vite preview",
|
||||
"build:win": "node ./addVersion.js && vite build && electron-builder --w",
|
||||
"postinstall": "electron-builder install-app-deps"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.6.2",
|
||||
"bignumber.js": "^9.3.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"electron-pos-printer": "^1.3.6",
|
||||
"electron-pos-printer-vue": "^1.0.9",
|
||||
"element-plus": "^2.4.3",
|
||||
"js-md5": "^0.8.3",
|
||||
"lodash": "^4.17.21",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"qrcode": "^1.5.3",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"speak-tts": "^2.0.8",
|
||||
"swiper": "^11.1.1",
|
||||
"uuid": "^10.0.0",
|
||||
"vue": "^3.3.8",
|
||||
"vue-router": "^4.2.5"
|
||||
"vue-router": "^4.2.5",
|
||||
"ysk-utils": "^1.0.47"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.5.0",
|
||||
"electron": "^28.3.3",
|
||||
"electron-builder": "^24.13.3",
|
||||
"electron-rebuild": "^3.2.9",
|
||||
"path": "^0.12.7",
|
||||
"sass": "^1.69.5",
|
||||
"sass-loader": "^13.3.2",
|
||||
|
|
@ -25,5 +44,39 @@
|
|||
"vite": "^5.0.0",
|
||||
"vite-plugin-electron": "^0.15.4",
|
||||
"vite-plugin-electron-renderer": "^0.14.5"
|
||||
},
|
||||
"build": {
|
||||
"appId": "com.cashierdesktop.app",
|
||||
"productName": "银收客",
|
||||
"asar": true,
|
||||
"files": [
|
||||
"./dist/**/*",
|
||||
"./dist-electron/**/*"
|
||||
],
|
||||
"directories": {
|
||||
"buildResources": "build",
|
||||
"output": "release"
|
||||
},
|
||||
"win": {
|
||||
"icon": "./public/logo.ico",
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"arch": [
|
||||
"ia32"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
"allowElevation": true,
|
||||
"allowToChangeInstallationDirectory": true,
|
||||
"installerIcon": "./public/logo.ico",
|
||||
"uninstallerIcon": "./public/logo.ico",
|
||||
"installerHeaderIcon": "./public/logo.ico",
|
||||
"createDesktopShortcut": true,
|
||||
"createStartMenuShortcut": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
|
@ -0,0 +1,79 @@
|
|||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0 8mm;
|
||||
}
|
||||
|
||||
.print_view {
|
||||
padding: 20px 0;
|
||||
}
|
||||
.print_view .title {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.print_view .title.t1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
.print_view .title.t2 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.print_view .row {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.print_view .row.between {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.print_view .line {
|
||||
margin: 10px 0;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.print_view .table {
|
||||
width: 100%;
|
||||
}
|
||||
.print_view .table tr {
|
||||
width: 100%;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.print_view .table tr:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.print_view .table tr td {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
}
|
||||
.print_view .table tr td:nth-child(1) {
|
||||
-webkit-box-flex: 2;
|
||||
-ms-flex: 2;
|
||||
flex: 2;
|
||||
}
|
||||
.print_view .table tr td:not(:first-child) {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: end;
|
||||
-ms-flex-pack: end;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.print_view .table tr td .sku {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
<!--
|
||||
~ Copyright (c) 2023. Author Hubert Formin <2399270194@qq.com>
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Print preview</title>
|
||||
<link rel="stylesheet" href="./print.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="print_view">
|
||||
<div class="title t1">{{data.shop_name}}</div>
|
||||
<div class="title t2">
|
||||
结算单【{{data.orderInfo && data.orderInfo.masterId}}】
|
||||
</div>
|
||||
<div class="row">
|
||||
订单号:{{data.orderInfo && data.orderInfo.orderNo}}
|
||||
</div>
|
||||
<div class="row">交易时间:{{data.createdAt}}</div>
|
||||
<div class="row">收银员:【POS-1】1</div>
|
||||
<div class="line"></div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td>品名</td>
|
||||
<td>单价</td>
|
||||
<td>数量</td>
|
||||
<td>小计</td>
|
||||
</tr>
|
||||
<tr v-for="item in data.carts" :key="item.id">
|
||||
<td>
|
||||
<div>{{item.name}}</div>
|
||||
<div class="sku">{{item.skuName}}</div>
|
||||
</td>
|
||||
<td>{{item.salePrice}}</td>
|
||||
<td>{{item.number}}</td>
|
||||
<td>{{item.totalAmount}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="line"></div>
|
||||
<div class="row between">
|
||||
<span>合计:</span>
|
||||
<span>{{data.amount}}</span>
|
||||
</div>
|
||||
<!-- <div class="row between">
|
||||
<span>合计:</span>
|
||||
<span>30.00</span>
|
||||
</div> -->
|
||||
<div class="row between">
|
||||
<span>原价:{{data.amount}},节省了0</span>
|
||||
</div>
|
||||
<div class="row between">
|
||||
<span>积分:</span>
|
||||
<span>0</span>
|
||||
</div>
|
||||
<div class="row between">
|
||||
<span>余额:</span>
|
||||
<span>0.00</span>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row">备注:</div>
|
||||
<div class="row">打印时间:{{data.printTime}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module">
|
||||
const { ipcRenderer } = require("electron");
|
||||
import {
|
||||
createApp,
|
||||
ref,
|
||||
onMounted,
|
||||
} from "../node_modules/vue/dist/vue.esm-browser.js";
|
||||
|
||||
createApp({
|
||||
setup() {
|
||||
const data = ref({});
|
||||
|
||||
onMounted(() => {
|
||||
ipcRenderer.on("getParams", (event, arg) => {
|
||||
data.value = JSON.parse(arg);
|
||||
console.log(data.value);
|
||||
|
||||
setTimeout(() => {
|
||||
ipcRenderer.send(
|
||||
"printStart",
|
||||
JSON.stringify({ deviceName: data.value.deviceName })
|
||||
);
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
};
|
||||
},
|
||||
}).mount("#app");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
padding: 0 8mm;
|
||||
}
|
||||
.print_view {
|
||||
padding: 20px 0;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 4px;
|
||||
|
||||
&.t1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
&.t2 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
|
||||
&.between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 10px 0;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
|
||||
tr {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
td {
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
|
||||
&:nth-child(1) {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.sku {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.print_view {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-left: 12px;
|
||||
}
|
||||
.print_view .ewm {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 99;
|
||||
}
|
||||
.print_view .header {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
.print_view .header .logo {
|
||||
width: 90px;
|
||||
height: 30px;
|
||||
-o-object-fit: cover;
|
||||
object-fit: cover;
|
||||
}
|
||||
.print_view .header .title {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.print_view .number_wrap {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: end;
|
||||
-ms-flex-align: end;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.print_view .number_wrap .num {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.print_view .number_wrap .info {
|
||||
font-weight: bold;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.print_view .time {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
<!--
|
||||
~ Copyright (c) 2023. Author Hubert Formin <2399270194@qq.com>
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Print preview</title>
|
||||
<link rel="stylesheet" href="./tag_print.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="print_view">
|
||||
<div class="ewm" id="ewm"></div>
|
||||
<div class="header">
|
||||
<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> -->
|
||||
<div class="info" v-if="data.masterId">座位号:{{data.masterId}}</div>
|
||||
</div>
|
||||
<div class="shop_info">
|
||||
<div class="name">{{data.name}}</div>
|
||||
<div class="text" v-if="data.skuName">【{{data.skuName}}】</div>
|
||||
</div>
|
||||
<div class="time">{{data.createdAt}}</div>
|
||||
<div class="tips">建议尽快享用,风味更佳 {{ data.count }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="./qrcode.js"></script>
|
||||
<script type="module">
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
import {
|
||||
createApp,
|
||||
ref,
|
||||
onMounted,
|
||||
} from "../node_modules/vue/dist/vue.esm-browser.js";
|
||||
|
||||
createApp({
|
||||
setup() {
|
||||
const data = ref({});
|
||||
|
||||
onMounted(() => {
|
||||
ipcRenderer.on("getParams", (event, arg) => {
|
||||
data.value = JSON.parse(arg);
|
||||
// console.log(data.value);
|
||||
|
||||
let size = 46;
|
||||
let qrcode = new QRCode(document.getElementById("ewm"), {
|
||||
text: data.value.outNumber,
|
||||
width: size,
|
||||
height: size,
|
||||
correctLevel: QRCode.CorrectLevel.H,
|
||||
});
|
||||
|
||||
ipcRenderer.send(
|
||||
"printTagStart",
|
||||
JSON.stringify({ deviceName: data.value.deviceName })
|
||||
);
|
||||
|
||||
// setTimeout(() => {
|
||||
// ipcRenderer.send(
|
||||
// "printTagStart",
|
||||
// JSON.stringify({ deviceName: data.value.deviceName })
|
||||
// );
|
||||
// }, 100);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
};
|
||||
},
|
||||
}).mount("#app");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
color: #000;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
body {
|
||||
padding: 10px;
|
||||
}
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.print_view {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-left: 12px;
|
||||
.ewm {
|
||||
$size: 50px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 99;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.logo {
|
||||
$size: 90px;
|
||||
width: $size;
|
||||
height: 30px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.title {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
.number_wrap {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
.num {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.info {
|
||||
font-weight: bold;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
}
|
||||
.time {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
|
|
@ -0,0 +1,83 @@
|
|||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0 8mm;
|
||||
}
|
||||
|
||||
.empty {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.print_view {
|
||||
padding: 20px 0;
|
||||
}
|
||||
.print_view .title {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.print_view .title.t1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
.print_view .title.t2 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.print_view .row {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.print_view .row.between {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.print_view .line {
|
||||
margin: 10px 0;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.print_view .table {
|
||||
width: 100%;
|
||||
}
|
||||
.print_view .table tr {
|
||||
width: 100%;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.print_view .table tr:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.print_view .table tr td {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
}
|
||||
.print_view .table tr td:nth-child(1) {
|
||||
-webkit-box-flex: 2;
|
||||
-ms-flex: 2;
|
||||
flex: 2;
|
||||
}
|
||||
.print_view .table tr td:not(:first-child) {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: end;
|
||||
-ms-flex-pack: end;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.print_view .table tr td .sku {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
<!--
|
||||
~ Copyright (c) 2023. Author Hubert Formin <2399270194@qq.com>
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Print preview</title>
|
||||
<link rel="stylesheet" href="./work_print.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="print_view">
|
||||
<div class="title t1">{{data.merchantName}}</div>
|
||||
<div class="title t2">交班小票</div>
|
||||
<div class="row">交班时间:{{data.startTime}}</div>
|
||||
<div class="row">收银员:{{data.staff}}</div>
|
||||
<div class="row">当班收入:{{data.totalAmount}}</div>
|
||||
<div class="row" v-for="(item,index) in data.payInfos" :key="index">
|
||||
  {{item.payType }}:{{item.amount}}
|
||||
</div>
|
||||
<div class="row">会员数据</div>
|
||||
<div class="row" v-for="(item,index) in data.memberData" :key="index">
|
||||
  {{item.deposit }}:{{item.amount}}
|
||||
</div>
|
||||
<div class="row">分类数据</div>
|
||||
<div
|
||||
class="row"
|
||||
v-for="(item,index) in data.productCategories"
|
||||
:key="index"
|
||||
>
|
||||
  {{item.categoryName
|
||||
}} {{item.num}} {{item.amount}}
|
||||
</div>
|
||||
<div class="row">快捷收款金额:{{data.quickAmount}}</div>
|
||||
<div class="row">退款金额:{{data.returnAmount}}</div>
|
||||
<div class="row">总收入:{{data.totalAmount}}</div>
|
||||
<div class="row">备用金:{{data.imprest}}</div>
|
||||
<div class="row">应交金额:{{data.payable}}</div>
|
||||
<div class="row">上交金额:{{data.handIn}}</div>
|
||||
<div class="empty"></div>
|
||||
<div class="row">总订单数:{{data.orderNum}}</div>
|
||||
<div class="row">打印时间:{{data.printTime}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module">
|
||||
const { ipcRenderer } = require("electron");
|
||||
import {
|
||||
createApp,
|
||||
ref,
|
||||
onMounted,
|
||||
} from "../node_modules/vue/dist/vue.esm-browser.js";
|
||||
|
||||
createApp({
|
||||
setup() {
|
||||
const data = ref({});
|
||||
|
||||
onMounted(() => {
|
||||
ipcRenderer.on("getParams", (event, arg) => {
|
||||
data.value = JSON.parse(arg);
|
||||
console.log(data.value);
|
||||
|
||||
setTimeout(() => {
|
||||
ipcRenderer.send(
|
||||
"printWorkStart",
|
||||
JSON.stringify({ deviceName: data.value.deviceName })
|
||||
);
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
};
|
||||
},
|
||||
}).mount("#app");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
padding: 0 8mm;
|
||||
}
|
||||
.empty {
|
||||
height: 20px;
|
||||
}
|
||||
.print_view {
|
||||
padding: 20px 0;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 4px;
|
||||
|
||||
&.t1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
&.t2 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
|
||||
&.between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 10px 0;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
|
||||
tr {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
td {
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
|
||||
&:nth-child(1) {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.sku {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
331
src/App.vue
|
|
@ -1,19 +1,20 @@
|
|||
<template>
|
||||
<el-config-provider size="large">
|
||||
<div class="container">
|
||||
<div class="left" v-if="route.path !== 'login'">
|
||||
<left-menu />
|
||||
<div class="left" v-if="!hideLeftMenu">
|
||||
<left-menu ref="leftMenuRef" />
|
||||
</div>
|
||||
<div class="view">
|
||||
<router-view />
|
||||
<div :class="{ view: !hideLeftMenu }">
|
||||
<!-- <div class="wrapper">
|
||||
<div class="animation">
|
||||
<div class="animation"> -->
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition :name="transitionName">
|
||||
<!-- <transition :name="transitionName"> -->
|
||||
<keep-alive :include="includeList">
|
||||
<component :is="Component"></component>
|
||||
</transition>
|
||||
</keep-alive>
|
||||
<!-- </transition> -->
|
||||
</router-view>
|
||||
</div>
|
||||
<!-- </div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -21,12 +22,40 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import leftMenu from '@/components/leftMenu.vue'
|
||||
|
||||
import _ from 'lodash'
|
||||
import { ref, reactive, watch, onMounted } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { ref } from "vue";
|
||||
import leftMenu from "@/components/leftMenu.vue";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { scanSendMessage } from "@/api/order/index";
|
||||
import { useGlobal } from "@/store/global.js";
|
||||
import { useSocket } from "@/store/socket.js";
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
|
||||
const route = useRoute()
|
||||
const goodsStore = useGoods()
|
||||
const socket = useSocket();
|
||||
const global = useGlobal();
|
||||
const leftMenuRef = ref(null);
|
||||
const store = useUser();
|
||||
const route = useRoute();
|
||||
|
||||
const includeList = reactive([]);
|
||||
const hideLeftMenu = ref(false);
|
||||
watch(route, (to) => {
|
||||
// console.log(to);
|
||||
if (to.meta.keepAlive) {
|
||||
includeList.push(to.name);
|
||||
}
|
||||
// 需要全屏的路由
|
||||
let arr = ["/login", "/device_list", "/add_device", "/add_label", "/webview", '/workrecord'];
|
||||
if (arr.includes(to.path)) {
|
||||
hideLeftMenu.value = true;
|
||||
} else {
|
||||
hideLeftMenu.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
let transitionName = ref();
|
||||
let router = useRouter();
|
||||
|
|
@ -42,6 +71,129 @@ router.beforeEach((to, from) => {
|
|||
transitionName.value = "";
|
||||
}
|
||||
});
|
||||
|
||||
// 通过扫码枪获取条形码
|
||||
const nextCodeRef = ref("");
|
||||
const lastTimeRef = ref("");
|
||||
const codeRef = ref("");
|
||||
async function getBarCode(e) {
|
||||
let nextCode = "";
|
||||
let nextTime = "";
|
||||
const lastTime = lastTimeRef.value;
|
||||
let code = codeRef.value;
|
||||
if (window.event) {
|
||||
// IE
|
||||
nextCode = e.keyCode;
|
||||
} else if (e.which) {
|
||||
// Netscape/Firefox/Opera
|
||||
nextCode = e.which;
|
||||
}
|
||||
nextTime = new Date().getTime();
|
||||
// 字母上方 数字键0-9 对应键码值 48-57; 数字键盘 数字键0-9 对应键码值 96-105
|
||||
if (
|
||||
(nextCode >= 48 && nextCode <= 57) ||
|
||||
(nextCode >= 96 && nextCode <= 105)
|
||||
) {
|
||||
const codes = {
|
||||
48: 48,
|
||||
49: 49,
|
||||
50: 50,
|
||||
51: 51,
|
||||
52: 52,
|
||||
53: 53,
|
||||
54: 54,
|
||||
55: 55,
|
||||
56: 56,
|
||||
57: 57,
|
||||
96: 48,
|
||||
97: 49,
|
||||
98: 50,
|
||||
99: 51,
|
||||
100: 52,
|
||||
101: 53,
|
||||
102: 54,
|
||||
103: 55,
|
||||
104: 56,
|
||||
105: 57,
|
||||
};
|
||||
nextCode = codes[nextCode];
|
||||
nextTime = new Date().getTime();
|
||||
}
|
||||
// 第二次输入延迟两秒,删除之前的数据重新计算
|
||||
if (nextTime && lastTime && nextTime - lastTime > 2000) {
|
||||
code = String.fromCharCode(nextCode);
|
||||
} else {
|
||||
code += String.fromCharCode(nextCode);
|
||||
}
|
||||
|
||||
// 保存数据
|
||||
nextCodeRef.value = nextCode;
|
||||
lastTimeRef.value = nextTime;
|
||||
codeRef.value = code;
|
||||
// 键入Enter
|
||||
if (e.which === 13) {
|
||||
// 判断 code 长度(这里就获取到条码值了,以下业务自由发挥)
|
||||
code = code.trim();
|
||||
if (code.length == 13) {
|
||||
console.log("A类条码:" + code);
|
||||
} else if (code.length == 23) {
|
||||
console.log("B类条码:" + code);
|
||||
} else if (code.length == 0) {
|
||||
console.log("请输入条码");
|
||||
} else {
|
||||
console.log("条码不合法:" + code);
|
||||
try {
|
||||
if (!global.isCallNumber || !code.length) return;
|
||||
await scanSendMessage({
|
||||
outNumber: code,
|
||||
shopId: store.userInfo.shopId,
|
||||
});
|
||||
ElMessage.success("叫号成功");
|
||||
leftMenuRef.value.updateCallNumber();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('code', code);
|
||||
// 键入回车务必清空code值
|
||||
codeRef.value = "";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 全局监听叫号
|
||||
// document.addEventListener("keydown", (e) => {
|
||||
// getBarCode(e);
|
||||
// });
|
||||
|
||||
// 防止刷新页面长连接丢失
|
||||
if (store.userInfo && store.userInfo.id) {
|
||||
goodsStore.initGoods()
|
||||
store.getShopInfo()
|
||||
store.shopPagePermissionMineAjax()
|
||||
}
|
||||
|
||||
ipcRenderer.on('showCloseDialog', (event, arg) => {
|
||||
ElMessageBox.confirm("确定要关闭软件吗?")
|
||||
.then(() => {
|
||||
ipcRenderer.send("quitHandler", "退出吧");
|
||||
})
|
||||
.catch(() => { });
|
||||
})
|
||||
|
||||
|
||||
window.addEventListener('online', function () {
|
||||
console.log('有网络了');
|
||||
this.location.reload()
|
||||
})
|
||||
|
||||
window.addEventListener('offline', function () {
|
||||
ElMessage.warning('网络异常')
|
||||
socket.close()
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
@ -53,23 +205,149 @@ router.beforeEach((to, from) => {
|
|||
}
|
||||
|
||||
:root {
|
||||
--primary-color: #2FAFA2;
|
||||
--r: 24;
|
||||
--g: 124;
|
||||
--b: 170;
|
||||
--r-lighter: calc(var(--r) + (255 - var(--r)) * 0.2);
|
||||
--g-lighter: calc(var(--g) + (255 - var(--g)) * 0.2);
|
||||
--b-lighter: calc(var(--b) + (255 - var(--b)) * 0.2);
|
||||
|
||||
--r-lighter2: calc(var(--r) + (255 - var(--r)) * 0.5);
|
||||
--g-lighter2: calc(var(--g) + (255 - var(--g)) * 0.5);
|
||||
--b-lighter2: calc(var(--b) + (255 - var(--b)) * 0.5);
|
||||
|
||||
--r-lighter3: calc(var(--r) + (255 - var(--r)) * 0.9);
|
||||
--g-lighter3: calc(var(--g) + (255 - var(--g)) * 0.9);
|
||||
--b-lighter3: calc(var(--b) + (255 - var(--b)) * 0.9);
|
||||
|
||||
--r-darker: calc(var(--r) * 0.8);
|
||||
--g-darker: calc(var(--g) * 0.8);
|
||||
--b-darker: calc(var(--b) * 0.8);
|
||||
|
||||
--primary-color: rgb(var(--r), var(--g), var(--b));
|
||||
--primary-color-hover: rgb(var(--r-lighter3),
|
||||
var(--g-lighter3),
|
||||
var(--b-lighter3));
|
||||
--el-color-primary: var(--primary-color) !important;
|
||||
--el-button-hover-bg-color: var(--primary-color) !important;
|
||||
--el-color-primary-light-3: lighten(var(--primary-color), 20%) !important;
|
||||
--el-color-primary-dark-2: darken(var(--primary-color), 20%) !important;
|
||||
--el-color-primary-light-3: rgb(var(--r-lighter),
|
||||
var(--g-lighter),
|
||||
var(--b-lighter)) !important;
|
||||
--el-color-primary-dark-2: rgb(var(--r-darker),
|
||||
var(--g-darker),
|
||||
var(--b-darker)) !important;
|
||||
--el-color-primary-light-5: rgb(var(--r-lighter2),
|
||||
var(--g-lighter2),
|
||||
var(--b-lighter2)) !important;
|
||||
|
||||
--el-font-size-base: 16px !important;
|
||||
--el-message-close-size: var(--el-font-size-base) !important;
|
||||
--el-component-size-large: 40px !important;
|
||||
--el-mask-color: rgba(255, 255, 255, 0.6) !important;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "num";
|
||||
src: url("@/assets/font/Ignotum-Regular.ttf");
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: var(--el-font-size-base);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.el-divider__text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.el-dialog__headerbtn {
|
||||
top: 10px !important;
|
||||
}
|
||||
|
||||
.el-pagination {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.el-drawer__header {
|
||||
// padding: 0 !important;
|
||||
margin-bottom: 5px !important;
|
||||
}
|
||||
|
||||
.el-table .warning-row {
|
||||
--el-table-tr-bg-color: var(--el-color-warning-light-9);
|
||||
}
|
||||
|
||||
.el-table .success-row {
|
||||
--el-table-tr-bg-color: var(--el-color-success-light-9);
|
||||
}
|
||||
|
||||
.el-drawer__body {
|
||||
padding: 0 var(--el-drawer-padding-primary) !important;
|
||||
}
|
||||
|
||||
.el-textarea {
|
||||
font-size: var(--el-font-size-base) !important;
|
||||
}
|
||||
|
||||
.el-popover__title {
|
||||
font-size: var(--el-font-size-base) !important;
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
background-color: #555;
|
||||
margin-right: 0 !important;
|
||||
padding-bottom: 20px !important;
|
||||
border-radius: var(--el-dialog-border-radius) var(--el-dialog-border-radius) 0 0;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.el-button--large {
|
||||
--el-button-size: var(--el-component-size-large) !important;
|
||||
font-size: var(--el-font-size-base) !important;
|
||||
}
|
||||
|
||||
.el-input--large {
|
||||
font-size: var(--el-font-size-base) !important;
|
||||
}
|
||||
|
||||
.el-dialog {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: calc(var(--el-dialog-padding-primary) + 10px) var(--el-dialog-padding-primary);
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
padding: var(--el-dialog-padding-primary);
|
||||
padding-bottom: 10px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.el-input__suffix {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
|
||||
.empty {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
/*定义滚动条高宽及背景
|
||||
高宽分别对应横竖滚动条的尺寸*/
|
||||
::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
/*定义滚动条轨道
|
||||
内阴影+圆角*/
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: #F5F5F5;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/*定义滑块
|
||||
|
|
@ -79,6 +357,21 @@ router.beforeEach((to, from) => {
|
|||
background-color: #d3d3d3;
|
||||
}
|
||||
|
||||
.scroll-x {
|
||||
&::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.mt50 {
|
||||
margin-top: 50px;
|
||||
|
|
@ -90,7 +383,7 @@ router.beforeEach((to, from) => {
|
|||
.view {
|
||||
flex: 1;
|
||||
height: 100vh;
|
||||
padding: 20px;
|
||||
padding: var(--el-font-size-base);
|
||||
background-color: #efefef;
|
||||
}
|
||||
}
|
||||
|
|
@ -157,4 +450,8 @@ router.beforeEach((to, from) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.height_auto {
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,417 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 商户登录
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function login(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/auth/login",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function logout(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/auth/logout",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码获取
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function captcha(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/auth/captcha",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 店铺详情
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopInfo_detail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopInfo/detail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前店铺拓展通过key
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopExtendDetail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopExtend/detail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺用户列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopUserList(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopUser",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取台桌区域
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopArea(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopArea",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取台桌列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopTable(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopTable",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付方式列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getPayType(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/payType",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前登录员工信息
|
||||
*/
|
||||
export function shopStaffInfo() {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopStaff/info",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺用户充值记录
|
||||
*/
|
||||
export function shopUserChargeFlow(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopUser/flow",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺用户充值记录
|
||||
*/
|
||||
export function addShopUser(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/shopUser",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取叫号队列
|
||||
*/
|
||||
export function callTableQueue(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/callTable/queue",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取叫号配置
|
||||
*/
|
||||
export function callTableConfig(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/callTable/config",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改叫号配置
|
||||
*/
|
||||
export function callTableConfigPut(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/account/admin/callTable/config",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 叫号桌型新增
|
||||
*/
|
||||
export function addCallTable(data) {
|
||||
return request({
|
||||
method: data.id ? "put" : "post",
|
||||
url: "/account/admin/callTable",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 叫号桌型删除
|
||||
*/
|
||||
export function delCallTable(data) {
|
||||
return request({
|
||||
method: "delete",
|
||||
url: "/account/admin/callTable",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取桌型列表
|
||||
*/
|
||||
export function getCallTable(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/callTable",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增叫号号码
|
||||
*/
|
||||
export function takeNumber(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/callTable/takeNumber",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取桌型列表
|
||||
*/
|
||||
export function callRecord(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/callTable/callRecord",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行叫号
|
||||
*/
|
||||
export function callTableCall(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/callTable/call",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改叫号队列状态
|
||||
*/
|
||||
export function callTableCallState(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/account/admin/callTable/updateState",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收银机-交班数据统计
|
||||
*/
|
||||
export function handoverTotal(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/handoverRecord/total",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收银机-交班
|
||||
*/
|
||||
export function handover(isPrint) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/account/admin/handoverRecord/handover?isPrint=" + isPrint,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收银机-交班记录-详情
|
||||
*/
|
||||
export function handoverData(id) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/account/admin/handoverRecord/detail/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 交班记录-分页
|
||||
*/
|
||||
export function handoverRecordPage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/account/admin/handoverRecord/page`,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收银机-交班/关班-网络打印机打印交班小票
|
||||
*/
|
||||
export function handoverNetworkPrint(id) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: `/account/admin/handoverRecord/network/print/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印机列表
|
||||
*/
|
||||
export function printerList(subType = "") {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/printer",
|
||||
params: {
|
||||
name: "",
|
||||
subType: subType,
|
||||
connectionType: "USB",
|
||||
page: 1,
|
||||
size: 100,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印机详情
|
||||
*/
|
||||
export function printerDetail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/printer/detail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增打印机
|
||||
*/
|
||||
export function printerAdd(data, method = "post") {
|
||||
return request({
|
||||
method: method,
|
||||
url: "/account/admin/printer",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找优惠券 生成订单后使用
|
||||
*/
|
||||
export function findCoupon(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/market/admin/coupon/findCoupon",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 002-获取订单可用积分及抵扣金额(支付页面使用)
|
||||
*/
|
||||
export function calcUsablePoints(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/points/memberPoints/calcUsablePoints",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 003-根据积分计算可抵扣金额
|
||||
*/
|
||||
export function calcDeductionAmount(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/points/memberPoints/calcDeductionAmount",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺用户详情
|
||||
*/
|
||||
export function shopUserDetail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopUser/detail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前员工已拥有页面路径
|
||||
*/
|
||||
export function shopPagePermissionMine(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/account/admin/shopPagePermission/mine",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 台桌清台
|
||||
*/
|
||||
export function shopTableClear(data) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: "/account/admin/shopTable/clear",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 新增打印机
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function tbPrintMachinePost(data, method = "post") {
|
||||
return request({
|
||||
method: method,
|
||||
url: "tbPrintMachine",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询打印机
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function tbPrintMachineGet(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/tbPrintMachine",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过主键查询打印机
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function tbPrintMachineDetail(id) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/tbPrintMachine/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除打印机
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function tbPrintMachineDelete(params) {
|
||||
return request({
|
||||
method: "DELETE",
|
||||
url: "tbPrintMachine",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型查询打印机列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function bySubType(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/tbPrintMachine/bySubType",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品分类列表
|
||||
* @returns
|
||||
*/
|
||||
export function tbShopCategoryGet(params) {
|
||||
return request({
|
||||
url: `/product/queryAllCategory`,
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,244 @@
|
|||
import request from "@/utils/request.js";
|
||||
import request_php from "@/utils/request_php.js";
|
||||
|
||||
/**
|
||||
* 团购卷订单列表(分页)
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function groupOrderlist(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/groupOrder/list",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 团购卷核销前回显
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function groupOrderorderInfo(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/groupOrder/orderInfo",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 团购卷核销(仅核销待使用订单)
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function groupOrdergroupScan(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/groupOrder/groupScan",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 退单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function returnGpOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/pay/returnGpOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 注意 抖音核销使用的请求为PHP服务 request_php
|
||||
|
||||
/**
|
||||
* 会员签入
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function douyincheckIn(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "douyin/checkIn",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 团购核销准备
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function douyinfulfilmentcertificateprepare(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "douyin/fulfilmentcertificateprepare",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 团购核销
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function douyincertificateprepare(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "douyin/certificateprepare",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 团购核销记录
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function douyinorderlist(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "douyin/orderlist",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 团购核销撤销
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function douyinfulfilmentcertificatecancel(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "douyin/fulfilmentcertificatecancel",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 门店列表
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function douyinstorelist(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "douyin/storelist",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定门店
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function douyinbindstore(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "douyin/bindstore",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出团购
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function tglogout(data) {
|
||||
return request_php({
|
||||
method: "post",
|
||||
url: "user/logout",
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import request_kp from "@/utils/request_kp.js";
|
||||
|
||||
/**
|
||||
* 开票人列表
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function issuedby(data) {
|
||||
return request_kp({
|
||||
method: "post",
|
||||
url: "szzpy/syjissuedby",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商家通过收银机提交开票信息
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function carsubinvoicing(data) {
|
||||
return request_kp({
|
||||
method: "post",
|
||||
url: "store/carsubinvoicing",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印二维码
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function syjprintqrcode(data) {
|
||||
return request_kp({
|
||||
method: "post",
|
||||
url: "store/syjprintqrcode",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 智慧充值 配置信息获取
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function shopRecharge(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/market/admin/shopRecharge",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 查询店铺会员信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryMembermember(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "member/queryMember",
|
||||
params,
|
||||
});
|
||||
}
|
||||
export function createMembermember(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "member/createMember",
|
||||
data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 查询会员流水
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function memberqueryMemberAccount(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "member/queryMemberAccount",
|
||||
params,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 会员现金充值
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function accountPaymember(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "member/accountPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 会员扫码充值
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function membermemberScanPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "member/memberScanPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值退款
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function returnFlow(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "member/returnFlow",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 反扫
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function microPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/microPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 现金支付订单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function cashPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/cashPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单状态
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function queryOrderStatus(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/order/pay/queryOrderStatus`,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单列表
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function orderList(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/order/admin/order`,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增订单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function createOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/createOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 历史订单(多次下单使用)
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function historyOrder(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/admin/order/historyOrder",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单退款
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function refundOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/refundOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单详情
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function getOrderById(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/admin/order/getOrderByIdPrint",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值 - 现金充值
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function cashPayVip(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/cashPayVip",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值 - 反扫
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function microPayVip(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/microPayVip",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值 - 会员退款前置接口
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function refundVipBefore(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/refundVipBefore",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员充值 - 会员退款
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function refundVip(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/refundVip",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂账人 - 分页
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function buyerPage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/admin/order/credit/buyer/page",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂账人 - 付款
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function creditPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/creditPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂账人 - 会员支付订单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function vipPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/pay/vipPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单打印
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function orderPrint(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/print",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询会员充值支付状态
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function queryPayStatus(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/pay/queryPayStatus",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单转桌
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function mergeOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/mergeOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消订单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function cancelOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/cancelOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消某一次 下单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function rmPlaceOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/admin/order/rmPlaceOrder",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 获取订单列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function orderfindOrder(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "order/findOrder",
|
||||
params,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 订单详情
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function orderorderDetail(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "order/orderDetail",
|
||||
params,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 退单
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function payreturnOrder(data, pwd, isOnline) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: `pay/returnOrder?pwd=${pwd}&isOnline=${isOnline}`,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function cloudPrinterprint(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "cloudPrinter/print",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询快捷收银订单
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryQuickPay(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "pay/queryQuickPay",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 叫号
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function sendMessage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/sendMessage",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码叫号
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function scanSendMessage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/scanSendMessage",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取叫号记录
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getsendMessage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/getsendMessage",
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 查询分类信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryPayType(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "pay/queryPayType",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 付款
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function payOrder(api, data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: api,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码支付
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function scanpay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "pay/scanpay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 储值卡付款
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function accountPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "pay/accountPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 现金付款
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function cashPay(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "pay/cashPay",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单支付状态
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryOrder(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "pay/queryOrder",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function print(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "cloudPrinter/print",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 快捷收款
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function quickPay(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "pay/quickPay",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询快捷收银订单
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryQuickPayStatus(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "pay/queryQuickPayStatus",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员支付状态查询
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryScanPay(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "member/queryScanPay",
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 查询分类信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryCategory(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "product/queryCategory",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询商品信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function productqueryCommodityInfo(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "product/queryCommodityInfo",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询商品信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryNewCommodityInfo(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "product/queryNewCommodityInfo",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过选中的商品规格查询价格
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryProductSku(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "product/queryProductSku",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加购物车
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function createCart(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/createCart",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取购物车商品
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryCart(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "order/queryCart",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取取件码
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function createCode(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/createCode",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 全部打包
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function packall(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/packall",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除购物车
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function delCart(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/delCart",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂单/j激活购物车
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function cartStatus(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/cartStatus",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取挂起购物车列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getCartList(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/order/getCartList",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空购物车
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function clearCart(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/clearCart",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function createOrder(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/order/createOrder",
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 查询分类信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function categoryList(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/product/admin/prod/category/list",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询商品列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function productPage(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/product/admin/product/list",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品上下架
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function productOnOff(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/product/admin/product/onOff",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品售罄
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function markIsSoldOut(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/product/admin/product/markIsSoldOut",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 获取版本 pc:pc端 type 0 windows,1 安卓,2 iOS
|
||||
* @returns
|
||||
*/
|
||||
export function findVersion(source = "pc", type = 0) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/system/admin/version/${source}/${type}`,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 查询台桌分类
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryShopArea(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "shopInfo/queryShopArea",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询台桌信息
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function queryShopTable(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "shopInfo/queryShopTable",
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import request from "@/utils/request.js";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
export function login(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "login/login",
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import request from "@/utils/request.js";
|
||||
|
||||
/**
|
||||
* 当前用户交班详情
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopInfoqueryDuty(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "shopInfo/queryDuty",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 交班记录
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function shopinfoqueryDutyFlow(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "shopInfo/queryDutyFlow",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function loginlogout(params) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "login/logout",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取交班数据
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function handoverData(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/data/handoverData",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印交班数据
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function handoverprint(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "data/handoverprint",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
Before Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 170 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
After Width: | Height: | Size: 258 KiB |
|
|
@ -0,0 +1,14 @@
|
|||
<svg width="121" height="120" viewBox="0 0 121 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_5_38)">
|
||||
<circle cx="60.2939" cy="60" r="58.5" stroke="white" stroke-width="3"/>
|
||||
<circle cx="60.2938" cy="60" r="51.1997" stroke="white" stroke-width="2" stroke-dasharray="2 2"/>
|
||||
<line x1="19.8277" y1="50.637" x2="82.4435" y2="27.8676" stroke="white"/>
|
||||
<line x1="36.7388" y1="93.3029" x2="99.3547" y2="70.5335" stroke="white"/>
|
||||
<path d="M22.4599 62.0201C23.1265 62.5176 23.7976 63.0902 24.4821 63.7599L32.6011 60.8049L33.2304 62.3625L16.5189 68.445L18.5688 73.5186C20.4655 78.4692 21.3126 82.6787 21.0559 86.1414L19.2488 85.4463C19.4643 82.4581 18.6888 78.6819 16.8999 74.126L14.2207 67.4948L22.7005 64.4084C22.0609 63.8499 21.4032 63.3746 20.7815 62.9883L22.4599 62.0201ZM22.7471 66.8928L24.4471 66.6825C24.4958 67.3794 24.5266 68.0319 24.5574 68.6843L33.3529 65.483L33.9193 66.8849L24.56 70.2914C24.5039 71.9454 24.3398 73.4601 24.0676 74.8353L28.285 73.3004L27.1971 70.6078L28.8209 70.0168L29.9088 72.7093L34.938 70.8789L35.5224 72.3253L30.4932 74.1558L31.5001 76.648L38.2433 74.1937L38.8367 75.6623L32.0935 78.1167L33.514 81.6326L31.8902 82.2236L30.4697 78.7077L22.3282 81.671L21.7348 80.2023L29.8763 77.239L28.8694 74.7468L22.9606 76.8974L22.0649 75.6409C22.4993 74.2831 22.7672 72.7051 22.846 70.9153L19.4405 72.1547L18.8741 70.7528L22.8659 69.2999C22.8353 68.5198 22.7957 67.7175 22.7471 66.8928ZM35.6949 60.0106L41.8292 57.7779C41.8077 56.8924 41.7637 56.015 41.6655 55.1319L43.3928 54.7329C43.464 55.5493 43.5261 56.3435 43.5658 57.1459L55.1127 52.9431L55.742 54.5008L43.5862 58.9252C43.5249 61.1426 43.1977 63.2781 42.6272 65.3235L47.2034 76.65L45.6247 77.2246L41.8217 67.8118C41.3876 68.9143 40.9129 69.9804 40.3616 71.0489L38.8343 70.1499C40.6237 66.7675 41.6063 63.2448 41.8045 59.5736L36.3242 61.5683L35.6949 60.0106ZM45.8068 68.1992L52.3471 65.8187L51.511 63.7492C52.5088 62.5693 53.394 61.3027 54.1711 59.8967L45.6913 62.9831L45.089 61.4922L55.6436 57.6506L56.246 59.1415C55.4777 60.6974 54.5335 62.2662 53.4045 63.8258L53.9709 65.2277L59.609 63.1756L60.2294 64.711L54.5912 66.7631L56.2905 70.9688C56.8209 72.2817 56.414 73.1955 55.0834 73.6798L52.2644 74.7059L51.2245 73.3487C52.0454 73.0754 52.9114 72.7858 53.836 72.4492C54.5126 72.203 54.7296 71.7156 54.4599 71.048L52.9674 67.3541L46.4272 69.7346L45.8068 68.1992ZM57.6942 50.7528L76.9993 43.7263L77.6286 45.284L70.2313 47.9764C70.194 49.0365 70.08 50.099 69.8894 51.1638L70.303 52.1874C74.7565 52.9658 78.7948 54.125 82.4178 55.6651L81.8432 57.3802C78.698 55.8704 75.0971 54.7051 70.9862 53.8786L75.967 66.2065L74.2981 66.8139L69.1555 54.0855C68.0785 57.4384 66.217 60.7705 63.5756 64.0291L61.9582 63.0352C65.9314 58.2709 68.0832 53.4803 68.4271 48.6331L58.3236 52.3105L57.6942 50.7528ZM82.9851 41.1903L97.1482 36.0354L100.205 43.6012L94.1383 45.8093L95.6308 49.5032L103.073 46.7944L103.702 48.3521L96.2601 51.0609L98.1391 55.7116C99.4425 55.4159 100.989 54.955 102.749 54.3147C104.44 53.6991 105.843 53.1374 106.989 52.6438L107.185 54.4102C105.809 54.9109 104.56 55.3401 103.446 55.7201C99.3998 57.1671 96.5271 57.8043 94.796 57.6176C93.2813 57.4542 91.6187 56.6044 89.8622 55.0741C89.8232 57.5387 89.4373 59.7211 88.6821 61.6296L87.1322 60.7388C88.2721 57.6694 88.4342 54.0369 87.5961 49.8496L89.2916 49.5643C89.5381 50.8784 89.7124 52.1423 89.8056 53.3335C91.7197 55.0617 93.4544 55.9618 95.0413 56.0478C95.4336 56.0582 95.8709 56.0522 96.3669 55.9993L92.492 46.4085L86.0419 48.7561L82.9851 41.1903ZM97.9473 42.6873L96.1222 38.17L85.2293 42.1347L87.0544 46.652L97.9473 42.6873Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_5_38">
|
||||
<rect width="120" height="120" fill="white" transform="translate(0.293854)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
|
|
@ -0,0 +1,14 @@
|
|||
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2_36)">
|
||||
<circle cx="60" cy="60" r="58.5" stroke="white" stroke-width="3"/>
|
||||
<circle cx="60" cy="60" r="51.1997" stroke="white" stroke-width="2" stroke-dasharray="2 2"/>
|
||||
<line x1="19.5338" y1="50.637" x2="82.1497" y2="27.8676" stroke="white"/>
|
||||
<line x1="36.445" y1="93.3029" x2="99.0608" y2="70.5335" stroke="white"/>
|
||||
<path d="M57.134 66.8373L60.6344 75.5009L58.4994 76.278L57.912 74.8242L41.9748 80.6248L42.5622 82.0786L40.4272 82.8557L36.9269 74.1921L57.134 66.8373ZM41.2076 78.7259L57.1448 72.9253L55.7423 69.4539L39.8051 75.2546L41.2076 78.7259ZM32.5035 63.2439C31.9245 64.8841 31.2192 66.468 30.3698 68.0364L28.8571 66.1707C30.8456 62.2138 31.8241 58.3182 31.7745 54.5246L34.0473 54.1738C34.046 55.1952 34.0028 56.1979 33.8994 57.2225L41.3568 54.5083C40.4981 53.6637 39.6574 52.9487 38.7805 52.3149L40.8618 51.149C41.7145 51.8936 42.5852 52.7679 43.4617 53.7421L52.2121 50.5573L52.9313 52.3374L43.79 55.6646L44.6651 57.8305L52.4833 54.9849L53.1666 56.6761L45.3484 59.5217L46.1875 61.5986L54.0659 58.7311L54.7491 60.4223L46.8708 63.2898L47.7698 65.515L57.3923 62.0127L58.1235 63.8226L35.9919 71.8779L32.5035 63.2439ZM45.6348 66.2921L44.7358 64.0669L36.4364 67.0876L37.3355 69.3128L45.6348 66.2921ZM44.0525 62.3757L43.2134 60.2988L34.914 63.3195L35.7531 65.3964L44.0525 62.3757ZM42.5301 58.6076L41.655 56.4417L33.5661 59.3858C33.5239 59.5373 33.4997 59.6482 33.4875 59.7888L34.2307 61.6283L42.5301 58.6076ZM56.4839 47.471L62.7084 45.2054L62.121 43.7516L64.2259 42.9855L64.8133 44.4393L69.8952 42.5897L70.5185 44.1325L65.4367 45.9821L66.0001 47.3766L70.27 45.8225L70.8454 47.2466L59.6593 51.318L59.0839 49.8939L63.8951 48.1427L63.3317 46.7483L57.1072 49.0138L56.4839 47.471ZM65.8022 52.0091L62.7651 53.1145L63.0168 53.7375C63.1607 54.0936 63.2864 54.4902 63.3701 54.8682L66.4974 53.7299L65.8022 52.0091ZM68.1212 53.1389L70.7674 52.1758L70.0721 50.4549L67.426 51.4181L68.1212 53.1389ZM63.615 56.2425C63.7454 57.7605 63.5032 59.21 62.8703 60.6315L60.9416 59.8701C61.7612 58.1424 61.8294 56.3478 61.0923 54.438L60.3131 52.5095L71.379 48.4818L73.1171 52.784L63.615 56.2425ZM71.9233 40.6944L79.1401 38.0676L80.0991 40.4412C80.2669 40.8566 80.5433 41.0283 80.9342 40.886L83.1894 40.0652L83.8128 41.608L81.1065 42.593C79.9037 43.0308 79.0505 42.6266 78.559 41.4102L78.0795 40.2234L74.2306 41.6243C74.5542 42.4254 74.6495 43.1735 74.5766 43.8466C74.4254 44.5823 74.0097 45.3462 73.3114 46.1789L71.635 45.5299C72.189 44.6816 72.4844 43.9615 72.5694 43.318C72.5942 42.6964 72.3788 41.8218 71.9233 40.6944ZM83.3605 42.7936L83.84 43.9804C83.6458 45.5486 82.9887 47.081 81.8387 48.5886C83.4017 48.5302 85.2234 48.3436 87.3038 48.0288L87.0971 49.9078C84.4457 50.2603 82.2093 50.3595 80.358 50.2166C79.0219 51.5197 77.3552 52.7729 75.358 53.9763L73.9227 52.729C75.6071 51.7756 77.0149 50.8208 78.1882 49.8832C76.5055 49.4747 75.1958 48.7942 74.2712 47.8716L73.0984 48.2984L72.4751 46.7556L83.3605 42.7936ZM75.925 47.2696C76.6817 47.9471 77.9255 48.3793 79.6446 48.5363C80.7641 47.3802 81.5169 46.2553 81.8789 45.1026L75.925 47.2696ZM68.9973 59.4905C68.6716 60.3918 68.2738 61.2853 67.8219 62.1304L65.6343 61.6674C66.8993 59.5054 67.5631 57.392 67.6858 55.3053L69.8683 54.9874C69.8194 55.7199 69.7283 56.4337 69.6134 57.0882L83.8967 51.8895L84.6639 53.7883L77.0862 56.5464L78.177 59.2463L89.6338 55.0764L90.401 56.9753L78.9442 61.1452L80.3468 64.6166L87.2328 62.1103L86.2619 59.707L88.3668 58.9409L90.5605 64.3705L88.4556 65.1366L87.988 63.9795L71.9907 69.802L72.4582 70.9591L70.3533 71.7253L68.1836 66.355L70.2885 65.5889L71.2355 67.9328L78.2118 65.3937L76.8093 61.9223L64.4204 66.4315L63.6532 64.5326L76.0421 60.0234L74.9512 57.3235L68.9973 59.4905Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2_36">
|
||||
<rect width="120" height="120" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
|
|
@ -0,0 +1,14 @@
|
|||
<svg width="121" height="120" viewBox="0 0 121 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2_35)">
|
||||
<circle cx="60.2939" cy="60" r="58.5" stroke="white" stroke-width="3"/>
|
||||
<circle cx="60.2938" cy="60" r="51.1997" stroke="white" stroke-width="2" stroke-dasharray="2 2"/>
|
||||
<line x1="19.8277" y1="50.637" x2="82.4435" y2="27.8676" stroke="white"/>
|
||||
<line x1="36.7388" y1="93.3029" x2="99.3547" y2="70.5335" stroke="white"/>
|
||||
<path d="M26.044 58.3135L28.1301 57.5543L29.6698 61.365L39.3392 57.8456L40.1259 59.7927L30.4565 63.3121L32.4456 68.2354L43.6092 64.1722L44.3958 66.1193L35.0929 69.5053C38.3977 72.3226 42.9265 74.2477 48.6624 75.3187L47.9721 77.6119C41.831 76.0184 36.9817 73.5399 33.4578 70.1004L33.2323 70.1825L38.3569 82.8664L36.2708 83.6257L31.1462 70.9418L30.8925 71.0341C30.7058 76.3346 28.8006 81.3035 25.1994 85.9962L23.2907 84.5532C26.8122 80.4638 28.8237 76.1582 29.3138 71.6087L19.9826 75.005L19.196 73.0579L30.3595 68.9947L28.3703 64.0714L18.8982 67.5189L18.1116 65.5718L27.5837 62.1243L26.044 58.3135ZM44.9692 53.2121L66.9298 45.2191L67.7165 47.1662L63.0086 48.8797L65.9867 56.2508L72.1605 54.0037L72.936 55.923L66.7622 58.1701L71.7407 70.4923L69.6828 71.2414L64.7042 58.9191L56.5571 61.8844C57.4609 64.8417 57.8806 67.401 57.799 69.6003C57.6718 72.3267 56.6263 74.7811 54.6624 76.9636L52.8662 75.6392C54.6327 73.5285 55.5541 71.2469 55.6021 68.8046C55.5422 66.9758 55.1727 64.9407 54.4992 62.6334L47.9871 65.0036L47.2117 63.0843L53.8365 60.6731C53.6904 60.3115 53.5837 59.9675 53.4714 59.6893L50.8866 53.2917L45.7559 55.1592L44.9692 53.2121ZM52.9727 52.5324L55.5575 58.93C55.6923 59.2638 55.799 59.6079 55.9226 59.9138L63.9288 56.9998L60.9507 49.6287L52.9727 52.5324ZM100.444 51.1754L103.725 59.2975L101.724 60.026L101.173 58.6631L86.2321 64.1012L86.7828 65.4641L84.7812 66.1927L81.4997 58.0705L100.444 51.1754ZM85.5128 62.321L100.454 56.8829L99.1391 53.6285L84.198 59.0666L85.5128 62.321ZM77.3528 47.8066C76.8099 49.3442 76.1488 50.8292 75.3524 52.2996L73.9343 50.5504C75.7985 46.8408 76.7158 43.1887 76.6693 39.6322L78.8 39.3034C78.7989 40.261 78.7583 41.201 78.6614 42.1616L85.6527 39.6169C84.8477 38.8251 84.0595 38.1548 83.2374 37.5607L85.1887 36.4676C85.9881 37.1657 86.8043 37.9853 87.626 38.8987L95.8295 35.9128L96.5038 37.5818L87.9338 40.701L88.7542 42.7315L96.0838 40.0638L96.7244 41.6493L89.3948 44.317L90.1815 46.2641L97.5675 43.5758L98.208 45.1613L90.8221 47.8496L91.6649 49.9358L100.686 46.6524L101.371 48.3491L80.6231 55.9009L77.3528 47.8066ZM89.6634 50.6643L88.8205 48.5781L81.0399 51.41L81.8827 53.4962L89.6634 50.6643ZM88.1799 46.9926L87.3933 45.0455L79.6126 47.8774L80.3993 49.8245L88.1799 46.9926ZM86.7527 43.46L85.9323 41.4295L78.349 44.1896C78.3094 44.3317 78.2867 44.4356 78.2753 44.5674L78.972 46.292L86.7527 43.46Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2_35">
|
||||
<rect width="120" height="120" fill="white" transform="translate(0.293854)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
|
|
@ -0,0 +1,14 @@
|
|||
<svg width="121" height="121" viewBox="0 0 121 121" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2_37)">
|
||||
<circle cx="60.706" cy="60.1438" r="58.5" stroke="white" stroke-width="3"/>
|
||||
<circle cx="60.706" cy="60.1438" r="51.1997" stroke="white" stroke-width="2" stroke-dasharray="2 2"/>
|
||||
<line x1="20.2398" y1="50.7807" x2="82.8557" y2="28.0114" stroke="white"/>
|
||||
<line x1="37.151" y1="93.4466" x2="99.7668" y2="70.6773" stroke="white"/>
|
||||
<path d="M41.9891 67.1295L24.2853 73.5732L27.6006 81.7788C28.095 83.0027 29.0019 83.4064 30.2987 82.9344L44.4505 77.7836C45.127 77.5373 45.6234 77.1652 45.9114 76.6775C46.273 75.9717 45.9202 74.0581 44.8531 70.9368L47.0737 70.8305C48.1854 74.3822 48.5377 76.615 48.1534 77.5845C47.7692 78.3943 46.9625 79.0389 45.8009 79.5255L30.5215 85.0867C28.2381 85.9178 26.6385 85.16 25.7169 82.8791L19.8169 68.276L21.8466 67.5372L23.5099 71.6539L39.1557 65.9593L36.2226 58.6994L17.4193 65.5433L16.6326 63.5962L37.4938 56.0033L41.9891 67.1295ZM43.6958 53.746L68.7574 44.6243L69.5553 46.5992L57.3205 51.0523L59.0175 55.2525C63.2099 55.7047 67.5711 56.4146 72.101 57.3821L71.6081 59.6035C66.8697 58.5204 62.9482 57.7781 59.8716 57.3664L66.2549 73.1657L64.1969 73.9147L55.2626 51.8013L44.4937 55.7209L43.6958 53.746ZM86.686 38.737L95.7634 35.4331L99.6406 45.0294L90.5631 48.3333L86.686 38.737ZM96.9649 43.9294L94.5487 37.949L89.3334 39.8473L91.7496 45.8276L96.9649 43.9294ZM75.9761 40.4016L77.9495 39.6834L78.9609 42.1868L84.4581 40.1859C86.3629 44.9805 87.2273 47.9203 87.0456 49.0712C86.8357 50.2324 86.04 51.0644 84.6305 51.5774C84.1795 51.7416 83.6495 51.8707 83.0069 52.0408L81.769 50.4174L83.432 49.9717C84.4357 49.5745 84.9379 48.9769 84.9389 48.1789C84.8947 47.4292 84.3052 45.5699 83.1815 42.6288L79.5167 43.9626C80.5827 48.0415 80.0148 51.5983 77.8133 54.633L75.791 53.8695C77.823 51.2155 78.4015 48.1653 77.5434 44.6809L73.4557 46.1687L72.759 44.4441L76.9876 42.905L75.9761 40.4016ZM77.6697 56.9187L88.8896 52.835L87.9793 50.5819L90.009 49.8431L90.9193 52.0962L102.167 48.0022L102.932 49.8937L93.5441 53.3104C96.3883 54.8277 100.451 55.6783 105.709 55.8065L104.996 58.0441C99.2876 57.4416 94.9159 56.0655 91.8527 53.9261L91.6835 53.9876L95.1337 62.527L93.1039 63.2658L89.6538 54.7264L89.5128 54.7777C88.7079 58.708 86.3138 62.5466 82.3811 66.339L80.4836 64.9239C84.269 61.7275 86.7018 58.5448 87.7932 55.4036L78.4339 58.8101L77.6697 56.9187Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2_37">
|
||||
<rect width="120" height="120" fill="white" transform="translate(0.706001 0.143768)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
|
@ -0,0 +1,289 @@
|
|||
<!-- 取餐号组件 -->
|
||||
<template>
|
||||
<el-dialog :title="props.title" width="600" v-model="dialogVisible" @open="opne">
|
||||
<!-- <el-input v-model="number" :placeholder="props.placeholder" readonly></el-input> -->
|
||||
<!-- <el-input ref="inputRef" v-model="number" :placeholder="props.placeholder" :readonly="loading" clearable
|
||||
@change="inputChange"></el-input> -->
|
||||
<div class="tips">注意:请扫描标签二维码</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" disabled style="width: 100%;">.</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="list" v-loading="tableData.loading">
|
||||
<div class="item" v-for="item in tableData.list" :key="item.id">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<div class="title">取餐号:{{ filterCode(item.outCode) }}</div>
|
||||
<div class="shop">商品:{{ item.productName }}</div>
|
||||
</div>
|
||||
<div class="state s1" v-if="item.status == 0">
|
||||
<div class="dot"></div> 叫号成功
|
||||
</div>
|
||||
<div class="state s2" v-if="item.status == 1">
|
||||
<div class="dot"></div> 叫号失败
|
||||
</div>
|
||||
</div>
|
||||
<div class="btm">
|
||||
<div class="time">{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}</div>
|
||||
<div class="info" v-if="item.status == 1">
|
||||
{{ item.remark }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty description="暂无记录" :image-size="60" v-if="!tableData.list.length" />
|
||||
</div>
|
||||
<div class="page">
|
||||
<el-pagination v-model:current-page="tableData.page" v-model:page-size="tableData.pageSize" background
|
||||
layout="total, prev, pager, next" :total="tableData.total" @current-change="handleCurrentChange" />
|
||||
</div>
|
||||
<!-- <div class="footer">
|
||||
<el-button type="primary" style="width: 100%;" :loading="loading" @click="confirmHandle">确认</el-button>
|
||||
</div> -->
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import _ from "lodash";
|
||||
import dayjs from 'dayjs'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { scanSendMessage, getsendMessage } from '@/api/order/index'
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
const global = useGlobal()
|
||||
const store = useUser();
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '叫号取餐记录'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请扫描取餐号'
|
||||
}
|
||||
})
|
||||
|
||||
const inputRef = ref(null)
|
||||
const loading = ref(false)
|
||||
const dialogVisible = ref(false)
|
||||
const number = ref('')
|
||||
|
||||
const tableData = reactive({
|
||||
loading: false,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
list: []
|
||||
})
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
// 截取字符串
|
||||
function filterCode(t, c = '#') {
|
||||
let n = t.split(c)
|
||||
return n[1]
|
||||
}
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true
|
||||
getsendMessageAjax()
|
||||
// setTimeout(() => {
|
||||
// inputRef.value.focus();
|
||||
// }, 500);
|
||||
}
|
||||
|
||||
function opne() {
|
||||
number.value = ''
|
||||
global.updateData(true)
|
||||
}
|
||||
|
||||
// 输入
|
||||
function inputHandle(n) {
|
||||
number.value += n
|
||||
}
|
||||
|
||||
// 删除
|
||||
function delHandle() {
|
||||
if (!number.value) return
|
||||
number.value = number.value.substring(0, number.value.length - 1)
|
||||
}
|
||||
|
||||
const inputChange = _.debounce(function (e) {
|
||||
// console.log(e);
|
||||
confirmHandle();
|
||||
}, 100);
|
||||
|
||||
// 页码改变
|
||||
function handleCurrentChange() {
|
||||
getsendMessageAjax()
|
||||
}
|
||||
|
||||
// 获取叫号记录
|
||||
async function getsendMessageAjax() {
|
||||
try {
|
||||
if (!store.userInfo.shopId) return
|
||||
tableData.loading = true
|
||||
const res = await getsendMessage({
|
||||
page: tableData.page,
|
||||
pageSize: tableData.pageSize,
|
||||
shopId: store.userInfo.shopId,
|
||||
// shopId: 4,
|
||||
})
|
||||
tableData.loading = false
|
||||
tableData.list = res.list
|
||||
tableData.total = res.total
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
tableData.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
// 确认
|
||||
const confirmHandle = _.throttle(async function () {
|
||||
try {
|
||||
if (!number.value) return
|
||||
loading.value = true
|
||||
|
||||
const res = await scanSendMessage({
|
||||
outNumber: number.value,
|
||||
shopId: store.userInfo.shopId,
|
||||
// shopId: 4
|
||||
})
|
||||
ElMessage.success('叫号成功')
|
||||
|
||||
loading.value = false
|
||||
number.value = ''
|
||||
getsendMessageAjax()
|
||||
setTimeout(() => {
|
||||
inputRef.value.focus();
|
||||
}, 500);
|
||||
} catch (error) {
|
||||
getsendMessageAjax()
|
||||
loading.value = false
|
||||
number.value = ''
|
||||
console.log(error);
|
||||
setTimeout(() => {
|
||||
inputRef.value.focus();
|
||||
}, 500);
|
||||
}
|
||||
}, 800, { leading: true, trailing: false })
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
getsendMessageAjax
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.el-input__inner) {
|
||||
height: 60px;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.page {
|
||||
display: flex;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.tips {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.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: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
height: 200px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
overflow-y: auto;
|
||||
padding: 0 14px;
|
||||
|
||||
.item {
|
||||
padding: 16px 0;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.left {
|
||||
color: #000;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.shop {
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.dot {
|
||||
$size: 6px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
border-radius: 50%;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&.s1 {
|
||||
color: var(--primary-color);
|
||||
|
||||
.dot {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.s2 {
|
||||
color: var(--el-color-error);
|
||||
|
||||
.dot {
|
||||
background-color: var(--el-color-error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btm {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-top: 4px;
|
||||
|
||||
.time,
|
||||
.info {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
<template>
|
||||
<el-dialog title="选择分类" v-model="dialogVisible">
|
||||
<div class="list" v-loading="loading">
|
||||
<div class="row" v-for="(item, index) in categorys" :key="item.id">
|
||||
<div class="list_title">{{ item.name }}</div>
|
||||
<div class="item_wrap">
|
||||
<el-button :type="item.active ? 'primary' : ''" @click="selectHandle(item)">全部</el-button>
|
||||
<!-- <el-button :type="val.active ? 'primary' : ''" v-for="val in item.childrenList" :key="val.id"
|
||||
@click="selectHandle(val, index)">{{ val.name }}</el-button> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer" style="display: flex; justify-content: flex-end">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmitHandle">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
|
||||
const store = useUser();
|
||||
const emit = defineEmits(["success"]);
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const categorys = ref([]);
|
||||
|
||||
// 确定
|
||||
function onSubmitHandle() {
|
||||
let categorysArr = [];
|
||||
for (let item of categorys.value) {
|
||||
if (item.active) {
|
||||
categorysArr.push({
|
||||
name: `${item.name}`,
|
||||
id: item.id,
|
||||
});
|
||||
}
|
||||
// if (item.childrenList.length) {
|
||||
// for (let val of item.childrenList) {
|
||||
// if (val.active) {
|
||||
// categorysArr.push({
|
||||
// name: `${val.name}`,
|
||||
// id: val.id,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
emit("success", categorysArr);
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
|
||||
// 选择分类
|
||||
function selectHandle(item, index = -1) {
|
||||
// if (index != -1) {
|
||||
// categorys.value[index].active = false;
|
||||
// } else {
|
||||
// item.childrenList.map((item) => {
|
||||
// item.active = false;
|
||||
// });
|
||||
// }
|
||||
item.active = !item.active;
|
||||
}
|
||||
|
||||
// 获取分类
|
||||
async function tbShopCategoryGetAjax() {
|
||||
try {
|
||||
// loading.value = true;
|
||||
// const res = await categoryList();
|
||||
// res.list.map((item) => {
|
||||
// item.active = false;
|
||||
// item.childrenList.map((item) => {
|
||||
// item.active = false;
|
||||
// });
|
||||
// });
|
||||
categorys.value = goodsStore.originCategoryList.map(item => {
|
||||
item.active = false
|
||||
return item
|
||||
});
|
||||
// setTimeout(() => {
|
||||
// loading.value = false;
|
||||
// }, 300);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true;
|
||||
tbShopCategoryGetAjax();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
tbShopCategoryGetAjax();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list {
|
||||
min-height: 200px;
|
||||
|
||||
.row {
|
||||
padding-bottom: 20px;
|
||||
|
||||
.list_title {
|
||||
color: #999;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.item_wrap {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
<template>
|
||||
<div class='keyboard' @click.stop='_handleKeyPress'>
|
||||
<div class='key-row'>
|
||||
<div class='key-cell cell_b' data-num='7'>7</div>
|
||||
<div class='key-cell cell_b' data-num='8'>8</div>
|
||||
<div class='key-cell cell_b' data-num='9'>9</div>
|
||||
<div class='key-cell cell_b' data-num='-1'></div>
|
||||
</div>
|
||||
<div class='key-row'>
|
||||
<div class='key-cell cell_b' data-num='4'>4</div>
|
||||
<div class='key-cell cell_b' data-num='5'>5</div>
|
||||
<div class='key-cell cell_b' data-num='6'>6</div>
|
||||
<div class='key-cell cell_b' data-num='-1'></div>
|
||||
</div>
|
||||
<div class='key-row'>
|
||||
<div class='key-cell cell_b' data-num='1'>1</div>
|
||||
<div class='key-cell cell_b' data-num='2'>2</div>
|
||||
<div class='key-cell cell_b' data-num='3'>3</div>
|
||||
<div class='key-cell cell_b' data-num='-1'></div>
|
||||
</div>
|
||||
<div class="key-zero-and-point">
|
||||
<div class="a cell_b zero" data-num='0'>0</div>
|
||||
<div class="a cell_b point" data-num='.'>.</div>
|
||||
</div>
|
||||
|
||||
<div @touchstart="touchstart" @touchend="touchend" data-num='D' class="key-confirm2">
|
||||
<text data-num='D'>C</text>
|
||||
</div>
|
||||
|
||||
<div class='key-confirm' :style="{ 'background': btnColor }" data-num='S'>
|
||||
<div data-num='S' class="">
|
||||
<div data-num='S' class="title">{{ title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, reactive } from 'vue'
|
||||
import { dayjs } from 'element-plus'
|
||||
const props = defineProps({
|
||||
title: {
|
||||
default: '确认',
|
||||
type: String
|
||||
},
|
||||
btnColor: {
|
||||
default: 'green',
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(["consumeFee", "confirmEvent"])
|
||||
const this_money = reactive({
|
||||
money: '',
|
||||
Cdel: '',
|
||||
Time: ''
|
||||
})
|
||||
|
||||
watch(() => this_money.money, (newval, oldval) => {
|
||||
emit('consumeFee', newval)
|
||||
|
||||
});
|
||||
const touchstart = () => {
|
||||
this_money.Time = setInterval(() => {
|
||||
console.log(this_money.money);
|
||||
if (this_money.money == '') {
|
||||
clearInterval();
|
||||
}
|
||||
this_money.money = this_money.money.substring(0, this_money.money.length - 1);
|
||||
}, 200)
|
||||
}
|
||||
const touchend = () => {
|
||||
clearInterval(this_money.Time);
|
||||
}
|
||||
//处理按键
|
||||
const _handleKeyPress = (e) => {
|
||||
let num = e.target.dataset.num;
|
||||
//不同按键处理逻辑
|
||||
// -1 代表无效按键,直接返回
|
||||
if (num == -1) return false;
|
||||
switch (String(num)) {
|
||||
//小数点
|
||||
case '.':
|
||||
_handleDecimalPoint();
|
||||
break;
|
||||
//删除键
|
||||
case 'D':
|
||||
_handleDeleteKey();
|
||||
break;
|
||||
//清空键
|
||||
case 'C':
|
||||
_handleClearKey();
|
||||
break;
|
||||
//确认键
|
||||
case 'S':
|
||||
_handleConfirmKey();
|
||||
break;
|
||||
default:
|
||||
_handleNumberKey(num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//处理小数点函数
|
||||
const _handleDecimalPoint = () => {
|
||||
//如果包含小数点,直接返回
|
||||
if (this_money.money.indexOf('.') > -1) return false;
|
||||
//如果小数点是第一位,补0
|
||||
if (!this_money.money.length)
|
||||
this_money.money = '0.';
|
||||
//如果不是,添加一个小数点
|
||||
else
|
||||
this_money.money = this_money.money + '.';
|
||||
}
|
||||
//处理删除键
|
||||
const _handleDeleteKey = () => {
|
||||
let S = this_money.money;
|
||||
//如果没有输入,直接返回
|
||||
if (!S.length) return false;
|
||||
//否则删除最后一个
|
||||
this_money.money = S.substring(0, S.length - 1);
|
||||
}
|
||||
|
||||
//处理清空键
|
||||
const _handleClearKey = () => {
|
||||
this_money.money = '';
|
||||
}
|
||||
|
||||
//处理数字
|
||||
const _handleNumberKey = (num) => {
|
||||
if (this_money.money.length == 10) {
|
||||
return
|
||||
}
|
||||
let S = this_money.money;
|
||||
//如果有小数点且小数点位数不小于2
|
||||
if (S.indexOf('.') > -1 && S.substring(S.indexOf('.') + 1).length < 2)
|
||||
this_money.money = S + num;
|
||||
//没有小数点
|
||||
if (!(S.indexOf('.') > -1)) {
|
||||
//如果第一位是0,只能输入小数点
|
||||
if (num == 0 && S.length == 0)
|
||||
this_money.money = '0.';
|
||||
else {
|
||||
if (S.length && Number(S.charAt(0)) === 0) return;
|
||||
this_money.money = S + num;
|
||||
}
|
||||
}
|
||||
}
|
||||
//提交
|
||||
const _handleConfirmKey = () => {
|
||||
let S = this_money.money;
|
||||
//未输入
|
||||
if (!S.length || S == 0) {
|
||||
uni.showToast({
|
||||
title: '请输入正确的数值',
|
||||
icon: 'none',
|
||||
duration: 1000
|
||||
});
|
||||
return false;
|
||||
}
|
||||
//将 8. 这种转换成 8.00
|
||||
if (S.indexOf('.') > -1 && S.indexOf('.') == (S.length - 1))
|
||||
S = Number(S.substring(0, S.length - 1)).toFixed(2);
|
||||
//保留两位
|
||||
S = Number(S).toFixed(2);
|
||||
emit('confirmEvent', S); //提交参数
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cell_b {
|
||||
border-right: 1px solid #d5d5d6;
|
||||
border-bottom: 1px solid #d5d5d6;
|
||||
}
|
||||
|
||||
.key-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.keyboard {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 40vh;
|
||||
width: 100%;
|
||||
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
.keyboard .key-row {
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
position: relative;
|
||||
height: 10vh;
|
||||
line-height: 10vh;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.keyboard .key-cell {
|
||||
flex: 1;
|
||||
-webkit-box-flex: 1;
|
||||
font-size: 60upx;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.keyboard .key-confirm {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
height: 30vh;
|
||||
width: 25%;
|
||||
line-height: 30vh;
|
||||
color: #FFFFFF;
|
||||
z-index: 5;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.keyboard .key-confirm2 {
|
||||
position: absolute;
|
||||
height: 10vh;
|
||||
width: 25%;
|
||||
line-height: 10vh;
|
||||
z-index: 9999;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.key-zero-and-point {
|
||||
display: flex;
|
||||
height: 10vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 75%;
|
||||
font-size: 60upx;
|
||||
|
||||
.zero {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 66.66%;
|
||||
font-size: 60upx;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.point {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 33.33%;
|
||||
font-size: 60upx;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.key-cell:active {
|
||||
color: white;
|
||||
background: black; //黑色
|
||||
opacity: 0.1; //这里重要,就是通过这个透明度来设置
|
||||
}
|
||||
|
||||
.a:active,
|
||||
.key-confirm2:active {
|
||||
color: white;
|
||||
background: black; //黑色
|
||||
opacity: 0.1; //这里重要,就是通过这个透明度来设置
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,502 @@
|
|||
<template>
|
||||
<div class="card">
|
||||
<div class="header">
|
||||
<div class="return" @click="returnHandle">
|
||||
<el-icon class="icon">
|
||||
<ArrowLeftBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="t1" v-if="props.type == 0">
|
||||
<span class="title">应收:¥</span>
|
||||
<span class="num">{{ money }}</span>
|
||||
</div>
|
||||
<div class="t1" v-else>
|
||||
<span class="title">会员:</span>
|
||||
<span class="num">
|
||||
{{ props.userInfo.id && props.userInfo.phone }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="t2">
|
||||
<span>已付:¥0.00</span>
|
||||
<span>优惠:¥0.00</span>
|
||||
</div>
|
||||
</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="icon">
|
||||
<el-image :src="item.icon" class="img"></el-image>
|
||||
</div>
|
||||
<span class="title">{{ item.payName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quick_charge">
|
||||
<div class="item" :class="{active:chargeActive == index }" v-for="(item,index) in chargeList" :key="item.id" @click="changeCharge(index,item)">
|
||||
<div class="row">
|
||||
<span class="icon">¥</span>
|
||||
<span class="num">{{ item.amount }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="t1">赠¥{{ item.rewardAmount }}</span>
|
||||
<span class="t1">送{{ item.rewardPoints }}积分</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="t2">送{{item.couponCount}}张券</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input_wrap">
|
||||
<div class="input" style="flex: 1">储值:¥{{ money }}</div>
|
||||
</div>
|
||||
<div class="blance">
|
||||
<!-- 可用余额:0.00 -->
|
||||
</div>
|
||||
<div class="keybord_wrap">
|
||||
<div class="left">
|
||||
<div class="item" v-for="item in 9" :key="item" @click="amountInput(`${item}`)">
|
||||
{{ item }}
|
||||
</div>
|
||||
<div class="item" @click="amountInput('.')">.</div>
|
||||
<div class="item" @click="amountInput('0')">0</div>
|
||||
<div class="item" @click="delHandle">
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pay_btn" v-loading="payLoading" @click="confirmOrder">
|
||||
<span>支</span>
|
||||
<span>付</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<scanModal ref="scanModalRef" fast :amount="money" :money="money" :selecttype="props.type"
|
||||
:orderId="props.userInfo.id" :chargeId="chargeId" @success="scanCodeSuccess" />
|
||||
<takeFoodCode ref="takeFoodCodeRef" title="支付密码" :type="2" input-type="password" placeholder="请输入支付密码"
|
||||
@success="passwordSuccess" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { shopRecharge } from '@/api/market.js'
|
||||
import { getPayType } from '@/api/account.js'
|
||||
import { cashPayVip } from "@/api/order.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";
|
||||
import { useUser } from '@/store/user.js'
|
||||
|
||||
const takeFoodCodeRef = ref(null);
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: [String, Number],
|
||||
default: 0, // 0 订单支付 1 会员充值 2 快捷收款
|
||||
},
|
||||
userInfo: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
});
|
||||
|
||||
const store = useUser();
|
||||
|
||||
const emit = defineEmits(["paySuccess", "close"]);
|
||||
|
||||
const money = ref("0");
|
||||
const scanModalRef = ref(null);
|
||||
|
||||
const payActive = ref(0);
|
||||
const payList = ref([]);
|
||||
const payLoading = ref(false);
|
||||
|
||||
function returnHandle() {
|
||||
emit("close");
|
||||
}
|
||||
|
||||
// 获得扫码值
|
||||
function scanCodeSuccess() {
|
||||
emit("paySuccess");
|
||||
}
|
||||
|
||||
// 切换支付类型
|
||||
function payTypeChange(index, item) {
|
||||
if (item.payType == "scanCode") {
|
||||
if (money.value > 0) {
|
||||
scanModalRef.value.show();
|
||||
} else {
|
||||
ElMessage.error("请输入金额");
|
||||
return;
|
||||
}
|
||||
}
|
||||
payActive.value = index;
|
||||
}
|
||||
|
||||
// 获取支付密码
|
||||
async function passwordSuccess(e = '') {
|
||||
try {
|
||||
payLoading.value = true;
|
||||
await cashPayVip({
|
||||
shopId: store.shopInfo.id,
|
||||
shopUserId: props.userInfo.id,
|
||||
amount: money.value,
|
||||
// pwd: e ? md5(e) : '',
|
||||
pwd: e,
|
||||
orderId: '',
|
||||
allPack: '',
|
||||
rechargeDetailId: chargeId.value
|
||||
});
|
||||
payLoading.value = false;
|
||||
ElMessage.success("充值成功");
|
||||
emit("paySuccess");
|
||||
} catch (error) {
|
||||
payLoading.value = false;
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 结算支付
|
||||
async function confirmOrder() {
|
||||
if (payLoading.value) return;
|
||||
try {
|
||||
if (payList.value[payActive.value].payType == "scanCode") {
|
||||
if (money.value <= 0) {
|
||||
ElMessage.error("请输入金额");
|
||||
return;
|
||||
}
|
||||
scanModalRef.value.show();
|
||||
} else {
|
||||
if (money.value <= 0) {
|
||||
ElMessage.error("请输入金额");
|
||||
return;
|
||||
}
|
||||
switch (payList.value[payActive.value].payType) {
|
||||
case "cash": //现金
|
||||
if (props.type == 0) {
|
||||
payLoading.value = true;
|
||||
await quickPay({
|
||||
amount: money.value,
|
||||
authCode: "",
|
||||
payType: payList.value[payActive.value].payType,
|
||||
});
|
||||
payLoading.value = false;
|
||||
ElMessage.success("支付成功");
|
||||
emit("paySuccess");
|
||||
} else {
|
||||
// 会员充值
|
||||
await store.getShopInfo()
|
||||
if (store.shopInfo.isMemberInPwd == 1) {
|
||||
takeFoodCodeRef.value.show();
|
||||
} else {
|
||||
passwordSuccess()
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
payLoading.value = false;
|
||||
scanModalRef.value.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 输入
|
||||
function amountInput(num) {
|
||||
money.value = clearNoNum({ value: (money.value += num) });
|
||||
chargeActive.value = null
|
||||
chargeId.value = ''
|
||||
}
|
||||
|
||||
// 删除
|
||||
function delHandle() {
|
||||
if (!money.value) return;
|
||||
chargeActive.value = null
|
||||
chargeId.value = ''
|
||||
money.value = money.value.substring(0, money.value.length - 1);
|
||||
if (!money.value) {
|
||||
money.value = "0";
|
||||
}
|
||||
}
|
||||
|
||||
// 获取支付方式
|
||||
async function queryPayTypeAjax() {
|
||||
try {
|
||||
const res = await getPayType();
|
||||
|
||||
const arr = [];
|
||||
res.map((item) => {
|
||||
if (item.payType == "cash" || item.payType == "scanCode") {
|
||||
arr.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
payList.value = arr;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
function reset() {
|
||||
money.value = 0;
|
||||
payActive.value = 0;
|
||||
chargeActive.value = null;
|
||||
}
|
||||
|
||||
// 获取智慧充值的配置信息
|
||||
const chargeActive = ref(null);
|
||||
const chargeList = ref([])
|
||||
const chargeId = ref('')
|
||||
|
||||
function changeCharge(index,item) {
|
||||
chargeActive.value = index
|
||||
chargeId.value = item.id
|
||||
money.value = ''
|
||||
money.value = clearNoNum({ value: (money.value += item.amount) })
|
||||
}
|
||||
|
||||
async function shopRechargeAjax() {
|
||||
try {
|
||||
const res = await shopRecharge()
|
||||
res.rechargeDetailList.map((item) => {
|
||||
item.couponCount = 0
|
||||
item.couponInfoList.map(val => {
|
||||
item.couponCount += val.num;
|
||||
})
|
||||
})
|
||||
|
||||
chargeList.value = res.rechargeDetailList
|
||||
|
||||
console.log(chargeList.value)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
defineExpose({ reset });
|
||||
|
||||
onMounted(() => {
|
||||
queryPayTypeAjax();
|
||||
shopRechargeAjax()
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.card {
|
||||
padding: var(--el-font-size-base);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding-bottom: var(--el-font-size-base);
|
||||
border-bottom: 1px solid #ececec;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.return {
|
||||
$size: 50px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20px;
|
||||
|
||||
.icon {
|
||||
color: #333;
|
||||
font-size: var(--el-font-size-base);
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
.t1 {
|
||||
display: flex;
|
||||
color: var(--el-color-danger);
|
||||
font-weight: bold;
|
||||
|
||||
.title {
|
||||
font-size: var(--el-font-size-base);
|
||||
position: relative;
|
||||
top: 14px;
|
||||
}
|
||||
|
||||
.num {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.t2 {
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
color: #999;
|
||||
padding-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.number_wrap {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
|
||||
.menus {
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
.item {
|
||||
height: 80px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #efefef;
|
||||
padding: 10px 0;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
$lineHeight: 4px;
|
||||
|
||||
&.active {
|
||||
&::after {
|
||||
content: "";
|
||||
width: 50%;
|
||||
height: $lineHeight;
|
||||
background-color: var(--primary-color);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 25%;
|
||||
border-radius: $lineHeight;
|
||||
}
|
||||
}
|
||||
|
||||
.img {
|
||||
$size: 40px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.quick_charge {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
overflow-x: auto;
|
||||
margin-top: var(--el-font-size-base);
|
||||
display: flex;
|
||||
|
||||
.item {
|
||||
$activeColor: #FF6300;
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
background-color: #F5F5F5;
|
||||
border-radius: 8px;
|
||||
padding: var(--el-font-size-base);
|
||||
margin-right: var(--el-font-size-base);
|
||||
border: 2px solid #F5F5F5;
|
||||
&.active {
|
||||
border-color: $activeColor;
|
||||
.row {
|
||||
.icon {
|
||||
color: $activeColor;
|
||||
}
|
||||
.num {
|
||||
color: $activeColor;
|
||||
}
|
||||
.t1 {
|
||||
color: $activeColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.icon {
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
.num {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.t2 {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input_wrap {
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
padding: var(--el-font-size-base) 0;
|
||||
|
||||
.input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--primary-color);
|
||||
font-size: calc(var(--el-font-size-base) + 6px);
|
||||
padding: 0 var(--el-font-size-base);
|
||||
}
|
||||
}
|
||||
|
||||
.blance {
|
||||
color: var(--el-color-danger);
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.keybord_wrap {
|
||||
display: flex;
|
||||
|
||||
.left {
|
||||
--item-height: calc((100vh - 440px) / 5);
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: var(--item-height) var(--item-height) var(--item-height) var(--item-height);
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
.item {
|
||||
background-color: #efefef;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
|
||||
&:active {
|
||||
background-color: #dbdbdb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pay_btn {
|
||||
flex: 0.3;
|
||||
border-radius: 6px;
|
||||
color: #fff;
|
||||
background-color: var(--el-color-warning);
|
||||
margin-left: var(--el-font-size-base);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,85 +1,185 @@
|
|||
<template>
|
||||
<div class="left_menu_wrap">
|
||||
<div class="item online">
|
||||
<div class="top_item_wra">
|
||||
<div class="item first" :class="{ online: socketStore.online }" @click="connectWsHandle">
|
||||
<el-icon class="icon">
|
||||
<Monitor />
|
||||
</el-icon>
|
||||
<el-text type="success">在线</el-text>
|
||||
<el-text :type="socketStore.online ? 'success' : 'danger'">
|
||||
{{ socketStore.online ? '在线' : '离线' }}
|
||||
</el-text>
|
||||
</div>
|
||||
<router-link class="item" :class="{ active: route.path == item.path }" v-for="item in menus" :key="item.path"
|
||||
:to="item.path">
|
||||
<router-link class="item" :class="{ active: route.path == item.path }" v-for="item in store.menus"
|
||||
:key="item.path" :to="item.path">
|
||||
<el-icon class="icon">
|
||||
<component :is="item.icon" />
|
||||
</el-icon>
|
||||
<el-text class="text">{{ item.label }}</el-text>
|
||||
</router-link>
|
||||
<div class="item more">
|
||||
<div class="item" @click="workRef.show()">
|
||||
<el-icon class="icon">
|
||||
<component is="SwitchButton" />
|
||||
</el-icon>
|
||||
<el-text class="text">交班</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item" @click="moreref.show()">
|
||||
<el-icon class="icon">
|
||||
<Operation />
|
||||
</el-icon>
|
||||
<el-text class="text">更多</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 交班 -->
|
||||
<work ref="workRef" />
|
||||
<!-- 更多 -->
|
||||
<more ref="moreref" @openCall="openCall"></more>
|
||||
<!-- 叫号 -->
|
||||
<!-- <callNumber ref="callNumberRef" /> -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useSocket } from '@/store/socket.js'
|
||||
import { useUser } from '@/store/user.js'
|
||||
import more from '@/components/more.vue'
|
||||
import callNumber from './callNumber.vue'
|
||||
import work from '@/views/work/index.vue'
|
||||
|
||||
const socketStore = useSocket()
|
||||
const route = useRoute()
|
||||
console.log(route.path)
|
||||
const menus = ref([
|
||||
{
|
||||
label: '收银',
|
||||
path: '/',
|
||||
icon: 'ShoppingCartFull'
|
||||
},
|
||||
{
|
||||
label: '台桌',
|
||||
path: '/table',
|
||||
icon: 'Reading'
|
||||
},
|
||||
{
|
||||
label: '订单',
|
||||
path: '/order',
|
||||
icon: 'Tickets'
|
||||
},
|
||||
{
|
||||
label: '网络',
|
||||
path: '/internat',
|
||||
icon: 'Paperclip'
|
||||
},
|
||||
{
|
||||
label: '会员',
|
||||
path: '/user',
|
||||
icon: 'User'
|
||||
},
|
||||
{
|
||||
label: '交班',
|
||||
path: '/work',
|
||||
icon: 'SwitchButton'
|
||||
const moreref = ref(null)
|
||||
const callNumberRef = ref(null)
|
||||
const workRef = ref(null)
|
||||
const store = useUser()
|
||||
|
||||
// 更新叫号记录
|
||||
function updateCallNumber() {
|
||||
callNumberRef.value.getsendMessageAjax()
|
||||
}
|
||||
])
|
||||
|
||||
function openCall() {
|
||||
callNumberRef.value.show()
|
||||
}
|
||||
|
||||
// 手动重新连接ws
|
||||
function connectWsHandle() {
|
||||
location.reload()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
updateCallNumber
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.drawerbox {
|
||||
:deep(.el-drawer__body) {
|
||||
background: #1c1d1f !important;
|
||||
}
|
||||
|
||||
.drawerbox_box {
|
||||
color: #fff;
|
||||
|
||||
.drawerbox_bo_top {
|
||||
padding: 20px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ccc;
|
||||
|
||||
.drawerbox_bo_top_left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawerbox_bo_top_ring {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.drawerbox_bo_top_ring_tb {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 6px;
|
||||
padding: 6px 10px;
|
||||
|
||||
span {
|
||||
width: 80px;
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawerbox_bo_box {
|
||||
width: 100%;
|
||||
|
||||
.drawerbox_bo_box_itemb_felx {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
padding: 0 20px;
|
||||
|
||||
.drawerbox_bo_box_itembox:nth-child(1) {
|
||||
margin-left: 0px;
|
||||
|
||||
}
|
||||
|
||||
.drawerbox_bo_box_itembox {
|
||||
width: 20%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-left: 40px;
|
||||
|
||||
.drawerbox_bo_box_icon {
|
||||
border-radius: 6px;
|
||||
background: #2196f3;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.drawerbox_bo_box_icontext {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left_menu_wrap {
|
||||
height: 100vh;
|
||||
width: 120px;
|
||||
width: 60px;
|
||||
background-color: #555;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.top_item_wra {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
|
||||
&:first-child {
|
||||
border-bottom: 1px solid #666;
|
||||
}
|
||||
/* 去除下划线 */
|
||||
color: inherit;
|
||||
/* 继承父元素的颜色 */
|
||||
cursor: pointer;
|
||||
/* 修改鼠标指针样式 */
|
||||
border: none;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&.online {
|
||||
|
||||
|
|
@ -98,19 +198,15 @@ const menus = ref([
|
|||
}
|
||||
}
|
||||
|
||||
&.more {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: #999;
|
||||
font-size: 32px;
|
||||
font-size: 22px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: #999;
|
||||
font-size: 22px;
|
||||
font-size: var(--el-font-size-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,207 @@
|
|||
//==本JS是加载Lodop插件或Web打印服务CLodop/Lodop7的综合示例,可直接使用,建议理解后融入自己程序==
|
||||
|
||||
//用双端口加载主JS文件Lodop.js(或CLodopfuncs.js兼容老版本)以防其中某端口被占:
|
||||
var MainJS = "CLodopfuncs.js",
|
||||
URL_WS1 = "ws://localhost:8000/" + MainJS, //ws用8000/18000
|
||||
URL_WS2 = "ws://localhost:18000/" + MainJS,
|
||||
URL_HTTP1 = "http://localhost:8000/" + MainJS, //http用8000/18000
|
||||
URL_HTTP2 = "http://localhost:18000/" + MainJS,
|
||||
URL_HTTP3 = "https://localhost.lodop.net:8443/" + MainJS; //https用8000/8443
|
||||
|
||||
var CreatedOKLodopObject, CLodopIsLocal, LoadJsState;
|
||||
|
||||
//==判断是否需要CLodop(那些不支持插件的浏览器):==
|
||||
function needCLodop() {
|
||||
try {
|
||||
var ua = navigator.userAgent;
|
||||
if (ua.match(/Windows\sPhone/i) ||
|
||||
ua.match(/iPhone|iPod|iPad/i) ||
|
||||
ua.match(/Android/i) ||
|
||||
ua.match(/Edge\D?\d+/i))
|
||||
return true;
|
||||
var verTrident = ua.match(/Trident\D?\d+/i);
|
||||
var verIE = ua.match(/MSIE\D?\d+/i);
|
||||
var verOPR = ua.match(/OPR\D?\d+/i);
|
||||
var verFF = ua.match(/Firefox\D?\d+/i);
|
||||
var x64 = ua.match(/x64/i);
|
||||
if ((!verTrident) && (!verIE) && (x64)) return true;
|
||||
else if (verFF) {
|
||||
verFF = verFF[0].match(/\d+/);
|
||||
if ((verFF[0] >= 41) || (x64)) return true;
|
||||
} else if (verOPR) {
|
||||
verOPR = verOPR[0].match(/\d+/);
|
||||
if (verOPR[0] >= 32) return true;
|
||||
} else if ((!verTrident) && (!verIE)) {
|
||||
var verChrome = ua.match(/Chrome\D?\d+/i);
|
||||
if (verChrome) {
|
||||
verChrome = verChrome[0].match(/\d+/);
|
||||
if (verChrome[0] >= 41) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (err) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//==检查加载成功与否,如没成功则用http(s)再试==
|
||||
//==低版本CLODOP6.561/Lodop7.043及前)用本方法==
|
||||
function checkOrTryHttp() {
|
||||
if (window.getCLodop) {
|
||||
LoadJsState = "complete";
|
||||
return true;
|
||||
}
|
||||
if (LoadJsState == "loadingB" || LoadJsState == "complete") return;
|
||||
LoadJsState = "loadingB";
|
||||
var head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
|
||||
var JS1 = document.createElement("script"),
|
||||
JS2 = document.createElement("script"),
|
||||
JS3 = document.createElement("script");
|
||||
JS1.src = URL_HTTP1;
|
||||
JS2.src = URL_HTTP2;
|
||||
JS3.src = URL_HTTP3;
|
||||
JS1.onload = JS2.onload = JS3.onload = JS2.onerror = JS3.onerror = function () {
|
||||
LoadJsState = "complete";
|
||||
}
|
||||
JS1.onerror = function (e) {
|
||||
if (window.location.protocol !== 'https:')
|
||||
head.insertBefore(JS2, head.firstChild);
|
||||
else
|
||||
head.insertBefore(JS3, head.firstChild);
|
||||
}
|
||||
head.insertBefore(JS1, head.firstChild);
|
||||
}
|
||||
|
||||
//==加载Lodop对象的主过程:==
|
||||
(function loadCLodop() {
|
||||
if (!needCLodop()) return;
|
||||
CLodopIsLocal = !!((URL_WS1 + URL_WS2).match(/\/\/localho|\/\/127.0.0./i));
|
||||
LoadJsState = "loadingA";
|
||||
if (!window.WebSocket && window.MozWebSocket) window.WebSocket = window.MozWebSocket;
|
||||
//ws方式速度快(小于200ms)且可避免CORS错误,但要求Lodop版本足够新:
|
||||
try {
|
||||
var WSK1 = new WebSocket(URL_WS1);
|
||||
WSK1.onopen = function (e) {
|
||||
setTimeout(checkOrTryHttp(), 200);
|
||||
}
|
||||
WSK1.onmessage = function (e) {
|
||||
if (!window.getCLodop) eval(e.data);
|
||||
}
|
||||
WSK1.onerror = function (e) {
|
||||
var WSK2 = new WebSocket(URL_WS2);
|
||||
WSK2.onopen = function (e) {
|
||||
setTimeout(checkOrTryHttp(), 200);
|
||||
}
|
||||
WSK2.onmessage = function (e) {
|
||||
if (!window.getCLodop) eval(e.data);
|
||||
}
|
||||
WSK2.onerror = function (e) {
|
||||
checkOrTryHttp();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
checkOrTryHttp();
|
||||
}
|
||||
})();
|
||||
|
||||
//==获取LODOP对象主过程,判断是否安装、需否升级:==
|
||||
function getLodop(oOBJECT, oEMBED) {
|
||||
var strFontTag = "<br><font color='#FF00FF'>打印控件";
|
||||
var strLodopInstall = strFontTag + "未安装!点击这里<a href='https://h5-invoice.sxczgkj.cn/invo/czg.zip'>执行安装</a>";
|
||||
var strLodopUpdate = strFontTag + "需要升级!点击这里<a href='https://h5-invoice.sxczgkj.cn/invo/czg.zip'>执行升级</a>";
|
||||
var strLodop64Install = strFontTag + "未安装!点击这里<a href='https://h5-invoice.sxczgkj.cn/invo/czg.zip'>执行安装</a>";
|
||||
var strLodop64Update = strFontTag + "需要升级!点击这里<a href='https://h5-invoice.sxczgkj.cn/invo/czg.zip'>执行升级</a>";
|
||||
var strCLodopInstallA =
|
||||
"<br><font color='#FF00FF'>Web打印服务CLodop未安装启动,点击这里<a href='https://h5-invoice.sxczgkj.cn/invo/czg.zip'>下载执行安装</a>";
|
||||
// var strCLodopInstallB = "<br>(若此前已安装过,可<a href='CLodop.protocol:setup' target='_self'>点这里直接再次启动</a>)";
|
||||
var strCLodopUpdate =
|
||||
"<br><font color='#FF00FF'>Web打印服务CLodop需升级!点击这里<a href='https://h5-invoice.sxczgkj.cn/invo/czg.zip'>执行升级</a>";
|
||||
var strLodop7FontTag = "<br><font color='#FF00FF'>Web打印服务Lodop7";
|
||||
var strLodop7HrefX86 = "点击这里<a href='https://h5-invoice.sxczgkj.cn/invo/czg.zip' target='_self'>下载安装</a>(下载后解压,点击lodop文件开始执行)";
|
||||
var strLodop7HrefARM = "点击这里<a href='https://h5-invoice.sxczgkj.cn/invo/czg.zip'>下载安装</a>(下载后解压,点击lodop文件开始执行)";
|
||||
var strLodop7Install_X86 = strLodop7FontTag + "未安装启动," + strLodop7HrefX86;
|
||||
var strLodop7Install_ARM = strLodop7FontTag + "未安装启动," + strLodop7HrefARM;
|
||||
var strLodop7Update_X86 = strLodop7FontTag + "需升级," + strLodop7HrefX86;
|
||||
var strLodop7Update_ARM = strLodop7FontTag + "需升级," + strLodop7HrefARM;
|
||||
var strInstallOK = ",成功后请刷新本页面或重启浏览器。</font>";
|
||||
var LODOP;
|
||||
try {
|
||||
var isWinIE = (/MSIE/i.test(navigator.userAgent)) || (/Trident/i.test(navigator.userAgent));
|
||||
var isWinIE64 = isWinIE && (/x64/i.test(navigator.userAgent));
|
||||
var isLinuxX86 = (/Linux/i.test(navigator.platform)) && (/x86/i.test(navigator.platform));
|
||||
var isLinuxARM = (/Linux/i.test(navigator.platform)) && (/aarch/i.test(navigator.platform));
|
||||
|
||||
if (needCLodop() || isLinuxX86 || isLinuxARM) {
|
||||
try {
|
||||
LODOP = window.getCLodop();
|
||||
} catch (err) { }
|
||||
if (!LODOP && LoadJsState !== "complete") {
|
||||
if (!LoadJsState)
|
||||
alert("未曾加载Lodop主JS文件,请先调用loadCLodop过程.");
|
||||
else
|
||||
alert("网页还没下载完毕,请稍等一下再操作.");
|
||||
return;
|
||||
}
|
||||
var strAlertMessage;
|
||||
if (!LODOP) {
|
||||
if (isLinuxX86)
|
||||
strAlertMessage = strLodop7Install_X86;
|
||||
else if (isLinuxARM)
|
||||
strAlertMessage = strLodop7Install_ARM;
|
||||
else
|
||||
strAlertMessage = strCLodopInstallA + (CLodopIsLocal ? strCLodopInstallB : "");
|
||||
document.body.innerHTML = strAlertMessage + strInstallOK + document.body.innerHTML;
|
||||
return;
|
||||
} else {
|
||||
if (isLinuxX86 && LODOP.CVERSION < "7.0.7.5")
|
||||
strAlertMessage = strLodop7Update_X86;
|
||||
else if (isLinuxARM && LODOP.CVERSION < "7.0.7.5")
|
||||
strAlertMessage = strLodop7Update_ARM;
|
||||
else if (CLODOP.CVERSION < "6.5.9.4")
|
||||
strAlertMessage = strCLodopUpdate;
|
||||
|
||||
if (strAlertMessage)
|
||||
document.body.innerHTML = strAlertMessage + strInstallOK + document.body.innerHTML;
|
||||
}
|
||||
} else {
|
||||
//==如果页面有Lodop插件就直接使用,否则新建:==
|
||||
if (oOBJECT || oEMBED) {
|
||||
if (isWinIE)
|
||||
LODOP = oOBJECT;
|
||||
else
|
||||
LODOP = oEMBED;
|
||||
} else if (!CreatedOKLodopObject) {
|
||||
LODOP = document.createElement("object");
|
||||
LODOP.setAttribute("width", 0);
|
||||
LODOP.setAttribute("height", 0);
|
||||
LODOP.setAttribute("style", "position:absolute;left:0px;top:-100px;width:0px;height:0px;");
|
||||
if (isWinIE)
|
||||
LODOP.setAttribute("classid", "clsid:2105C259-1E0C-4534-8141-A753534CB4CA");
|
||||
else
|
||||
LODOP.setAttribute("type", "application/x-print-lodop");
|
||||
document.documentElement.appendChild(LODOP);
|
||||
CreatedOKLodopObject = LODOP;
|
||||
} else
|
||||
LODOP = CreatedOKLodopObject;
|
||||
//==Lodop插件未安装时提示下载地址:==
|
||||
if ((!LODOP) || (!LODOP.VERSION)) {
|
||||
document.body.innerHTML = (isWinIE64 ? strLodop64Install : strLodopInstall) + strInstallOK + document
|
||||
.body.innerHTML;
|
||||
return LODOP;
|
||||
}
|
||||
if (LODOP.VERSION < "6.2.2.6") {
|
||||
document.body.innerHTML = (isWinIE64 ? strLodop64Update : strLodopUpdate) + strInstallOK + document.body
|
||||
.innerHTML;
|
||||
}
|
||||
}
|
||||
//===如下空白位置适合调用统一功能(如注册语句、语言选择等):=======================
|
||||
// LODOP.SET_LICENSES("超掌柜独有!","DCFF409304DFCEB3E2C644BF96CD0720","","");
|
||||
//===============================================================================
|
||||
return LODOP;
|
||||
} catch (err) {
|
||||
alert("getLodop出错:" + err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default getLodop
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog v-model="centerDialogVisible" title="二维码" width="666" center>
|
||||
<div class="dialog-footer" style="text-align: center">
|
||||
<!-- <qrcode-vue :value="form.url" :size="200" /> -->
|
||||
<div class="qrcodefooter">{{ props.form.article }}</div>
|
||||
<div class="qrcodefooter">{{ props.form.type }}</div>
|
||||
<div class="qrcodefooter">
|
||||
<el-select v-model="rintermodel" placeholder="请选择打印机" @change="changerintermodel">
|
||||
<el-option v-for="item in rintermodeldata" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<el-button @click="centerDialogVisible = false">关闭</el-button>
|
||||
<el-button type="primary" :disabled="rintermodel ? false : true" @click="Printing"> 打印 </el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { dayjs } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
import _lodash from 'lodash'
|
||||
import getLodop from './LodopFuncs'
|
||||
const props = defineProps({
|
||||
form: Object,
|
||||
})
|
||||
|
||||
const centerDialogVisible = ref(false) //显示隐藏
|
||||
const rintermodeldata = ref([]) // 获取打印机列表
|
||||
const rintermodel = ref() //打印机类型
|
||||
// 确定打印机类型
|
||||
const changerintermodel = (i: string) => {
|
||||
rintermodel.value = i
|
||||
}
|
||||
const emit = defineEmits(['somethingDone'])
|
||||
// 以下是打印
|
||||
const Printing = () => {
|
||||
let LODOP = getLodop()
|
||||
centerDialogVisible.value = false
|
||||
rintermodeldata.value = [] //清空
|
||||
emit('somethingDone')
|
||||
LODOP.PRINT_INIT('')
|
||||
// 设置打印纸大小D
|
||||
LODOP.SET_PRINT_PAGESIZE(3, 800, '', '')
|
||||
// 二维码控制大小
|
||||
LODOP.ADD_PRINT_BARCODE('', '30px', '150px', '150px', 'QRCode', props.form.url) //打印产品代码条码
|
||||
LODOP.SET_PRINT_MODE('PRINT_PAGE_PERCENT', 'Full-Width ') //设置打印风格,这里是等宽打印
|
||||
LODOP.SET_PRINTER_INDEX(rintermodel.value) //设置默认打印机(这里用的是打印机名称)
|
||||
LODOP.SET_PRINT_STYLE("TextAlign", "Center");
|
||||
// 文字内容
|
||||
LODOP.ADD_PRINT_HTM(
|
||||
'150px',
|
||||
'5px',
|
||||
'100%',
|
||||
'100%',
|
||||
`<div style="width: 100%;font-size: 12px; ">项目分类:${props.form.article}</div>
|
||||
<div style="width: 100%;font-size: 12px; margin-top:6px;">发票类型:${props.form.type}</div>
|
||||
<div style="width: 100%;font-size: 12px; margin-top:6px;">生成时间:${dayjs().format('YYYY-MM-DD HH:mm:ss')}</div>
|
||||
<div style="width: 100%;font-size: 12px; margin-top:6px;">*二维码有效期30天,超过自动失效!</div>
|
||||
<div style="width: 100%;font-size: 14px; margin-top: 15px;">您可以使用微信,扫码开票</div>`,
|
||||
'150px',
|
||||
'5px',
|
||||
'100%',
|
||||
'100%',
|
||||
)
|
||||
LODOP.SET_LICENSES('', 'DCFF409304DFCEB3E2C644BF96CD0720', '', '')
|
||||
LODOP.PRINT()
|
||||
}
|
||||
const initialization = async () => {
|
||||
rintermodeldata.value = [] //清空
|
||||
let LODOP = getLodop()
|
||||
setTimeout(() => {
|
||||
if (LODOP == null) {
|
||||
alert('请先安装打印控件')
|
||||
return
|
||||
}
|
||||
for (var i = 0; i < LODOP.GET_PRINTER_COUNT(); i++) {
|
||||
let obj: {
|
||||
id: string
|
||||
name: string
|
||||
} = {
|
||||
id: '',
|
||||
name: '',
|
||||
}
|
||||
obj.id = LODOP.GET_PRINTER_NAME(i)
|
||||
obj.name = LODOP.GET_PRINTER_NAME(i)
|
||||
// console.log(obj)
|
||||
rintermodeldata.value.push(obj)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
const centerDialogVisibleshow = () => {
|
||||
centerDialogVisible.value = !centerDialogVisible.value
|
||||
}
|
||||
defineExpose({
|
||||
Printing,
|
||||
centerDialogVisibleshow,
|
||||
initialization,
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dialog-footer {
|
||||
text-align: center;
|
||||
|
||||
.qrcodefooter {
|
||||
text-align: center;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import getLodop from "./LodopFuncs.js";
|
||||
/**
|
||||
* 打印订单发票
|
||||
*/
|
||||
export default (data) => {
|
||||
console.log("data.deviceName===", data.deviceName);
|
||||
let LODOP = getLodop();
|
||||
LODOP.PRINT_INIT("打印小票");
|
||||
// 设置打印纸大小D
|
||||
LODOP.SET_PRINT_PAGESIZE(3, "58mm", 20, "");
|
||||
// 二维码控制大小;
|
||||
LODOP.ADD_PRINT_BARCODE("", "40px", "150px", "150px", "QRCode", data.url);
|
||||
//设置默认打印机(这里用的是打印机名称)
|
||||
LODOP.SET_PRINTER_INDEX(data.deviceName);
|
||||
// 文字内容
|
||||
let html = `
|
||||
<div style="height: 100px;"></div>
|
||||
<div style="width: 100%;font-size: 16px;display:flex;justify-content:center;">
|
||||
请使用微信扫码下载发票,二维码有效期30天,超过自动失效
|
||||
</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
`;
|
||||
|
||||
setTimeout(() => {
|
||||
LODOP.ADD_PRINT_HTM("9mm", "0mm", "RightMargin:0mm", 20, html);
|
||||
LODOP.SET_LICENSES("", "DCFF409304DFCEB3E2C644BF96CD0720", "", "");
|
||||
LODOP.PRINT();
|
||||
}, 800);
|
||||
};
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
import getLodop from "./LodopFuncs.js";
|
||||
/**
|
||||
* 打印交班小票
|
||||
*/
|
||||
export default (data) => {
|
||||
console.log("data.deviceName===", data.deviceName);
|
||||
let LODOP = getLodop();
|
||||
LODOP.PRINT_INIT("打印小票");
|
||||
// 设置打印纸大小D
|
||||
LODOP.SET_PRINT_PAGESIZE(3, "58mm", 20, "");
|
||||
//设置默认打印机(这里用的是打印机名称)
|
||||
LODOP.SET_PRINTER_INDEX(data.deviceName);
|
||||
// 文字内容
|
||||
let html = `
|
||||
<div style="font-size: 24px;display:flex;justify-content:center;">
|
||||
${data.shopName}
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
交班小票
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top:50px;">
|
||||
当班时间:${data.loginTime}
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
交班时间:${data.handoverTime}
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
收银员:${data.staffName}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
当班总收入:${data.handAmount}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
现金收入:${data.cashAmount}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
微信收入:${data.wechatAmount}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
支付宝收入:${data.alipayAmount}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
会员支付:${data.vipPay}
|
||||
</div>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
会员充值:${data.vipRecharge}
|
||||
</div>
|
||||
`;
|
||||
|
||||
// let payInfos = "";
|
||||
// if (data.payInfos && data.payInfos.length) {
|
||||
// for (let item of data.payInfos) {
|
||||
// payInfos += `
|
||||
// <div style="font-size: 12px;padding-left:20px;">
|
||||
// ${item.payType}:${item.amount}
|
||||
// </div>
|
||||
// `;
|
||||
// }
|
||||
// }
|
||||
|
||||
// let memberTitle = `
|
||||
// <div style="font-size: 12px;margin-top: 4px;">
|
||||
// 会员数据
|
||||
// </div>
|
||||
// `;
|
||||
|
||||
// let memberData = "";
|
||||
// if (data.memberData && data.memberData.length) {
|
||||
// for (let item of data.memberData) {
|
||||
// memberData += `
|
||||
// <div style="font-size: 12px;padding-left:20px;">
|
||||
// ${item.deposit}:${item.amount}
|
||||
// </div>
|
||||
// `;
|
||||
// }
|
||||
// }
|
||||
|
||||
let productCategoriesTabHead = `
|
||||
<div style="font-size: 12px;margin-top: 4px;">分类数据</div>
|
||||
<table class="table" style="width: 100%;">
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:50%;">名称</td>
|
||||
<td style="font-size: 12px;width:25%;">数量</td>
|
||||
<td style="font-size: 12px;width:25%;">总计</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
let productCategoriesTableBody = "";
|
||||
if (data.categoryDataList && data.categoryDataList.length) {
|
||||
for (let item of data.categoryDataList) {
|
||||
productCategoriesTableBody += `
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:50%;">
|
||||
<div>${item.categoryName}</div>
|
||||
</td>
|
||||
<td style="font-size: 12px;width:25%;">${item.num}</td>
|
||||
<td style="font-size: 12px;width:25%;">
|
||||
${item.amount}
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
let tabHead = `
|
||||
</table>
|
||||
<div style="font-size: 12px;margin-top: 4px;">商品数据</div>
|
||||
<table class="table" style="width: 100%;">
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:75%;">商品</td>
|
||||
<td style="font-size: 12px;width:25%;">数量</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
let tableBody = "";
|
||||
if (data.productDataList && data.productDataList.length) {
|
||||
for (let item of data.productDataList) {
|
||||
tableBody += `
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:75%;">
|
||||
<div>${item.productName}</div>
|
||||
</td>
|
||||
<td style="font-size: 12px;width:25%;">${item.num}</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.printShop) {
|
||||
tabHead = "";
|
||||
tableBody = "";
|
||||
}
|
||||
|
||||
let str = `
|
||||
</table>
|
||||
<div style="font-size: 12px;margin-top: 4px;">
|
||||
<span>快捷收款金额:</span>
|
||||
<span>${data.quickInAmount}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
<span>退款金额:</span>
|
||||
<span>${data.refundAmount}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
<span>总收入:</span>
|
||||
<span>${data.handAmount}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
<span>挂账金额:</span>
|
||||
<span>${data.creditAmount}</span>
|
||||
</div>
|
||||
<div style="margin-top: 20px; font-size: 12px;">
|
||||
<span>总订单数:</span>
|
||||
<span>${data.orderCount}</span>
|
||||
</div>
|
||||
<div style="font-size: 12px;">
|
||||
打印时间:${data.printTime}
|
||||
</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
`;
|
||||
|
||||
// let lastHtml = `${html}${payInfos}${memberTitle}${memberData}${productCategoriesTabHead}${productCategoriesTableBody}${tabHead}${tableBody}${str}`;
|
||||
|
||||
let lastHtml = `${html}${productCategoriesTabHead}${productCategoriesTableBody}${tabHead}${tableBody}${str}`;
|
||||
|
||||
setTimeout(() => {
|
||||
LODOP.ADD_PRINT_HTM("9mm", "0mm", "RightMargin:0mm", 20, lastHtml);
|
||||
LODOP.SET_LICENSES("", "DCFF409304DFCEB3E2C644BF96CD0720", "", "");
|
||||
LODOP.PRINT();
|
||||
}, 800);
|
||||
};
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
import getLodop from "./LodopFuncs.js";
|
||||
import { formatDecimal } from "@/utils/index.js";
|
||||
|
||||
/**
|
||||
* 打印订单小票
|
||||
*/
|
||||
export default (data) => {
|
||||
// console.log("需要打印的订单数据===", data);
|
||||
// console.log("data.deviceName===", data.deviceName);
|
||||
let LODOP = getLodop();
|
||||
LODOP.PRINT_INIT("打印小票");
|
||||
// 设置打印纸大小D
|
||||
LODOP.SET_PRINT_PAGESIZE(3, "58mm", 20, "");
|
||||
//设置默认打印机(这里用的是打印机名称)
|
||||
LODOP.SET_PRINTER_INDEX(data.deviceName);
|
||||
// 文字内容
|
||||
let t1 = 40;
|
||||
let t2 = (100 - t1) / 3;
|
||||
let html = `
|
||||
<div style="font-size: 24px;display:flex;justify-content:center;">
|
||||
${data.shop_name}
|
||||
</div>
|
||||
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||
${data.isBefore ? "预" : ""}结算单 #${data.orderInfo.orderNum || ''}
|
||||
</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>
|
||||
<div style="margin-top: 4px;font-size: 12px;">
|
||||
交易时间:${data.createdAt}
|
||||
</div>
|
||||
<div style="margin-top: 4px;font-size: 12px;">
|
||||
收银员:${data.loginAccount}
|
||||
</div>
|
||||
<div style="margin-top: 6px;margin-bottom: 6px;width: 100%">
|
||||
<hr/>
|
||||
</div>
|
||||
<table class="table" style="width: 100%;">
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:${t1}%;">品名</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">单价</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">数量</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">小计</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
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 = item.proGroupInfo;
|
||||
for (let item of proGroupInfo) {
|
||||
table += `
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:${t1}%;">
|
||||
<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 = `
|
||||
</table>
|
||||
<div style="margin-top: 6px;margin-bottom: 6px;width: 100%">
|
||||
<hr/>
|
||||
</div>
|
||||
<div style="margin-top: 6px; font-size: 12px;display:flex;justify-content: space-between;">
|
||||
<span>原价</span>
|
||||
<span>${data.originAmount}</span>
|
||||
</div>
|
||||
<div style="margin-top: 6px; font-size: 12px;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: 6px; font-size: 22px;display:flex;justify-content: space-between;">
|
||||
<span>实付</span>
|
||||
<span>¥${data.amount}</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>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
`;
|
||||
|
||||
let lastHtml = `${html}${table}${str}`;
|
||||
|
||||
setTimeout(() => {
|
||||
LODOP.ADD_PRINT_HTM("9mm", "0mm", "RightMargin:0mm", 20, lastHtml);
|
||||
LODOP.SET_LICENSES("", "DCFF409304DFCEB3E2C644BF96CD0720", "", "");
|
||||
LODOP.PRINT();
|
||||
}, 800);
|
||||
};
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
import getLodop from "./LodopFuncs.js";
|
||||
/**
|
||||
* 打印退单小票
|
||||
*/
|
||||
export default (data) => {
|
||||
let LODOP = getLodop();
|
||||
LODOP.PRINT_INIT("打印小票");
|
||||
// 设置打印纸大小D
|
||||
LODOP.SET_PRINT_PAGESIZE(3, "58mm", 20, "");
|
||||
//设置默认打印机(这里用的是打印机名称)
|
||||
LODOP.SET_PRINTER_INDEX(data.deviceName);
|
||||
// 文字内容
|
||||
let t1 = 40;
|
||||
let t2 = (100 - t1) / 3;
|
||||
let html = `
|
||||
<div style="font-size: 24px;display:flex;justify-content:center;">
|
||||
${data.shop_name}
|
||||
</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>
|
||||
<div style="margin-top: 4px;font-size: 12px;">
|
||||
交易时间:${data.createdAt}
|
||||
</div>
|
||||
<div style="margin-top: 4px;font-size: 12px;">
|
||||
收银员:${data.loginAccount}
|
||||
</div>
|
||||
<div style="margin-top: 6px;margin-bottom: 6px;width: 100%">
|
||||
<hr/>
|
||||
</div>
|
||||
<table class="table" style="width: 100%;">
|
||||
<tr>
|
||||
<td style="font-size: 12px;width:${t1}%;">品名</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">单价</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">数量</td>
|
||||
<td style="font-size: 12px;width:${t2}%;">小计</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
let table = "";
|
||||
for (let item of data.carts) {
|
||||
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 = `
|
||||
</table>
|
||||
<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>
|
||||
<div style="margin-top: 4px; font-size: 12px;">
|
||||
<span>余额:</span>
|
||||
<span>0.00</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>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
<div>.</div>
|
||||
`;
|
||||
|
||||
let lastHtml = `${html}${table}${str}`;
|
||||
|
||||
setTimeout(() => {
|
||||
LODOP.ADD_PRINT_HTM("9mm", "0mm", "RightMargin:0mm", 20, lastHtml);
|
||||
LODOP.SET_LICENSES("", "DCFF409304DFCEB3E2C644BF96CD0720", "", "");
|
||||
LODOP.PRINT();
|
||||
}, 800);
|
||||
};
|
||||
|
|
@ -0,0 +1,244 @@
|
|||
<template>
|
||||
<div class="drawerbox">
|
||||
<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" @click="computeExpired">
|
||||
<div class="drawerbox_bo_top_left_one" style="font-size: 24px;">
|
||||
{{ store.shopInfo.shopName }}
|
||||
</div>
|
||||
<div class="tips" style="margin-top: 4px; color: var(--el-color-warning);" v-if="showTips">注意:您的账号将于{{
|
||||
store.shopInfo.expireTime }}后过期,请尽快续期!</div>
|
||||
<div class="drawerbox_bo_top_left_tow" style="margin-top: 10px">
|
||||
收银员:{{ store.userInfo.name }}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color: #999">{{ dayjs(store.userInfo.loginTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="drawerbox_bo_top_ring">
|
||||
<div class="drawerbox_bo_top_ring_tb">
|
||||
<el-icon style="margin: 0 auto;" size="20">
|
||||
<FolderAdd />
|
||||
</el-icon>
|
||||
<span>修改密码</span>
|
||||
</div>
|
||||
<div class="drawerbox_bo_top_ring_tb" style="margin-left: 10px;">
|
||||
<el-icon style="margin: 0 auto;" size="20">
|
||||
<CopyDocument />
|
||||
</el-icon>
|
||||
<span>最小化</span>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="drawerbox_bo_box">
|
||||
<!-- <div style="padding: 10px 0; color: #999; font-weight: bold">系统</div> -->
|
||||
<div class="drawerbox_bo_box_itemb_felx">
|
||||
<!-- <div class="drawerbox_bo_box_itembox">
|
||||
<div class="drawerbox_bo_box_icon">
|
||||
<el-icon size="40">
|
||||
<Setting />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_icontext">设置</div>
|
||||
</div> -->
|
||||
<div class="drawerbox_bo_box_itembox" @click="router.push({ name: 'device_list' })">
|
||||
<div class="drawerbox_bo_box_icon">
|
||||
<el-icon size="40">
|
||||
<TurnOff />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_icontext">设备管理</div>
|
||||
</div>
|
||||
<!-- <div class="drawerbox_bo_box_itembox" @click="openCallHandle">
|
||||
<div class="drawerbox_bo_box_icon">
|
||||
<el-icon size="40">
|
||||
<Bell />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_icontext">叫号</div>
|
||||
</div> -->
|
||||
<!-- <div class="drawerbox_bo_box_itembox" @click="screenref.shows()">
|
||||
<div class="drawerbox_bo_box_icon">
|
||||
<el-icon size="40">
|
||||
<Lock />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_icontext">锁屏</div>
|
||||
</div> -->
|
||||
<!-- <div class="drawerbox_bo_box_itembox" @click="to('webview', {
|
||||
url: 'https://cashiernewadmin.sxczgkj.cn/',
|
||||
title: '后台管理'
|
||||
})">
|
||||
<div class="drawerbox_bo_box_icon">
|
||||
<el-icon size="40">
|
||||
<Monitor />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="drawerbox_bo_box_icontext">
|
||||
后台管理
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxabsolute">
|
||||
<div>©银收客 v{{ packageData.version }}</div>
|
||||
<!-- <div>
|
||||
有效期
|
||||
</div> -->
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
<screen ref="screenref"></screen>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { dayjs } from 'element-plus'
|
||||
import { useRouter } from "vue-router";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import screen from "@/components/screen.vue";
|
||||
|
||||
import packageData from "../../package.json";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const emit = defineEmits(["openCall"]);
|
||||
|
||||
const store = useUser();
|
||||
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.expireTime).subtract(30, 'day')
|
||||
// 判断当前时间是否大于到期时间30天
|
||||
showTips.value = now.isBefore(expired)
|
||||
|
||||
console.log("computeExpired===", showTips.value);
|
||||
}
|
||||
|
||||
// 打开叫号弹窗
|
||||
function openCallHandle() {
|
||||
dialogVisible.value = false;
|
||||
emit("openCall");
|
||||
}
|
||||
|
||||
// 跳转
|
||||
function to(pathName, data) {
|
||||
router.push({
|
||||
name: pathName,
|
||||
query: data,
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.drawerbox {
|
||||
:deep(.el-drawer__body) {
|
||||
background: #1c1d1f !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.boxabsolute {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
|
||||
div {
|
||||
color: #8c9196;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div:nth-child(2) {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.drawerbox_box {
|
||||
color: #fff;
|
||||
|
||||
.drawerbox_bo_top {
|
||||
padding: 20px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #47484b;
|
||||
|
||||
.drawerbox_bo_top_left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawerbox_bo_top_ring {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.drawerbox_bo_top_ring_tb {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 6px;
|
||||
padding: 6px 10px;
|
||||
|
||||
span {
|
||||
width: 80px;
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawerbox_bo_box {
|
||||
width: 100%;
|
||||
|
||||
.drawerbox_bo_box_itemb_felx {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
padding: 20px 0;
|
||||
|
||||
.drawerbox_bo_box_itembox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.drawerbox_bo_box_icon {
|
||||
border-radius: 6px;
|
||||
background-color: var(--primary-color);
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.drawerbox_bo_box_icontext {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,542 @@
|
|||
<template>
|
||||
<el-dialog v-model="showDialog" title="选择优惠券" top="12vh" width="80%" @closed="resetHandle">
|
||||
<el-radio-group v-model="querForm.statusActiveIndex" @change="typeChange">
|
||||
<el-radio-button :label="`商品兑换券(${goodsCoupon.length})`" :value="0"></el-radio-button>
|
||||
<el-radio-button :label="`折扣优惠券(${discountCoupon.length})`" :value="1"></el-radio-button>
|
||||
</el-radio-group>
|
||||
<div style="height: 50vh;overflow-y: auto;">
|
||||
<div class="table" v-if="querForm.statusActiveIndex == 0">
|
||||
<div class="title">可用优惠券</div>
|
||||
<el-table ref="tableRef1" :data="list.canUseCoupons" border stripe v-loading="tableData.loading"
|
||||
row-key="id">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="抵扣" prop="discountAmount"></el-table-column>
|
||||
<el-table-column label="限制" prop="fullAmount">
|
||||
<template v-slot="scope">
|
||||
满{{ scope.row.fullAmount }}减{{ scope.row.discountAmount }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" prop="useRestrictions">
|
||||
<template v-slot="scope">
|
||||
<div v-html="scope.row.useRestrictions"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="选择" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-checkbox v-model="scope.row.selected" :true-value="1" :false-value="0"
|
||||
:disabled="scope.row.disabled" @change="selectCoupon($event, scope.row)"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="title">不可用优惠券</div>
|
||||
<el-table ref="tableRef2" :data="list.noCanUseCoupons" border v-loading="tableData.loading">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="不可用原因">
|
||||
<template v-slot="scope">
|
||||
{{ scope.row.canuseResult.reason }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" prop="useRestrictions">
|
||||
<template v-slot="scope">
|
||||
<div v-html="scope.row.useRestrictions"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="table" v-if="querForm.statusActiveIndex == 1">
|
||||
<div class="title">可用优惠券</div>
|
||||
<el-table ref="tableRef1" :data="list.canUseDiscountCoupon" border stripe v-loading="tableData.loading">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="抵扣" prop="discountAmount"></el-table-column>
|
||||
<el-table-column label="限制" prop="fullAmount">
|
||||
<template v-slot="scope">
|
||||
满{{ scope.row.fullAmount }}减{{ scope.row.discountAmount }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" prop="useRestrictions">
|
||||
<template v-slot="scope">
|
||||
<div v-html="scope.row.useRestrictions"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="选择" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-checkbox v-model="scope.row.selected" :true-value="1" :false-value="0"
|
||||
:disabled="scope.row.disabled" @change="selectCoupon($event, scope.row)"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="title">不可用优惠券</div>
|
||||
<el-table ref="tableRef2" :data="list.noUseDiscountCoupon" border v-loading="tableData.loading">
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="不可用原因">
|
||||
<template v-slot="scope">
|
||||
{{ scope.row.canuseResult.reason }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" prop="useRestrictions">
|
||||
<template v-slot="scope">
|
||||
<div v-html="scope.row.useRestrictions"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog_footer">
|
||||
<el-button @click="showDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="selectCouponConfirm">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import { findCoupon } from '@/api/account.js'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import * as UTILS from '@/utils/coupon-utils.js';
|
||||
import { useUser } from "@/store/user.js";
|
||||
|
||||
const props = defineProps({
|
||||
orderList: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const store = useUser()
|
||||
const goodsStore = useGoods()
|
||||
const tableRef1 = ref(null)
|
||||
const tableRef2 = ref(null)
|
||||
const showDialog = ref(false)
|
||||
const query = ref({
|
||||
type: 1,
|
||||
userId: ''
|
||||
})
|
||||
const tableData = reactive({
|
||||
loading: false,
|
||||
list: []
|
||||
})
|
||||
|
||||
// 关闭初始化
|
||||
function resetHandle() {
|
||||
query.value.type = 1
|
||||
tableData.loading = false
|
||||
tableData.list = []
|
||||
}
|
||||
|
||||
function typeChange() {
|
||||
tableData.loading = false
|
||||
// tableData.list = []
|
||||
list.canUseCoupons = []
|
||||
list.noCanUseCoupons = []
|
||||
list.canUseDiscountCoupon = []
|
||||
list.noUseDiscountCoupon = []
|
||||
findCouponAjax()
|
||||
// if (query.type == 2) {
|
||||
// tableRef2.value.clearSelection()
|
||||
// }
|
||||
}
|
||||
|
||||
function groupByPropertyAndCount(arr, property) {
|
||||
// 创建一个空对象来存储每个属性值对应的数量
|
||||
const propertyMap = {};
|
||||
|
||||
// 遍历原始数组
|
||||
arr.forEach(item => {
|
||||
const key = item[property];
|
||||
const num = item.number || 1;
|
||||
if (!propertyMap[key]) {
|
||||
// 如果该属性值还没有在 propertyMap 中,初始化一个对象
|
||||
propertyMap[key] = {
|
||||
value: item[property],
|
||||
count: num
|
||||
};
|
||||
} else {
|
||||
// 如果该属性值已经存在,增加数量
|
||||
propertyMap[key].count += num;
|
||||
}
|
||||
});
|
||||
|
||||
// 将 propertyMap 中的结果转换为数组
|
||||
return Object.values(propertyMap);
|
||||
}
|
||||
|
||||
// 选择优惠券
|
||||
const goodsCoupon = ref([]) // 商品券
|
||||
const discountCoupon = ref([]) // 其他优惠券
|
||||
function selectCoupon($event, e) {
|
||||
console.log($event);
|
||||
console.log(e);
|
||||
if (querForm.value.statusActiveIndex == 0) {
|
||||
goodsCoupon.value = []
|
||||
if ($event) {
|
||||
goodsCoupon.value.push(e)
|
||||
list.canUseCoupons.map(item => {
|
||||
if (item.id != e.id) {
|
||||
item.disabled = true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
list.canUseCoupons.map(item => {
|
||||
if (item.id != e.id) {
|
||||
item.disabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
discountCoupon.value = []
|
||||
if ($event) {
|
||||
discountCoupon.value.push(e)
|
||||
list.canUseDiscountCoupon.map(item => {
|
||||
if (item.id != e.id) {
|
||||
item.disabled = true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
list.canUseDiscountCoupon.map(item => {
|
||||
if (item.id != e.id) {
|
||||
item.disabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
console.log('goodsStore.cartInfo===', goodsStore.cartInfo);
|
||||
|
||||
|
||||
|
||||
// if (query.value.type == 1) {
|
||||
// emits('success', { type: query.value.type, couponList: [{ ...row }] })
|
||||
// } else {
|
||||
|
||||
// let goods = [
|
||||
// ...goodsStore.cartList,
|
||||
// ...goodsStore.orderList.map(item => item.goods).flat()
|
||||
// ]
|
||||
|
||||
// let arr = tableRef2.value.getSelectionRows()
|
||||
|
||||
|
||||
// if (!arr.length) {
|
||||
// ElMessage.error('请选择优惠券')
|
||||
// return
|
||||
// }
|
||||
|
||||
// let obj = groupByPropertyAndCount(arr, 'proId')
|
||||
// let goodsObj = groupByPropertyAndCount(goods, 'product_id')
|
||||
|
||||
// console.log(obj);
|
||||
// console.log(goodsObj);
|
||||
|
||||
// for (let val of goodsObj) {
|
||||
// for (let item of obj) {
|
||||
// if (val.value == item.value) {
|
||||
// if (item.count > val.count) {
|
||||
// ElMessage.error('超出订单数量,请重新选择')
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// emits('success', { type: query.value.type, couponList: arr })
|
||||
// }
|
||||
// showDialog.value = false
|
||||
}
|
||||
|
||||
let orderPrice = ref(goodsStore.cartInfo.costSummary.goodsRealAmount);
|
||||
function updateSelCoupon() {
|
||||
const newval = [...goodsCoupon.value, ...discountCoupon.value];
|
||||
|
||||
const user = goodsStore.vipUserInfo;
|
||||
let shopInfo = store.shopInfo;
|
||||
if (!shopInfo.isMemberPrice) {
|
||||
shopInfo = {};
|
||||
}
|
||||
const canDikouGoodsArr = UTILS.returnCanDikouGoods(goodsStore.cartInfo.allGoods, [], user);
|
||||
|
||||
if (newval.length >= 2) {
|
||||
let goodsCoupon = newval.filter((v) => v.type == 2);
|
||||
let otherCoupon = newval.filter((v) => v.type != 2);
|
||||
goodsCoupon = goodsCoupon.map((v) => {
|
||||
const discount = UTILS.returnCouponDiscount(
|
||||
canDikouGoodsArr,
|
||||
v,
|
||||
user,
|
||||
orderPrice.value,
|
||||
[],
|
||||
shopInfo
|
||||
);
|
||||
return {
|
||||
...v,
|
||||
discount,
|
||||
discountAmount: discount ? discount.discountPrice : v.discountAmount,
|
||||
};
|
||||
});
|
||||
otherCoupon = otherCoupon.map((v) => {
|
||||
const canuseResult = UTILS.returnCouponCanUse({
|
||||
canDikouGoodsArr,
|
||||
coupon: v,
|
||||
orderPrice: orderPrice.value,
|
||||
user: user,
|
||||
selCoupon: goodsCoupon,
|
||||
shopInfo: shopInfo,
|
||||
});
|
||||
|
||||
const discount = UTILS.returnCouponDiscount(
|
||||
canDikouGoodsArr,
|
||||
v,
|
||||
user,
|
||||
orderPrice.value,
|
||||
goodsCoupon,
|
||||
shopInfo
|
||||
);
|
||||
return {
|
||||
...v,
|
||||
canuseResult,
|
||||
discount,
|
||||
discountAmount: discount ? discount.discountPrice : v.discountAmount,
|
||||
};
|
||||
});
|
||||
if (!otherCoupon[0].canuseResult.canUse) {
|
||||
ElMessage.warning('已为您自动剔除叠加不可用的优惠券')
|
||||
discountCoupon.value = [];
|
||||
goodsCoupon.value = goodsCoupon;
|
||||
return;
|
||||
}
|
||||
goodsCoupon.value = goodsCoupon;
|
||||
discountCoupon.value = otherCoupon;
|
||||
}
|
||||
}
|
||||
|
||||
// 确认选择优惠券,然后关闭弹窗
|
||||
function selectCouponConfirm() {
|
||||
updateSelCoupon();
|
||||
|
||||
let ngoodsCoupon = goodsCoupon.value.filter(item => item.discountAmount > 0)
|
||||
let ndiscountCoupon = discountCoupon.value.filter(item => item.discountAmount > 0)
|
||||
|
||||
if (ngoodsCoupon.length != goodsCoupon.value.length || ndiscountCoupon.length != discountCoupon.value.length) {
|
||||
ElMessage.warning('已为您自动剔除叠加不可用的优惠券')
|
||||
}
|
||||
|
||||
console.log('ngoodsCoupon', ngoodsCoupon);
|
||||
console.log('ndiscountCoupon', ndiscountCoupon);
|
||||
|
||||
const data = [...ngoodsCoupon, ...ndiscountCoupon]
|
||||
|
||||
console.log(data);
|
||||
|
||||
// return
|
||||
emits('success', data)
|
||||
goodsCoupon.value = []
|
||||
discountCoupon.value = []
|
||||
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
const querForm = ref({
|
||||
searchValue: '',
|
||||
shopId: '',
|
||||
shopName: '',
|
||||
statusActiveIndex: 0
|
||||
});
|
||||
|
||||
const list = reactive({
|
||||
page: 1,
|
||||
size: 10,
|
||||
status: 'nomore',
|
||||
data: [],
|
||||
noCanUseCoupons: [],
|
||||
canUseCoupons: [],
|
||||
noUseDiscountCoupon: [],
|
||||
canUseDiscountCoupon: []
|
||||
});
|
||||
|
||||
const couponSel = ref({
|
||||
id: ''
|
||||
});
|
||||
const goodsCouponSel = ref({
|
||||
id: ''
|
||||
});
|
||||
const quansSelArr = computed(() => {
|
||||
return [couponSel.value, goodsCouponSel.value].filter((v) => v.id);
|
||||
});
|
||||
|
||||
// 格式化优惠券
|
||||
function formatCoupon() {
|
||||
let canUseGoodsCoupon = [];
|
||||
let canUseDiscountCoupon = [];
|
||||
|
||||
let noUseGoodsCoupon = [];
|
||||
let noUseDiscountCoupon = [];
|
||||
const user = goodsStore.vipUserInfo;
|
||||
let shopInfo = store.shopInfo;
|
||||
if (!shopInfo.isMemberPrice) {
|
||||
shopInfo = {};
|
||||
}
|
||||
const goodsOrderPrice = goodsStore.cartInfo.costSummary.goodsRealAmount;
|
||||
|
||||
console.log('goodsOrderPrice==========', goodsOrderPrice);
|
||||
|
||||
|
||||
const canDikouGoodsArr = UTILS.returnCanDikouGoods(goodsStore.cartInfo.allGoods, [], user);
|
||||
for (let i = 0; i < couponList.value.length; i++) {
|
||||
const coupon = couponList.value[i];
|
||||
const canuseResult = UTILS.returnCouponCanUse({
|
||||
canDikouGoodsArr,
|
||||
coupon,
|
||||
goodsOrderPrice,
|
||||
user,
|
||||
selCoupon: quansSelArr.value,
|
||||
shopInfo
|
||||
});
|
||||
const { canUse, reason } = canuseResult;
|
||||
if (coupon.type == 2) {
|
||||
if (canUse || goodsCouponSel.value.id == coupon.id) {
|
||||
canUseGoodsCoupon.push(coupon);
|
||||
} else {
|
||||
noUseGoodsCoupon.push({
|
||||
...coupon,
|
||||
canuseResult
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (canUse || couponSel.value.id == coupon.id) {
|
||||
canUseDiscountCoupon.push(coupon);
|
||||
} else {
|
||||
noUseDiscountCoupon.push({
|
||||
...coupon,
|
||||
canuseResult
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
//商品券
|
||||
canUseGoodsCoupon = canUseGoodsCoupon.map((v) => {
|
||||
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, quansSelArr.value, shopInfo);
|
||||
return {
|
||||
...v,
|
||||
discount,
|
||||
discountAmount: discount ? discount.discountPrice : v.discountAmount
|
||||
};
|
||||
});
|
||||
//非商品券
|
||||
canUseDiscountCoupon = canUseDiscountCoupon.map((v) => {
|
||||
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, quansSelArr.value, shopInfo);
|
||||
return {
|
||||
...v,
|
||||
discount,
|
||||
discountAmount: discount ? discount.discountPrice : v.discountAmount
|
||||
};
|
||||
});
|
||||
|
||||
if (querForm.value.statusActiveIndex == 0) {
|
||||
list.noCanUseCoupons = noUseGoodsCoupon;
|
||||
|
||||
canUseGoodsCoupon.map(item => {
|
||||
item.selected = false
|
||||
item.disabled = false
|
||||
})
|
||||
|
||||
list.canUseCoupons = canUseGoodsCoupon;
|
||||
} else {
|
||||
list.noUseDiscountCoupon = noUseDiscountCoupon;
|
||||
|
||||
canUseDiscountCoupon.map(item => {
|
||||
item.selected = false
|
||||
item.disabled = false
|
||||
})
|
||||
|
||||
list.canUseDiscountCoupon = canUseDiscountCoupon;
|
||||
}
|
||||
|
||||
console.log('canUseGoodsCoupon', canUseGoodsCoupon);
|
||||
console.log('noUseGoodsCoupon', noUseGoodsCoupon);
|
||||
console.log('canUseDiscountCoupon', canUseDiscountCoupon);
|
||||
console.log('noUseDiscountCoupon', noUseDiscountCoupon);
|
||||
|
||||
console.log('list===', list);
|
||||
|
||||
}
|
||||
|
||||
// 获取用户可用的优惠券
|
||||
const couponList = ref([])
|
||||
async function findCouponAjax() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await findCoupon({
|
||||
shopUserId: query.value.userId
|
||||
})
|
||||
couponList.value = res
|
||||
formatCoupon()
|
||||
// if (query.value.type == 1) {
|
||||
// tableData.list = res
|
||||
// } else {
|
||||
// let arr = []
|
||||
// let ids = props.orderList.map(item => item.product_id)
|
||||
// res && res.map((item, index) => {
|
||||
|
||||
// let found = ids.find(val => val == item.proId)
|
||||
// let result = found !== undefined
|
||||
|
||||
// if (result) {
|
||||
// let pro = props.orderList.find(val => val.product_id == item.proId)
|
||||
|
||||
// console.log('pro===', pro);
|
||||
|
||||
// let discount = pro.lowPrice
|
||||
|
||||
// if (goodsStore.showVipPrice) {
|
||||
// discount = pro.memberPrice
|
||||
// }
|
||||
|
||||
// if (+pro.discount_sale_amount) {
|
||||
// discount = pro.discount_sale_amount
|
||||
// }
|
||||
|
||||
// arr.push({
|
||||
// ...item,
|
||||
// productName: pro.productName,
|
||||
// lowPrice: pro.lowPrice,
|
||||
// discount: discount
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// tableData.list = arr
|
||||
|
||||
// console.log('tableData.list===', tableData.list);
|
||||
// }
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
tableData.loading = false
|
||||
}
|
||||
|
||||
function show(userId) {
|
||||
showDialog.value = true
|
||||
query.value.userId = userId
|
||||
findCouponAjax()
|
||||
console.log('couponModal.orderList===', props.orderList);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dialog_footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-top: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 20px 0 10px 0;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,515 @@
|
|||
<!-- 扫码弹窗 -->
|
||||
<template>
|
||||
<div class="dialog">
|
||||
<el-dialog title="扫码支付" width="600" v-model="dialogVisible" :close-on-click-modal="false" :show-close="!userPayWait"
|
||||
@open="reset" @closed="resetScanCode">
|
||||
<div class="content">
|
||||
<div class="left">
|
||||
<el-image :src="icon" style="width: 60px; height: 60px"></el-image>
|
||||
</div>
|
||||
<div class="right" v-if="!userPayWait">
|
||||
<div class="amount">
|
||||
<span class="t">扫码支付</span>
|
||||
<span class="n">{{ goodsStore.cartInfo.costSummary.finalPayAmount }}</span>
|
||||
</div>
|
||||
<div class="input">
|
||||
<el-input ref="inputRef" v-model="scanCode" :maxlength="18"
|
||||
style="height: calc(var(--el-component-size-large) + 30px)" placeholder="请扫描付款码" clearable
|
||||
@change="inputChange"></el-input>
|
||||
<div class="tips">注意:扫码支付请保证输入框获得焦点,输入内容结束后会自动支付,请勿重复操作</div>
|
||||
</div>
|
||||
<!-- <div class="number_warp">
|
||||
<div class="item" v-for="item in 9" :key="item" @click="inputHandle(item)">{{ item }}</div>
|
||||
<div class="item disabled">.</div>
|
||||
<div class="item" @click="inputHandle(0)">0</div>
|
||||
<div class="item" @click="delHandle">
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" v-loading="loading" @click="submitHandle">
|
||||
立即支付
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pay_wait" v-else>
|
||||
<div class="loading" v-loading="loading" element-loading-text="用户支付中..."></div>
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%" :disabled="!closeState" type="primary" @click="resetScanCode">
|
||||
<span v-if="!closeState">{{ closeStateTime }}秒后可重新扫码</span>
|
||||
<span v-else>重新扫码</span>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%" :disabled="!closeState" @click="closeScanCode">
|
||||
<span v-if="!closeState">{{ closeStateTime }}秒后可关闭</span>
|
||||
<span v-else>关闭</span>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import _ from "lodash";
|
||||
import { ref } from "vue";
|
||||
import icon from "@/assets/icon_scan.png";
|
||||
import { quickPay, queryQuickPayStatus, accountPay } from "@/api/pay";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
import { formatDecimal } from '@/utils'
|
||||
import { microPay, queryOrderStatus, microPayVip, vipPay, queryPayStatus } from '@/api/order.js'
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useGoods } from "@/store/goods.js";
|
||||
const goodsStore = useGoods();
|
||||
|
||||
const store = useUser();
|
||||
const emits = defineEmits(["success", 'orderExpired']);
|
||||
|
||||
const props = defineProps({
|
||||
amount: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
// 0 订单支付 1 会员充值 2 快捷收款
|
||||
selecttype: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
orderId: {
|
||||
type: [Number, String],
|
||||
default: "",
|
||||
},
|
||||
fast: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 支付类型
|
||||
payType: {
|
||||
type: [Number, String],
|
||||
default: "",
|
||||
},
|
||||
money: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
payData: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
chargeId: {
|
||||
type: [Number, String],
|
||||
default: "",
|
||||
}
|
||||
});
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const scanCode = ref("");
|
||||
const inputRef = ref(null);
|
||||
|
||||
const loading = ref(false);
|
||||
const userPayWait = ref(false);
|
||||
|
||||
const fastOrder = ref('')
|
||||
|
||||
const submitHandle = _.throttle(submitHandleAjax, 200);
|
||||
const table_code = ref('')
|
||||
|
||||
// 提交扫码支付
|
||||
async function submitHandleAjax() {
|
||||
// console.log('props.selecttype===', props.selecttype);
|
||||
try {
|
||||
if (!scanCode.value || scanCode.value.length > 18) return;
|
||||
loading.value = true;
|
||||
|
||||
console.log('props.selecttype===', props.selecttype);
|
||||
console.log('props.payType===', props.payType);
|
||||
|
||||
// return;
|
||||
|
||||
// 判断订单是否锁定
|
||||
await goodsStore.isOrderLock({
|
||||
table_code: goodsStore.orderListInfo.tableCode
|
||||
})
|
||||
|
||||
if (props.selecttype == 0) {
|
||||
// 下单扫码支付
|
||||
if (props.payType == 'scanCode') {
|
||||
await microPay({
|
||||
...props.payData,
|
||||
authCode: scanCode.value
|
||||
});
|
||||
} else if (props.payType == 'deposit') {
|
||||
await vipPay({
|
||||
...props.payData,
|
||||
payType: 'scanCode',
|
||||
authCode: scanCode.value
|
||||
});
|
||||
}
|
||||
} else if (props.selecttype == 1) {
|
||||
// 会员扫码充值
|
||||
await microPayVip({
|
||||
shopId: store.shopInfo.id,
|
||||
shopUserId: props.orderId,
|
||||
amount: props.amount,
|
||||
authCode: scanCode.value,
|
||||
rechargeDetailId: props.chargeId,
|
||||
})
|
||||
} else {
|
||||
// 快捷收银
|
||||
if (props.fast) {
|
||||
await quickPay({
|
||||
amount: props.amount,
|
||||
authCode: scanCode.value,
|
||||
payType: "scanCode",
|
||||
});
|
||||
} else {
|
||||
if (props.payType == 'scanCode') {
|
||||
if (props.selecttype == 1) {
|
||||
|
||||
} else if (props.selecttype == 2) {
|
||||
|
||||
}
|
||||
}
|
||||
if (props.payType == 'deposit') {
|
||||
await accountPay({
|
||||
orderId: props.orderId,
|
||||
memberId: '',
|
||||
memberAccount: scanCode.value,
|
||||
payAmount: props.money < props.amount ? props.money : '',
|
||||
discountAmount: props.money < props.amount ? formatDecimal(props.amount - props.money) : ''
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
dialogVisible.value = false;
|
||||
emits("success");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
if (error.code === 211) {
|
||||
// 开始锁单
|
||||
goodsStore.isOrderLock({
|
||||
table_code: table_code.value
|
||||
}, 'pay_lock')
|
||||
|
||||
userPayWait.value = true;
|
||||
fastOrder.value = error.data
|
||||
autoCheckOrder()
|
||||
} else if (error.code == 701) {
|
||||
// 订单已过期需刷新购物车和订单
|
||||
emits('orderExpired')
|
||||
} else {
|
||||
scanCode.value = "";
|
||||
loading.value = false;
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭扫码支付
|
||||
function closeScanCode() {
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
|
||||
const closeState = ref(false)
|
||||
const closeStateTime = ref(5);
|
||||
const closeStateTimer = ref(null)
|
||||
|
||||
function closeStateTimerFuc() {
|
||||
closeStateTimer.value = setInterval(() => {
|
||||
closeStateTime.value--
|
||||
if (closeStateTime.value <= 0) {
|
||||
clearInterval(closeStateTimer.value)
|
||||
closeStateTimer.value = null
|
||||
closeState.value = true
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 自动查询订单状态
|
||||
const timer = ref(null)
|
||||
function autoCheckOrder() {
|
||||
closeStateTimerFuc()
|
||||
timer.value = setInterval(() => {
|
||||
// 开始锁单
|
||||
goodsStore.isOrderLock({
|
||||
table_code: table_code.value
|
||||
}, 'pay_lock')
|
||||
checkPayStauts(false)
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
// 查询用户支付状态
|
||||
async function checkPayStauts(tips = true) {
|
||||
try {
|
||||
if (props.selecttype == 1) {
|
||||
// 会员扫码充值
|
||||
const res = await queryPayStatus({
|
||||
shopId: store.shopInfo.id,
|
||||
payOrderNo: fastOrder.value.payOrderNo,
|
||||
});
|
||||
if (res == 'TRADE_SUCCESS') {
|
||||
userPayWait.value = false
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
ElMessage.success("支付成功");
|
||||
dialogVisible.value = false;
|
||||
clearAutoCheckOrder()
|
||||
emits("success");
|
||||
return;
|
||||
} else if (res == 'TRADE_AWAIT') {
|
||||
if (tips) {
|
||||
ElMessage.warning("用户支付中...");
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
clearAutoCheckOrder()
|
||||
ElMessage.error(res.payRemark || "支付失败!");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 其他扫码支付
|
||||
if (props.fast) {
|
||||
// 快捷收银
|
||||
const res = await queryQuickPayStatus({ orderId: fastOrder.value.orderNo });
|
||||
if (res.status == 0) {
|
||||
userPayWait.value = false
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
ElMessage.success("支付成功");
|
||||
dialogVisible.value = false;
|
||||
clearAutoCheckOrder()
|
||||
emits("success");
|
||||
return;
|
||||
}
|
||||
if (res.status == 1) {
|
||||
if (tips) {
|
||||
ElMessage.warning("用户支付中...");
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
clearAutoCheckOrder()
|
||||
ElMessage.error(res.payRemark || "支付失败!");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 扫码下单
|
||||
const res = await queryOrderStatus({ orderId: props.payData.checkOrderPay.orderId });
|
||||
if (res == "done") {
|
||||
// 支付成功,解锁订单
|
||||
await goodsStore.isOrderLock({
|
||||
table_code: table_code.value
|
||||
}, 'pay_unlock')
|
||||
|
||||
userPayWait.value = false
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
dialogVisible.value = false;
|
||||
clearAutoCheckOrder()
|
||||
emits("success");
|
||||
return;
|
||||
}
|
||||
if (res == "unpaid") {
|
||||
if (tips) {
|
||||
ElMessage.warning("用户支付中...");
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
clearAutoCheckOrder()
|
||||
ElMessage.warning(res.msg || '');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function clearAutoCheckOrder() {
|
||||
clearInterval(timer.value)
|
||||
timer.value = null
|
||||
}
|
||||
|
||||
// 重新扫码
|
||||
function resetScanCode() {
|
||||
clearInterval(timer.value)
|
||||
timer.value = null
|
||||
|
||||
clearInterval(closeStateTimer.value)
|
||||
closeStateTimer.value = null
|
||||
|
||||
reset()
|
||||
setTimeout(() => {
|
||||
inputRef.value.focus();
|
||||
}, 500)
|
||||
}
|
||||
|
||||
// 输入
|
||||
function inputHandle(n) {
|
||||
scanCode.value += n;
|
||||
inputRef.value.focus();
|
||||
}
|
||||
|
||||
// 删除
|
||||
function delHandle() {
|
||||
if (!scanCode.value) return;
|
||||
scanCode.value = scanCode.value.substring(0, scanCode.value.length - 1);
|
||||
inputRef.value.focus();
|
||||
}
|
||||
|
||||
// 监听扫码枪回车事件
|
||||
// function enterHandle() {
|
||||
// inputRef.value.focus()
|
||||
// }
|
||||
|
||||
const inputChange = _.debounce(function (e) {
|
||||
submitHandle();
|
||||
}, 100);
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true;
|
||||
table_code.value = goodsStore.orderListInfo.tableCode
|
||||
setTimeout(() => {
|
||||
inputRef.value.focus();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function close() {
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
userPayWait.value = false;
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
closeState.value = false
|
||||
closeStateTime.value = 5
|
||||
|
||||
// 关闭锁单
|
||||
// goodsStore.isOrderLock({
|
||||
// table_code: table_code.value
|
||||
// }, 'pay_unlock')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
close,
|
||||
loading,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tips {
|
||||
padding-top: 10px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.dialog :deep(.el-dialog__body) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
|
||||
.left {
|
||||
width: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #efefef;
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 1;
|
||||
padding: var(--el-font-size-base);
|
||||
|
||||
.amount {
|
||||
display: flex;
|
||||
height: calc(var(--el-component-size-large) + 20px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: var(--primary-color);
|
||||
background-color: #555;
|
||||
border-radius: 6px;
|
||||
padding: 0 var(--el-font-size-base);
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
}
|
||||
|
||||
.input {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.number_warp {
|
||||
--h: 50px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: var(--h) var(--h) var(--h) var(--h);
|
||||
gap: 8px;
|
||||
|
||||
.item {
|
||||
background-color: #dddddd;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
border-radius: 4px;
|
||||
|
||||
&.disabled {
|
||||
color: #999;
|
||||
background-color: #efefef;
|
||||
|
||||
&:active {
|
||||
background-color: #efefef;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #b9b9b9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .btn {
|
||||
// padding-top: 20px;
|
||||
// }
|
||||
}
|
||||
|
||||
.pay_wait {
|
||||
flex: 1;
|
||||
padding: 0 var(--el-font-size-base);
|
||||
height: 400px;
|
||||
padding-bottom: 100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.loading {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
--el-loading-spinner-size: 100px;
|
||||
|
||||
:deep(.el-loading-text) {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 200px;
|
||||
padding-top: var(--el-font-size-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<el-dialog title="备注" width="600" v-model="dialogVisible">
|
||||
<div class="tag_wrap">
|
||||
<el-button plain type="primary" v-for="item in tagList" :key="item.remark" @click="remark = item.remark">
|
||||
{{ item.remark }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<el-input type="textarea" :rows="6" v-model="remark" placeholder="请输入备注" @focus="
|
||||
global.updateData(false)" @blur="global.updateData(true)"></el-input>
|
||||
</div>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" @click="confirmHandle">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
const global = useGlobal()
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
|
||||
const remark = ref('')
|
||||
|
||||
const tagList = ref([
|
||||
{
|
||||
remark: '味道淡一点'
|
||||
},
|
||||
{
|
||||
remark: '味道大一点'
|
||||
}
|
||||
])
|
||||
|
||||
function confirmHandle() {
|
||||
emit('success', remark.value)
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
// 显示组件
|
||||
const show = () => {
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tag_wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.footer_wrap {
|
||||
display: flex;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<el-dialog width="400" v-model="dialogVisible" style="padding: 0; " title="已锁屏" :close-on-click-modal="false" :show-close="false">
|
||||
<div class="drawerbox_box">
|
||||
<el-input v-model="loginName" placeholder="请输入登录账号" />
|
||||
<el-button style="width: 100%; margin-top: 20px;" type="primary" @click="loginNameclick">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useUser } from "@/store/user.js"
|
||||
import { ElMessage } from 'element-plus'
|
||||
const store = useUser()
|
||||
const loginName = ref()
|
||||
const loginNameclick = () => {
|
||||
if (loginName.value == store.userInfo.loginName) {
|
||||
dialogVisible.value = false
|
||||
} else {
|
||||
ElMessage({
|
||||
message: '输入错误',
|
||||
type: 'Error',
|
||||
})
|
||||
}
|
||||
}
|
||||
const dialogVisible = ref(false)
|
||||
|
||||
function shows() {
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
shows
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.drawerbox {
|
||||
:deep(.el-drawer__body) {
|
||||
background: #1c1d1f !important;
|
||||
}
|
||||
|
||||
.drawerbox_box {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
<template>
|
||||
<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-select v-model="tableData.isVips" placeholder="是否为会员" style="width: 150px;" @change="changeIsVips">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="是" :value="1"></el-option>
|
||||
<el-option label="否" :value="0"></el-option>
|
||||
</el-select>
|
||||
</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="400px" border stripe v-loading="tableData.loading">
|
||||
<el-table-column prop="nickName" label="昵称" width="150px" />
|
||||
<el-table-column prop="phone" label="手机" width="150px" />
|
||||
<el-table-column prop="code" label="编号" width="150px" />
|
||||
<el-table-column prop="level" label="等级" />
|
||||
<el-table-column prop="accountPoints" label="积分" />
|
||||
<el-table-column prop="amount" label="余额" width="120px">
|
||||
<template v-slot="scope">
|
||||
¥{{ formatDecimal(scope.row.amount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120px" fixed="right">
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { shopUserList } from "@/api/account.js";
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const props = defineProps({
|
||||
amount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
const showDialog = ref(false)
|
||||
const tableData = reactive({
|
||||
phone: '',
|
||||
isVips: "",
|
||||
loading: false,
|
||||
list: [],
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 选择会员去下单
|
||||
async function toHomeMember(row) {
|
||||
try {
|
||||
emits('success', { ...row })
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
// 重置表格
|
||||
function resetTable() {
|
||||
tableData.phone = ''
|
||||
tableData.isVips = ''
|
||||
tableData.page = 1
|
||||
getMemberList()
|
||||
}
|
||||
|
||||
function changeIsVips() {
|
||||
tableData.page = 1
|
||||
getMemberList()
|
||||
}
|
||||
|
||||
// 获取会员列表
|
||||
async function getMemberList() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const res = await shopUserList({
|
||||
key: tableData.phone,
|
||||
isVips: tableData.isVips,
|
||||
page: tableData.page,
|
||||
size: tableData.size,
|
||||
amount: props.amount
|
||||
})
|
||||
tableData.list = res.records
|
||||
tableData.total = res.totalRow
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
tableData.loading = false
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// 显示选择会员弹窗
|
||||
function show() {
|
||||
showDialog.value = true
|
||||
getMemberList()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,33 +1,44 @@
|
|||
<template>
|
||||
<el-dialog title="选择规格" width="800" v-model="show">
|
||||
<el-dialog :title="goods.name" width="600" v-model="dialogVisible" top="5vh">
|
||||
<div class="header">选择规格</div>
|
||||
<div class="row">
|
||||
<div class="title">规格</div>
|
||||
<div v-loading="loading">
|
||||
<div class="row" v-for="(item, index) in goods.selectSpec" :key="index">
|
||||
<div class="title">{{ item.name }}</div>
|
||||
<div class="sku_wrap">
|
||||
<div class="item">默认(1人份)</div>
|
||||
<!-- <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" :disabled="val.disabled" @click="selectedSku(index, i)" class="btn">{{ val.name }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="title">温度</div>
|
||||
<div class="sku_wrap">
|
||||
<div class="item">冰</div>
|
||||
<div class="item">热</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="title">糖度</div>
|
||||
<div class="sku_wrap">
|
||||
<div class="item">不另外加糖</div>
|
||||
<div class="item">半糖</div>
|
||||
<div class="item">标准糖</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="info">
|
||||
<div class="price" v-if="goodsInfo.id">
|
||||
<span class="i">¥</span>
|
||||
<span class="n">{{ formatDecimal(+goodsInfo.salePrice) }}</span>
|
||||
</div>
|
||||
<span>库存:{{ stockNumber }}</span>
|
||||
</div>
|
||||
<div class="btn_wrap">
|
||||
<div class="btn">
|
||||
<el-button plain style="width: 100%;" @click="show = false">取消</el-button>
|
||||
<el-button plain style="width: 100%;" @click="dialogVisible = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;">确认</el-button>
|
||||
<el-button type="primary" style="width: 100%;"
|
||||
:disabled="!goodsInfo.id || !+goodsInfo.isGrounding || !!+goodsInfo.isSoldStock"
|
||||
@click="submitSku">
|
||||
<template v-if="goodsInfo.id && !+goodsInfo.isGrounding">
|
||||
未上架
|
||||
</template>
|
||||
<template v-if="goodsInfo.id && +goodsInfo.isSoldStock">
|
||||
已售罄
|
||||
</template>
|
||||
<template v-if="(+goodsInfo.isGrounding && !+goodsInfo.isPauseSale) || !goodsInfo.id">
|
||||
确认
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
|
@ -35,8 +46,178 @@
|
|||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const show = ref(true)
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
const type = ref('shop')
|
||||
const dialogVisible = ref(false)
|
||||
const goods = ref({})
|
||||
|
||||
const selectedSkuNum = ref(0)
|
||||
const selectedSkuTag = ref('')
|
||||
const goodsInfo = ref({})
|
||||
const loading = ref(false)
|
||||
const selecSkuArray = ref([])
|
||||
const stockNumber = ref(0)
|
||||
|
||||
// 确认选择规格
|
||||
function submitSku() {
|
||||
dialogVisible.value = false
|
||||
// switch (type.value) {
|
||||
// case 'shop':
|
||||
// break;
|
||||
// case 'cart':
|
||||
// emit('success', goodsInfo.value)
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
emit('success', goodsInfo.value)
|
||||
}
|
||||
|
||||
// 选择规格
|
||||
function selectedSku(index = 0, i = 0) {
|
||||
goodsInfo.value = {}
|
||||
|
||||
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.skuList.map(val => {
|
||||
// console.log(val);
|
||||
// console.log(`${selecSkuArray.value.join(',')},${item.name}`);
|
||||
// console.log(val.specInfo.indexOf(`${selecSkuArray.value.join(',')},${item.name}`));
|
||||
if (val.specInfo.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--
|
||||
} else {
|
||||
goods.value.selectSpec[index].selectSpecResult[i].active = true
|
||||
selectedSkuNum.value++
|
||||
}
|
||||
|
||||
selectedSuccess()
|
||||
}
|
||||
|
||||
// 规格是否选择完
|
||||
function selectedSuccess() {
|
||||
let num = 0
|
||||
let tag = []
|
||||
goods.value.selectSpec.map(item => {
|
||||
item.selectSpecResult.map(val => {
|
||||
if (val.active) {
|
||||
num++
|
||||
tag.push(val.name)
|
||||
}
|
||||
})
|
||||
selectedSkuNum.value = num
|
||||
selectedSkuTag.value = tag.join(',')
|
||||
})
|
||||
|
||||
if (selectedSkuNum.value >= goods.value.selectSpec.length) {
|
||||
// 规格选完了
|
||||
queryProductSkuAjax()
|
||||
} else {
|
||||
goodsInfo.value = {}
|
||||
}
|
||||
}
|
||||
|
||||
// 通过选中的商品规格查询价格
|
||||
async function queryProductSkuAjax() {
|
||||
goods.value.skuList.map(item => {
|
||||
if (item.specInfo == selectedSkuTag.value) {
|
||||
goodsInfo.value = item
|
||||
}
|
||||
})
|
||||
|
||||
console.log('goodsInfo.value===', goodsInfo.value);
|
||||
}
|
||||
|
||||
// 显示规格
|
||||
function show(item, t = 'shop') {
|
||||
stockNumber.value = item.stockNumber
|
||||
type.value = t
|
||||
let arr = []
|
||||
for (let val in item.selectSpecInfo) {
|
||||
if (item.selectSpecInfo[val].length) {
|
||||
switch (type.value) {
|
||||
case 'shop':
|
||||
arr.push({
|
||||
name: val,
|
||||
selectSpecResult: item.selectSpecInfo[val].map(item => {
|
||||
return {
|
||||
active: false,
|
||||
name: item,
|
||||
disabled: false
|
||||
}
|
||||
})
|
||||
})
|
||||
break;
|
||||
case 'cart':
|
||||
// 如果从购物车选择规格需要做选中效果
|
||||
const skus = item.sku_name.split(',')
|
||||
arr.push({
|
||||
name: val,
|
||||
selectSpecResult: item.selectSpecInfo[val].map(item => {
|
||||
return {
|
||||
active: !!skus.find(val => val === item),
|
||||
name: item,
|
||||
disabled: false
|
||||
}
|
||||
})
|
||||
})
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item.selectSpec = arr
|
||||
|
||||
// 赋值新的规格数据
|
||||
goodsInfo.value = {}
|
||||
goods.value = {}
|
||||
selectedSkuNum.value = 0
|
||||
dialogVisible.value = true
|
||||
goods.value = ""
|
||||
goods.value = item
|
||||
|
||||
selectedSuccess()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
@ -47,41 +228,51 @@ const show = ref(true)
|
|||
|
||||
.row {
|
||||
border-bottom: 1px solid #ececec;
|
||||
margin-top: 20px;
|
||||
margin-top: var(--el-font-size-base);
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
font-size: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
.sku_wrap {
|
||||
display: flex;
|
||||
padding: 14px 0;
|
||||
|
||||
.item {
|
||||
color: var(--primary-color);
|
||||
padding: 8px 16px;
|
||||
font-size: 18px;
|
||||
border: 1px solid var(--primary-color);
|
||||
margin-right: 14px;
|
||||
border-radius: 2px;
|
||||
|
||||
&.active {
|
||||
background-color: var(--primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
padding: var(--el-font-size-base) 0;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--el-font-size-base);
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding-top: 30px;
|
||||
|
||||
.info {
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 20px;
|
||||
|
||||
.price {
|
||||
color: var(--el-color-danger);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
|
||||
.i {
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.n {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn_wrap {
|
||||
display: flex;
|
||||
padding-top: 100px;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
|
|
@ -91,4 +282,5 @@ const show = ref(true)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<!-- 取餐号组件 -->
|
||||
<template>
|
||||
<el-dialog :title="props.title" width="600" v-model="dialogVisible" @open="opne">
|
||||
<el-input :type="props.inputType" v-model="number" :placeholder="props.placeholder" readonly></el-input>
|
||||
<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="footer">
|
||||
<el-button type="primary" style="width: 100%" :disabled="number <= 0" :loading="loading"
|
||||
@click="confirmHandle">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { clearNoNum } from '@/utils/index.js'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: [String, Number],
|
||||
default: 1, // 1取餐号 2密码
|
||||
},
|
||||
inputType: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: "标题",
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "提示",
|
||||
},
|
||||
});
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const number = ref("");
|
||||
|
||||
const emit = defineEmits(["success"]);
|
||||
|
||||
function show() {
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
function opne() {
|
||||
number.value = "";
|
||||
}
|
||||
|
||||
// 输入
|
||||
function inputHandle(n) {
|
||||
number.value += n;
|
||||
number.value = clearNoNum({ value: number.value })
|
||||
}
|
||||
|
||||
// 删除
|
||||
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 || number.value <= 0) return
|
||||
if (props.type == 2) {
|
||||
if (number.value.length < 6) {
|
||||
ElMessage.error('请输入正确的密码')
|
||||
return
|
||||
} else {
|
||||
loading.value = true
|
||||
emit("success", number.value);
|
||||
dialogVisible.value = false;
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
}
|
||||
} else {
|
||||
emit("success", number.value);
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.el-input__inner) {
|
||||
height: 60px;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.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: 60px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<template>
|
||||
<el-dialog v-model="showDialog" :title="`发现新版本v${newVersionRef}`" top="30vh" width="500" :close-on-click-modal="false"
|
||||
:close-on-press-escape="false" :show-close="false">
|
||||
<div class="message" v-html="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.isForce && !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/system.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 newVersionRef = ref('')
|
||||
|
||||
// 关闭更新弹窗,下次登录在提示
|
||||
function closeHandle() {
|
||||
showDialog.value = false
|
||||
useStorage.set('updateFlag', true)
|
||||
}
|
||||
|
||||
// 检查版本更新
|
||||
async function findVersionAjax() {
|
||||
try {
|
||||
let updateFlag = useStorage.get('updateFlag')
|
||||
const res = await findVersion()
|
||||
if (res && res.version) {
|
||||
const newVersion = res.version;
|
||||
const oldVersion = packageData.version;
|
||||
|
||||
console.log('当前版本:', oldVersion);
|
||||
console.log('获取版本:', newVersion);
|
||||
|
||||
const result = compareVersions(newVersion, oldVersion);
|
||||
if (result > 0) {
|
||||
if (!updateFlag) {
|
||||
newVersionRef.value = newVersion
|
||||
showDialog.value = true
|
||||
updataInfo.value = res
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('检查版本更新===', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 比较版本号
|
||||
function compareVersions(version1, version2) {
|
||||
const v1 = version1.split('.').map(Number);
|
||||
const v2 = version2.split('.').map(Number);
|
||||
const maxLength = Math.max(v1.length, v2.length);
|
||||
|
||||
for (let i = 0; i < maxLength; i++) {
|
||||
const num1 = v1[i] || 0;
|
||||
const num2 = v2[i] || 0;
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1;
|
||||
} else if (num1 < num2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 下载新版本
|
||||
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.shopInfo.id) {
|
||||
findVersionAjax()
|
||||
}
|
||||
ipcRenderer.on('updateProgress', (event, res) => {
|
||||
uploadPro.value = res
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
<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 userStore from '@/utils/useStorage.js'
|
||||
import { ElUpload, ElMessage } from 'element-plus';
|
||||
|
||||
|
||||
const fileList = ref([])
|
||||
|
||||
// 定义接收的外部属性
|
||||
const props = defineProps({
|
||||
uploadUrl: {
|
||||
type: String,
|
||||
default: import.meta.env.MODE == 'development' ? '/api/account/admin/common/upload' : import.meta.env.VITE_API_URL + '/account/admin/common/upload',
|
||||
},
|
||||
headers: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
token: userStore.get('token'),
|
||||
shopId: userStore.get('shopInfo').id,
|
||||
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>
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
import { createRouter, createWebHashHistory } from "vue-router";
|
||||
import home from "@/views/home.vue";
|
||||
import home from "@/views/home/index.vue";
|
||||
import test from "@/views/home/test.vue";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
// component: test,
|
||||
component: home,
|
||||
},
|
||||
{
|
||||
|
|
@ -23,14 +25,82 @@ const routes = [
|
|||
},
|
||||
component: () => import("@/views/register.vue"),
|
||||
},
|
||||
{
|
||||
path: "/group_buy",
|
||||
name: "group_buy",
|
||||
meta: {
|
||||
index: 1,
|
||||
},
|
||||
component: () => import("@/views/group_buy/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/table",
|
||||
name: "table",
|
||||
meta: {
|
||||
index: 1,
|
||||
},
|
||||
component: () => import("@/views/table.vue"),
|
||||
}
|
||||
component: () => import("@/views/table/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/order",
|
||||
name: "order",
|
||||
meta: {
|
||||
index: 1,
|
||||
},
|
||||
component: () => import("@/views/order/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/member",
|
||||
name: "member",
|
||||
meta: {
|
||||
index: 1,
|
||||
},
|
||||
component: () => import("@/views/member/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/queue",
|
||||
name: "queue",
|
||||
meta: {
|
||||
index: 1,
|
||||
},
|
||||
component: () => import("@/views/queue/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/work",
|
||||
name: "work",
|
||||
meta: {
|
||||
index: 1,
|
||||
},
|
||||
component: () => import("@/views/work/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/workrecord",
|
||||
name: "workrecord",
|
||||
meta: {
|
||||
index: 1,
|
||||
},
|
||||
component: () => import("@/views/work/record.vue"),
|
||||
},
|
||||
{
|
||||
path: "/device_list",
|
||||
name: "device_list",
|
||||
component: () => import("@/views/device/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/add_device",
|
||||
name: "add_device",
|
||||
component: () => import("@/views/device/add.vue"),
|
||||
},
|
||||
{
|
||||
path: "/add_label",
|
||||
name: "add_label",
|
||||
component: () => import("@/views/device/add_label.vue"),
|
||||
},
|
||||
{
|
||||
path: "/webview",
|
||||
name: "webview",
|
||||
component: () => import("@/views/webview/index.vue"),
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
|
|
|
|||
|
|
@ -0,0 +1,176 @@
|
|||
import { defineStore } from "pinia";
|
||||
|
||||
export const useGlobal = defineStore("global", {
|
||||
state: () => ({
|
||||
// 是否监听叫号
|
||||
isCallNumber: true,
|
||||
orderStatus: [
|
||||
{
|
||||
type: "unpaid",
|
||||
label: "待支付",
|
||||
},
|
||||
{
|
||||
type: "in_production",
|
||||
label: "制作中",
|
||||
},
|
||||
{
|
||||
type: "wait_out",
|
||||
label: "待取餐",
|
||||
},
|
||||
{
|
||||
type: "done",
|
||||
label: "订单完成",
|
||||
},
|
||||
{
|
||||
type: "refunding",
|
||||
label: "申请退单",
|
||||
},
|
||||
{
|
||||
type: "refund",
|
||||
label: "退单",
|
||||
},
|
||||
{
|
||||
type: "part_refund",
|
||||
label: "部分退单",
|
||||
},
|
||||
{
|
||||
type: "cancelled",
|
||||
label: "取消订单",
|
||||
},
|
||||
],
|
||||
orderType: [
|
||||
{
|
||||
type: "cash",
|
||||
label: "收银",
|
||||
},
|
||||
{
|
||||
type: "miniapp",
|
||||
label: "小程序",
|
||||
},
|
||||
],
|
||||
platformType: [
|
||||
{
|
||||
type: "WX",
|
||||
label: "微信小程序",
|
||||
},
|
||||
{
|
||||
type: "ALI",
|
||||
label: "支付宝小程序",
|
||||
},
|
||||
{
|
||||
type: "PC",
|
||||
label: "收银机客户端",
|
||||
},
|
||||
{
|
||||
type: "WEB",
|
||||
label: "PC管理端",
|
||||
},
|
||||
{
|
||||
type: "APP",
|
||||
label: "APP管理端",
|
||||
},
|
||||
{
|
||||
type: "H5",
|
||||
label: "收款码",
|
||||
},
|
||||
],
|
||||
dineMode: [
|
||||
{
|
||||
type: "dine-in",
|
||||
label: "堂食",
|
||||
},
|
||||
{
|
||||
type: "take-out",
|
||||
label: "外带",
|
||||
},
|
||||
{
|
||||
type: "take-away",
|
||||
label: "外卖",
|
||||
},
|
||||
],
|
||||
payType: [
|
||||
{
|
||||
type: "main_scan",
|
||||
label: "主扫",
|
||||
},
|
||||
{
|
||||
type: "back_scan",
|
||||
label: "被扫",
|
||||
},
|
||||
{
|
||||
type: "wechat_mini",
|
||||
label: "微信小程序",
|
||||
},
|
||||
{
|
||||
type: "alipay_mini",
|
||||
label: "支付宝小程序",
|
||||
},
|
||||
{
|
||||
type: "vip_pay",
|
||||
label: "会员支付",
|
||||
},
|
||||
{
|
||||
type: "cash_pay",
|
||||
label: "现金支付",
|
||||
},
|
||||
{
|
||||
type: "credit_pay",
|
||||
label: "挂账支付",
|
||||
},
|
||||
],
|
||||
bizCodes: [
|
||||
{
|
||||
type: "cashIn",
|
||||
label: "现金充值",
|
||||
},
|
||||
{
|
||||
type: "wechatIn",
|
||||
label: "微信小程序充值",
|
||||
},
|
||||
{
|
||||
type: "alipayIn",
|
||||
label: "支付宝小程序充值",
|
||||
},
|
||||
{
|
||||
type: "awardIn",
|
||||
label: "充值奖励",
|
||||
},
|
||||
{
|
||||
type: "rechargeRefund",
|
||||
label: "充值退款",
|
||||
},
|
||||
{
|
||||
type: "orderPay",
|
||||
label: "订单消费",
|
||||
},
|
||||
{
|
||||
type: "orderRefund",
|
||||
label: "订单退款",
|
||||
},
|
||||
{
|
||||
type: "adminIn",
|
||||
label: "管理员充值",
|
||||
},
|
||||
{
|
||||
type: "adminOut",
|
||||
label: "管理员消费",
|
||||
},
|
||||
],
|
||||
refundType: [
|
||||
{
|
||||
type: "cash",
|
||||
label: "手动退款",
|
||||
},
|
||||
{
|
||||
type: "payBack",
|
||||
label: "原路退回",
|
||||
},
|
||||
],
|
||||
}),
|
||||
actions: {
|
||||
// 更新状态
|
||||
updateData(state) {
|
||||
this.isCallNumber = state;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import dayjs from "dayjs";
|
||||
import receiptPrint from "@/components/lodop/receiptPrint.js";
|
||||
import lodopPrintWork from "@/components/lodop/lodopPrintWork.js";
|
||||
import invoicePrint from "@/components/lodop/invoicePrint.js";
|
||||
import refundPrint from "@/components/lodop/refundPrint.js";
|
||||
import { printerList } from "@/api/account.js";
|
||||
|
||||
export const usePrint = defineStore("print", {
|
||||
state: () => ({
|
||||
isPrintService: false, // 打印服务是否启动
|
||||
printServiceTimer: false, // 打印服务定时器
|
||||
printServiceTimerCount: 0, // 打印服务定时器计数
|
||||
printServiceTimerMaxCount: 10, // 打印服务定时器最大计数
|
||||
showPrintNotService: false, // 是否显示重启软件,
|
||||
localDevices: [], // 本地打印机列表
|
||||
deviceNoteList: [], // 添加的打印机
|
||||
deviceLableList: [], // 添加的打印机
|
||||
labelList: [], // 要打印的队列数据
|
||||
printTimer: null,
|
||||
receiptList: [], // 小票队列数据
|
||||
receiptTimer: null,
|
||||
}),
|
||||
actions: {
|
||||
// 获取本地打印机和已添加的可以用打印机列表
|
||||
async init() {
|
||||
// 获取本地打印机
|
||||
ipcRenderer.send("getPrintList");
|
||||
ipcRenderer.on("printList", (event, arg) => {
|
||||
this.localDevices = arg;
|
||||
});
|
||||
|
||||
try {
|
||||
// 获取已添加的打印机
|
||||
const res = await printerList();
|
||||
this.deviceNoteList = res.records.filter(
|
||||
(item) => item.status && item.subType == "cash"
|
||||
);
|
||||
this.deviceLableList = res.records.filter(
|
||||
(item) => item.status && item.subType == "label"
|
||||
);
|
||||
console.log("打印队列初始化成功", {
|
||||
deviceNoteList: this.deviceNoteList,
|
||||
deviceLableList: this.deviceLableList,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("获取已添加的打印机列表失败", error);
|
||||
}
|
||||
|
||||
// 检测打印服务是否启动
|
||||
this.checkPrintService();
|
||||
},
|
||||
// 检测打印组件服务是否启动
|
||||
checkPrintService() {
|
||||
this.printServiceTimer = setInterval(() => {
|
||||
if (
|
||||
typeof LODOP !== "undefined" &&
|
||||
LODOP.webskt &&
|
||||
LODOP.webskt.readyState == 1
|
||||
) {
|
||||
// 准备好
|
||||
this.isPrintService = true;
|
||||
clearInterval(this.printServiceTimer);
|
||||
this.printServiceTimer = null;
|
||||
} else {
|
||||
this.printServiceTimerCount++;
|
||||
console.log("打印服务未启动", this.printServiceTimerCount);
|
||||
|
||||
if (this.printServiceTimerCount >= this.printServiceTimerMaxCount) {
|
||||
// 超过最大次数
|
||||
this.isPrintService = false;
|
||||
this.showPrintNotService = true;
|
||||
clearInterval(this.printServiceTimer);
|
||||
this.printServiceTimer = null;
|
||||
}
|
||||
}
|
||||
console.log("打印服务是否启动:", this.isPrintService);
|
||||
}, 1000);
|
||||
},
|
||||
// 检查本地打印机是否能正常使用
|
||||
checkLocalPrint(address) {
|
||||
let print = "";
|
||||
for (let item of this.localDevices) {
|
||||
if (item.name == address) {
|
||||
print = item;
|
||||
}
|
||||
}
|
||||
|
||||
if (!print.name) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
// 打印标签小票
|
||||
labelPrint(props) {
|
||||
const store = useUser();
|
||||
|
||||
if (
|
||||
this.deviceLableList.length &&
|
||||
this.checkLocalPrint(this.deviceLableList[0].address)
|
||||
) {
|
||||
let pids = this.deviceLableList[0].categoryList;
|
||||
let count = 0;
|
||||
let sum = 0;
|
||||
|
||||
props.carts.map((item) => {
|
||||
if (pids.some((el) => el == item.categoryId)) {
|
||||
for (let i = 0; i < item.number; i++) {
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
props.carts.map((item) => {
|
||||
if (pids.some((el) => el == item.categoryId)) {
|
||||
for (let i = 0; i < item.number; i++) {
|
||||
count++;
|
||||
this.labelList.push({
|
||||
outNumber: props.outNumber,
|
||||
name: item.name,
|
||||
skuName: item.skuName,
|
||||
masterId: props.orderInfo.tableName,
|
||||
deviceName: this.deviceLableList[0].address,
|
||||
createdAt: dayjs(props.createdAt).format("YYYY-MM-DD HH:mm:ss"),
|
||||
isPrint: false,
|
||||
count: `${count}/${sum}`,
|
||||
ticketLogo: store.shopInfo.ticketLogo,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log("this.labelList===", this.labelList);
|
||||
// return;
|
||||
|
||||
// 执行打印操作
|
||||
this.startLabelPrint();
|
||||
} else {
|
||||
console.log("标签打印:未在本机查询到打印机");
|
||||
}
|
||||
},
|
||||
// 开始打印标签数据
|
||||
startLabelPrint() {
|
||||
if (this.printTimer != null) return;
|
||||
this.printTimer = setInterval(() => {
|
||||
let item = "";
|
||||
if (!this.labelList.length) {
|
||||
clearInterval(this.printTimer);
|
||||
this.printTimer = null;
|
||||
} else {
|
||||
item = this.labelList[0];
|
||||
if (!item.isPrint) {
|
||||
ipcRenderer.send("printerTagSync", JSON.stringify(item));
|
||||
this.labelList[0].isPrint = true;
|
||||
this.labelList.splice(0, 1);
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
},
|
||||
// 添加小票打印队列数据
|
||||
pushReceiptData(props, isDevice = true) {
|
||||
// console.log("pushReceiptData===", props);
|
||||
if (!isDevice) {
|
||||
// 测试打印,无需校验本地打印机
|
||||
this.receiptList.push(props);
|
||||
this.startReceiptPrint();
|
||||
} else {
|
||||
if (
|
||||
this.deviceNoteList.length &&
|
||||
this.checkLocalPrint(this.deviceNoteList[0].address) &&
|
||||
this.isPrintService
|
||||
) {
|
||||
const store = useUser();
|
||||
props.deviceName = this.deviceNoteList[0].address;
|
||||
props.shop_name = store.shopInfo.shopName;
|
||||
props.loginAccount = store.userInfo.name;
|
||||
props.createdAt = dayjs(props.createdAt).format(
|
||||
"YYYY-MM-DD HH:mm:ss"
|
||||
);
|
||||
props.printTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
if (!props.orderInfo.masterId) {
|
||||
props.orderInfo.masterId = props.orderInfo.tableName;
|
||||
}
|
||||
props.orderInfo.outNumber = props.outNumber;
|
||||
if (!props.discountAmount) {
|
||||
props.discountAmount = props.amount;
|
||||
}
|
||||
|
||||
this.receiptList.push(props);
|
||||
this.startReceiptPrint();
|
||||
} else {
|
||||
console.log("订单小票:未在本机查询到打印机");
|
||||
}
|
||||
}
|
||||
},
|
||||
// 开始打印小票
|
||||
startReceiptPrint() {
|
||||
if (this.receiptTimer !== null) return;
|
||||
this.receiptTimer = setInterval(() => {
|
||||
if (!this.receiptList.length) {
|
||||
clearInterval(this.receiptTimer);
|
||||
this.receiptTimer = null;
|
||||
} else {
|
||||
receiptPrint(this.receiptList[0]);
|
||||
this.receiptList.splice(0, 1);
|
||||
}
|
||||
}, 2000);
|
||||
},
|
||||
// 打印交班小票
|
||||
printWork(data) {
|
||||
if (
|
||||
this.deviceNoteList.length &&
|
||||
this.checkLocalPrint(this.deviceNoteList[0].address)
|
||||
) {
|
||||
data.deviceName = this.deviceNoteList[0].address;
|
||||
lodopPrintWork(data);
|
||||
} else {
|
||||
console.log("交班小票:未在本机查询到打印机");
|
||||
}
|
||||
},
|
||||
// 打印订单发票
|
||||
printInvoice(data) {
|
||||
if (
|
||||
this.deviceNoteList.length &&
|
||||
this.checkLocalPrint(this.deviceNoteList[0].address)
|
||||
) {
|
||||
data.deviceName = this.deviceNoteList[0].address;
|
||||
invoicePrint(data);
|
||||
} else {
|
||||
console.log("订单发票:未在本机查询到打印机");
|
||||
}
|
||||
},
|
||||
// 打印退单小票
|
||||
printRefund(data) {
|
||||
if (
|
||||
this.deviceNoteList.length &&
|
||||
this.checkLocalPrint(this.deviceNoteList[0].address)
|
||||
) {
|
||||
data.deviceName = this.deviceNoteList[0].address;
|
||||
refundPrint(data);
|
||||
} else {
|
||||
console.log("退单小票:未在本机查询到打印机");
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { shopInfo_detail } from "@/api/account.js";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
|
||||
export const useShop = defineStore({
|
||||
id: "shopInfo",
|
||||
state: () => ({
|
||||
info: useStorage.get("shopInfo"),
|
||||
}),
|
||||
actions: {
|
||||
// 获取店铺信息
|
||||
async queryShopInfo() {
|
||||
try {
|
||||
const res = await shopInfo_detail();
|
||||
useStorage.set("shopInfo", res);
|
||||
this.info = useStorage.get("shopInfo");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
import _ from "lodash";
|
||||
import { defineStore } from "pinia";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import ReconnectingWebSocket from "reconnecting-websocket";
|
||||
import { useGoods } from "@/store/goods.js";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { getOrderByIdAjax, commOrderPrintData } from "@/utils/index.js";
|
||||
|
||||
export const useSocket = defineStore("socket", {
|
||||
state: () => ({
|
||||
online: false, // 在线状态
|
||||
ws: null, // websocket实例
|
||||
heartbeatTimer: null, // 心跳计时器
|
||||
orderList: [],
|
||||
orderListTimer: null,
|
||||
log: false,
|
||||
isPrinting: false,
|
||||
}),
|
||||
actions: {
|
||||
// 关闭ws
|
||||
close() {
|
||||
if (this.log) console.log("关闭ws");
|
||||
this.online = false;
|
||||
this.ws.close(1000);
|
||||
this.ws = null;
|
||||
this.clearHeartBeat();
|
||||
},
|
||||
wsReconnect: _.throttle(
|
||||
function () {
|
||||
if (this.ws.readyState == ReconnectingWebSocket.OPEN) return;
|
||||
this.ws.reconnect();
|
||||
// console.log("11111");
|
||||
},
|
||||
2000,
|
||||
{ leading: true, trailing: false }
|
||||
),
|
||||
cartInit() {
|
||||
const store = useUser();
|
||||
const goodsStore = useGoods();
|
||||
|
||||
this.ws.send(
|
||||
JSON.stringify({
|
||||
type: "cashier",
|
||||
account: `cashier_${store.shopInfo.id}`,
|
||||
operate_type: "init",
|
||||
shop_id: store.shopInfo.id,
|
||||
table_code:
|
||||
goodsStore.tableInfo.tableCode || useStorage.get("tableCode"),
|
||||
})
|
||||
);
|
||||
},
|
||||
// 初始化
|
||||
init(wsUrl = import.meta.env.VITE_API_WSS) {
|
||||
const store = useUser();
|
||||
const printStore = usePrint();
|
||||
const goodsStore = useGoods();
|
||||
|
||||
if (!store.shopInfo.id) return;
|
||||
|
||||
printStore.init();
|
||||
|
||||
if (this.ws == null) {
|
||||
if (this.log) console.log("创建新的ws连接");
|
||||
|
||||
const protocols = []; // 可选的子协议数组
|
||||
const options = {
|
||||
// 自动重新连接的选项(可选)
|
||||
connectionTimeout: 1000,
|
||||
maxRetries: 100,
|
||||
};
|
||||
this.ws = new ReconnectingWebSocket(wsUrl, protocols, options);
|
||||
} else {
|
||||
if (this.log) console.log("重新连接ws");
|
||||
this.wsReconnect();
|
||||
}
|
||||
|
||||
this.ws.addEventListener("open", (event) => {
|
||||
if (this.log) console.log("wss连接成功");
|
||||
this.online = true;
|
||||
// 清除心跳
|
||||
this.clearHeartBeat();
|
||||
if (this.log) console.log(this);
|
||||
this.cartInit();
|
||||
this.startheartbeat();
|
||||
});
|
||||
|
||||
this.ws.addEventListener("message", async (e) => {
|
||||
let data = JSON.parse(e.data);
|
||||
if (data.operate_type == "init") {
|
||||
// console.log("接收消息", data);
|
||||
if (!goodsStore.tableInfo.tableCode) {
|
||||
useStorage.set("tableCode", data.table_code);
|
||||
}
|
||||
goodsStore.getCartList(data.data);
|
||||
}
|
||||
|
||||
this.ws.send(
|
||||
JSON.stringify({
|
||||
type: "receipt",
|
||||
msg_id: data.msg_id,
|
||||
})
|
||||
);
|
||||
|
||||
if (data.data_type == "cart") {
|
||||
if (data.status == 1) {
|
||||
// 返回成功状态
|
||||
switch (data.operate_type) {
|
||||
case "add":
|
||||
// 添加购物车商品
|
||||
goodsStore.successAddCart(data.data);
|
||||
break;
|
||||
case "edit":
|
||||
// 编辑购物车商品
|
||||
goodsStore.successEditCart(data.data);
|
||||
break;
|
||||
case "del":
|
||||
// 删除购物车商品
|
||||
if (data.type && data.type == "bc") {
|
||||
goodsStore.successDeleteCartItem(data.data);
|
||||
} else {
|
||||
goodsStore.successDeleteCartItem();
|
||||
}
|
||||
break;
|
||||
case "cleanup":
|
||||
// 清空购物车
|
||||
if (
|
||||
data.data.table_code == goodsStore.orderListInfo.tableCode &&
|
||||
!data.type
|
||||
)
|
||||
return;
|
||||
goodsStore.successClearCart();
|
||||
break;
|
||||
case "batch":
|
||||
// 整单打包
|
||||
this.cartInit();
|
||||
break;
|
||||
case "rottable":
|
||||
// 转桌
|
||||
useStorage.set("tableCode", data.data.new_table_code);
|
||||
goodsStore.successClearCart();
|
||||
goodsStore.historyOrderAjax(data.data.new_table_code);
|
||||
this.cartInit();
|
||||
break;
|
||||
case "clearOrder":
|
||||
// 清空订单或删除订单
|
||||
goodsStore.historyOrderAjax(data.data.table_code);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (data.type == "no_suit_num") {
|
||||
let product = goodsStore.cartList[goodsStore.cartActiveIndex];
|
||||
ElMessage.error(
|
||||
`${product.product_name}库存不足,已删除,请选择其他商品`
|
||||
);
|
||||
goodsStore.operateCart(product, "del");
|
||||
} else {
|
||||
ElMessage.error(data.msg || "操作失败");
|
||||
}
|
||||
}
|
||||
} else if (data.data_type == "order") {
|
||||
// 收到订单消息,打印订单小票
|
||||
let orderInfo = data.data.split("_");
|
||||
let orderId = orderInfo[0]; // 订单ID
|
||||
let orderModel = orderInfo[1]; // 订单类型
|
||||
let orderStatus = orderInfo[2]; // 订单状态
|
||||
|
||||
let printList = useStorage.get("printList") || [];
|
||||
|
||||
if (goodsStore.orderListInfo.tableCode) {
|
||||
goodsStore.historyOrderAjax(goodsStore.orderListInfo.tableCode);
|
||||
}
|
||||
|
||||
// 防止重复打印
|
||||
if (!printList.some((el) => el == orderId) && orderStatus == 1) {
|
||||
printList.push(orderId);
|
||||
useStorage.set("printList", _.uniq(printList));
|
||||
|
||||
this.orderList.push(orderId);
|
||||
this.startPrintInterval();
|
||||
}
|
||||
} else if (data.data_type == "product_update") {
|
||||
// 商品更新
|
||||
this.updateGoods();
|
||||
}
|
||||
});
|
||||
|
||||
this.ws.addEventListener("error", () => {
|
||||
if (this.log) console.log("WebSocket连接发生错误");
|
||||
this.online = false;
|
||||
this.clearHeartBeat();
|
||||
});
|
||||
|
||||
this.ws.addEventListener("error", (e) => {
|
||||
if (this.log) console.log("ws关闭了", e);
|
||||
this.online = false;
|
||||
this.clearHeartBeat();
|
||||
});
|
||||
},
|
||||
updateGoods: _.throttle(function () {
|
||||
const goodsStore = useGoods();
|
||||
goodsStore.updateGoodsList();
|
||||
}, 1000),
|
||||
// 启动心跳连接
|
||||
startheartbeat() {
|
||||
this.heartbeatTimer = setInterval(() => {
|
||||
if (this.log) console.log("发送心跳");
|
||||
this.ws.send(JSON.stringify({ type: "ping_interval", set: "cashier" }));
|
||||
}, 10000);
|
||||
},
|
||||
// 清除心跳
|
||||
clearHeartBeat() {
|
||||
// 清除心跳
|
||||
clearInterval(this.heartbeatTimer);
|
||||
this.heartbeatTimer = null;
|
||||
},
|
||||
// 打印队列开始执行
|
||||
startPrintInterval() {
|
||||
if (this.isPrinting) return; // 如果正在打印,直接返回
|
||||
this.isPrinting = true; // 标记为正在打印
|
||||
let printTime = 2000; // 定时器
|
||||
const printStore = usePrint();
|
||||
const printNextOrder = async () => {
|
||||
try {
|
||||
if (!this.orderList.length) {
|
||||
this.isPrinting = false; // 订单处理完,标记为不在打印
|
||||
return;
|
||||
}
|
||||
const orderInfo = await getOrderByIdAjax(this.orderList[0]);
|
||||
if (orderInfo.status == "done") {
|
||||
// 打印订单小票
|
||||
printStore.pushReceiptData(commOrderPrintData(orderInfo));
|
||||
// 打印标签小票
|
||||
printStore.labelPrint(commOrderPrintData(orderInfo));
|
||||
}
|
||||
this.orderList.splice(0, 1);
|
||||
// 递归调用打印下一个订单
|
||||
setTimeout(printNextOrder, printTime);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// 发生错误时继续尝试下一个订单
|
||||
// this.orderList.splice(0, 1);
|
||||
setTimeout(printNextOrder, printTime);
|
||||
}
|
||||
};
|
||||
// 开始打印第一个订单
|
||||
printNextOrder();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -1,13 +1,174 @@
|
|||
import { defineStore } from "pinia";
|
||||
export const useUserStore = defineStore({
|
||||
id: "user",
|
||||
import {
|
||||
login,
|
||||
shopStaffInfo,
|
||||
shopInfo_detail,
|
||||
logout,
|
||||
shopExtendDetail,
|
||||
shopPagePermissionMine,
|
||||
} from "@/api/account.js";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import { useSocket } from "@/store/socket.js";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
export const useUser = defineStore("user", {
|
||||
state: () => ({
|
||||
name: "张三",
|
||||
token: "sas121sasdADSAD",
|
||||
userInfo: useStorage.get("userInfo"),
|
||||
shopInfo: useStorage.get("shopInfo"),
|
||||
token: useStorage.get("token"),
|
||||
loginType: useStorage.get("loginType") || 0,
|
||||
menus: [
|
||||
{
|
||||
label: "收银",
|
||||
path: "/",
|
||||
state: 0,
|
||||
icon: "ShoppingCartFull",
|
||||
},
|
||||
],
|
||||
menuList: [
|
||||
{
|
||||
label: "台桌",
|
||||
path: "/table",
|
||||
icon: "Reading",
|
||||
},
|
||||
{
|
||||
label: "团购",
|
||||
path: "/group_buy",
|
||||
icon: "Handbag",
|
||||
},
|
||||
{
|
||||
label: "订单",
|
||||
path: "/order",
|
||||
icon: "Tickets",
|
||||
},
|
||||
{
|
||||
label: "会员",
|
||||
path: "/member",
|
||||
icon: "User",
|
||||
},
|
||||
{
|
||||
label: "排队",
|
||||
path: "/queue",
|
||||
icon: "Timer",
|
||||
},
|
||||
],
|
||||
route: null,
|
||||
router: null,
|
||||
}),
|
||||
actions: {
|
||||
login(data) {
|
||||
this.name = data;
|
||||
// 登录
|
||||
userlogin(param) {
|
||||
return login(param).then(async (res) => {
|
||||
this.token = res.tokenInfo.tokenValue;
|
||||
useStorage.set("token", this.token);
|
||||
|
||||
const logo = shopExtendDetail({ autoKey: "ticket_logo" });
|
||||
useStorage.set("shopInfo", {
|
||||
...res.shopInfo,
|
||||
ticketLogo: logo ? logo.value : "",
|
||||
});
|
||||
this.shopInfo = useStorage.get("shopInfo");
|
||||
useStorage.set("loginType", param.loginType);
|
||||
this.shopPagePermissionMineAjax(param.loginType);
|
||||
return await this.shopStaffInfo();
|
||||
});
|
||||
},
|
||||
// 初始化路由信息
|
||||
initRoute() {
|
||||
this.route = useRoute();
|
||||
this.router = useRouter();
|
||||
},
|
||||
// 获取当前员工已拥有页面路径
|
||||
async shopPagePermissionMineAjax(loginType = useStorage.get("loginType")) {
|
||||
try {
|
||||
if (this.route == null) {
|
||||
this.initRoute();
|
||||
}
|
||||
if (loginType == 0) {
|
||||
this.menus[0].state = 1;
|
||||
this.menus.push(...this.menuList);
|
||||
} else {
|
||||
const res = await shopPagePermissionMine();
|
||||
|
||||
let pathFlag = true;
|
||||
res.map((item) => {
|
||||
if (item.path == "/") {
|
||||
this.menus[0].state = 1;
|
||||
}
|
||||
|
||||
if (this.route.path != item.path) {
|
||||
pathFlag = false;
|
||||
}
|
||||
|
||||
this.menuList.map((menu) => {
|
||||
if (item.path === menu.path) {
|
||||
this.menus.push(menu);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
console.log("当前路由===", this.route);
|
||||
if (!pathFlag) {
|
||||
this.router.push("/");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("获取当前员工已拥有页面路径失败===", error);
|
||||
}
|
||||
},
|
||||
// 获取用户信息
|
||||
async shopStaffInfo() {
|
||||
try {
|
||||
const res = await shopStaffInfo();
|
||||
useStorage.set("userInfo", res);
|
||||
this.userInfo = useStorage.get("userInfo");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
// 更新店铺信息
|
||||
async getShopInfo() {
|
||||
try {
|
||||
const res = await shopInfo_detail();
|
||||
// 获取标签小票的logo
|
||||
const logo = await shopExtendDetail({ autoKey: "ticket_logo" });
|
||||
useStorage.set("shopInfo", {
|
||||
...res,
|
||||
ticketLogo: logo ? logo.value : "",
|
||||
});
|
||||
this.shopInfo = useStorage.get("shopInfo");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
// 退出登录
|
||||
async logout() {
|
||||
try {
|
||||
const socket = useSocket();
|
||||
await logout();
|
||||
socket.close();
|
||||
|
||||
useStorage.del("userInfo");
|
||||
useStorage.del("shopInfo");
|
||||
useStorage.del("token");
|
||||
useStorage.del("douyin");
|
||||
useStorage.del("categoryIndex");
|
||||
useStorage.del("tableCode");
|
||||
|
||||
this.userInfo = {};
|
||||
this.shopInfo = {};
|
||||
this.token = "";
|
||||
this.menus = [
|
||||
{
|
||||
label: "收银",
|
||||
path: "/",
|
||||
state: 0,
|
||||
icon: "ShoppingCartFull",
|
||||
},
|
||||
];
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,499 @@
|
|||
import { BigNumber } from "bignumber.js";
|
||||
import _ from "lodash";
|
||||
|
||||
/**
|
||||
* 返回商品单价
|
||||
* @param goods 商品
|
||||
* @param user 用户信息
|
||||
* @param {Object} shopInfo
|
||||
*/
|
||||
export function returnGoodsPrice(goods, user, shopInfo) {
|
||||
if (!goods) {
|
||||
return 0;
|
||||
}
|
||||
if (goods.discount_sale_amount * 1 > 0) {
|
||||
return goods.discount_sale_amount;
|
||||
}
|
||||
if (shopInfo && !shopInfo.isMemberPrice) {
|
||||
return goods.salePrice;
|
||||
}
|
||||
if (user.isVip && goods.memberPrice * 1 <= goods.salePrice * 1 && goods.memberPrice * 1 > 0) {
|
||||
return goods.memberPrice;
|
||||
}
|
||||
return goods.salePrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回商品分组
|
||||
* @param arr 商品列表
|
||||
*/
|
||||
export function returnGoodsGroupMap(arr) {
|
||||
let map = {};
|
||||
arr.forEach((v) => {
|
||||
const key = v.productId + "_" + v.skuId;
|
||||
if (!map[key]) {
|
||||
map[key] = [];
|
||||
}
|
||||
map[key].push(v);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠券类型:1-满减券,2-商品兑换券,3-折扣券,4-第二件半价券,5-消费送券,6-买一送一券,7-固定价格券,8-免配送费券
|
||||
* @param coupon
|
||||
*/
|
||||
export function returnCoupType(coupon) {
|
||||
const couponTypes = {
|
||||
1: "满减券",
|
||||
2: "商品券",
|
||||
3: "折扣券",
|
||||
4: "第二件半价券",
|
||||
5: "消费送券",
|
||||
6: "买一送一券",
|
||||
7: "固定价格券",
|
||||
8: "免配送费券",
|
||||
};
|
||||
return couponTypes[coupon.type] || "未知类型";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回商品券抵扣后的商品列表
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param selCoupon 已选择的优惠券列表
|
||||
* @param user 用户信息
|
||||
*/
|
||||
export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) {
|
||||
const types = [2, 4, 6];
|
||||
// 收集已抵扣商品并关联对应的优惠券类型
|
||||
const goodsCouponGoods = selCoupon
|
||||
.filter((v) => types.includes(v.type))
|
||||
.reduce((prev, cur) => {
|
||||
// 给每个抵扣商品添加所属优惠券类型
|
||||
const goodsWithType = cur.discount.hasDiscountGoodsArr.map((goods) => ({
|
||||
...goods,
|
||||
couponType: cur.type, // 记录该商品是被哪种类型的优惠券抵扣的
|
||||
}));
|
||||
prev.push(...goodsWithType);
|
||||
return prev;
|
||||
}, []);
|
||||
const arr = _.cloneDeep(canDikouGoodsArr)
|
||||
.map((v) => {
|
||||
const findCart = goodsCouponGoods.find((carts) => carts.id == v.id);
|
||||
if (findCart) {
|
||||
// 根据优惠券类型判断扣减数量
|
||||
if ([4, 6].includes(findCart.couponType)) {
|
||||
// 类型4(第二件半价)或6(买一送一),数量减2
|
||||
v.num -= 2;
|
||||
} else {
|
||||
// 其他类型(如类型2商品券),按原逻辑扣减对应数量
|
||||
v.num -= findCart.num;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
})
|
||||
.filter((v) => v.num > 0); // 过滤掉数量<=0的商品
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断优惠券是否可使用,并返回不可用原因
|
||||
*
|
||||
* @param {Object} args - 函数参数集合
|
||||
* @param {Array} args.canDikouGoodsArr - 可参与抵扣的商品列表
|
||||
* @param {Object} args.coupon - 优惠券信息对象
|
||||
* @param {boolean} args.coupon.use - 优惠券是否启用
|
||||
* @param {Array} args.coupon.useFoods - 优惠券适用的商品ID列表
|
||||
* @param {number} args.coupon.fullAmount - 优惠券使用门槛金额
|
||||
* @param {number} args.coupon.type - 优惠券类型
|
||||
* @param {number} args.goodsOrderPrice - 订单中所有商品的总金额
|
||||
* @param {Object} args.user - 用户信息对象
|
||||
* @param {Object} args.selCoupon - 已经选择的优惠券信息对象
|
||||
* @param {Object} args.shopInfo
|
||||
* @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因
|
||||
*/
|
||||
export function returnCouponCanUse(args) {
|
||||
let { canDikouGoodsArr, coupon, goodsOrderPrice, user, selCoupon, shopInfo } = args;
|
||||
// 优惠券未启用
|
||||
if (!coupon.use) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: coupon.noUseRestrictions || "不在可用时间段内",
|
||||
};
|
||||
}
|
||||
|
||||
// 计算门槛金额
|
||||
let fullAmount = goodsOrderPrice;
|
||||
canDikouGoodsArr = returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user, shopInfo);
|
||||
//优惠券指定门槛商品列表
|
||||
let canCalcGoodsArr = [...canDikouGoodsArr];
|
||||
//部分商品参与门槛计算
|
||||
if (coupon.thresholdFoods.length) {
|
||||
canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
|
||||
return coupon.thresholdFoods.find((food) => food.id == v.productId);
|
||||
});
|
||||
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
|
||||
return pre + returnGoodsPrice(cur, user, shopInfo) * cur.num;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// 是否全部商品可用
|
||||
const isDikouAll = coupon.useFoods.length === 0;
|
||||
// 订单可用商品列表
|
||||
let canUseGoodsArr = [];
|
||||
if (!isDikouAll) {
|
||||
canUseGoodsArr = canDikouGoodsArr.filter((v) => {
|
||||
return coupon.useFoods.find((food) => food.id == v.productId);
|
||||
});
|
||||
}
|
||||
if (user.isVip && !coupon.vipPriceShare) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "非会员可用",
|
||||
};
|
||||
}
|
||||
if (selCoupon.length > 0 && !selCoupon[0].otherCouponShare) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "当前选中的券不可与其他券同享",
|
||||
};
|
||||
}
|
||||
if (selCoupon.length > 0 && !coupon.otherCouponShare) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "当前选中的券不可与其他券同享",
|
||||
};
|
||||
}
|
||||
// 满减券和折扣券计算门槛金额是否满足
|
||||
if ([1, 3].includes(coupon.type)) {
|
||||
if (canCalcGoodsArr.length <= 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有可参与计算门槛的商品",
|
||||
};
|
||||
}
|
||||
// 不满足门槛金额
|
||||
if (fullAmount < coupon.fullAmount) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
}
|
||||
// 商品兑换券,第二件半价和买一送一判断是否有可用商品
|
||||
if ([2, 4, 5].includes(coupon.type)) {
|
||||
if (coupon.type == 2 && fullAmount < coupon.fullAmount) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
|
||||
// 没有符合条件的商品
|
||||
if (isDikouAll && canDikouGoodsArr.length === 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有符合条件的商品",
|
||||
};
|
||||
}
|
||||
if (!isDikouAll && canUseGoodsArr.length === 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有符合条件的商品",
|
||||
};
|
||||
}
|
||||
}
|
||||
//商品兑换券是否达到门槛金额
|
||||
if (coupon.type == 2 && goodsOrderPrice < coupon.fullAmount) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
|
||||
// 买一送一券特殊验证
|
||||
if (coupon.type === 6) {
|
||||
let canUse = false;
|
||||
if (isDikouAll) {
|
||||
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
|
||||
} else if (canUseGoodsArr.length > 0) {
|
||||
canUse = canUseGoodsArr.some((v) => v.num >= 2);
|
||||
}
|
||||
|
||||
if (!canUse) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "需要购买至少2件相同的商品才能使用",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 第二件半价券特殊验证
|
||||
if (coupon.type === 4) {
|
||||
let canUse = false;
|
||||
if (isDikouAll) {
|
||||
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
|
||||
} else if (canUseGoodsArr.length > 0) {
|
||||
canUse = canUseGoodsArr.some((v) => v.num >= 2);
|
||||
}
|
||||
if (!canUse) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "需要购买至少2件相同的商品才能使用",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 所有条件都满足
|
||||
return {
|
||||
canUse: true,
|
||||
reason: "",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算抵扣商品金额
|
||||
* @param discountGoodsArr 可抵扣商品列表
|
||||
* @param discountNum 抵扣数量
|
||||
* @param user 用户信息
|
||||
* @param {Object} shopInfo 店铺信息
|
||||
*/
|
||||
export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user, shopInfo) {
|
||||
let hasCountNum = 0;
|
||||
let discountPrice = 0;
|
||||
let hasDiscountGoodsArr = [];
|
||||
for (let i = 0; i < discountGoodsArr.length; i++) {
|
||||
if (hasCountNum >= discountNum) {
|
||||
break;
|
||||
}
|
||||
const goods = discountGoodsArr[i];
|
||||
const shengyuNum = discountNum - hasCountNum;
|
||||
const num = Math.min(goods.num, shengyuNum);
|
||||
discountPrice += returnGoodsPrice(goods, user, shopInfo) * num;
|
||||
|
||||
hasCountNum += num;
|
||||
hasDiscountGoodsArr.push({
|
||||
...goods,
|
||||
num,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
discountPrice,
|
||||
hasDiscountGoodsArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算优惠券抵扣金额
|
||||
* @param arr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param goodsOrderPrice 商品订单金额
|
||||
* @param selCoupon 已选择的优惠券列表
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
export function returnCouponDiscount(arr, coupon, user, goodsOrderPrice, selCoupon, shopInfo) {
|
||||
arr=returnCanDikouGoods(arr,user,shopInfo)
|
||||
const canDikouGoodsArr = returnCanDikouGoodsArr(arr, selCoupon, user);
|
||||
console.log('canDikouGoodsArr',canDikouGoodsArr)
|
||||
if (coupon.type == 2) {
|
||||
return returnCouponProductDiscount(canDikouGoodsArr, coupon, user, shopInfo);
|
||||
}
|
||||
if (coupon.type == 6) {
|
||||
const result = returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, shopInfo);
|
||||
return result;
|
||||
}
|
||||
if (coupon.type == 4) {
|
||||
return returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo);
|
||||
}
|
||||
if (coupon.type == 3) {
|
||||
return returnCouponZhekouDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice, selCoupon);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 折扣券抵扣金额
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param goodsOrderPrice 商品订单金额
|
||||
* @param selCoupon 已选择的优惠券列表
|
||||
*
|
||||
*/
|
||||
export function returnCouponZhekouDiscount(
|
||||
canDikouGoodsArr,
|
||||
coupon,
|
||||
user,
|
||||
goodsOrderPrice,
|
||||
selCoupon
|
||||
) {
|
||||
const { discountRate, maxDiscountAmount } = coupon;
|
||||
|
||||
// 计算商品优惠券折扣总和,使用BigNumber避免精度问题
|
||||
const goodsCouponDiscount = selCoupon
|
||||
.filter((v) => v.type == 2)
|
||||
.reduce((prve, cur) => {
|
||||
return new BigNumber(prve).plus(new BigNumber(cur.discount.discountPrice));
|
||||
}, new BigNumber(0));
|
||||
|
||||
// 将商品订单价格转换为BigNumber并减去优惠券折扣
|
||||
const adjustedGoodsOrderPrice = new BigNumber(goodsOrderPrice).minus(goodsCouponDiscount);
|
||||
|
||||
// 计算优惠比例:(100 - 折扣率) / 100
|
||||
const discountAmountRatio = new BigNumber(100).minus(discountRate).dividedBy(100);
|
||||
|
||||
// 计算折扣金额:调整后的商品订单金额 × 优惠比例
|
||||
let discountPrice = adjustedGoodsOrderPrice
|
||||
.times(discountAmountRatio)
|
||||
.decimalPlaces(2, BigNumber.ROUND_FLOOR)
|
||||
.toNumber();
|
||||
|
||||
// 应用最大折扣金额限制
|
||||
if (maxDiscountAmount !== 0) {
|
||||
discountPrice = discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
|
||||
}
|
||||
|
||||
return {
|
||||
discountPrice, // 折扣抵扣金额(即优惠的金额)
|
||||
hasDiscountGoodsArr: [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品券抵扣金额
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
export function returnCouponProductDiscount(canDikouGoodsArr, coupon, user, shopInfo) {
|
||||
const { useFoods, discountNum, useRule } = coupon;
|
||||
//抵扣商品数组
|
||||
let discountGoodsArr = [];
|
||||
//抵扣全部商品
|
||||
if (useFoods.length === 0) {
|
||||
if (useRule == "price_asc") {
|
||||
discountGoodsArr = canDikouGoodsArr.slice(discountNum * -1).reverse();
|
||||
} else {
|
||||
discountGoodsArr = canDikouGoodsArr.slice(0, discountNum);
|
||||
}
|
||||
} else {
|
||||
//抵扣选中商品
|
||||
const discountSelGoodsArr = canDikouGoodsArr.filter((v) =>
|
||||
useFoods.find((food) => food.id == v.productId)
|
||||
);
|
||||
if (useRule == "price_asc") {
|
||||
discountGoodsArr = discountSelGoodsArr.slice(discountNum * -1).reverse();
|
||||
} else {
|
||||
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
|
||||
}
|
||||
}
|
||||
const result = calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user, shopInfo);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 返回买一送一券抵扣详情
|
||||
/**
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, shopInfo) {
|
||||
const { useFoods, useRule } = coupon;
|
||||
//抵扣商品
|
||||
let discountGoods = undefined;
|
||||
//符合买一送一条件的商品
|
||||
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
|
||||
//抵扣全部商品
|
||||
if (useFoods.length === 0) {
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods[canUseGoods.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods[0];
|
||||
}
|
||||
} else {
|
||||
//符合抵扣条件的商品
|
||||
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId));
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods1[canUseGoods1.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods1[0];
|
||||
}
|
||||
}
|
||||
let discountPrice = 0;
|
||||
let hasDiscountGoodsArr = [];
|
||||
console.log("returnCouponBuyOneGiveOneDiscount:discountGoods", discountGoods);
|
||||
if (discountGoods) {
|
||||
discountPrice = returnGoodsPrice(discountGoods, user, shopInfo);
|
||||
hasDiscountGoodsArr = [discountGoods];
|
||||
}
|
||||
return {
|
||||
discountPrice: discountPrice <= 0 ? 0 : discountPrice,
|
||||
hasDiscountGoodsArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回第二件半价券抵扣详情
|
||||
* @param canDikouGoodsArr 可抵扣商品列表
|
||||
* @param coupon 优惠券
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
function returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo) {
|
||||
const { useFoods, useRule } = coupon;
|
||||
//抵扣商品
|
||||
let discountGoods = undefined;
|
||||
//符合条件的商品
|
||||
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
|
||||
//抵扣全部商品
|
||||
if (useFoods.length === 0) {
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods[canUseGoods.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods[0];
|
||||
}
|
||||
} else {
|
||||
//符合抵扣条件的商品
|
||||
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId));
|
||||
if (useRule == "price_asc") {
|
||||
discountGoods = canUseGoods1[canUseGoods1.length - 1];
|
||||
} else {
|
||||
discountGoods = canUseGoods1[0];
|
||||
}
|
||||
}
|
||||
let discountPrice = 0;
|
||||
let hasDiscountGoodsArr = [];
|
||||
if (discountGoods) {
|
||||
discountPrice = returnGoodsPrice(discountGoods, user, shopInfo);
|
||||
hasDiscountGoodsArr = [discountGoods];
|
||||
}
|
||||
//返回半价价格
|
||||
return {
|
||||
discountPrice: discountPrice <= 0 ? 0 : new BigNumber(discountPrice).dividedBy(2).toNumber(),
|
||||
hasDiscountGoodsArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回可以抵扣优惠券的商品列表,过滤掉赠品、临时商品,价格从高到低排序
|
||||
* @param arr 商品列表
|
||||
* @param user 用户信息
|
||||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
export function returnCanDikouGoods(arr, user, shopInfo) {
|
||||
const result = arr
|
||||
.filter((v) => {
|
||||
return v.is_temporary != 1 && v.is_gift != 1;
|
||||
})
|
||||
.filter((v) => {
|
||||
return v.num > 0;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return returnGoodsPrice(b, user, shopInfo) - returnGoodsPrice(a, user, shopInfo);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
import { getOrderById } from "@/api/order.js";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
/**
|
||||
* 生成范围随机数
|
||||
* @param {Object} Min
|
||||
* @param {Object} Max
|
||||
*/
|
||||
export function RandomNumBoth(Max, Min = 0) {
|
||||
var Range = Max - Min;
|
||||
var Rand = Math.random();
|
||||
var num = Min + Math.round(Rand * Range); //四舍五入
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除字符串中除了数字和点以外的其他字符
|
||||
* @param {Object} obj
|
||||
*/
|
||||
export function clearNoNum(obj) {
|
||||
// 如果用户第一位输入的是小数点,则重置输入框内容
|
||||
if (obj.value != "" && obj.value.substr(0, 1) == ".") {
|
||||
obj.value = "";
|
||||
}
|
||||
|
||||
// 去除数字前面多余的 0,但保留 0. 这种情况
|
||||
obj.value = obj.value.replace(/^0*(0\.|[1-9])/, "$1");
|
||||
|
||||
// 清除“数字”和“.”以外的字符
|
||||
obj.value = obj.value.replace(/[^\d.]/g, "");
|
||||
|
||||
// 只保留第一个. 清除多余的
|
||||
obj.value = obj.value.replace(/\.{2,}/g, ".");
|
||||
obj.value = obj.value
|
||||
.replace(".", "$#$")
|
||||
.replace(/\./g, "")
|
||||
.replace("$#$", ".");
|
||||
|
||||
// 只能输入两个小数
|
||||
obj.value = obj.value.replace(/^(\-)*(\d+)\.(\d\d).*$/, "$1$2.$3");
|
||||
|
||||
if (obj.value.indexOf(".") < 0 && obj.value != "") {
|
||||
// 以上已经过滤,此处控制的是如果没有小数点,首位不能为类似于 01、02 的金额
|
||||
if (obj.value.substr(0, 1) == "0" && obj.value.length == 2) {
|
||||
obj.value = obj.value.substr(1, obj.value.length);
|
||||
}
|
||||
}
|
||||
return obj.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保留小数n位,不进行四舍五入
|
||||
* num你传递过来的数字,
|
||||
* decimal你保留的几位,默认保留小数后两位
|
||||
* isInt 是否保留0
|
||||
*/
|
||||
export function formatDecimal(num, decimal = 2, isInt = false) {
|
||||
num = num.toFixed(3).toString();
|
||||
const index = num.indexOf(".");
|
||||
if (index !== -1) {
|
||||
num = num.substring(0, decimal + index + 1);
|
||||
} else {
|
||||
num = num.substring(0);
|
||||
}
|
||||
//截取后保留两位小数
|
||||
if (isInt) {
|
||||
return parseFloat(num);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将手机号中间四位替换为*号
|
||||
* @param {*} phone
|
||||
* @returns
|
||||
*/
|
||||
export function formatPhoneNumber(phone, isFormat = true) {
|
||||
if (isFormat) {
|
||||
return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
|
||||
} else {
|
||||
return phone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单详情
|
||||
* @param {*} orderId
|
||||
* @returns
|
||||
*/
|
||||
export async function getOrderByIdAjax(orderId) {
|
||||
try {
|
||||
if (!orderId) return;
|
||||
const res = await getOrderById({ orderId: orderId });
|
||||
|
||||
let arr = [];
|
||||
for (let key in res.detailMap) {
|
||||
arr.push(res.detailMap[key]);
|
||||
}
|
||||
|
||||
arr = arr.flat();
|
||||
arr.map((item) => {
|
||||
if (item.productType == "package" && item.proGroupInfo) {
|
||||
item.proGroupInfo = JSON.parse(item.proGroupInfo).flat();
|
||||
}
|
||||
});
|
||||
res.cartList = arr;
|
||||
return Promise.resolve(res);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将订单小票打印的数据组合起来
|
||||
* @param {*} orderDetail
|
||||
*/
|
||||
export function commOrderPrintData(orderInfo) {
|
||||
const userStore = useUser();
|
||||
let data = {
|
||||
isBefore: orderInfo.isBefore || false,
|
||||
shop_name: userStore.shopInfo.shopName,
|
||||
loginAccount: userStore.userInfo.name,
|
||||
carts: [],
|
||||
amount: formatDecimal(+orderInfo.payAmount),
|
||||
originAmount: formatDecimal(+orderInfo.originAmount),
|
||||
discountAmount:
|
||||
orderInfo.status == "unpaid"
|
||||
? "0.00"
|
||||
: formatDecimal(orderInfo.originAmount - orderInfo.orderAmount),
|
||||
discount: orderInfo.discountRatio,
|
||||
remark: orderInfo.remark,
|
||||
orderInfo: orderInfo,
|
||||
outNumber: orderInfo.tableCode,
|
||||
createdAt: orderInfo.createTime,
|
||||
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
};
|
||||
|
||||
orderInfo.cartList.map((item) => {
|
||||
data.carts.push({
|
||||
categoryId: item.categoryId,
|
||||
name: item.productName,
|
||||
number: item.num,
|
||||
skuName: item.skuName,
|
||||
salePrice: formatDecimal(+item.price),
|
||||
totalAmount: formatDecimal(+item.payAmount),
|
||||
proGroupInfo: item.proGroupInfo
|
||||
? item.proGroupInfo.map((item) => item.goods).flat()
|
||||
: "",
|
||||
});
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验手机号
|
||||
* @param {*} phone
|
||||
* @returns
|
||||
*/
|
||||
export function regPhone(phone) {
|
||||
let reg = /^(?:(?:\+|00)86)?1\d{10}$/;
|
||||
return reg.test(phone);
|
||||
}
|
||||
|
|
@ -1,8 +1,76 @@
|
|||
import axios from "axios";
|
||||
import { ElMessage } from "element-plus";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import router from "@/router";
|
||||
|
||||
const request = axios.create({
|
||||
baseURL: "http://localhost",
|
||||
timeout: 100000,
|
||||
const service = axios.create({
|
||||
baseURL:
|
||||
import.meta.env.MODE == "development"
|
||||
? "/api/"
|
||||
: import.meta.env.VITE_API_URL,
|
||||
// withCredentials: true, // 跨域请求时发送 cookies
|
||||
timeout: 20000, // 请求超时
|
||||
});
|
||||
|
||||
request.interceptors.request.use((config) => {});
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
// 在发送请求之前做些什么 token
|
||||
config.headers["platformType"] = "PC";
|
||||
if (useStorage.get("token")) {
|
||||
// 让每个请求携带 token
|
||||
// ['X-Token'] 是自定义标题键
|
||||
// 请根据实际情况修改
|
||||
config.headers["token"] = useStorage.get("token");
|
||||
if (useStorage.get("shopInfo") && useStorage.get("shopInfo").id) {
|
||||
config.headers["shopId"] = useStorage.get("shopInfo").id;
|
||||
}
|
||||
// config.headers["loginName"] = useStorage.get("userInfo").loginName;
|
||||
// config.headers['Content-Type'] = 'application/json'
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 处理请求错误
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
// 对响应数据做点什么
|
||||
if (+response.status === 200) {
|
||||
if (+response.data.code == 200) {
|
||||
return response.data.data;
|
||||
} else if (+response.data.code == 501) {
|
||||
useStorage.del("token");
|
||||
useStorage.del("userInfo");
|
||||
useStorage.del("shopInfo");
|
||||
useStorage.del("douyin");
|
||||
ElMessage.error("登录已过期,请重新登录");
|
||||
window.location.reload();
|
||||
return Promise.reject("登录已过期,请重新登录");
|
||||
} else {
|
||||
// 响应错误
|
||||
ElMessage.error(response.data.msg);
|
||||
return Promise.reject(response.data);
|
||||
}
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// 对响应错误做点什么
|
||||
if (error.message.indexOf("timeout") != -1) {
|
||||
ElMessage.error("网络超时");
|
||||
} else if (error.message == "Network Error") {
|
||||
ElMessage.error("网络连接错误");
|
||||
} else {
|
||||
console.log(error);
|
||||
if (error.response.data) ElMessage.error(error.response.statusText);
|
||||
else ElMessage.error("接口路径找不到");
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default service;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
import axios from "axios";
|
||||
import { ElMessage } from "element-plus";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import router from "@/router";
|
||||
|
||||
const service = axios.create({
|
||||
baseURL:
|
||||
import.meta.env.MODE == "development"
|
||||
? "/kp/"
|
||||
: import.meta.env.VITE_API_KP_URL,
|
||||
// withCredentials: true, // 跨域请求时发送 cookies
|
||||
timeout: 5000, // 请求超时
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
// 在发送请求之前做些什么 token
|
||||
config.headers["pctoken"] = useStorage.get("token");
|
||||
config.headers["ispc"] = 1;
|
||||
config.headers["loginName"] = useStorage.get("userInfo").loginName;
|
||||
config.headers["clientType"] = "pc";
|
||||
config.headers["shopId"] = useStorage.get("userInfo").shopId;
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 处理请求错误
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
// 对响应数据做点什么
|
||||
if (+response.status === 200) {
|
||||
if (+response.data.code == 1) {
|
||||
return response.data.data;
|
||||
} else {
|
||||
// 响应错误
|
||||
ElMessage.error(response.data.msg);
|
||||
return Promise.reject(response.data);
|
||||
}
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// 对响应错误做点什么
|
||||
if (error.message.indexOf("timeout") != -1) {
|
||||
ElMessage.error("网络超时");
|
||||
} else if (error.message == "Network Error") {
|
||||
ElMessage.error("网络连接错误");
|
||||
} else {
|
||||
console.log(error);
|
||||
if (error.response.data) ElMessage.error(error.response.statusText);
|
||||
else ElMessage.error("接口路径找不到");
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default service;
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
import axios from "axios";
|
||||
import { ElMessage } from "element-plus";
|
||||
import useStorage from "@/utils/useStorage";
|
||||
import router from "@/router";
|
||||
|
||||
const service = axios.create({
|
||||
baseURL:
|
||||
import.meta.env.MODE == "development"
|
||||
? "/php/"
|
||||
: import.meta.env.VITE_API_PHP_URL,
|
||||
// withCredentials: true, // 跨域请求时发送 cookies
|
||||
timeout: 5000, // 请求超时
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
// 在发送请求之前做些什么 token
|
||||
if (useStorage.get("douyin") && useStorage.get("douyin").token) {
|
||||
config.headers["bausertoken"] = useStorage.get("douyin").token;
|
||||
// config.headers['Content-Type'] = 'application/json'
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 处理请求错误
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
// 对响应数据做点什么
|
||||
if (+response.status === 200) {
|
||||
if (+response.data.code == 1) {
|
||||
return response.data.data;
|
||||
} else {
|
||||
// 响应错误
|
||||
ElMessage.error(response.data.msg);
|
||||
return Promise.reject(response.data);
|
||||
}
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// 对响应错误做点什么
|
||||
if (error.message.indexOf("timeout") != -1) {
|
||||
ElMessage.error("网络超时");
|
||||
} else if (error.message == "Network Error") {
|
||||
ElMessage.error("网络连接错误");
|
||||
} else {
|
||||
console.log(error);
|
||||
if (error.response.data) ElMessage.error(error.response.statusText);
|
||||
else ElMessage.error("接口路径找不到");
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default service;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
export default {
|
||||
get(key) {
|
||||
return JSON.parse(localStorage.getItem(key))
|
||||
},
|
||||
set(key, value) {
|
||||
localStorage.setItem(key, JSON.stringify(value))
|
||||
},
|
||||
del(key) {
|
||||
localStorage.removeItem(key)
|
||||
},
|
||||
clear() {
|
||||
localStorage.clear()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
<template>
|
||||
<div class="device_container" v-loading="requestLoading">
|
||||
<div class="header" @click="router.back()">
|
||||
<el-icon style="position: relative; top: 2px; margin-right: 4px" size="22">
|
||||
<ArrowLeft />
|
||||
</el-icon>
|
||||
<el-text>{{ form.id ? "编辑小票打印机" : "添加小票打印机" }}</el-text>
|
||||
</div>
|
||||
<div class="d_content">
|
||||
<div class="d_list">
|
||||
<el-form :model="form" label-position="left" label-width="60%">
|
||||
<el-form-item label="设备名称">
|
||||
<el-input v-model="form.name" placeholder="请输入设备名称"></el-input>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="打印机品牌">
|
||||
<el-input v-model="form.contentType" placeholder="请输入打印机品牌"></el-input>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="设备尺寸">
|
||||
<el-select v-model="form.receiptSize">
|
||||
<el-option label="58mm" value="58mm"></el-option>
|
||||
<el-option label="80mm" value="80mm"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备类型">
|
||||
<el-select v-model="form.connectionType">
|
||||
<el-option label="USB" value="USB"></el-option>
|
||||
<!-- <el-option label="网络" value="network"></el-option> -->
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择设备">
|
||||
<el-select v-model="form.address">
|
||||
<el-option :label="item.name" :value="item.name" v-for="item in printList" :key="item.name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="打印份数">
|
||||
<el-select v-model="form.printQty">
|
||||
<el-option :label="item" :value="item" v-for="item in 4" :key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品模式">
|
||||
<el-select v-model="form.config.model">
|
||||
<el-option label="普通出单" value="normal"></el-option>
|
||||
<el-option label="分类出单" value="category"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="打印子订单">
|
||||
<el-select v-model="form.config.printSub">
|
||||
<el-option label="是" :value="0"></el-option>
|
||||
<el-option label="否" :value="1"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="自动切刀">
|
||||
<el-select v-model="form.config.autoCut">
|
||||
<el-option label="是" :value="1"></el-option>
|
||||
<el-option label="否" :value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="尾部留空">
|
||||
<el-select v-model="form.config.feet">
|
||||
<el-option :label="`${item}行`" :value="`${item}`" v-for="item in feets" :key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="menu_wrap">
|
||||
<div class="print_view">
|
||||
<div class="title t1">{{ printData.shop_name }}</div>
|
||||
<div class="title t2">
|
||||
预结算单 <span style="margin-left: 6px;">#{{ printData.orderInfo.orderNum }}</span>
|
||||
</div>
|
||||
<div class="title t2" style="margin-bottom: 20px;">
|
||||
桌号:无
|
||||
</div>
|
||||
<div class="row">订单号:{{ printData.orderInfo.orderNo }}</div>
|
||||
<div class="row">交易时间:{{ printData.createdAt }}</div>
|
||||
<div class="row">收银员:{{ printData.loginAccount }}</div>
|
||||
<div class="line"></div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td>品名</td>
|
||||
<td>单价</td>
|
||||
<td>数量</td>
|
||||
<td>小计</td>
|
||||
</tr>
|
||||
<tr v-for="(item, index) in printData.carts" :key="index">
|
||||
<td>
|
||||
<div>{{ item.name }}</div>
|
||||
<div class="sku">{{ item.skuName }}</div>
|
||||
</td>
|
||||
<td>{{ item.salePrice }}</td>
|
||||
<td>{{ item.number }}</td>
|
||||
<td>{{ item.totalAmount }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="line"></div>
|
||||
<div class="row between">
|
||||
<span>原价:</span>
|
||||
<span>{{ printData.originAmount }}</span>
|
||||
</div>
|
||||
<div class="row between">
|
||||
<span>折扣:</span>
|
||||
<span>-0.00</span>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row between" style="font-size: 24px;">
|
||||
<span>实付:</span>
|
||||
<span>¥{{ printData.amount }}</span>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row" style="font-weight: bold;">备注:{{ printData.remark }}</div>
|
||||
<div class="row" style="font-size: 14px;">打印时间:{{ printData.printTime }}</div>
|
||||
</div>
|
||||
<div class="btn_wrap">
|
||||
<div class="btn">
|
||||
<el-button plain style="width: 100%" :loading="printDataLoading" @click="printHandle">
|
||||
打印测试小票
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="submitHandle">
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import dayjs from "dayjs";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { onMounted, reactive, ref } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { printerAdd, printerDetail } from "@/api/account.js";
|
||||
|
||||
const printStore = usePrint();
|
||||
const store = useUser();
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const printList = ref([]);
|
||||
const feets = ref([0, 1, 2, 3, 4, 5, 8]);
|
||||
const loading = ref(false);
|
||||
const requestLoading = ref(false);
|
||||
const form = ref({
|
||||
id: "",
|
||||
name: '', // 设备名称
|
||||
connectionType: 'USB', // 现在打印机支持USB 和 网络、蓝牙
|
||||
address: '', // 打印机名称
|
||||
port: '', // 端口
|
||||
subType: 'cash', // 打印类型(分类)label标签cash小票kitchen出品
|
||||
contentType: '', // 打印机品牌
|
||||
categoryIds: [], // 打印分类Id
|
||||
categoryList: [], // 分类
|
||||
sort: '',
|
||||
receiptSize: '58mm', // 小票尺寸 58mm 80mm
|
||||
classifyPrint: 1, // 分类打印 0-所有 1-部分分类 2-部分商品
|
||||
printQty: '', // 打印数量 c1m1^2 = 顾客+商家[2张] m1^1 = 商家[1张] c1^1顾客[1张] c2m1^3顾客2+商家1[3张]
|
||||
printMethod: 'all', // 打印方式 all-全部打印 normal-仅打印结账单「前台」one-仅打印制作单「厨房」queue-仅打印排队取号
|
||||
printType: [], // 打印类型,JSON数组 refund-确认退款单 handover-交班单 queue-排队取号
|
||||
status: 1
|
||||
});
|
||||
|
||||
const printDataLoading = ref(false);
|
||||
const printData = reactive({
|
||||
shop_name: '',
|
||||
loginAccount: '',
|
||||
isBefore: true,
|
||||
carts: [
|
||||
{
|
||||
id: 1,
|
||||
name: "【测试勿管】娃哈哈矿泉水",
|
||||
skuName: "500ml",
|
||||
salePrice: "1.0",
|
||||
number: "10",
|
||||
totalAmount: "10",
|
||||
},
|
||||
],
|
||||
amount: "10.00",
|
||||
originAmount: '10.00',
|
||||
discountAmount: "0.00",
|
||||
discount: 0,
|
||||
remark: "给我多放点辣椒,谢谢老板",
|
||||
orderInfo: {
|
||||
masterId: "",
|
||||
orderNo: "202404021023542223445",
|
||||
orderNum: '12'
|
||||
},
|
||||
deviceName: "",
|
||||
createdAt: "2024-04-02 10:15",
|
||||
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
});
|
||||
|
||||
// 获取打印机列表
|
||||
function getPrintList() {
|
||||
ipcRenderer.send("getPrintList");
|
||||
ipcRenderer.on("printList", (event, arg) => {
|
||||
printList.value = arg;
|
||||
});
|
||||
}
|
||||
|
||||
// 测试打印
|
||||
function printHandle() {
|
||||
if (!form.value.address) {
|
||||
ElMessage.error("请选择打印设备");
|
||||
return;
|
||||
}
|
||||
printDataLoading.value = true;
|
||||
printData.shop_name = store.shopInfo.shopName
|
||||
printData.loginAccount = store.userInfo.name
|
||||
printData.deviceName = form.value.address;
|
||||
printData.printTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
printStore.pushReceiptData(printData, false);
|
||||
setTimeout(() => {
|
||||
printDataLoading.value = false;
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
// 提交打印机
|
||||
async function submitHandle() {
|
||||
try {
|
||||
if (!form.value.name) {
|
||||
ElMessage.error("请输入设备名称");
|
||||
return;
|
||||
}
|
||||
if (!form.value.address) {
|
||||
ElMessage.error("请选择打印设备");
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
await printerAdd(form.value, form.value.id ? "put" : "post");
|
||||
ElMessage.success(form.value.id ? "编辑成功" : "添加成功");
|
||||
printStore.init();
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
// 查询打印机详情
|
||||
async function tbPrintMachineDetailAjax(id) {
|
||||
try {
|
||||
requestLoading.value = true;
|
||||
const res = await printerDetail({ id: id });
|
||||
form.value = res;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
requestLoading.value = false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
printData.shop_name = store.shopInfo.shopName
|
||||
printData.loginAccount = store.userInfo.name
|
||||
|
||||
getPrintList();
|
||||
if (route.query.id) {
|
||||
tbPrintMachineDetailAjax(route.query.id);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.device_container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
padding: 15px;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 50px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.d_content {
|
||||
padding-top: 15px;
|
||||
display: flex;
|
||||
height: calc(100vh - 15px * 2 - 50px);
|
||||
|
||||
.d_list {
|
||||
flex: 2;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.menu_wrap {
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
margin-left: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 0 15px;
|
||||
|
||||
.btn_wrap {
|
||||
display: flex;
|
||||
gap: var(--el-font-size-base);
|
||||
padding: var(--el-font-size-base) 0;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.print_view {
|
||||
flex: 1;
|
||||
padding: 20px 0;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 4px;
|
||||
|
||||
&.t1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-top: 2px;
|
||||
|
||||
&.between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.line {
|
||||
margin: 10px 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
|
||||
tr {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
td {
|
||||
flex: 1;
|
||||
|
||||
&:nth-child(1) {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.sku {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
<template>
|
||||
<div class="device_container" v-loading="requestLoading">
|
||||
<div class="header" @click="router.back()">
|
||||
<el-icon style="position: relative; top: 2px; margin-right: 4px" size="22">
|
||||
<ArrowLeft />
|
||||
</el-icon>
|
||||
<el-text>{{ form.id ? "编辑便签打印机" : "添加便签打印机" }}</el-text>
|
||||
</div>
|
||||
<div class="d_content">
|
||||
<div class="d_list">
|
||||
<el-form :model="form" label-position="left" label-width="60%">
|
||||
<el-form-item label="设备名称">
|
||||
<el-input v-model="form.name" placeholder="请输入设备名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备尺寸">
|
||||
<el-select v-model="form.receiptSize">
|
||||
<el-option label="58mm" value="58mm"></el-option>
|
||||
<el-option label="80mm" value="80mm"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备类型">
|
||||
<el-select v-model="form.connectionType">
|
||||
<el-option label="USB" value="USB"></el-option>
|
||||
<!-- <el-option label="网络" value="network"></el-option> -->
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择设备">
|
||||
<el-select v-model="form.address">
|
||||
<el-option :label="item.name" :value="item.name" v-for="item in printList" :key="item.name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类">
|
||||
<div style="cursor: pointer" @click="classifyRef.show()">
|
||||
<span style="color: #409eff" v-if="form.categoryList.length">
|
||||
{{form.categoryList.map(item => item.name).join(',')}}
|
||||
</span>
|
||||
<span style="color: #e65d6e" v-else>
|
||||
请选择分类
|
||||
</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="打印子订单">
|
||||
<el-select v-model="form.config.printSub">
|
||||
<el-option label="是" :value="0"></el-option>
|
||||
<el-option label="否" :value="1"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="自动切刀">
|
||||
<el-select v-model="form.config.autoCut">
|
||||
<el-option label="是" :value="1"></el-option>
|
||||
<el-option label="否" :value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="尾部留空">
|
||||
<el-select v-model="form.config.feet">
|
||||
<el-option
|
||||
:label="`${item}行`"
|
||||
:value="`${item}`"
|
||||
v-for="item in feets"
|
||||
:key="item"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="menu_wrap">
|
||||
<div class="print_view">
|
||||
<canvas class="ewm" ref="canvasRef"></canvas>
|
||||
<div class="header">
|
||||
<img class="logo" :src="printData.ticketLogo || logo" />
|
||||
<!-- <span class="title">双屿Pisces</span> -->
|
||||
</div>
|
||||
<div class="number_wrap">
|
||||
<!-- <div class="num" v-if="printData.outNumber">{{ printData.outNumber }}</div> -->
|
||||
<div class="info">座位号:{{ printData.masterId }}</div>
|
||||
</div>
|
||||
<div class="shop_info">
|
||||
<div class="name">{{ printData.name }}</div>
|
||||
<div class="text" v-if="printData.skuName">【{{ printData.skuName }}】</div>
|
||||
</div>
|
||||
<div class="time">{{ printData.createdAt }}</div>
|
||||
<div class="tips">建议尽快享用,风味更佳 {{ printData.count }}</div>
|
||||
</div>
|
||||
<div class="btn_wrap">
|
||||
<div class="btn">
|
||||
<el-button plain style="width: 100%" :loading="printLoading" @click="printHandle">
|
||||
打印测试小票
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" :loading="loading" @click="submitHandle">
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<classify ref="classifyRef" @success="(e) => (form.categoryList = e)" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import _ from 'lodash'
|
||||
import { ipcRenderer } from "electron";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { ElMessage, dayjs } from "element-plus";
|
||||
import { printerAdd, printerDetail } from "@/api/account.js";
|
||||
import { useUser } from "@/store/user.js";
|
||||
import classify from "@/components/classify/index.vue";
|
||||
import QRCode from 'qrcode'
|
||||
import { usePrint } from "@/store/print.js";
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import logo from '@/assets/prinnt_label_logo.png';
|
||||
|
||||
const goodsStore = useGoods()
|
||||
const printStore = usePrint();
|
||||
const store = useUser();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const printLoading = ref(false);
|
||||
const classifyRef = ref(null);
|
||||
const printList = ref([]);
|
||||
const feets = ref([0, 1, 2, 3, 4, 5, 8]);
|
||||
const loading = ref(false);
|
||||
const requestLoading = ref(false);
|
||||
const form = ref({
|
||||
id: "",
|
||||
name: '', // 设备名称
|
||||
connectionType: 'USB', // 现在打印机支持USB 和 网络、蓝牙
|
||||
address: '', // 打印机名称
|
||||
port: '', // 端口
|
||||
subType: 'label', // 打印类型(分类)label标签cash小票kitchen出品
|
||||
contentType: '', // 打印机品牌
|
||||
categoryIds: [], // 打印分类Id
|
||||
categoryList: [], // 分类
|
||||
sort: '',
|
||||
receiptSize: '58mm', // 小票尺寸 58mm 80mm
|
||||
classifyPrint: 1, // 分类打印 0-所有 1-部分分类 2-部分商品
|
||||
printQty: '', // 打印数量 c1m1^2 = 顾客+商家[2张] m1^1 = 商家[1张] c1^1顾客[1张] c2m1^3顾客2+商家1[3张]
|
||||
printMethod: 'all', // 打印方式 all-全部打印 normal-仅打印结账单「前台」one-仅打印制作单「厨房」queue-仅打印排队取号
|
||||
printType: [], // 打印类型,JSON数组 refund-确认退款单 handover-交班单 queue-排队取号
|
||||
status: 1
|
||||
});
|
||||
|
||||
const canvasRef = ref(null)
|
||||
const printData = ref({
|
||||
deviceName: '',
|
||||
outNumber: '123',
|
||||
name: '【测试勿管】甜橙马黛茶',
|
||||
skuName: '测试、加珍珠',
|
||||
masterId: '#A9',
|
||||
createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
ticketLogo: store.shopInfo.ticketLogo,
|
||||
})
|
||||
|
||||
// 获取打印机列表
|
||||
function getPrintList() {
|
||||
ipcRenderer.send("getPrintList");
|
||||
ipcRenderer.on("printList", (event, arg) => {
|
||||
printList.value = arg;
|
||||
});
|
||||
}
|
||||
|
||||
// 测试打印
|
||||
const printHandle = _.throttle(function () {
|
||||
if (!form.value.address) {
|
||||
ElMessage.error("请选择打印设备");
|
||||
return;
|
||||
}
|
||||
printLoading.value = true;
|
||||
printData.value.deviceName = form.value.address
|
||||
ipcRenderer.send(
|
||||
"printerTagSync",
|
||||
JSON.stringify(printData.value)
|
||||
);
|
||||
setTimeout(() => {
|
||||
printLoading.value = false;
|
||||
}, 2500);
|
||||
}, 1500, { leading: true, trailing: false })
|
||||
|
||||
// 提交打印机
|
||||
async function submitHandle() {
|
||||
try {
|
||||
if (!form.value.name) {
|
||||
ElMessage.error("请输入设备名称");
|
||||
return;
|
||||
}
|
||||
if (!form.value.address) {
|
||||
ElMessage.error("请选择打印设备");
|
||||
return;
|
||||
}
|
||||
if (!form.value.categoryList.length) {
|
||||
ElMessage.error("请选择商品分类");
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
form.value.categoryIds = form.value.categoryList.map(item => item.id)
|
||||
await printerAdd(form.value, form.value.id ? "put" : "post");
|
||||
loading.value = false;
|
||||
ElMessage.success(form.value.id ? "编辑成功" : "添加成功");
|
||||
printStore.init();
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 查询打印机详情
|
||||
async function tbPrintMachineDetailAjax() {
|
||||
try {
|
||||
requestLoading.value = true;
|
||||
const res = await printerDetail({ id: route.query.id });
|
||||
form.value = res;
|
||||
|
||||
let arr = []
|
||||
goodsStore.originCategoryList.map(item => {
|
||||
res.categoryList.map(val => {
|
||||
if (item.id == val) {
|
||||
arr.push({
|
||||
id: item.id,
|
||||
name: item.name
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
form.value.categoryList = arr
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
requestLoading.value = false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getPrintList();
|
||||
if (route.query.id) {
|
||||
tbPrintMachineDetailAjax(route.query.id);
|
||||
}
|
||||
|
||||
QRCode.toCanvas(canvasRef.value, printData.value.outNumber, function (error) {
|
||||
if (error) console.error(error)
|
||||
// console.log('success!');
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.device_container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
padding: 15px;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 50px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.d_content {
|
||||
padding-top: 15px;
|
||||
display: flex;
|
||||
height: calc(100vh - 15px * 2 - 50px);
|
||||
|
||||
.d_list {
|
||||
flex: 2;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.menu_wrap {
|
||||
flex: 1.5;
|
||||
margin-left: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 0 15px;
|
||||
|
||||
.print_view {
|
||||
position: relative;
|
||||
|
||||
.ewm {
|
||||
$size: 50px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.logo {
|
||||
$size: 90px;
|
||||
width: $size;
|
||||
height: 30px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.number_wrap {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
.num {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding-bottom: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.time {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.btn_wrap {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 20px 0;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import icon_dev1 from '@/assets/icon_dev1.png'
|
||||
import icon_dev2 from '@/assets/icon_dev2.png'
|
||||
import icon_dev3 from '@/assets/icon_dev3.png'
|
||||
export default {
|
||||
cash: icon_dev2,
|
||||
label: icon_dev1,
|
||||
kitchen: icon_dev3
|
||||
}
|
||||
|
|
@ -0,0 +1,315 @@
|
|||
<template>
|
||||
<div class="device_container">
|
||||
<div class="header" @click="router.back()">
|
||||
<el-icon style="position: relative; top: 2px; margin-right: 4px" size="22">
|
||||
<ArrowLeft />
|
||||
</el-icon>
|
||||
<el-text>设备管理</el-text>
|
||||
</div>
|
||||
<div class="d_content">
|
||||
<div class="d_list">
|
||||
<div class="row_title">打印设备</div>
|
||||
<div class="row_list">
|
||||
<div class="item" v-for="item in list" :key="item.id">
|
||||
<div class="left">
|
||||
<div class="icon">
|
||||
<el-image :src="icons[item.subType]" style="width: 40px; height: 40px"></el-image>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name">{{ item.name }}</div>
|
||||
<div class="xh">{{ item.address }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="switch">
|
||||
<el-switch v-model="item.status" inline-prompt active-text="开" inactive-text="关" :active-value="1"
|
||||
:inactive-value="0" width="90" @change="statusChange($event, item)" />
|
||||
</div>
|
||||
<div class="editor">
|
||||
<el-text type="primary" @click="
|
||||
router.push({
|
||||
name: deviceRoute[item.subType],
|
||||
query: { id: item.id },
|
||||
})
|
||||
">
|
||||
编辑
|
||||
</el-text>
|
||||
<el-text type="primary" @click="showDelete(item)">删除</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="row_title">云打印设备</div>
|
||||
<div class="row_list">
|
||||
<div class="item" v-for="item in list" :key="item.id">
|
||||
<div class="left">
|
||||
<div class="icon"></div>
|
||||
<div class="info">
|
||||
<div class="name">{{ item.name }}</div>
|
||||
<div class="xh">{{ item.xh }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="switch">
|
||||
<el-switch
|
||||
v-model="item.state"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
width="90"
|
||||
/>
|
||||
</div>
|
||||
<div class="editor">
|
||||
<el-text type="primary">编辑</el-text>
|
||||
<el-text type="primary">删除</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="menu_wrap">
|
||||
<div class="row" @click="router.push({ name: 'add_device' })">
|
||||
<div class="icon" style="background-color: var(--primary-color)">
|
||||
<el-image :src="icons.cash" style="width: 36px; height: 36px"></el-image>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name">添加小票打印机</div>
|
||||
<div class="intro">用来打印客户(收银)小票的打印机。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="router.push({ name: 'add_label' })">
|
||||
<div class="icon" style="background-color: #79c3d5">
|
||||
<el-image :src="icons.label" style="width: 38px; height: 38px"></el-image>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name">添加标签打印机</div>
|
||||
<div class="intro">用来打印商品标签的打印机。</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="row">
|
||||
<div class="icon" style="background-color: #8fc783">
|
||||
<el-image :src="icons.kitchen" style="width: 44px; height: 44px"></el-image>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name">添加出品打印机</div>
|
||||
<div class="intro">用来打印商品至厨房或出品台的打印机。</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="dialogVisible" title="注意" width="500">
|
||||
<span class="dialog_content">确定删除该打印机吗?</span>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="delLoading" @click="tbPrintMachineDeleteAjax">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { printerList, printerAdd } from '@/api/account.js'
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { ElMessage } from "element-plus";
|
||||
import icons from "./icons";
|
||||
import { usePrint } from "@/store/print.js";
|
||||
|
||||
const printStore = usePrint();
|
||||
|
||||
const router = useRouter();
|
||||
const list = ref([]);
|
||||
const dialogVisible = ref(false);
|
||||
const deleteId = ref("");
|
||||
const delLoading = ref(false);
|
||||
const deviceRoute = ref({
|
||||
cash: "add_device",
|
||||
label: "add_label",
|
||||
kitchen: "add_kitchen",
|
||||
});
|
||||
|
||||
async function statusChange(e, item) {
|
||||
try {
|
||||
await printerAdd(item, "put");
|
||||
tbPrintMachineGetAjax();
|
||||
printStore.init();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示删除打印机弹窗
|
||||
function showDelete(item) {
|
||||
deleteId.value = item.id;
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
// 删除打印机
|
||||
async function tbPrintMachineDeleteAjax() {
|
||||
try {
|
||||
delLoading.value = true;
|
||||
await printerAdd({ id: deleteId.value }, 'delete');
|
||||
dialogVisible.value = false;
|
||||
ElMessage.success("删除成功");
|
||||
tbPrintMachineGetAjax();
|
||||
printStore.init();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
delLoading.value = false;
|
||||
}
|
||||
|
||||
// 获取打印机列表
|
||||
async function tbPrintMachineGetAjax() {
|
||||
try {
|
||||
const res = await printerList();
|
||||
list.value = res.records;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
tbPrintMachineGetAjax();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dialog_content {
|
||||
font-size: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
padding: 0 var(--el-font-size-base) var(--el-font-size-base);
|
||||
}
|
||||
|
||||
.device_container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
padding: 15px;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 50px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.d_content {
|
||||
padding-top: 15px;
|
||||
display: flex;
|
||||
height: calc(100vh - 15px * 2 - 50px);
|
||||
|
||||
.d_list {
|
||||
flex: 2;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
padding: 15px;
|
||||
|
||||
.row_title {
|
||||
color: #555;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.row_list {
|
||||
.item {
|
||||
border-radius: 6px;
|
||||
background-color: #f1f1f1;
|
||||
margin-bottom: 10px;
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 15px;
|
||||
|
||||
.xh {
|
||||
color: #999;
|
||||
padding-top: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.editor {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu_wrap {
|
||||
flex: 1.5;
|
||||
margin-left: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 0 15px;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px 0;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.icon {
|
||||
--size: 60px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding-left: 15px;
|
||||
|
||||
.name {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.intro {
|
||||
color: #999;
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
<template>
|
||||
<el-dialog title="绑定门店" v-model="showDialog" width="80%">
|
||||
<div class="dialog">
|
||||
<div class="tips">注意:门店绑定后无法更改,请谨慎选择</div>
|
||||
<el-table :data="tableData.list" height="240px" border v-loading="tableData.loading">
|
||||
<el-table-column label="门店名称" prop="poi_name"></el-table-column>
|
||||
<el-table-column label="门店地址" prop="address"></el-table-column>
|
||||
<el-table-column label="操作" width="120px">
|
||||
<template v-slot="scope">
|
||||
<el-button type="primary" size="small"
|
||||
@click="bindShopHandle(scope.row.poi_id)">选择门店</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination">
|
||||
<el-pagination @current-change="paginationChange" :current-page="tableData.page"
|
||||
:page-size="tableData.size" layout="total, prev, pager, next, jumper" :total="tableData.total"
|
||||
background>
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { douyinstorelist, douyinbindstore } from '@/api/group.js'
|
||||
|
||||
const emits = defineEmits(['success'])
|
||||
|
||||
const showDialog = ref(false)
|
||||
|
||||
const tableData = reactive({
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
loading: false,
|
||||
list: []
|
||||
})
|
||||
|
||||
// 绑定门店
|
||||
async function bindShopHandle(poi_id) {
|
||||
try {
|
||||
await douyinbindstore({
|
||||
poi_id: poi_id
|
||||
})
|
||||
showDialog.value = false
|
||||
ElMessage.success('绑定成功')
|
||||
emits('success')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 分页变化
|
||||
function paginationChange(e) {
|
||||
tableData.page = e
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 获取门店列表
|
||||
async function getTableData() {
|
||||
try {
|
||||
tableData.loading = true
|
||||
const { list, count } = await douyinstorelist({
|
||||
page: tableData.page,
|
||||
size: tableData.size
|
||||
})
|
||||
tableData.loading = false
|
||||
tableData.list = list
|
||||
tableData.total = count
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示
|
||||
function show() {
|
||||
showDialog.value = true;
|
||||
getTableData()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tips {
|
||||
color: var(--el-color-danger);
|
||||
padding-bottom: 14px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
padding: 0 14px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
padding: 14px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
<template>
|
||||
<el-dialog title="退款" v-model="showDialog" width="400px" @close="reset">
|
||||
<el-form ref="refundFormRef" :model="refundForm" :rules="refundFormRules" label-position="top">
|
||||
<el-form-item label="退单数" prop="num">
|
||||
<el-select v-model="refundForm.num" placeholder="请选择退单数" style="width: 100%;" @change="refundNumChange">
|
||||
<el-option :label="item" :value="item" v-for="item in refundNumList" :key="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="退单金额">
|
||||
<el-input v-model="refundForm.refundAmount" disabled placeholder="请选择退单数"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="退款原因">
|
||||
<el-input v-model="refundForm.refundReason" type="textarea" placeholder="请输入退款原因"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="showDialog = false" style="width: 100%;">取消</el-button>
|
||||
<el-button type="primary" :loading="refundLoading" @click="refundConfirm" style="width: 100%;">确
|
||||
定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { returnGpOrder } from '@/api/group'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const emits = defineEmits(["success"]);
|
||||
|
||||
const newRow = ref('')
|
||||
const showDialog = ref(false)
|
||||
const refundLoading = ref(false)
|
||||
const refundFormRef = ref(null)
|
||||
const refundForm = reactive({
|
||||
num: '',
|
||||
orderId: '',
|
||||
refundAmount: '',
|
||||
refundDesc: '',
|
||||
refundReason: ''
|
||||
})
|
||||
|
||||
const refundFormRules = reactive({
|
||||
num: [
|
||||
{
|
||||
required: true,
|
||||
message: ' ',
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const refundNumList = ref([])
|
||||
|
||||
// 提交退单
|
||||
function refundConfirm() {
|
||||
refundFormRef.value.validate(async valid => {
|
||||
if (valid) {
|
||||
try {
|
||||
refundLoading.value = true
|
||||
const res = await returnGpOrder(refundForm)
|
||||
ElMessage.success('退单成功')
|
||||
refundLoading.value = false
|
||||
showDialog.value = false
|
||||
emits('succcess')
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
refundLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 计算退单金额
|
||||
function refundNumChange(e) {
|
||||
refundForm.refundAmount = Math.floor(newRow.value.orderAmount / newRow.value.number * e * 100) / 100
|
||||
}
|
||||
|
||||
// 显示
|
||||
function show(row) {
|
||||
showDialog.value = true;
|
||||
newRow.value = row
|
||||
let arr = []
|
||||
for (let i = 1; i <= row.number - row.refundNumber; i++) {
|
||||
arr.push(i)
|
||||
}
|
||||
refundNumList.value = arr
|
||||
refundForm.orderId = row.id
|
||||
}
|
||||
|
||||
// 初始化
|
||||
function reset() {
|
||||
newRow.value = ''
|
||||
refundNumList.value = []
|
||||
refundForm.orderId = ''
|
||||
for (let key in refundForm) {
|
||||
refundForm[key] = ''
|
||||
}
|
||||
refundFormRef.value.resetFields()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,525 @@
|
|||
<!-- 扫码弹窗 -->
|
||||
|
||||
<template>
|
||||
<div class="dialog">
|
||||
<el-dialog :title="`核销${props.title}团购券`" width="600" v-model="dialogVisible" @open="reset" @close="close">
|
||||
<div class="content">
|
||||
<div class="left">
|
||||
<el-image :src="icon" style="width: 60px; height: 60px"></el-image>
|
||||
</div>
|
||||
<div class="right" v-if="!userPayWait">
|
||||
<div class="amount">
|
||||
<span class="t">扫码核销</span>
|
||||
<!-- <span class="n">{{ props.amount }}</span> -->
|
||||
</div>
|
||||
<div class="input">
|
||||
<el-input ref="inputRef" v-model="scanCode"
|
||||
style="height: calc(var(--el-component-size-large) + 30px)" placeholder="请扫描团购券" clearable
|
||||
@change="inputChange"></el-input>
|
||||
<div class="tips">注意:扫码支付请保证输入框获得焦点,输入内容结束后会自动核销,请勿重复操作</div>
|
||||
</div>
|
||||
<!-- <div class="number_warp">
|
||||
<div class="item" v-for="item in 9" :key="item" @click="inputHandle(item)">{{ item }}</div>
|
||||
<div class="item disabled">.</div>
|
||||
<div class="item" @click="inputHandle(0)">0</div>
|
||||
<div class="item" @click="delHandle">
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" v-loading="loading">立即核销</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pay_wait" v-else>
|
||||
<div class="loading" v-loading="loading" element-loading-text="用户支付中..."></div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%" v-loading="checkPayStatusLoading"
|
||||
@click="checkPayStauts">
|
||||
<span v-if="!checkPayStatusLoading">查询用户支付状态</span>
|
||||
<span v-else>查询中...</span>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%" @click="resetScanCode">
|
||||
重新扫码
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog title="团购券详情" width="600" v-model="detailVisible">
|
||||
<div class="group_detil">
|
||||
<div class="shop_info" v-if="props.type == 1">
|
||||
<el-image :src="groupDetail.images[0]" style="width: 50px;height: 50px;"></el-image>
|
||||
<div class="info">
|
||||
<div class="name">{{ groupDetail.productName }}</div>
|
||||
<div class="price">
|
||||
<span class="p">¥{{ groupDetail.salePrice }}</span>
|
||||
<span class="o">¥{{ groupDetail.originPrice }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table">
|
||||
<el-table :data="groupDetail.productList" border v-if="props.type == 1">
|
||||
<el-table-column label="名称" prop="title"></el-table-column>
|
||||
<el-table-column label="数量" prop="number"></el-table-column>
|
||||
<el-table-column label="商品信息">
|
||||
<template v-slot="scope">
|
||||
<div class="shop_list">
|
||||
<div class="item" v-for="(item, index) in scope.row.goods" :key="item.id">
|
||||
<span class="dot"></span>
|
||||
<div class="name">
|
||||
<div class="t">{{ item.name }}</div>
|
||||
<div class="t">x{{ item.groupNum }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<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>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button style="width: 100%;" @click="detailVisible = false">取消</el-button>
|
||||
<el-button type="primary" style="width: 100%;" :loading="groupDetailLoading"
|
||||
@click="groupOrdergroupScanHandle">确认核销</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<BindShop ref="BindShopRef" @success="submitHandle()" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import _ from "lodash";
|
||||
import { ref } from "vue";
|
||||
import icon from "@/assets/icon_scan.png";
|
||||
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)
|
||||
const store = useUser();
|
||||
import {
|
||||
queryMembermember,
|
||||
createMembermember,
|
||||
membermemberScanPay,
|
||||
accountPaymember,
|
||||
} from "@/api/member/index.js";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import { useGlobal } from '@/store/global.js'
|
||||
const global = useGlobal()
|
||||
|
||||
const emits = defineEmits(["success"]);
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
type: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
});
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const scanCode = ref("");
|
||||
const inputRef = ref(null);
|
||||
|
||||
const loading = ref(false);
|
||||
const userPayWait = ref(false);
|
||||
const checkPayStatusLoading = ref(false);
|
||||
|
||||
const fastOrder = ref('')
|
||||
|
||||
const groupDetailLoading = ref(false)
|
||||
const groupDetail = ref({})
|
||||
const detailVisible = ref(false)
|
||||
|
||||
// 团购卷核销(仅核销待使用订单)
|
||||
async function groupOrdergroupScanHandle() {
|
||||
try {
|
||||
switch (props.type) {
|
||||
case 1:
|
||||
{
|
||||
groupDetailLoading.value = true
|
||||
const res = await groupOrdergroupScan({
|
||||
id: groupDetail.value.id
|
||||
})
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
let encrypted_codes = douyin_table.value.getSelectionRows()
|
||||
if (encrypted_codes.length) {
|
||||
groupDetailLoading.value = true
|
||||
let arr = encrypted_codes.map(item => item.encrypted_code)
|
||||
console.log(encrypted_codes);
|
||||
const res = await douyincertificateprepare({
|
||||
verify_token: groupDetail.value.verify_token,
|
||||
encrypted_codes: arr.join(','),
|
||||
id: groupDetail.value.id
|
||||
})
|
||||
} else {
|
||||
ElMessage.error('请选择核销项目')
|
||||
return
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
groupDetailLoading.value = false
|
||||
detailVisible.value = false
|
||||
scanCode.value = ''
|
||||
inputRef.value.focus();
|
||||
ElMessage.success('核销成功')
|
||||
emits('succcess')
|
||||
} catch (error) {
|
||||
console.log('groupOrdergroupScanHandle.error', error);
|
||||
}
|
||||
groupDetailLoading.value = false
|
||||
}
|
||||
|
||||
const douyin_table = ref(null)
|
||||
|
||||
// 核销券码
|
||||
async function submitHandle() {
|
||||
try {
|
||||
loading.value = true
|
||||
switch (props.type) {
|
||||
case 1:
|
||||
{
|
||||
const res = await groupOrderorderInfo({
|
||||
coupon: scanCode.value,
|
||||
});
|
||||
loading.value = false
|
||||
groupDetail.value = res
|
||||
detailVisible.value = true
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
const res = await douyinfulfilmentcertificateprepare({
|
||||
object_id: decodeURI(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;
|
||||
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;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('submitHandle.error', error);
|
||||
if (error.code == 4399) {
|
||||
BindShopRef.value.show()
|
||||
}
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
// 重新扫码
|
||||
function resetScanCode() {
|
||||
userPayWait.value = false;
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
inputRef.value.focus();
|
||||
}
|
||||
|
||||
// 输入
|
||||
function inputHandle(n) {
|
||||
scanCode.value += n;
|
||||
inputRef.value.focus();
|
||||
}
|
||||
|
||||
// 删除
|
||||
function delHandle() {
|
||||
if (!scanCode.value) return;
|
||||
scanCode.value = scanCode.value.substring(0, scanCode.value.length - 1);
|
||||
inputRef.value.focus();
|
||||
}
|
||||
|
||||
// 监听扫码枪回车事件
|
||||
// function enterHandle() {
|
||||
// inputRef.value.focus()
|
||||
// }
|
||||
|
||||
const inputChange = _.debounce(function (e) {
|
||||
// console.log(e);
|
||||
if (scanCode.value) {
|
||||
submitHandle();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
function show() {
|
||||
global.updateData(false)
|
||||
dialogVisible.value = true;
|
||||
setTimeout(() => {
|
||||
inputRef.value.focus();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function close() {
|
||||
global.updateData(true)
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
loading.value = false;
|
||||
scanCode.value = "";
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
close,
|
||||
loading,
|
||||
submitHandle
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.footer {
|
||||
display: flex;
|
||||
padding: 0 14px 14px;
|
||||
}
|
||||
|
||||
.group_detil {
|
||||
padding: 14px;
|
||||
|
||||
.shop_info {
|
||||
display: flex;
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
padding-left: 10px;
|
||||
|
||||
.name {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.price {
|
||||
.p {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.o {
|
||||
color: #999;
|
||||
text-decoration: line-through;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
padding-top: 14px;
|
||||
}
|
||||
|
||||
.shop_list {
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.dot {
|
||||
$size: 6px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
border-radius: 50%;
|
||||
background-color: #1890FF;
|
||||
}
|
||||
|
||||
.name {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
margin-left: 10px;
|
||||
align-items: center;
|
||||
|
||||
.t {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
width: 100px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.del {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tips {
|
||||
padding-top: 10px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.dialog :deep(.el-dialog__body) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
|
||||
.left {
|
||||
width: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #efefef;
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 1;
|
||||
padding: var(--el-font-size-base);
|
||||
|
||||
.amount {
|
||||
display: flex;
|
||||
height: calc(var(--el-component-size-large) + 20px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: var(--primary-color);
|
||||
background-color: #555;
|
||||
border-radius: 6px;
|
||||
padding: 0 var(--el-font-size-base);
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
}
|
||||
|
||||
.input {
|
||||
padding: var(--el-font-size-base) 0;
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.number_warp {
|
||||
--h: 50px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: var(--h) var(--h) var(--h) var(--h);
|
||||
gap: 8px;
|
||||
|
||||
.item {
|
||||
background-color: #dddddd;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(var(--el-font-size-base) + 10px);
|
||||
border-radius: 4px;
|
||||
|
||||
&.disabled {
|
||||
color: #999;
|
||||
background-color: #efefef;
|
||||
|
||||
&:active {
|
||||
background-color: #efefef;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #b9b9b9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .btn {
|
||||
// padding-top: 20px;
|
||||
// }
|
||||
}
|
||||
|
||||
.pay_wait {
|
||||
flex: 1;
|
||||
padding: 0 var(--el-font-size-base);
|
||||
height: 400px;
|
||||
padding-bottom: 100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.loading {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
--el-loading-spinner-size: 100px;
|
||||
|
||||
:deep(.el-loading-text) {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 200px;
|
||||
padding-top: var(--el-font-size-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,595 @@
|
|||
<template>
|
||||
<div class="content">
|
||||
<div class="cart_wrap card">
|
||||
<div class="header">
|
||||
<div class="left">
|
||||
<el-select v-model="tableData.type" placeholder="核销类型" @change="typeChange">
|
||||
<el-option v-for="item in typeList" :key="item.value" :value="item.value"
|
||||
:label="item.label"></el-option>
|
||||
</el-select>
|
||||
<el-input placeholder="搜索订单" v-model="tableData.proName" @focus="
|
||||
global.updateData(false)" @blur="global.updateData(true)"></el-input>
|
||||
<el-select v-model="tableData.status" placeholder="订单状态">
|
||||
<el-option v-for="item in statusList" :key="item.value" :value="item.value"
|
||||
:label="item.label"></el-option>
|
||||
</el-select>
|
||||
<div class="btn">
|
||||
<el-button type="primary" :icon="Search" @click="groupOrderlistAjax">搜索</el-button>
|
||||
<el-button :icon="RefreshRight" :loading="tableData.resetLoading"
|
||||
@click="resetHandle">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<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"
|
||||
v-if="tableData.type == 1">
|
||||
<el-table-column label="订单号" prop="orderNo" width="100px"></el-table-column>
|
||||
<el-table-column label="优惠卷" prop="proImg" width="200px">
|
||||
<template v-slot="scope">
|
||||
<div class="info_wrap">
|
||||
<el-image :src="scope.row.proImg" style="width: 40px;height: 40px;flex-shrink: 0;" />
|
||||
<div class="t">{{ scope.row.proName }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="支付方式" prop="payType">
|
||||
<template v-slot="scope">
|
||||
{{ payTypeFilter(scope.row.payType) }}
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column label="订单金额" prop="orderAmount">
|
||||
<template v-slot="scope">
|
||||
¥{{ scope.row.orderAmount }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="实付金额" prop="payAmount">
|
||||
<template v-slot="scope">
|
||||
¥{{ scope.row.payAmount }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="下单数量" prop="number">
|
||||
<template v-slot="scope">
|
||||
{{ scope.row.number }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" prop="status">
|
||||
<template v-slot="scope">
|
||||
{{ statusFilter(scope.row.status) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right">
|
||||
<template v-slot="scope">
|
||||
<el-button type="primary" size="small"
|
||||
v-if="scope.row.refundAble == 1 && scope.row.status == 'unused'"
|
||||
@click="refundDialogRef.show(scope.row)">退款</el-button>
|
||||
<el-button type="primary" size="small" disabled v-else>退款</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table :data="tableData.list" height="540px" v-loading="tableData.loading"
|
||||
v-if="tableData.type == 2">
|
||||
<el-table-column label="抖音订单号" prop="d_order_id" width="240"></el-table-column>
|
||||
<el-table-column label="总金额" prop="pay_amount">
|
||||
<template v-slot="scope">
|
||||
<span style="color: var(--primary-color);">¥{{ scope.row.pay_amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品信息" prop="douyinCodeGoods">
|
||||
<template v-slot="scope">
|
||||
<div class="goods_list">
|
||||
<div class="row" v-for="item in scope.row.douyinCodeGoods" :key="item.id">
|
||||
<div class="item" style="width: 240px;">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<div class="item" style="width: 100px;color: var(--primary-color);">
|
||||
¥{{ item.pay_amount }}
|
||||
</div>
|
||||
<div class="item"
|
||||
style="margin-right: 10px;display: flex;justify-content: flex-end;">
|
||||
<el-tag :type="typeStatus(item.status)" disable-transitions size="default"
|
||||
effect="light" round>
|
||||
{{ item.status_text }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="item" style="flex: 1;display: flex;justify-content: flex-end;">
|
||||
<el-button type="danger" size="small" v-if="item.is_show_cacel_banner"
|
||||
@click="cacelDouyinHandle(item)">撤销</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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"
|
||||
layout="total, prev, pager, next" :total="tableData.total" background
|
||||
@current-change="paginationChange" @size-change="paginationChange">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<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, 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'
|
||||
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'
|
||||
const global = useGlobal()
|
||||
|
||||
const scanGroupRef = ref(null)
|
||||
const refundDialogRef = ref(null)
|
||||
|
||||
function typeStatus(t) {
|
||||
const m = {
|
||||
0: 'warning',
|
||||
1: 'success',
|
||||
2: 'danger'
|
||||
}
|
||||
return m[t]
|
||||
}
|
||||
|
||||
const tableData = reactive({
|
||||
resetLoading: false,
|
||||
proName: '',
|
||||
type: 3,
|
||||
status: '',
|
||||
loading: false,
|
||||
list: [],
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 支付方式类型
|
||||
function payTypeFilter(t) {
|
||||
const m = {
|
||||
wechatPay: '微信支付',
|
||||
aliPay: '支付宝支付'
|
||||
}
|
||||
return m[t]
|
||||
}
|
||||
|
||||
// 订单类型
|
||||
const typeList = reactive([
|
||||
// {
|
||||
// value: 1,
|
||||
// label: '自营'
|
||||
// },
|
||||
{
|
||||
value: 2,
|
||||
label: '抖音'
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '美团'
|
||||
}
|
||||
])
|
||||
|
||||
// 本店团购订单状态
|
||||
const originStatus = [
|
||||
{
|
||||
value: 'unpaid',
|
||||
label: '待付款'
|
||||
},
|
||||
{
|
||||
value: 'unused',
|
||||
label: '待使用'
|
||||
},
|
||||
{
|
||||
value: 'closed',
|
||||
label: '已完成'
|
||||
},
|
||||
{
|
||||
value: 'refunding',
|
||||
label: '退款中'
|
||||
},
|
||||
{
|
||||
value: 'refund',
|
||||
label: '已退款'
|
||||
},
|
||||
{
|
||||
value: 'cancelled',
|
||||
label: '已取消'
|
||||
}
|
||||
]
|
||||
|
||||
// 抖音美团
|
||||
const dmStatus = [
|
||||
{
|
||||
value: 0,
|
||||
label: '等待验券'
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '成功'
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '失败'
|
||||
}
|
||||
]
|
||||
|
||||
const statusList = ref([])
|
||||
|
||||
// 切换筛选条件
|
||||
function typeChange(e) {
|
||||
switch (e) {
|
||||
case 1:
|
||||
statusList.value = [...originStatus]
|
||||
break;
|
||||
case 2:
|
||||
statusList.value = [...dmStatus]
|
||||
break;
|
||||
case 3:
|
||||
statusList.value = [...dmStatus]
|
||||
thirdPartyCoupon_state_ajax()
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tableData.status = ''
|
||||
tableData.page = 1
|
||||
tableData.list = []
|
||||
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
|
||||
}
|
||||
|
||||
// 分页变化
|
||||
function paginationChange(e) {
|
||||
groupOrderlistAjax()
|
||||
}
|
||||
|
||||
// 重置
|
||||
function resetHandle() {
|
||||
tableData.proName = ''
|
||||
tableData.status = ''
|
||||
tableData.page = 1
|
||||
tableData.resetLoading = true
|
||||
groupOrderlistAjax()
|
||||
}
|
||||
|
||||
// 显示团购核销撤销
|
||||
function cacelDouyinHandle(item) {
|
||||
ElMessageBox.confirm(
|
||||
'是否撤销该团购?',
|
||||
'注意').then(async () => {
|
||||
await douyinfulfilmentcertificatecancel({ verify_id: item.verify_id, certificate_id: item.certificate_id })
|
||||
ElMessage.success('撤销成功')
|
||||
groupOrderlistAjax()
|
||||
}).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 {
|
||||
tableData.loading = true
|
||||
let res = ''
|
||||
switch (tableData.type) {
|
||||
case 1:
|
||||
// 获取本店团购数据
|
||||
res = await groupOrderlist({
|
||||
shopId: store.userInfo.shopId,
|
||||
proName: tableData.proName,
|
||||
status: tableData.status,
|
||||
page: tableData.page,
|
||||
size: tableData.size
|
||||
})
|
||||
tableData.resetLoading = false
|
||||
tableData.loading = false
|
||||
tableData.list = res.list
|
||||
tableData.total = res.total
|
||||
break;
|
||||
case 2:
|
||||
// 获取抖音团购数据
|
||||
res = await douyinorderlist({
|
||||
page: tableData.page,
|
||||
status: tableData.status,
|
||||
d_order_id: tableData.proName
|
||||
})
|
||||
tableData.resetLoading = false
|
||||
tableData.loading = false
|
||||
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;
|
||||
}
|
||||
} catch (error) {
|
||||
tableData.loading = false
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
typeChange(tableData.type)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pagination {
|
||||
display: flex;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.info_wrap {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
.t {
|
||||
width: 100px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.cart_wrap {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.right_card {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
margin-left: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 14px;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #ececec;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.menus {
|
||||
display: flex;
|
||||
padding: 0 10px;
|
||||
|
||||
.item {
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
span {
|
||||
font-size: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
width: 70%;
|
||||
height: 4px;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 15%;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
span {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.all {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.tab_container {
|
||||
padding: 0 var(--el-font-size-base) var(--el-font-size-base);
|
||||
|
||||
.tab_head {
|
||||
padding-bottom: var(--el-font-size-base);
|
||||
}
|
||||
|
||||
.overflow_y {
|
||||
height: calc(100vh - 225px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.tab_list {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
grid-template-rows: auto;
|
||||
gap: var(--el-font-size-base);
|
||||
|
||||
.item {
|
||||
background-color: #efefef;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border: 2px solid #fff;
|
||||
|
||||
&.active {
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tab_title {
|
||||
height: var(--el-component-size-large);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
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 {
|
||||
height: 120px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
color: #555;
|
||||
font-size: 30px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.goods_list {
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,568 +0,0 @@
|
|||
<template>
|
||||
<div class="content">
|
||||
<div class="cart_wrap card">
|
||||
<div class="menu_top">
|
||||
<div class="menu">
|
||||
<el-icon class="icon">
|
||||
<TakeawayBox />
|
||||
</el-icon>
|
||||
<el-text class="t">(1)</el-text>
|
||||
</div>
|
||||
<div class="number">
|
||||
<el-text class="t">#2</el-text>
|
||||
</div>
|
||||
<div class="select_user">
|
||||
<el-icon class="icon">
|
||||
<UserFilled />
|
||||
</el-icon>
|
||||
<el-text class="t">选择会员</el-text>
|
||||
<el-icon class="arrow">
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shop_operation">
|
||||
<div class="shop_list">
|
||||
<div class="item" v-for="item in 3" :key="item">
|
||||
<div class="name_wrap">
|
||||
<span>鲜肉</span>
|
||||
<span>¥1.00</span>
|
||||
</div>
|
||||
<div class="sku_list">
|
||||
<div class="tag">默认1份</div>
|
||||
<div class="tag">热</div>
|
||||
<div class="tag">半糖</div>
|
||||
</div>
|
||||
<div class="num">
|
||||
<el-text>X1</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="operation_wrap">
|
||||
<div class="item">
|
||||
<el-icon class="icon">
|
||||
<SemiSelect />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item number">
|
||||
<el-text class="num">1</el-text>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-icon class="icon add">
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-icon class="icon">
|
||||
<Filter />
|
||||
</el-icon>
|
||||
<el-text class="t">规格</el-text>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-icon class="icon">
|
||||
<ShoppingBag />
|
||||
</el-icon>
|
||||
<el-text class="t">赠送</el-text>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-icon class="icon">
|
||||
<Box />
|
||||
</el-icon>
|
||||
<el-text class="t">打包</el-text>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-icon class="icon">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
<el-text class="t">删除</el-text>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-icon class="icon">
|
||||
<Sell />
|
||||
</el-icon>
|
||||
<el-text class="t">挂单</el-text>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-icon class="icon">
|
||||
<RefreshRight />
|
||||
</el-icon>
|
||||
<el-text class="t">清空</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<div class="selected">
|
||||
<el-icon class="icon">
|
||||
<CircleCheckFilled />
|
||||
</el-icon>
|
||||
</div>
|
||||
<el-text class="t">打包(¥0.00)</el-text>
|
||||
</div>
|
||||
<div class="num-wrap">
|
||||
<el-text>共6种商品,7件</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btm">
|
||||
<div class="editor">
|
||||
<el-icon>
|
||||
<Edit />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="button">
|
||||
<div class="js">
|
||||
<el-text class="t">¥3.09</el-text>
|
||||
<el-text class="t">结算</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shop_manage card">
|
||||
<div class="header">
|
||||
<div class="menus">
|
||||
<div class="item active">
|
||||
<el-text>全部</el-text>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-text>咖啡</el-text>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-text>测试</el-text>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-text>套餐</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<div class="all">
|
||||
<el-icon class="icon">
|
||||
<Menu />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search_wrap">
|
||||
<div class="input">
|
||||
<el-input placeholder="商品名称或首字母简称" prefix-icon="Search"></el-input>
|
||||
</div>
|
||||
<el-button :icon="shopListType == 'text' ? 'PictureRounded' : 'PriceTag'" @click="changeShopListType"></el-button>
|
||||
</div>
|
||||
<div class="shop_list" :class="{ img: shopListType == 'img' }">
|
||||
<div class="item_wrap" v-for="item in 7" :key="item">
|
||||
<div class="item">
|
||||
<div class="dot">2</div>
|
||||
<div class="cover" v-if="shopListType == 'img'">
|
||||
<el-image src="https://img1.baidu.com/it/u=2183780444,2807225961&fm=253&fmt=auto&app=138&f=JPEG?w=600&h=400"
|
||||
style="width: 100%;height: 100%;" fit="cover"></el-image>
|
||||
</div>
|
||||
<div class="name"><el-text>酱香拿铁</el-text></div>
|
||||
<div class="empty" v-if="shopListType == 'text'"></div>
|
||||
<div class="price">
|
||||
<el-text>¥0.03</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<skuModal />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import skuModal from '@/components/skuModal.vue'
|
||||
|
||||
import { ref } from 'vue'
|
||||
const shopListType = ref('text')
|
||||
|
||||
// 切换商品显示模式
|
||||
function changeShopListType() {
|
||||
if (shopListType.value == 'text') {
|
||||
shopListType.value = 'img'
|
||||
} else {
|
||||
shopListType.value = 'text'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.cart_wrap {
|
||||
width: 550px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.menu_top {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
height: 60px;
|
||||
$fs: 20px;
|
||||
|
||||
.menu {
|
||||
background-color: var(--el-color-warning);
|
||||
color: #fff;
|
||||
width: 100px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
font-size: 24px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.t {
|
||||
color: #fff;
|
||||
margin-left: 4px;
|
||||
font-size: $fs;
|
||||
}
|
||||
}
|
||||
|
||||
.number {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: var(--el-color-info-light-7);
|
||||
padding-left: 20px;
|
||||
|
||||
.t {
|
||||
font-size: $fs;
|
||||
}
|
||||
}
|
||||
|
||||
.select_user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: var(--el-color-info-light-8);
|
||||
padding: 0 20px;
|
||||
|
||||
.icon {
|
||||
color: var(--el-color-primary);
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.t {
|
||||
font-size: $fs;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
color: #999;
|
||||
font-size: 20px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shop_operation {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
.shop_list {
|
||||
flex: 1;
|
||||
height: calc(100vh - 40px - 60px - 130px);
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #ececec;
|
||||
|
||||
.item {
|
||||
padding: 20px;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.name_wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.sku_list {
|
||||
display: flex;
|
||||
padding-top: 10px;
|
||||
|
||||
.tag {
|
||||
padding: 4px 10px;
|
||||
background-color: var(--el-color-danger);
|
||||
color: #fff;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.num {
|
||||
padding-top: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.operation_wrap {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
.item {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #efefef;
|
||||
border-radius: 6px;
|
||||
|
||||
&.number {
|
||||
background-color: transparent;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.num {
|
||||
color: #333;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.add {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.t {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 20px;
|
||||
border-top: 1px solid #ececec;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.selected {
|
||||
|
||||
.icon {
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.t {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.btm {
|
||||
$h: 70px;
|
||||
display: flex;
|
||||
height: $h;
|
||||
padding-top: 20px;
|
||||
gap: 20px;
|
||||
|
||||
.editor {
|
||||
width: $h;
|
||||
border: 1px solid #ececec;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #555;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.button {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
background-color: var(--primary-color);
|
||||
padding: 0 20px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--el-color-primary-light-3);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--el-color-primary-dark-2);
|
||||
}
|
||||
|
||||
.js {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.t {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
:deep(span) {
|
||||
width: auto;
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shop_manage {
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
height: 100%;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
height: 80px;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #ececec;
|
||||
|
||||
.menus {
|
||||
display: flex;
|
||||
padding: 0 10px;
|
||||
|
||||
.item {
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
span {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
&::after {
|
||||
content: "";
|
||||
width: 70%;
|
||||
height: 2px;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 15%;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
span {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.all {
|
||||
width: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
height: 60%;
|
||||
border-left: 1px solid #ececec;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 20%;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: #555;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search_wrap {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.shop_list {
|
||||
max-height: calc(100vh - 40px - 80px - 80px);
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 0 10px;
|
||||
|
||||
&.img {
|
||||
.item_wrap {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.item_wrap {
|
||||
width: 20%;
|
||||
padding: 0 10px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.item {
|
||||
border: 1px solid #ececec;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 0 8px;
|
||||
background-color: var(--el-color-danger);
|
||||
color: #fff;
|
||||
border-radius: 20px;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
z-index: 1;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.cover {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.name {
|
||||
padding: 14px 10px;
|
||||
|
||||
span {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.price {
|
||||
padding: 10px 20px;
|
||||
background-color: var(--primary-color);
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
<template>
|
||||
<div class="cart_item" :class="{ active: props.item.active, border: props.border }"
|
||||
@click="selectCartItemHandle(index)">
|
||||
<div class="name_wrap">
|
||||
<span>{{ props.item.product_name }}</span>
|
||||
<template v-if="props.item.is_gift">
|
||||
<div class="price">
|
||||
<span class="dis" v-if="props.item.is_temporary">
|
||||
¥{{ formatDecimal(+props.item.discount_sale_amount, 2, true) }}
|
||||
</span>
|
||||
<span class="dis" v-else>
|
||||
¥{{ formatDecimal(goodsStore.showVipPrice ? +props.item.memberPrice || +props.item.lowPrice :
|
||||
+props.item.lowPrice, 2,
|
||||
true) }}
|
||||
</span>
|
||||
<span v-if="props.item.discount_sale_amount">
|
||||
¥0.00
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="price" v-if="props.item.is_temporary">
|
||||
<span>
|
||||
¥{{ formatDecimal(+props.item.discount_sale_amount, 2, true) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="price" v-else>
|
||||
<template v-if="+props.item.discount_sale_amount">
|
||||
<span class="dis">
|
||||
¥{{ formatDecimal(goodsStore.showVipPrice ? +props.item.memberPrice || +props.item.lowPrice
|
||||
: +props.item.lowPrice,
|
||||
2, true) }}
|
||||
</span>
|
||||
<span>
|
||||
¥{{ formatDecimal(+props.item.discount_sale_amount, 2, true) }}
|
||||
</span>
|
||||
</template>
|
||||
<div class="flex" v-else>
|
||||
<template v-if="goodsStore.showVipPrice">
|
||||
<span class="dis">
|
||||
¥{{ formatDecimal(+props.item.lowPrice, 2, true) }}
|
||||
</span>
|
||||
</template>
|
||||
<span>
|
||||
¥{{ formatDecimal(goodsStore.showVipPrice ? +props.item.memberPrice || +props.item.lowPrice
|
||||
:
|
||||
+props.item.lowPrice,
|
||||
2,
|
||||
true) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="remark_wrap" @click="showRemark(props.item)">
|
||||
备注:<span class="t">{{ props.item.remark }}</span><el-icon class="icon" v-if="props.type == 'cart'">
|
||||
<EditPen />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="sku_list" v-if="props.item.sku_name">
|
||||
<div class="tag" v-for="item in item.sku_name.split(',')">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grooup_wrap" v-if="props.item.goods_type == 'package' && props.item.group_text">
|
||||
{{ props.item.group_type == 0 ? '固定套餐:' : '自选套餐:' }}
|
||||
<span>{{ props.item.group_text }}</span>
|
||||
</div>
|
||||
<div class="num">
|
||||
<div class="left">
|
||||
<div class="icon_item zen" v-if="props.item.is_gift">
|
||||
<span class="t">赠</span>
|
||||
</div>
|
||||
<div class="icon_item bao" v-if="+props.item.pack_number">
|
||||
<span class="t">打包({{ +props.item.pack_number }})</span>
|
||||
</div>
|
||||
<div class="icon_item tui" v-if="props.item.returnNum">
|
||||
<span class="t">退({{ props.item.returnNum }})</span>
|
||||
</div>
|
||||
<div class="icon_item lin" v-if="props.item.is_temporary == 1">
|
||||
<span class="t">临</span>
|
||||
</div>
|
||||
<div class="icon_item zhe" v-if="props.item.discount_sale_amount > 0 && !props.item.is_temporary">
|
||||
<span class="t">折</span>
|
||||
</div>
|
||||
<div class="icon_item chu" v-if="props.item.is_print == 0">
|
||||
<span class="t">免厨打印</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-text class="t">x{{ formatDecimal(+props.item.number, 2, true) }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 备注 -->
|
||||
<remarkModal ref="remarkRef" @success="remarkSuccess" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import remarkModal from "@/components/remarkModal.vue";
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import { formatDecimal } from '@/utils/index.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: 'cart'
|
||||
},
|
||||
item: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
index: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
i: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
// 购物车选中
|
||||
function selectCartItemHandle() {
|
||||
if (props.type == 'cart') {
|
||||
goodsStore.selectCartItemHandle(props.index)
|
||||
} else if (props.type == 'order') {
|
||||
goodsStore.selectOrderItem(props.index, props.i)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加单品备注
|
||||
const remarkRef = ref(null)
|
||||
function showRemark() {
|
||||
if (props.type == 'cart') {
|
||||
remarkRef.value.show()
|
||||
}
|
||||
}
|
||||
|
||||
// 修改备注
|
||||
function remarkSuccess(e) {
|
||||
goodsStore.operateCart({ ...props.item, remark: e }, 'edit')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.remark_wrap {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
padding-top: 10px;
|
||||
|
||||
.icon {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.cart_item {
|
||||
padding: var(--el-font-size-base);
|
||||
|
||||
&.active {
|
||||
background-color: var(--primary-color-hover);
|
||||
}
|
||||
|
||||
&.border {
|
||||
border-bottom: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.name_wrap {
|
||||
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;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vip {
|
||||
color: var(--el-color-danger);
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.sku_list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 10px;
|
||||
|
||||
.tag {
|
||||
padding: 2px 6px;
|
||||
background-color: var(--el-color-danger);
|
||||
color: #fff;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding-right: 10px;
|
||||
|
||||
.icon_item {
|
||||
$size: 20px;
|
||||
height: $size;
|
||||
padding: 0 6px;
|
||||
border-radius: 2px;
|
||||
background-color: #e2e2e2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.t {
|
||||
font-size: var(--el-font-size-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,709 @@
|
|||
<template>
|
||||
<div class="operation_wrap">
|
||||
<template v-if="goodsStore.cartType == 'cart'">
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartList.length && (!goodsStore.cartList[goodsStore.cartActiveIndex].id || (goodsStore.cartList[goodsStore.cartActiveIndex].goods_type == 'package' && goodsStore.cartList[goodsStore.cartActiveIndex].group_type == 1)) }"
|
||||
@click="numberChange('sub')">
|
||||
<el-icon class="icon">
|
||||
<SemiSelect />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item number"
|
||||
:class="{ disabled: goodsStore.cartList.length && (goodsStore.cartList[goodsStore.cartActiveIndex].goods_type == 'package' && goodsStore.cartList[goodsStore.cartActiveIndex].group_type == 1) }"
|
||||
@click="showEditNumber">
|
||||
<el-text class="num">
|
||||
{{ formatDecimal(goodsStore.cartList.length ?
|
||||
+goodsStore.cartList[goodsStore.cartActiveIndex].number :
|
||||
1, 2, true) }}
|
||||
</el-text>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartList.length && (goodsStore.cartList[goodsStore.cartActiveIndex].goods_type == 'package' && goodsStore.cartList[goodsStore.cartActiveIndex].group_type == 1) || (goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].number >= goodsStore.cartList[goodsStore.cartActiveIndex].stockNumber && goodsStore.cartList[goodsStore.cartActiveIndex].isStock) }"
|
||||
@click="numberChange('add')">
|
||||
<el-icon class="icon add">
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: (goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].id && goodsStore.cartList[goodsStore.cartActiveIndex].goods_type != 'sku' && goodsStore.cartList[goodsStore.cartActiveIndex].group_type != 1) }"
|
||||
@click="showSkuModal">
|
||||
<el-icon class="icon">
|
||||
<Filter />
|
||||
</el-icon>
|
||||
<el-text class="t">规格</el-text>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].is_temporary || goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].is_gift }"
|
||||
@click="showDiscountModalHandle">
|
||||
<el-icon class="icon">
|
||||
<PriceTag />
|
||||
</el-icon>
|
||||
<el-text class="t">改价</el-text>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].is_gift }"
|
||||
@click="giftPackHandle('is_gift')">
|
||||
<el-icon class="icon">
|
||||
<ShoppingBag />
|
||||
</el-icon>
|
||||
<el-text class="t">赠送</el-text>
|
||||
</div>
|
||||
<div class="item" :class="{ disabled: goodsStore.allSelected }" @click="packHandle">
|
||||
<el-icon class="icon">
|
||||
<Box />
|
||||
</el-icon>
|
||||
<el-text class="t">打包</el-text>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartList.length && goodsStore.cartList[goodsStore.cartActiveIndex].is_print == 0 }"
|
||||
@click="giftPackHandle('is_print')">
|
||||
<el-icon class="icon">
|
||||
<DishDot />
|
||||
</el-icon>
|
||||
<el-text class="t">免厨</el-text>
|
||||
</div>
|
||||
<div class="item" @click="deleteHandle">
|
||||
<el-icon class="icon">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
<el-text class="t">删除</el-text>
|
||||
</div>
|
||||
<div class="item" @click="pendingOrderHandle">
|
||||
<el-icon class="icon">
|
||||
<Sell />
|
||||
</el-icon>
|
||||
<el-text class="t">挂单</el-text>
|
||||
</div>
|
||||
<div class="item" @click="tableMergingRef.show()">
|
||||
<el-icon class="icon">
|
||||
<EditPen />
|
||||
</el-icon>
|
||||
<el-text class="t">转桌</el-text>
|
||||
</div>
|
||||
<div class="item" @click="clearCart">
|
||||
<el-icon class="icon">
|
||||
<RefreshRight />
|
||||
</el-icon>
|
||||
<el-text class="t">清空</el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="goodsStore.cartType == 'order'">
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<SemiSelect />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item number disabled">
|
||||
<el-text class="num">
|
||||
{{ formatDecimal(goodsStore.cartList.length ?
|
||||
+goodsStore.cartList[goodsStore.cartActiveIndex].number :
|
||||
1, 2, true) }}
|
||||
</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon add">
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<Filter />
|
||||
</el-icon>
|
||||
<el-text class="t">规格</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<PriceTag />
|
||||
</el-icon>
|
||||
<el-text class="t">改价</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<ShoppingBag />
|
||||
</el-icon>
|
||||
<el-text class="t">赠送</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<Box />
|
||||
</el-icon>
|
||||
<el-text class="t">打包</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<DishDot />
|
||||
</el-icon>
|
||||
<el-text class="t">免厨</el-text>
|
||||
</div>
|
||||
<div class="item"
|
||||
:class="{ disabled: goodsStore.cartOrderItem.returnNum >= goodsStore.cartOrderItem.number }"
|
||||
@click="returnOrderItemHandle">
|
||||
<el-icon class="icon">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
<el-text class="t">退菜</el-text>
|
||||
</div>
|
||||
<div class="item" @click="pendingOrderHandle">
|
||||
<el-icon class="icon">
|
||||
<Sell />
|
||||
</el-icon>
|
||||
<el-text class="t">挂单</el-text>
|
||||
</div>
|
||||
<div class="item" @click="tableMergingRef.show()">
|
||||
<el-icon class="icon">
|
||||
<EditPen />
|
||||
</el-icon>
|
||||
<el-text class="t">转桌</el-text>
|
||||
</div>
|
||||
<div class="item disabled">
|
||||
<el-icon class="icon">
|
||||
<RefreshRight />
|
||||
</el-icon>
|
||||
<el-text class="t">清空</el-text>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<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="discount_sale_amount">
|
||||
<el-input v-model="discountForm.discount_sale_amount" placeholder="请输入改价金额" @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>
|
||||
<!-- 修改打包数量 -->
|
||||
<el-dialog v-model="showPackModal" title="打包数量" @open="packModalOpen" width="350">
|
||||
<div class="dialog">
|
||||
<div class="el-popover__title content">
|
||||
<el-form ref="packNumerFormRef" :model="packNumberForm" :rules="packNumberFormRules" label-width="100px"
|
||||
label-position="left">
|
||||
<el-form-item :label="`数量(${packItem.unitName})`" prop="number">
|
||||
<!-- <el-input v-model="packNumberForm.number"
|
||||
:placeholder="`最多输入${+packItem.number}${packItem.unitName}`" @input="packNumberInput">
|
||||
<template #append></template>
|
||||
</el-input> -->
|
||||
<el-input-number v-model="packNumberForm.number" :min="1"
|
||||
:max="+packItem.number"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showPackModal = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" @click="packFormSubmit">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 合并/转桌 -->
|
||||
<tableMerging ref="tableMergingRef" @success="" />
|
||||
<!-- 退菜数量 -->
|
||||
<el-dialog
|
||||
:title="`退菜:${goodsStore.cartOrderItem.product_name} x ${goodsStore.cartOrderItem.number - goodsStore.cartOrderItem.returnNum}`"
|
||||
v-model="showReturnForm" width="350" top="20%">
|
||||
<el-form :model="returnForm" label-width="0" label-position="left">
|
||||
<el-form-item prop="num">
|
||||
<el-input-number v-model="returnForm.num" :min="1"
|
||||
:max="goodsStore.cartOrderItem.number - goodsStore.cartOrderItem.returnNum" style="width: 100%;">
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="footer_wrap">
|
||||
<div class="btn">
|
||||
<el-button style="width: 100%;" @click="showReturnForm = false">取消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" style="width: 100%;" :loading="returnFormLoading"
|
||||
@click="returnFormSubmit">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import takeFoodCode from '@/components/takeFoodCode.vue'
|
||||
import TableMerging from './tableMerging.vue'
|
||||
import skuModal from '@/components/skuModal.vue'
|
||||
import { useGoods } from '@/store/goods.js'
|
||||
import { inputFilterFloat, formatDecimal } from '@/utils/index.js'
|
||||
import { refundOrder } from '@/api/order.js'
|
||||
import { useSocket } from '@/store/socket.js'
|
||||
|
||||
const goodsStore = useGoods()
|
||||
const socket = useSocket()
|
||||
|
||||
const tableMergingRef = ref(null)
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['confirm', 'delete', 'pending', 'clearCart', 'merging', 'showPackage'])
|
||||
|
||||
const takeFoodCodeRef = ref(null)
|
||||
const skuModalRef = ref([])
|
||||
|
||||
const showReturnForm = ref(false)
|
||||
const returnFormLoading = ref(false)
|
||||
const returnForm = ref({
|
||||
num: 1
|
||||
})
|
||||
|
||||
// 挂单
|
||||
function pendingOrderHandle() {
|
||||
let cart = goodsStore.cartList;
|
||||
let order = goodsStore.orderList;
|
||||
if (cart.length || order.length) {
|
||||
goodsStore.pendingCart()
|
||||
goodsStore.successClearCart();
|
||||
socket.cartInit();
|
||||
|
||||
ElMessage.success('挂单成功')
|
||||
}
|
||||
}
|
||||
|
||||
// 退菜
|
||||
async function returnOrderItemHandle() {
|
||||
if (goodsStore.cartOrderItem.returnNum >= goodsStore.cartOrderItem.number) return
|
||||
if (goodsStore.cartOrderItem.number == 1) {
|
||||
returnOrderItemAjax()
|
||||
} else {
|
||||
showReturnForm.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 提交自定义数量退菜
|
||||
async function returnFormSubmit() {
|
||||
try {
|
||||
returnFormLoading.value = true
|
||||
await returnOrderItemAjax(returnForm.value.num)
|
||||
showReturnForm.value = false
|
||||
ElMessage.success('退菜成功')
|
||||
} catch (error) {
|
||||
console.log('退菜失败了');
|
||||
}
|
||||
returnFormLoading.value = false
|
||||
}
|
||||
|
||||
// 提交退菜
|
||||
async function returnOrderItemAjax(num = 1) {
|
||||
try {
|
||||
let data = {
|
||||
orderId: goodsStore.orderListInfo.id,
|
||||
refundAmount: 0,
|
||||
modify: 0,
|
||||
cash: false,
|
||||
refundReason: '',
|
||||
refundDetails: [
|
||||
{
|
||||
id: goodsStore.cartOrderItem.id,
|
||||
returnAmount: goodsStore.cartOrderItem.lowPrice,
|
||||
num: num
|
||||
}
|
||||
]
|
||||
}
|
||||
await refundOrder(data)
|
||||
goodsStore.cartOrderItem.returnNum += num
|
||||
goodsStore.calcCartInfo()
|
||||
// await goodsStore.historyOrderAjax('', data.orderId)
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示打包
|
||||
function packHandle() {
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
if (item && item.id && !goodsStore.allSelected) {
|
||||
if (!item.pack_number || item.pack_number <= 0) {
|
||||
if (item.number > 1 && item.goods_type != 'weight') {
|
||||
// 大于1时需要编辑
|
||||
showPackModal.value = true
|
||||
} else {
|
||||
// 小于1时直接提交
|
||||
goodsStore.operateCart({ ...item, pack_number: 1 }, 'edit')
|
||||
}
|
||||
} else {
|
||||
// 取消打包
|
||||
goodsStore.operateCart({ ...item, pack_number: 0 }, 'edit')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 赠送打包操作
|
||||
function giftPackHandle(key) {
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
if (item && item.id) {
|
||||
if (key == 'is_gift' && goodsStore.cartList[goodsStore.cartActiveIndex] == 0) {
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex].discount_sale_amount = 0
|
||||
}
|
||||
|
||||
if (goodsStore.cartList[goodsStore.cartActiveIndex][key] == 0) {
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex][key] = 1
|
||||
} else {
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex][key] = 0
|
||||
}
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex] }, 'edit')
|
||||
goodsStore.calcCartInfo()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 显示直接修改数量
|
||||
function showEditNumber() {
|
||||
let item = goodsStore.cartList.length ? goodsStore.cartList[goodsStore.cartActiveIndex] : ''
|
||||
if (!item || (item.goods_type == 'package' && item.group_type == 1)) return
|
||||
takeFoodCodeRef.value.show()
|
||||
}
|
||||
|
||||
// 加减修改数量
|
||||
function numberChange(t) {
|
||||
let item = goodsStore.cartList.length ? goodsStore.cartList[goodsStore.cartActiveIndex] : ''
|
||||
if (!item || (item.goods_type == 'package' && item.group_type == 1)) return
|
||||
let number = +goodsStore.cartList[goodsStore.cartActiveIndex].number
|
||||
|
||||
|
||||
switch (t) {
|
||||
case 'sub':
|
||||
if (item.number - 1 < item.suitNum) {
|
||||
goodsStore.deleteCartItem()
|
||||
} else {
|
||||
if (goodsStore.allSelected) {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: number - 1, number: number - 1 }, 'edit')
|
||||
} else {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], number: number - 1 }, 'edit')
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'add':
|
||||
if (goodsStore.allSelected) {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: number + 1, number: number + 1 }, 'edit')
|
||||
} else {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], number: +number + 1 }, 'edit')
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
console.log('numberChange===', goodsStore.cartList[goodsStore.cartActiveIndex].number);
|
||||
}
|
||||
|
||||
// 输入修改数量
|
||||
function updateNumber(num) {
|
||||
if (goodsStore.allSelected) {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], pack_number: num, number: num }, 'edit')
|
||||
} else {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], number: num }, 'edit')
|
||||
}
|
||||
}
|
||||
|
||||
// 显示规格
|
||||
function showSkuModal() {
|
||||
let item = goodsStore.cartList.length ? goodsStore.cartList[goodsStore.cartActiveIndex] : ''
|
||||
if (!item || (item.goods_type == 'package' && item.group_type == 0)) return
|
||||
|
||||
switch (item.goods_type) {
|
||||
case 'sku':
|
||||
skuModalRef.value.show({ ...goodsStore.cartList[goodsStore.cartActiveIndex] }, 'cart')
|
||||
break;
|
||||
case 'package':
|
||||
emit('showPackage', item)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 修改规格
|
||||
function skuConfirm(e) {
|
||||
if (goodsStore.cartList[goodsStore.cartActiveIndex].sku_id != e.id) {
|
||||
goodsStore.operateCart({ ...goodsStore.cartList[goodsStore.cartActiveIndex], sku_id: e.id, sku_name: e.specInfo }, 'edit')
|
||||
}
|
||||
}
|
||||
|
||||
/**单品改价 start */
|
||||
const showDiscountModal = ref(false)
|
||||
const resetDiscountForm = ref({})
|
||||
const discountFormRef = ref(null)
|
||||
const discountFormLoading = ref(false)
|
||||
const discountForm = ref({
|
||||
discount_sale_amount: '',
|
||||
note: ''
|
||||
})
|
||||
|
||||
function validateAmount(rule, value, callback) {
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
let lowPrice = 0
|
||||
if (goodsStore.showVipPrice) {
|
||||
lowPrice = +item.memberPrice
|
||||
} else {
|
||||
lowPrice = +item.discount_sale_amount || +item.lowPrice
|
||||
}
|
||||
if (value == '') {
|
||||
callback(new Error('请输入折扣价格'))
|
||||
} else if (value <= 0 || value >= lowPrice) {
|
||||
callback(new Error(`输入大于0小于${lowPrice}的数字`))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const discountFormRules = ref({
|
||||
discount_sale_amount: [
|
||||
{
|
||||
required: true,
|
||||
validator: validateAmount,
|
||||
trigger: 'blur',
|
||||
}
|
||||
]
|
||||
})
|
||||
const noteList = ref([
|
||||
'顾客投诉质量...',
|
||||
'友情打折',
|
||||
'临时活动',
|
||||
])
|
||||
|
||||
// 显示
|
||||
function showDiscountModalHandle() {
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
if ((item && item.id) && (!item.is_temporary && !item.is_gift)) {
|
||||
// 存在商品并且不能为临时菜或者赠送
|
||||
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
|
||||
|
||||
goodsStore.operateCart({
|
||||
...goodsStore.cartList[goodsStore.cartActiveIndex],
|
||||
discount_sale_amount: discountForm.value.discount_sale_amount,
|
||||
discount_sale_note: discountForm.value.note
|
||||
}, 'edit')
|
||||
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex].discount_sale_amount = discountForm.value.discount_sale_amount
|
||||
goodsStore.cartList[goodsStore.cartActiveIndex].discount_sale_note = discountForm.value.note
|
||||
showDiscountModal.value = false
|
||||
|
||||
goodsStore.calcCartInfo()
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
discountFormLoading.value = false
|
||||
})
|
||||
}
|
||||
/**单品打折 end */
|
||||
|
||||
// 删除
|
||||
function deleteHandle() {
|
||||
let item = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
if (item && item.id) {
|
||||
goodsStore.deleteCartItem()
|
||||
}
|
||||
}
|
||||
|
||||
// 清空购物车
|
||||
function clearCart() {
|
||||
goodsStore.clearCart()
|
||||
}
|
||||
|
||||
/** 修改打包数量 start */
|
||||
const showPackModal = ref(false)
|
||||
const packNumerFormRef = ref(null)
|
||||
const packItem = ref('')
|
||||
const packNumberForm = ref({
|
||||
number: 1
|
||||
})
|
||||
const packNumberFormRules = {
|
||||
number: [
|
||||
{
|
||||
required: true,
|
||||
validator: validatePackNumber,
|
||||
trigger: 'blur',
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 校验数量是否合法
|
||||
function validatePackNumber(rule, value, callback) {
|
||||
if (!packNumberForm.value.number) {
|
||||
callback(new Error('请输入打包数量'))
|
||||
} else if (packNumberForm.value.number < 1) {
|
||||
callback(new Error('输入有误'))
|
||||
} else if (packNumberForm.value.number > packItem.value.number) {
|
||||
callback(new Error(`最多输入${+packItem.value.number}${packItem.value.unitName}`))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
// modal打开时
|
||||
function packModalOpen() {
|
||||
packNumberForm.value.number = 1
|
||||
packItem.value = goodsStore.cartList[goodsStore.cartActiveIndex]
|
||||
}
|
||||
|
||||
// 提交
|
||||
function packFormSubmit() {
|
||||
packNumerFormRef.value.validate(valid => {
|
||||
if (valid) {
|
||||
showPackModal.value = false
|
||||
goodsStore.operateCart({ ...packItem.value, pack_number: packNumberForm.value.number }, 'edit')
|
||||
}
|
||||
})
|
||||
}
|
||||
/** 修改打包数量 end */
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.operation_wrap {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.item {
|
||||
width: 70px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #efefef;
|
||||
border-radius: 6px;
|
||||
|
||||
&:active {
|
||||
background-color: #d3d3d3;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
|
||||
.t {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.num {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
&.number {
|
||||
background-color: transparent;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.num {
|
||||
color: #333;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.add {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.t {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer_wrap {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog {
|
||||
|
||||
.content {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.remark_list {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
|
||||
.item {
|
||||
padding: 0 10px;
|
||||
border: 1px solid #ddd;
|
||||
color: #999;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||