uniapp 标签打印 笔记

连接蓝牙

  • 初始化蓝牙模块、找到对应连接的打印机 Bluetooth
  • 连接蓝牙 BLE
  • 找到支持写入数据 write、订阅变化 notify的特征值 characteristic

打印

  • 根据打印机提供API,拼接打印指令
    SIZE 40 mm,20 mm\r\n
    GAP 2 mm,0 mm\r\n
    CLS\r\n
    QRCODE 12,28,L,3,A,0,"http://172.16.0.20:15016?O22CdW14$A00002073106"\r\n
    TEXT 116,32,"3",0,1,1,"6233"\r\n
    TEXT 116,64,"3",0,1,1,"220704SK1001"\r\n
    TEXT 116,96,"3",0,1,1,"0"\r\n
    PRINT 1,1\r\n
    
  • 一张一张标签发送打印指令
  • 打印指令发送失败,记录索引下标,标签打印指令全部发送完成,弹窗提示是否重新打印失败的标签。
  • 标签发送失败 failArr记录下标,上一张标签发送指令失败(发送的指令不知在哪个位置发生截断),在数组起始位置添加换行符\r\n,使下一张标签的指令生效(都是记录思路的伪代码!
    /**
     * @param {Array} printData 需要打印的数据数组, 一项代表一张标签
     */
    async function _print (printData = []) {
    	const number = 1,	// 几张标签调用函数发送一次打印指令
    		failArr = [];	// 记录失败的标签
    	let command = [],
    		num = 0,
    		percentage = 0;	// 进度
    	for (let i = 0, len = printData.length; i < len; i++) {
    		command = [...];	// ... 拼接打印指令 调用打印机API转为数组
    		num++;
    		if ((number === num) || ((i === len - 1) && num > 0)) {
    			// 发送打印指令
    			const arr = await handleSend(i - number + 1, i, command);	// 调用函数发送打印指令
    			if (arr.length) {
    				// 打印指令发送失败 记录索引下标
    				failArr.push(...arr);
    			}
    			// 重新记录打印指令
    			num = 0;
    			command = [];
    			if (arr.length) {
    				// 上一张标签的打印指令发送失败, 在下一张标签起始位置添加换行符, 使CLS生效
    				command.push(...);	// EOL
    			}
    		}
    		percentage = Math.ceil((i + 1) / len * 100);	// 更新进度
    	}
    	if (failArr.length) {
    		// 处理发送失败的标签
    		const arr = printData.filter((item, index) => (failArr.indexOf(index) != -1));
    		// 弹窗提示:以下编号的标签打印失败:8、16,是否需要重新打印?
    		// 如果用户选择重新打印
    		return this._print(arr);
    	}
    }
    
  • 发送打印指令(number张标签)
  • 若打印指令发送失败,手动添加换行符\r\n,使CLS生效,重试3次
  • 若发送失败,返回打印指令发送失败的索引下标
    async function handleSend(begin, end, command) {
    	const retryCount = 3;	// 定义重试次数
    	let complete = false,	// 是否打印完成
    		tryNum = 0;			// 尝试打印次数
    	while (!complete && (tryNum < (retryCount + 1))) {
    		tryNum++;
    		if (tryNum == 2) {
    			// 指令发送失败 直接结束循环 重新发送打印指令(尝试打印的第2次)
    			// 在数组起始位置添加换行符 (使CLS生效)
    			command.unshift(...);	// EOL
    		}
    		const hasFail = await send(command);
    		if (hasFail) {
    			console.log('--- 重新打印 --->', end);
    		}
    		complete = !hasFail;
    	}
    	const arr = [];
    	if (!complete) {
    		for (let j = begin; j <= end; j++) {
    			arr.push(j);	// 打印指令发送失败的标签索引
    		}
    	}
    	return arr;
    }
    
  • 分包发送打印指令:若某次指令发送失败,直接结束循环,结束函数
  • 通过蓝牙写入数据发送打印指令,官网建议每次写入不超过20字节 oneTimeData
    async function send(buff) {
    	const oneTimeData = 20,	// 每次发送字节数
    		printNum = 1;		// 打印份数
    	const loopTime = Math.ceil(buff.length / oneTimeData),	// 一份发送几次 = buff / 每次发送字节数
    		lastData = parseInt(buff.length % oneTimeData);
    	for (let i = 0; i < printNum; i++) {	// printNum 份
    		// 第 i 份
    		for (let j = 0; j < loopTime; j++) {		// 循环发送
    			// 分包发送的第 j 次
    			const size = (j == loopTime - 1 && lastData > 0) ? lastData : oneTimeData;	// 是否余数 ? lastData : 每次发送字节数
    			const buf = new ArrayBuffer(size);
    			const dataView = new DataView(buf);
    			for (let k = 0; k < size; k++) {
    				const index = j * oneTimeData + k;
    				dataView.setUint8(k, buff[index]);
    			}
    			const flag = await handleSendItem(buf, j, loopTime);
    			if (!flag) {
    				console.warn(`fail: 发送的第${j}次, 共发送${loopTime}次 (经多次重试失败)`);
    				// 指令发送失败 直接结束循环 不继续往后发
    				return true;
    			}
    		}
    	}
    	return false;
    }
    
  • 问题:不确定哪次指令发送失败,直接结束循环,可能导致打印机走纸,但是没有打印内容,也可能中间几张标签丢失(没想明白原因)
  • 解决方法:
    • handleSendItem函数内部添加逻辑,如果某个包(20字节)发送失败,这个包重试3次。
    • 若仍旧失败,再走之前逻辑,问题依旧在,只是概率小
    async function handleSendItem(buf, j, loopTime) {
    	const retryCount = 3;	// 定义重试次数
    	let complete = false,	// 指令是否发送完成
    		tryNum = 0;			// 尝试发送次数
    	while (!complete && (tryNum < (retryCount + 1))) {
    		tryNum++;
    		if (tryNum > 1) {
    			console.log('重新发送这个包', tryNum);
    		}
    		// 调用 uni.writeBLECharacteristicValue 向低功耗蓝牙设备特征值中写入二进制数据 发送打印指令
    		const flag = await writeBLECharacteristicValue(buf);
    		if (!flag) {
    			console.warn(`fail: 发送的第${j}次, 共发送${loopTime}`);
    		}
    		complete = flag;
    	}
    	return complete;
    }
    

流程图

流程图:标签打印(语雀)

问题

  • 某一张标签指令发送失败,直接结束循环,重新发送指令,或直接发送下一张标签指令
    • 往数组前添加换行符EOL使CLS生效,可能导致空标签、几张标签漏打印
  • 解决方法:
    • 某个包发送失败,这个包重新发送,重试三次
    • 若仍旧失败,走之前流程(结束循环,发送下一张标签指令)
    • 问题依旧在,只是概率小 ~( TロT)σ

优化

  • handleSendhandleSendItem 通过调用函数 _try 传入参数tryNum(重试次数)、fn(处理函数)处理重试逻辑
    function isPromise(obj) {
    	return obj instanceof Promise;
    	// return (!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function');
    }
    
    /**
     * 传入参数tryNum(重试次数)、fn(处理函数)处理重试逻辑
     * @param {Function} fn 处理函数 返回Boolean(是否成功); 或者返回Promise, thenable返回状态数据Boolean(是否成功)
     * @param {Number} retryCount 重试次数
     * @returns {Promise} 是否执行成功
     */
    async function _try(fn, retryCount = 3) {
    	if (retryCount < 0) {
    		console.warn('retryCount must be greater than 0');
    		retryCount = 0;
    	}
    	let tryNum = 0, // 执行次数
    		complete = false; // 是否完成
    	while (!complete && (tryNum < (retryCount + 1))) {
    		tryNum++;
    		if (tryNum > 1) {
    			console.log(`重试第${tryNum - 1}`);
    		}
    		let result = fn.call(this, tryNum);
    		if (isPromise(result)) {
    			result = await result;
    		}
    		if (result) { // 执行成功
    			complete = true;
    		}
    	}
    	return complete;
    }
    
  • 优化 handleSend
    async function handleSend(begin, end, command) {
        const complete = await _try(async (tryNum) => {
        	// 处理函数
            if (tryNum == 2) {
                // 指令发送失败 直接结束循环 重新发送打印指令(尝试打印的第2次)
                // 在数组起始位置添加换行符 (使CLS生效)
                command.unshift(...); // EOL
            }
            const hasFail = await send(command);
            return !hasFail;
        }, 3); // 重试3次
        const arr = [];
        if (!complete) {
            for (let j = begin; j <= end; j++) {
                arr.push(j); // 打印指令发送失败的标签索引
            }
        }
        return arr;
    }
    
  • 优化 handleSendItem
    async function handleSendItem(buf, j, loopTime) {
        const complete = await _try(() => {
            // 调用 uni.writeBLECharacteristicValue 向低功耗蓝牙设备特征值中写入二进制数据 发送打印指令
            const flag = await writeBLECharacteristicValue(buf);
            if (!flag) {
                console.warn(`fail: 发送的第${j}次, 共发送${loopTime}`);
            }
            return flag;
        }, 3); // 重试3次
        return complete;
    }
    
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值