更多文章请访问 深的个人博客

最近开发的一个小程序里需要对接热敏打印机打印小票,在此记录一下对接的过程

项目开发注意点:
1、因为项目中有多个页面的数据是需要进行打印的,为了保持蓝牙的连接状态和数据,所以连接蓝牙的操作和数据会在vuex里面进行统一管理。
2、打印模板会统一进行管理
3、打印数据前需要对上一次打印的数据进行清理 使用 printerJobs 对象里的 clear() 方法实现清理数据
4、在原有的sdk上增加三列打印的方法

技术栈

uni-app

参考资料

微信小程序蓝牙打印

项目效果图

打印效果图


项目结构

只展示主要项目结构

项目页面讲解

vuex相关文件讲解

蓝牙连接:connect.js
/*** 连接蓝牙*/
function inArray(arr, key, val) {for (let i = 0; i < arr.length; i++) {if (arr[i][key] === val) {return i}}return -1
}export default {namespaced: true,  // 开启命名空间state: {devices: [], // 搜索到的蓝牙设备connected: false, // 是否连接discoveryStarted: false, // 是否开始搜索蓝牙name: "", // 连接到的蓝牙设备名称deviceId: "", // 连接到的蓝牙设备的deviceIdcanWrite: false,_deviceId: "", // 连接到的蓝牙设备的deviceId_serviceId: "", // 连接到的蓝牙设备的seviceId_characteristicId: "", // 连接到的蓝牙设备的characteristicId},getters: {getDevices: state => state.devices,getName: state => state.name,getConnected: state => state.connected,getDiscoveryStarted: state => state.discoveryStarted,getConnectDeviceId: state => state._deviceId,getServiceId: state => state._serviceId,getCharacteristicId: state => state._characteristicId},mutations: {// 初始化连接initConnect(state) {state.devices = []if (!uni.openBluetoothAdapter) {uni.showModal({title: '提示',content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'})return}uni.openBluetoothAdapter({success: (res) => {console.log('openBluetoothAdapter success', res)this.commit('connect/startBluetoothDevicesDiscovery')},fail: (res) => {console.log('openBluetoothAdapter fail', res)if (res.errCode === 10001) {uni.showModal({title: '错误',content: '未找到蓝牙设备, 请打开蓝牙后重试。',showCancel: false})uni.onBluetoothAdapterStateChange((res) => {console.log('onBluetoothAdapterStateChange', res)if (res.available) {// 取消监听,否则stopBluetoothDevicesDiscovery后仍会继续触发onBluetoothAdapterStateChange,// 导致再次调用startBluetoothDevicesDiscoveryuni.onBluetoothAdapterStateChange(() => {});this.commit('connect/startBluetoothDevicesDiscovery')}})}}})uni.onBLEConnectionStateChange((res) => {// 该方法回调中可以用于处理连接意外断开等异常情况console.log('onBLEConnectionStateChange',`device ${res.deviceId} state has changed, connected: ${res.connected}`)// this.setData({//   connected: res.connected// })state.connected = res.connectedif (!res.connected) {uni.showModal({title: '错误',content: '蓝牙连接已断开',showCancel: false})}});},getBluetoothAdapterState(state) {uni.getBluetoothAdapterState({success: (res) => {console.log('getBluetoothAdapterState', res)if (res.discovering) {this.commit('connect/onBluetoothDeviceFound')} else if (res.available) {this.commit('connect/startBluetoothDevicesDiscovery')}}})},// 开启蓝牙搜索startBluetoothDevicesDiscovery(state) {if (state.discoveryStarted) {return}state.discoveryStarted = trueuni.startBluetoothDevicesDiscovery({success: (res) => {this.commit('connect/onBluetoothDeviceFound')},fail: (res) => {console.log('startBluetoothDevicesDiscovery fail', res)}})},// 停止搜索蓝牙stopBluetoothDevicesDiscovery(state) {uni.stopBluetoothDevicesDiscovery({complete: () => {console.log('complete,stopBluetoothDevicesDiscovery')state.discoveryStarted = falseconsole.log(this.discoveryStarted)}})},// 搜索蓝牙onBluetoothDeviceFound(state) {uni.onBluetoothDeviceFound((res) => {console.log("搜索到的蓝牙", res.devices)res.devices.forEach(device => {if (!device.name && !device.localName) {return}const idx = inArray(state.devices, 'deviceId', device.deviceId)if (idx === -1) {state.devices.push(device)}})})},// 连接蓝牙 1createBLEConnection(state, item) {console.log("连接的设备", item)this.commit("connect/next_createBLEConnection", {deviceId: item.deviceId,name: item.name})},// 连接蓝牙 2next_createBLEConnection(state, equipment) {let {deviceId,name} = equipmentuni.showLoading()uni.createBLEConnection({deviceId,success: () => {console.log('createBLEConnection success');state.name = namestate.connected = truestate.deviceId = deviceIdconsole.log("连接的设备", state.name)this.commit("connect/getBLEDeviceServices", deviceId)uni.setStorageSync('LAST_CONNECTED_DEVICE', name + ":" + deviceId)},complete() {uni.hideLoading()},fail: (res) => {console.log('createBLEConnection fail', res)}})this.commit("connect/stopBluetoothDevicesDiscovery")},// 断开蓝牙连接closeBLEConnection(state) {uni.closeBLEConnection({deviceId: state.deviceId})state.connected = falsestate.canWrite = falsestate.deviceId = ""state._deviceId= ""state._serviceId= ""state._characteristicId= ""},// 获取蓝牙服务getBLEDeviceServices(state, deviceId) {uni.getBLEDeviceServices({deviceId,success: (res) => {console.log('getBLEDeviceServices', res)for (let i = 0; i < res.services.length; i++) {if (res.services[i].isPrimary) {// this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)this.commit("connect/getBLEDeviceCharacteristics", {deviceId,serviceId: res.services[i].uuid})return}}}})},getBLEDeviceCharacteristics(state, idObject) {let {deviceId,serviceId} = idObjectuni.getBLEDeviceCharacteristics({deviceId,serviceId,success: (res) => {console.log('getBLEDeviceCharacteristics success', res.characteristics)// 这里会存在特征值是支持write,写入成功但是没有任何反应的情况// 只能一个个去试for (let i = 0; i < res.characteristics.length; i++) {const item = res.characteristics[i]if (item.properties.write) {// this.setData({//     canWrite: true// })state.canWrite = truestate._deviceId = deviceIdstate._serviceId = serviceIdstate._characteristicId = item.uuidbreak;}}},fail(res) {console.error('getBLEDeviceCharacteristics', res)}})},closeBluetoothAdapter(state) {uni.closeBluetoothAdapter()state.discoveryStarted = falseconsole.log("关闭蓝牙")},},actions: {}
}
打印数据:print.js

