支付宝/钉钉小程序实现蓝牙打印

2021/5/8 20:27:19

本文主要是介绍支付宝/钉钉小程序实现蓝牙打印,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

本文主要是钉钉小程序通过蓝牙进行打印,当然钉钉和支付宝都是相同的。打印机设备佳博M-322便携式打印机,打印效果图在文末
使用到的接口请参照钉钉开发文档

1.连接蓝牙打印机的js

Page({
  data: {
    list: [],
    loading: false,//搜索状态
    write: false,//写入的值是否已经确定
    characteristicId: '',
    serviceId: '',
    deviceId: '',
    services: [],
    num: 0,
    printer: ''
  },
  onl oad() {
    //初始化蓝牙
    dd.openBluetoothAdapter({
      success: (res) => {
        //获取本季蓝牙模块的状态
        dd.getBluetoothAdapterState({
          success: (res) => {
            //是否可用
            if (res.available) {
              //是否正在搜索
              this.setData({
                loading: res.discovering
              })
              /*if (res.discovering) {
                //停止搜索
                dd.stopBluetoothDevicesDiscovery({
                  success: (res) => {
                    console.log(res)
                  },
                  fail: (res) => {
                  },
                  complete: (res) => {
                  }
                });
              }*/
              //获取已经搜索到的设备
              this.getBluetoothDevices();
            } else {
              dd.alert({
                title: '提示',
                content: '手机蓝牙模块不可用!'
              })
            }
          },
          fail: (res) => {
            console.log(res)
          },
          complete: (res) => {
            console.log(res)
          }
        });
      },
      fail: (res) => {
        if (res.error == 12) {
          dd.alert({
            title: '提示',
            content: '蓝牙未打开,请尝试打开蓝牙。'
          })
        }
        else if (res.error == 13) {
          dd.alert({
            title: '提示',
            content: '与系统服务的链接暂时丢失,请尝试重新连接。'
          })
        } else if (res.error == 14) {
          dd.alert({
            title: '提示',
            content: '未授权使用蓝牙功能。请授权使用蓝牙功能。'
          })
        } else if (res.error == 10000) {
          dd.alert({
            title: '提示',
            content: '未初始化蓝牙适配器'
          })
        } else {
          dd.alert({
            title: '提示',
            content: '未知错误!'
          })
        }
      },
      complete: (res) => {
      }
    });
    //监听搜索到的设备
    this.callback = this.callback.bind(this);
    dd.onBluetoothDeviceFound(this.callback);
  },
  callback(res) {
    //监听新设备事件
    //console.log(res);
    var list = this.data.list;
    res.devices.forEach(element => {
      //判断list中的id没有这个才可以
      var ok = true;
      for (var i = 0; i < list.length; i++) {
        //console.log(list[i].deviceId, element.deviceId)
        if (list[i].deviceId == element.deviceId) {
          ok = false;
        }
      }
      if (ok && element.localName != '' && element.name != null) {
        list.push(element);
      }
    });
    this.setData({
      list: list
    })
    //console.log(list)
  },
  getBluetoothDevices() {
    //android 6.0需要授权地理位置权限
    dd.getBluetoothDevices({
      success: (res) => {
        this.callback(res);
      },
      fail: (res) => {
        console.log(res)
        dd.alert({
          title: '提示',
          content: '位置权限未开启!请给钉钉开启定位权限'
        })
      },
      complete: (res) => {
        console.log(res)
      }
    });
  },
  onClick(e) {
    console.log(e)
    this.setData({
      deviceId: e.target.dataset.item.deviceId,
      printer: e.target.dataset.item.name
    })
    this.stopBluetoothDevicesDiscovery();//停止搜索蓝牙
    //链接蓝牙设备
    dd.showLoading();
    dd.connectBLEDevice({
      //判断蓝牙搜索的状态如果是正在搜索那么就关闭掉搜索
      // 这里的 deviceId 可通过 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
      deviceId: e.target.dataset.item.deviceId,
      success: (res) => {
        //获取设备的特征值用于收发数据
        dd.getBLEDeviceServices({
          deviceId: e.target.dataset.item.deviceId,
          success: (res) => {
            this.setData({
              services: res.services
            })
            //遍历特征值看都是什么类型的。只需要写入类型
            this.getBLEDeviceServices();
          },
          fail: (res) => {
            console.log(res)
          }, complete: (res) => {
            dd.hideLoading()
          }
        })
      },
      fail: (res) => {
        dd.alert({
          title: '提示',
          content: res.errorMessage
        })
      },
      complete: (res) => {
      }
    });
  },
  getBLEDeviceServices() {
    dd.getBLEDeviceCharacteristics({
      deviceId: this.data.deviceId,
      serviceId: this.data.services[this.data.num].serviceId,
      success: (res) => {
        console.log(res)
        for (var j = 0; j < res.characteristics.length; j++) {
          //判断特征值是否支持写入,读取,通知,操作,如果支持就可以了
          if (res.characteristics[j].properties.write && !this.data.write) {
            //characteristicId = res.characteristics[0].characteristicId;
            //serviceId = res.characteristics[0].serviceId;
            this.setData({
              write: true,
              characteristicId: res.characteristics[j].characteristicId,
              serviceId: res.characteristics[j].serviceId,
            })
          }
        }
        if (this.data.write) {
          dd.showToast({
            type: 'success',
            content: '连接成功!'
          })
          //返回上一个页面
          let pages = getCurrentPages();//获取当前页面js里面的pages里的所有信息。
          //prevPage 是获取上一个页面的js里面的pages的所有信息。 -2 是上一个页面,-3是上上个页面以此类推
          let prevPage = pages[pages.length - 2];
          prevPage.setData({
            characteristicId: this.data.characteristicId,
            deviceId: this.data.deviceId,
            printer: this.data.printer,
            serviceId: this.data.serviceId,
            printtype: '1',
            'printtypes[1].checked': true,
            'printtypes[0].checked': false,
          })
          console.log(this.data.serviceId);
          console.log(this.data.characteristicId)
          dd.navigateBack();
        } else {
          if (this.data.num < this.data.services.length) {
            this.setData({
              num: this.data.num + 1
            })
            this.getBLEDeviceServices();
          }
        }
      }
    })
  },
  stopBluetoothDevicesDiscovery() {
    //停止搜索
    dd.stopBluetoothDevicesDiscovery({
      success: (res) => {
        //获得蓝牙的状态
        dd.getBluetoothAdapterState({
          success: (res) => {
            //是否可用
            if (res.available) {
              //是否正在搜索
              this.setData({
                loading: res.discovering
              })
              //获取已经搜索到的设备
              this.getBluetoothDevices();
            } else {
              dd.alert({
                title: '提示',
                content: '手机蓝牙模块不可用!'
              })
            }
          },
          fail: (res) => {
            console.log(res)
          },
          complete: (res) => {
            console.log(res)
          }
        });
      },
      fail: (res) => {
      },
      complete: (res) => {
      }
    });
  },
  onseaer() {
    //如果但当前正在搜索蓝牙,那么点击就是停止搜索
    if (this.data.loading) {
      this.stopBluetoothDevicesDiscovery();
    } else {
      //开启蓝牙搜索
      dd.startBluetoothDevicesDiscovery({
        //services: ['fff0'],
        success: (res) => {
          //获得蓝牙的状态
          //获取本季蓝牙模块的状态
          dd.getBluetoothAdapterState({
            success: (res) => {
              //是否可用
              if (res.available) {
                //是否正在搜索
                this.setData({
                  loading: res.discovering
                })
                /* if (res.discovering) {
                   //停止搜索
                   dd.stopBluetoothDevicesDiscovery({
                     success: (res) => {
                       console.log(res)
                     },
                     fail: (res) => {
                     },
                     complete: (res) => {
                     }
                   });
                 }*/
                //获取已经搜索到的设备
                this.getBluetoothDevices();
              } else {
                dd.alert({
                  title: '提示',
                  content: '手机蓝牙模块不可用!'
                })
              }
            },
            fail: (res) => {
              console.log(res)
            },
            complete: (res) => {
              console.log(res)
            }
          });
        },
        fail: (res) => {
        },
        complete: (res) => {
        }
      });
    }
  }
});

