新增本地USB打印

This commit is contained in:
gyq 2024-07-29 18:10:01 +08:00
parent 4fb34a4235
commit b2e450fd52
8 changed files with 222 additions and 46 deletions

View File

@ -3,10 +3,10 @@ ENV = development
# 正式ws # 正式ws
VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client' # VITE_API_WSS = 'wss://cashier.sxczgkj.cn/client'
#测试ws #测试ws
# VITE_API_WSS = 'wss://wxcashiertest.sxczgkj.cn/client' VITE_API_WSS = 'wss://wxcashiertest.sxczgkj.cn/client'
# 阿伟本地ws # 阿伟本地ws
# VITE_API_WSS = 'ws://192.168.2.17:9998/client' # VITE_API_WSS = 'ws://192.168.2.17:9998/client'
@ -27,7 +27,7 @@ VITE_API_KP_URL = 'https://invoice.sxczgkj.cn/api'
# VITE_API_URL = 'http://192.168.1.106:10589/cashier-client' # VITE_API_URL = 'http://192.168.1.106:10589/cashier-client'
# 测试 # 测试
# VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client' VITE_API_URL = 'https://cashier-client.sxczgkj.cn/cashier-client'
# 正式 # 正式
VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client' # VITE_API_URL = 'https://cashierclient.sxczgkj.cn/cashier-client'

View File

