vue(网页)实现多台小票打印机实时打印

1.需求:

  • 商户端后台实时获取后台支付订单状态,支付完成后根据单据内容分配对应打印机并自动打印小票

2.设备/技术支持:

  • GP-C80180I佳博打印机(网口打印机)
  • 电脑(windows)
  • c-lodop
  • websocket

3.实现步骤

实现原理:通过websocket与后台建立实时连接,获取打印消息,获取到消息后自动调用打印方法;打印时通过c-lodop插件获取本地电脑打印机,并与接口返回的打印机进行匹配,根据获取到的打印机索引值开启对应的打印机
  1. 打印机配置:
  • 打印机连接路由器,配置ip地址
  • 下载安装驱动(找到对应型号)
  • 安装成功后,打印机列表会显示出打印机名称
  • 在电脑上找到对应的打印,配置(打印机属性->端口->添加端口(端口号为打印机ip地址))
  • 配置完成后,可以手动执行cmd命令连接打印机(默认是未连接的)
//telnet + 空格 + ip + 空格 + 端口号
telnet 192.168.5.6 9100  (打印机端口号,注意格式)
  • 连接成功跳后,会打开全黑的cmd窗口,随便输入字符,回车,打印机会自动打印输入的内容
  1. 插件配置
  • 下载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功能强大满足目前需求,但是通过接口直接打印,打印出的小票底部带有“本页”
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容