1.新增全部本地打印标签

2.优化订单重但标签小票
This commit is contained in:
gyq 2024-06-21 13:56:16 +08:00
parent c86fff9691
commit 0b2b4b44d0
17 changed files with 2356 additions and 342 deletions

View File

@ -1,8 +1,15 @@
# 本地环境
ENV = development
# 正式ws
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
#测试ws
# VITE_API_WSS = 'wss://wxcashiertest.sxczgkj.cn/client'
# 测试
VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client'
# VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client'
# 阿伟
# VITE_API_URL = 'http://192.168.2.96:10587/cashier-client'
@ -11,4 +18,4 @@ VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client'
# VITE_API_URL = 'http://192.168.2.41:10587/cashier-client'
# 正式
# VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'
VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'

View File

@ -1,6 +1,9 @@
# 线上环境
ENV = production
# 正式ws
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
# 线上环境接口地址
VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client/'

View File

@ -1,172 +1 @@
"use strict";
const path = require("path");
const electron = require("electron");
let win;
electron.app.whenReady().then(() => {
win = new electron.BrowserWindow({
title: "银收客",
width: 1024,
height: 768,
fullscreenable: true,
fullscreen: process.env.VITE_DEV_SERVER_URL ? false : true,
simpleFullscreen: true,
frame: process.env.VITE_DEV_SERVER_URL ? true : false,
webPreferences: {
// 集成网页和 Node.js也就是在渲染进程中可以调用 Node.js 方法
nodeIntegration: true,
contextIsolation: false
}
});
if (process.env.VITE_DEV_SERVER_URL) {
win.loadURL(process.env.VITE_DEV_SERVER_URL);
} else {
win.loadFile(path.resolve(__dirname, "../dist/index.html"));
}
electron.app.on("activate", () => {
if (electron.BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
electron.ipcMain.on("quitHandler", (_, msg) => {
electron.app.quit();
});
electron.ipcMain.on("getPrintList", () => {
win.webContents.getPrintersAsync().then((res) => {
win.webContents.send("printList", res);
});
});
const printWin = new electron.BrowserWindow({
show: false,
width: 464,
height: 1726,
webPreferences: {
// 集成网页和 Node.js也就是在渲染进程中可以调用 Node.js 方法
nodeIntegration: true,
contextIsolation: false
}
});
if (process.env.VITE_DEV_SERVER_URL) {
printWin.loadFile(path.join(__dirname, "../public/print.html"));
} else {
printWin.loadFile(path.resolve(__dirname, "../dist/print.html"));
}
electron.ipcMain.on("printerInfoSync", (event, arg) => {
printWin.webContents.send("getParams", arg);
});
electron.ipcMain.on("printStart", (event, arg) => {
console.log(arg);
const _parmas = JSON.parse(arg);
let name = _parmas.deviceName;
printWin.webContents.print({
silent: true,
deviceName: name,
pageSize: {
width: 58e3,
height: 216e3
},
scaleFactor: 80,
landscape: false,
margins: {
marginType: "none",
top: 0,
bottom: 0,
left: 0,
right: 0
},
dpi: {
horizontal: 203,
vertical: 203
}
});
});
const workPrintWin = new electron.BrowserWindow({
show: false,
width: 464,
height: 1726,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
if (process.env.VITE_DEV_SERVER_URL) {
workPrintWin.loadFile(path.join(__dirname, "../public/work_print.html"));
} else {
workPrintWin.loadFile(path.resolve(__dirname, "../dist/work_print.html"));
}
electron.ipcMain.on("printerWorkSync", (event, arg) => {
workPrintWin.webContents.send("getParams", arg);
});
electron.ipcMain.on("printWorkStart", (event, arg) => {
console.log(arg);
const _parmas = JSON.parse(arg);
let name = _parmas.deviceName;
workPrintWin.webContents.print({
silent: true,
deviceName: name,
pageSize: {
width: 58e3,
height: 216e3
},
scaleFactor: 80,
landscape: false,
margins: {
marginType: "none",
top: 0,
bottom: 0,
left: 0,
right: 0
},
dpi: {
horizontal: 203,
vertical: 203
}
});
});
const tagPrintWin = new electron.BrowserWindow({
show: true,
width: 320,
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) => {
tagPrintWin.webContents.send("getParams", arg);
});
electron.ipcMain.on("printTagStart", (event, arg) => {
console.log(arg);
const _parmas = JSON.parse(arg);
let name = _parmas.deviceName;
tagPrintWin.webContents.print({
silent: true,
deviceName: name,
pageSize: {
width: 4e4,
height: 3e4
},
scaleFactor: 80,
landscape: false,
margins: {
marginType: "none",
top: 0,
bottom: 0,
left: 0,
right: 0
},
dpi: {
horizontal: 203,
vertical: 203
}
});
});
});
electron.app.on("window-all-closed", () => {
if (process.platform !== "darwin")
electron.app.quit();
});
"use strict";const i=require("path"),e=require("electron");let a;e.app.whenReady().then(()=>{a=new e.BrowserWindow({title:"银收客",width:1024,height:768,fullscreenable:!0,fullscreen:!process.env.VITE_DEV_SERVER_URL,simpleFullscreen:!0,frame:!!process.env.VITE_DEV_SERVER_URL,webPreferences:{nodeIntegration:!0,contextIsolation:!1}}),process.env.VITE_DEV_SERVER_URL?a.loadURL(process.env.VITE_DEV_SERVER_URL):a.loadFile(i.resolve(__dirname,"../dist/index.html")),e.app.on("activate",()=>{e.BrowserWindow.getAllWindows().length===0&&createWindow()}),e.ipcMain.on("quitHandler",(t,n)=>{e.app.quit()}),e.ipcMain.on("getPrintList",()=>{a.webContents.getPrintersAsync().then(t=>{a.webContents.send("printList",t)})});const o=new e.BrowserWindow({show:!1,width:464,height:1726,webPreferences:{nodeIntegration:!0,contextIsolation:!1}});process.env.VITE_DEV_SERVER_URL?o.loadFile(i.join(__dirname,"../public/print.html")):o.loadFile(i.resolve(__dirname,"../dist/print.html")),e.ipcMain.on("printerInfoSync",(t,n)=>{o.webContents.send("getParams",n)}),e.ipcMain.on("printStart",(t,n)=>{console.log(n);let r=JSON.parse(n).deviceName;o.webContents.print({silent:!0,deviceName:r,pageSize:{width:58e3,height:216e3},scaleFactor:80,landscape:!1,margins:{marginType:"none",top:0,bottom:0,left:0,right:0},dpi:{horizontal:203,vertical:203}})});const s=new e.BrowserWindow({show:!1,width:464,height:1726,webPreferences:{nodeIntegration:!0,contextIsolation:!1}});process.env.VITE_DEV_SERVER_URL?s.loadFile(i.join(__dirname,"../public/work_print.html")):s.loadFile(i.resolve(__dirname,"../dist/work_print.html")),e.ipcMain.on("printerWorkSync",(t,n)=>{s.webContents.send("getParams",n)}),e.ipcMain.on("printWorkStart",(t,n)=>{let r=JSON.parse(n).deviceName;s.webContents.print({silent:!0,deviceName:r,pageSize:{width:58e3,height:216e3},scaleFactor:80,landscape:!1,margins:{marginType:"none",top:0,bottom:0,left:0,right:0},dpi:{horizontal:203,vertical:203}})});const l=new e.BrowserWindow({show:!1,width:320,height:240,webPreferences:{nodeIntegration:!0,contextIsolation:!1}});process.env.VITE_DEV_SERVER_URL?l.loadFile(i.join(__dirname,"../public/tag_print.html")):l.loadFile(i.resolve(__dirname,"../dist/tag_print.html")),e.ipcMain.on("printerTagSync",(t,n)=>{console.log(n),l.webContents.send("getParams",n)}),e.ipcMain.on("printTagStart",(t,n)=>{let r=JSON.parse(n).deviceName;l.webContents.print({silent:!0,deviceName:r,pageSize:{width:4e4,height:3e4},scaleFactor:80,landscape:!1,margins:{marginType:"none",top:0,bottom:0,left:0,right:0},dpi:{horizontal:203,vertical:203}})})});e.app.on("window-all-closed",()=>{process.platform!=="darwin"&&e.app.quit()});

View File

@ -135,7 +135,7 @@ app.whenReady().then(() => {
// 执行交班小票的打印操作
ipcMain.on("printWorkStart", (event, arg) => {
console.log(arg);
// console.log(arg);
const _parmas = JSON.parse(arg);
// console.log(_parmas)
let name = _parmas.deviceName;
@ -164,7 +164,7 @@ app.whenReady().then(() => {
// 标签小票的窗口
const tagPrintWin = new BrowserWindow({
show: true,
show: false,
width: 320,
height: 240,
webPreferences: {
@ -182,12 +182,13 @@ app.whenReady().then(() => {
// 接收渲染进程发送的数据
ipcMain.on("printerTagSync", (event, arg) => {
console.log(arg);
tagPrintWin.webContents.send("getParams", arg);
});
// 执行标签小票的打印操作
ipcMain.on("printTagStart", (event, arg) => {
console.log(arg);
// console.log(arg);
const _parmas = JSON.parse(arg);
// console.log(_parmas)
let name = _parmas.deviceName;

View File

@ -1,7 +1,7 @@
{
"name": "vite-electron",
"private": true,
"version": "1.2.21",
"version": "1.3.5",
"main": "dist-electron/main.js",
"scripts": {
"dev": "chcp 65001 && vite",
@ -18,8 +18,10 @@
"element-plus": "^2.4.3",
"lodash": "^4.17.21",
"pinia": "^2.1.7",
"qrcode": "^1.5.3",
"serialport": "^12.0.0",
"swiper": "^11.1.1",
"uuid": "^10.0.0",
"vue": "^3.3.8",
"vue-router": "^4.2.5"
},

1540
public/qrcode.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -15,11 +15,9 @@ body {
position: relative;
}
.print_view .ewm {
width: 50px;
height: 50px;
position: absolute;
top: 0;
right: 0;
right: 4px;
z-index: 99;
}
.print_view .header {

View File

@ -12,29 +12,27 @@
<body>
<div id="app">
<div class="print_view">
<img
class="ewm"
src="data:image/png;base64,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"
alt=""
/>
<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">196</div>
<div class="info">座位号:B4</div>
<div class="num">{{data.outNumber}}</div>
<div class="info">座位号{{data.masterId}}</div>
</div>
<div class="shop_info">
<div class="name">[冰]美式抹茶拿铁焦糖</div>
<div class="text">半塘 去冰 去咖啡液</div>
<div class="name">{{data.name}}</div>
<div class="text">{{data.skuName}}</div>
</div>
<div class="time">2024-06-14 16:22:44</div>
<div class="tips">建议尽快享用,风味更佳</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,
@ -50,12 +48,25 @@
data.value = JSON.parse(arg);
console.log(data.value);
let size = 40;
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 })
);
}, 500);
}, 100);
});
});

View File

@ -11,12 +11,9 @@ body {
.print_view {
position: relative;
.ewm {
$size: 50px;
width: $size;
height: $size;
position: absolute;
top: 0;
right: 0;
right: 4px;
z-index: 99;
}
.header {

View File

@ -22,15 +22,28 @@
</template>
<script setup>
import { ref, reactive, watch } from "vue";
import { v4 as uuidv4 } from 'uuid'
import { ref, reactive, watch, onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import leftMenu from "@/components/leftMenu.vue";
import useStorage from '@/utils/useStorage'
import { useUser } from "@/store/user.js";
import { bySubType } from "@/api/device";
import { dayjs, ElMessage } from "element-plus";
import { ipcRenderer } from 'electron'
if (!useStorage.get('uuid')) {
useStorage.set('uuid', uuidv4())
}
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);
}
@ -40,8 +53,27 @@ watch(route, (to) => {
} else {
hideLeftMenu.value = false;
}
if (to.fullPath == '/login') {
if (ws.value != null) {
console.log('关闭ws');
ws.value.close()
wsIsClose.value = true
}
} else {
// ws
console.log('打开ws');
openWs()
}
});
// ws
function openWs() {
if (store.userInfo && store.userInfo.shopId && ws.value == null) {
bySubTypeAjax();
initWebSocket()
}
}
let transitionName = ref();
let router = useRouter();
router.beforeEach((to, from) => {
@ -56,6 +88,229 @@ router.beforeEach((to, from) => {
transitionName.value = "";
}
});
//
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 = import.meta.env.VITE_API_WSS) {
wsIsClose.value = false
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 >= 100) {
// console.log('5');
// clearInterval(reConnectTimer.value)
// reConnectTimer.value = null
// reConnectCount.value = 0
// wsIsClose.value = true
// ws.value.close()
// } else {
// }
reConnectCount.value++
initWebSocket(wsUrl)
}, 5000)
}
onMounted(() => {
getPrintList();
})
</script>
<style lang="scss">
@ -87,28 +342,20 @@ router.beforeEach((to, from) => {
--b-darker: calc(var(--b) * 0.8);
--primary-color: rgb(var(--r), var(--g), var(--b));
--primary-color-hover: rgb(
var(--r-lighter3),
--primary-color-hover: rgb(var(--r-lighter3),
var(--g-lighter3),
var(--b-lighter3)
);
var(--b-lighter3));
--el-color-primary: var(--primary-color) !important;
--el-button-hover-bg-color: var(--primary-color) !important;
--el-color-primary-light-3: rgb(
var(--r-lighter),
--el-color-primary-light-3: rgb(var(--r-lighter),
var(--g-lighter),
var(--b-lighter)
) !important;
--el-color-primary-dark-2: rgb(
var(--r-darker),
var(--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(--b-darker)) !important;
--el-color-primary-light-5: rgb(var(--r-lighter2),
var(--g-lighter2),
var(--b-lighter2)
) !important;
var(--b-lighter2)) !important;
--el-font-size-base: 16px !important;
--el-message-close-size: var(--el-font-size-base) !important;
@ -163,8 +410,7 @@ html {
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;
border-radius: var(--el-dialog-border-radius) var(--el-dialog-border-radius) 0 0;
}
.el-dialog__title {
@ -185,8 +431,7 @@ html {
}
.el-dialog__body {
padding: calc(var(--el-dialog-padding-primary) + 10px)
var(--el-dialog-padding-primary);
padding: calc(var(--el-dialog-padding-primary) + 10px) var(--el-dialog-padding-primary);
}
.el-dialog__header {
@ -274,7 +519,7 @@ html {
display: flex;
width: 200%;
& > div {
&>div {
width: 50%;
}

View File

@ -5,11 +5,11 @@ import request from "@/utils/request.js";
* @param {*} data
* @returns
*/
export function tbPrintMachinePost(data, method = 'post') {
export function tbPrintMachinePost(data, method = "post") {
return request({
method: method,
url: "tbPrintMachine",
data
data,
});
}
@ -22,7 +22,7 @@ export function tbPrintMachineGet(params) {
return request({
method: "get",
url: "/tbPrintMachine",
params
params,
});
}
@ -34,7 +34,7 @@ export function tbPrintMachineGet(params) {
export function tbPrintMachineDetail(id) {
return request({
method: "get",
url: `/tbPrintMachine/${id}`
url: `/tbPrintMachine/${id}`,
});
}
@ -45,9 +45,9 @@ export function tbPrintMachineDetail(id) {
*/
export function tbPrintMachineDelete(params) {
return request({
method: 'DELETE',
method: "DELETE",
url: "tbPrintMachine",
params
params,
});
}
@ -60,7 +60,7 @@ export function bySubType(params) {
return request({
method: "get",
url: "/tbPrintMachine/bySubType",
params
params,
});
}
@ -70,8 +70,8 @@ export function bySubType(params) {
*/
export function tbShopCategoryGet(params) {
return request({
url: `/tbShopCategory`,
method: 'get',
params
})
url: `/product/queryAllCategory`,
method: "get",
params,
});
}

View File

@ -23,13 +23,14 @@
<div class="item" v-for="item in tableData.list" :key="item.id">
<div class="top">
<div class="left">
{{ item.outCode }} - {{ item.productName }}
<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">
@ -54,6 +55,7 @@
<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'
@ -85,8 +87,15 @@ const tableData = reactive({
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);
@ -120,6 +129,7 @@ function handleCurrentChange() {
//
async function getsendMessageAjax() {
try {
if (!store.userInfo.shopId) return
tableData.loading = true
const res = await getsendMessage({
page: tableData.page,
@ -132,6 +142,7 @@ async function getsendMessageAjax() {
tableData.total = res.total
} catch (error) {
console.log(error);
tableData.loading = false
}
}
@ -145,7 +156,10 @@ const confirmHandle = _.throttle(async function () {
shopId: store.userInfo.shopId,
// shopId: 4
})
ElMessage.success('叫号成功')
loading.value = false
number.value = ''
getsendMessageAjax()
setTimeout(() => {
inputRef.value.focus();
@ -163,10 +177,6 @@ const confirmHandle = _.throttle(async function () {
defineExpose({
show
})
onMounted(() => {
getsendMessageAjax()
})
</script>
<style scoped lang="scss">
@ -218,15 +228,42 @@ onMounted(() => {
.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);
}
}
}
}
@ -236,7 +273,8 @@ onMounted(() => {
justify-content: space-between;
padding-top: 4px;
.time {
.time,
.info {
color: #999;
}
}

View File

@ -4,18 +4,9 @@
<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
>
<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>
@ -82,15 +73,16 @@ async function tbShopCategoryGetAjax() {
shopId: store.userInfo.shopId,
sort: "sort,desc",
page: 0,
size: 500,
pageSize: 200,
});
res.map((item) => {
console.log(res);
res.list.map((item) => {
item.active = false;
item.childrenList.map((item) => {
item.active = false;
});
});
categorys.value = res;
categorys.value = res.list;
setTimeout(() => {
loading.value = false;

View File

@ -1,10 +1,7 @@
<template>
<div class="device_container">
<div class="header" @click="router.back()">
<el-icon
style="position: relative; top: 2px; margin-right: 4px"
size="22"
>
<el-icon style="position: relative; top: 2px; margin-right: 4px" size="22">
<ArrowLeft />
</el-icon>
<el-text>{{ form.id ? "编辑便签打印机" : "添加便签打印机" }}</el-text>
@ -26,28 +23,15 @@
</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-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-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-option :label="item" :value="item" v-for="item in 4" :key="item"></el-option>
</el-select>
</el-form-item>
<el-form-item label="商品模式">
@ -58,16 +42,10 @@
</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"
>
<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 style="color: #e65d6e" v-if="!form.config.categoryList.length">
请选择分类
</span>
</div>
@ -115,12 +93,7 @@
</el-button>
</div>
<div class="btn">
<el-button
type="primary"
style="width: 100%"
:loading="loading"
@click="submitHandle"
>
<el-button type="primary" style="width: 100%" :loading="loading" @click="submitHandle">
保存
</el-button>
</div>
@ -129,17 +102,14 @@
</div>
</div>
</div>
<classify
ref="classifyRef"
@success="(e) => (form.config.categoryList = e)"
/>
<classify ref="classifyRef" @success="(e) => (form.config.categoryList = e)" />
</template>
<script setup>
import { ipcRenderer } from "electron";
import { onMounted, ref } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ElMessage } from "element-plus";
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";
@ -190,8 +160,15 @@ function printHandle() {
return;
}
ipcRenderer.send(
"printStart",
JSON.stringify({ deviceName: form.value.config.deviceName })
"printerTagSync",
JSON.stringify({
deviceName: form.value.config.deviceName,
outNumber: '123',
name: '甜橙马黛茶',
skuName: '加奶、加珍珠',
masterId: '#A9',
createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss')
})
);
}
@ -268,9 +245,11 @@ onMounted(() => {
.print_view {
padding: 20px 0;
.blod {
font-weight: 600;
}
.title {
display: flex;
justify-content: center;

View File

@ -1,11 +1,241 @@
<template>
<!-- <el-button @click="chooseSerial">获取串口列表</el-button> -->
<el-button @click="printTag">打印标签</el-button>
<el-button @click="initWebSocket()">连接ws</el-button>
</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 } from 'vue';
import { onMounted, ref } from 'vue';
import { useUser } from "@/store/user.js";
import useStorage from '@/utils/useStorage'
const store = useUser();
//
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 = () => {
@ -25,12 +255,17 @@ const chooseSerial = async () => {
// localStorage.setItem('printNum', printNum)
// }
// ipcRenderer.send('printStart', printNum)
ipcRenderer.send('getSerialPort')
// ipcRenderer.send('getSerialPort')
};
onMounted(() => {
ipcRenderer.on('seriaportList', (e, a) => {
console.log('seriaportList', a);
})
getPrintList();
bySubTypeAjax();
initWebSocket()
})
</script>

View File

@ -247,6 +247,120 @@ import { clearNoNum } from '@/utils'
const store = useUser()
const itemboxshow = ref(false)
import { ipcRenderer } from 'electron'
import { bySubType } from "@/api/device";
//
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 checkLabelPrint(props) {
// console.log(props);
// console.log(printLabelList.value);
if (!checkLocalPrint(printLabelList.value[0].config.deviceName)) {
ElMessage.error("本地打印机无法使用,请检查打印机是否正确连接");
} else {
let pids = printLabelList.value[0].config.categoryList.map(item => item.id)
let labelList = []
props.skuInfos.map(item => {
if (pids.some(el => el == item.categoryId)) {
for (let i = 0; i < item.num; i++) {
labelList.push(
{
outNumber: props.outNumber,
name: item.productName,
skuName: item.productSkuName,
masterId: props.tableName,
deviceName: printLabelList.value[0].config.deviceName,
createdAt: dayjs(props.createAt).format('YYYY-MM-DD HH:mm:ss')
}
)
}
}
})
if (labelList.length) printLabel(labelList)
}
}
//
let labelCount = ref(0)
let labelPrintTimer = ref(null)
const printLabel = lodash.throttle(function (list) {
// console.log('printLabel===', list);
if (!checkLocalPrint(printLabelList.value[0].config.deviceName)) {
ElMessage.error("本地打印机无法使用,请检查打印机是否正确连接");
} else {
clearInterval(labelPrintTimer.value)
labelPrintTimer.value = null
labelCount.value = 0
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++
console.log(labelCount.value);
if (labelCount.value > list.length - 1) {
clearInterval(labelPrintTimer.value)
labelPrintTimer.value = null
labelCount.value = 0
}
}, 1000)
}
}, 1500, { leading: true, trailing: false })
const handleClick = (Name) => {//teb
ordereData.status = Name.props.name
asyncorderfindOrder()
@ -303,6 +417,9 @@ const payreturnOrderclick = lodash.debounce(async () => { //搜索手机号
const print = async (e) => {
try {
if (e == 'label' && printLabelList.value.length) {
checkLabelPrint(printLabelOrder.value)
} else {
await cloudPrinterprint({
type: e,
orderId: orderDetaildata.value.id,
@ -312,14 +429,20 @@ const print = async (e) => {
message: '成功打票',
type: 'success',
})
}
} catch (error) {
console.log(error);
}
}
const loadingboxshow = ref(false);
//
const printLabelOrder = ref('')
const emititemboxshow = async (e) => { //
// console.log('emititemboxshow', e);
printLabelOrder.value = e
loadingboxshow.value = true
try {
let res = await orderorderDetail({
@ -453,6 +576,9 @@ const callNumberHandle = async () => {
onMounted(() => {
// resetMembrform.value = { ...membrform.value }
asyncorderfindOrder()
getPrintList();
bySubTypeAjax();
})
</script>

View File

@ -187,7 +187,18 @@ const exit = async () => {
try {
if (printList.value.length) {
if (!checkLocalPrint(printList.value[0].config.deviceName)) {
ElMessage.error("本地打印机无法使用,请检查打印机是否正确连接");
loading.value = true;
let res = await loginlogout({
status: 1
})
useStorage.clear()
ElMessage.success("交班成功");
setTimeout(() => {
router.replace({
name: "login",
});
}, 1000);
loading.value = false;
} else {
//
const data = await handoverData({