打印数据:页面传递过来的要打印的数据是一个对象,为了避免数据没有及时更新的问题,所以存储这个对象用的是一个数组(printData),这个打印数据会传递到打印模板 (template.js) 中
打印类型 :每个页面都对应一个打印的模板,这个模板存储在 print/printTheTemplat/template.js 文件中,打印的时候会根据传递的打印类型打印相应的模板

/*** 打印的相关数据*/
export default {namespaced: true,state: {printType: "", // 打印类型printData: [], // 打印的数据},getters: {// 获取打印类型getPrintType: state => state.printType,// 获取打印数据getPrintData: state => state.printData},mutations: {// 更新打印数据和打印类型updatePrintData(state, printObj) {let {printData,printType} = printObjconsole.log("接收到的数据", printObj)state.printType = printTypestate.printData = []state.printData.push(printData)}},actions: {}
}

print文件夹相关文件讲解

打印常量 pritConstant.js
// 打印的常量
export const REGISTRATION = "registration" // 退款单/收款单
export const CARSALES = "carSales" // 车销单
export const INVENTORY = "inventory" // 盘点详情
export const DAILY = "daily" // 销售日报
export const CUSTOMER = "customer" //客户汇总
export const COMMODITY = "commodity" // 商品汇总
export const STOCK = "stock" // 库存汇总
打印模板 template.js
// 模板
// printerJobs
//  .print('2018年12月5日17:34')
//  .print(printerUtil.fillLine())
//  .setAlign('ct')
//  .setSize(2, 2)
//  .print('#20饿了么外卖')
//  .setSize(1, 1)
//  .print('切尔西Chelsea')
//  .setSize(2, 2)
//  .print('在线支付(已支付)')
//  .setSize(1, 1)
//  .print('订单号:5415221202244734')
//  .print('下单时间:2017-07-07 18:08:08')
//  .setAlign('lt')
//  .print(printerUtil.fillAround('一号口袋'))
//  .print(printerUtil.inline('意大利茄汁一面 * 1', '15.00'))
//  .print(printerUtil.fillAround('其他'))
//  .print('餐盒费:1')
//  .print('[赠送康师傅冰红茶] * 1')
//  .print(printerUtil.fillLine())
//  .setAlign('rt')
//  .print('原价:¥16.00')
//  .print('总价:¥16.00')
//  .setAlign('lt')
//  .print(printerUtil.fillLine())
//  .print('备注')
//  .print("无")
//  .print(printerUtil.fillLine())
//  .println();
import {REGISTRATION,CARSALES,INVENTORY,DAILY,CUSTOMER,COMMODITY,STOCK
} from "../../utils/pritConstant.js"
const PrinterJobs = require('../sdk/printer/printerjobs.js')
const printerUtil = require('../sdk/printer/printerutil')
let printerJobs = new PrinterJobs();export default {// 收款单[REGISTRATION]: (array) => {console.log("打印接收的数据", array)let data = array[0]let prefix = ""data.order_type == 1 ? prefix = "收款" : prefix = "退款"printerJobs.setAlign('ct').setSize(2, 2).print(`${prefix}单`).lineFeed().setSize(1, 1).setAlign('lt').print(printerUtil.inline(`${prefix}单号`, data.pay_sn)).print(printerUtil.inline('客户名称', data.client_name)).print(printerUtil.fillLine())if (data.order_type == 1) {printerJobs.print(printerUtil.inline(`${prefix}类型`, data.pay_type))}printerJobs.print(printerUtil.inline(`${prefix}金额`, data.pay_money)).print(printerUtil.inline('优惠金额', data.dicount_money)).print(printerUtil.inline(`${prefix}方式`, data.pay_method)).print(printerUtil.inline(`${prefix}时间`, data.pay_time)).print(printerUtil.fillLine()).print(printerUtil.inline('经办人', data.operator)).print(printerUtil.inline('提交人', data.userName)).print(printerUtil.inline('提交日期', data.created_at)).print(printerUtil.fillLine()).print('审批历程')data.log_list.forEach(item => {printerJobs.print(item.username + '' + item.contents)})printerJobs.print(printerUtil.doubleFillLine()).print('业代签字').lineFeed(2).println();return {buffer: printerJobs.buffer(),printerJobs};},// 车销单[CARSALES]: (array) => {let data = array[0]printerJobs.setAlign('ct').setSize(2, 2).print('车销单').lineFeed().setSize(1, 1).setAlign('lt').print(printerUtil.inline('客户名称', data.shopClient.username)).setBold(false).print(printerUtil.inline('状态', data.status_name)).print(printerUtil.inline('销售单编号', data.order_sn)).print(printerUtil.inline('提交日期', data.created_at)).print(printerUtil.inline('客户经理', data.member.username)).print(printerUtil.doubleFillLine()).print(printerUtil.inline('销售清单', `共${data.products_list.length}种`))data.products_list.forEach(item => {printerJobs.print(item.product_name).print(printerUtil.inline(`   数量:${item.num}`, `单价:${item.price}`)).print(`   金额:${(item.price * 1 * item.num)}`)})printerJobs.print(printerUtil.fillLine()).print(printerUtil.inline('销售金额', `${data.pay_money}`)).print(printerUtil.inline('退货金额', `${ data.refuned_money}`)).print(printerUtil.inline('本单应收', `${data.remain_money}`)).print(printerUtil.fillLine()).print('收款记录').print(printerUtil.inline('记录数量', `${data.log_list.length}`))// .print(printerUtil.inline('收款核销', '230.00'))// .print(printerUtil.inline('欠款', '230.00')).print(printerUtil.doubleFillLine()).print('业代签字').lineFeed(2).println();return {buffer: printerJobs.buffer(),printerJobs};},// 盘点详情[INVENTORY]: (array) => {let data = array[0]let {products_list,log_list} = datalet status = ""data.status == 0 ? status = "待审批" : data.status == 1 ? status = "已通过" : status = "作废"let range = data.order_type && data.order_type == 2 ? "部分盘点" : "全部盘点"printerJobs.setAlign('ct').setSize(2, 2).print('盘点详情').lineFeed().setSize(1, 1).setAlign('lt').print(printerUtil.inline('盘点单号', `${data.order_sn}`)).print(printerUtil.inline('盘点人员', `${data.member.username}`)).print(printerUtil.inline('状态', `${status}`)).print(printerUtil.inline('盘点范围', `${range}`)).print(printerUtil.inline('提交日期', `${data.created}`)).print(printerUtil.fillLine()).print("商品清单")products_list.forEach(item => {printerJobs.print(`${item.product_name}`).print(printerUtil.inline(`  账面:${item.num}`, `实盘:${item.diff_num}`))})if (log_list.length > 0) {printerJobs.print(printerUtil.fillLine()).print('审批历程')log_list.forEach(item => {printerJobs.print(`${item.username} ${item.created_at} [${item.contents}]`)})} else {printerJobs.print(printerUtil.fillLine()).print('审批历程(暂无)')}printerJobs.print(printerUtil.doubleFillLine()).print('业代签字').lineFeed(2).println();return {buffer: printerJobs.buffer(),printerJobs};},// 日报汇总[DAILY]: (array) => {let data = array[0]printerJobs.setAlign('ct').setSize(2, 2).print('销售日报').lineFeed().setSize(1, 1).setAlign('lt').setUnderline(true).print(`日期:${data.date}`).print(printerUtil.doubleFillLine()).setUnderline(false).print(printerUtil.inline('销售金额', `${data.incomeTotal}`)).print(printerUtil.inline('其中:销售金额', `${data.salesTotal}`)).print(printerUtil.inline('     退货金额', `${data.returndTotal}`)).print(printerUtil.fillLine()).print(printerUtil.inline('应收金额', `${data.remainTotal}`)).print(printerUtil.fillLine()).print(printerUtil.inline('收款金额', `${data.payTotal}`)).print(printerUtil.inline('收款优惠', `${data.dicountTotal}`)).print(printerUtil.inline('支出费用', `${data.debtTotal}`)).print(printerUtil.fillLine()).print(`打印时间:${format(new Date(),"full")}`).print(printerUtil.doubleFillLine()).print('业代签字').lineFeed().println();return {buffer: printerJobs.buffer(),printerJobs};},// 库存汇总[STOCK]: array => {printerJobs.setAlign('ct').setSize(2, 2).print('库存汇总').lineFeed().setSize(1, 1).setAlign('lt').setUnderline(true).print('日期:2021-07-19   仓库:一号仓库').print(printerUtil.doubleFillLine()).print(printerUtil.inline('正常品清单', '共0家')).print(printerUtil.fillLine()).print(printerUtil.centerInline('白酒商品名称', '库存量', '金额')).print(printerUtil.centerInline('白酒', '2000', '0.35')).print(printerUtil.centerInline('白酒', '2000', '5000')).print(printerUtil.centerInline('燕京330吉祥红佳节订单', '1000', '7000')).print(printerUtil.fillLine()).print(printerUtil.inline('合计', '0.35')).print('打印时间:2021-07-19 17:34').print('业务员:张三').print(printerUtil.doubleFillLine()).print('业代签字').lineFeed().lineFeed().println();return {buffer: printerJobs.buffer(),printerJobs};}
}// 时间处理
function format(shijianchuo, type) {//shijianchuo是整数,否则要parseInt转换var time = new Date(shijianchuo);var y = time.getFullYear();var m = time.getMonth() + 1;var d = time.getDate();var h = time.getHours();var mm = time.getMinutes();var s = time.getSeconds();if (type == "full") {return y + '-' + add0(m) + '-' + add0(d) + ' ' + add0(h) + ':' + add0(mm) + ':' +add0(s);} else {return y + '-' + add0(m) + '-' + add0(d);}
}function add0(m) {return m < 10 ? '0' + m : m
}
sdk相关讲解

具体sdk可以下载 github上的代码,这里只展示在printerutil.js文件中添加的几个方法

/*** 一排三列* 同一行输出str1, str2,str3,str1居左, str2居中偏右,str3居右* @param {string} str1 内容1 固定宽度 占可打印宽度的3/5* @param {string} str2 内容2 * @param {string} str3 内容3* @param {number} fontWidth 字符宽度 1/2* @param {string} fillWith str1 str2之间的填充字符**/
function centerInline(str1, str2, str3, fillWith = ' ', fontWidth = 1) {const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;let newStr1 = setString(str1, 14)console.log("截取的字符", newStr1)console.log("newStr1的字符长度", getStringWidth(newStr1))// 需要填充的字符数量let fillCount = lineWidth - (getStringWidth(newStr1) + getStringWidth(str2) + getStringWidth(str3)) % lineWidth;let leftWidth = Math.round(lineWidth / 5 * 3);console.log("fillcount", fillCount)console.log("左侧的字符长度", getStringWidth(str1))let leftCount = leftWidth - getStringWidth(newStr1) % lineWidthlet rightCount = fillCount - leftCountlet lefFillStr = new Array(leftCount).fill(fillWith.charAt(0)).join('');let rightFillStr = new Array(rightCount).fill(fillWith.charAt(0)).join('');return newStr1 + lefFillStr + str2 + rightFillStr + str3;
}// 截取字符串,多余的部分用...代替
function setString(str, len) {var strlen = 0;var s = "";for (var i = 0; i < str.length; i++) {if (str.charCodeAt(i) > 128) {strlen += 2;} else {strlen++;}s += str.charAt(i);if (strlen >= len) {return s + '...'}}return s;
}
/*** 用 = 字符填充一整行* @param {string} fillWith 填充字符* @param {number} fontWidth 字符宽度 1/2*/
function doubleFillLine(fillWith = '=', fontWidth = 1) {const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;return new Array(lineWidth).fill(fillWith.charAt(0)).join('');
}

打印页面

print.vue

注意点:在调用打印或者是退出页面的时候要清理掉上一次打印的数据,这个可以通过 printerJobs 对象里的 clear() 方法实现清理数据, printerJobs 对象会在调用打印模板的时候返回,这个时候我们需要将printerJobs 对象保存在data中

<template><view class="container"><view class="page-section"><view class="devices-summary my-2 flex items-center"><view>已发现 {{getDevices.length}} 个设备</view><view class="ml-2" v-if="getDiscoveryStarted"><u-loading mode="flower"></u-loading></view></view><scroll-view class="device-list" scroll-y scroll-with-animation><view class="scroll_box mx-3 p-2 px-4" v-if="getDevices.length>0"><view v-for="(item,index) in getDevices" :key="item.deviceId" @click="connect(item)"class="device-item"><view class="item_left" style="font-size: 15px; color: #333;">{{item.name}}</view><view class="item_right" style="font-size: 15px;" v-if="getConnectDeviceId == item.deviceId">已连接</view></view></view><view class="scroll_box mx-3 p-2 px-4 null_box" v-else>暂无可连接设备</view></scroll-view><view class="py-4 px-3 w-full"><view class="info_box p-2 bg-white" v-if="getConnected">已连接设备: {{getName}}</view><view class="info_box p-2 bg-white" v-else>暂未连接设备</view></view><view class="btn-area"><view class="btn_box px-4"><view class="btn_view" type="primary" @click="refreshDiscovery">重新扫描</view></view><view class="btn_box px-4"><view class="btn_view" @click="stopDiscovery" style="margin-top: 10px;">停止扫描</view></view></view></view><view class="page-section connected-area" v-if="getConnected"><view class="btn-area"><view class="btn_box px-4" style="margin-bottom: 10px;margin-top: 10px;"><view class="btn_view" type="primary" @click="writeBLECharacteristicValue">打印</view></view><view class="btn_box px-4"><view class="btn_view" @click="closeBLEConnection">断开连接</view></view></view></view></view>
</template><script>const LAST_CONNECTED_DEVICE = 'last_connected_device'const PrinterJobs = require('./sdk/printer/printerjobs')const printerUtil = require('./sdk/printer/printerutil')import printObject from "./printTheTemplate/template.js"import {mapGetters} from "vuex"function inArray(arr, key, val) {for (let i = 0; i < arr.length; i++) {if (arr[i][key] === val) {return i}}return -1}// ArrayBuffer转16进度字符串示例function ab2hex(buffer) {const hexArr = Array.prototype.map.call(new Uint8Array(buffer),function(bit) {return ('00' + bit.toString(16)).slice(-2)})return hexArr.join(',')}function str2ab(str) {// Convert str to ArrayBuff and write to printerlet buffer = new ArrayBuffer(str.length)let dataView = new DataView(buffer)for (let i = 0; i < str.length; i++) {dataView.setUint8(i, str.charAt(i).charCodeAt(0))}return buffer;}export default {data() {return {devices: [],connected: false,discoveryStarted: false,chs: [],name: "",deviceId: "",canWrite: false,lastDevice: "",printerJobs: null}},computed: {...mapGetters("print", ['getPrintType', 'getPrintData']),...mapGetters("connect", ['getDevices', 'getDiscoveryStarted', 'getName', 'getConnected', 'getConnectDeviceId','getServiceId','getCharacteristicId'])},onShow() {console.log(this.getDiscoveryStarted, this.getConnected)if (!this.getDiscoveryStarted && !this.getConnected) {this.$store.commit("connect/initConnect")}// const lastDevice = uni.getStorageSync(LAST_CONNECTED_DEVICE);// this.lastDevice = lastDevice// if (this.lastDevice) {//    this.createBLEConnectionWithDeviceId()// } else {//     this.openBluetoothAdapter()// }},onUnload() {// 清理上一次打印的数据this.printerJobs && this.printerJobs.clear()},methods: {connect(item) {// createBLEConnection(item)this.$store.commit("connect/createBLEConnection", item)},refreshDiscovery() {this.$store.commit("connect/startBluetoothDevicesDiscovery")},stopDiscovery() {this.$store.commit("connect/stopBluetoothDevicesDiscovery")},closeBLEConnection(){this.$store.commit("connect/closeBLEConnection")},writeBLECharacteristicValue() {if (this.printerJobs) {// 清理上一次打印的数据this.printerJobs.clear()}let {buffer,printerJobs} = printObject[this.getPrintType](this.getPrintData)this.printerJobs = printerJobs// console.log("buffer", buffer)// console.log('ArrayBuffer', 'length: ' + buffer.byteLength, ' hex: ' + ab2hex(buffer));// 1.并行调用多次会存在写失败的可能性// 2.建议每次写入不超过20字节// 分包处理,延时调用const maxChunk = 20;const delay = 20;for (let i = 0, j = 0, length = buffer.byteLength; i < length; i += maxChunk, j++) {let subPackage = buffer.slice(i, i + maxChunk <= length ? (i + maxChunk) : length);setTimeout(this._writeBLECharacteristicValue, j * delay, subPackage);}},_writeBLECharacteristicValue(buffer) {uni.writeBLECharacteristicValue({deviceId: this.getConnectDeviceId,serviceId: this.getServiceId,characteristicId: this.getCharacteristicId,value: buffer,success(res) {console.log('writeBLECharacteristicValue success', res)},fail(res) {console.log('writeBLECharacteristicValue fail', res)}})},closeBluetoothAdapter() {uni.closeBluetoothAdapter()this.discoveryStarted = false},createBLEConnectionWithDeviceId(e) {// 小程序在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备const device = this.lastDeviceif (!device) {return}const index = device.indexOf(':');const name = device.substring(0, index);const deviceId = device.substring(index + 1, device.length);console.log('createBLEConnectionWithDeviceId', name + ':' + deviceId)uni.openBluetoothAdapter({success: (res) => {console.log('openBluetoothAdapter success', res)this._createBLEConnection(deviceId, name)},fail: (res) => {console.log('openBluetoothAdapter fail', res)if (res.errCode === 10001) {uni.showModal({title: '错误',content: '未找到蓝牙设备, 请打开蓝牙后重试。',showCancel: false})uni.onBluetoothAdapterStateChange((res) => {console.log('onBluetoothAdapterStateChange', res)if (res.available) {// 取消监听uni.onBluetoothAdapterStateChange(() => {});this._createBLEConnection(deviceId, name)}})}}})}}}
</script><style lang="scss" scoped>.page-section {display: flex;flex-direction: column;align-items: center;width: 100%;box-sizing: border-box;border-bottom: 2rpx solid #EEE;// padding: 30rpx 0;}.devices-summary {padding: 10rpx;font-size: 30rpx;}.device-list {height: 400rpx;.scroll_box {background: #FAFAFA;height: 400rpx;.device-item {// border-bottom: 1rpx solid #EEE;padding: 20rpx;color: #666;background-color: white;margin: 10upx 0upx;display: flex;justify-content: space-between;align-items: center;.item_left {width: 80%;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;padding-right: 20upx;}.item_right {color: #CCCCCC;}}}.null_box {display: flex;justify-content: center;align-items: center;font-size: 28upx;color: #CCCCCC;}}.device-item-hover {background-color: rgba(0, 0, 0, .1);}.btn-area {box-sizing: border-box;width: 100%;// padding: 0 30rpx;}.connected-area {font-size: 22rpx;}.connected-info {}.input-area {background: #fff;margin-top: 10rpx;width: 100%;}.input {font-size: 28rpx;height: 2.58823529em;min-height: 2.58823529em;line-height: 2.58823529em;padding: 10rpx;}.btn_box {width: 100%;display: flex;justify-content: center;align-items: center;.btn_view {width: 100%;height: 80upx;background-color: $colorred;color: white;display: flex;justify-content: center;align-items: center;border-radius: 10upx;font-size: 30upx;}}.info_box {width: 100%;text-align: center;font-size: 28upx;}
</style>

微信小程序蓝牙对接热敏打印机相关推荐

  1. wx.getBLEDeviceCharacteristics 微信小程序蓝牙 微信小程序热敏打印机

    1 微信小程序蓝牙功能开发概述 第一步 判断当前微信版本,是否支持蓝牙 通信 第二步 打开蓝牙 第三步扫描设备 第四步连接设备 第五步 获取服务与特征值 看是否支持读写数据操作 第六步 发送数据 本文 ...

  2. 微信小程序蓝牙模块BLE开发说明基础知识

    微信小程序蓝牙模块说明 一.简介 微信小程序作为轻量级应用的载体,确实方便了很多的应用场景.传统的产品如果要和手机互联互通,那么必须要开发两套APP,即IOS和安卓.十分的麻烦和成本巨高.但是微信小程 ...

  3. 微信小程序蓝牙BLE开发——关于进制转换(四)

    微信小程序蓝牙BLE开发--进制转换 这段时间开发共享设备,对接蓝牙BLE设备通信协议,过程中用到一些进制转换, 记录下方便使用. 有些参考大神们,感谢分享. 文章目录 微信小程序蓝牙BLE开发--进 ...

  4. 微信小程序蓝牙BLE开发实战——案例(二)

    微信小程序蓝牙BLE开发实战(二) 上篇主要介绍在开发过程中应用到相关API操作.接下来介绍个人在项目开发中应用蓝牙BLE一些事情. 由于时间比较仓促, 有些注释没那么详细.请理解~写的不好欢迎各位大 ...

  5. 泰凌微ble mesh蓝牙模组天猫精灵学习之旅 ② 如何实现 微信小程序蓝牙控制 Ble Mesh模组 安信可TB02,全部开源!

    本<泰凌微ble mesh蓝牙模组天猫精灵学习之旅>系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1.小 ...

  6. 微信小程序蓝牙标签打印/标签云打印开放平台(2)

    微信小程序蓝牙标签打印/标签云打印开放云平台(下面简称"平台" www.herro.cn 技术服务TEL:15759216805),支持开发者通过API调用完成标签蓝牙打印或标签云 ...

  7. 【微信小程序控制硬件 第12篇-项目篇】微信小程序蓝牙控制硬件应如何开始动手?为您全面解析微信小程序蓝牙API的使用;(附带demo)

    [微信小程序控制硬件第1篇 ] 全网首发,借助 emq 消息服务器带你如何搭建微信小程序的mqtt服务器,轻松控制智能硬件! [微信小程序控制硬件第2篇 ] 开始微信小程序之旅,导入小程序Mqtt客户 ...

  8. 【微信小程序控制硬件14 】 微信小程序蓝牙+WiFi双控制ESP32-C3应用示范;(附带Demo)

    文章目录 一.前言 二.设备核心代码 2.1 蓝牙控制 2.2 WiFi控制 2.3 外设驱动 三.微信小程序核心代码 3.1 蓝牙搜索 3.2 蓝牙服务发现 四.感谢 另外,不要把我的博客作为学习标 ...

  9. 【TB-02模组专题③】微信小程序蓝牙通讯 Ble 蓝牙Mesh TB02模组;

    本<安信可ble mesh蓝牙模组TB-02模组专题>系列博客学习由官方博客 CSDN安信可博客 潜心所力所写.如有不对之处,请留言,我们及时更改. 1.BLE MESH开发环境linux ...

最新文章

  1. C语言的指针、链表的原理和各类操作
  2. 成本预算的四个步骤_全网推广步骤有哪些?
  3. 计算机应用技术面试的礼仪和技巧,远程复试下,这些面试礼仪一定要注意!
  4. 外媒:苹果聘请更多司机在加州测试其自动驾驶汽车
  5. aix 添加lv 大小
  6. .NET Framework 3.5 SP1的图表控件——Chart (转)
  7. Position属性四个值:static、fixed、absolute和relative的区别和用法
  8. python判断ip能否ping通_python 检查IP是否能ping通,并且分别导入两个文件
  9. [转载]网页栅格系统研究(1):960的秘密
  10. [Vue CLI 3] 环境变量和模式配置实践与源码分析
  11. ShellServiceObjectDelayLoad注册表键值作用
  12. Cocos2d摄像机详解
  13. CentOS 7 安装 Weadmin(ITOSS)
  14. 金蝶KIS迷你版、标准版年结注意事项!!
  15. 【Git学习记录】git查询历史版本记录命令
  16. 论文总结——因果发现与推断
  17. ruoyi(若依)框架学习
  18. 三分钟看懂ERP、MES、APS系统的关联和区别
  19. 计算机教程打字方法,电脑快速打字方法教程
  20. uni-app,文本实现展开、收起全文

热门文章

  1. ECharts可视化库 学习笔记
  2. 源码学习:CUDA samples(持续更新)
  3. 最新完整版标准 UL 2271标准中文版-2018轻型电动车用锂电池UL中文版标准.
  4. Mybatis学习(叁)
  5. 新手java五子棋完整代码判断落子落在线上_JAVA五子棋开发
  6. 32个关于赞美的英文单词
  7. windows7建行网上银行不能使用,弹出白框问题
  8. 云易卡社区系统V4.7源码
  9. 好看的某云易支付首页模板 open易支付程序
  10. Qt之信号signals和槽slots详解