You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

604 lines
14 KiB

<template>
<view class="kk-printer">
<view class="kk-printer-btn" @tap="handlePrintTap" style="color:#FFF;">
{{isPrinting?printingText:defaultText}}
</view>
<view class="kk-shadow" :class="isShowSearch?'show':''" @tap="handleSearchClose">
<view class="kk-modal" @tap.stop="doNothing">
<view class="kk-search-device">
<view class="kk-btn-wrap">
<view class="kk-btn-item confirm-btn" @tap="sousuo" v-if="!isSearching">
搜索设备
</view>
<view class="kk-btn-item confirm-btn" v-else>
搜索中...
</view>
<view class="kk-btn-item" @tap="stopSearchBtnTap">
停止搜索
</view>
</view>
<view class="kk-devices-wrap">
<view class="empty-wrap" v-if="devicesList.length <= 0">
<view class="empty-icon"></view>
<view class="empty-text">无可搜索到的设备</view>
</view>
<view class="" v-else>
<view class="kk-devices-item" v-for="(item,index) in devicesList" :key="index"
@tap="lianejieshebei(item.deviceId)">
<view class="name" style="color:#000;display: flex;flex-direction: column;">
<text>设备名称</text>
<text>{{item.name?item.name:'未命名'}}</text>
</view>
<!-- <view class="rssi">
<text>信号强度</text>
<text>({{item.RSSI}})</text>
</view> -->
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import gbk from '@/components/kk-printer/utils/printUtil-GBK.js';
import * as blesdk from './utils/bluetoolth';
import util from './utils/util.js';
export default {
data() {
return {
//是否正在打印
isPrinting: false,
//是否正在搜索设备
isSearching: false,
//是否显示蓝牙列表
isShowSearch: false,
//按蓝牙名过滤
filterName: '',
//按信号过滤
filterRSSI: -95,
//设备列表
devicesList: [],
//打印图片断开连接等待时间
picWaitTime:0,
//连接的设备ID
deviceId: '',
//根据设备ID获取的服务
services: '',
//获取特征值时返回的三要素
serviceId: '',
writeId: '',
readId: '',
iosNo: false,
deviceType: 'ios'
}
},
props: {
//按钮默认文字
defaultText: {
type: String,
default: '打印'
},
//按钮打印中的文字
printingText: {
type: String,
default: '打印中...'
},
bufferData: {
type: Array,
require: true
},
roomcode: {
type: String,
require: true
},
CustName: {
type: String,
require: true
},
roomid: {
type: String,
require: true
}
},
mounted() {
},
onLoad() {
},
beforeDestroy() {
this.stopSearchBtnTap();
},
methods: {
doNothing() {
return;
},
//点击打印按钮
handlePrintTap() {
let that = this
uni.showLoading({
mask: true,
title: '打印中...'
});
uni.getSystemInfo({
success(res) {
that.deviceType = res.osName
},fail(err){
}
})
// 初始化蓝牙模块
wx.openBluetoothAdapter({ //111
mode: 'central',
success: (res2) => {
that.sousuo()
},
fail: (res) => {
if (res.errCode == '10001') {
uni.showToast({
duration: 2000,
title: "请打开蓝牙后,再进行连接",
icon: 'none',
mask: true
})
} else {
that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-1')
that.isShowSearch = true
}
setTimeout(res => {
uni.hideLoading();
}, 2000)
}
})
},
// 开始搜索附近的蓝牙外围设备
sousuo() {
let that = this;
this.devicesList = []
wx.startBluetoothDevicesDiscovery({ //222
success(res3) {
that.jiantingshebei()
},
fail(err) {
that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-2',err)
wx.closeBLEConnection({
deviceId: uni.getStorageSync('deviceId'),
success(res2) {
},fail(err1){
}
})
wx.closeBluetoothAdapter({
success(res) {
},fail(err2){
}
})
uni.removeStorageSync('deviceId')
that.handlePrintTap()
that.isShowSearch = true
setTimeout(res => {
uni.hideLoading();
}, 2000)
}
})
},
//停止搜索蓝牙设备
stopSearchBtnTap() {
wx.stopBluetoothDevicesDiscovery()
},
/**
* jiantingshebei方法判断缓存中有没有deviceId等数据的时候
* 直接拿到缓存中的deviceId等直接请求 wx.createBLEConnection
* 没有才会调用 wx.onBluetoothDeviceFound 搜索
*/
jiantingshebei() {
let that = this;
if (uni.getStorageSync('deviceId')) {
// that.huoqufuwu(uni.getStorageSync('deviceId'))
that.lianejieshebei(uni.getStorageSync('deviceId'))
} else {
uni.hideLoading();
that.isShowSearch = true
// 监听扫描到新设备事件
wx.onBluetoothDeviceFound((res4) => { //333
res4.devices.forEach((device) => {
if (!device.name && !device.localName) {
return
}
that.devicesList.push(device)
})
})
}
},
lianejieshebei(deviceId) {
let that = this;
uni.showLoading({
mask: true,
title: '加载中...'
});
let timerId = setTimeout(() => {
wx.closeBLEConnection({
deviceId: deviceId,
success(res2) {
},fail(err1){
}
})
wx.closeBluetoothAdapter({
success(res) {
},fail(err2){
}
})
uni.removeStorageSync('deviceId')
that.handlePrintTap()
that.isShowSearch = true
return
}, 5000);
// 连接设备
wx.createBLEConnection({ //555
deviceId: deviceId, // 搜索到设备的 deviceId
success: () => {
// 连接成功就清除定时器
clearTimeout(timerId);
that.isShowSearch = false
that.huoqufuwu(deviceId)
},
fail: (res) => {
clearTimeout(timerId);
if(res.errno == '1509007'){
that.huoqufuwu(deviceId)
}
if(res.errno == '1509003'){
that.lianejieshebei(deviceId)
}
}
})
},
huoqufuwu(deviceId) {
let that = this;
//获取服务
wx.getBLEDeviceServices({ //666
deviceId: deviceId, // 搜索到设备的 deviceId
success: (res5) => {
that.duxietezhengzhi(deviceId, res5)
},
fail: (res) => {
that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-4',res)
wx.closeBLEConnection({
deviceId: uni.getStorageSync('deviceId'),
success(res1) {
}
})
uni.removeStorageSync('deviceId')
that.sousuo()
that.isShowSearch = true
setTimeout(res => {
uni.hideLoading();
}, 2000)
}
})
},
duxietezhengzhi(deviceId, res5) {
let that = this;
//读写特征值
wx.getBLEDeviceCharacteristics({ //777
deviceId: deviceId, // 搜索到设备的 deviceId
serviceId: res5.services[0].uuid, // 上一步中找到的某个服务
success: (res6) => {
for (let i = 0; i < res6.characteristics.length; i++) {
let item = res6.characteristics[i]
that.startNoticeBle(deviceId, res5.services[0].uuid, res6.characteristics[2].uuid)
if (item.properties.write) { // 该特征值可写
uni.setStorageSync('deviceId', deviceId);
uni.setStorageSync('serviceId', res5.services[0].uuid);
uni.setStorageSync('characteristicId', item.uuid);
that.xierushuju()
return;
}
}
},
fail: (res) => {
that.tui.toast('连接失败,请重启蓝牙或删除小程序重新进入-5',res)
wx.closeBLEConnection({
deviceId: uni.getStorageSync('deviceId'),
success(res) {
}
})
uni.removeStorageSync('deviceId')
that.sousuo()
that.isShowSearch = true
setTimeout(res => {
uni.hideLoading();
}, 2000)
}
})
},
// 开启蓝牙数据监听
startNoticeBle(deviceId, serviceId, characteristicId) {
let _this = this
uni.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
deviceId: deviceId,
serviceId: serviceId,
characteristicId: characteristicId,
success(res) {
_this.GetDataFromBle();
},
fail: function(err) {
}
})
},
// 设备返回的数据接收
GetDataFromBle() {
var _this = this;
uni.onBLECharacteristicValueChange((res) => {
// 此时可以拿到蓝牙设备返回来的数据是一个ArrayBuffer类型数据,所以需要通过一个方法转换成字符串
_this.bleData = _this.ab2hex(res.value)
uni.hideLoading()
setTimeout(res=>{
uni.closeBLEConnection({
deviceId: uni.getStorageSync('deviceId'),
success(res) {
},
fail(err) {}
})
},_this.picWaitTime)
})
},
ab2hex(buffer) {
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function(bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
},
xierushuju() {
let that = this;
//写入数据
if (this.defaultText == '打印小票') {
that.$emit('onPrintSmall');
} else if (this.defaultText == '确认打印') {
that.$emit('goPrint');
} else if (this.defaultText == '小标签') {
that.$emit('onPrintSmall1');
}else {
that.$emit('onPrint');
}
that.$nextTick(() => {
var dataStr = ''
for (let m = 0; m < that.bufferData.length; m++) {
dataStr += that.bufferData[m]
}
const maxChunk = that.deviceType == 'android' ? 20 : 180;
const delay = that.deviceType == 'android' ? 20 : 180;
let buffer = gbk.strToGBKByte(dataStr)
if(dataStr.indexOf('EG ') != -1){
that.picWaitTime = buffer.byteLength + 200
}
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(that._writeBLECharacteristicValue, j * delay, subPackage);
}
})
return;
},
_writeBLECharacteristicValue(buffer) {
let that = this;
wx.writeBLECharacteristicValue({
deviceId: uni.getStorageSync('deviceId'),
serviceId: uni.getStorageSync('serviceId'),
characteristicId: uni.getStorageSync('characteristicId'),
value: buffer,
success(res) {
},
fail(res) {
wx.closeBLEConnection({
deviceId: uni.getStorageSync('deviceId'),
success(res) {
}
})
if (uni.getStorageSync('deviceId')) {
// that.xierushuju()
} else {
that.jiantingshebei()
}
uni.hideLoading();
}
})
},
handleSearchClose() {
wx.closeBluetoothAdapter({
success(res) {
}
})
this.isShowSearch = false
}
}
}
</script>
<style lang="scss" scoped>
.kk-printer {
&-btn {
width: 100%;
height: 100%;
}
.kk-shadow {
display: none;
z-index: 999;
&.show {
display: block;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.4);
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
.kk-modal {
width: 420rpx;
height: 600rpx;
padding: 24rpx;
box-sizing: border-box;
overflow-y: auto;
border-radius: 20rpx;
background: #ffffff;
display: flex;
justify-content: center;
align-items: center;
.kk-search-device {
width: 100%;
height: 100%;
.kk-filter-wrap {
width: 100%;
height: 160rpx;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
&>slider {
width: 90%;
height: 90rpx;
}
&>input {
padding: 0 20rpx;
box-sizing: border-box;
border-radius: 10rpx;
height: 90rpx;
width: 100%;
border: 1rpx solid #ebebeb;
}
}
.kk-btn-wrap {
width: 100%;
height: 90rpx;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx;
&>view {
flex: 1 1 auto;
height: 60rpx;
line-height: 60rpx;
border-radius: 16rpx;
text-align: center;
color: #ffffff;
font-size: 26rpx;
&.confirm-btn {
background: #007AFF;
margin-right: 30rpx;
}
&:nth-last-child(1) {
background: #DD524D;
}
}
}
.kk-devices-wrap {
height: calc(100% - 80rpx);
overflow-y: auto;
padding: 10rpx 20rpx;
box-sizing: border-box;
border: 1rpx solid #ebebeb;
box-sizing: border-box;
border-radius: 20rpx;
.empty-wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.empty-icon {
width: 268rpx;
height: 240rpx;
background-size: 100% 100%;
margin-bottom: 26rpx;
}
.empty-text {
width: 100%;
line-height: 50rpx;
font-size: 30rpx;
text-align: center;
color: #999999;
}
}
.kk-devices-item {
width: 100%;
border-bottom: 1rpx solid #ebebeb;
padding: 10rpx 0;
box-sizing: border-box;
z-index: 500;
&:nth-last-child(1) {
border-bottom: none;
}
&>view {
width: 100%;
font-size: 30rpx;
}
}
}
}
}
}
}
}
</style>