欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > uniapp实现小票打印 兼容微信小程序安卓

uniapp实现小票打印 兼容微信小程序安卓

2025/4/2 0:23:09 来源:https://blog.csdn.net/luck332/article/details/146551634  浏览:    关键词:uniapp实现小票打印 兼容微信小程序安卓

在uni-app中实现蓝牙打印需要分平台处理,因为不同平台(App/小程序/H5)的蓝牙API和权限机制不同。以下是分步骤实现方案:

核心实现思路

平台适配:主要适配App和小程序(H5因浏览器限制通常无法直接连接蓝牙硬件)
设备发现:扫描附近的蓝牙打印机
连接管理:建立并维护蓝牙连接
数据发送:将打印内容转换为ESC打印机指令集
异常处理:处理连接中断、设备不兼容等问题

小程序蓝牙API核心代码调用

// 初始化蓝牙适配器
uni.openBluetoothAdapter({success(res) {console.log('适配器已打开');// 开始扫描uni.startBluetoothDevicesDiscovery({services: [],success(res) {console.log('扫描到设备:', res.devices);}});}
});// 连接设备
uni.createBLEConnection({deviceId: '设备ID',success(res) {console.log('连接成功');// 获取服务UUIDuni.getBLEDeviceServices({deviceId: '设备ID',success(res) {const serviceId = res.services[0].uuid;// 获取特征值uni.getBLEDeviceCharacteristics({deviceId,serviceId,success(res) {const characteristicId = res.characteristics[0].uuid;// 发送数据const printData = this.generateEscPosData('Hello World\n');uni.writeBLECharacteristicValue({deviceId,serviceId,characteristicId,value: printData,success(res) {console.log('打印成功');}});}});}});}
});

核心ESC代码

核心ESC代码类库来源于网上。


import encode from './encoding.js';
var app = getApp();
var jpPrinter = {    createNew: function() {      var jpPrinter = {};var data = [];var bar = ["UPC-A", "UPC-E", "EAN13", "EAN8", "CODE39", "ITF", "CODABAR", "CODE93", "CODE128"];jpPrinter.name = "蓝牙打印机";jpPrinter.init = function() { //初始化打印机data.push(27)data.push(64)};jpPrinter.setText = function(content) { //设置文本内容var code = new encode.TextEncoder('gb2312', {NONSTANDARD_allowLegacyEncoding: true}).encode(content)for (var i = 0; i < code.length; ++i) {data.push(code[i])}}jpPrinter.setFontSize=function(n){//设置字体大小data.push(29)data.push(33)data.push(n)}jpPrinter.bold = function (n) {//加粗data.push(27)data.push(69)data.push(n)}jpPrinter.setUnderline=function(n){//设置下划线data.push(27)data.push(45)data.push(n)}jpPrinter.setUnderline2 = function (n) {//设置下划线data.push(28)data.push(45)data.push(n)}// jpPrinter.setBarcodeWidth = function(width) { //设置条码宽度//   data.push(29)//   data.push(119)//   if (width > 6) {//     width = 6;//   }//   if (width < 2) {//     width = 1;//   }//   data.push(width)// }// jpPrinter.setBarcodeHeight = function(height) { //设置条码高度//   data.push(29)//   data.push(104)//   data.push(height)// }// jpPrinter.setBarcodeContent = function(t,content) {//   var ty = 73;//   data.push(29)//   data.push(107)//   switch (t) {//     case bar[0]://       ty = 65;//       break;//     case bar[1]://       ty = 66;//       break;//     case bar[2]://       ty = 67;//       break;//     case bar[3]://       ty = 68;//       break;//     case bar[4]://       ty = 69;//       break;//     case bar[5]://       ty = 70;//       break;//     case bar[6]://       ty = 71;//       break;//     case bar[7]://       ty = 72;//       break;//     case bar[8]://       ty = 73;//       break;//   }//   data.push(ty)// }jpPrinter.setSelectSizeOfModuleForQRCode = function(n) { //设置二维码大小data.push(29)data.push(40)data.push(107)data.push(3)data.push(0)data.push(49)data.push(67)if (n > 15) {n = 15}if (n < 1) {n = 1}data.push(n)}jpPrinter.setSelectErrorCorrectionLevelForQRCode = function(n) { //设置纠错等级/*n      功能      纠错能力48 选择纠错等级 L 749 选择纠错等级 M 1550 选择纠错等级 Q 2551 选择纠错等级 H 30*/data.push(29)data.push(40)data.push(107)data.push(3)data.push(0)data.push(49)data.push(69)data.push(n)}jpPrinter.setStoreQRCodeData = function(content) { //设置二维码内容var code = new encode.TextEncoder('gb18030', {NONSTANDARD_allowLegacyEncoding: true}).encode(content)data.push(29)data.push(40)data.push(107)data.push(parseInt((code.length + 3) % 256))data.push(parseInt((code.length + 3) / 256))data.push(49)data.push(80)data.push(48)for (var i = 0; i < code.length; ++i) {data.push(code[i])}}jpPrinter.setPrintQRCode = function() { //打印二维码data.push(29)data.push(40)data.push(107)data.push(3)data.push(0)data.push(49)data.push(81)data.push(48)}jpPrinter.setHorTab = function() { //移动打印位置到下一个水平定位点的位置data.push(9)}jpPrinter.setAbsolutePrintPosition = function(where) { //设置绝对打印位置data.push(27)data.push(36)data.push(parseInt(where % 256))data.push(parseInt(where / 256))}jpPrinter.setRelativePrintPositon = function(where) { //设置相对横向打印位置data.push(27)data.push(92)data.push(parseInt(where % 256))data.push(parseInt(where / 256))}jpPrinter.setSelectJustification = function(which) { //对齐方式/*0, 48 左对齐1, 49 中间对齐2, 50 右对齐*/data.push(27)data.push(97)data.push(which)}jpPrinter.space = function (n) { //设置横向跳格位置data.push(27)data.push(68)data.push(n)}jpPrinter.setLeftMargin = function(n) { //设置左边距data.push(29)data.push(76)data.push(parseInt(n % 256))data.push(parseInt(n / 256))}jpPrinter.textMarginRight = function (n) { //设置字符右间距data.push(27)data.push(32)data.push(n)}jpPrinter.rowSpace = function (n) { //设置行间距data.push(27)data.push(51)data.push(n)}jpPrinter.setPrintingAreaWidth = function(width) { //设置打印区域宽度data.push(29)data.push(87)data.push(parseInt(width % 256))data.push(parseInt(width / 256))}jpPrinter.setSound = function(n, t) { //设置蜂鸣器data.push(27)data.push(66)if (n < 0) {n = 1;} else if (n > 9) {n = 9;}if (t < 0) {t = 1;} else if (t > 9) {t = 9;}data.push(n)data.push(t)}jpPrinter.setBitmap = function(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 point_list = []console.log(width + "--" + height)data.push(29)data.push(118)data.push(48)data.push(0)data.push((parseInt((res.width + 7) / 8) * 8) / 8)data.push(0)data.push(parseInt(res.height % 256))data.push(parseInt(res.height / 256))console.log(res.data.length)console.log("temp=" + temp)for (var i = 0; i < height; ++i) {for (var j = 0; j < width; ++j) {for (var k = 0; k < 32; k += 4) {var po = {}if (res.data[temp] == 0 && res.data[temp + 1] == 0 && res.data[temp + 2] == 0 && res.data[temp + 3] == 0) {po.point = 0;} else {po.point = 1;}point_list.push(po)temp += 4}}time++temp = res.data.length - width * 32 * time}for (var i = 0; i < point_list.length; i += 8) {var p = point_list[i].point * 128 + point_list[i + 1].point * 64 + point_list[i + 2].point * 32 + point_list[i + 3].point * 16 + point_list[i + 4].point * 8 + point_list[i + 5].point * 4 + point_list[i + 6].point * 2 + point_list[i + 7].pointdata.push(p)}}jpPrinter.setPrint = function() { //打印并换行data.push(10)}jpPrinter.setPrintAndFeed = function(feed) { //打印并走纸feed个单位data.push(27)data.push(74)data.push(feed)}jpPrinter.setPrintAndFeedRow = function(row) { //打印并走纸row行data.push(27)data.push(100)data.push(row)}jpPrinter.getData = function() { //获取打印数据return data;};return jpPrinter; },Query: function() {var queryStatus = {};var buf;var dateView;queryStatus.getRealtimeStatusTransmission = function(n) { //查询打印机实时状态/*n = 1:传送打印机状态n = 2:传送脱机状态n = 3:传送错误状态n = 4:传送纸传感器状态*/buf = new ArrayBuffer(3)dateView = new DataView(buf)dateView.setUint8(0, 16)dateView.setUint8(1, 4)dateView.setUint8(2, n)queryStatus.query(buf)}queryStatus.query = function(buf) {wx.writeBLECharacteristicValue({deviceId: app.BLEInformation.deviceId,serviceId: app.BLEInformation.writeServiceId,characteristicId: app.BLEInformation.writeCharaterId,value: buf,success: function(res) {},complete: function(res) {console.log(res)buf = nulldateView = null;}})}return queryStatus;}
};var esc={jpPrinter
}
export default esc;

小票实现过程

UniApp中使用ESC指令进行蓝牙小票打印时,如何实现每行显示商品名、单价、数量和金额的问题。用户之前已经得到了如何让文本左对齐、金额右对齐的指导,现在需要更复杂的排版,即一行内有四个数据项,分别对齐。

首先,我需要回顾用户提供的代码。之前的示例中使用了绝对定位来实现左右对齐,但这次用户需要四个列,可能需要不同的方法。ESC/POS指令的对齐指令是针对整行的,所以如果用户直接使用对齐指令,可能无法在同一行内实现多列的不同对齐方式。因此,可能需要结合使用绝对定位或者制表符来分隔各列。

接下来,我需要确定用户的具体需求。用户提到“每行商品名 单价 数量 金额”,这四个数据项可能需要分别左对齐、右对齐等。通常,商品名左对齐,单价、数量、金额右对齐,但具体排版可能根据用户需求有所不同。比如,商品名占较宽的位置,单价、数量、金额依次右对齐。

然后,我需要考虑现有的代码结构。用户提供的`jpPrinter`对象有设置绝对位置和对齐的方法,比如`setSelectJustification`和`setAbsolutePrintPosition`。可能需要利用这些方法,或者结合制表符来分隔各列。例如,设置多个制表位,让每个列在指定位置打印。

另外,还需要处理字体宽度的问题。不同字体大小会影响每个字符占用的点数,需要计算每列的起始位置。例如,默认字体每个字符12点宽,如果放大字体,需要调整计算方式。同时,中文和英文字符的宽度可能不同,需要确认编码是否正确,避免乱码。

// 计算右对齐X坐标const charWidth = 12;     // 单个字符宽度(需实测)item.products.forEach(product=>{command.setSelectJustification(0);//居左command.setText(product.title);if(product.title.length>6){command.setPrint()}command.setAbsolutePrintPosition(170);command.setText(product.number+""+product.unit);command.setAbsolutePrintPosition(250 + 4*charWidth - getStringWidth(product.price+"")*charWidth);command.setText(product.price);command.setAbsolutePrintPosition(320 + 4*charWidth - getStringWidth(product.total+"")*charWidth);command.setText(product.total);command.setPrint()})

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词