This commit is contained in:
2026-06-02 15:28:25 +08:00
commit b271b84f70
249 changed files with 42240 additions and 0 deletions
+171
View File
@@ -0,0 +1,171 @@
<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>
.device-item, .service-item, .char-item {
padding: 10px;
border-bottom: 1px solid #ddd;
margin: 5px 0;
}
.mac {
font-size: 12px;
color: gray;
margin-left: 10px;
}
</style>