<template> <view class="kk-printer"> <view class="kk-printer-btn"> <u-button v-if="printBtnStyle=='blue-large'" @tap="handlePrintTap(1)" :loading="isPrinting||isConnecting" shape="circle" :custom-style="{background:$config('primaryColor')}" type="primary">{{isPrinting?printingText:defaultText}}</u-button> <u-button v-if="printBtnStyle=='default-mid'" shape="circle" size="medium" hover-class="none" @tap="handlePrintTap(1)" :loading="isPrinting||isConnecting">{{isPrinting?printingText:defaultText}}</u-button> </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-filter-wrap"> <view class="filter-title">根据SRRI过滤设备</view> <slider @change="handleSRRIChange" max='-20' min='-100' value="-95" show-value/> </view> --> <!-- <view class="kk-filter-wrap"> <view class="filter-title">根据蓝牙名过滤</view> <input type="text" placeholder-class="kk-placeholder-class" placeholder="请输入蓝牙名字或设备ID搜索" v-model="filterName" /> </view> --> <view style="text-align: left;"> <u-parse :html="content"></u-parse> </view> <view class="kk-btn-wrap"> <view class="kk-btn-item confirm-btn" @tap="searchBtnTap" 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="filterDeviceList.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 filterDeviceList" :key="index" @tap="handleConnectDevice(item)"> <view> <view class="name"> <text>设备名称:</text> <text>{{item.name?item.name:'未命名'}}</text> </view> <view class="flex align_center justify_between"> <view class="rssi"> <text>信号强度:</text> <text>({{Math.max(0, item.RSSI + 100)}}%)</text> </view> <view style="width: 120rpx;text-align: right;"> <!-- <u-icon :size="60" color="#55aaff" name="plus-circle"></u-icon> --> <u-button :loading="isConnecting" @tap="handleConnectDevice(item)" shape="circle" size="mini" :custom-style="{background:$config('primaryColor')}" type="primary">{{isConnecting?'连接中':'连接'}}</u-button> </view> </view> </view> </view> </view> </view> <view style="margin-top: 20upx;"> <view v-if="!isConnecting" style="text-align: center;padding: 20upx;border:2upx solid #eee;border-radius: 15upx;" @tap="handleSearchClose">取消打印</view> </view> </view> </view> </view> </view> </template> <script> import tsc from '@/components/kk-printer/printer/tsc.js' // import esc from '@/components/kk-printer/printer/esc.js' import * as cpcl from '@/components/kk-printer/printer/cpcl.js' import * as blesdk from './utils/bluetoolth'; import util from './utils/util.js'; export default { data(){ return{ content: ` <div style="font-size:12px;"> <p>注意事项:</p> <p>1、连接打印机之前,先打开手机蓝牙开关</p> <p>2、如果已有其它手机连接,请手动断开或重启打印机</p> <p>3、如果连接打印机没有任何反应或需要切换连接其它打印机,请在“我的”页面点击“重置打印机”后再试</p> <p>4、目前仅支持“得力(DL-886BW(NEW))”、“新北洋(BTP-P39)”蓝牙打印机</p> </div> `, //是否正在打印 isPrinting:false, //是否正在搜索设备 isSearching:false, // 是否正在连接 isConnecting: false, //是否显示蓝牙列表 isShowSearch:false, //按蓝牙名过滤 filterName: ['DL-','BTP-'], //按信号过滤 filterRSSI:-95, //设备列表 devicesList:[], //连接的设备ID deviceId:'', deviceName: '', //根据设备ID获取的服务 services:'', //获取特征值时返回的三要素 serviceId: '', writeId: '', readId: '' } }, props:{ //按钮默认文字 defaultText:{ type:String, default:'快速打印' }, //按钮打印中的文字 printingText:{ type:String, default:'打印中...' }, // 按钮样式 printBtnStyle:{ type: String, default: 'blue-large' }, roomcode:{ type:String, require:true }, CustName:{ type:String, require:true }, roomid:{ type:String, require:true }, autoConnect: { type: Boolean, default: true } }, computed:{ mapFilterRSSI(){ return (0 - this.filterRSSI) }, filterDeviceList(){ let devices = this.devicesList; let name = this.filterName; let rssi = this.filterRSSI; //按RSSI过滤 let filterDevices1 = devices.filter((item)=>{ return item.RSSI > rssi }) // 按名字过滤 let filterDevices2 if(name!=''){ filterDevices2 = filterDevices1.filter((item)=>{ return name.find(a => item.name.indexOf(a) >= 0 || item.deviceId.indexOf(a) >= 0) }) }else{ filterDevices2 = filterDevices1 } // 根据广播数据提取MAC地址 for (let i = 0; i < filterDevices2.length;i++) { if (filterDevices2[i].hasOwnProperty('advertisData')){ if (filterDevices2[i].advertisData.byteLength == 8) { filterDevices2[i].advMac = util.buf2hex(filterDevices2[i].advertisData.slice(2, 7)); } } } return filterDevices2 } }, mounted() { if(this.autoConnect){ this.handlePrintTap(0) } }, beforeDestroy(){ this.stopSearchBtnTap(); }, methods:{ doNothing(){ return; }, //点击打印按钮,flag : true 如果已连接直接执行打印命令,false,不执行 handlePrintTap(flag){ //打开蓝牙适配器 blesdk.openBlue().then((res)=>{ //获取已连接设备 blesdk.getConnectedBluetoothDevices().then((res)=>{ const lastDevice = uni.getStorageSync('vuex_lastBuleDevice') console.log(lastDevice) console.log(res,this.deviceId,this.serviceId,this.writeId,this.onPrintSuccess) // 如果之前连接过设备 if(lastDevice){ // 有正在连接的设备,且和上次连接设备一样 if(res.devices.length && res.devices[0].deviceId == lastDevice.deviceId){ this.deviceId = lastDevice.deviceId this.deviceName = lastDevice.name this.serviceId = lastDevice.serviceId this.writeId = lastDevice.writeId this.readId = lastDevice.readId console.log(this.deviceName.indexOf('DL-')>=0?tsc:cpcl) if(flag){ this.isPrinting = true; this.$nextTick(()=>{ this.$emit("startPrint",{ deviceId: this.deviceId, serviceId: this.serviceId, writeId: this.writeId }, this.deviceName.indexOf('DL-')>=0?tsc:cpcl, blesdk) }) } }else{ // 重新直接连接 this.handleConnectDevice(lastDevice) } }else{ if(this.autoConnect || flag){ //若没有已连接设备,弹框搜索设备 this.isShowSearch = true this.devicesList = [] this.searchBtnTap() } } }).catch((err)=>{ blesdk.catchToast(err); }) }).catch((err)=>{ console.log(err) blesdk.catchToast(err); }) }, onGetDevice(res){ this.devicesList = res; }, handleSearchClose(){ if(!this.isConnecting){ this.isShowSearch = false this.stopSearchBtnTap() } }, handleSRRIChange(e){ this.filterRSSI = e.detail.value }, //开始搜索设备 searchBtnTap(){ blesdk.startBluetoothDevicesDiscovery(); this.isSearching = true; blesdk.onfindBlueDevices(this.onGetDevice) }, //停止搜索设备 stopSearchBtnTap(){ blesdk.stopBlueDevicesDiscovery(); this.isSearching = false; }, //点击连接设备 handleConnectDevice(device){ const _this = this let deviceId = device.deviceId; let name = device.name; this.deviceId = deviceId; this.deviceName = name; this.isConnecting = true this.stopSearchBtnTap() uni.onBLEConnectionStateChange(function(res){ console.log('连接',res) if(res.connected){ plus.nativeUI.toast('设备'+ res.deviceId + '已连接',{ verticalAlign:'center' }) }else{ _this.closeConnect() plus.nativeUI.toast('设备'+ res.deviceId + '已断开连接',{ verticalAlign:'center' }) _this.isShowSearch = true _this.devicesList = [] _this.searchBtnTap() } _this.isConnecting = false }) blesdk.createBLEConnection(deviceId, this.onConnectSuccess, this.onConnectFail); }, onConnectSuccess(res){ this.stopSearchBtnTap() this.isConnecting = false blesdk.getBLEDeviceServices(this.deviceId, this.onGetServicesSuccess, this.onGetServicesFail); }, onConnectFail(err){ console.log('链接失败',err) this.isConnecting = false blesdk.catchToast(err.res) uni.setStorageSync('vuex_lastBuleDevice','') if(err.res.code == 10012){ this.isShowSearch = true this.devicesList = [] this.searchBtnTap() } }, onGetServicesSuccess(res){ console.log('获取服务',res) this.services = res.serviceId; blesdk.getDeviceCharacteristics(this.deviceId, this.services, this.onGetCharacterSuccess, this.onGetCharacterFail); }, onGetServicesFail(err){ console.log('获取服务失败') }, onGetCharacterSuccess(res){ console.log('获取特征值成功',res) this.serviceId = res.serviceId; this.writeId = res.writeId; this.readId = res.readId; this.isShowSearch = false; try { uni.setStorageSync('vuex_lastBuleDevice', {deviceId:this.deviceId,serviceId:this.serviceId,writeId:this.writeId,readId:this.readId,name:this.deviceName}); } catch (e) { // error } }, onGetCharacterFail(err){ console.log('特征值获取失败') this.isPrinting = false; }, onPrintSuccess(){ this.isPrinting = false; console.log('打印成功') // this.$emit('onPrintSuccess') }, onPrintFail(){ console.log('打印失败') this.isPrinting = false; }, closeConnect(){ blesdk.closeBLEConnection(this.deviceId) this.isPrinting = false; uni.hideLoading(); this.$emit('closeConnect') }, } } </script> <style lang="scss" scoped> .kk-printer{ &-btn{ width:100%; height:100%; } .kk-shadow{ display: none; &.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; z-index: 10000; .kk-modal{ width:680upx; height: 80%; padding:24upx; box-sizing: border-box; overflow-y: auto; border-radius: 20upx; background: #ffffff; display: flex; justify-content: center; align-items: center; .kk-search-device{ width:100%; height: 100%; .kk-filter-wrap{ width:100%; height: 200upx; display: flex; flex-direction: column; justify-content: flex-start; align-items: flex-start; .filter-title{ line-height: 70upx; font-size: 30upx; color: #999999; } &>slider{ width:90%; height: 90upx; } &>input{ padding:0 20upx; box-sizing: border-box; border-radius: 10upx; height: 90upx; width:100%; border: 1upx solid #ebebeb; } } .kk-btn-wrap{ width:100%; height: 140upx; display: flex; justify-content: space-between; align-items: center; &>view{ flex:1 1 auto; height: 80upx; line-height: 80upx; border-radius: 100upx; text-align: center; color:#ffffff; &.confirm-btn{ background: #007AFF; margin-right:30upx; } &:nth-last-child(1){ background: #DD524D; } } } .kk-devices-wrap{ height: calc(100% - 460upx); overflow-y:auto; padding:10upx 20upx; box-sizing: border-box; border: 1upx solid #ebebeb; box-sizing: border-box; border-radius: 20upx; .empty-wrap{ width:100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; .empty-icon{ width:268upx; height: 240upx; background: url('./empty-icon.png') no-repeat; background-size:100% 100%; margin-bottom: 26upx; } .empty-text{ width: 100%; line-height: 50upx; font-size: 30upx; text-align: center; color: #999999; } } .kk-devices-item{ width:100%; border-bottom: 1upx solid #ebebeb; padding:20upx 0; box-sizing: border-box; &:nth-last-child(1){ border-bottom: none; } button{ width: auto; } } } } } } } } .kk-placeholder-class{ font-size: 30upx; color:#999999; } </style>