173 lines
5.6 KiB
Vue
173 lines
5.6 KiB
Vue
<template>
|
||
<view class="container">
|
||
<!-- 步骤1:扫描设备 -->
|
||
<button @click="startScan">1. 扫描蓝牙设备</button>
|
||
<view v-if="devices.length">
|
||
<view v-for="device in devices" :key="device.deviceId" class="device-item" @click="selectDevice(device)">
|
||
<text>{{ device.name || '未知设备' }}</text>
|
||
<text class="mac">{{ device.deviceId }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 步骤2:连接后展示服务 -->
|
||
<view v-if="services.length">
|
||
<text>请选择服务:</text>
|
||
<view v-for="svc in services" :key="svc.uuid" class="service-item" @click="selectService(svc)">
|
||
<text>{{ svc.uuid }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 步骤3:选择特征值 -->
|
||
<view v-if="characteristics.length">
|
||
<text>请选择写入特征值:</text>
|
||
<view v-for="char in characteristics" :key="char.uuid" class="char-item" @click="selectWriteChar(char)">
|
||
<text>{{ char.uuid }} ({{ char.properties.write ? '可写' : '' }})</text>
|
||
</view>
|
||
<text>请选择通知特征值(可选):</text>
|
||
<view v-for="char in characteristics" :key="char.uuid" class="char-item" @click="selectNotifyChar(char)">
|
||
<text>{{ char.uuid }} ({{ char.properties.notify ? '可通知' : '' }})</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 步骤4:保存配置 -->
|
||
<button v-if="selectedWriteChar" @click="saveConfiguration">4. 保存配置并测试连接</button>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import bluetoothManager from '@/utils/BluetoothManager.js';
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
devices: [], // 扫描到的设备列表
|
||
selectedDeviceId: null,
|
||
services: [], // 选中设备的服务列表
|
||
characteristics: [], // 选中服务的特征值列表
|
||
selectedServiceId: null,
|
||
selectedWriteChar: null,
|
||
selectedNotifyChar: null,
|
||
};
|
||
},
|
||
methods: {
|
||
async startScan() {
|
||
await bluetoothManager.init();
|
||
this.devices = [];
|
||
bluetoothManager.setDeviceFoundCallback((device) => {
|
||
// 避免重复添加
|
||
if (!this.devices.find(d => d.deviceId === device.deviceId)) {
|
||
this.devices.push(device);
|
||
}
|
||
});
|
||
await bluetoothManager.startScan();
|
||
uni.showToast({ title: '扫描中...', icon: 'none' });
|
||
// 30秒后停止
|
||
setTimeout(() => bluetoothManager.stopScan(), 30000);
|
||
},
|
||
|
||
async selectDevice(device) {
|
||
bluetoothManager.stopScan();
|
||
uni.showLoading({ title: '连接设备中...' });
|
||
try {
|
||
const { services, deviceId } = await bluetoothManager.connectForDiscovery(device.deviceId);
|
||
this.selectedDeviceId = deviceId;
|
||
this.services = services;
|
||
this.characteristics = [];
|
||
this.selectedServiceId = null;
|
||
this.selectedWriteChar = null;
|
||
this.selectedNotifyChar = null;
|
||
uni.hideLoading();
|
||
uni.showToast({ title: '连接成功,请选择服务', icon: 'success' });
|
||
} catch (err) {
|
||
uni.hideLoading();
|
||
uni.showToast({ title: '连接失败', icon: 'none' });
|
||
}
|
||
},
|
||
|
||
async selectService(service) {
|
||
this.selectedServiceId = service.uuid;
|
||
uni.showLoading({ title: '获取特征值...' });
|
||
try {
|
||
const chars = await this._getCharacteristics(this.selectedDeviceId, service.uuid);
|
||
this.characteristics = chars;
|
||
uni.hideLoading();
|
||
} catch (err) {
|
||
uni.hideLoading();
|
||
uni.showToast({ title: '获取特征值失败', icon: 'none' });
|
||
}
|
||
},
|
||
|
||
async _getCharacteristics(deviceId, serviceId) {
|
||
return new Promise((resolve, reject) => {
|
||
uni.getBLEDeviceCharacteristics({
|
||
deviceId,
|
||
serviceId,
|
||
success: (res) => resolve(res.characteristics),
|
||
fail: reject,
|
||
});
|
||
});
|
||
},
|
||
|
||
selectWriteChar(char) {
|
||
if (!char.properties.write && !char.properties.writeNoResponse) {
|
||
uni.showToast({ title: '该特征值不支持写入', icon: 'none' });
|
||
return;
|
||
}
|
||
this.selectedWriteChar = char.uuid;
|
||
},
|
||
|
||
selectNotifyChar(char) {
|
||
if (!char.properties.notify && !char.properties.indicate) {
|
||
uni.showToast({ title: '该特征值不支持通知', icon: 'none' });
|
||
return;
|
||
}
|
||
this.selectedNotifyChar = char.uuid;
|
||
},
|
||
|
||
async saveConfiguration() {
|
||
if (!this.selectedWriteChar) {
|
||
uni.showToast({ title: '请先选择写入特征值', icon: 'none' });
|
||
return;
|
||
}
|
||
try {
|
||
await bluetoothManager.saveAndConnect(
|
||
this.selectedDeviceId,
|
||
this.selectedServiceId,
|
||
this.selectedWriteChar,
|
||
this.selectedNotifyChar
|
||
);
|
||
// 保存配置到本地
|
||
const config = {
|
||
deviceId: this.selectedDeviceId,
|
||
serviceId: this.selectedServiceId,
|
||
writeCharId: this.selectedWriteChar,
|
||
notifyCharId: this.selectedNotifyChar,
|
||
deviceName: this.devices.find(d => d.deviceId === this.selectedDeviceId)?.name || '',
|
||
};
|
||
uni.setStorageSync('bleDeviceConfig', config);
|
||
uni.showToast({ title: '配置已保存,可返回使用', icon: 'success' });
|
||
// 可选:跳转到主页面
|
||
setTimeout(() => uni.navigateBack(), 1500);
|
||
} catch (err) {
|
||
console.error('保存失败', err);
|
||
uni.showToast({ title: '保存失败', icon: 'none' });
|
||
}
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
@import '@/styles/variables.scss';
|
||
|
||
.device-item, .service-item, .char-item {
|
||
padding: 10px;
|
||
border-bottom: 1px solid #ddd;
|
||
margin: 5px 0;
|
||
}
|
||
.mac {
|
||
font-size: $font-size-sm;
|
||
color: gray;
|
||
margin-left: 10px;
|
||
}
|
||
</style> |