Compare commits
228 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
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,33 @@
|
||||||
|
# 本地环境
|
||||||
|
ENV = development
|
||||||
|
|
||||||
|
|
||||||
|
# 正式ws
|
||||||
|
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
|
||||||
|
|
||||||
|
#测试ws
|
||||||
|
# VITE_API_WSS = 'wss://wxcashiertest.sxczgkj.cn/client'
|
||||||
|
|
||||||
|
# 阿伟本地ws
|
||||||
|
# VITE_API_WSS = 'ws://192.168.2.17:9998/client'
|
||||||
|
|
||||||
|
# 正式 php
|
||||||
|
VITE_API_PHP_URL = 'https://czgdoumei.sxczgkj.com/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.2.96:10587/cashier-client'
|
||||||
|
|
||||||
|
# 鹏辉
|
||||||
|
# VITE_API_URL = 'http://192.168.1.106:10589/cashier-client'
|
||||||
|
|
||||||
|
# 测试
|
||||||
|
# VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client'
|
||||||
|
|
||||||
|
# 正式
|
||||||
|
VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
# 线上环境
|
||||||
|
ENV = production
|
||||||
|
|
||||||
|
# 正式ws
|
||||||
|
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
|
||||||
|
|
||||||
|
# 正式 php
|
||||||
|
VITE_API_PHP_URL = 'https://czgdoumei.sxczgkj.com/index.php/api'
|
||||||
|
|
||||||
|
# 正式 php 开票
|
||||||
|
VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
|
||||||
|
|
||||||
|
# 线上环境接口地址
|
||||||
|
VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client/'
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# 线上环境
|
||||||
|
ENV = test
|
||||||
|
|
||||||
|
#测试ws
|
||||||
|
VITE_API_WSS = 'wss://wxcashiertest.sxczgkj.cn/client'
|
||||||
|
|
||||||
|
# 正式ws
|
||||||
|
# VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
|
||||||
|
|
||||||
|
# 正式 php
|
||||||
|
VITE_API_PHP_URL = 'https://czgdoumei.sxczgkj.com/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 = 'https://cashier-client.sxczgkj.cn/cashier-client'
|
||||||
|
|
||||||
|
# 正式
|
||||||
|
# VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'
|
||||||
|
|
@ -8,6 +8,8 @@ pnpm-debug.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
|
release
|
||||||
|
|
||||||
dist
|
dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
# Vue 3 + Vite
|
# Vue 3 + Vite
|
||||||
|
|
||||||
|
npm install
|
||||||
|
|
||||||
|
npm install @element-plus/icons-vue
|
||||||
|
|
||||||
npm run dev
|
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.
|
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
|
## 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) => { }
|
||||||
|
);
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
const path = require("path");
|
||||||
const electron = require("electron");
|
const electron = require("electron");
|
||||||
|
const os = require("os");
|
||||||
|
let win;
|
||||||
electron.app.whenReady().then(() => {
|
electron.app.whenReady().then(() => {
|
||||||
const win = new electron.BrowserWindow({
|
win = new electron.BrowserWindow({
|
||||||
title: "Main window",
|
title: "银收客",
|
||||||
width: 1200,
|
width: 1024,
|
||||||
height: 800,
|
height: 768,
|
||||||
fullscreenable: true,
|
fullscreenable: true,
|
||||||
fullscreen: false,
|
fullscreen: process.env.VITE_DEV_SERVER_URL ? false : true,
|
||||||
simpleFullscreen: true,
|
simpleFullscreen: true,
|
||||||
frame: true,
|
frame: process.env.VITE_DEV_SERVER_URL ? true : false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
// 集成网页和 Node.js,也就是在渲染进程中,可以调用 Node.js 方法
|
// 集成网页和 Node.js,也就是在渲染进程中,可以调用 Node.js 方法
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
|
|
@ -18,16 +21,92 @@ electron.app.whenReady().then(() => {
|
||||||
if (process.env.VITE_DEV_SERVER_URL) {
|
if (process.env.VITE_DEV_SERVER_URL) {
|
||||||
win.loadURL(process.env.VITE_DEV_SERVER_URL);
|
win.loadURL(process.env.VITE_DEV_SERVER_URL);
|
||||||
} else {
|
} else {
|
||||||
win.loadFile("dist/index.html");
|
win.loadFile(path.resolve(__dirname, "../dist/index.html"));
|
||||||
}
|
}
|
||||||
win.webContents.openDevTools();
|
|
||||||
electron.app.on("activate", () => {
|
electron.app.on("activate", () => {
|
||||||
if (electron.BrowserWindow.getAllWindows().length === 0)
|
if (electron.BrowserWindow.getAllWindows().length === 0) {
|
||||||
createWindow();
|
createWindow();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
electron.ipcMain.on("quitHandler", (_, msg) => {
|
electron.ipcMain.on("quitHandler", (_, msg) => {
|
||||||
console.log(msg);
|
win = null;
|
||||||
|
electron.app.exit();
|
||||||
|
});
|
||||||
|
electron.ipcMain.on("getPrintList", () => {
|
||||||
|
win.webContents.getPrintersAsync().then((res) => {
|
||||||
|
win.webContents.send("printList", res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
electron.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 tagPrintWin = new electron.BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
width: 360,
|
||||||
|
height: 240,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
contextIsolation: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (process.env.VITE_DEV_SERVER_URL) {
|
||||||
|
tagPrintWin.loadFile(path.join(__dirname, "../public/tag_print.html"));
|
||||||
|
} else {
|
||||||
|
tagPrintWin.loadFile(path.resolve(__dirname, "../dist/tag_print.html"));
|
||||||
|
}
|
||||||
|
electron.ipcMain.on("printerTagSync", (event, arg) => {
|
||||||
|
console.log(arg);
|
||||||
|
tagPrintWin.webContents.send("getParams", arg);
|
||||||
|
});
|
||||||
|
electron.ipcMain.on("printTagStart", (event, arg) => {
|
||||||
|
const _parmas = JSON.parse(arg);
|
||||||
|
let name = _parmas.deviceName;
|
||||||
|
tagPrintWin.webContents.print({
|
||||||
|
silent: true,
|
||||||
|
deviceName: name,
|
||||||
|
pageSize: {
|
||||||
|
width: 45e3,
|
||||||
|
height: 3e4
|
||||||
|
},
|
||||||
|
scaleFactor: 80,
|
||||||
|
landscape: false,
|
||||||
|
margins: {
|
||||||
|
marginType: "none",
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0
|
||||||
|
},
|
||||||
|
dpi: {
|
||||||
|
horizontal: 203,
|
||||||
|
vertical: 203
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const gotTheLock = electron.app.requestSingleInstanceLock();
|
||||||
|
if (!gotTheLock) {
|
||||||
electron.app.quit();
|
electron.app.quit();
|
||||||
|
} else {
|
||||||
|
electron.app.on("second-instance", (event, commandLine, workingDirectory) => {
|
||||||
|
if (win) {
|
||||||
|
if (win.isMinimized())
|
||||||
|
win.restore();
|
||||||
|
win.focus();
|
||||||
|
win.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
win.on("close", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
win.webContents.send("showCloseDialog");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
electron.app.on("window-all-closed", () => {
|
electron.app.on("window-all-closed", () => {
|
||||||
|
|
|
||||||
238
electron/main.js
|
|
@ -1,14 +1,18 @@
|
||||||
|
import path from "path";
|
||||||
import { app, BrowserWindow, ipcMain } from "electron";
|
import { app, BrowserWindow, ipcMain } from "electron";
|
||||||
|
import os from "os";
|
||||||
|
// const SerialPort = require("serialport");
|
||||||
|
|
||||||
|
let win;
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
const win = new BrowserWindow({
|
win = new BrowserWindow({
|
||||||
title: "Main window",
|
title: "银收客",
|
||||||
width: 1200,
|
width: 1024,
|
||||||
height: 800,
|
height: 768,
|
||||||
fullscreenable: true,
|
fullscreenable: true,
|
||||||
fullscreen: false,
|
fullscreen: process.env.VITE_DEV_SERVER_URL ? false : true,
|
||||||
simpleFullscreen: true,
|
simpleFullscreen: true,
|
||||||
frame: true,
|
frame: process.env.VITE_DEV_SERVER_URL ? true : false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
// 集成网页和 Node.js,也就是在渲染进程中,可以调用 Node.js 方法
|
// 集成网页和 Node.js,也就是在渲染进程中,可以调用 Node.js 方法
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
|
|
@ -19,23 +23,233 @@ app.whenReady().then(() => {
|
||||||
// You can use `process.env.VITE_DEV_SERVER_URL` when the vite command is called `serve`
|
// You can use `process.env.VITE_DEV_SERVER_URL` when the vite command is called `serve`
|
||||||
if (process.env.VITE_DEV_SERVER_URL) {
|
if (process.env.VITE_DEV_SERVER_URL) {
|
||||||
win.loadURL(process.env.VITE_DEV_SERVER_URL);
|
win.loadURL(process.env.VITE_DEV_SERVER_URL);
|
||||||
|
// 使用vite开发服务的url路径访问应用
|
||||||
|
// win.webContents.openDevTools();
|
||||||
} else {
|
} else {
|
||||||
// Load your file
|
win.loadFile(path.resolve(__dirname, "../dist/index.html")); // 打包后使用文件路径访问应用
|
||||||
win.loadFile("dist/index.html");
|
|
||||||
}
|
}
|
||||||
win.webContents.openDevTools();
|
|
||||||
app.on("activate", () => {
|
app.on("activate", () => {
|
||||||
// 在 macOS 系统内, 如果没有已开启的应用窗口
|
// 在 macOS 系统内, 如果没有已开启的应用窗口
|
||||||
// 点击托盘图标时通常会重新创建一个新窗口
|
// 点击托盘图标时通常会重新创建一个新窗口
|
||||||
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on("quitHandler", (_, msg) => {
|
ipcMain.on("quitHandler", (_, msg) => {
|
||||||
console.log(msg);
|
win = null;
|
||||||
|
app.exit();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 给渲染进程返回打印机列表
|
||||||
|
ipcMain.on("getPrintList", () => {
|
||||||
|
win.webContents.getPrintersAsync().then((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);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ipcMain.on("getSerialPort", () => {
|
||||||
|
// SerialPort.SerialPort.list().then(
|
||||||
|
// (ports) => {
|
||||||
|
// console.log(ports);
|
||||||
|
// win.webContents.send("seriaportList", ports);
|
||||||
|
// },
|
||||||
|
// (err) => console.error(err)
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 创建打印小票子窗口
|
||||||
|
// const printWin = new BrowserWindow({
|
||||||
|
// show: false,
|
||||||
|
// 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();
|
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", () => {
|
app.on("window-all-closed", () => {
|
||||||
if (process.platform !== "darwin") app.quit();
|
if (process.platform !== "darwin") app.quit();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" id="html">
|
<html lang="en" id="html">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + Vue</title>
|
<meta http-equiv="Content-Security-Policy" />
|
||||||
|
<title>银收客</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|
|
||||||
56
package.json
|
|
@ -1,23 +1,39 @@
|
||||||
{
|
{
|
||||||
"name": "vite-electron",
|
"name": "vite-electron",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "1.4.14",
|
||||||
"main": "dist-electron/main.js",
|
"main": "dist-electron/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "chcp 65001 && vite",
|
"dev": "chcp 65001 && vite",
|
||||||
"build": "vite build",
|
"build": "node ./addVersion.js && vite build && electron-builder",
|
||||||
"preview": "vite preview"
|
"build:test": "vite build --mode test && electron-builder",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"build:win": "node ./addVersion.js && vite build && electron-builder --w"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
|
"dayjs": "^1.11.10",
|
||||||
|
"electron-pos-printer": "^1.3.6",
|
||||||
|
"electron-pos-printer-vue": "^1.0.9",
|
||||||
"element-plus": "^2.4.3",
|
"element-plus": "^2.4.3",
|
||||||
|
"js-md5": "^0.8.3",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
|
"pinia-plugin-persistedstate": "^3.2.1",
|
||||||
|
"qrcode": "^1.5.3",
|
||||||
|
"reconnecting-websocket": "^4.4.0",
|
||||||
|
"serialport": "^12.0.0",
|
||||||
|
"swiper": "^11.1.1",
|
||||||
|
"uuid": "^10.0.0",
|
||||||
"vue": "^3.3.8",
|
"vue": "^3.3.8",
|
||||||
"vue-router": "^4.2.5"
|
"vue-router": "^4.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^4.5.0",
|
"@vitejs/plugin-vue": "^4.5.0",
|
||||||
|
"electron": "^28.2.3",
|
||||||
|
"electron-builder": "^24.13.3",
|
||||||
|
"electron-rebuild": "^3.2.9",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"sass": "^1.69.5",
|
"sass": "^1.69.5",
|
||||||
"sass-loader": "^13.3.2",
|
"sass-loader": "^13.3.2",
|
||||||
|
|
@ -25,5 +41,39 @@
|
||||||
"vite": "^5.0.0",
|
"vite": "^5.0.0",
|
||||||
"vite-plugin-electron": "^0.15.4",
|
"vite-plugin-electron": "^0.15.4",
|
||||||
"vite-plugin-electron-renderer": "^0.14.5"
|
"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,72 @@
|
||||||
|
* {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
.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 {
|
||||||
|
margin-left: 10px;
|
||||||
|
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="./logo.png" />
|
||||||
|
<!-- <span class="title">双屿Pisces</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,61 @@
|
||||||
|
* {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.number_wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
.num {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
margin-left: 10px;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
338
src/App.vue
|
|
@ -1,19 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<el-config-provider size="large">
|
<el-config-provider size="large">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="left" v-if="route.path !== 'login'">
|
<div class="left" v-if="!hideLeftMenu">
|
||||||
<left-menu />
|
<left-menu ref="leftMenuRef" />
|
||||||
</div>
|
</div>
|
||||||
<div class="view">
|
<div :class="{ view: !hideLeftMenu }">
|
||||||
<router-view />
|
|
||||||
<!-- <div class="wrapper">
|
<!-- <div class="wrapper">
|
||||||
<div class="animation">
|
<div class="animation"> -->
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<transition :name="transitionName">
|
<!-- <transition :name="transitionName"> -->
|
||||||
|
<keep-alive :include="includeList">
|
||||||
<component :is="Component"></component>
|
<component :is="Component"></component>
|
||||||
</transition>
|
</keep-alive>
|
||||||
|
<!-- </transition> -->
|
||||||
</router-view>
|
</router-view>
|
||||||
</div>
|
<!-- </div>
|
||||||
</div> -->
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -21,12 +22,42 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<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 { useRouter, useRoute } from "vue-router";
|
||||||
import { ref } from "vue";
|
import leftMenu from "@/components/leftMenu.vue";
|
||||||
|
import useStorage from "@/utils/useStorage";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import { dayjs, 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';
|
||||||
|
const socket = useSocket();
|
||||||
|
|
||||||
const route = useRoute()
|
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 transitionName = ref();
|
||||||
let router = useRouter();
|
let router = useRouter();
|
||||||
|
|
@ -42,6 +73,142 @@ router.beforeEach((to, from) => {
|
||||||
transitionName.value = "";
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取网络状态
|
||||||
|
const updateInfo = _.throttle(function () {
|
||||||
|
let isOnLine = navigator.onLine
|
||||||
|
// // 获取网络信息
|
||||||
|
// let info = navigator.connection
|
||||||
|
console.log(isOnLine);
|
||||||
|
// console.log(info);
|
||||||
|
if (store.userInfo && store.userInfo.shopId) {
|
||||||
|
if (isOnLine) {
|
||||||
|
console.log('有网了重新连接ws~');
|
||||||
|
socket.init();
|
||||||
|
} else {
|
||||||
|
socket.close();
|
||||||
|
console.log('网络连接失败~');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100, { leading: true, trailing: false })
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener("keydown", (e) => {
|
||||||
|
getBarCode(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 防止刷新页面长连接丢失
|
||||||
|
if (store.userInfo && store.userInfo.shopId) {
|
||||||
|
socket.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcRenderer.on('showCloseDialog', (event, arg) => {
|
||||||
|
ElMessageBox.confirm("确定要关闭软件吗?")
|
||||||
|
.then(() => {
|
||||||
|
ipcRenderer.send("quitHandler", "退出吧");
|
||||||
|
})
|
||||||
|
.catch(() => { });
|
||||||
|
})
|
||||||
|
|
||||||
|
// listnerCloseDialog()
|
||||||
|
|
||||||
|
// // 监听网络在线状态
|
||||||
|
// window.addEventListener("onLine", updateInfo)
|
||||||
|
// // 监听网络离线
|
||||||
|
// window.addEventListener("offLine", updateInfo)
|
||||||
|
// 监听网络信息变化
|
||||||
|
// navigator.connection.addEventListener('change', updateInfo)
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
@ -53,23 +220,145 @@ router.beforeEach((to, from) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
: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-color-primary: var(--primary-color) !important;
|
||||||
--el-button-hover-bg-color: 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-light-3: rgb(var(--r-lighter),
|
||||||
--el-color-primary-dark-2: darken(var(--primary-color), 20%) !important;
|
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-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: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*定义滚动条高宽及背景
|
/*定义滚动条高宽及背景
|
||||||
高宽分别对应横竖滚动条的尺寸*/
|
高宽分别对应横竖滚动条的尺寸*/
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 4px;
|
width: 4px;
|
||||||
|
height: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*定义滚动条轨道
|
/*定义滚动条轨道
|
||||||
内阴影+圆角*/
|
内阴影+圆角*/
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
background-color: #F5F5F5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*定义滑块
|
/*定义滑块
|
||||||
|
|
@ -79,6 +368,21 @@ router.beforeEach((to, from) => {
|
||||||
background-color: #d3d3d3;
|
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 {
|
.mt50 {
|
||||||
margin-top: 50px;
|
margin-top: 50px;
|
||||||
|
|
@ -90,7 +394,7 @@ router.beforeEach((to, from) => {
|
||||||
.view {
|
.view {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
padding: 20px;
|
padding: var(--el-font-size-base);
|
||||||
background-color: #efefef;
|
background-color: #efefef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,160 @@
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -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,57 @@
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
import request from "@/utils/request.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询分类信息
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function queryPayType(params) {
|
||||||
|
return request({
|
||||||
|
method: "get",
|
||||||
|
url: "pay/queryPayType",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 付款
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function payOrder(api, params) {
|
||||||
|
return request({
|
||||||
|
method: "get",
|
||||||
|
url: api,
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫码支付
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function scanpay(params) {
|
||||||
|
return request({
|
||||||
|
method: "get",
|
||||||
|
url: "pay/scanpay",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 储值卡付款
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function accountPay(params) {
|
||||||
|
return request({
|
||||||
|
method: "get",
|
||||||
|
url: "pay/accountPay",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 现金付款
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function cashPay(params) {
|
||||||
|
return request({
|
||||||
|
method: "get",
|
||||||
|
url: "pay/cashPay",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询订单支付状态
|
||||||
|
* @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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import request from "@/utils/request.js";
|
||||||
|
|
||||||
|
export function login(data) {
|
||||||
|
return request({
|
||||||
|
method: "post",
|
||||||
|
url: "login/login",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -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 |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 58 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,127 @@
|
||||||
|
<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 { tbShopCategoryGet } from "@/api/device";
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
|
||||||
|
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 tbShopCategoryGet({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
sort: "sort,desc",
|
||||||
|
page: 0,
|
||||||
|
pageSize: 200,
|
||||||
|
});
|
||||||
|
// console.log(res);
|
||||||
|
res.list.map((item) => {
|
||||||
|
item.active = false;
|
||||||
|
item.childrenList.map((item) => {
|
||||||
|
item.active = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
categorys.value = res.list;
|
||||||
|
|
||||||
|
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,399 @@
|
||||||
|
<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.telephone
|
||||||
|
}}</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="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" :selecttype="props.type" :orderId="props.userInfo.id"
|
||||||
|
@success="scanCodeSuccess" />
|
||||||
|
<takeFoodCode ref="takeFoodCodeRef" title="支付密码" :type="2" input-type="password" placeholder="请输入支付密码"
|
||||||
|
@success="passwordSuccess" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { queryPayType, quickPay } from "@/api/pay";
|
||||||
|
import {
|
||||||
|
queryMembermember,
|
||||||
|
createMembermember,
|
||||||
|
membermemberScanPay,
|
||||||
|
accountPaymember,
|
||||||
|
} from "@/api/member/index.js";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import { clearNoNum } from "@/utils";
|
||||||
|
import md5 from "js-md5";
|
||||||
|
|
||||||
|
import scanModal from "@/components/payCard/scanModal.vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import takeFoodCode from "@/components/takeFoodCode.vue";
|
||||||
|
const takeFoodCodeRef = ref(null);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 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 accountPaymember({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
memberId: props.userInfo.id,
|
||||||
|
amount: money.value,
|
||||||
|
pwd: md5(e),
|
||||||
|
});
|
||||||
|
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 {
|
||||||
|
// 会员充值
|
||||||
|
takeFoodCodeRef.value.show();
|
||||||
|
// 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) });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
function delHandle() {
|
||||||
|
if (!money.value) return;
|
||||||
|
money.value = money.value.substring(0, money.value.length - 1);
|
||||||
|
if (!money.value) {
|
||||||
|
money.value = "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取支付方式
|
||||||
|
async function queryPayTypeAjax() {
|
||||||
|
try {
|
||||||
|
const res = await queryPayType({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ reset });
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
queryPayTypeAjax();
|
||||||
|
});
|
||||||
|
</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: 130px;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input_wrap {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--el-font-size-base);
|
||||||
|
padding: var(--el-font-size-base) 0;
|
||||||
|
|
||||||
|
.input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 60px;
|
||||||
|
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) / 4);
|
||||||
|
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,10 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="left_menu_wrap">
|
<div class="left_menu_wrap">
|
||||||
<div class="item online">
|
<div class="item" :class="{ online: socketStore.online }" @click="connectWsHandle">
|
||||||
<el-icon class="icon">
|
<el-icon class="icon">
|
||||||
<Monitor />
|
<Monitor />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<el-text type="success">在线</el-text>
|
<el-text :type="socketStore.online ? 'success' : ''">
|
||||||
|
<template v-if="socketStore.online">
|
||||||
|
在线
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
离线
|
||||||
|
</template>
|
||||||
|
</el-text>
|
||||||
</div>
|
</div>
|
||||||
<router-link class="item" :class="{ active: route.path == item.path }" v-for="item in menus" :key="item.path"
|
<router-link class="item" :class="{ active: route.path == item.path }" v-for="item in menus" :key="item.path"
|
||||||
:to="item.path">
|
:to="item.path">
|
||||||
|
|
@ -13,20 +20,42 @@
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<el-text class="text">{{ item.label }}</el-text>
|
<el-text class="text">{{ item.label }}</el-text>
|
||||||
</router-link>
|
</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 class="item more" @click="moreref.show()">
|
||||||
<el-icon class="icon">
|
<el-icon class="icon">
|
||||||
<Operation />
|
<Operation />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<el-text class="text">更多</el-text>
|
<el-text class="text">更多</el-text>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 交班 -->
|
||||||
|
<work ref="workRef" />
|
||||||
|
<!-- 更多 -->
|
||||||
|
<more ref="moreref" @openCall="openCall"></more>
|
||||||
|
<!-- 叫号 -->
|
||||||
|
<callNumber ref="callNumberRef" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
import { useSocket } from '@/store/socket.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()
|
const route = useRoute()
|
||||||
console.log(route.path)
|
const moreref = ref(null)
|
||||||
|
const callNumberRef = ref(null)
|
||||||
|
const workRef = ref(null)
|
||||||
|
|
||||||
const menus = ref([
|
const menus = ref([
|
||||||
{
|
{
|
||||||
label: '收银',
|
label: '收银',
|
||||||
|
|
@ -38,33 +67,134 @@ const menus = ref([
|
||||||
path: '/table',
|
path: '/table',
|
||||||
icon: 'Reading'
|
icon: 'Reading'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '团购',
|
||||||
|
path: '/group_buy',
|
||||||
|
icon: 'Handbag'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '订单',
|
label: '订单',
|
||||||
path: '/order',
|
path: '/order',
|
||||||
icon: 'Tickets'
|
icon: 'Tickets'
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
label: '网络',
|
// label: '网络',
|
||||||
path: '/internat',
|
// path: '/internat',
|
||||||
icon: 'Paperclip'
|
// icon: 'Paperclip'
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
label: '会员',
|
label: '会员',
|
||||||
path: '/user',
|
path: '/member',
|
||||||
icon: 'User'
|
icon: 'User'
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
label: '交班',
|
// label: '交班',
|
||||||
path: '/work',
|
// path: '/work',
|
||||||
icon: 'SwitchButton'
|
// icon: 'SwitchButton'
|
||||||
}
|
// }
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// 更新叫号记录
|
||||||
|
function updateCallNumber() {
|
||||||
|
callNumberRef.value.getsendMessageAjax()
|
||||||
|
}
|
||||||
|
|
||||||
|
function openCall() {
|
||||||
|
callNumberRef.value.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动重新连接ws
|
||||||
|
function connectWsHandle() {
|
||||||
|
if (socketStore.online) return
|
||||||
|
window.onload()
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
updateCallNumber
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<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 {
|
.left_menu_wrap {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 120px;
|
width: 60px;
|
||||||
background-color: #555;
|
background-color: #555;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -76,10 +206,14 @@ const menus = ref([
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
/* 去除下划线 */
|
||||||
&:first-child {
|
color: inherit;
|
||||||
border-bottom: 1px solid #666;
|
/* 继承父元素的颜色 */
|
||||||
}
|
cursor: pointer;
|
||||||
|
/* 修改鼠标指针样式 */
|
||||||
|
border: none;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
|
||||||
&.online {
|
&.online {
|
||||||
|
|
||||||
|
|
@ -99,18 +233,18 @@ const menus = ref([
|
||||||
}
|
}
|
||||||
|
|
||||||
&.more {
|
&.more {
|
||||||
margin-top: 30px;
|
margin-top: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: #999;
|
color: #999;
|
||||||
font-size: 32px;
|
font-size: 22px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
color: #999;
|
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,161 @@
|
||||||
|
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: 30px;display:flex;justify-content:center;">
|
||||||
|
${data.merchantName}
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||||
|
交班小票
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px;margin-top:50px;">
|
||||||
|
当班时间:${data.startTime}
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px;">
|
||||||
|
交班时间:${data.endTime}
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px;">
|
||||||
|
收银员:${data.staff}
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px;margin-top: 4px;">
|
||||||
|
当班收入:${data.totalAmount}
|
||||||
|
</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.productCategories && data.productCategories.length) {
|
||||||
|
for (let item of data.productCategories) {
|
||||||
|
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.productInfos && data.productInfos.length) {
|
||||||
|
for (let item of data.productInfos) {
|
||||||
|
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.quickAmount}</span>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px;">
|
||||||
|
<span>退款金额:</span>
|
||||||
|
<span>${data.returnAmount}</span>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px;">
|
||||||
|
<span>总收入:</span>
|
||||||
|
<span>${data.totalAmount}</span>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px;">
|
||||||
|
<span>备用金:</span>
|
||||||
|
<span>${data.imprest}</span>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px;">
|
||||||
|
<span>应交金额:</span>
|
||||||
|
<span>${data.payable}</span>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 20px; font-size: 12px;">
|
||||||
|
<span>总订单数:</span>
|
||||||
|
<span>${data.orderNum}</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}`;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
LODOP.ADD_PRINT_HTM("9mm", "0mm", "RightMargin:0mm", 20, lastHtml);
|
||||||
|
LODOP.SET_LICENSES("", "DCFF409304DFCEB3E2C644BF96CD0720", "", "");
|
||||||
|
LODOP.PRINT();
|
||||||
|
}, 800);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
import getLodop from "./LodopFuncs.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: 30px;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.masterId ? data.orderInfo.masterId : ""
|
||||||
|
}】
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:20px;">
|
||||||
|
${data.orderInfo.outNumber ? data.orderInfo.outNumber : ""}
|
||||||
|
</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,96 @@
|
||||||
|
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: 30px;display:flex;justify-content:center;">
|
||||||
|
${data.shop_name}
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
|
||||||
|
退款单【${data.orderInfo.masterId ? data.orderInfo.masterId : ""}】
|
||||||
|
</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: 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,227 @@
|
||||||
|
<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">
|
||||||
|
<div class="drawerbox_bo_top_left_one" style="font-size: 24px;">
|
||||||
|
{{ store.userInfo.shopName }}
|
||||||
|
</div>
|
||||||
|
<div class="drawerbox_bo_top_left_tow" style="margin-top: 10px">
|
||||||
|
收银员:{{ store.userInfo.loginAccount }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span style="color: #666">{{ 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; 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);
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开叫号弹窗
|
||||||
|
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 #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;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.drawerbox_bo_box_itembox {
|
||||||
|
width: 20%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 20px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
|
||||||
|
.drawerbox_bo_box_icon {
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #2196f3;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawerbox_bo_box_icontext {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,362 @@
|
||||||
|
<template>
|
||||||
|
<div class="card">
|
||||||
|
<div class="header">
|
||||||
|
<div class="t1">
|
||||||
|
<span class="title">应收:¥</span>
|
||||||
|
<span class="num">{{ props.amount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="t2">
|
||||||
|
<span>已付:¥0.00</span>
|
||||||
|
<span>优惠:¥0.00</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="number_wrap">
|
||||||
|
<div class="menus">
|
||||||
|
<div class="item" :class="{ active: payActive == index }" v-for="(item, index) in payList"
|
||||||
|
:key="item.id" @click="payTypeChange(index, item)">
|
||||||
|
<div class="icon">
|
||||||
|
<el-image :src="item.icon" class="img"></el-image>
|
||||||
|
</div>
|
||||||
|
<span class="title">{{ item.payName }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input_wrap">
|
||||||
|
<div class="input" style="flex: 1;">储值:¥{{ money }}</div>
|
||||||
|
<div class="input" v-if="waitPayMoney > 0">待支付:¥{{ waitPayMoney }}</div>
|
||||||
|
</div>
|
||||||
|
<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" :amount="props.amount" :orderId="props.orderId" :selecttype="props.selecttype"
|
||||||
|
:payType="payType" @success="scanCodeSuccess" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, computed, watch } from 'vue'
|
||||||
|
import { queryPayType, accountPay, cashPay } from '@/api/pay'
|
||||||
|
import { queryMembermember, createMembermember, membermemberScanPay, accountPaymember } from '@/api/member/index.js'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
import { clearNoNum } from '@/utils'
|
||||||
|
|
||||||
|
import scanModal from '@/components/payCard/scanModal.vue'
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
amount: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
selecttype: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
orderId: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
member: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['paySuccess'])
|
||||||
|
|
||||||
|
const money = ref('0')
|
||||||
|
const scanModalRef = ref(null)
|
||||||
|
|
||||||
|
watch(props, (value) => {
|
||||||
|
money.value = `${props.amount}`
|
||||||
|
})
|
||||||
|
|
||||||
|
const waitPayMoney = computed(() => {
|
||||||
|
let num = JSON.stringify(props.amount - money.value)
|
||||||
|
num = Math.floor(num * 100) / 100
|
||||||
|
return num
|
||||||
|
})
|
||||||
|
|
||||||
|
const payActive = ref(0)
|
||||||
|
const payType = ref('')
|
||||||
|
const payList = ref([])
|
||||||
|
const payLoading = ref(false)
|
||||||
|
|
||||||
|
// 获得扫码值
|
||||||
|
function scanCodeSuccess() {
|
||||||
|
emit('paySuccess')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换支付类型
|
||||||
|
function payTypeChange(index, item) {
|
||||||
|
payActive.value = index
|
||||||
|
payType.value = item.payType
|
||||||
|
if (item.payType == 'scanCode') {
|
||||||
|
scanModalRef.value.show()
|
||||||
|
}
|
||||||
|
if (payList.value[payActive.value].payType == 'deposit' && !props.member.id) {
|
||||||
|
scanModalRef.value.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结算支付
|
||||||
|
async function confirmOrder() {
|
||||||
|
if (payLoading.value) return
|
||||||
|
try {
|
||||||
|
if (payList.value[payActive.value].payType == 'scanCode') {
|
||||||
|
scanModalRef.value.show()
|
||||||
|
} else {
|
||||||
|
if (money.value < props.amount) return
|
||||||
|
payLoading.value = true
|
||||||
|
switch (payList.value[payActive.value].payType) {
|
||||||
|
case 'deposit'://储值卡
|
||||||
|
// if (props.selecttype == 1) {
|
||||||
|
|
||||||
|
// } else {
|
||||||
|
|
||||||
|
// }
|
||||||
|
if (props.member.id) {
|
||||||
|
await accountPay({
|
||||||
|
orderId: props.orderId,
|
||||||
|
memberId: props.member.id,
|
||||||
|
memberAccount: ''
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
payLoading.value = false
|
||||||
|
scanModalRef.value.show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'cash'://现金
|
||||||
|
if (props.selecttype == 1) {
|
||||||
|
await accountPaymember({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
memberId: props.orderId,
|
||||||
|
amount: props.amount
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await cashPay({
|
||||||
|
orderId: props.orderId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'bank'://银行卡
|
||||||
|
if (props.selecttype == 1) {//1 代表会员
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
payLoading.value = false
|
||||||
|
ElMessage.success('支付成功')
|
||||||
|
emit('paySuccess')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
payLoading.value = false
|
||||||
|
scanModalRef.value.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入
|
||||||
|
function amountInput(num) {
|
||||||
|
if (money.value + num <= props.amount) {
|
||||||
|
money.value = clearNoNum({ value: (money.value += num) })
|
||||||
|
} else {
|
||||||
|
money.value = clearNoNum({ value: `${props.amount}` })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
function delHandle() {
|
||||||
|
if (!money.value) return
|
||||||
|
money.value = money.value.substring(0, money.value.length - 1)
|
||||||
|
if (!money.value) {
|
||||||
|
money.value = '0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取支付方式
|
||||||
|
async function queryPayTypeAjax() {
|
||||||
|
try {
|
||||||
|
const res = await queryPayType({
|
||||||
|
shopId: store.userInfo.shopId
|
||||||
|
})
|
||||||
|
payList.value = res
|
||||||
|
if (res[0].payType == 'scanCode' || res[0].payType == 'deposit') {
|
||||||
|
scanModalRef.value.show()
|
||||||
|
payType.value = res[0].payType
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
money.value = `${props.amount}`
|
||||||
|
queryPayTypeAjax()
|
||||||
|
})
|
||||||
|
|
||||||
|
</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;
|
||||||
|
|
||||||
|
.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: 130px;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input_wrap {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--el-font-size-base);
|
||||||
|
padding: var(--el-font-size-base) 0;
|
||||||
|
|
||||||
|
.input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 60px;
|
||||||
|
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) / 4);
|
||||||
|
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>
|
||||||
|
|
@ -0,0 +1,421 @@
|
||||||
|
<!-- 扫码弹窗 -->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="dialog">
|
||||||
|
<el-dialog title="扫码支付" width="600" v-model="dialogVisible" @open="reset" @close="clearAutoCheckOrder">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import _ from "lodash";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import icon from "@/assets/icon_scan.png";
|
||||||
|
import { scanpay, queryOrder, quickPay, queryQuickPayStatus, accountPay, queryScanPay } from "@/api/pay";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import { useGlobal } from '@/store/global.js'
|
||||||
|
const store = useUser();
|
||||||
|
const global = useGlobal()
|
||||||
|
import {
|
||||||
|
queryMembermember,
|
||||||
|
createMembermember,
|
||||||
|
membermemberScanPay,
|
||||||
|
accountPaymember,
|
||||||
|
} from "@/api/member/index.js";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
const emits = defineEmits(["success"]);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
amount: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
selecttype: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
orderId: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
fast: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
payType: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: "",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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('')
|
||||||
|
|
||||||
|
// 提交扫码支付
|
||||||
|
async function submitHandle() {
|
||||||
|
try {
|
||||||
|
if (!scanCode.value) return;
|
||||||
|
loading.value = true;
|
||||||
|
if (props.selecttype == 1) {
|
||||||
|
await membermemberScanPay({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
memberId: props.orderId,
|
||||||
|
amount: props.amount,
|
||||||
|
authCode: scanCode.value,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (props.fast) {
|
||||||
|
await quickPay({
|
||||||
|
amount: props.amount,
|
||||||
|
authCode: scanCode.value,
|
||||||
|
payType: "scanCode",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (props.payType == 'scanCode') {
|
||||||
|
await scanpay({
|
||||||
|
orderId: props.orderId,
|
||||||
|
authCode: scanCode.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (props.payType == 'deposit') {
|
||||||
|
await accountPay({
|
||||||
|
orderId: props.orderId,
|
||||||
|
memberId: '',
|
||||||
|
memberAccount: scanCode.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = false;
|
||||||
|
scanCode.value = "";
|
||||||
|
ElMessage.success("支付成功");
|
||||||
|
dialogVisible.value = false;
|
||||||
|
emits("success");
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
if (error.code === "100015") {
|
||||||
|
userPayWait.value = true;
|
||||||
|
fastOrder.value = error.data
|
||||||
|
autoCheckOrder()
|
||||||
|
} else {
|
||||||
|
scanCode.value = "";
|
||||||
|
loading.value = false;
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const timer = ref(null)
|
||||||
|
// 自动查询订单状态
|
||||||
|
function autoCheckOrder() {
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
checkPayStauts(false)
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除自动查询扫码支付订单
|
||||||
|
function clearAutoCheckOrder() {
|
||||||
|
clearInterval(timer.value)
|
||||||
|
timer.value = null
|
||||||
|
// 开启叫号功能
|
||||||
|
global.updateData(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户支付状态
|
||||||
|
async function checkPayStauts(tips = true) {
|
||||||
|
try {
|
||||||
|
if (props.selecttype == 1) {
|
||||||
|
// 会员扫码充值
|
||||||
|
const res = await queryScanPay({ flowId: fastOrder.value.id });
|
||||||
|
if (res.status == 0) {
|
||||||
|
userPayWait.value = false
|
||||||
|
loading.value = false;
|
||||||
|
scanCode.value = "";
|
||||||
|
ElMessage.success("支付成功");
|
||||||
|
dialogVisible.value = false;
|
||||||
|
clearAutoCheckOrder()
|
||||||
|
emits("success");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res.status == 7) {
|
||||||
|
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 queryOrder({ orderId: props.orderId });
|
||||||
|
if (res.status == "closed") {
|
||||||
|
userPayWait.value = false
|
||||||
|
loading.value = false;
|
||||||
|
scanCode.value = "";
|
||||||
|
ElMessage.success("支付成功");
|
||||||
|
dialogVisible.value = false;
|
||||||
|
clearAutoCheckOrder()
|
||||||
|
emits("success");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res.status == "paying") {
|
||||||
|
if (tips) {
|
||||||
|
ElMessage.warning("用户支付中...");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
clearAutoCheckOrder()
|
||||||
|
ElMessage.error(res.payRemark || "支付失败!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新扫码
|
||||||
|
function resetScanCode() {
|
||||||
|
clearAutoCheckOrder()
|
||||||
|
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);
|
||||||
|
submitHandle();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
inputRef.value.focus();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
loading.value = false;
|
||||||
|
scanCode.value = "";
|
||||||
|
// 关闭叫号功能
|
||||||
|
global.updateData(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
@ -1,33 +1,32 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog title="选择规格" width="800" v-model="show">
|
<el-dialog :title="goods.name" width="600" v-model="dialogVisible">
|
||||||
<div class="header">选择规格</div>
|
<div class="header">选择规格</div>
|
||||||
<div class="row">
|
<div v-loading="loading">
|
||||||
<div class="title">规格</div>
|
<div class="row" v-for="(item, index) in goods.selectSpec" :key="index">
|
||||||
|
<div class="title">{{ item.name }}</div>
|
||||||
<div class="sku_wrap">
|
<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" @click="selectedSku(index, i)" class="btn">{{ val.name }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
|
<div class="info">
|
||||||
|
<template v-if="goodsInfo.id">
|
||||||
|
<span>库存:{{ goodsInfo.stockNumber }}</span>
|
||||||
|
<span>¥{{ goodsInfo.salePrice }}</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="btn_wrap">
|
||||||
<div class="btn">
|
<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>
|
||||||
<div class="btn">
|
<div class="btn">
|
||||||
<el-button type="primary" style="width: 100%;">确认</el-button>
|
<el-button type="primary" style="width: 100%;" :disabled="!goodsInfo.id"
|
||||||
|
@click="submitSku">确认</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -35,8 +34,147 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
const show = ref(true)
|
import { useUser } from "@/store/user.js"
|
||||||
|
import { queryProductSku } from '@/api/product'
|
||||||
|
|
||||||
|
const store = useUser();
|
||||||
|
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)
|
||||||
|
|
||||||
|
// 确认选择规格
|
||||||
|
function submitSku() {
|
||||||
|
dialogVisible.value = false
|
||||||
|
switch (type.value) {
|
||||||
|
case 'shop':
|
||||||
|
emit('success', goodsInfo.value)
|
||||||
|
break;
|
||||||
|
case 'cart':
|
||||||
|
emit('success', goods.value)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择规格
|
||||||
|
function selectedSku(index, i) {
|
||||||
|
goods.value.selectSpec[index].selectSpecResult.map(item => {
|
||||||
|
item.active = 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过选中的商品规格查询价格
|
||||||
|
async function queryProductSkuAjax() {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
const res = await queryProductSku({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
productId: type.value == 'shop' ? goods.value.id : goods.value.productId,
|
||||||
|
spec_tag: selectedSkuTag.value
|
||||||
|
})
|
||||||
|
goodsInfo.value = res
|
||||||
|
if (type.value == 'cart') {
|
||||||
|
goods.value.skuId = res.id
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false
|
||||||
|
}, 100)
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示规格
|
||||||
|
function show(item, t = 'shop') {
|
||||||
|
goodsInfo.value = {}
|
||||||
|
goods.value = {}
|
||||||
|
selectedSkuNum.value = 0
|
||||||
|
dialogVisible.value = true
|
||||||
|
goods.value = ""
|
||||||
|
goods.value = item
|
||||||
|
type.value = t
|
||||||
|
goods.value.selectSpec = JSON.parse(goods.value.selectSpec)
|
||||||
|
goods.value.selectSpec.map(item => {
|
||||||
|
let arr = []
|
||||||
|
item.selectSpecResult.map(val => {
|
||||||
|
switch (type.value) {
|
||||||
|
case 'shop':
|
||||||
|
arr.push({
|
||||||
|
active: false,
|
||||||
|
name: val
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'cart':
|
||||||
|
// 如果从购物车选择规格需要做选中效果
|
||||||
|
const skus = goods.value.skuName.split(',')
|
||||||
|
arr.push({
|
||||||
|
active: !!skus.find(item => item === val),
|
||||||
|
name: val
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
item.selectSpecResult = arr
|
||||||
|
})
|
||||||
|
|
||||||
|
let arr = []
|
||||||
|
|
||||||
|
goods.value.selectSpec.map(item => {
|
||||||
|
if (item.selectSpecResult.length) {
|
||||||
|
arr.push({ ...item })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
goods.value.selectSpec = arr
|
||||||
|
|
||||||
|
selectedSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
@ -47,41 +185,33 @@ const show = ref(true)
|
||||||
|
|
||||||
.row {
|
.row {
|
||||||
border-bottom: 1px solid #ececec;
|
border-bottom: 1px solid #ececec;
|
||||||
margin-top: 20px;
|
margin-top: var(--el-font-size-base);
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 20px;
|
font-size: var(--el-font-size-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sku_wrap {
|
.sku_wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 14px 0;
|
padding: var(--el-font-size-base) 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
.item {
|
gap: var(--el-font-size-base);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
|
padding-top: 30px;
|
||||||
|
|
||||||
|
.info {
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn_wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-top: 100px;
|
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
@ -90,5 +220,6 @@ const show = ref(true)
|
||||||
margin-left: 14px;
|
margin-left: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
<!-- 取餐号组件 -->
|
||||||
|
<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" 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="footer">
|
||||||
|
<el-button type="primary" style="width: 100%" @click="confirmHandle">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
function delHandle() {
|
||||||
|
if (!number.value) return;
|
||||||
|
number.value = number.value.substring(0, number.value.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认
|
||||||
|
function confirmHandle() {
|
||||||
|
if (!number.value) return
|
||||||
|
if (props.type == 2) {
|
||||||
|
if (number.value.length < 6) {
|
||||||
|
ElMessage.error('请输入正确的密码')
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
emit("success", number.value);
|
||||||
|
dialogVisible.value = false;
|
||||||
|
}
|
||||||
|
} 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>
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import { createRouter, createWebHashHistory } from "vue-router";
|
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 = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
name: "home",
|
name: "home",
|
||||||
|
// component: test,
|
||||||
component: home,
|
component: home,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -23,14 +25,74 @@ const routes = [
|
||||||
},
|
},
|
||||||
component: () => import("@/views/register.vue"),
|
component: () => import("@/views/register.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/group_buy",
|
||||||
|
name: "group_buy",
|
||||||
|
meta: {
|
||||||
|
index: 1,
|
||||||
|
},
|
||||||
|
component: () => import("@/views/group_buy/index.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/table",
|
path: "/table",
|
||||||
name: "table",
|
name: "table",
|
||||||
meta: {
|
meta: {
|
||||||
index: 1,
|
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: "/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({
|
const router = createRouter({
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
|
export const useGlobal = defineStore({
|
||||||
|
id: "global",
|
||||||
|
state: () => ({
|
||||||
|
// 是否监听叫号
|
||||||
|
isCallNumber: true,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
// 更新状态
|
||||||
|
updateData(state) {
|
||||||
|
this.isCallNumber = state;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,220 @@
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { ipcRenderer } from "electron";
|
||||||
|
import { bySubType } from "@/api/device";
|
||||||
|
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";
|
||||||
|
|
||||||
|
export const usePrint = defineStore({
|
||||||
|
id: "print",
|
||||||
|
state: () => ({
|
||||||
|
localDevices: [], // 本地打印机列表
|
||||||
|
deviceNoteList: [], // 添加的打印机
|
||||||
|
deviceLableList: [], // 添加的打印机
|
||||||
|
labelList: [], // 要打印的队列数据
|
||||||
|
printTimer: null,
|
||||||
|
receiptList: [], // 小票队列数据
|
||||||
|
receiptTimer: null,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
// 获取本地打印机和已添加的可以用打印机列表
|
||||||
|
async init() {
|
||||||
|
const store = useUser();
|
||||||
|
|
||||||
|
// 获取本地打印机
|
||||||
|
ipcRenderer.send("getPrintList");
|
||||||
|
ipcRenderer.on("printList", (event, arg) => {
|
||||||
|
// localPrintList.value = arg;
|
||||||
|
// console.log(localPrintList.value);
|
||||||
|
this.localDevices = arg;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取已添加的小票打印机
|
||||||
|
this.deviceNoteList = await bySubType({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
contentType: "local",
|
||||||
|
subType: "cash",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取已添加的标签打印机
|
||||||
|
this.deviceLableList = await bySubType({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
contentType: "local",
|
||||||
|
subType: "label",
|
||||||
|
});
|
||||||
|
console.log("打印队列初始化成功");
|
||||||
|
},
|
||||||
|
// 检查本地打印机是否能正常使用
|
||||||
|
checkLocalPrint(deviceName) {
|
||||||
|
let print = "";
|
||||||
|
for (let item of this.localDevices) {
|
||||||
|
if (item.name == deviceName) {
|
||||||
|
print = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!print.name) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 打印标签小票
|
||||||
|
labelPrint(props) {
|
||||||
|
if (
|
||||||
|
this.deviceLableList.length &&
|
||||||
|
this.checkLocalPrint(this.deviceLableList[0].config.deviceName)
|
||||||
|
) {
|
||||||
|
let pids = this.deviceLableList[0].config.categoryList.map(
|
||||||
|
(item) => item.id
|
||||||
|
);
|
||||||
|
|
||||||
|
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].config.deviceName,
|
||||||
|
// deviceName: "Xprinter XP-T202UA",
|
||||||
|
createdAt: dayjs(props.createdAt).format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
isPrint: false,
|
||||||
|
count: `${count}/${sum}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 执行打印操作
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 800);
|
||||||
|
},
|
||||||
|
// 添加小票打印对列表数据
|
||||||
|
pushReceiptData(props, isDevice = true) {
|
||||||
|
console.log("pushReceiptData===", props);
|
||||||
|
if (!isDevice) {
|
||||||
|
// 测试打印,无需校验本地打印机
|
||||||
|
const store = useUser();
|
||||||
|
props.shop_name = store.userInfo.shopName;
|
||||||
|
props.loginAccount = store.userInfo.loginAccount;
|
||||||
|
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;
|
||||||
|
|
||||||
|
this.receiptList.push(props);
|
||||||
|
this.startReceiptPrint();
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
this.deviceNoteList.length &&
|
||||||
|
this.checkLocalPrint(this.deviceNoteList[0].config.deviceName)
|
||||||
|
) {
|
||||||
|
const store = useUser();
|
||||||
|
props.deviceName = this.deviceNoteList[0].config.deviceName;
|
||||||
|
props.shop_name = store.userInfo.shopName;
|
||||||
|
props.loginAccount = store.userInfo.loginAccount;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}, 800);
|
||||||
|
},
|
||||||
|
// 打印交班小票
|
||||||
|
printWork(data) {
|
||||||
|
if (
|
||||||
|
this.deviceNoteList.length &&
|
||||||
|
this.checkLocalPrint(this.deviceNoteList[0].config.deviceName)
|
||||||
|
) {
|
||||||
|
data.deviceName = this.deviceNoteList[0].config.deviceName;
|
||||||
|
lodopPrintWork(data);
|
||||||
|
} else {
|
||||||
|
console.log("交班小票:没有小票打印机");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 打印订单发票
|
||||||
|
printInvoice(data) {
|
||||||
|
if (
|
||||||
|
this.deviceNoteList.length &&
|
||||||
|
this.checkLocalPrint(this.deviceNoteList[0].config.deviceName)
|
||||||
|
) {
|
||||||
|
data.deviceName = this.deviceNoteList[0].config.deviceName;
|
||||||
|
invoicePrint(data);
|
||||||
|
} else {
|
||||||
|
console.log("订单发票:没有小票打印机");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 打印退单小票
|
||||||
|
printRefund(data) {
|
||||||
|
if (
|
||||||
|
this.deviceNoteList.length &&
|
||||||
|
this.checkLocalPrint(this.deviceNoteList[0].config.deviceName)
|
||||||
|
) {
|
||||||
|
data.deviceName = this.deviceNoteList[0].config.deviceName;
|
||||||
|
refundPrint(data);
|
||||||
|
} else {
|
||||||
|
console.log("退单小票:没有小票打印机");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
import _ from "lodash";
|
||||||
|
import { dayjs } from "element-plus";
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import { usePrint } from "@/store/print.js";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import useStorage from "@/utils/useStorage";
|
||||||
|
import ReconnectingWebSocket from "reconnecting-websocket";
|
||||||
|
import { ipcRenderer } from "electron";
|
||||||
|
|
||||||
|
export const useSocket = defineStore({
|
||||||
|
id: uuidv4(),
|
||||||
|
state: () => ({
|
||||||
|
online: false, // 在线状态
|
||||||
|
ws: null, // websocket实例
|
||||||
|
uuid: "", // 长连接唯一id
|
||||||
|
heartbeatTimer: null, // 心跳计时器
|
||||||
|
orderList: [],
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
// 创建uuid
|
||||||
|
createUUID() {
|
||||||
|
if (!useStorage.get("uuid")) {
|
||||||
|
ipcRenderer.send("getOSmacSync");
|
||||||
|
// useStorage.set("uuid", uuidv4());
|
||||||
|
ipcRenderer.on("getOSmacRes", (event, arg) => {
|
||||||
|
useStorage.set("uuid", arg);
|
||||||
|
this.uuid = useStorage.get("uuid");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.uuid = useStorage.get("uuid");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 关闭ws
|
||||||
|
close() {
|
||||||
|
console.log("关闭ws");
|
||||||
|
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 }
|
||||||
|
),
|
||||||
|
// 初始化
|
||||||
|
init(wsUrl = import.meta.env.VITE_API_WSS) {
|
||||||
|
this.createUUID();
|
||||||
|
const store = useUser();
|
||||||
|
const printStore = usePrint();
|
||||||
|
|
||||||
|
printStore.init();
|
||||||
|
|
||||||
|
if (this.ws == null) {
|
||||||
|
console.log("创建新的ws连接");
|
||||||
|
|
||||||
|
const protocols = []; // 可选的子协议数组
|
||||||
|
const options = {
|
||||||
|
// 自动重新连接的选项(可选)
|
||||||
|
connectionTimeout: 1000,
|
||||||
|
maxRetries: 100,
|
||||||
|
};
|
||||||
|
this.ws = new ReconnectingWebSocket(wsUrl, protocols, options);
|
||||||
|
} else {
|
||||||
|
console.log("重新连接ws");
|
||||||
|
this.wsReconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ws.addEventListener("open", (event) => {
|
||||||
|
console.log("wss连接成功");
|
||||||
|
this.online = true;
|
||||||
|
// 清除心跳
|
||||||
|
this.clearHeartBeat();
|
||||||
|
|
||||||
|
console.log(this);
|
||||||
|
|
||||||
|
this.ws.send(
|
||||||
|
JSON.stringify({
|
||||||
|
type: "connect",
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
clientId: this.uuid,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.startheartbeat();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.addEventListener("message", (e) => {
|
||||||
|
let data = JSON.parse(e.data);
|
||||||
|
if (data.type == "order") {
|
||||||
|
console.log("接收消息", data);
|
||||||
|
this.ws.send(
|
||||||
|
JSON.stringify({
|
||||||
|
type: "send",
|
||||||
|
orderNo: data.orderInfo.orderNo,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
// 接收订单消息,打印小票
|
||||||
|
// printBill(data)
|
||||||
|
// 打印标签小票
|
||||||
|
if (!this.orderList.some((el) => el == data.orderInfo.orderNo)) {
|
||||||
|
// console.log("打印", data);
|
||||||
|
printStore.labelPrint(data);
|
||||||
|
printStore.pushReceiptData(data);
|
||||||
|
this.orderList.push(data.orderInfo.orderNo);
|
||||||
|
if (this.orderList.length > 30) {
|
||||||
|
this.orderList.splice(0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (data.type == "heartbeat") {
|
||||||
|
console.log("接收心跳");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.addEventListener("error", () => {
|
||||||
|
console.log("WebSocket连接发生错误");
|
||||||
|
this.online = false;
|
||||||
|
this.clearHeartBeat();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.addEventListener("error", (e) => {
|
||||||
|
console.log("ws关闭了", e);
|
||||||
|
this.online = false;
|
||||||
|
this.clearHeartBeat();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 启动心跳连接
|
||||||
|
startheartbeat() {
|
||||||
|
this.heartbeatTimer = setInterval(() => {
|
||||||
|
console.log("发送心跳");
|
||||||
|
this.ws.send(JSON.stringify({ type: "heartbeat" }));
|
||||||
|
}, 10000);
|
||||||
|
},
|
||||||
|
// 清除心跳
|
||||||
|
clearHeartBeat() {
|
||||||
|
// 清除心跳
|
||||||
|
clearInterval(this.heartbeatTimer);
|
||||||
|
this.heartbeatTimer = null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -1,13 +1,24 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
export const useUserStore = defineStore({
|
import { login } from "@/api/user";
|
||||||
|
import useStorage from "@/utils/useStorage";
|
||||||
|
|
||||||
|
export const useUser = defineStore({
|
||||||
id: "user",
|
id: "user",
|
||||||
state: () => ({
|
state: () => ({
|
||||||
name: "张三",
|
userInfo: useStorage.get("userInfo"),
|
||||||
token: "sas121sasdADSAD",
|
token: useStorage.get("token"),
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
login(data) {
|
// 登录
|
||||||
this.name = data;
|
userlogin(param) {
|
||||||
|
return login(param).then((res) => {
|
||||||
|
this.userInfo = res;
|
||||||
|
this.token = res.token;
|
||||||
|
useStorage.set("token", this.token);
|
||||||
|
// this.userInfo.shopId = "24";
|
||||||
|
useStorage.set("userInfo", this.userInfo);
|
||||||
|
return this.userInfo;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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,59 @@
|
||||||
|
/**
|
||||||
|
* 生成范围随机数
|
||||||
|
* @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 = "";
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,68 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import useStorage from '@/utils/useStorage'
|
||||||
|
import router from '@/router'
|
||||||
|
|
||||||
const request = axios.create({
|
const service = axios.create({
|
||||||
baseURL: "http://localhost",
|
baseURL: import.meta.env.MODE == 'development' ? '/api/' : import.meta.env.VITE_API_URL,
|
||||||
timeout: 100000,
|
// withCredentials: true, // 跨域请求时发送 cookies
|
||||||
|
timeout: 5000, // 请求超时
|
||||||
});
|
});
|
||||||
|
|
||||||
request.interceptors.request.use((config) => {});
|
// 请求拦截器
|
||||||
|
service.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
// 在发送请求之前做些什么 token
|
||||||
|
if (useStorage.get("token")) {
|
||||||
|
// 让每个请求携带 token
|
||||||
|
// ['X-Token'] 是自定义标题键
|
||||||
|
// 请根据实际情况修改
|
||||||
|
config.headers["token"] = useStorage.get("token");
|
||||||
|
config.headers["loginName"] = useStorage.get("userInfo").loginName;
|
||||||
|
config.headers["clientType"] = 'pc';
|
||||||
|
// 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 == '0') {
|
||||||
|
return response.data.data;
|
||||||
|
} else if (+response.data.code == '9999') {
|
||||||
|
ElMessage.error('登录已过期,请重新登录')
|
||||||
|
useStorage.clear()
|
||||||
|
router.replace("/login")
|
||||||
|
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,362 @@
|
||||||
|
<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>{{ 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-select v-model="form.config.width">
|
||||||
|
<el-option label="58mm" value="58"></el-option>
|
||||||
|
<el-option label="80mm" value="80"></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.config.deviceName">
|
||||||
|
<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-input v-model="form.name" placeholder="请输入设备名称"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="打印份数">
|
||||||
|
<el-select v-model="form.config.printerNum">
|
||||||
|
<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">预结算单【{{ printData.orderInfo.masterId }}】</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.amount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="row between">
|
||||||
|
<span>余额:</span>
|
||||||
|
<span>0.00</span>
|
||||||
|
</div>
|
||||||
|
<div class="line"></div>
|
||||||
|
<div class="row">备注:{{ printData.remark }}</div>
|
||||||
|
<div class="row">打印时间:{{ printData.printTime }}</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>
|
||||||
|
</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 { tbPrintMachinePost, tbPrintMachineDetail } from "@/api/device";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import { Loading } from "element-plus/es/components/loading/src/service";
|
||||||
|
import { usePrint } from "@/store/print.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 form = ref({
|
||||||
|
id: "",
|
||||||
|
contentType: "",
|
||||||
|
connectionType: "USB",
|
||||||
|
config: {
|
||||||
|
deviceName: "",
|
||||||
|
width: "58", // 设备尺寸毫米mm
|
||||||
|
printerNum: 1, //打印份数
|
||||||
|
categoryList: [], // 商品分类
|
||||||
|
model: "normal", // 出品模式,
|
||||||
|
feet: "2",
|
||||||
|
autoCut: 0,
|
||||||
|
printSub: 1,
|
||||||
|
},
|
||||||
|
name: "小票打印机",
|
||||||
|
subType: "cash", // 打印类型
|
||||||
|
status: 1,
|
||||||
|
sort: "",
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const printDataLoading = ref(false)
|
||||||
|
const printData = reactive({
|
||||||
|
shop_name: store.userInfo.shopName,
|
||||||
|
loginAccount: store.userInfo.loginAccount,
|
||||||
|
isBefore: true,
|
||||||
|
carts: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: '【测试】娃哈哈矿泉水',
|
||||||
|
skuName: '500ml',
|
||||||
|
salePrice: '1.0',
|
||||||
|
number: '10',
|
||||||
|
totalAmount: '10'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: '【测试】柠檬奶茶',
|
||||||
|
skuName: '加冰、加珍珠',
|
||||||
|
salePrice: '10',
|
||||||
|
number: '2',
|
||||||
|
totalAmount: '20'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
amount: '30.00',
|
||||||
|
remark: '给我多放点辣椒,谢谢老板',
|
||||||
|
orderInfo: {
|
||||||
|
masterId: '#002',
|
||||||
|
orderNo: '202404021023542223445'
|
||||||
|
},
|
||||||
|
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.config.deviceName) {
|
||||||
|
ElMessage.warning("请选择打印设备");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printDataLoading.value = true
|
||||||
|
printData.deviceName = form.value.config.deviceName
|
||||||
|
printData.printTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
printStore.pushReceiptData(printData, false)
|
||||||
|
setTimeout(() => {
|
||||||
|
printDataLoading.value = false
|
||||||
|
}, 1500)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交打印机
|
||||||
|
async function submitHandle() {
|
||||||
|
try {
|
||||||
|
if (!form.value.config.deviceName) {
|
||||||
|
ElMessage.warning("请选择打印设备");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Loading.value = true;
|
||||||
|
await tbPrintMachinePost(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 {
|
||||||
|
const res = await tbPrintMachineDetail(route.query.id);
|
||||||
|
form.value = res;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
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.5;
|
||||||
|
margin-left: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 0 15px;
|
||||||
|
|
||||||
|
.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;
|
||||||
|
|
||||||
|
&.between {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn_wrap {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
padding: 20px 0;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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,325 @@
|
||||||
|
<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>{{ 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-select v-model="form.config.width">
|
||||||
|
<el-option label="58mm" value="58"></el-option>
|
||||||
|
<el-option label="80mm" value="80"></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.config.deviceName">
|
||||||
|
<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-input v-model="form.name" placeholder="请输入设备名称"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="打印份数">
|
||||||
|
<el-select v-model="form.config.printerNum">
|
||||||
|
<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="商品分类">
|
||||||
|
<div style="cursor: pointer" @click="classifyRef.show()">
|
||||||
|
<span style="color: #409eff" v-for="item in form.config.categoryList">
|
||||||
|
{{ item.name }},
|
||||||
|
</span>
|
||||||
|
<span style="color: #e65d6e" v-if="!form.config.categoryList.length">
|
||||||
|
请选择分类
|
||||||
|
</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="../../assets/prinnt_label_logo.png" />
|
||||||
|
<!-- <span class="title">双屿Pisces</span> -->
|
||||||
|
</div>
|
||||||
|
<div class="number_wrap">
|
||||||
|
<div class="num" v-if="printData.outNumber">{{ printData.outNumber }}</div>
|
||||||
|
<div class="info" v-if="printData.masterId">座位号:{{ 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%" @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.config.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 { tbPrintMachinePost, tbPrintMachineDetail } from "@/api/device";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import { Loading } from "element-plus/es/components/loading/src/service";
|
||||||
|
import classify from "@/components/classify/index.vue";
|
||||||
|
import QRCode from 'qrcode'
|
||||||
|
import { usePrint } from "@/store/print.js";
|
||||||
|
|
||||||
|
const printStore = usePrint();
|
||||||
|
|
||||||
|
const store = useUser();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const classifyRef = ref(null);
|
||||||
|
const printList = ref([]);
|
||||||
|
const feets = ref([0, 1, 2, 3, 4, 5, 8]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const form = ref({
|
||||||
|
id: "",
|
||||||
|
contentType: "",
|
||||||
|
connectionType: "USB",
|
||||||
|
config: {
|
||||||
|
deviceName: "",
|
||||||
|
width: "40", // 设备尺寸毫米mm
|
||||||
|
printerNum: 1, //打印份数
|
||||||
|
categoryList: [], // 商品分类
|
||||||
|
model: "normal", // 出品模式,
|
||||||
|
feet: "2",
|
||||||
|
autoCut: 0,
|
||||||
|
printSub: 1,
|
||||||
|
},
|
||||||
|
name: "标签打印机",
|
||||||
|
subType: "label", // 打印类型
|
||||||
|
status: 1,
|
||||||
|
sort: "",
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const canvasRef = ref(null)
|
||||||
|
const printData = ref({
|
||||||
|
deviceName: '',
|
||||||
|
outNumber: '123',
|
||||||
|
name: '甜橙马黛茶',
|
||||||
|
skuName: '加奶、加珍珠',
|
||||||
|
masterId: '#A9',
|
||||||
|
createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取打印机列表
|
||||||
|
function getPrintList() {
|
||||||
|
ipcRenderer.send("getPrintList");
|
||||||
|
ipcRenderer.on("printList", (event, arg) => {
|
||||||
|
printList.value = arg;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试打印
|
||||||
|
const printHandle = _.throttle(function () {
|
||||||
|
if (!form.value.config.deviceName) {
|
||||||
|
ElMessage.error("请选择打印设备");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printData.value.deviceName = form.value.config.deviceName
|
||||||
|
ipcRenderer.send(
|
||||||
|
"printerTagSync",
|
||||||
|
JSON.stringify(printData.value)
|
||||||
|
);
|
||||||
|
}, 1500, { leading: true, trailing: false })
|
||||||
|
|
||||||
|
// 提交打印机
|
||||||
|
async function submitHandle() {
|
||||||
|
try {
|
||||||
|
if (!form.value.config.deviceName) {
|
||||||
|
ElMessage.warning("请选择打印设备");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Loading.value = true;
|
||||||
|
await tbPrintMachinePost(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 {
|
||||||
|
const res = await tbPrintMachineDetail(route.query.id);
|
||||||
|
form.value = res;
|
||||||
|
printData.value.deviceName = res.config.deviceName
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.number_wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
.num {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
margin-left: 12px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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,325 @@
|
||||||
|
<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.config.deviceName }}</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 {
|
||||||
|
tbPrintMachineGet,
|
||||||
|
tbPrintMachineDelete,
|
||||||
|
tbPrintMachinePost,
|
||||||
|
} from "@/api/device";
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import icons from "./icons";
|
||||||
|
import { usePrint } from "@/store/print.js";
|
||||||
|
|
||||||
|
const printStore = usePrint();
|
||||||
|
const store = useUser();
|
||||||
|
|
||||||
|
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 tbPrintMachinePost(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 tbPrintMachineDelete({ id: deleteId.value });
|
||||||
|
delLoading.value = false;
|
||||||
|
dialogVisible.value = false;
|
||||||
|
ElMessage.success("删除成功");
|
||||||
|
tbPrintMachineGetAjax();
|
||||||
|
printStore.init();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取打印机列表
|
||||||
|
async function tbPrintMachineGetAjax() {
|
||||||
|
try {
|
||||||
|
const res = await tbPrintMachineGet({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
page: 0,
|
||||||
|
pageSize: 100,
|
||||||
|
});
|
||||||
|
list.value = res.list;
|
||||||
|
} 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,491 @@
|
||||||
|
<!-- 扫码弹窗 -->
|
||||||
|
|
||||||
|
<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-if="props.type == 2">
|
||||||
|
<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 } 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;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
groupDetailLoading.value = false
|
||||||
|
detailVisible.value = false
|
||||||
|
scanCode.value = ''
|
||||||
|
inputRef.value.focus();
|
||||||
|
ElMessage.success('核销成功')
|
||||||
|
emits('succcess')
|
||||||
|
} catch (error) {
|
||||||
|
groupDetailLoading.value = false
|
||||||
|
console.log('groupOrdergroupScanHandle.error', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false
|
||||||
|
console.log('submitHandle.error', error);
|
||||||
|
if (error.code == 4399) {
|
||||||
|
BindShopRef.value.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新扫码
|
||||||
|
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,481 @@
|
||||||
|
<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="scanGroupRef.show()">核销团购券</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" width="100">
|
||||||
|
<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>
|
||||||
|
</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" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { groupOrderlist, douyinorderlist, douyinfulfilmentcertificatecancel } 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'
|
||||||
|
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: 2,
|
||||||
|
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: '抖音'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
// 本店团购订单状态
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tableData.status = ''
|
||||||
|
tableData.page = 1
|
||||||
|
tableData.list = []
|
||||||
|
groupOrderlistAjax()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态
|
||||||
|
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(() => { })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取团购订单数据
|
||||||
|
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;
|
||||||
|
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,173 @@
|
||||||
|
<template>
|
||||||
|
<div class="operation_wrap">
|
||||||
|
<div class="item" :class="{ disabled: props.item.number <= 1 || !props.item.id }" @click="numberChange('sub')">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<SemiSelect />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div class="item number" @click="props.item.id && takeFoodCodeRef.show()">
|
||||||
|
<el-text class="num">{{ props.item.number || 1 }}</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="item" @click="numberChange('add')">
|
||||||
|
<el-icon class="icon add">
|
||||||
|
<CloseBold />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div class="item" :class="{ disabled: (props.item.id && !props.item.tbProductSpec) }" @click="showSkuModal">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<Filter />
|
||||||
|
</el-icon>
|
||||||
|
<el-text class="t">规格</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="item" :class="{ disabled: props.item.isGift == 'true' }" @click="giftPackHandle('isGift')">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<ShoppingBag />
|
||||||
|
</el-icon>
|
||||||
|
<el-text class="t">赠送</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="item" :class="{ disabled: props.item.isPack == 'true' }" @click="giftPackHandle('isPack')">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<Box />
|
||||||
|
</el-icon>
|
||||||
|
<el-text class="t">打包</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="item" @click="props.item.id && emit('delete', props.item)">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<Delete />
|
||||||
|
</el-icon>
|
||||||
|
<el-text class="t">删除</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="item" @click="props.item.id && emit('pending', props.item)">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<Sell />
|
||||||
|
</el-icon>
|
||||||
|
<el-text class="t">挂单</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="item" @click="props.item.id && emit('clearCart')">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<RefreshRight />
|
||||||
|
</el-icon>
|
||||||
|
<el-text class="t">清空</el-text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<takeFoodCode ref="takeFoodCodeRef" title="修改商品数量" placeholder="请输入商品数量" @success="updateNumber" />
|
||||||
|
<!-- 购物车选择规格 -->
|
||||||
|
<skuModal ref="skuModalRef" @success="skuConfirm" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import takeFoodCode from '@/components/takeFoodCode.vue'
|
||||||
|
import skuModal from '@/components/skuModal.vue'
|
||||||
|
const props = defineProps({
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['confirm', 'delete', 'pending', 'clearCart'])
|
||||||
|
|
||||||
|
const takeFoodCodeRef = ref(null)
|
||||||
|
const skuModalRef = ref([])
|
||||||
|
|
||||||
|
// 赠送打包操作
|
||||||
|
function giftPackHandle(key) {
|
||||||
|
if (!props.item.id) return
|
||||||
|
if (props.item[key] == 'true') {
|
||||||
|
props.item[key] = false
|
||||||
|
} else {
|
||||||
|
props.item[key] = true
|
||||||
|
}
|
||||||
|
emit('confirm', props.item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加减修改数量
|
||||||
|
function numberChange(t) {
|
||||||
|
if (!props.item.id) return
|
||||||
|
switch (t) {
|
||||||
|
case 'sub':
|
||||||
|
if (props.item.number <= 1) return
|
||||||
|
props.item.number--
|
||||||
|
break;
|
||||||
|
case 'add':
|
||||||
|
props.item.number++
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
emit('confirm', props.item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入修改数量
|
||||||
|
function updateNumber(num) {
|
||||||
|
if (!props.item.id) return
|
||||||
|
props.item.number = num
|
||||||
|
emit('confirm', props.item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示规格
|
||||||
|
function showSkuModal() {
|
||||||
|
if (!props.item.id) return
|
||||||
|
if (props.item.tbProductSpec && props.item.tbProductSpec.specList) {
|
||||||
|
skuModalRef.value.show(props.item, 'cart')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改规格
|
||||||
|
function skuConfirm(e) {
|
||||||
|
if (!props.item.id) return
|
||||||
|
emit('confirm', e)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.operation_wrap {
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
width: 70px;
|
||||||
|
height: 34px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #efefef;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
|
||||||
|
.t {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
<!-- 分类 -->
|
||||||
|
<template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { queryCategory } from '@/api/product'
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const categorys = ref([])
|
||||||
|
const categorysActive = ref(0)
|
||||||
|
|
||||||
|
// 查询分类信息
|
||||||
|
async function queryCategoryAjax() {
|
||||||
|
try {
|
||||||
|
const res = await queryCategory({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 100
|
||||||
|
})
|
||||||
|
categorys.value = res.list
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
queryCategoryAjax()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
size="100%"
|
||||||
|
:with-header="false"
|
||||||
|
direction="btt"
|
||||||
|
v-model="dialogVisible"
|
||||||
|
>
|
||||||
|
<div class="drawer_wrap">
|
||||||
|
<div class="pay_wrap">
|
||||||
|
<fastPayCard
|
||||||
|
ref="fastPayCardRef"
|
||||||
|
@paySuccess="paySuccess"
|
||||||
|
@close="dialogVisible = false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import fastPayCard from "@/components/fastPayCard.vue";
|
||||||
|
|
||||||
|
const emit = defineEmits(["paySuccess"]);
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const fastPayCardRef = ref(null);
|
||||||
|
|
||||||
|
// 订单已支付
|
||||||
|
function paySuccess() {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
emit("paySuccess");
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
fastPayCardRef.value.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.drawer_wrap {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
padding: var(--el-font-size-base) 0;
|
||||||
|
.pay_wrap {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,552 @@
|
||||||
|
<!-- 商品列表 -->
|
||||||
|
<template>
|
||||||
|
<div class="header">
|
||||||
|
<div class="menus scroll-x">
|
||||||
|
<div class="item" :class="{ active: categorysActive == index }" v-for="(item, index) in categorys"
|
||||||
|
:key="item.id" @click="changeCategory(index)">
|
||||||
|
<el-text>{{ item.name }}</el-text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-popover trigger="click" :width="600" title="全部分类" :visible="showPopover">
|
||||||
|
<template #reference>
|
||||||
|
<div class="all" @click="showMoreMenu">
|
||||||
|
<el-icon class="icon" :class="{ active: showPopover }">
|
||||||
|
<Menu />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<div class="popover_wrap">
|
||||||
|
<el-button :plain="categorysActive != index" type="primary" v-for="(item, index) in categorys"
|
||||||
|
:key="item.id" @click="changeCategory(index)">
|
||||||
|
{{ item.name }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
<div class="search_wrap">
|
||||||
|
<div class="input">
|
||||||
|
<el-input placeholder="请输入商品名称查询" v-model="commdityName" clearable @focus="
|
||||||
|
global.updateData(false)" @blur="global.updateData(true)" @input="inputChange"></el-input>
|
||||||
|
</div>
|
||||||
|
<el-button :loading="searchLoading" :icon="Search" @click="searchHandle">搜索</el-button>
|
||||||
|
<!-- <el-button :icon="shopListType == 'text' ? 'PictureRounded' : 'PriceTag'"
|
||||||
|
@click="changeShopListType"></el-button> -->
|
||||||
|
</div>
|
||||||
|
<div class="shop_list" :class="{ img: shopListType == 'img' }" v-loading="loading">
|
||||||
|
<!-- <swiper class="swiper_box" direction="vertical" @slideChange="onSlideChange"> -->
|
||||||
|
<swiper class="swiper_box" direction="vertical" @slideChange="onSlideChange">
|
||||||
|
<swiper-slide class="slide_item" v-for="(goods, index) in goodsList" :key="index">
|
||||||
|
<div class="item_wrap" v-for="item in goods" :key="item.id" @click="showSkuHandle(item)">
|
||||||
|
<div class="item">
|
||||||
|
<div class="dot" v-if="item.orderCount">{{ item.orderCount }}</div>
|
||||||
|
<div class="cover" v-if="shopListType == 'img'">
|
||||||
|
<el-image :src="`${item.coverImg}?x-oss-process=image/resize,m_lfit,w_150,h_150`"
|
||||||
|
class="el_img" fit="cover"></el-image>
|
||||||
|
</div>
|
||||||
|
<div class="name"><el-text line-clamp="1">{{ item.name }}</el-text></div>
|
||||||
|
<div class="item_empty" v-if="shopListType == 'text'"></div>
|
||||||
|
<div class="price">
|
||||||
|
<el-text>¥{{ item.lowPrice }}</el-text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</swiper-slide>
|
||||||
|
</swiper>
|
||||||
|
</div>
|
||||||
|
<div class="empty">
|
||||||
|
<el-empty description="空空如也~" v-if="!goodsList.length" />
|
||||||
|
</div>
|
||||||
|
<!-- 选择规格 -->
|
||||||
|
<skuModal ref="skuModalRef" @success="skuConfirm" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { Search } from '@element-plus/icons-vue'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import useStorage from "@/utils/useStorage";
|
||||||
|
|
||||||
|
import skuModal from '@/components/skuModal.vue'
|
||||||
|
|
||||||
|
import { queryCategory, queryNewCommodityInfo, queryProductSku } from '@/api/product'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
|
||||||
|
import { Swiper, SwiperSlide } from 'swiper/vue'
|
||||||
|
import "swiper/swiper-bundle.css";
|
||||||
|
|
||||||
|
|
||||||
|
import { useGlobal } from '@/store/global.js'
|
||||||
|
const global = useGlobal()
|
||||||
|
|
||||||
|
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
masterId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['success'])
|
||||||
|
|
||||||
|
const skuModalRef = ref(null)
|
||||||
|
|
||||||
|
const shopListType = ref('img')
|
||||||
|
|
||||||
|
const categorys = ref([])
|
||||||
|
const categorysActive = ref(0)
|
||||||
|
|
||||||
|
const commdityName = ref('')
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const goodsList = ref([])
|
||||||
|
const goodsPage = ref(1)
|
||||||
|
const goodsPageSize = ref(12)
|
||||||
|
const finish = ref(false) // 是否加载完
|
||||||
|
const currentGoodsIndex = ref(0)
|
||||||
|
const loopMax = ref(0)
|
||||||
|
const loopTimer = ref(null)
|
||||||
|
|
||||||
|
const showPopover = ref(false)
|
||||||
|
|
||||||
|
const inputChange = _.debounce(function () {
|
||||||
|
searchHandle()
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
const searchLoading = ref(false)
|
||||||
|
function searchHandle() {
|
||||||
|
searchLoading.value = true
|
||||||
|
goodsList.value = []
|
||||||
|
goodsPage.value = 1
|
||||||
|
finish.value = false
|
||||||
|
currentGoodsIndex.value = 0
|
||||||
|
loopMax.value = 0
|
||||||
|
loopTimer.value = null
|
||||||
|
|
||||||
|
updataGoods()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认选择规格回调
|
||||||
|
function skuConfirm(params) {
|
||||||
|
emit('success', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示全部分类
|
||||||
|
function showMoreMenu() {
|
||||||
|
showPopover.value = !showPopover.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示sku
|
||||||
|
function showSkuHandle(item) {
|
||||||
|
if (item.typeEnum == 'sku') {
|
||||||
|
// 多规格
|
||||||
|
skuModalRef.value.show({ ...item })
|
||||||
|
} else {
|
||||||
|
// 单规格
|
||||||
|
queryProductSkuAjax(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过选中的商品规格查询价格
|
||||||
|
const queryProductSkuAjax = _.throttle(async function (goods) {
|
||||||
|
try {
|
||||||
|
const res = await queryProductSku({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
productId: goods.id,
|
||||||
|
spec_tag: ''
|
||||||
|
})
|
||||||
|
emit('success', res)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}, 1500)
|
||||||
|
|
||||||
|
// 切换商品显示模式
|
||||||
|
function changeShopListType() {
|
||||||
|
if (shopListType.value == 'text') {
|
||||||
|
shopListType.value = 'img'
|
||||||
|
} else {
|
||||||
|
shopListType.value = 'text'
|
||||||
|
}
|
||||||
|
useStorage.set('shopListType', shopListType.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从本地更新商品显示模式
|
||||||
|
function localUpdateShopListType() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let type = useStorage.get('shopListType')
|
||||||
|
if (type != null) {
|
||||||
|
shopListType.value = type
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换分类
|
||||||
|
function changeCategory(index) {
|
||||||
|
showPopover.value = false
|
||||||
|
categorysActive.value = index
|
||||||
|
|
||||||
|
useStorage.set('categorysActive', index)
|
||||||
|
|
||||||
|
goodsList.value = []
|
||||||
|
goodsPage.value = 1
|
||||||
|
finish.value = false
|
||||||
|
currentGoodsIndex.value = 0
|
||||||
|
loopMax.value = 0
|
||||||
|
clearInterval(loopTimer.value)
|
||||||
|
loopTimer.value = null
|
||||||
|
|
||||||
|
updataGoods()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从本地更新已选择的选项
|
||||||
|
function updateCategoryActive() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let index = useStorage.get('categorysActive')
|
||||||
|
if (index != null) {
|
||||||
|
categorysActive.value = index
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询分类信息
|
||||||
|
async function queryCategoryAjax() {
|
||||||
|
try {
|
||||||
|
const res = await queryCategory({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 100
|
||||||
|
})
|
||||||
|
categorys.value = res.list
|
||||||
|
categorys.value.unshift({
|
||||||
|
name: '全部',
|
||||||
|
id: ''
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询商品信息
|
||||||
|
async function productqueryCommodityInfoAjax() {
|
||||||
|
try {
|
||||||
|
// loading.value = true
|
||||||
|
const res = await queryNewCommodityInfo({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
categoryId: categorys.value[categorysActive.value].id,
|
||||||
|
commdityName: commdityName.value,
|
||||||
|
page: goodsPage.value,
|
||||||
|
pageSize: goodsPageSize.value,
|
||||||
|
masterId: props.masterId
|
||||||
|
})
|
||||||
|
if (res.list.length < goodsPageSize.value) {
|
||||||
|
finish.value = true
|
||||||
|
}
|
||||||
|
// loading.value = false
|
||||||
|
|
||||||
|
// if (res.pages > 2 && loopTimer.value == null) {
|
||||||
|
// // 启动循环任务
|
||||||
|
// // loopMax.value = parseInt(res.total / goodsPageSize.value)
|
||||||
|
// loopGetGoods()
|
||||||
|
// }
|
||||||
|
// if (goodsPage.value >= res.pages) {
|
||||||
|
// clearInterval(loopTimer.value)
|
||||||
|
// loopTimer.value = null
|
||||||
|
// }
|
||||||
|
return res
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 循环获取商品
|
||||||
|
function loopGetGoods() {
|
||||||
|
loopTimer.value = setInterval(async () => {
|
||||||
|
goodsPage.value++
|
||||||
|
const res = await productqueryCommodityInfoAjax()
|
||||||
|
goodsList.value.push(res.list)
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新商品数据
|
||||||
|
async function updateData() {
|
||||||
|
updataGoods()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新商品数据
|
||||||
|
async function updataGoods() {
|
||||||
|
if (!goodsList.value.length) {
|
||||||
|
const res = await productqueryCommodityInfoAjax()
|
||||||
|
goodsList.value.push(res.list)
|
||||||
|
|
||||||
|
if (!res.isLastPage) {
|
||||||
|
goodsPage.value++
|
||||||
|
const res2 = await productqueryCommodityInfoAjax()
|
||||||
|
goodsList.value.push(res2.list)
|
||||||
|
}
|
||||||
|
searchLoading.value = false
|
||||||
|
} else {
|
||||||
|
goodsPage.value = currentGoodsIndex.value + 1
|
||||||
|
// console.log('更新第二页数据', goodsPage.value);
|
||||||
|
const res = await productqueryCommodityInfoAjax()
|
||||||
|
goodsList.value[currentGoodsIndex.value] = res.list
|
||||||
|
searchLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 轮播图开始滑动
|
||||||
|
const onSlideChange = _.debounce(async function (e) {
|
||||||
|
if (e.activeIndex == e.previousIndex) return
|
||||||
|
if (e.activeIndex > e.previousIndex) {
|
||||||
|
// console.log('向下滑动');
|
||||||
|
{
|
||||||
|
goodsPage.value++
|
||||||
|
const res = await productqueryCommodityInfoAjax()
|
||||||
|
res.list.length && goodsList.value.push(res.list)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
goodsPage.value++
|
||||||
|
const res = await productqueryCommodityInfoAjax()
|
||||||
|
res.list.length && goodsList.value.push(res.list)
|
||||||
|
}
|
||||||
|
// goodsList.value.shift()
|
||||||
|
} else {
|
||||||
|
// console.log('向上滑动');
|
||||||
|
// goodsPage.value--
|
||||||
|
// const res = await productqueryCommodityInfoAjax()
|
||||||
|
// goodsList.value.unshift(res)
|
||||||
|
// goodsList.value.pop()
|
||||||
|
}
|
||||||
|
currentGoodsIndex.value = e.activeIndex
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
// 订单已结算,清楚商品所有数字
|
||||||
|
function clearDot() {
|
||||||
|
goodsList.value.map(item => {
|
||||||
|
item.map(val => {
|
||||||
|
val.orderCount = 0
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
updateData,
|
||||||
|
clearDot
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
localUpdateShopListType()
|
||||||
|
await updateCategoryActive()
|
||||||
|
await queryCategoryAjax()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.swiper_box {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.slide_item {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading_wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
color: #999;
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover_wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--el-font-size-base);
|
||||||
|
padding: var(--el-font-size-base) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
height: var(--el-component-size-large);
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menus {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
padding: 0 10px;
|
||||||
|
overflow-x: auto;
|
||||||
|
width: 100px;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
padding: 0 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.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: calc(var(--el-component-size-large) + 10px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
height: 60%;
|
||||||
|
border-left: 1px solid #ececec;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: #555;
|
||||||
|
font-size: 20px;
|
||||||
|
transition: all .2s ease-in-out;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
transform: rotate(45deg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search_wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
padding: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shop_list {
|
||||||
|
// max-height: calc(100vh - 40px - 80px - 40px);
|
||||||
|
height: calc(100vh - 40px - 80px - 28px);
|
||||||
|
// overflow-y: auto;
|
||||||
|
// display: flex;
|
||||||
|
// flex-wrap: wrap;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
&.img {
|
||||||
|
.item_wrap {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item_wrap {
|
||||||
|
float: left;
|
||||||
|
width: 20%;
|
||||||
|
height: 33.333%;
|
||||||
|
padding: 0 5px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
height: 100%;
|
||||||
|
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: 60%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.el_img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #efefef;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
padding: 0 10px;
|
||||||
|
height: 20%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
// margin-top: 20px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item_empty {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price {
|
||||||
|
height: 20%;
|
||||||
|
padding: 6px 10px;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,200 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="orderbox_right_inputkeyboard">
|
||||||
|
<div class='keyboard' @click.stop='_handleKeyPress'>
|
||||||
|
<div class='key-row'>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='1'>1</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='2'>2</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='3'>3</el-button>
|
||||||
|
</div>
|
||||||
|
<div class='key-row'>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='4'>4</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='5'>5</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='6'>6</el-button>
|
||||||
|
</div>
|
||||||
|
<div class='key-row'>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='7'>7</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='8'>8</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='9'>9</el-button>
|
||||||
|
</div>
|
||||||
|
<div class='key-row'>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='.'>.</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='0'>0</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='D'>c</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch } from 'vue'
|
||||||
|
import { useRoute } from "vue-router"
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import lodash_ from 'lodash'
|
||||||
|
|
||||||
|
const moneys = reactive({
|
||||||
|
money: ''
|
||||||
|
})
|
||||||
|
const emit = defineEmits(["consumeFees"])
|
||||||
|
watch(() => moneys.money, (newval, oldval) => {
|
||||||
|
console.log(newval)
|
||||||
|
emit('consumeFees', newval)
|
||||||
|
});
|
||||||
|
|
||||||
|
const _handleKeyPress = (e) => {
|
||||||
|
console.log('点击传e', e.target.dataset.num);
|
||||||
|
let num = e.target.dataset.num;
|
||||||
|
//不同按键处理逻辑
|
||||||
|
// -1 代表无效按键,直接返回
|
||||||
|
if (num == -1) return false;
|
||||||
|
switch (String(num)) {
|
||||||
|
//小数点
|
||||||
|
case '.':
|
||||||
|
_handleDecimalPoint();
|
||||||
|
break;
|
||||||
|
//删除键
|
||||||
|
case 'D':
|
||||||
|
_handleDeleteKey();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_handleNumberKey(num);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理数字
|
||||||
|
const _handleNumberKey = (num) => {
|
||||||
|
if (num == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (moneys.money.length == 10) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log(num, 247)
|
||||||
|
let S = moneys.money;
|
||||||
|
//如果有小数点且小数点位数不小于2
|
||||||
|
if (S.indexOf('.') > -1 && S.substring(S.indexOf('.') + 1).length < 2)
|
||||||
|
moneys.money = S + num;
|
||||||
|
//没有小数点
|
||||||
|
if (!(S.indexOf('.') > -1)) {
|
||||||
|
//如果第一位是0,只能输入小数点
|
||||||
|
if (num == 0 && S.length == 0)
|
||||||
|
moneys.money = '0.';
|
||||||
|
else {
|
||||||
|
if (S.length && Number(S.charAt(0)) === 0) return;
|
||||||
|
moneys.money = S + num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//处理小数点函数
|
||||||
|
const _handleDecimalPoint = () => {
|
||||||
|
//如果包含小数点,直接返回
|
||||||
|
if (moneys.money.indexOf('.') > -1) return false;
|
||||||
|
//如果小数点是第一位,补0
|
||||||
|
if (!moneys.money.length) {
|
||||||
|
moneys.money = '0.';
|
||||||
|
} else {
|
||||||
|
//如果不是,添加一个小数点
|
||||||
|
moneys.money = moneys.money + '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//处理删除键
|
||||||
|
const _handleDeleteKey = () => {
|
||||||
|
let S = moneys.money;
|
||||||
|
//如果没有输入,直接返回
|
||||||
|
if (!S.length) return false;
|
||||||
|
//否则删除最后一个
|
||||||
|
moneys.money = S.substring(0, S.length - 1);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.orderbox_right_top {
|
||||||
|
color: #fff;
|
||||||
|
width: 100%;
|
||||||
|
background: #8b008b;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
.orderbox_right_topdiv:nth-child(1) {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_topdiv {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_top_item {
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
padding: 6px 10px;
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.orderbox_right_top_item_one {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.orderbox_right_top_item_onespan {
|
||||||
|
color: black;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_top_item_tow {
|
||||||
|
color: black;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_input {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_inputkeyboard {
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.keyboard {
|
||||||
|
width: 100%;
|
||||||
|
background: #FFFFFF;
|
||||||
|
|
||||||
|
.key-row {
|
||||||
|
display: flex;
|
||||||
|
display: -webkit-flex;
|
||||||
|
position: relative;
|
||||||
|
height: 8vh;
|
||||||
|
line-height: 8vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.keyboard .key-cell {
|
||||||
|
flex: 1;
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
font-size: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_button {
|
||||||
|
position: absolute;
|
||||||
|
width: 90%;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
transform: translateX(-50%) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,481 @@
|
||||||
|
<template>
|
||||||
|
<div class="orderbox">
|
||||||
|
<div class="orderbox_left">
|
||||||
|
<el-table :data="tableData" height="90%" style="width: 100%;margin-top: 10px;">
|
||||||
|
<el-table-column prop="date" label="昵称" width="" />
|
||||||
|
<el-table-column prop="name" label="手机" width="" />
|
||||||
|
<el-table-column prop="address" label="编号" />
|
||||||
|
<el-table-column prop="address" label="等级" />
|
||||||
|
|
||||||
|
<el-table-column prop="address" label="积分" />
|
||||||
|
<el-table-column prop="address" label="余额" />
|
||||||
|
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right">
|
||||||
|
<div class="orderbox_right_top">
|
||||||
|
<div class="orderbox_right_topdiv">
|
||||||
|
<span>会员昵称:</span>
|
||||||
|
<span>admin</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_topdiv">
|
||||||
|
<span>手机号码:</span>
|
||||||
|
<span>1999999999999</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_topdiv">
|
||||||
|
<span>会员编号:</span>
|
||||||
|
<span>1245</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_topdiv">
|
||||||
|
<span>会员等级:</span>
|
||||||
|
<span>未设置</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_top_item">
|
||||||
|
<div class="orderbox_right_top_item_one">
|
||||||
|
<el-icon :size="24" style="color:#ffbc42 ;">
|
||||||
|
<Money />
|
||||||
|
</el-icon>
|
||||||
|
<span class="orderbox_right_top_item_onespan">会员积分</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_top_item_tow">0</div>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_top_item" @click="stored = true">
|
||||||
|
<div class="orderbox_right_top_item_one">
|
||||||
|
<el-icon :size="24" style="color:#00b58d ;">
|
||||||
|
<Box />
|
||||||
|
</el-icon>
|
||||||
|
<span class="orderbox_right_top_item_onespan">储值余额</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_top_item_tow">
|
||||||
|
<span>0</span>
|
||||||
|
<el-icon size="10">
|
||||||
|
<ArrowRight />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<keyboard ></keyboard>
|
||||||
|
<!-- <div class="orderbox_right_input">
|
||||||
|
<el-input placeholder="请输入会员手机号或者编号" v-model="moneys.money" clearable @input="inputChange"></el-input>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_inputkeyboard">
|
||||||
|
<div class='keyboard' @click.stop='_handleKeyPress'>
|
||||||
|
<div class='key-row'>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='1'>1</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='2'>2</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='3'>3</el-button>
|
||||||
|
</div>
|
||||||
|
<div class='key-row'>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='4'>4</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='5'>5</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='6'>6</el-button>
|
||||||
|
</div>
|
||||||
|
<div class='key-row'>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='7'>7</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='8'>8</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='9'>9</el-button>
|
||||||
|
</div>
|
||||||
|
<div class='key-row'>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='.'>.</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='0'>0</el-button>
|
||||||
|
<el-button type="primary" plain class='key-cell cell_b' data-num='D'>c</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
<div class="orderbox_right_button">
|
||||||
|
<el-button style="width: 35%;" @click="recharge = true">添加会员</el-button>
|
||||||
|
<el-button style="width: 60%;" type="primary" @click="onSubmit">确认</el-button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-dialog v-model="stored" title="余额明细" width="500" :before-close="handleClose">
|
||||||
|
<div class="dialog_footer" v-for="(iten, index) in 6" :key="index">
|
||||||
|
<div class="dialog_footer_left">
|
||||||
|
<span>微信用户</span>
|
||||||
|
<span>2021-02-22 18:05:53</span>
|
||||||
|
</div>
|
||||||
|
<div class="dialog_footer_right">
|
||||||
|
<span>19000</span>
|
||||||
|
<span>26300</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog v-model="recharge" title="会员充值" width="800" :before-close="handlerecharge">
|
||||||
|
<div class="recharge_footer">
|
||||||
|
<div class="recharge_footer_item">
|
||||||
|
qq
|
||||||
|
</div>
|
||||||
|
<div class="recharge_footer_itemright">
|
||||||
|
<div class="recharge_footer_itemright_input">
|
||||||
|
<div>充值金额:</div>
|
||||||
|
<div v-if="moneys.money">{{ moneys.money ? moneys.money : '请输入充值金额' }}</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch } from 'vue'
|
||||||
|
import { useRoute } from "vue-router"
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import lodash_ from 'lodash'
|
||||||
|
import keyboard from '@/views/home/components/keyboard.vue'
|
||||||
|
|
||||||
|
|
||||||
|
const stored = ref(false)//储值余额
|
||||||
|
// const inputChange = lodash_.debounce(function (e) {
|
||||||
|
// productqueryCommodityInfoAjax()
|
||||||
|
// }, 500)
|
||||||
|
const handleClose = () => {
|
||||||
|
stored.value = !stored.value
|
||||||
|
}
|
||||||
|
const recharge = ref(false)//充值
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
ElMessage({
|
||||||
|
message: '请输入订单号查询',
|
||||||
|
type: 'warning',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handlerecharge = () => {
|
||||||
|
recharge.value = !recharge.value
|
||||||
|
}
|
||||||
|
const tableData = [
|
||||||
|
{
|
||||||
|
date: '2016-05-03',
|
||||||
|
name: 'Tom',
|
||||||
|
address: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2016-05-02',
|
||||||
|
name: 'Tom',
|
||||||
|
address: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2016-05-04',
|
||||||
|
name: 'Tom',
|
||||||
|
address: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2016-05-01',
|
||||||
|
name: 'Tom',
|
||||||
|
address: '1',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const moneys = reactive({
|
||||||
|
money: ''
|
||||||
|
})
|
||||||
|
const _handleKeyPress = (e) => {
|
||||||
|
console.log('点击传e', e.target.dataset.num);
|
||||||
|
let num = e.target.dataset.num;
|
||||||
|
//不同按键处理逻辑
|
||||||
|
// -1 代表无效按键,直接返回
|
||||||
|
if (num == -1) return false;
|
||||||
|
switch (String(num)) {
|
||||||
|
//小数点
|
||||||
|
case '.':
|
||||||
|
_handleDecimalPoint();
|
||||||
|
break;
|
||||||
|
//删除键
|
||||||
|
case 'D':
|
||||||
|
_handleDeleteKey();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_handleNumberKey(num);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watch(() => moneys.money, (newVal, oldVal) => {
|
||||||
|
console.log(`New: ${newVal}, Old: ${oldVal}`)
|
||||||
|
})
|
||||||
|
//处理数字
|
||||||
|
const _handleNumberKey = (num) => {
|
||||||
|
if (num == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (moneys.money.length == 10) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log(num, 247)
|
||||||
|
let S = moneys.money;
|
||||||
|
//如果有小数点且小数点位数不小于2
|
||||||
|
if (S.indexOf('.') > -1 && S.substring(S.indexOf('.') + 1).length < 2)
|
||||||
|
moneys.money = S + num;
|
||||||
|
//没有小数点
|
||||||
|
if (!(S.indexOf('.') > -1)) {
|
||||||
|
//如果第一位是0,只能输入小数点
|
||||||
|
if (num == 0 && S.length == 0)
|
||||||
|
moneys.money = '0.';
|
||||||
|
else {
|
||||||
|
if (S.length && Number(S.charAt(0)) === 0) return;
|
||||||
|
moneys.money = S + num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//处理小数点函数
|
||||||
|
const _handleDecimalPoint = () => {
|
||||||
|
//如果包含小数点,直接返回
|
||||||
|
if (moneys.money.indexOf('.') > -1) return false;
|
||||||
|
//如果小数点是第一位,补0
|
||||||
|
if (!moneys.money.length) {
|
||||||
|
moneys.money = '0.';
|
||||||
|
} else {
|
||||||
|
//如果不是,添加一个小数点
|
||||||
|
moneys.money = moneys.money + '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//处理删除键
|
||||||
|
const _handleDeleteKey = () => {
|
||||||
|
let S = moneys.money;
|
||||||
|
//如果没有输入,直接返回
|
||||||
|
if (!S.length) return false;
|
||||||
|
//否则删除最后一个
|
||||||
|
moneys.money = S.substring(0, S.length - 1);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.orderbox {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.orderbox_left {
|
||||||
|
width: 70%;
|
||||||
|
height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right {
|
||||||
|
position: relative;
|
||||||
|
width: 30%;
|
||||||
|
padding: 20px;
|
||||||
|
margin-left: 10px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
.orderbox_right_top {
|
||||||
|
color: #fff;
|
||||||
|
width: 100%;
|
||||||
|
background: #8b008b;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
.orderbox_right_topdiv:nth-child(1) {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_topdiv {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_top_item {
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
padding: 6px 10px;
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.orderbox_right_top_item_one {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.orderbox_right_top_item_onespan {
|
||||||
|
color: black;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_top_item_tow {
|
||||||
|
color: black;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_input {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_inputkeyboard {
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.keyboard {
|
||||||
|
width: 100%;
|
||||||
|
background: #FFFFFF;
|
||||||
|
|
||||||
|
.key-row {
|
||||||
|
display: flex;
|
||||||
|
display: -webkit-flex;
|
||||||
|
position: relative;
|
||||||
|
height: 8vh;
|
||||||
|
line-height: 8vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.keyboard .key-cell {
|
||||||
|
flex: 1;
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
font-size: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_button {
|
||||||
|
position: absolute;
|
||||||
|
width: 90%;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
transform: translateX(-50%) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_footer:nth-child(1) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_footer {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
|
||||||
|
.dialog_footer_left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
span:nth-child(1) {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
span:nth-child(2) {
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_footer_right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
span:nth-child(1) {
|
||||||
|
color: #fc3d3d;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
span:nth-child(2) {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.recharge_footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.recharge_footer_item {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recharge_footer_itemright {
|
||||||
|
width: 50%;
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
.recharge_footer_itemright_input {
|
||||||
|
width: 100%;
|
||||||
|
background: #333333;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 0 6px;
|
||||||
|
display: flex;
|
||||||
|
height: 60px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
div:nth-child(1) {
|
||||||
|
color: #56792e;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div:nth-child(2) {
|
||||||
|
color: #88937c;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.key-zero-and-point {
|
||||||
|
display: flex;
|
||||||
|
height: 10vh;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 75%;
|
||||||
|
font-size: 30px;
|
||||||
|
|
||||||
|
.zero {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 66.66%;
|
||||||
|
font-size: 30px;
|
||||||
|
text-align: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 33.33%;
|
||||||
|
font-size: 30px;
|
||||||
|
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,113 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog title="恢复挂起的订单" width="800" v-model="dialogVisible">
|
||||||
|
<div class="pending_carts">
|
||||||
|
<div class="item" v-for="(item, index) in cartList" :key="index" @click="select(item)">
|
||||||
|
<div class="time">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<Clock />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ dayjs(item.pendingAt).format('HH:mm') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info">
|
||||||
|
<span class="name">{{ item.productName }}</span>
|
||||||
|
<span class="p">¥{{ item.totalAmount }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="empty">
|
||||||
|
<el-empty description="暂无挂单" v-if="!cartList.length" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { dayjs } from 'element-plus'
|
||||||
|
import { getCartList } from "@/api/product";
|
||||||
|
import { useUser } from "@/store/user"
|
||||||
|
|
||||||
|
const emit = defineEmits(['select'])
|
||||||
|
|
||||||
|
const store = useUser()
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const cartList = ref([])
|
||||||
|
|
||||||
|
// 恢复挂单
|
||||||
|
function select(item) {
|
||||||
|
emit('select', item)
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
dialogVisible.value = true
|
||||||
|
getCartListAjax()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取挂起购物车列表
|
||||||
|
async function getCartListAjax() {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
const res = await getCartList({
|
||||||
|
shopId: store.userInfo.shopId
|
||||||
|
})
|
||||||
|
cartList.value = res
|
||||||
|
loading.value = false
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.pending_carts {
|
||||||
|
height: 50vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #efefef;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
padding: 20px 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--el-color-warning);
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: calc(var(--el-font-size-base) + 6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
|
||||||
|
.p {
|
||||||
|
color: var(--el-color-warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,435 @@
|
||||||
|
<!-- 结算订单 -->
|
||||||
|
<template>
|
||||||
|
<el-drawer size="100%" :with-header="false" direction="btt" v-model="dialogVisible">
|
||||||
|
<div class="drawer_wrap">
|
||||||
|
<div class="cart_list">
|
||||||
|
<div class="nav_wrap card">
|
||||||
|
<div class="return" @click="dialogVisible = false">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<ArrowLeftBold />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="master_id">
|
||||||
|
<span>{{ props.masterId }}</span>
|
||||||
|
<span class="member_info" v-if="memberInfo.telephone">会员:{{ memberInfo.telephone }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="btm">
|
||||||
|
<span class="p">服务员:{{ store.userInfo.loginAccount || "暂无" }}</span>
|
||||||
|
<span class="t">{{
|
||||||
|
props.orderInfo.createdAt &&
|
||||||
|
dayjs(props.orderInfo.createdAt).format("MM-DD HH:mm")
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="list_wrap card" style="margin-top: var(--el-font-size-base)">
|
||||||
|
<div class="item" v-for="item in props.cart" :key="item.id">
|
||||||
|
<div class="top">
|
||||||
|
<span class="name">{{ item.name }}</span>
|
||||||
|
<span class="n">x{{ item.number }}</span>
|
||||||
|
<span class="p">¥{{ item.salePrice }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="gift_wrap" v-if="item.isGift == 'true'">
|
||||||
|
<span>[赠送]</span>
|
||||||
|
<span>¥-{{ item.salePrice }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="tag_wrap" v-if="item.skuName">
|
||||||
|
<div class="tag" v-for="item in item.skuName.split(',')">
|
||||||
|
{{ item }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="packge_Wrap" v-if="item.isPack == 'true'">
|
||||||
|
<div class="icon_item" v-if="item.isPack == 'true'" @click="giftPackHandle('isPack', item)">
|
||||||
|
<el-icon class="icon" style="color: var(--primary-color)">
|
||||||
|
<Box />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<!-- <el-button icon="Edit"></el-button> -->
|
||||||
|
<div class="button">
|
||||||
|
<el-checkbox v-model="isPrint" border label="打印结算小票" style="width: 100%" />
|
||||||
|
</div>
|
||||||
|
<div class="print">
|
||||||
|
<el-button type="primary" v-loading="printLoading" @click="printHandle">打印预结单</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pay_wrap">
|
||||||
|
<payCard :amount="props.amount" :member="props.member" :orderId="props.orderInfo.id" @paySuccess="paySuccess" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import payCard from "@/components/payCard/payCard.vue";
|
||||||
|
import { print } from "@/api/pay";
|
||||||
|
import { orderfindOrder } from '@/api/order/index.js'
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import useStorage from '@/utils/useStorage'
|
||||||
|
import { ipcRenderer } from "electron";
|
||||||
|
import { formatDecimal } from '@/utils/index.js'
|
||||||
|
import receiptPrint from "@/components/lodop/receiptPrint.js";
|
||||||
|
|
||||||
|
import { usePrint } from '@/store/print.js'
|
||||||
|
const printStore = usePrint()
|
||||||
|
|
||||||
|
const store = useUser();
|
||||||
|
|
||||||
|
const emit = defineEmits("paySuccess");
|
||||||
|
|
||||||
|
const printLoading = ref(false);
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const props = defineProps({
|
||||||
|
cart: {
|
||||||
|
type: Array,
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
amount: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
remark: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
orderInfo: {
|
||||||
|
type: Object,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
masterId: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
member: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const isPrint = ref(true);
|
||||||
|
|
||||||
|
// 预打印操作
|
||||||
|
const printHandle = _.throttle(async function () {
|
||||||
|
try {
|
||||||
|
if (!isPrint.value) return;
|
||||||
|
printLoading.value = true;
|
||||||
|
const data = {
|
||||||
|
shop_name: store.userInfo.shopName,
|
||||||
|
loginAccount: store.userInfo.loginAccount,
|
||||||
|
isBefore: true,
|
||||||
|
carts: props.cart,
|
||||||
|
amount: props.amount,
|
||||||
|
remark: props.remark,
|
||||||
|
orderInfo: props.orderInfo,
|
||||||
|
createdAt: dayjs(props.orderInfo.createdAt).format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
};
|
||||||
|
printStore.labelPrint(data)
|
||||||
|
setTimeout(() => {
|
||||||
|
printLoading.value = false;
|
||||||
|
}, 1500)
|
||||||
|
if (printStore.deviceNoteList.length) {
|
||||||
|
printStore.pushReceiptData(data)
|
||||||
|
} else {
|
||||||
|
await print({
|
||||||
|
type: "normal",
|
||||||
|
ispre: true,
|
||||||
|
orderId: props.orderInfo.id,
|
||||||
|
});
|
||||||
|
printLoading.value = false;
|
||||||
|
ElMessage.success("打印成功");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}, 1500, { leading: true, trailing: false })
|
||||||
|
|
||||||
|
// 打印订单标签
|
||||||
|
async function printOrderLable() {
|
||||||
|
try {
|
||||||
|
if (!isPrint.value) return
|
||||||
|
const res = await orderfindOrder({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
status: '',
|
||||||
|
size: 10,
|
||||||
|
page: 1,
|
||||||
|
orderNo: props.orderInfo.orderNo
|
||||||
|
})
|
||||||
|
|
||||||
|
const printLabelOrder = res.list[0]
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
shop_name: store.userInfo.shopName,
|
||||||
|
loginAccount: store.userInfo.loginAccount,
|
||||||
|
carts: [],
|
||||||
|
amount: printLabelOrder.orderAmount,
|
||||||
|
remark: printLabelOrder.remark,
|
||||||
|
orderInfo: printLabelOrder,
|
||||||
|
outNumber: printLabelOrder.outNumber,
|
||||||
|
createdAt: dayjs(printLabelOrder.createdAt).format(
|
||||||
|
"YYYY-MM-DD HH:mm:ss"
|
||||||
|
),
|
||||||
|
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
}
|
||||||
|
printLabelOrder.skuInfos.map(item => {
|
||||||
|
data.carts.push(
|
||||||
|
{
|
||||||
|
categoryId: item.categoryId,
|
||||||
|
name: item.productName,
|
||||||
|
number: item.num,
|
||||||
|
skuName: item.productSkuName,
|
||||||
|
salePrice: formatDecimal(item.priceAmount / item.num),
|
||||||
|
totalAmount: formatDecimal(item.priceAmount)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
// 打印标签
|
||||||
|
printStore.labelPrint(data)
|
||||||
|
|
||||||
|
if (printStore.deviceNoteList.length) {
|
||||||
|
// 打印小票
|
||||||
|
printStore.pushReceiptData(data)
|
||||||
|
} else {
|
||||||
|
await print({
|
||||||
|
type: "normal",
|
||||||
|
ispre: true,
|
||||||
|
orderId: props.orderInfo.id,
|
||||||
|
});
|
||||||
|
printLoading.value = false;
|
||||||
|
ElMessage.success("打印成功");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单已支付
|
||||||
|
function paySuccess() {
|
||||||
|
useStorage.del('memberInfo')
|
||||||
|
dialogVisible.value = false;
|
||||||
|
printOrderLable()
|
||||||
|
emit("paySuccess");
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
getLocalMemberInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const memberInfo = ref('')
|
||||||
|
|
||||||
|
// 从本地获取会员信息
|
||||||
|
function getLocalMemberInfo() {
|
||||||
|
let localMemberInfo = useStorage.get('memberInfo')
|
||||||
|
if (localMemberInfo && localMemberInfo.telephone) {
|
||||||
|
memberInfo.value = localMemberInfo
|
||||||
|
} else {
|
||||||
|
memberInfo.value = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getLocalMemberInfo()
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.el-drawer {
|
||||||
|
background-color: #efefef !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.drawer_wrap {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
padding: var(--el-font-size-base) 0;
|
||||||
|
|
||||||
|
.cart_list {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.nav_wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 var(--el-font-size-base);
|
||||||
|
|
||||||
|
.return {
|
||||||
|
$size: 50px;
|
||||||
|
width: $size;
|
||||||
|
height: $size;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid #333;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: #333;
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
flex: 1;
|
||||||
|
padding-left: var(--el-font-size-base);
|
||||||
|
$padding: 10px;
|
||||||
|
|
||||||
|
.master_id {
|
||||||
|
font-size: calc(var(--el-font-size-base) + 10px);
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
|
padding: $padding 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.member_info {
|
||||||
|
color: #999;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btm {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: $padding 0;
|
||||||
|
|
||||||
|
.p {
|
||||||
|
color: #999;
|
||||||
|
width: 160px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list_wrap {
|
||||||
|
padding: var(--el-font-size-base);
|
||||||
|
height: calc(100vh - 200px);
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
padding-bottom: var(--el-font-size-base);
|
||||||
|
|
||||||
|
.top {
|
||||||
|
display: flex;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.n {
|
||||||
|
margin-right: 50px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.gift_wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: #999;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag_wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
padding: 2px 6px;
|
||||||
|
background-color: var(--el-color-danger);
|
||||||
|
color: #fff;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.packge_Wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon_item {
|
||||||
|
$size: 40px;
|
||||||
|
width: $size;
|
||||||
|
height: $size;
|
||||||
|
background-color: #e2e2e2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
padding-top: var(--el-font-size-base);
|
||||||
|
gap: var(--el-font-size-base);
|
||||||
|
|
||||||
|
.editor {
|
||||||
|
border: 1px solid #ececec;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
:deep(.el-checkbox.el-checkbox--large) {
|
||||||
|
height: var(--el-component-size-large);
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-checkbox__inner) {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-width: 2px;
|
||||||
|
top: 3px;
|
||||||
|
left: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-checkbox__label) {
|
||||||
|
font-size: var(--el-font-size-base) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay_wrap {
|
||||||
|
flex: 1.5;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,637 @@
|
||||||
|
<template>
|
||||||
|
<div class="content">
|
||||||
|
<div class="cart_wrap card">
|
||||||
|
<div class="menu_top">
|
||||||
|
<div class="menu" @click="pendingCartModalRef.show()">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<TakeawayBox />
|
||||||
|
</el-icon>
|
||||||
|
<el-text class="t">({{ pendingCartNum }})</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="number" @click="takeFoodCodeRef.show()">
|
||||||
|
<el-text class="t">{{ masterId }}</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="select_user" @click="fastCashierRef.show()" v-if="!memberInfo.telephone">
|
||||||
|
<div class="left">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<WalletFilled />
|
||||||
|
</el-icon>
|
||||||
|
<el-text class="t">快捷收银</el-text>
|
||||||
|
</div>
|
||||||
|
<el-icon class="arrow">
|
||||||
|
<ArrowRight />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div class="select_user" v-else @click="clearMember">
|
||||||
|
<div class="left">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<UserFilled />
|
||||||
|
</el-icon>
|
||||||
|
<el-text class="t">{{ memberInfo.telephone }}</el-text>
|
||||||
|
</div>
|
||||||
|
<el-icon class="arrow">
|
||||||
|
<Close />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="shop_operation" v-loading="cartLoading">
|
||||||
|
<div class="shop_list">
|
||||||
|
<div class="item" :class="{ active: cartListActive == index }" v-for="(item, index) in cartList"
|
||||||
|
:key="item.id" @click="selectCartItemHandle(item, index)">
|
||||||
|
<div class="name_wrap">
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<span>¥{{ item.salePrice }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sku_list" v-if="item.skuName">
|
||||||
|
<div class="tag" v-for="item in item.skuName.split(',')">
|
||||||
|
{{ item }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="num">
|
||||||
|
<div class="left">
|
||||||
|
<div class="icon_item" v-if="item.isGift == 'true'" @click="giftPackHandle('isGift', item)">
|
||||||
|
<el-icon class="icon">
|
||||||
|
<ShoppingBag />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div class="icon_item" v-if="item.isPack == 'true'" @click="giftPackHandle('isPack', item)">
|
||||||
|
<el-icon class="icon" style="color: var(--primary-color)">
|
||||||
|
<Box />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-text class="t">X{{ item.number }}</el-text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="empty">
|
||||||
|
<el-empty description="请选择商品" v-if="!cartList.length" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 购物车操作栏 -->
|
||||||
|
<cartOperation :item="cartList[cartListActive]" @confirm="(res) => addCart(res, 'edit')" @delete="delCartHandle"
|
||||||
|
@pending="pendingCart" @clearCart="clearCartHandle" />
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<div class="top">
|
||||||
|
<div class="left" @click="allSelectedHandle">
|
||||||
|
<div class="selected">
|
||||||
|
<div class="selected_round" v-if="!allSelected"></div>
|
||||||
|
<el-icon class="icon" v-else>
|
||||||
|
<CircleCheckFilled />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<el-text class="t">打包(¥{{ cartInfo.packAmount || 0 }})</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="num-wrap">
|
||||||
|
<el-text>共{{ cartInfo.productNum || 0 }}种商品,{{
|
||||||
|
cartInfo.productSum || 0
|
||||||
|
}}件</el-text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="btm">
|
||||||
|
<el-button icon="Edit" @click="remarkRef.show()"></el-button>
|
||||||
|
<div class="button">
|
||||||
|
<el-button type="primary" style="width: 100%" :disabled="!cartList.length" v-loading="createOrderLoading"
|
||||||
|
@click="createOrderHandle">
|
||||||
|
<span v-if="!createOrderLoading">结算(¥{{ cartInfo.totalAmount || 0 }})</span>
|
||||||
|
<span v-else>下单中...</span>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="shop_manage card">
|
||||||
|
<!-- 分类/商品列表 -->
|
||||||
|
<goods ref="goodsRef" :masterId="masterId" @success="addCart" />
|
||||||
|
<!-- ©银收客 v{{ packageData.version }} -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 备注 -->
|
||||||
|
<remarkModal ref="remarkRef" @success="(e) => (remark = e)" />
|
||||||
|
<!-- 修改取餐号 -->
|
||||||
|
<takeFoodCode />
|
||||||
|
<el-drawer v-model="membershow" :with-header="true" size="90%" title="选择会员">
|
||||||
|
<member :membershow="'1'"></member>
|
||||||
|
</el-drawer>
|
||||||
|
<takeFoodCode ref="takeFoodCodeRef" title="修改取餐号" placeholder="请输入取餐号" @success="takeFoodCodeSuccess" />
|
||||||
|
<!-- 结算订单 -->
|
||||||
|
<settleAccount ref="settleAccountRef" :cart="cartList" :amount="cartInfo.totalAmount" :remark="remark"
|
||||||
|
:masterId="masterId" :orderInfo="orderInfo" :member="memberInfo" @paySuccess="createCodeAjax(1)" />
|
||||||
|
<!-- 快捷收银 -->
|
||||||
|
<fastCashier ref="fastCashierRef" type="0" />
|
||||||
|
<!-- 挂起订单 -->
|
||||||
|
<pendingCartModal ref="pendingCartModalRef" @select="pendingCartHandle" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "home",
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import remarkModal from "@/components/remarkModal.vue";
|
||||||
|
import takeFoodCode from "@/components/takeFoodCode.vue";
|
||||||
|
import cartOperation from "@/views/home/components/cartOperation.vue";
|
||||||
|
import settleAccount from "@/views/home/components/settleAccount.vue";
|
||||||
|
import fastCashier from "@/views/home/components/fastCashier.vue";
|
||||||
|
import pendingCartModal from "@/views/home/components/pendingCartModal.vue";
|
||||||
|
import useStorage from '@/utils/useStorage'
|
||||||
|
|
||||||
|
import {
|
||||||
|
createCart,
|
||||||
|
queryCart,
|
||||||
|
createCode,
|
||||||
|
packall,
|
||||||
|
delCart,
|
||||||
|
cartStatus,
|
||||||
|
clearCart,
|
||||||
|
createOrder,
|
||||||
|
} from "@/api/product";
|
||||||
|
|
||||||
|
// 商品列表
|
||||||
|
import goods from "@/views/home/components/goods.vue";
|
||||||
|
import member from "@/views/member/index.vue";
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const membershow = ref(false);
|
||||||
|
const store = useUser();
|
||||||
|
const remarkRef = ref(null);
|
||||||
|
const takeFoodCodeRef = ref(null);
|
||||||
|
const goodsRef = ref(null);
|
||||||
|
const pendingCartModalRef = ref(null);
|
||||||
|
const settleAccountRef = ref(null);
|
||||||
|
const fastCashierRef = ref(null);
|
||||||
|
|
||||||
|
const allSelected = ref(false);
|
||||||
|
|
||||||
|
const remark = ref("");
|
||||||
|
const cartListActive = ref(0);
|
||||||
|
const cartList = ref([]);
|
||||||
|
const cartInfo = ref({});
|
||||||
|
const cartLoading = ref(false);
|
||||||
|
|
||||||
|
const orderInfo = ref({});
|
||||||
|
const createOrderLoading = ref(false);
|
||||||
|
|
||||||
|
const memberInfo = ref({})
|
||||||
|
|
||||||
|
// 取餐码
|
||||||
|
const masterId = ref("");
|
||||||
|
|
||||||
|
// 挂单量
|
||||||
|
const pendingCartNum = ref(0);
|
||||||
|
|
||||||
|
// 生成订单
|
||||||
|
async function createOrderHandle() {
|
||||||
|
try {
|
||||||
|
createOrderLoading.value = true;
|
||||||
|
const res = await createOrder({
|
||||||
|
masterId: masterId.value,
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
remark: remark.value,
|
||||||
|
});
|
||||||
|
orderInfo.value = res;
|
||||||
|
settleAccountRef.value.show();
|
||||||
|
createOrderLoading.value = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
createOrderLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空购物车
|
||||||
|
async function clearCartHandle() {
|
||||||
|
try {
|
||||||
|
await clearCart({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
masterId: masterId.value,
|
||||||
|
});
|
||||||
|
queryCartAjax();
|
||||||
|
|
||||||
|
// 清除商品所有红点
|
||||||
|
goodsRef.value.clearDot()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复挂单
|
||||||
|
async function pendingCartHandle(item) {
|
||||||
|
const nItem = { ...item };
|
||||||
|
if (cartList.value.length) {
|
||||||
|
// 当购物车有数据时,先挂起当前购物车
|
||||||
|
await pendingCart({ masterId: masterId.value });
|
||||||
|
}
|
||||||
|
masterId.value = nItem.masterId;
|
||||||
|
await pendingCart(nItem, false);
|
||||||
|
await queryCartAjax();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 挂单
|
||||||
|
async function pendingCart(params, status = true) {
|
||||||
|
try {
|
||||||
|
cartLoading.value = true;
|
||||||
|
await cartStatus({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
masterId: params.masterId,
|
||||||
|
status: status,
|
||||||
|
uuid: params.uuid,
|
||||||
|
});
|
||||||
|
if (status && cartList.value.length) {
|
||||||
|
await createCodeAjax();
|
||||||
|
cartLoading.value = false;
|
||||||
|
} else {
|
||||||
|
cartLoading.value = false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除购物车
|
||||||
|
async function delCartHandle(params) {
|
||||||
|
try {
|
||||||
|
cartLoading.value = true;
|
||||||
|
await delCart({
|
||||||
|
masterId: params.masterId,
|
||||||
|
cartId: params.id,
|
||||||
|
});
|
||||||
|
await queryCartAjax();
|
||||||
|
cartLoading.value = false;
|
||||||
|
cartListActive.value = 0;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 赠送打包操作
|
||||||
|
function giftPackHandle(key, item) {
|
||||||
|
item[key] = false;
|
||||||
|
addCart(item, "edit");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打包全选
|
||||||
|
const allSelectedHandle = async () => {
|
||||||
|
if (!cartList.value.length) return;
|
||||||
|
allSelected.value = !allSelected.value;
|
||||||
|
await packall({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
status: allSelected.value,
|
||||||
|
masterId: masterId.value,
|
||||||
|
});
|
||||||
|
queryCartAjax();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认取餐号
|
||||||
|
async function takeFoodCodeSuccess(code) {
|
||||||
|
if (cartList.value.length) {
|
||||||
|
await pendingCart({
|
||||||
|
masterId: masterId.value,
|
||||||
|
uuid: cartList.value[0].uuid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
masterId.value = `#${code}`;
|
||||||
|
queryCartAjax();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从购物车选择商品
|
||||||
|
function selectCartItemHandle(item, index) {
|
||||||
|
cartListActive.value = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择完规格开始添加购物车
|
||||||
|
async function addCart(params, type = "add") {
|
||||||
|
try {
|
||||||
|
cartLoading.value = true;
|
||||||
|
const res = await createCart({
|
||||||
|
productId: params.productId,
|
||||||
|
masterId: masterId.value,
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
skuId: type == "add" ? params.id : params.skuId,
|
||||||
|
number: params.number || 1,
|
||||||
|
isPack: params.isPack || "false",
|
||||||
|
isGift: params.isGift || "false",
|
||||||
|
cartId: type == "add" ? "" : params.id,
|
||||||
|
uuid: params.uuid || store.userInfo.uuid,
|
||||||
|
type: type,
|
||||||
|
});
|
||||||
|
cartLoading.value = false;
|
||||||
|
masterId.value = res;
|
||||||
|
goodsRef.value.updateData();
|
||||||
|
queryCartAjax();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
cartLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取购物车商品
|
||||||
|
async function queryCartAjax() {
|
||||||
|
try {
|
||||||
|
const res = await queryCart({
|
||||||
|
masterId: masterId.value,
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
});
|
||||||
|
cartList.value = res.list;
|
||||||
|
cartInfo.value = res.amount;
|
||||||
|
pendingCartNum.value = res.num;
|
||||||
|
goodsRef.value.updateData();
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
res.list.map((item) => {
|
||||||
|
if (item.isPack == "true") {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (i == res.list.length) {
|
||||||
|
allSelected.value = true;
|
||||||
|
} else {
|
||||||
|
allSelected.value = false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("获取购物车商品", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取取餐码
|
||||||
|
async function createCodeAjax(type = "0") {
|
||||||
|
try {
|
||||||
|
// if (!process.env.VITE_DEV_SERVER_URL) {
|
||||||
|
// masterId.value = '#20'
|
||||||
|
// } else {
|
||||||
|
// const res = await createCode({
|
||||||
|
// shopId: store.userInfo.shopId
|
||||||
|
// })
|
||||||
|
// masterId.value = res.code
|
||||||
|
// }
|
||||||
|
const res = await createCode({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
type: type,
|
||||||
|
});
|
||||||
|
masterId.value = res.code;
|
||||||
|
queryCartAjax();
|
||||||
|
getLocalMemberInfo()
|
||||||
|
|
||||||
|
if (type == 1) {
|
||||||
|
// 结算订单 清楚商品所有红点
|
||||||
|
goodsRef.value.clearDot()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从本地获取会员信息
|
||||||
|
function getLocalMemberInfo() {
|
||||||
|
let localMemberInfo = useStorage.get('memberInfo')
|
||||||
|
if (localMemberInfo && localMemberInfo.telephone) {
|
||||||
|
memberInfo.value = localMemberInfo
|
||||||
|
} else {
|
||||||
|
memberInfo.value = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除本地会员
|
||||||
|
function clearMember() {
|
||||||
|
useStorage.del('memberInfo')
|
||||||
|
getLocalMemberInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
createCodeAjax();
|
||||||
|
getLocalMemberInfo()
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.cart_wrap {
|
||||||
|
flex: 1.5;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.menu_top {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
height: var(--el-component-size-large);
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
background-color: var(--el-color-warning);
|
||||||
|
color: #fff;
|
||||||
|
width: 60px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t {
|
||||||
|
color: #fff;
|
||||||
|
margin-left: 4px;
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.number {
|
||||||
|
width: 50px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: var(--el-color-info-light-7);
|
||||||
|
// padding-left: var(--el-font-size-base);
|
||||||
|
|
||||||
|
.t {
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select_user {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: var(--el-color-info-light-8);
|
||||||
|
padding: 0 var(--el-font-size-base);
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t {
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
color: #999;
|
||||||
|
font-size: 16px;
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shop_operation {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.shop_list {
|
||||||
|
flex: 1;
|
||||||
|
height: calc(100vh - 40px - 60px - 80px);
|
||||||
|
overflow-y: auto;
|
||||||
|
border-right: 1px solid #ececec;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
padding: var(--el-font-size-base);
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: var(--primary-color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name_wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.num {
|
||||||
|
padding-top: var(--el-font-size-base);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon_item {
|
||||||
|
$size: 30px;
|
||||||
|
width: $size;
|
||||||
|
height: $size;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #e2e2e2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.t {
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
padding: var(--el-font-size-base);
|
||||||
|
border-top: 1px solid #ececec;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: block;
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected_round {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.t {
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btm {
|
||||||
|
$h: 70px;
|
||||||
|
display: flex;
|
||||||
|
height: $h;
|
||||||
|
padding-top: var(--el-font-size-base);
|
||||||
|
gap: var(--el-font-size-base);
|
||||||
|
|
||||||
|
.editor {
|
||||||
|
width: $h;
|
||||||
|
border: 1px solid #ececec;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #555;
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.js {
|
||||||
|
.t {
|
||||||
|
color: #fff;
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shop_manage {
|
||||||
|
flex: 3;
|
||||||
|
margin-left: var(--el-font-size-base);
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,290 @@
|
||||||
|
<template>
|
||||||
|
<!-- <el-button @click="chooseSerial">获取串口列表</el-button> -->
|
||||||
|
<el-button @click="initWebSocket()">连接ws</el-button>
|
||||||
|
<el-button @click="dakai()"></el-button>
|
||||||
|
<!-- 打印二维码 -->
|
||||||
|
<rintermodelindex ref="rintermodelindexref" :form="form" @somethingDone="handleSomethingDone"></rintermodelindex>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { bySubType } from "@/api/device";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { ipcRenderer } from 'electron'
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import useStorage from '@/utils/useStorage'
|
||||||
|
import rintermodelindex from '@/components/lodop/index.vue'
|
||||||
|
const store = useUser();
|
||||||
|
|
||||||
|
const rintermodelindexref = ref()//打印机ref
|
||||||
|
// 打印成功回调
|
||||||
|
const handleSomethingDone = () => {
|
||||||
|
console.log('打印成功回调成功')
|
||||||
|
}
|
||||||
|
const form = ref({
|
||||||
|
article: '1',
|
||||||
|
type: '2',
|
||||||
|
|
||||||
|
})
|
||||||
|
const dakai = () => {
|
||||||
|
rintermodelindexref.value.centerDialogVisibleshow() //打开二维码打印
|
||||||
|
rintermodelindexref.value.initialization()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小票打印机列表
|
||||||
|
const printList = ref([]);
|
||||||
|
// 标签打印机列表
|
||||||
|
const printLabelList = ref([]);
|
||||||
|
const localPrintList = ref([])
|
||||||
|
|
||||||
|
// 获取打印机状态
|
||||||
|
async function bySubTypeAjax() {
|
||||||
|
try {
|
||||||
|
const res1 = await bySubType({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
contentType: "local",
|
||||||
|
subType: "cash",
|
||||||
|
});
|
||||||
|
const res2 = await bySubType({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
contentType: "local",
|
||||||
|
subType: "label",
|
||||||
|
});
|
||||||
|
printList.value = res1;
|
||||||
|
printLabelList.value = res2;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取本地打印机列表
|
||||||
|
function getPrintList() {
|
||||||
|
ipcRenderer.send("getPrintList");
|
||||||
|
ipcRenderer.on("printList", (event, arg) => {
|
||||||
|
localPrintList.value = arg;
|
||||||
|
// console.log(localPrintList.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查本地打印机是否能正常使用
|
||||||
|
function checkLocalPrint(deviceName) {
|
||||||
|
let print = ''
|
||||||
|
for (let item of localPrintList.value) {
|
||||||
|
if (item.name == deviceName) {
|
||||||
|
print = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!print.name) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印小票
|
||||||
|
function printBill(props) {
|
||||||
|
if (!checkLocalPrint(printLabelList.value[0].config.deviceName)) {
|
||||||
|
ElMessage.error("本地打印机无法使用,请检查打印机是否正确连接");
|
||||||
|
} else {
|
||||||
|
const data = {
|
||||||
|
shop_name: store.userInfo.merchantName,
|
||||||
|
carts: props.carts,
|
||||||
|
amount: props.amount,
|
||||||
|
remark: props.remark,
|
||||||
|
orderInfo: props.orderInfo,
|
||||||
|
deviceName: printList.value[0].config.deviceName,
|
||||||
|
createdAt: dayjs(props.orderInfo.createdAt).format(
|
||||||
|
"YYYY-MM-DD HH:mm:ss"
|
||||||
|
),
|
||||||
|
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
};
|
||||||
|
ipcRenderer.send("printerInfoSync", JSON.stringify(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测是否打印标签小票
|
||||||
|
function checkLabelPrint(props) {
|
||||||
|
if (!checkLocalPrint(printLabelList.value[0].config.deviceName)) {
|
||||||
|
ElMessage.error("本地打印机无法使用,请检查打印机是否正确连接");
|
||||||
|
} else {
|
||||||
|
let pids = printLabelList.value[0].config.categoryList.map(item => item.id)
|
||||||
|
let labelList = []
|
||||||
|
props.carts.map(item => {
|
||||||
|
if (pids.some(el => el == item.categoryId)) {
|
||||||
|
for (let i = 0; i < item.number; i++) {
|
||||||
|
labelList.push(
|
||||||
|
{
|
||||||
|
outNumber: props.outNumber,
|
||||||
|
name: item.name,
|
||||||
|
skuName: item.skuName,
|
||||||
|
masterId: props.orderInfo.tableName,
|
||||||
|
deviceName: printLabelList.value[0].config.deviceName,
|
||||||
|
createdAt: dayjs(props.createdAt).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
printLabel(labelList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印标签
|
||||||
|
let labelCount = ref(0)
|
||||||
|
let labelPrintTimer = ref(null)
|
||||||
|
function printLabel(list) {
|
||||||
|
console.log(list);
|
||||||
|
if (!checkLocalPrint(printLabelList.value[0].config.deviceName)) {
|
||||||
|
ElMessage.error("本地打印机无法使用,请检查打印机是否正确连接");
|
||||||
|
} else {
|
||||||
|
labelPrintTimer.value = setInterval(() => {
|
||||||
|
// console.log('labelCount', labelCount.value);
|
||||||
|
list[labelCount.value].count = `${list.length - labelCount.value}/${list.length}`
|
||||||
|
ipcRenderer.send('printerTagSync', JSON.stringify(list[labelCount.value]))
|
||||||
|
labelCount.value++
|
||||||
|
if (labelCount.value > list.length - 1) {
|
||||||
|
clearInterval(labelPrintTimer.value)
|
||||||
|
labelPrintTimer.value = null
|
||||||
|
labelCount.value = 0
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ws = ref(null)
|
||||||
|
let wsIsClose = ref(false)
|
||||||
|
// 初始化websocket
|
||||||
|
function initWebSocket(wsUrl = 'wss://wxcashiertest.sxczgkj.cn/client') {
|
||||||
|
ws.value = new WebSocket(wsUrl);
|
||||||
|
console.log("websocket:", ws.value);
|
||||||
|
|
||||||
|
ws.value.onopen = function () {
|
||||||
|
console.log('wss连接成功');
|
||||||
|
// 清除心跳
|
||||||
|
clearInterval(heartbeatTimer.value)
|
||||||
|
heartbeatTimer.value = null
|
||||||
|
startheartbeat()
|
||||||
|
|
||||||
|
// 清除重连
|
||||||
|
clearInterval(reConnectTimer.value)
|
||||||
|
reConnectTimer.value = null
|
||||||
|
reConnectCount.value = 0
|
||||||
|
|
||||||
|
ws.value.send(JSON.stringify({
|
||||||
|
type: "connect",
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
clientId: useStorage.get('uuid')
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
// 接收消息
|
||||||
|
ws.value.onmessage = function (e) {
|
||||||
|
// websocketonmessage(e);
|
||||||
|
let data = JSON.parse(e.data)
|
||||||
|
if (data.type == 'order') {
|
||||||
|
console.log('接收消息', data);
|
||||||
|
// 接收订单消息,打印小票
|
||||||
|
// printBill(data)
|
||||||
|
|
||||||
|
// 检测是否需要打印标签小票
|
||||||
|
checkLabelPrint(data)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 连接发生错误
|
||||||
|
ws.value.onerror = function () {
|
||||||
|
console.log("WebSocket连接发生错误");
|
||||||
|
|
||||||
|
// 清除心跳
|
||||||
|
clearInterval(heartbeatTimer.value)
|
||||||
|
heartbeatTimer.value = null
|
||||||
|
|
||||||
|
// 手动关闭后不在执行自动连接任务
|
||||||
|
if (!wsIsClose.value) reConnect(wsUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭
|
||||||
|
ws.value.onclose = function (e) {
|
||||||
|
console.log('ws关闭了', e);
|
||||||
|
|
||||||
|
// 清除心跳
|
||||||
|
clearInterval(heartbeatTimer.value)
|
||||||
|
heartbeatTimer.value = null
|
||||||
|
|
||||||
|
// 手动关闭后不在执行自动连接任务
|
||||||
|
if (!wsIsClose.value) reConnect(wsUrl);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动心跳连接
|
||||||
|
let heartbeatTimer = ref(null)
|
||||||
|
function startheartbeat() {
|
||||||
|
heartbeatTimer.value = setInterval(() => {
|
||||||
|
ws.value.send(JSON.stringify({ type: 'heartbeat' }))
|
||||||
|
}, 10000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重连最大次数5次
|
||||||
|
let reConnectCount = ref(0)
|
||||||
|
let reConnectTimer = ref(null)
|
||||||
|
function reConnect(wsUrl) {
|
||||||
|
if (reConnectTimer.value != null) return
|
||||||
|
reConnectTimer.value = setInterval(() => {
|
||||||
|
// 自动连接超过5次不在连接,需手动出发
|
||||||
|
console.log('reConnectCount.value===', reConnectCount.value);
|
||||||
|
if (reConnectCount.value >= 5) {
|
||||||
|
console.log('重连超过5次,不在连接');
|
||||||
|
clearInterval(reConnectTimer.value)
|
||||||
|
reConnectTimer.value = null
|
||||||
|
reConnectCount.value = 0
|
||||||
|
wsIsClose.value = true
|
||||||
|
ws.value.close()
|
||||||
|
} else {
|
||||||
|
reConnectCount.value++
|
||||||
|
initWebSocket(wsUrl)
|
||||||
|
}
|
||||||
|
}, 5000)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 打印标签小票
|
||||||
|
const printTag = () => {
|
||||||
|
ipcRenderer.send('printerTagSync', JSON.stringify({
|
||||||
|
deviceName: 'Xprinter XP-365B123'
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
//选择串口设备
|
||||||
|
const chooseSerial = async () => {
|
||||||
|
// let printNum = localStorage.getItem('printNum')
|
||||||
|
// if (!printNum) {
|
||||||
|
// printNum = 1
|
||||||
|
// localStorage.setItem('printNum', printNum)
|
||||||
|
// } else {
|
||||||
|
// printNum++
|
||||||
|
// localStorage.setItem('printNum', printNum)
|
||||||
|
// }
|
||||||
|
// ipcRenderer.send('printStart', printNum)
|
||||||
|
// ipcRenderer.send('getSerialPort')
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
ipcRenderer.on('seriaportList', (e, a) => {
|
||||||
|
console.log('seriaportList', a);
|
||||||
|
})
|
||||||
|
|
||||||
|
getPrintList();
|
||||||
|
bySubTypeAjax();
|
||||||
|
initWebSocket()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
@ -4,57 +4,46 @@
|
||||||
<el-image :src="logo" style="width: 180px"></el-image>
|
<el-image :src="logo" style="width: 180px"></el-image>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-wrap">
|
<div class="form-wrap">
|
||||||
<div class="reg-wrap">
|
<div style="flex: 1">
|
||||||
|
<!-- <div class="reg-wrap">
|
||||||
<router-link :to="{ name: 'register' }">
|
<router-link :to="{ name: 'register' }">
|
||||||
<el-link type="primary">注册</el-link>
|
<el-link type="primary">注册</el-link>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span class="t1">银收客</span>
|
<span class="t1">银收客</span>
|
||||||
<span class="t2">收银、库存、营销、支付等业务一体化解决方案</span>
|
<span class="t2">收银、库存、营销、支付等业务一体化解决方案</span>
|
||||||
</div>
|
</div>
|
||||||
<el-form
|
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" hide-required-asterisk>
|
||||||
ref="formRef"
|
<el-form-item label="商户号" prop="merchantName">
|
||||||
:model="form"
|
<el-input v-model="form.merchantName" placeholder="请输入注册商户号"></el-input>
|
||||||
:rules="rules"
|
|
||||||
label-position="top"
|
|
||||||
size="large"
|
|
||||||
hide-required-asterisk
|
|
||||||
>
|
|
||||||
<el-form-item label="注册商户号" prop="shopCode">
|
|
||||||
<el-input
|
|
||||||
v-model="form.shopCode"
|
|
||||||
placeholder="请输入注册商户号"
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="手机号码" prop="phone">
|
<el-form-item label="手机号码" prop="loginName">
|
||||||
<el-input
|
<el-input v-model="form.loginName" placeholder="请输入11位手机号码"></el-input>
|
||||||
v-model="form.phone"
|
|
||||||
placeholder="请输入11位手机号码"
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="登录密码" prop="password">
|
<el-form-item label="登录密码" prop="password">
|
||||||
<el-input
|
<el-input v-model="form.password" :type="passwordType" placeholder="请输入登录密码">
|
||||||
v-model="form.password"
|
<template #suffix>
|
||||||
type="password"
|
<el-icon class="el-input__icon" v-if="passwordType == 'password'" @click="passwordType = 'text'">
|
||||||
placeholder="请输入登录密码"
|
<Hide />
|
||||||
></el-input>
|
</el-icon>
|
||||||
|
<el-icon class="el-input__icon" v-else @click="passwordType = 'password'">
|
||||||
|
<View />
|
||||||
|
</el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<!-- <el-form-item>
|
||||||
<div style="width: 100%; display: flex; justify-content: flex-end">
|
<div style="width: 100%; display: flex; justify-content: flex-end">
|
||||||
<router-link :to="{ name: 'register' }">
|
<router-link :to="{ name: 'register' }">
|
||||||
<el-link type="info">忘记密码</el-link>
|
<el-link type="info">忘记密码</el-link>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button
|
<el-button type="primary" style="width: 100%" :loading="loading" @click="submitHandle">
|
||||||
type="primary"
|
<span v-if="!loading">登录</span>
|
||||||
style="width: 100%"
|
<span v-else>登录中...</span>
|
||||||
:loading="loading"
|
|
||||||
@click="submitHandle"
|
|
||||||
>
|
|
||||||
登录
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
|
|
@ -62,49 +51,65 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="version">
|
<div class="version">
|
||||||
<el-text size="large">Ver2.1.6</el-text>
|
<el-text size="large">Ver{{ packageData.version }}</el-text>
|
||||||
<el-text size="large">陕西超掌柜科技有限公司</el-text>
|
<el-text size="large">陕西超掌柜科技有限公司</el-text>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import packageData from "../../package.json";
|
||||||
import logo from "@/assets/logo.png";
|
import logo from "@/assets/logo.png";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import { reactive, ref } from "vue";
|
import { Hide, View } from '@element-plus/icons-vue'
|
||||||
|
import { onMounted, reactive, ref } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
|
import { RandomNumBoth } from "@/utils";
|
||||||
|
import useStorage from "@/utils/useStorage";
|
||||||
|
import { douyincheckIn } from "@/api/group";
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import { useSocket } from "@/store/socket.js";
|
||||||
|
import { useGlobal } from '@/store/global.js'
|
||||||
|
const global = useGlobal()
|
||||||
|
|
||||||
|
const store = useUser();
|
||||||
|
const socket = useSocket();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const formRef = ref(null);
|
const formRef = ref(null);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const passwordType = ref('password')
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
shopCode: "",
|
serialNumber: RandomNumBoth(1000, 9999),
|
||||||
phone: "",
|
clientType: "pc",
|
||||||
|
merchantName: "",
|
||||||
|
loginName: "",
|
||||||
password: "",
|
password: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
shopCode: [
|
merchantName: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入注册商户号",
|
message: " ",
|
||||||
trigger: "blur",
|
trigger: "blur",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
phone: [
|
loginName: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入11位手机号码",
|
message: " ",
|
||||||
trigger: "blur",
|
trigger: "blur",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入登录密码",
|
message: " ",
|
||||||
trigger: "blur",
|
trigger: "blur",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -112,16 +117,30 @@ const rules = reactive({
|
||||||
|
|
||||||
// 提交
|
// 提交
|
||||||
const submitHandle = () => {
|
const submitHandle = () => {
|
||||||
formRef.value.validate((valid) => {
|
formRef.value.validate(async (valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
store
|
||||||
|
.userlogin(form)
|
||||||
|
.then(async (res) => {
|
||||||
ElMessage.success("登录成功");
|
ElMessage.success("登录成功");
|
||||||
localStorage.setItem("token", "skk918sjakajhjjqhw19jsdkandkahk");
|
socket.init();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
router.replace({
|
router.replace({
|
||||||
name: "home",
|
name: "home",
|
||||||
});
|
});
|
||||||
}, 1500);
|
}, 1000);
|
||||||
|
const douyin = await douyincheckIn({
|
||||||
|
token: res.token,
|
||||||
|
loginName: res.loginName,
|
||||||
|
clientType: 'pc'
|
||||||
|
})
|
||||||
|
useStorage.set('douyin', douyin.userInfo)
|
||||||
|
global.updateData(true)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -131,14 +150,25 @@ const logout = () => {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
ipcRenderer.send("quitHandler", "退出吧");
|
ipcRenderer.send("quitHandler", "退出吧");
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => { });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
global.updateData(false)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.login-container {
|
.login-container {
|
||||||
|
width: 100vw;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
background-color: #efefef;
|
||||||
|
|
||||||
|
:deep(.el-form-item__label) {
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: inherit;
|
height: inherit;
|
||||||
|
|
@ -147,32 +177,40 @@ const logout = () => {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-wrap {
|
.form-wrap {
|
||||||
flex: 1;
|
flex: 1.5;
|
||||||
height: inherit;
|
height: inherit;
|
||||||
padding: 50px;
|
padding: 0 50px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reg-wrap {
|
.reg-wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding-bottom: 100px;
|
padding-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding-bottom: 100px;
|
padding-bottom: 20px;
|
||||||
|
|
||||||
.t1 {
|
.t1 {
|
||||||
font-size: 52px;
|
font-size: 42px;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t2 {
|
.t2 {
|
||||||
font-size: 24px;
|
font-size: var(--el-font-size-base);
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.version {
|
.version {
|
||||||
padding-top: 50px;
|
padding-top: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
<template>
|
||||||
|
<div class="box">
|
||||||
|
<div class="dialog_footer" v-for="(item, index) in props.flowingwater.list" :key="index">
|
||||||
|
<div class="dialog_footer_left">
|
||||||
|
<span>{{ item.biz_name }}</span>
|
||||||
|
<span>{{ dayjs(item.create_time).format("YYYY-MM-DD HH:mm:ss") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="dialog_footer_right">
|
||||||
|
<span :class="{ active: item.type == '+' }">
|
||||||
|
<template v-if="item.type == '+'">+</template>
|
||||||
|
<template v-else>-</template>
|
||||||
|
¥{{ formatDecimal(item.amount) }}
|
||||||
|
</span>
|
||||||
|
<span>余额:¥{{ formatDecimal(item.balance) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty description="暂无数据" v-if="!props.flowingwater.list.length" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { dayjs } from 'element-plus'
|
||||||
|
import { formatDecimal } from '@/utils/index'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
flowingwater: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.box {
|
||||||
|
height: 400px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.dialog_footer:nth-child(1) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_footer {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
|
||||||
|
.dialog_footer_left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
span:nth-child(1) {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
span:nth-child(2) {
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_footer_right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
span:nth-child(1) {
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: #fc3d3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
span:nth-child(2) {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<el-drawer size="100%" :with-header="false" direction="btt" v-model="dialogVisible">
|
||||||
|
<div class="drawer_wrap">
|
||||||
|
<div class="pay_wrap">
|
||||||
|
<fastPayCard ref="fastPayCardRef" type="1" :userInfo="userInfo" @paySuccess="paySuccess"
|
||||||
|
@close="dialogVisible = false" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import fastPayCard from "@/components/fastPayCard.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
userInfo: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(["paySuccess"]);
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const fastPayCardRef = ref(null);
|
||||||
|
|
||||||
|
// 订单已支付
|
||||||
|
function paySuccess() {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
emit("paySuccess");
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
fastPayCardRef.value.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.drawer_wrap {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
padding: var(--el-font-size-base) 0;
|
||||||
|
|
||||||
|
.pay_wrap {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,777 @@
|
||||||
|
<template>
|
||||||
|
<div class="orderbox">
|
||||||
|
<div class="orderbox_left">
|
||||||
|
<div class="demo_tabs" v-if="props.membershow == '0'">
|
||||||
|
<div class="demo_tabs_div">
|
||||||
|
<el-input v-model="tableData.phone" placeholder="请输入手机号" @input="inputChange" clearable @focus="
|
||||||
|
global.updateData(false)" @blur="global.updateData(true)" />
|
||||||
|
<el-button style="margin-left: 10px;" type="primary" @click="memberaddshow = true">添加</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-table :data="tableData.list" style="width: 100%;margin-top: 10px;height:80%;"
|
||||||
|
:row-class-name="tableRowClassName" @cell-click="cellclicktableData" v-loading="loading">
|
||||||
|
<el-table-column prop="name" label="昵称" />
|
||||||
|
<el-table-column prop="telephone" label="手机" width="200px" />
|
||||||
|
<el-table-column prop="code" label="编号" width="150px" />
|
||||||
|
<el-table-column prop="level" label="等级" />
|
||||||
|
<el-table-column prop="levelConsume" label="积分" />
|
||||||
|
<el-table-column prop="amount" label="余额" />
|
||||||
|
</el-table>
|
||||||
|
<el-pagination layout="prev, pager, next, jumper" style="margin-top: 20px;" :total="Number(tableData.total)"
|
||||||
|
@current-change="handleCurrentChange" />
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right">
|
||||||
|
<div class="orderbox_right_top">
|
||||||
|
<div class="orderbox_right_topdiv">
|
||||||
|
<span>会员昵称:</span>
|
||||||
|
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].name : '无' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_topdiv">
|
||||||
|
<span>手机号码:</span>
|
||||||
|
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].telephone : '无' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_topdiv">
|
||||||
|
<span>会员编号:</span>
|
||||||
|
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].code : '无' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_topdiv">
|
||||||
|
<span>会员等级:</span>
|
||||||
|
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].level : '无' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_top_item">
|
||||||
|
<div class="orderbox_right_top_item_one">
|
||||||
|
<el-icon :size="24" style="color:#ffbc42 ;">
|
||||||
|
<Money />
|
||||||
|
</el-icon>
|
||||||
|
<span class="orderbox_right_top_item_onespan">会员积分</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_top_item_tow">{{ tableData.list.length != 0 ?
|
||||||
|
tableData.list[datarow].levelConsume : '无' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_top_item" @click="stored = true">
|
||||||
|
<div class="orderbox_right_top_item_one">
|
||||||
|
<el-icon :size="24" style="color:#00b58d ;">
|
||||||
|
<Box />
|
||||||
|
</el-icon>
|
||||||
|
<span class="orderbox_right_top_item_onespan">储值余额</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_top_item_tow">
|
||||||
|
<span>{{ tableData.list.length != 0 ? tableData.list[datarow].amount : '无' }}</span>
|
||||||
|
<el-icon size="10">
|
||||||
|
<ArrowRight />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="orderbox_right_top_item">
|
||||||
|
<div class="orderbox_right_top_item_one">
|
||||||
|
<el-icon :size="24" style="color:#00b58d ;">
|
||||||
|
<CopyDocument />
|
||||||
|
</el-icon>
|
||||||
|
<span class="orderbox_right_top_item_onespan">优惠券</span>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_top_item_tow">
|
||||||
|
<span>0</span>
|
||||||
|
<el-icon size="10">
|
||||||
|
<ArrowRight />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_input" style="margin-top:20px ;" v-if="props.membershow == '1'">
|
||||||
|
<el-input placeholder="请输入会员手机号或者编号" v-model="tableData.phone" clearable
|
||||||
|
@input="inputChange"></el-input>
|
||||||
|
</div>
|
||||||
|
<keyboard v-if="props.membershow == '1'" @consumeFees="consumeFees"></keyboard>
|
||||||
|
<div class="orderbox_right_button" v-if="props.membershow == '0'">
|
||||||
|
<el-button style="width: 100%;" @click="toHome">创建订单</el-button>
|
||||||
|
<!-- <el-button style="width: 60%;" type="primary" @click="recharge = true">账户充值</el-button> -->
|
||||||
|
<el-button style="width: 60%;" type="primary" @click="userChargeRef.show()">账户充值</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="orderbox_right_button" v-if="props.membershow == '1'">
|
||||||
|
<router-link to="/" style="width: 35%;">
|
||||||
|
<el-button style="width: 100%;" @click="memberaddshowclose">添加会员</el-button>
|
||||||
|
</router-link>
|
||||||
|
<el-button style="width: 60%;" type="primary">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog v-model="stored" title="余额明细" width="500" :before-close="handleClose">
|
||||||
|
<add :flowingwater='flowingwater' />
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog v-model="memberaddshow" title="添加会员" width="600" :before-close="memberaddshowclose"
|
||||||
|
@open="membrform = { ...resetMembrform }">
|
||||||
|
<el-form ref="formRef" :rules="rules" :model="membrform" label-width="70px" hide-required-asterisk>
|
||||||
|
<el-form-item label="手机号" prop="phone">
|
||||||
|
<el-input v-model="membrform.phone" @focus="
|
||||||
|
global.updateData(false)" @blur="global.updateData(true)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="昵称" prop="nickName">
|
||||||
|
<el-input v-model="membrform.nickName" @focus="
|
||||||
|
global.updateData(false)" @blur="global.updateData(true)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="生日" prop="birthDay">
|
||||||
|
<el-col :span="11">
|
||||||
|
<el-date-picker v-model="membrform.birthDay" type="date" placeholder="请选择生日" style="width: 100%"
|
||||||
|
@focus="
|
||||||
|
global.updateData(false)" @blur="global.updateData(true)" />
|
||||||
|
</el-col>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="性别" prop="sex">
|
||||||
|
<el-radio-group v-model="membrform.sex">
|
||||||
|
<el-radio :label="1">男</el-radio>
|
||||||
|
<el-radio :label="2">女</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="等级" prop="level">
|
||||||
|
<el-select v-model="membrform.level" placeholder="请选择等级">
|
||||||
|
<el-option label="等级1" value="1" />
|
||||||
|
<el-option label="等级2" value="2" />
|
||||||
|
<el-option label="等级3" value="3" />
|
||||||
|
<el-option label="等级4" value="4" />
|
||||||
|
<el-option label="等级5" value="5" />
|
||||||
|
<el-option label="等级6" value="6" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button style="width: 100%;" type="primary" @click="createMembermemberSubmit">确认</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog v-model="recharge" title="会员充值" width="400" :before-close="handlerecharge">
|
||||||
|
<div class="recharge_footer">
|
||||||
|
<!-- <div class="recharge_footer_item">
|
||||||
|
<div class="recharge_footer_items" v-for="(item, index) in 6" :key="index">
|
||||||
|
<div>充1000送300</div>
|
||||||
|
<div>充1000.00到13000.00</div>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
<div class="recharge_footer_itemright">
|
||||||
|
<div class="recharge_footer_itemright_input">
|
||||||
|
<div>充值金额:</div>
|
||||||
|
<div v-if="moneys">{{ moneys ? moneys : '请输入充值金额' }}</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class='keyboard'>
|
||||||
|
<cwxeyboard @confirmEvent="confirmEvent" @consumeFee="consumeFee" btn-color="orange" title="支付">
|
||||||
|
</cwxeyboard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
<el-dialog width="500" v-model="payCarddialogVisible" style="padding: 0; " title="会员充值"
|
||||||
|
:close-on-click-modal="false">
|
||||||
|
<payCard :amount="moneys" :orderId="orderId" :selecttype="1" @paySuccess="paySuccess" />
|
||||||
|
</el-dialog>
|
||||||
|
<userCharge ref="userChargeRef" :userInfo="tableData.list[datarow]" @paySuccess="asyncqueryMembermember" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch, onMounted } from 'vue'
|
||||||
|
import { ElMessage, dayjs } from 'element-plus'
|
||||||
|
import { queryMembermember, createMembermember, memberqueryMemberAccount, accountPaymember } from '@/api/member/index.js'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
import lodash from 'lodash'
|
||||||
|
import add from '@/views/member/components/add.vue'
|
||||||
|
import cwxeyboard from '@/components/cwx-keyboard/cwx-keyboard.vue'
|
||||||
|
import keyboard from '@/views/home/components/keyboard.vue'
|
||||||
|
import payCard from '@/components/payCard/payCard.vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import useStorage from '@/utils/useStorage'
|
||||||
|
import userCharge from './components/userCharge.vue'
|
||||||
|
|
||||||
|
import { useGlobal } from '@/store/global.js'
|
||||||
|
const global = useGlobal()
|
||||||
|
|
||||||
|
const userChargeRef = ref(null)
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const stored = ref(false)//储值余额
|
||||||
|
|
||||||
|
const handleClose = async () => {
|
||||||
|
stored.value = !stored.value
|
||||||
|
}
|
||||||
|
const emit = defineEmits('paySuccess')
|
||||||
|
|
||||||
|
function paySuccess() {
|
||||||
|
payCarddialogVisible.value = false
|
||||||
|
recharge.value = false
|
||||||
|
moneys.value = 0
|
||||||
|
asyncqueryMembermember()
|
||||||
|
emit('paySuccess')
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({//首页传值
|
||||||
|
membershow: {
|
||||||
|
type: String,
|
||||||
|
default: '0'
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '提示'
|
||||||
|
},
|
||||||
|
amount: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const flowingwater = reactive({//获取流水初始化
|
||||||
|
total: '',
|
||||||
|
list: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const consumeFee = (e) => { //接收子组件值 并赋值给父组件
|
||||||
|
moneys.value = e
|
||||||
|
}
|
||||||
|
|
||||||
|
const consumeFees = (e) => {
|
||||||
|
tableData.phone = e
|
||||||
|
}
|
||||||
|
|
||||||
|
const payCarddialogVisible = ref(false)
|
||||||
|
|
||||||
|
const orderId = ref('')
|
||||||
|
|
||||||
|
const confirmEvent = async () => {//子组件 确认按钮
|
||||||
|
orderId.value = tableData.list[datarow.value].id
|
||||||
|
payCarddialogVisible.value = true
|
||||||
|
// try {
|
||||||
|
// let res = await accountPaymember({
|
||||||
|
// shopId: store.userInfo.shopId,
|
||||||
|
// memberId: tableData.list[datarow.value].id,
|
||||||
|
// amount: moneys.value
|
||||||
|
// })
|
||||||
|
// if (res == null) {
|
||||||
|
// recharge.value = false
|
||||||
|
// moneys.value = 0
|
||||||
|
// ElMessage({
|
||||||
|
// message: '充值成功',
|
||||||
|
// type: 'success',
|
||||||
|
// })
|
||||||
|
// resetMembrform.value = { ...membrform.value }
|
||||||
|
// asyncqueryMembermember()
|
||||||
|
// }
|
||||||
|
// } catch (error) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
const MemberAccount = async () => {//获取流水
|
||||||
|
try {
|
||||||
|
let res = await memberqueryMemberAccount({
|
||||||
|
memberId: tableData.list[datarow.value].id,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10
|
||||||
|
})
|
||||||
|
flowingwater.total = res.total
|
||||||
|
flowingwater.list = res.list
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const recharge = ref(false)//充值
|
||||||
|
|
||||||
|
const memberaddshow = ref(false) //添加会员
|
||||||
|
|
||||||
|
const memberaddshowclose = () => {
|
||||||
|
memberaddshow.value = !memberaddshow.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableData = reactive({//表格数据
|
||||||
|
list: [],
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
phone: '',
|
||||||
|
total: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const inputChange = lodash.debounce(function () { //搜索手机号
|
||||||
|
asyncqueryMembermember()
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
const asyncqueryMembermember = async () => {//会员列表数据
|
||||||
|
loading.value = true
|
||||||
|
let res = await queryMembermember({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
page: tableData.page,
|
||||||
|
pageSize: 10,
|
||||||
|
phone: tableData.phone
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false
|
||||||
|
}, 300)
|
||||||
|
tableData.list = res.list
|
||||||
|
MemberAccount()
|
||||||
|
tableData.total = res.total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableRowClassName = ({ row, rowIndex }) => {//动态给tab加样式
|
||||||
|
if (rowIndex === datarow.value) {
|
||||||
|
return 'warning-row'
|
||||||
|
} return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const datarow = ref(0) //初始化右边
|
||||||
|
const cellclicktableData = (row, column, cell, event) => {
|
||||||
|
const index = tableData.list.findIndex(item => item.id == row.id)
|
||||||
|
datarow.value = index
|
||||||
|
MemberAccount()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => { //页码
|
||||||
|
tableData.page = val
|
||||||
|
datarow.value = 0
|
||||||
|
asyncqueryMembermember()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlerecharge = () => {
|
||||||
|
recharge.value = !recharge.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetMembrform = ref({})
|
||||||
|
|
||||||
|
const membrform = ref({ //membrform 添加会员表单
|
||||||
|
phone: '',
|
||||||
|
nickName: '',
|
||||||
|
level: '',
|
||||||
|
birthDay: '',
|
||||||
|
sex: '',
|
||||||
|
level: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const formRef = ref(null); //ref membrform
|
||||||
|
|
||||||
|
const rules = reactive({ // membrform验证
|
||||||
|
phone: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请输入11位手机号码",
|
||||||
|
trigger: "blur",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
nickName: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请输入昵称",
|
||||||
|
trigger: "blur",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sex: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请选择性别",
|
||||||
|
trigger: 'change',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
level: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "请选择等级",
|
||||||
|
trigger: 'change',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
birthDay: [
|
||||||
|
{
|
||||||
|
type: 'date',
|
||||||
|
required: true,
|
||||||
|
message: '请选择生日日期',
|
||||||
|
trigger: 'change',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const createMembermemberSubmit = async () => { ///添加会员
|
||||||
|
formRef.value.validate(async (valid) => {
|
||||||
|
console.log(valid)
|
||||||
|
if (valid) {
|
||||||
|
|
||||||
|
let res = await createMembermember({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
phone: membrform.value.phone,
|
||||||
|
nickName: membrform.value.nickName,
|
||||||
|
sex: membrform.value.sex,
|
||||||
|
level: membrform.value.level,
|
||||||
|
birthDay: dayjs(membrform.value.birthDay).format("YYYY-MM-DD")
|
||||||
|
})
|
||||||
|
if (res == null) {
|
||||||
|
|
||||||
|
memberaddshowclose()
|
||||||
|
ElMessage({
|
||||||
|
message: '添加成功',
|
||||||
|
type: 'success',
|
||||||
|
})
|
||||||
|
asyncqueryMembermember()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const moneys = ref('')// 钱数
|
||||||
|
|
||||||
|
const toHome = () => {
|
||||||
|
useStorage.set('memberInfo', tableData.list[datarow.value])
|
||||||
|
router.push({
|
||||||
|
name: 'home'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// resetMembrform.value = { ...membrform.value }
|
||||||
|
asyncqueryMembermember()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.orderbox {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.orderbox_left {
|
||||||
|
width: 60%;
|
||||||
|
height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px 0;
|
||||||
|
|
||||||
|
.demo_tabs {
|
||||||
|
.demo_tabs_div {
|
||||||
|
padding: 0 20px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo_tabs_box {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 20px;
|
||||||
|
|
||||||
|
.demo_tabs_boxitem {
|
||||||
|
width: 100%;
|
||||||
|
padding: 6px 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
// background: #eeeeee;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
|
||||||
|
.demo_tabs_boxitem_one {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.demo_tabs_boxitem_oneone {
|
||||||
|
display: flex;
|
||||||
|
margin-left: 20px;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 70px;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo_tabs_boxitem_onetow {
|
||||||
|
display: flex;
|
||||||
|
margin-left: 20px;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 70px;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo_tabs_boxitem_tow {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 70px;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right {
|
||||||
|
position: relative;
|
||||||
|
width: 40%;
|
||||||
|
padding: 20px;
|
||||||
|
margin-left: 10px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
.orderbox_right_top {
|
||||||
|
color: #fff;
|
||||||
|
width: 100%;
|
||||||
|
background: #8b008b;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
.orderbox_right_topdiv:nth-child(1) {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_topdiv {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_top_item {
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
padding: 6px 10px;
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.orderbox_right_top_item_one {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.orderbox_right_top_item_onespan {
|
||||||
|
color: black;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.orderbox_right_top_item_tow {
|
||||||
|
color: black;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.orderbox_right_button {
|
||||||
|
position: absolute;
|
||||||
|
width: 90%;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
transform: translateX(-50%) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_footer:nth-child(1) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_footer {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
|
||||||
|
.dialog_footer_left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
span:nth-child(1) {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
span:nth-child(2) {
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_footer_right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
span:nth-child(1) {
|
||||||
|
color: #fc3d3d;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
span:nth-child(2) {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.recharge_footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.recharge_footer_item {
|
||||||
|
width: 60%;
|
||||||
|
background: #f2f2f2;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-flow: wrap;
|
||||||
|
|
||||||
|
.recharge_footer_items {
|
||||||
|
background: #187ead;
|
||||||
|
padding: 16px 22px;
|
||||||
|
width: 45%;
|
||||||
|
height: fit-content;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
div:nth-child(1) {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div:nth-child(2) {
|
||||||
|
color: #bad9e7;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.recharge_footer_itemright {
|
||||||
|
padding-left: 20px;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
.recharge_footer_itemright_input {
|
||||||
|
width: 100%;
|
||||||
|
background: #333333;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 0 6px;
|
||||||
|
display: flex;
|
||||||
|
height: 60px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
div:nth-child(1) {
|
||||||
|
color: #56792e;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div:nth-child(2) {
|
||||||
|
color: #88937c;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.keyboard {
|
||||||
|
width: 100%;
|
||||||
|
height: 40vh;
|
||||||
|
background: #FFFFFF;
|
||||||
|
|
||||||
|
.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: 30px;
|
||||||
|
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: 60px;
|
||||||
|
font-size: 30px;
|
||||||
|
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: 30px;
|
||||||
|
|
||||||
|
.zero {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 66.66%;
|
||||||
|
font-size: 30px;
|
||||||
|
text-align: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 33.33%;
|
||||||
|
font-size: 30px;
|
||||||
|
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,132 @@
|
||||||
|
<template>
|
||||||
|
<div class="demo_tabs_box" v-loading="props.loading">
|
||||||
|
<div class="demo_tabs_boxitem" v-for="(item, index) in ordereData.list" :key="index"
|
||||||
|
@click="clickitemboxshow(item)">
|
||||||
|
<!-- <div class="demo_tabs_boxitem_oneyt" v-if="item.status == 'refund' && item.orderType == 'return'">已退款</div> -->
|
||||||
|
|
||||||
|
<div class="demo_tabs_boxitem_one">
|
||||||
|
<div class=""
|
||||||
|
style="width: 100px; height: 70px;border-radius: 4px; background:rgb(186 200 239); display: flex; justify-content: center; align-items: center;">
|
||||||
|
<div>{{ item.tableName || "pos" }}</div>
|
||||||
|
</div>
|
||||||
|
<!-- <el-image style="width: 100px; height: 70px;border-radius: 10px;" :src="item.imgUrl" fit="scale-down" /> -->
|
||||||
|
<div class="demo_tabs_boxitem_oneone">
|
||||||
|
<div>
|
||||||
|
{{ dayjs(item.createAt).format(" HH:mm:ss") }}
|
||||||
|
</div>
|
||||||
|
<div style="color: #757575;">
|
||||||
|
{{ dayjs(item.createAt).format("YYYY-MM-DD") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo_tabs_boxitem_onetow">
|
||||||
|
<div style="font-size: 16px; color: #757575;">{{ item.orderNo }}</div>
|
||||||
|
<div>
|
||||||
|
<span>{{ item.names && item.names[0] }} </span>
|
||||||
|
<span style="margin-left: 6px;">{{ item.names && item.names.length }}项</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo_tabs_boxitem_tow">
|
||||||
|
<div>
|
||||||
|
¥{{ item.orderAmount }}
|
||||||
|
</div>
|
||||||
|
<div style="color:#ff9e01;">
|
||||||
|
<span v-if="item.status == 'pending'">挂单</span>
|
||||||
|
<span style="color: red;" v-if="item.status == 'refund' && item.orderType == 'return'">退单</span>
|
||||||
|
<span style="color:#21c36b;"
|
||||||
|
v-if="item.orderType != 'return' && (item.status == 'closed' || item.status == 'refund')">订单完成</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { dayjs } from 'element-plus'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
ordereData: {
|
||||||
|
type: Object,
|
||||||
|
default: {
|
||||||
|
list: [{
|
||||||
|
names: []
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits(["emititemboxshow"])
|
||||||
|
const clickitemboxshow = (e) => {
|
||||||
|
emit('emititemboxshow', e)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.demo_tabs_box {
|
||||||
|
width: 100%;
|
||||||
|
height: 82%;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.demo_tabs_boxitem {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.demo_tabs_boxitem_oneyt {
|
||||||
|
position: absolute;
|
||||||
|
top: 20%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
right: 200px;
|
||||||
|
display: inline-block;
|
||||||
|
border: 3px solid red;
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 6px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo_tabs_boxitem_one {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.demo_tabs_boxitem_oneone {
|
||||||
|
display: flex;
|
||||||
|
margin-left: 20px;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 70px;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo_tabs_boxitem_onetow {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo_tabs_boxitem_tow {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 70px;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="tab_container">
|
||||||
|
<el-table :data="tableData.list" height="560px" v-loading="tableData.loading">
|
||||||
|
<el-table-column label="订单号" prop="orderNo"></el-table-column>
|
||||||
|
<el-table-column label="金额" prop="amount">
|
||||||
|
<template v-slot="scope">
|
||||||
|
¥{{ scope.row.amount }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="支付类型" prop="payType">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<el-tag disable-transitions :type="payTypeFilter(scope.row.payType).type">
|
||||||
|
{{ payTypeFilter(scope.row.payType).label }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建时间" prop="createTime">
|
||||||
|
<template v-slot="scope">
|
||||||
|
{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
<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>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { queryQuickPay } from '@/api/order'
|
||||||
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
|
|
||||||
|
const tableData = reactive({
|
||||||
|
resetLoading: false,
|
||||||
|
proName: '',
|
||||||
|
status: '',
|
||||||
|
loading: false,
|
||||||
|
list: [],
|
||||||
|
page: 1,
|
||||||
|
size: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// 分页变化
|
||||||
|
function paginationChange(e) {
|
||||||
|
tableData.page = e
|
||||||
|
queryQuickPayAjax()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 支付类型
|
||||||
|
function payTypeFilter(t) {
|
||||||
|
const m = {
|
||||||
|
cash: {
|
||||||
|
type: 'primary',
|
||||||
|
label: '现金'
|
||||||
|
},
|
||||||
|
scanCode: {
|
||||||
|
type: 'warning',
|
||||||
|
label: '扫码'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m[t]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询快捷收银订单
|
||||||
|
async function queryQuickPayAjax() {
|
||||||
|
try {
|
||||||
|
tableData.loading = true
|
||||||
|
const res = await queryQuickPay({
|
||||||
|
page: tableData.page,
|
||||||
|
pageSize: tableData.size
|
||||||
|
})
|
||||||
|
tableData.loading = false
|
||||||
|
tableData.list = res.list
|
||||||
|
tableData.total = res.total
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
queryQuickPayAjax()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.tab_container {
|
||||||
|
padding: 0 var(--el-font-size-base) var(--el-font-size-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
padding: 0 14px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<template>
|
||||||
|
<el-date-picker v-model="dateVlaue" type="daterange" :editable="false" :shortcuts="shortcuts" range-separator="至"
|
||||||
|
start-placeholder="开始时间" end-placeholder="结束时间" :clearable="false" @change="dateConfirm" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { dayjs } from 'element-plus'
|
||||||
|
|
||||||
|
const emits = defineEmits(['success'])
|
||||||
|
|
||||||
|
const shortcuts = [
|
||||||
|
{
|
||||||
|
text: '今天',
|
||||||
|
value: () => {
|
||||||
|
return [
|
||||||
|
dayjs()
|
||||||
|
.startOf("day"),
|
||||||
|
dayjs()
|
||||||
|
.endOf("day")
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '本月',
|
||||||
|
value: () => {
|
||||||
|
return [
|
||||||
|
dayjs()
|
||||||
|
.startOf("month"),
|
||||||
|
dayjs()
|
||||||
|
.endOf("month")
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '最近三个月',
|
||||||
|
value: () => {
|
||||||
|
return [
|
||||||
|
dayjs()
|
||||||
|
.add(-3, "M"),
|
||||||
|
dayjs()
|
||||||
|
.endOf("month")
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '本年',
|
||||||
|
value: () => {
|
||||||
|
return [
|
||||||
|
dayjs()
|
||||||
|
.startOf("year"),
|
||||||
|
dayjs()
|
||||||
|
.endOf("year")
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const dateVlaue = ref([dayjs(), dayjs()])
|
||||||
|
const format = ["YYYY-MM-DD 00:00:00", "YYYY-MM-DD 23:59:59"];
|
||||||
|
|
||||||
|
// 确认选择时间
|
||||||
|
function dateConfirm(value) {
|
||||||
|
// console.log(value);
|
||||||
|
emits('success', [
|
||||||
|
dayjs(value[0]).format(format[0]),
|
||||||
|
dayjs(value[1]).format(format[1]),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 创建组件后执行一次时间传递
|
||||||
|
emits('success', [
|
||||||
|
dayjs(dateVlaue[0]).format(format[0]),
|
||||||
|
dayjs(dateVlaue[1]).format(format[1]),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog title="选择开票人" width="60%" v-model="dialogVisible">
|
||||||
|
<el-table :data="tableData.list" border>
|
||||||
|
<el-table-column label="开票人" prop="name"></el-table-column>
|
||||||
|
<el-table-column label="操作" width="140">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<el-button type="primary" icon="" :loading="scope.row.loading"
|
||||||
|
@click="selectHandle(scope.row)">选择</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog title="扫描二维码开票" width="330px" v-model="showEwmDialog">
|
||||||
|
<canvas class="ewm" ref="canvasRef"></canvas>
|
||||||
|
<div class="footer">
|
||||||
|
<el-button type="primary" style="width: 100%" :loading="printEwmLoading"
|
||||||
|
@click="printEwmHandle">打印二维码</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import QRCode from 'qrcode'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { issuedby, carsubinvoicing, syjprintqrcode } from '@/api/invoice.js'
|
||||||
|
import { useUser } from "@/store/user.js";
|
||||||
|
import { usePrint } from "@/store/print.js";
|
||||||
|
const printStore = usePrint();
|
||||||
|
const store = useUser();
|
||||||
|
|
||||||
|
const emits = defineEmits(['loadComplete', 'success'])
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const showEwmDialog = ref(false)
|
||||||
|
const canvasRef = ref(null)
|
||||||
|
const ewmInfo = ref({})
|
||||||
|
const printEwmLoading = ref(false)
|
||||||
|
|
||||||
|
const tableData = reactive({
|
||||||
|
list: []
|
||||||
|
})
|
||||||
|
const orderInfo = ref({})
|
||||||
|
|
||||||
|
// 打印二维码
|
||||||
|
async function printEwmHandle() {
|
||||||
|
try {
|
||||||
|
printEwmLoading.value = true
|
||||||
|
if (printStore.deviceNoteList.length) {
|
||||||
|
printStore.printInvoice({
|
||||||
|
url: ewmInfo.value.wechat_url
|
||||||
|
})
|
||||||
|
ElMessage.success('打印成功')
|
||||||
|
showEwmDialog.value = false
|
||||||
|
setTimeout(() => {
|
||||||
|
printEwmLoading.value = false
|
||||||
|
}, 1000)
|
||||||
|
} else {
|
||||||
|
const res = await syjprintqrcode({
|
||||||
|
id: ewmInfo.value.id
|
||||||
|
})
|
||||||
|
ElMessage.success('打印成功')
|
||||||
|
showEwmDialog.value = false
|
||||||
|
setTimeout(() => {
|
||||||
|
printEwmLoading.value = false
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
printEwmLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择开票
|
||||||
|
async function selectHandle(row) {
|
||||||
|
try {
|
||||||
|
row.loading = true
|
||||||
|
const res = await carsubinvoicing({
|
||||||
|
store_id: store.userInfo.loginName,
|
||||||
|
orderNo: orderInfo.value.id,
|
||||||
|
dlzh: row.id
|
||||||
|
})
|
||||||
|
console.log(res);
|
||||||
|
row.loading = false
|
||||||
|
ewmInfo.value = res
|
||||||
|
dialogVisible.value = false
|
||||||
|
showEwmDialog.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
QRCode.toCanvas(canvasRef.value, ewmInfo.value.wechat_url, function (error) {
|
||||||
|
if (error) console.error(error)
|
||||||
|
// console.log('success!');
|
||||||
|
})
|
||||||
|
}, 10)
|
||||||
|
} catch (error) {
|
||||||
|
row.loading = false
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取开票人列表
|
||||||
|
async function getTableData() {
|
||||||
|
try {
|
||||||
|
const res = await issuedby({
|
||||||
|
store_id: store.userInfo.loginName
|
||||||
|
})
|
||||||
|
emits('loadComplete', false)
|
||||||
|
dialogVisible.value = true
|
||||||
|
tableData.list = res.map(item => {
|
||||||
|
item.loading = false
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
emits('loadComplete', false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function show(order) {
|
||||||
|
console.log(order);
|
||||||
|
orderInfo.value = order
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.ewm {
|
||||||
|
width: 300px !important;
|
||||||
|
height: 300px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<el-text>台桌</el-text>
|
|
||||||
</template>
|
|
||||||