更新记录
1.0.1(2024-12-19)
解决SDK兼容性问题:修复上一个版本SDK兼容设备打印服务版本6.0.0-6.2.3时无法获取默认打印机的问题。 支持到官方最新的printerx:1.0.17内核版本
平台兼容性
Vue2 | Vue3 |
---|---|
√ | √ |
App | 快应用 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节小程序 | QQ小程序 |
---|---|---|---|---|---|---|
HBuilderX 4.0,Android:5.0,iOS:不支持,HarmonyNext:支持 | × | × | × | × | × | × |
钉钉小程序 | 快手小程序 | 飞书小程序 | 京东小程序 | 鸿蒙元服务 |
---|---|---|---|---|
× | × | × | × | × |
H5-Safari | Android Browser | 微信浏览器(Android) | QQ浏览器(Android) | Chrome | IE | Edge | Firefox | PC-Safari |
---|---|---|---|---|---|---|---|---|
× | × | × | × | × | × | × | × | × |
概述
SunmiPrinterUTS封装商米打印模块,支持商米旗下的所有商用硬件的打印服务,设备应用于包括外卖接单,打印小票,扫描,收款,团购核销,点餐预约等一系列商业场景。
功能说明
-
商米打印服务介绍 商米打印服务是系统预置的功能,用于管理商米打印机设置和外接打印机的添加。开发者可以通过本服务配置内置打印机,以及添加外接打印机无需额外适配。该插件完整实现了Android原生库PrinterSDK(com.sunmi:printerx)的所有功能,方便开发者直接通过Uniapp和UniappX平台调用打印服务,实现跨平台需求。
-
商米新printx打印说明
为了更方便开发者调用商米品牌的打印机,也为了简化开发者打印相关开发难度,商米官方于2024年3月底对商米打印SDK做了重构,通过本次升级,扩展了SDK功能,提高了SDK使用的上手速度,统一并简化了所有设备打印业务的SDK封装
-
新旧功能对比示
对比项 旧版SDK 新版SDK 支持打印类型 仅支持热敏小票打印机按行打印 支持热敏小票、热敏标签、文件打印等多种方式 适配范围 仅针对商米内置打印机 支持所有商米设备,且可扩展连接云打印机 指令支持 仅支持ESC标准指令 支持ESC、TSPL以及将来扩展更多指令 友好度 构建复杂样式内容困难 构建复杂样式简单易上手 -
注意事项
从应用市场下载插件导入自己项目后,要先制作自定义插件后,才可以运行使用(示例程序已经打好基座,可以直接运行)
SunmiPrinterUTS插件需在 Android 5.0 版本及以上方可正常使用
尽量使用 HBuilderX 4.0+ 以上版本,以便更好在uni-app和uni-app x中使用uts插件
使用前要先调用initPrinter()方法初始化打印机,才可以正常打印,打印结束要及时调用closePrinter关闭打印服务
完整代码示例
<template>
<view style="display: flex;">
<view style="padding: 10px;">
<button @click="initPrinter()" style="margin-top: 10px;">初始化打印服务</button>
<button @click="getPrinterInfo()" style="margin-top: 10px;">获取打印机信息</button>
<button @click="cashOpen()" style="margin-top: 10px;">打开钱箱</button>
<button @click="closePrinter()" style="margin-top: 10px;">关闭打印服务</button>
</view>
<view style="padding: 10px;">
<button @click="printText()" style="margin-top: 10px;">打印文本内容</button>
<button @click="printTexts()" style="margin-top: 10px;">按列排列打印内容</button>
<button @click="printBarCode()" style="margin-top: 10px;">打印条形码</button>
<button @click="printQrCode()" style="margin-top: 10px;">打印二维码</button>
<button @click="printDividingLine()" style="margin-top: 10px;">打印分割线</button>
<button @click="printBitmap()" style="margin-top: 10px;">打印图片</button>
<button @click="autoOut()" style="margin-top: 10px;">切刀</button>
<button @click="printTestTicket()" style="margin-top: 10px;">打印测试小票</button>
</view>
</view>
</template>
<script>
import util from './util.js'
import { testTicketSample,getPrinterInfo,initPrinter,printTexts,fillLine,fillAround,printDividingLine,printText,printQrCode,printBarCode,printBitmap,autoOut,cashOpen,closePrinter } from "@/uni_modules/sunmi-printerx";
//引入方式
export default {
data() {
return {
textStyle :{
align:'default',//默认居左
textSize : 24,//设置文本字符大小 6~96像素 默认值24
textWidthRatio : 0,//横向放大倍数 0~7 默认值0
textHeightRatio : 0,//纵向放大倍数 0~7 默认值0
textSpace : 0,//文本字间距 0~100像素 默认值0
enableBold : false,//开启文本加粗功能 默认不开启
enableUnderline : false,//文本下划线 默认不开启
enableStrikethrough : false,//文本删除线 默认不开启
enableItalics : false,//文本斜体 默认不开启
enableInvert : false,//文本倒置 默认不开启
enableAntiColor : false,//文本反白 默认不开启
posX : 0,//设置行左边距 像素 默认值0
},
barcodeStyle:{
align : "default", //设置二维码行内对齐方式 默认居左
dotWidth : 2,//设置码块宽度 1~16像素将影响最终条码的总宽度 默认值2
barHeight : 140,//设置条码高度 1~255像素将影响最终条码的总高度 默认值162
readable : "POS_THREE", //设置HRI位 默认值POS_TWO条码下方 HIDE隐藏, POS_ONE条码上方, POS_TWO条码下方, POS_THREE条码上下
symbology : "code128",//设置条码类型 默认值code128
// width : 0,//生成条码指定缩放宽度 当设置缩放宽度后将强制改变码内容大小 默认值不缩放
// height : 0,//生成条码指定缩放高度 当设置缩放高度后将强制改变码内容大小 默认值不缩放
},
qrStyle:{
align : "center", //设置二维码行内对齐方式 默认居左
dot : 4,//设置二维码块大小 1~16像素最终将影响二维码大小 默认值4
errorLevel : "L",//设置二维码纠错等级 默认值
width:140,//生成二维码指定缩放宽度 当设置缩放宽度后将强制改变码内容大小 默认值不缩放
height:140,//生成二维码指定缩放高度 当设置缩放高度后将强制改变码内容大小 默认值不缩放
},
bitmapStyle:{
algorithm : "BINARIZATION",//设置图片转换方式 BINARIZATION二值化算法通过调整浮动值将转换不同彩色值为黑色可根据图片颜色信息调整参数设置浮动值(默认浮动值200) DITHERING 抖动灰度算法不用考虑浮动值变化
align : "default", //设置二维码行内对齐方式 默认居左
value : 200,//设置额外参数
width : 200,//图片缩放宽度 当设置缩放宽度后将强制改变图片大小 默认值不缩放
height : 200,//图片缩放高度 当设置缩放宽度后将强制改变图片大小 默认值不缩放
}
}
},
methods: {
//初始化打印机
initPrinter(){
initPrinter()
},
//打开钱箱
cashOpen(){
let data = cashOpen()
console.log('cashOpen--->',printInfo.name);
},
//获取打印机信息
getPrinterInfo(){
// {
// "paper":"576",//打印机当前支持的纸张可打印区域
// "distance":"248116",//打印机已经打印的距离
// "name":"商米内置打印机",//打印机名称
// "id":"1E04363437370A0130343734",//打印机硬件版本号
// "type":"black mark printer",//打印机类型
// "version":"2.13"//打印机固件版本号
// }
let printInfo = getPrinterInfo()
console.log('printInfo--->',printInfo.name);
},
//打印测试小票
printTestTicket(){
printText({text:util.formatTime(new Date())})
printDividingLine({style:'DOTTED',offset:1,marginBottom:30})
printText({text:'喜来乐餐厅',textStyle:{align:'center',textSize:22,enableBold:false}})
printText({text:'预结单',textStyle:{align:'center',textSize:50,enableBold:true}})
printText({text:'桌台14',textStyle:{align:'center',textSize:26,enableBold:true}})
printDividingLine({style:'EMPTY',offset:30})
printDividingLine({style:'DOTTED',offset:1})
printDividingLine({style:'EMPTY',offset:30})
printText({text:'订单号:FBD174659454555648464',textStyle:{textSize:26,enableBold:false}})
printText({text:'开台时间:'+util.formatTime(new Date()),textStyle:{textSize:26,enableBold:false}})
printText({text:'用餐人数:5',textStyle:{textSize:26,enableBold:false}})
printText({text:'收银员:18545263654',textStyle:{textSize:26,enableBold:false}})
fillAround('菜品')
printTexts({
texts:['菜品名称','数量','价格'],
colsWidthArrs:[3,1,1],
textStyles:[{textSize:30,enableBold:true},{textSize:30,enableBold:true},{textSize:30,enableBold:true}],
})
printDividingLine({style:'EMPTY',offset:10})
printTexts({
texts:['尖椒肉丝黄焖鸡饭','x3','139.5'],
colsWidthArrs:[3,1,1],
textStyles:[{align:'left',textSize:26},{align:'left',textSize:26},{align:'left',textSize:26}]
})
printText({
text:'规格:大份、加辣、不要洋葱、米饭多一点'
})
printDividingLine({style:'EMPTY',offset:10})
printTexts({
texts:['美式咖啡','x10','339.0'],
colsWidthArrs:[3,1,1],
textStyles:[{align:'left',textSize:26},{align:'left',textSize:26},{align:'left',textSize:26}]
})
printText({
text:'规格:加牛奶、加糖、加冰',
textStyle:{align:'left',enableBold:false,textSize:24}
})
fillLine()
printTexts({
texts:['合计:','¥1965.23'],
colsWidthArrs:[1,1],
textStyles:[{align:'left',textSize:30,enableBold:true},{align:'right',textSize:30,enableBold:true}]
})
fillLine()
printTexts({
texts:['应付:','¥965.23'],
colsWidthArrs:[1,1],
textStyles:[{align:'left',textSize:30,enableBold:true},{align:'right',textSize:30,enableBold:true}]
})
printDividingLine({style:'DOTTED',offset:1,marginTop:30,marginBottom:30})
printText({text:'谢谢惠顾',textStyle:{align:'center',textSize:30,enableBold:true}})
printDividingLine({style:'EMPTY',offset:60})
autoOut()
},
//切刀
autoOut(){
let data = autoOut()
console.log('autoOut--->',data);
},
//打印图片 base64格式
printBitmap(){
let data = printBitmap({
base64:"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",
bitmapStyle:{
algorithm : "BINARIZATION",//设置图片转换方式 BINARIZATION二值化算法通过调整浮动值将转换不同彩色值为黑色可根据图片颜色信息调整参数设置浮动值(默认浮动值200) DITHERING 抖动灰度算法不用考虑浮动值变化
align : "center", //设置二维码行内对齐方式 默认居左
value : 200,//设置额外参数
width : 100,//图片缩放宽度 当设置缩放宽度后将强制改变图片大小 默认值不缩放
height : 100,//图片缩放高度 当设置缩放宽度后将强制改变图片大小 默认值不缩放
}
})
console.log('printBitmap--->',data);
printDividingLine({style:'EMPTY',offset:60})
autoOut()
},
//打印分割线
printDividingLine(){
//EMPTY空白 SOLID实线 DOTTED点线
//分割线的显示高度(单位:像素)
let data = printDividingLine({style:'DOTTED',offset:1})
console.log('printDividingLine--->',data);
},
//打印二维码
printQrCode(){
let data = printQrCode({
code:'QrCode001233565',
qrStyle:this.qrStyle
})
console.log('printQrCode--->',data);
//也可以不写样式,全部采用默认
printQrCode({code:'QrCode001233565'})
},
//打印条形码
printBarCode(){
let data = printBarCode({
code:'LD1923446846165',
barcodeStyle:this.barcodeStyle
})
console.log('printBarCode--->',data);
//也可以不写样式,全部采用默认
printBarCode({code:'LD1923446846165'})
},
//打印按列排列打印内容
printTexts(){
let data = printTexts({
texts:['菜品名称','数量','价格'],
colsWidthArrs:[3,1,1],
textStyles:[
{align:'left',textSize:30,enableBold:true},
{align:'right',textSize:30,enableBold:true},
{align:'left',textSize:30,enableBold:true},
]
})
console.log('printTexts--->',data);
//也可以不写样式,全部采用默认 colsWidthArrs默认是1:1:1
printTexts({texts:['菜品名称','数量','价格']})
},
//打印文本
printText(){
let data = printText({text:'这是一条测试信息1',textStyle:this.textStyle})
console.log('printText--->',data);
//也可以不写样式,全部采用默认
printText({text:'这是一条测试信息2'})
fillAround('菜品')
fillLine()
},
//关闭打印机
closePrinter(){
let data = closePrinter()
console.log('closePrinter--->',data);
}
}
}
</script>
util工具
const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
module.exports = {
formatTime: formatTime
}