更多文章请访问 深的个人博客
最近开发的一个小程序里需要对接热敏打印机打印小票,在此记录一下对接的过程
项目开发注意点:
1、因为项目中有多个页面的数据是需要进行打印的,为了保持蓝牙的连接状态和数据,所以连接蓝牙的操作和数据会在vuex里面进行统一管理。
2、打印模板会统一进行管理
3、打印数据前需要对上一次打印的数据进行清理 使用 printerJobs 对象里的 clear() 方法实现清理数据
4、在原有的sdk上增加三列打印的方法
uni-app
微信小程序蓝牙打印
/**
* 连接蓝牙
*/
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: "", // 连接到的蓝牙设备的deviceId
canWrite: 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,
// 导致再次调用startBluetoothDevicesDiscovery
uni.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.connected
if (!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 = true
uni.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 = false
console.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)
}
})
})
},
// 连接蓝牙 1
createBLEConnection(state, item) {
console.log("连接的设备", item)
this.commit("connect/next_createBLEConnection", {
deviceId: item.deviceId,
name: item.name
})
},
// 连接蓝牙 2
next_createBLEConnection(state, equipment) {
let {
deviceId,
name
} = equipment
uni.showLoading()
uni.createBLEConnection({
deviceId,
success: () => {
console.log('createBLEConnection success');
state.name = name
state.connected = true
state.deviceId = deviceId
console.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 = false
state.canWrite = false
state.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
} = idObject
uni.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 = true
state._deviceId = deviceId
state._serviceId = serviceId
state._characteristicId = item.uuid
break;
}
}
},
fail(res) {
console.error('getBLEDeviceCharacteristics', res)
}
})
},
closeBluetoothAdapter(state) {
uni.closeBluetoothAdapter()
state.discoveryStarted = false
console.log("关闭蓝牙")
},
},
actions: {
}
}
打印数据:页面传递过来的要打印的数据是一个对象,为了避免数据没有及时更新的问题,所以存储这个对象用的是一个数组(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
} = printObj
console.log("接收到的数据", printObj)
state.printType = printType
state.printData = []
state.printData.push(printData)
}
},
actions: {
}
}
// 打印的常量
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" // 库存汇总
// 模板
// 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
} = data
let 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可以下载 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) % lineWidth
let rightCount = fillCount - leftCount
let 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 printer
let 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.lastDevice
if (!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>