@ -82,7 +82,7 @@ function checkOrTryHttp() {
try { try {
var WSK1 = new WebSocket(URL_WS1); var WSK1 = new WebSocket(URL_WS1);
WSK1.onopen = function (e) { WSK1.onopen = function (e) {
setTimeout("checkOrTryHttp()", 200); setTimeout(checkOrTryHttp(), 200);
} }
WSK1.onmessage = function (e) { WSK1.onmessage = function (e) {
if (!window.getCLodop) eval(e.data); if (!window.getCLodop) eval(e.data);
@ -90,7 +90,7 @@ function checkOrTryHttp() {
WSK1.onerror = function (e) { WSK1.onerror = function (e) {
var WSK2 = new WebSocket(URL_WS2); var WSK2 = new WebSocket(URL_WS2);
WSK2.onopen = function (e) { WSK2.onopen = function (e) {
setTimeout("checkOrTryHttp()", 200); setTimeout(checkOrTryHttp(), 200);
} }
WSK2.onmessage = function (e) { WSK2.onmessage = function (e) {
if (!window.getCLodop) eval(e.data); if (!window.getCLodop) eval(e.data);

View File

@ -20,7 +20,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { dayjs } from 'element-plus' import { dayjs } from 'element-plus'
import { ref, defineProps, defineExpose, defineEmits } from 'vue' import { ref } from 'vue'
import _lodash from 'lodash' import _lodash from 'lodash'
import getLodop from './LodopFuncs' import getLodop from './LodopFuncs'
const props = defineProps({ const props = defineProps({
@ -59,7 +59,11 @@ const Printing = () => {
<div style="width: 100%;font-size: 12px; margin-top:6px;">发票类型:${props.form.type}</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;">生成时间:${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: 12px; margin-top:6px;">*二维码有效期30天,超过自动失效</div>
<div style="width: 100%;font-size: 14px; margin-top: 15px;">您可以使用微信扫码开票</div>` <div style="width: 100%;font-size: 14px; margin-top: 15px;">您可以使用微信扫码开票</div>`,
'150px',
'5px',
'100%',
'100%',
) )
LODOP.SET_LICENSES('', 'DCFF409304DFCEB3E2C644BF96CD0720', '', '') LODOP.SET_LICENSES('', 'DCFF409304DFCEB3E2C644BF96CD0720', '', '')
LODOP.PRINT() LODOP.PRINT()

View File

@ -0,0 +1,83 @@
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 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="font-size: 16px;display: flex; justify-content:center;margin-top:6px;">
${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;border-bottom:1px dashed #000;"></div>
<table class="table">
<tr>
<td style="font-size: 12px;width:50%;">品名</td>
<td style="font-size: 12px;width:16.66%;">单价</td>
<td style="font-size: 12px;width:16.66%;">数量</td>
<td style="font-size: 12px;width:16.66%;">小计</td>
</tr>
`;
let table = "";
for (let item of data.carts) {
table += `
<tr>
<td style="font-size: 12px;width:50%;">
<div>${item.name}</div>
<div class="sku">规格${item.skuName || ""}</div>
</td>
<td style="font-size: 12px;width:16.66%;">${item.salePrice}</td>
<td style="font-size: 12px;width:16.66%;">${item.number}</td>
<td style="font-size: 12px;width:16.66%;">
${item.totalAmount}
</td>
</tr>
`;
}
let str = `
</table>
<div style="margin-top: 6px; border-bottom:1px dashed #000;"></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; border-bottom:1px dashed #000;"></div>
<div style="margin-top: 4px; font-size: 12px;">备注${data.remark}</div>
<div style="margin-top: 4px; padding-bottom: 50px;font-size: 12px;">
打印时间${data.printTime}
</div>
<div style="height: 50px;"></div>
`;
let lastHtml = `${html}${table}${str}`;
setTimeout(() => {
LODOP.ADD_PRINT_HTM("9mm", "0mm", "RightMargin:0mm", 20, lastHtml);
LODOP.SET_LICENSES("", "DCFF409304DFCEB3E2C644BF96CD0720", "", "");
LODOP.PRINT();
}, 800);
};

View File

@ -3,6 +3,7 @@ import { ipcRenderer } from "electron";
import { bySubType } from "@/api/device"; import { bySubType } from "@/api/device";
import { useUser } from "@/store/user.js"; import { useUser } from "@/store/user.js";
import dayjs from "dayjs"; import dayjs from "dayjs";
import receiptPrint from "@/components/lodop/receiptPrint.js";
export const usePrint = defineStore({ export const usePrint = defineStore({
id: "print", id: "print",
@ -12,6 +13,8 @@ export const usePrint = defineStore({
deviceLableList: [], // 添加的打印机 deviceLableList: [], // 添加的打印机
labelList: [], // 要打印的队列数据 labelList: [], // 要打印的队列数据
printTimer: null, printTimer: null,
receiptList: [], // 小票队列数据
receiptTimer: null,
}), }),
actions: { actions: {
// 获取本地打印机和已添加的可以用打印机列表 // 获取本地打印机和已添加的可以用打印机列表
@ -98,7 +101,7 @@ export const usePrint = defineStore({
// 执行打印操作 // 执行打印操作
this.startLabelPrint(); this.startLabelPrint();
} else { } else {
console.log("没有打印机"); console.log("没有标签打印机");
} }
}, },
// 开始打印标签数据 // 开始打印标签数据
@ -119,5 +122,43 @@ export const usePrint = defineStore({
} }
}, 800); }, 800);
}, },
// 添加小票打印对列表数据
pushReceiptData(props) {
if (
this.deviceNoteList.length &&
this.checkLocalPrint(this.deviceNoteList[0].config.deviceName)
) {
console.log(props);
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);
},
}, },
}); });

View File

@ -1,4 +1,5 @@
import _ from "lodash"; import _ from "lodash";
import { dayjs } from "element-plus";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { useUser } from "@/store/user.js"; import { useUser } from "@/store/user.js";
import { usePrint } from "@/store/print.js"; import { usePrint } from "@/store/print.js";
@ -96,6 +97,7 @@ export const useSocket = defineStore({
if (!this.orderList.some((el) => el == data.orderInfo.orderNo)) { if (!this.orderList.some((el) => el == data.orderInfo.orderNo)) {
// console.log("打印", data); // console.log("打印", data);
printStore.labelPrint(data); printStore.labelPrint(data);
printStore.pushReceiptData(data);
this.orderList.push(data.orderInfo.orderNo); this.orderList.push(data.orderInfo.orderNo);
if (this.orderList.length > 30) { if (this.orderList.length > 30) {
this.orderList.splice(0, 1); this.orderList.splice(0, 1);

View File

@ -1,5 +1,4 @@
<!-- 结算订单 --> <!-- 结算订单 -->
<template> <template>
<el-drawer size="100%" :with-header="false" direction="btt" v-model="dialogVisible"> <el-drawer size="100%" :with-header="false" direction="btt" v-model="dialogVisible">
<div class="drawer_wrap"> <div class="drawer_wrap">
@ -77,6 +76,8 @@ import { ElMessage } from "element-plus";
import dayjs from "dayjs"; import dayjs from "dayjs";
import useStorage from '@/utils/useStorage' import useStorage from '@/utils/useStorage'
import { ipcRenderer } from "electron"; import { ipcRenderer } from "electron";
import { formatDecimal } from '@/utils/index.js'
import receiptPrint from "@/components/lodop/receiptPrint.js";
import { usePrint } from '@/store/print.js' import { usePrint } from '@/store/print.js'
const printStore = usePrint() const printStore = usePrint()
@ -122,31 +123,30 @@ const printHandle = _.throttle(async function () {
try { try {
if (!isPrint.value) return; if (!isPrint.value) return;
const data = { const data = {
shop_name: store.userInfo.merchantName, shop_name: store.userInfo.shopName,
loginAccount: store.userInfo.loginAccount,
carts: props.cart, carts: props.cart,
amount: props.amount, amount: props.amount,
remark: props.remark, remark: props.remark,
orderInfo: props.orderInfo, orderInfo: props.orderInfo,
createdAt: dayjs(props.orderInfo.createdAt).format( createdAt: dayjs(props.orderInfo.createdAt).format("YYYY-MM-DD HH:mm:ss"),
"YYYY-MM-DD HH:mm:ss"
),
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
}; };
printStore.labelPrint(data) printStore.labelPrint(data)
printStore.pushReceiptData(data)
try { // try {
printLoading.value = true; // printLoading.value = true;
await print({ // await print({
type: "normal", // type: "normal",
ispre: true, // ispre: true,
orderId: props.orderInfo.id, // orderId: props.orderInfo.id,
}); // });
printLoading.value = false; // printLoading.value = false;
// ElMessage.success(""); // // ElMessage.success("");
} catch (error) { // } catch (error) {
printLoading.value = false; // printLoading.value = false;
console.log(error); // console.log(error);
} // }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
@ -166,13 +166,17 @@ async function printOrderLable() {
const printLabelOrder = res.list[0] const printLabelOrder = res.list[0]
const data = { const data = {
shop_name: store.userInfo.merchantName, shop_name: store.userInfo.shopName,
loginAccount: store.userInfo.loginAccount,
carts: [], carts: [],
amount: printLabelOrder.orderAmount,
remark: printLabelOrder.remark,
orderInfo: printLabelOrder, orderInfo: printLabelOrder,
outNumber: printLabelOrder.outNumber, outNumber: printLabelOrder.outNumber,
createdAt: dayjs(printLabelOrder.createdAt).format( createdAt: dayjs(printLabelOrder.createdAt).format(
"YYYY-MM-DD HH:mm:ss" "YYYY-MM-DD HH:mm:ss"
) ),
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
} }
printLabelOrder.skuInfos.map(item => { printLabelOrder.skuInfos.map(item => {
data.carts.push( data.carts.push(
@ -180,13 +184,16 @@ async function printOrderLable() {
categoryId: item.categoryId, categoryId: item.categoryId,
name: item.productName, name: item.productName,
number: item.num, number: item.num,
skuName: item.productSkuName skuName: item.productSkuName,
salePrice: formatDecimal(item.priceAmount / item.num),
totalAmount: formatDecimal(item.priceAmount)
} }
) )
}) })
//
// console.log('', data);
printStore.labelPrint(data) printStore.labelPrint(data)
//
printStore.pushReceiptData(data)
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }

View File

@ -142,8 +142,8 @@
(orderDetaildata.status == 'refund' || (orderDetaildata.status == 'refund' ||
orderDetaildata.status == 'closed') orderDetaildata.status == 'closed')
">开发票</el-button> ">开发票</el-button>
<el-button @click="print('normal')" style="flex: 1">重打小票</el-button> <el-button :loading="normalPrintLoading" @click="print('normal')" style="flex: 1">重打小票</el-button>
<el-button @click="print('label')" style="flex: 1">重打标签</el-button> <el-button :loading="labelPrintLoading" @click="print('label')" style="flex: 1">重打标签</el-button>
</div> </div>
</div> </div>
</div> </div>
@ -300,7 +300,7 @@ import {
} from "@/api/order/index.js"; } from "@/api/order/index.js";
import add from "@/views/order/components/add.vue"; import add from "@/views/order/components/add.vue";
import cashTable from "@/views/order/components/cashTable.vue"; import cashTable from "@/views/order/components/cashTable.vue";
import { clearNoNum } from "@/utils"; import { clearNoNum, formatDecimal } from "@/utils";
import md5 from "js-md5"; import md5 from "js-md5";
import dateRange from './components/dateRange.vue' import dateRange from './components/dateRange.vue'
import { useGlobal } from "@/store/global.js"; import { useGlobal } from "@/store/global.js";
@ -311,6 +311,9 @@ const invoiceLoading = ref(false)
const invoiceRef = ref(null) const invoiceRef = ref(null)
const takeFoodCodeRef = ref(null); const takeFoodCodeRef = ref(null);
const labelPrintLoading = ref(false)
const normalPrintLoading = ref(false)
const global = useGlobal(); const global = useGlobal();
const store = useUser(); const store = useUser();
@ -417,8 +420,10 @@ const print = lodash.throttle(
try { try {
if (e == "label") { if (e == "label") {
// checkLabelPrint(printLabelOrder.value) // checkLabelPrint(printLabelOrder.value)
labelPrintLoading.value = true
const data = { const data = {
shop_name: store.userInfo.merchantName, shop_name: store.userInfo.shopName,
loginAccount: store.userInfo.loginAccount,
carts: [], carts: [],
orderInfo: printLabelOrder.value, orderInfo: printLabelOrder.value,
outNumber: printLabelOrder.value.outNumber, outNumber: printLabelOrder.value.outNumber,
@ -437,16 +442,50 @@ const print = lodash.throttle(
// console.log('', data); // console.log('', data);
printStore.labelPrint(data); printStore.labelPrint(data);
setTimeout(() => {
labelPrintLoading.value = false
}, 1000)
} else { } else {
await cloudPrinterprint({ normalPrintLoading.value = true
type: e, const data = {
orderId: orderDetaildata.value.id, shop_name: store.userInfo.shopName,
ispre: false, loginAccount: store.userInfo.loginAccount,
}); carts: [],
ElMessage({ amount: printLabelOrder.value.orderAmount,
message: "成功打票", remark: printLabelOrder.value.remark,
type: "success", orderInfo: printLabelOrder.value,
}); outNumber: printLabelOrder.value.outNumber,
createdAt: dayjs(printLabelOrder.value.createdAt).format(
"YYYY-MM-DD HH:mm:ss"
),
printTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
}
printLabelOrder.value.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.pushReceiptData(data);
setTimeout(() => {
normalPrintLoading.value = false
}, 1000)
// //
// await cloudPrinterprint({
// type: e,
// orderId: orderDetaildata.value.id,
// ispre: false,
// });
// ElMessage({
// message: "",
// type: "success",
// });
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);