2.发送打印标签打印数据js

import { GetSkuList } from "../../../api/api";
import { GetPrintGood } from "../../../api/api"
import { jpPrinter } from "../../../util/tsc"
Page({
  data: {
    hidden: true, //款号选者是否隐藏
    ITCODE_IT: '',
    Price: 0,
    printtypes: [{ value: '0', label: 'WIFI', checked: true }, { value: '1', label: '蓝牙' }],
    printtype: '0',
    printer: '',
    characteristicId: '',
    deviceId: '',
    serviceId: '',
    time: 20,//限制在20字节内
    looptime: 0,//发送字节整数数量
    lastData: 0,//余数
    currentTime: 1,//发送次数
  },
  onl oad() {
    // 注意: 回调方法的注册在整个小程序启动阶段只要做一次,调多次会有多次回调
    dd.onSocketClose((res) => {
      dd.showToast({ type: 'exception', content: '连接打印机失败' });
      this.setData({
        sendMessageAbility: false,
        closeLinkAbility: false,
      });
    });
    // 注意: 回调方法的注册在整个小程序启动阶段只要做一次,调多次会有多次回调
    dd.onSocketOpen((res) => {
      dd.showToast({ type: 'success', content: '已连接打印机!' });
      this.setData({
        sendMessageAbility: true,
        closeLinkAbility: true,
      });
    });
    dd.onSocketError(function (res) {
      dd.showToast({ type: 'exception', content: 'WebSocket 连接打开失败,请检查!' + res });
    });
    // 注意: 回调方法的注册在整个小程序启动阶段只要做一次,调多次会有多次回调
    dd.onSocketMessage((res) => {
      //dd.alert({ content: '收到数据!' + JSON.stringify(res) });
    });
  },
  connect_start() {
    dd.connectSocket({
      url: 'ws://namemeiprintserver1.vaiwan.com', // 开发者服务器接口地址,必须是 wss 协议,且域名必须是后台配置的合法域名
      success: (res) => {
      }
    });
  },
  onPickerTap(e) {
    if (e.currentTarget.dataset.type == 'item') {
      //设置弹出的单选界面为显示
      this.setData(
        {
          hidden: false
        });
    }
    else {
      //跳转到蓝牙打印机
      dd.navigateTo(
        {
          url: '../lianjielanyadayinji/lianjielanyadayinji'
        }
      )
    }
  }, onShowSlect(e)//选者界面回掉韩素
  {
    this.setData({
      hidden: true
    })
    //console.log(e);
    if (e == null) {
      return
    }
    //请求这个款的sku
    var IT_CODE = e.value.split(" ")[0];
    GetSkuList({
      ItCode: IT_CODE
    }).then(res => {
      //console.log(res);
      this.setData(
        {
          ITCODE_IT: IT_CODE,
          Skus: res.data.Data.Skus,
          Price: res.data.Data.ip_priceb
        }
      )
    })

  }, //同步输入的数字
  onInputqty(e) {
    var str = 'Skus[' + e.target.dataset.index + '].qty';
    this.setData(
      {
        [str]: e.detail.value
      }
    )
  },//发送打印的数据
  ontap() {
    //用条码来请求符合要求的数据
    var str = '';
    this.data.Skus.forEach(element => {
      if (element.qty != null && element.qty > 0) {
        str += element.Sku + "','";
      }
    });
    if (this.data.Price <= 0 || this.data.Price > 9000) {
      dd.alert({ title: '价格不对请先修改!' })
      return;
    }
    if (str.length > 0) {
      var app = getApp();
      GetPrintGood({
        Code: str,
        type: 0
      }).then(res => {
        if (res.data.ErrorCode == 0) {
          //把数量都添加到对应的地方上面
          var oksku = [];
          res.data.Data.forEach(item => {
            this.data.Skus.forEach(list => {
              if (item.商品条码 == list.Sku) {
                item.数量 = list.qty
                oksku.push(item);
              }
            })
          })
          //如果是wifi
          if (this.data.printtype == 0) {
            this.connect_start();
            dd.sendSocketMessage({
              data: JSON.stringify(oksku), // 需要发送的内容
              success: (res) => {
                dd.showToast({ type: 'success', content: '发送成功!' });
              },
            });
          } else {
            if (this.data.characteristicId == '' || this.data.deviceId == '' || this.data.serviceId == '') {
              dd.showToast({
                type: 'fail',
                content: '打印机未连接!'
              })
            }
            else {
              console.log(oksku);
              this.setData({
                oksku: oksku,
                printnum: 0
              })
              dd.showLoading();
              this.printsku();
            }
          }
        }
        else {
          dd.alert({
            title: '请输入要打印的数量'
          })
        }
      })
    }
  },
  printsku() {
    //通过蓝牙发送数据

    var command = jpPrinter.createNew();
    command.setSize(60, 40);
    command.setGap(0);
    command.setCls();
    command.setText(0, 30, "TSS24.BF2", 1, 1, "品名:" + this.data.oksku[this.data.printnum].商品名称);
    //command.setText(0, 60, "TSS24.BF2", 1, 1, "款号:" + this.data.oksku[this.data.printnum].款号);
    command.setText(240, 70, "TSS24.BF2", 1, 1, "尺码:" + this.data.oksku[this.data.printnum].尺码描述);
    command.setText(0, 70, "TSS24.BF2", 1, 1, "颜色:" + this.data.oksku[this.data.printnum].颜色描述);
    command.setBar(0, 100, 128, 120, 1, 2, 1, this.data.oksku[this.data.printnum].商品条码);
    command.setText(240, 260, "TSS16.BF2", 2, 2, "零售价:" + this.data.oksku[this.data.printnum].建议零售价);
    command.setPagePrint(this.data.oksku[this.data.printnum].数量);
    var buffer = command.getData();
    var looptime = parseInt(buffer.length / this.data.time);//发送次数
    var lastData = parseInt(buffer.length % this.data.time);//余数
    this.setData({
      looptime: looptime + 1,
      lastData: lastData,
      currentTime: 1
    })
    //console.log(buffer.length);
    this.send(buffer);

  },
  radioChannge(e) {
    //打印方式修改
    this.setData(
      {
        printtype: e.detail.value,
      })
  },
  send(buff) {
    var buf;
    if (this.data.currentTime < this.data.looptime) {
      //如果当前发送次数小于总共需要发送的次数
      buf = buff.substring((this.data.currentTime - 1) * this.data.time, this.data.currentTime * this.data.time);
    } else { //否者发送剩余的字节
      buf = buff.substring((this.data.currentTime - 1) * this.data.time, (this.data.currentTime - 1) * this.data.time + this.data.lastData);
    }
    console.log(buf)
    //console.log('第' + this.data.currentTime + '次发送数据大小为:' + buf.byteLength);
    dd.writeBLECharacteristicValue({
      deviceId: this.data.deviceId,
      serviceId: this.data.serviceId,
      characteristicId: this.data.characteristicId,
      value: buf,
      success: (res) => {
        console.log(res)
      },
      fail: (res) => {
        console.log(res)
      },
      complete: (res) => {
        if (this.data.currentTime < this.data.looptime) {
          //如果当前发送的次数小于或者等于总共要发送的次数,那么就进行加一
          this.data.currentTime++;
          //console.log(this.data.currentTime);
          //开始下一次的发送
          this.send(buff);
        } else {
          //打印下一个条码
          this.data.printnum++;
          if (this.data.printnum < this.data.oksku.length) {
            this.printsku();
          }
          else {
            dd.hideLoading()
            //发送完毕
            dd.showToast({
              type: 'success',
              content: '发送陈工'
            })
          }
        }
      }
    })
  }
});

