1.需求:
- 商户端后台实时获取后台支付订单状态,支付完成后根据单据内容分配对应打印机并自动打印小票
2.设备/技术支持:
- GP-C80180I佳博打印机(网口打印机)
- 电脑(windows)
- c-lodop
- websocket
3.实现步骤
实现原理:通过websocket与后台建立实时连接,获取打印消息,获取到消息后自动调用打印方法;打印时通过c-lodop插件获取本地电脑打印机,并与接口返回的打印机进行匹配,根据获取到的打印机索引值开启对应的打印机
- 打印机配置:
- 打印机连接路由器,配置ip地址
- 下载安装驱动(找到对应型号)
- 安装成功后,打印机列表会显示出打印机名称
- 在电脑上找到对应的打印,配置(打印机属性->端口->添加端口(端口号为打印机ip地址))
- 配置完成后,可以手动执行cmd命令连接打印机(默认是未连接的)
//telnet + 空格 + ip + 空格 + 端口号
telnet 192.168.5.6 9100 (打印机端口号,注意格式)
- 连接成功跳后,会打开全黑的cmd窗口,随便输入字符,回车,打印机会自动打印输入的内容
- 插件配置
- 下载C-Lodop
- 安装
-
设置->端口设置(端口1自定义设置(非必要):8099,注意这里如果修改了要跟下边代码里配置的保持一致)
image.png
image.png
image.png
3.具体代码实现
- 在项目代码里,引入官方下载包里的LodopFuncs.js文件(要想在vue里使用需要做出一定修改)
1. 端口配置,需要跟上边服务端口等保持一致,否则无法正常连接
//用双端口加载主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. 文件底部增加导出代码,否者在对应vue文件导入时无法正常调用
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)
// 自定义打印内容
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 ? '自动打印' : '手动打印'
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">支付时间:${
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%;">结算金额:${
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%;">设 备 号:${data.printNo}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">设备名称:${
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;">打印时间:${this.$date.formatDate(
new Date(),
'yyyy-MM-dd hh:mm:ss'
)}</div>
</div>
`
this.getPrinterList(str, data)
},
// 获取本地打印
getPrinterList(str, data) {
if (needCLodop()) { // 这里时为了判断插件是否初始化完成,不加这个判断,直接调用getLodop()方法,会提示“网页还没下载完毕,请稍等一下再操作.”
let LODOP = getLodop()
this.printNameList = []
let counter = LODOP.GET_PRINTER_COUNT() // 获取打印机个数
let index = -1
for (let i = 0; i < counter; i++) {
//将打印机存入printList数组中
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)) { // 此处是根据对应打印机的索引值,找到并开启打印
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 + '打印机,请配置打印机后,重新登录本系统。',
description: '',
})
}
window.On_CLodop_Opened = null
}
},
}
}
- 完整代码
<script>
import { getLodop, needCLodop } from '@/utils/initPrint.js'
export default {
computed: {
...mapState({
printState: (state) => state.user.printState,
}),
},
watch: {
// 监听打印开启状态
printState: {
handler(val) {
// 页面刷新后printState会被初始化,所以再获取下浏览器存储的状态
let flag = sessionStorage.getItem('printState')
// 如果页面刷新了,刷新前开启了打印,这自动与后台建立连接
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) { // 接收到消息后自动打印
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 ? '自动打印' : '手动打印'
}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">支付时间:${
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%;">结算金额:${
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%;">设 备 号:${data.printNo}</div>
<div style="font-size:12px;margin-bottom:2px;display:inline-block;width:100%;">设备名称:${
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;">打印时间:${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 = '动态二维码支付'
}
return name
},
getPrinterList(str, data) {
if (needCLodop()) {
let LODOP = getLodop()
this.printNameList = []
let counter = LODOP.GET_PRINTER_COUNT() // 获取打印机个数
let index = -1
for (let i = 0; i < counter; i++) {
//将打印机存入printList数组中
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)) {
//预览打印
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 + '打印机,请配置打印机后,重新登录本系统。',
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: '小票打印服务已断开,是否尝试重新连接?',
okText: '确认',
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('打印功能连接出错,请重新连接!')
console.log('出错啦!', e)
},
}
备注:
- c-lodop功能强大满足目前需求,但是通过接口直接打印,打印出的小票底部带有“本页”