emis-app/pages/print/bluetoothPrinter.vue
2024-05-10 11:15:31 +08:00

482 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<tpx-page>
<tpx-layout>
<template v-slot:header>
<view class="blcok-white">
<view >
<u-row custom-style="gap: 10rpx;">
<u-button @click="discoveryPrinter">搜索周边设备</u-button>
<u-button @click="stopDiscoveryPrinter">停止搜索</u-button>
<u-button @click="writeBLECharacteristicValue" type="primary" :disabled="!(deviceId && serviceId && characteristicId)">打印</u-button>
</u-row>
</view>
<view class="">
<view class="pt-10 pb-10">连接信息</view>
<u-steps activeColor="#969799" :current="curTab" direction="column" dot="true">
<u-steps-item v-for="(item, index) in conInfos" @click="changeTab(index)">
<template v-slot:title>
<view :class="`${index == curTab ? 'clr-prm' : 'clr-sub'} pl-20`">{{item.title}}</view>
</template>
<template v-slot:desc>
<view class="mt-10 pl-20">{{item.desc}}</view>
</template>
</u-steps-item>
</u-steps>
</view>
</view>
</template>
<template v-slot:body>
<view class="blcok-white">
<view v-if="curTab == 0">
<view class="pb-10">蓝牙设备列表</view>
<template v-for="(item, index) in devices">
<view @click="handleSelectDeviceId(item)" v-if="item.name.length>0"
:key="index" :class="`list-item ${item.deviceId == deviceId?'list-item-active':''}`"
>
<u-row justify="between">
<view class="font-weight">{{item.name }}</view>
</u-row>
<view>
<text class="clr-sub">信号强度:</text> {{item.RSSI}}dBm ({{Math.max(100+item.RSSI,0)}}%)
</view>
<view>
<text class="clr-sub">deviceId:</text>{{item.deviceId}}
</view>
<view >
<text class="clr-sub">Service数量:</text> {{item.advertisServiceUUIDs.length || 0}}
</view>
</view>
</template>
</view>
<view v-if="curTab == 1">
<view class="pb-10">服务列表</view>
<template v-for="(item, index) in serverList" :key="index">
<view @click="handleSelectService(item)"
:class="`list-item ${item.uuid == serviceId?'list-item-active':''}`"
>
<view>
<text class="clr-sub">uuid:</text> {{item.uuid}}
</view>
</view>
</template>
</view>
<view v-if="curTab == 2">
<view class="pb-10">特征值列表</view>
<template v-for="(item, index) in characteristics" :key="index">
<view @click="handleSelectChara(item)"
:class="`list-item ${item.uuid == characteristicId?'list-item-active':''}`"
>
<view>
<text class="clr-sub">uuid:</text> {{item.uuid}}
</view>
<template v-if="item.properties">
<view>
<text class="clr-sub">write:</text> {{item.properties.write}}
</view>
<view>
<text class="clr-sub">notify:</text> {{item.properties.notify}}
</view>
<view>
<text class="clr-sub">indicate:</text> {{item.properties.indicate}}
</view>
</template>
</view>
</template>
</view>
</view>
</template>
</tpx-layout>
<canvas canvas-id="shareCanvas" :style="{width:canvas_width+'px', height: canvas_height+'px'}"></canvas>
</tpx-page>
</template>
<script>
import { showLoading, showToast, hideLoading } from "@/common/untool"
import PrinterJobs from './print/printerjobs.js'
import * as printerUtil from './print/printerutil.js'
import * as util from './print/util.js'
export default {
name: 'bluetoothPrint',
computed: {
conInfos() {
let ary = [
{ title: '蓝牙设备', desc: this.deviceId || '-' },
{ title: '服务', desc: this.serviceId || '-' },
{ title: '特征值', desc: this.characteristicId || '-' }
]
return ary
},
},
data () {
return {
canvasId: 'shareCanvas',
canvas_width: 240,
canvas_height: 240,
curTab: 0,
devices: [],
deviceId: '',
serverList: [],
serviceId: '',
characteristics: [],
characteristicId: ''
}
},
mounted () {
// 初始化蓝牙模块
this.openBluetoothAdapter()
},
methods: {
changeTab(type) {
this.curTab = type
},
openBluetoothAdapter () {
var _this = this
uni?.openBluetoothAdapter?.({
complete (e) {
console.log(e);
if (!e.errCode) {
console.log('初始化完成')
} else if (e.errCode == 10001) {
showToast('请打开手机蓝牙')
} else {
console.log('openBluetoothAdapter:error=========', e.errMsg)
showToast(e.errMsg)
}
}
})
},
// 开始搜寻附近的蓝牙外围设备
discoveryPrinter () {
var _this = this
_this.devices = []
_this.curTab = 0
uni.startBluetoothDevicesDiscovery({
complete (e) {
console.log(e)
if (e.errMsg == "startBluetoothDevicesDiscovery:ok") {
// ArrayBuffer转16进度字符串示例
uni.onBluetoothDeviceFound(devices => {
console.log("========devices=====", devices)
let curDvs = devices?.devices?.[0] || {}
// 过滤重复的
if(curDvs.deviceId && _this.devices.map(t=> t.deviceId).indexOf(curDvs.deviceId) == -1) {
_this.devices.push(curDvs)
}
})
}
}
})
},
// 停止搜寻附近的蓝牙外围设备
async stopDiscoveryPrinter () {
let res = await this.renderPic()
uni.stopBluetoothDevicesDiscovery()
},
async handleSelectDeviceId (item) {
this.deviceId = item.deviceId
this.serviceId = ''
this.serverList = []
this.characteristics = []
this.characteristicId = ''
//连接蓝牙
await this.connect()
if(this.serverList?.length > 0) {
this.curTab = 1
} else {
showToast('该设备无服务,请检查配置或换一个设备连接')
}
},
handleSelectService (item) {
this.serviceId = item.uuid
this.characteristics = []
this.characteristicId = ''
// 获取蓝牙特征值
setTimeout(async () =>{
await this.getBLEDeviceCharacteristics()
if(this.characteristics?.length > 0) {
this.curTab = 2
} else {
showToast('该服务无特征值,请检查配置或换一个服务')
}
}, 500);
},
handleSelectChara (item) {
this.characteristicId = item.uuid
},
connect () {
var _this = this
console.log("连接蓝牙=====deviceId", _this.deviceId)
showLoading('正在连接蓝牙')
return new Promise((resolve)=> {
uni.createBLEConnection({
deviceId: _this.deviceId,
complete (e) {
hideLoading()
console.log("蓝牙连接回调=====", e)
if (e.errMsg == "createBLEConnection:ok") {
showToast(`蓝牙连接成功`)
//获取蓝牙设备所有服务(service)。
setTimeout(async()=> {
await _this.getBLEDeviceServices()
resolve()
}, 2000)
} else {
resolve()
showToast(`连接设备失败:${e.errMsg}`)
}
}
})
})
},
getBLEDeviceServices(){
var _this = this
return new Promise((resolve)=> {
showLoading('正在搜索服务')
uni.getBLEDeviceServices({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId: _this.deviceId,
success:(res)=>{
hideLoading()
resolve()
console.log('device services:', res)
_this.serverList = res.services
// _this.serviceId = res.services[0].uuid;
console.log('serverId:', _this.serviceId)
},
fail:(e) =>{
hideLoading()
resolve()
this.serverList = []
showToast(`设备服务获取失败:${e.errMsg}`)
console.log("getBLEDeviceServices - fail==============", e)
}
})
})
},
getBLEDeviceCharacteristics () {
var _this = this
return new Promise((resolve)=> {
showLoading('正在搜索特征值')
uni.getBLEDeviceCharacteristics({
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId: _this.deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId:_this.serviceId,
success:(res)=>{
hideLoading()
console.log('getBLEDeviceCharacteristics', res)
_this.characteristics = res.characteristics
resolve()
// _this.characteristicId = res.characteristics[0].uuid
},
fail:(res)=>{
hideLoading()
resolve()
console.log(res)
}
})
})
},
// 打印-发送二进制数据
async writeBLECharacteristicValue(){
let errmsg = ''
if (!this.deviceId) {
errmsg = '请选择设备'
}
if (!this.serviceId) {
errmsg = '请选择设备服务'
}
if (!this.characteristicId) {
errmsg = '请选择特征值'
}
if(errmsg){
showToast(errmsg)
return
}
try{
let pic_res = await this.renderPic();
showToast('图片获取成功')
}catch(e){
showToast('图片获取失败')
}
let printerJobs = new PrinterJobs()
var arr = [{
title: '阿根廷车厘子',
number: 20,
price: '¥188.00'
}, {
title: '新鲜山竹',
number: 38,
price: '¥199.00'
}]
var arr2 = [{
title: '平台消暑费',
price: '9.99'
},{
title: '打包费',
price: '2.00',
}]
printerJobs
.print(`下单时间:2021-07-25 15:30:23`)
.print(printerUtil.fillLine())
.print('备注')
.setSize(2, 2)
.setBold(true)
.print(`叫那位非常漂亮的小姐姐送来,其他人送来拒收`)
.print(printerUtil.fillLine())
.printQrcode(pic_res)
// .setSize(1, 1)
// .setBold(false)
// .print(printerUtil.fillLine('*'))
// .setAlign('lt')
// .printArray(arr)
// .print(printerUtil.fillAround('其它'))
// .print(printerUtil.inline('平台随机立减', `-2.10`))
// .print(printerUtil.inline('平台服务费', `-10.99`))
// .printArray(arr2)
// .print(printerUtil.fillLine())
// .setAlign('rt')
// .setSize(1, 2)
// .setBold(true)
// .print(`用户支付:¥99.99`)
.print(printerUtil.fillLine())
let buffer = printerJobs.buffer();
console.log('buffer>>>',buffer)
showLoading('正在打印')
try{
await this.printbuffs(buffer)
hideLoading()
showToast('打印成功')
}catch(e){
hideLoading()
console.log('打印异常', e)
}
},
printbuffs(buffer) {
let _this = this
return new Promise(async (resolve, reject)=> {
// 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);
await new Promise((resolve)=> {
setTimeout(resolve, j * delay)
})
try{
await _this.printbuff(subPackage)
}catch(msg){
console.log("printbuffs:异常==", msg)
showToast('分段printbuff异常', msg)
return reject(msg)
}
}
resolve()
})
},
getImageInfo(params = {}) {
return new Promise((resolve, reject)=> {
uni.canvasGetImageData({
x: 0,
y: 0,
...params,
success(res) {
console.log("img====",res);
if(res.data) {
let data = util.zip_image(res)
console.log("zip====", data);
resolve(data);
} else {
showToast('获取图片信息异常:getImageInfo')
reject('获取图片信息异常:getImageInfo')
}
}
})
})
},
renderPic() {
let filePath = 'http://oss-emis.tanex56.com/sapp/sdg/hdbg.png' // TODO
let that = this
return new Promise((resolve, reject)=> {
const cxt = uni.createCanvasContext(that.canvasId, that);
let scla = 1
uni.getImageInfo({
src: filePath,
success(res) {
// that.canvasWidth = res.width * scla
// that.canvasHeight = res.height * scla
// console.log(res, that.canvasWidth, that.canvasHeight)
cxt.drawImage(filePath, 0, 0, that.canvas_width, that.canvas_height);
cxt.draw();
that.$nextTick(async () => { //获取画布像素数据
let data = await that.getImageInfo({ canvasId: that.canvasId, width: that.canvas_width, height: that.canvas_height, })
resolve(data)
})
},
fail(e) {
reject(e)
console.log(e)
}
})
})
},
printbuff(buffer) {
var _this = this
return new Promise((resolve, reject)=> {
uni.writeBLECharacteristicValue({
// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
deviceId: _this.deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId: _this.serviceId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId: _this.characteristicId,
// 这里的value是ArrayBuffer类型
value: buffer,
success:(res)=> {
console.log('writeBLECharacteristicValue success', res.errMsg)
resolve()
},
fail:(res)=> {
console.log('writeBLECharacteristicValue fail', res.errMsg)
reject(res.errMsg)
},
complete (e) {
console.log('writeBLECharacteristicValue complete', e)
}
})
})
}
}
}
</script>
<style scoped lang="scss">
.list-item {
font-size: 26rpx;
margin-bottom: 20rpx;
border-radius: 10rpx;
border: 2rpx solid #ddd;
padding: 20rpx;
background-color: #F6F6F6;
}
.list-item-active{
border-color: #B12D29;
&:last-child{
margin-bottom: 0;
}
}
/*二维码隐藏到窗口外*/
canvas {
position: absolute;
top: -999rpx
}
</style>