技术要点总结
- uniApp开发大屏安卓系统
- 通过usb连接58打印机
- 发送打印指令,进行小票打印
uni-app开发大屏安卓系统注意点
- 开发大屏时,可以不拘泥于原有的单位rpx,可以直接使用px进行大屏适配
- 博主因单位问题想了各种适配方案,最终突破了枷锁,直接使用了px,因为收银机是统一配置的(joke)
通过usb连接58打印机
发送打印指令,进行小票打印,保存即可使用(EscPosUtil.js)
class Esc {
constructor(arg) {
// 打印机纸宽58mm,页的宽度384,字符宽度为1,每行最多盛放32个字符
// 打印机纸宽80mm,页的宽度576,字符宽度为1,每行最多盛放48个字符
this.PAGE_WIDTH = 576
this.MAX_CHAR_COUNT_EACH_LINE = 48
}
//字符串转字节序列
stringToByte(str) {
var bytes = new Array()
var len, c
len = str.length
for (var i = 0
c = str.charCodeAt(i)
if (c >= 0x010000 && c <= 0x10FFFF) {
bytes.push(((c >> 18) & 0x07) | 0xF0)
bytes.push(((c >> 12) & 0x3F) | 0x80)
bytes.push(((c >> 6) & 0x3F) | 0x80)
bytes.push((c & 0x3F) | 0x80)
} else if (c >= 0x000800 && c <= 0x00FFFF) {
bytes.push(((c >> 12) & 0x0F) | 0xE0)
bytes.push(((c >> 6) & 0x3F) | 0x80)
bytes.push((c & 0x3F) | 0x80)
} else if (c >= 0x000080 && c <= 0x0007FF) {
bytes.push(((c >> 6) & 0x1F) | 0xC0)
bytes.push((c & 0x3F) | 0x80)
} else {
bytes.push(c & 0xFF)
}
}
return bytes
}
//字节序列转ASCII码
//[0x24, 0x26, 0x28, 0x2A] ==> "$&C*"
byteToString(arr) {
if (typeof arr === 'string') {
return arr
}
var str = '',
_arr = arr
for (var i = 0
var one = _arr[i].toString(2),
v = one.match(/^1+?(?=0)/)
if (v && one.length == 8) {
var bytesLength = v[0].length
var store = _arr[i].toString(2).slice(7 - bytesLength)
for (var st = 1
store += _arr[st + i].toString(2).slice(2)
}
str += String.fromCharCode(parseInt(store, 2))
i += bytesLength - 1
} else {
str += String.fromCharCode(_arr[i])
}
}
return str
}
//居中
Center() {
var Center = []
Center.push(27)
Center.push(97)
Center.push(1)
var strCenter = this.byteToString(Center)
return strCenter
}
//居左
Left() {
var Left = []
Left.push(27)
Left.push(97)
Left.push(0)
var strLeft = this.byteToString(Left)
return strLeft
}
//居右
Right() {
var right = []
right.push(27)
right.push(97)
right.push(2)
var strRight = this.byteToString(right)
return strRight
}
//标准字体
Size1() {
var Size1 = []
Size1.push(29)
Size1.push(33)
Size1.push(0)
var strSize1 = this.byteToString(Size1)
return strSize1
}
//大号字体
/* 放大1倍 n = 0
* 长宽各放大2倍 n = 17 */
Size2(n) {
var Size2 = []
Size2.push(29)
Size2.push(33)
Size2.push(n)
var strSize2 = this.byteToString(Size2)
return strSize2
}
// 字体加粗
boldFontOn() {
var arr = []
arr.push(27)
arr.push(69)
arr.push(1)
var cmd = this.byteToString(arr)
return cmd
}
// 取消字体加粗
boldFontOff() {
var arr = []
arr.push(27)
arr.push(69)
arr.push(0)
var cmd = this.byteToString(arr)
return cmd
}
// 打印并走纸n行
feedLines(n = 1) {
var feeds = []
feeds.push(27)
feeds.push(100)
feeds.push(n)
var printFeedsLines = this.byteToString(feeds)
return printFeedsLines
}
// 切纸
cutPaper() {
var cut = []
cut.push(29)
cut.push(86)
cut.push(49)
var cutType = this.byteToString(cut)
return cutType
}
// 开钱箱
open_money_box() {
var open = []
open.push(27)
open.push(112)
open.push(0)
open.push(60)
open.push(255)
var openType = this.byteToString(open)
return openType
}
// 初始化打印机
init() {
var arr = []
arr.push(27)
arr.push(68)
arr.push(0)
var str = this.byteToString(arr)
return str
}
/*
设置左边距
len:
*/
setLeftMargin(len = 1) {
var arr = []
arr.push(29)
arr.push(76)
arr.push(len)
var str = this.byteToString(arr)
return str
}
// 设置打印区域宽度
setPrintAreaWidth(width) {
var arr = []
arr.push(29)
arr.push(87)
arr.push(width)
var str = this.byteToString(arr)
return str
}
/**
* @param str
* @returns {boolean} str是否全是中文
*/
isChinese(str) {
return /^[\u4e00-\u9fa5]$/.test(str)
}
// str是否全含中文或者中文标点
isHaveChina(str) {
if (escape(str).indexOf("%u") < 0) {
return 0
} else {
return 1
}
}
/**
* 返回字符串宽度(1个中文=2个英文字符)
* @param str
* @returns {number}
*/
getStringWidth(str) {
let width = 0
for (let i = 0, len = str.length
width += this.isHaveChina(str.charAt(i)) ? 2 : 1
}
return width
}
/**
* 同一行输出str1, str2,str1居左, str2居右
* @param {string} str1 内容1
* @param {string} str2 内容2
* @param {string} fillWith str1 str2之间的填充字符
* @param {number} fontWidth 字符宽度 1/2
*
*/
inline(str1, str2, fillWith = ' ', fontWidth = 1) {
const lineWidth = this.MAX_CHAR_COUNT_EACH_LINE / fontWidth
// 需要填充的字符数量
let fillCount = lineWidth - (this.getStringWidth(str1) + this.getStringWidth(str2)) % lineWidth
let fillStr = new Array(fillCount).fill(fillWith.charAt(0)).join('')
return str1 + fillStr + str2
}
/**
* 用字符填充一整行
* @param {string} fillWith 填充字符
* @param {number} fontWidth 字符宽度 1/2
*/
fillLine(fillWith = '-', fontWidth = 1) {
const lineWidth = this.MAX_CHAR_COUNT_EACH_LINE / fontWidth
return new Array(lineWidth).fill(fillWith.charAt(0)).join('')
}
/**
* 文字内容居中,左右用字符填充
* @param {string} str 文字内容
* @param {number} fontWidth 字符宽度 1/2
* @param {string} fillWith str1 str2之间的填充字符
*/
fillAround(str, fillWith = '-', fontWidth = 1) {
const lineWidth = this.MAX_CHAR_COUNT_EACH_LINE / fontWidth
let strWidth = this.getStringWidth(str)
// 内容已经超过一行了,没必要填充
if (strWidth >= lineWidth) {
return str
}
// 需要填充的字符数量
let fillCount = lineWidth - strWidth
// 左侧填充的字符数量
let leftCount = Math.round(fillCount / 2)
// 两侧的填充字符,需要考虑左边需要填充,右边不需要填充的情况
let fillStr = new Array(leftCount).fill(fillWith.charAt(0)).join('')
return fillStr + str + fillStr.substr(0, fillCount - leftCount)
}
}
export default Esc
操作流程
const usbPrinterModule = uni.requireNativePlugin('singplugin-usbPrinter');
import EscPosUtil from '@/common/utils/EscPosUtil.js';
const globalEvent = uni.requireNativePlugin('globalEvent');
usbPrinterModule.initUSBPrinter((e) => {
console.log('打印机初始化==>' + JSON.stringify(e));
if (e.code === 'ok') {
this.connectusbPrint(initFlg);
return;
}
if (e.result === '请勿重复初始化') {
this.connectusbPrint(initFlg);
return;
}
if (!initFlg) this.toast('error', e.result);
});
connectusbPrint(initFlg) {
if (this.usbPrinterConnectFlg) return this.doPrint();
usbPrinterModule.connectUSBPrinter((e) => {
console.log('打印机连接==>' + JSON.stringify(e));
if (e.code !== 'ok') {
} else {
this.usbPrinterConnectFlg = true;
if (!initFlg) this.doPrint();
this.bindPluginEvent();
}
});
},
doPrintDeal(orderNo = '', payPrice = '', data, flg = '') {
data = [
{ name: '杏花村清香型白酒 53度5斤装 送礼佳品 纯粮食酒', num: 1, price: 10 },
{ name: '西凤6年52度500ml', num: 12, price: 100 },
{ name: '西凤酒年份封坛10年45度单瓶(500mlX1)', num: 99, price: 999.99 }
];
let Esc = new EscPosUtil();
let strCmd = Esc.Center() + Esc.Size2(16) + Esc.boldFontOn() + this.userInfo.realName + flg + '\n';
strCmd += Esc.boldFontOff() + Esc.Size1() + Esc.fillLine('-', 1.5) + '\n';
strCmd += Esc.Size1() + '商品名称 总额(数量)' + '\n';
strCmd += Esc.fillLine('-', 1.5) + '\n';
data.forEach((item) => {
strCmd += Esc.Left() + item.name + '\n';
strCmd += Esc.Right() + '¥' + item.price + '(' + item.num + ')\n\n';
});
strCmd += Esc.fillLine('-', 1.5) + '\n';
strCmd += Esc.Left() + '订单编号:' + orderNo + '\n';
strCmd += Esc.Left() + '打印时间:' + dateDeal.dateFormat('Y-m-d H:i:s') + '\n';
strCmd += Esc.Left() + '支付金额:¥' + payPrice + '\n';
strCmd += Esc.fillLine('-', 1.5) + '\n';
strCmd += Esc.Center() + '欢迎您下次光临!' + '\n';
strCmd += Esc.feedLines(1) + '\n\n';
usbPrinterModule.printText(
{
text: strCmd,
encoding: 'GBK'
},
(e) => {
console.log(e);
if (e.code != 'ok') {
this.toast('error', e.result);
}
}
);
},
踩坑指南
- 自动初始化的时候,在onReady的时候,最好先运行一次初始化代码,这样可以提高点击打印按钮的通过率
- 打印指令可以直接使用,上述EscPosUtil.js模块,这个地方可自行进行完善