1.需求:
- 商戶端后臺(tái)實(shí)時(shí)獲取后臺(tái)支付訂單狀態(tài),支付完成后根據(jù)單據(jù)內(nèi)容分配對應(yīng)打印機(jī)并自動(dòng)打印小票
2.設(shè)備/技術(shù)支持:
- GP-C80180I佳博打印機(jī)(網(wǎng)口打印機(jī))
- 電腦(windows)
- c-lodop
- websocket
3.實(shí)現(xiàn)步驟
實(shí)現(xiàn)原理:通過websocket與后臺(tái)建立實(shí)時(shí)連接,獲取打印消息,獲取到消息后自動(dòng)調(diào)用打印方法;打印時(shí)通過c-lodop插件獲取本地電腦打印機(jī),并與接口返回的打印機(jī)進(jìn)行匹配,根據(jù)獲取到的打印機(jī)索引值開啟對應(yīng)的打印機(jī)
- 打印機(jī)配置:
- 打印機(jī)連接路由器,配置ip地址
- 下載安裝驅(qū)動(dòng)(找到對應(yīng)型號)
- 安裝成功后,打印機(jī)列表會(huì)顯示出打印機(jī)名稱
- 在電腦上找到對應(yīng)的打印,配置(打印機(jī)屬性->端口->添加端口(端口號為打印機(jī)ip地址))
- 配置完成后,可以手動(dòng)執(zhí)行cmd命令連接打印機(jī)(默認(rèn)是未連接的)
//telnet + 空格 + ip + 空格 + 端口號
telnet 192.168.5.6 9100 (打印機(jī)端口號,注意格式)
- 連接成功跳后,會(huì)打開全黑的cmd窗口,隨便輸入字符,回車,打印機(jī)會(huì)自動(dòng)打印輸入的內(nèi)容
- 插件配置
- 下載C-Lodop
- 安裝
-
設(shè)置->端口設(shè)置(端口1自定義設(shè)置(非必要):8099,注意這里如果修改了要跟下邊代碼里配置的保持一致)
image.png
image.png
image.png
3.具體代碼實(shí)現(xiàn)
- 在項(xiàng)目代碼里,引入官方下載包里的LodopFuncs.js文件(要想在vue里使用需要做出一定修改)
1. 端口配置,需要跟上邊服務(wù)端口等保持一致,否則無法正常連接
//用雙端口加載主JS文件Lodop.js(或CLodopfuncs.js兼容老版本)以防其中某端口被占:
var MainJS = "CLodopfuncs.js",
URL_WS1 = "ws://localhost:8099/" + MainJS, //ws用8000/18000
URL_WS2 = "ws://localhost:18000/" + MainJS,
URL_HTTP1 = "http://localhost:8099/" + MainJS, //http用8000/18000
URL_HTTP2 = "http://localhost:18000/" + MainJS,
URL_HTTP3 = "https://localhost.lodop.net:8443/" + MainJS; //https用8000/8443
2. 文件底部增加導(dǎo)出代碼,否者在對應(yīng)vue文件導(dǎo)入時(shí)無法正常調(diào)用
export { getLodop,needCLodop };
- xx.vue(部分代碼)
import { getLodop, needCLodop } from '@/utils/initPrint.js'
export default {
methods: {
onMessage(e) {
console.log('接收到消息!', e.data)
let data = JSON.parse(e.data)
// 自定義打印內(nèi)容
let str = `
<div>
<h3 style="text-align: center;font-weight:400;">${data.enterpriseName}</h3>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">訂單類型:${this.formatOrderType(
data.orderType
)}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">交易類型:${this.formatTradeType(
data.tradeType
)}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">支付方式:${this.format(
data.payType
)}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">打印類型:${
data.printType == 1 ? '自動(dòng)打印' : '手動(dòng)打印'
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">支付時(shí)間:${
data.createTime
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">訂 單 號:${
data.orderNo || '-'
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">流 水 號:${data.flowNo}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">員 工 ID:${
data.createId
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">員工姓名:${
data.createName
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">結(jié)算金額:${
data.payAmount
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">幣 種:元</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">設(shè) 備 號:${data.printNo}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">設(shè)備名稱:${
data.printName
}</div>
<div style="border-bottom: 1px dashed #000;height:1px;width:100%;margin-top:4px"></div>
<div style="font-size:12px;margin-bottom:10px;margin-top:5px;">打印時(shí)間:${this.$date.formatDate(
new Date(),
'yyyy-MM-dd hh:mm:ss'
)}</div>
</div>
`
this.getPrinterList(str, data)
},
// 獲取本地打印
getPrinterList(str, data) {
if (needCLodop()) { // 這里時(shí)為了判斷插件是否初始化完成,不加這個(gè)判斷,直接調(diào)用getLodop()方法,會(huì)提示“網(wǎng)頁還沒下載完畢,請稍等一下再操作.”
let LODOP = getLodop()
this.printNameList = []
let counter = LODOP.GET_PRINTER_COUNT() // 獲取打印機(jī)個(gè)數(shù)
let index = -1
for (let i = 0; i < counter; i++) {
//將打印機(jī)存入printList數(shù)組中
this.printNameList.push({
index: i,
name: LODOP.GET_PRINTER_NAME(i),
})
if (LODOP.GET_PRINTER_NAME(i) === data.printNo) { // 匹配對應(yīng)的打印機(jī)
index = i
}
}
if (index >= 0 && LODOP.SET_PRINTER_INDEXA(index)) { // 此處是根據(jù)對應(yīng)打印機(jī)的索引值,找到并開啟打印
LODOP.SET_PRINT_PAGESIZE(3, 800, 80, '小票')
LODOP.ADD_PRINT_HTM(10, 10, '100%', 80, str)
// LODOP.PREVIEW() //預(yù)覽打印
LODOP.PRINT() //直接打印
} else {
this.$notification.error({
key: 'api-error',
message: '此電腦未配置' + data.printNo + '打印機(jī),請配置打印機(jī)后,重新登錄本系統(tǒng)。',
description: '',
})
}
window.On_CLodop_Opened = null
}
},
}
}
- 完整代碼
<script>
import { getLodop, needCLodop } from '@/utils/initPrint.js'
export default {
computed: {
...mapState({
printState: (state) => state.user.printState,
}),
},
watch: {
// 監(jiān)聽打印開啟狀態(tài)
printState: {
handler(val) {
// 頁面刷新后printState會(huì)被初始化,所以再獲取下瀏覽器存儲(chǔ)的狀態(tài)
let flag = sessionStorage.getItem('printState')
// 如果頁面刷新了,刷新前開啟了打印,這自動(dòng)與后臺(tái)建立連接
if (flag == 'true' && !val) {
this.$store.commit('START_PRINT', true)
} else {
if (val) {
this.initWebsocket(this.$store.getters.userInfo.id)
} else {
this.closeSocket()
}
}
},
immediate: true,
deep: true,
},
},
methods: {
initWebsocket(id) {
let that = this
this.$ws = new WebSocket('ws://xxxxxxxxx/websocket/link?id=' + id)
this.$ws.onopen = function (evt) {
that.onOpen(evt)
}
this.$ws.onclose = function (evt) {
that.onClose(evt)
}
this.$ws.onmessage = function (evt) {
that.onMessage(evt)
}
this.$ws.onerror = function (evt) {
that.onError(evt)
}
},
onMessage(e) { // 接收到消息后自動(dòng)打印
console.log('接收到消息!', e.data)
let data = JSON.parse(e.data)
let str = `
<div>
<h3 style="text-align: center;font-weight:400;">${data.enterpriseName}</h3>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">訂單類型:${this.formatOrderType(
data.orderType
)}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">交易類型:${this.formatTradeType(
data.tradeType
)}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">支付方式:${this.format(
data.payType
)}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">打印類型:${
data.printType == 1 ? '自動(dòng)打印' : '手動(dòng)打印'
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">支付時(shí)間:${
data.createTime
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">訂 單 號:${
data.orderNo || '-'
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">流 水 號:${data.flowNo}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">員 工 ID:${
data.createId
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">員工姓名:${
data.createName
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">結(jié)算金額:${
data.payAmount
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">幣 種:元</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">設(shè) 備 號:${data.printNo}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">設(shè)備名稱:${
data.printName
}</div>
<div style="border-bottom: 1px dashed #000;height:1px;width:100%;margin-top:4px"></div>
<div style="font-size:12px;margin-bottom:10px;margin-top:5px;">打印時(shí)間:${this.$date.formatDate(
new Date(),
'yyyy-MM-dd hh:mm:ss'
)}</div>
</div>
`
this.getPrinterList(str, data)
},
formatOrderType(val) {
let name = ''
if (val == 1) {
name = '支付單'
} else if (val == 2) {
name = '退款單'
} else {
name = '其它'
}
return name
},
format(val) {
let name = ''
if (val == 1) {
name = '支付寶'
} else if (val == 2) {
name = '微信'
} else {
name = '其它'
}
return name
},
formatTradeType(val) {
let name = ''
if (val == 1) {
name = '碼牌支付'
} else if (val == 2) {
name = '動(dòng)態(tài)二維碼支付'
}
return name
},
getPrinterList(str, data) {
if (needCLodop()) {
let LODOP = getLodop()
this.printNameList = []
let counter = LODOP.GET_PRINTER_COUNT() // 獲取打印機(jī)個(gè)數(shù)
let index = -1
for (let i = 0; i < counter; i++) {
//將打印機(jī)存入printList數(shù)組中
this.printNameList.push({
index: i,
name: LODOP.GET_PRINTER_NAME(i),
})
if (LODOP.GET_PRINTER_NAME(i) === data.printNo) {
index = i
}
}
if (index >= 0 && LODOP.SET_PRINTER_INDEXA(index)) {
//預(yù)覽打印
LODOP.SET_PRINT_PAGESIZE(3, 800, 80, '小票')
LODOP.ADD_PRINT_HTM(10, 10, '100%', 80, str)
// LODOP.PREVIEW()
LODOP.PRINT()
} else {
this.$notification.error({
key: 'api-error',
message: '此電腦未配置' + data.printNo + '打印機(jī),請配置打印機(jī)后,重新登錄本系統(tǒng)。',
description: '',
})
}
window.On_CLodop_Opened = null
}
},
closeSocket() {
this.$ws.close()
},
onClose(e) { // 斷開連接增加全局彈框提示
console.log('斷開連接!', e)
let that = this
if (this.printState) {
this.$confirm({
title: '提示?',
content: '小票打印服務(wù)已斷開,是否嘗試重新連接?',
okText: '確認(rèn)',
cancelText: '取消',
onOk() {
that.initWebsocket(that.$store.getters.userInfo.id)
},
onCancel() {
sessionStorage.setItem('printState', false)
that.$store.commit('START_PRINT', false)
},
})
} else {
this.$message.error('連接已斷開!')
}
},
onOpen(e) {
console.log('建立連接!', e)
this.$message.success('連接成功!')
},
onError(e) {
this.$message.error('打印功能連接出錯(cuò),請重新連接!')
console.log('出錯(cuò)啦!', e)
},
}
備注:
- c-lodop功能強(qiáng)大滿足目前需求,但是通過接口直接打印,打印出的小票底部帶有“本頁”