3.打印指令文件tsc.js

var app = getApp();
var encode = require("./encoding.js");
export const jpPrinter = {
  createNew: function () {
    var jpPrinter = {};
    var data = "";
    var command = [];
    var str = "";

    jpPrinter.name = "蓝牙打印机";

    jpPrinter.init = function () { };

    jpPrinter.addCommand = function (content) {  //将指令转成数组装起
      //content = 'HEX';
      var code = new encode.TextEncoder(
        'gb18030', {
        NONSTANDARD_allowLegacyEncoding: true
      }).encode(content)
      for (var i = 0; i < code.length; ++i) {
        command.push(code[i])
      }
      //str += content;
    }
    jpPrinter.setSize = function (pageWidght, pageHeight) { //设置页面大小
      data = "SIZE " + pageWidght.toString() + " mm" + "," + pageHeight.toString() + " mm" + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setSpeed = function (printSpeed) { //设置打印机速度
      data = "SPEED " + printSpeed.toString() + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setDensity = function (printDensity) { //设置打印机浓度
      data = "DENSITY " + printDensity.toString() + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setGap = function (printGap) { //传感器
      data = "GAP " + printGap.toString() + " mm\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setCountry = function (country) { //选择国际字符集
      /*
      001:USA
      002:French
      003:Latin America
      034:Spanish
      039:Italian
      044:United Kingdom
      046:Swedish
      047:Norwegian
      049:German
       */
      data = "COUNTRY " + country + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setCodepage = function (codepage) { //选择国际代码页
      /*
      8-bit codepage 字符集代表
      437:United States
      850:Multilingual
      852:Slavic
      860:Portuguese
      863:Canadian/French
      865:Nordic
      Windows code page
      1250:Central Europe
      1252:Latin I
      1253:Greek
      1254:Turkish
      以下代码页仅限于 12×24 dot 英数字体
      WestEurope:WestEurope
      Greek:Greek
      Hebrew:Hebrew
      EastEurope:EastEurope
      Iran:Iran
      IranII:IranII
      Latvian:Latvian
      Arabic:Arabic
      Vietnam:Vietnam
      Uygur:Uygur
      Thai:Thai
      1252:Latin I
      1257:WPC1257
      1251:WPC1251
      866:Cyrillic
      858:PC858
      747:PC747
      864:PC864
      1001:PC100
      */
      data = "CODEPAGE " + codepage + "\r\n";
      jpPrinter.addCommand(data)
    }

    jpPrinter.setCls = function () { //清除打印机缓存
      data = "CLS" + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setFeed = function (feed) { //将纸向前推出n
      data = "FEED " + feed + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setBackFeed = function (backup) { //将纸向后回拉n
      data = "BACKFEED " + backup + "\r\n";
      jpPrinter.addCommand(data)
    }

    jpPrinter.setDirection = function (direction) { //设置打印方向,参考编程手册  
      data = "DIRECTION " + direction + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setReference = function (x, y) { //设置坐标原点,与打印方向有关
      data = "REFERENCE " + x + "," + y + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setFromfeed = function () { //根据Size进一张标签纸
      data = "FORMFEED \r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setHome = function () { //根据Size找到下一张标签纸的位置
      data = "HOME \r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setSound = function (level, interval) { //控制蜂鸣器
      data = "SOUND " + level + "," + interval + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setLimitfeed = function (limit) { // 检测垂直间距
      data = "LIMITFEED " + limit + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setBar = function (x, y, width, height) { //绘制线条
      data = "BAR " + x + "," + y + "," + width + "," + height + "\r\n"
      jpPrinter.addCommand(data)
    };

    jpPrinter.setBox = function (x_start, y_start, x_end, y_end, thickness) { //绘制方框
      data = "BOX " + x_start + "," + y_start + "," + x_end + "," + y_end + "," + thickness + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setErase = function (x_start, y_start, x_width, y_height) { //清除指定区域的数据
      data = "ERASE " + x_start + "," + y_start + "," + x_width + "," + y_height + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setReverse = function (x_start, y_start, x_width, y_height) { //将指定的区域反相打印
      data = "REVERSE " + x_start + "," + y_start + "," + x_width + "," + y_height + "\r\n";
      jpPrinter.addCommand(data)
    };

    jpPrinter.setText = function (x, y, font, x_, y_, str) { //打印文字
      data = "TEXT " + x + "," + y + ",\"" + font + "\"," + 0 + "," + x_ + "," + y_ + "," + "\"" + str + "\"\r\n"
      jpPrinter.addCommand(data)
    };

    jpPrinter.setQR = function (x, y, level, width, mode, content) { //打印二维码
      data = "QRCODE " + x + "," + y + "," + level + "," + width + "," + mode + "," + 0 + ",\"" + content + "\"\r\n"
      jpPrinter.addCommand(data)
    };

    jpPrinter.setBar = function (x, y, codetype, height, readable, narrow, wide, content) { //打印条形码
      data = "BARCODE " + x + "," + y + ",\"" + codetype + "\"," + height + "," + readable + "," + 0 + "," + narrow + "," + wide + ",\"" + content + "\"\r\n"
      jpPrinter.addCommand(data)
    };

    jpPrinter.setBitmap = function (x, y, mode, res) {  //添加图片,res为画布参数
      console.log(res)
      var width = parseInt((res.width + 7) / 8 * 8 / 8)
      var height = res.height;
      var time = 1;
      var temp = res.data.length - width * 32;
      var pointList = []
      console.log(width + "--" + height)
      data = "BITMAP " + x + "," + y + "," + width + "," + height + "," + mode + ","
      jpPrinter.addCommand(data)
      for (var i = 0; i < height; ++i) {
        console.log(temp)
        for (var j = 0; j < width; ++j) {
          for (var k = 0; k < 32; k += 4) {
            if (res.data[temp] == 0 && res.data[temp + 1] == 0 && res.data[temp + 2] == 0 && res.data[temp + 3] == 0) {
              pointList.push(1)
            } else {
              pointList.push(0)
            }
            temp += 4
          }
        }
        time++
        temp = res.data.length - width * 32 * time
      }
      for (var i = 0; i < pointList.length; i += 8) {
        var p = pointList[i] * 128 + pointList[i + 1] * 64 + pointList[i + 2] * 32 + pointList[i + 3] * 16 + pointList[i + 4] * 8 + pointList[i + 5] * 4 + pointList[i + 6] * 2 + pointList[i + 7]
        command.push(p)
      }
    }

    jpPrinter.setPagePrint = function (qty) { //打印页面
      data = "PRINT " + qty + ",1\r\n"
      jpPrinter.addCommand(data)
    };
    //获取打印数据
    jpPrinter.getData = function () {
      var buf = new ArrayBuffer(command.length);
      var dataView = new DataView(buf);
      for (var i = 0; i < command.length; ++i) {
        dataView.setUint8(i, command[i]);
      }
      return Array.prototype.map.call(new Uint8Array(buf), x => ('00' + x.toString(16)).slice(-2)).join('');
    };
    return jpPrinter;
  }
};

在这里插入图片描述



这篇关于支付宝/钉钉小程序实现蓝牙打印的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程