|
@@ -12,7 +12,7 @@
|
|
|
|
|
|
|
|
<!-- 操作按钮区域 -->
|
|
<!-- 操作按钮区域 -->
|
|
|
<view class="pd-24 action-buttons">
|
|
<view class="pd-24 action-buttons">
|
|
|
- <up-button @click="handleStartSearch" class="mb-30" type="primary" :disabled="isConnected">
|
|
|
|
|
|
|
+ <up-button @click="handleStartSearch" class="mb-30" type="primary" :disabled="isSearching">
|
|
|
{{ isSearching ? '搜索中...' : '开始搜索' }}
|
|
{{ isSearching ? '搜索中...' : '开始搜索' }}
|
|
|
</up-button>
|
|
</up-button>
|
|
|
<view class="d-flex a-c j-c">
|
|
<view class="d-flex a-c j-c">
|
|
@@ -41,7 +41,8 @@
|
|
|
<view v-if="device.RSSI !== undefined" class="signal-strength"> 信号:{{ device.RSSI }} dBm </view>
|
|
<view v-if="device.RSSI !== undefined" class="signal-strength"> 信号:{{ device.RSSI }} dBm </view>
|
|
|
</view>
|
|
</view>
|
|
|
<view class="device-status">
|
|
<view class="device-status">
|
|
|
- <text v-if="connectedDevice?.deviceId === device.deviceId" class="status-connected">已连接</text>
|
|
|
|
|
|
|
+ <text v-if="isConnecting && connectingDeviceId === device.deviceId" class="status-new">连接中...</text>
|
|
|
|
|
+ <text v-else-if="connectedDevice?.deviceId === device.deviceId" class="status-connected">已连接</text>
|
|
|
<text v-else class="status-new">未连接</text>
|
|
<text v-else class="status-new">未连接</text>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
@@ -56,7 +57,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { checkBluetoothPermission, initBluetoothAdapter, getBluetoothAdapterState, startBluetoothDevicesDiscovery, stopBluetoothDevicesDiscovery, connectBLEDevice, closeBLEConnection, getBLEDeviceServicesAndCharacteristics, getBluetoothDevices } from '@/utils/blue-device-services';
|
|
|
|
|
|
|
+import { checkBluetoothPermission, initBluetoothAdapter, getBluetoothAdapterState, startBluetoothDevicesDiscovery, stopBluetoothDevicesDiscovery, connectBLEDevice, closeBLEConnection, getBLEDeviceServicesAndCharacteristics, getBluetoothDevices, onBLEConnectionStateChange } from '@/utils/blue-device-services';
|
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
|
info: {
|
|
info: {
|
|
|
type: Object,
|
|
type: Object,
|
|
@@ -76,10 +77,12 @@ const props = defineProps({
|
|
|
const emit = defineEmits(['connected', 'disconnected', 'next', 'prev']);
|
|
const emit = defineEmits(['connected', 'disconnected', 'next', 'prev']);
|
|
|
const isSearching = ref(false);
|
|
const isSearching = ref(false);
|
|
|
const isInitialized = ref(false);
|
|
const isInitialized = ref(false);
|
|
|
|
|
+const isConnecting = ref(false);
|
|
|
|
|
+const connectingDeviceId = ref('');
|
|
|
const devices = ref<Array<any>>([]);
|
|
const devices = ref<Array<any>>([]);
|
|
|
const connectedDevice = ref<any | null>(null);
|
|
const connectedDevice = ref<any | null>(null);
|
|
|
-const isConnected = computed(() => !!connectedDevice.value);
|
|
|
|
|
let stopDiscoveryListener: (() => void) | null = null;
|
|
let stopDiscoveryListener: (() => void) | null = null;
|
|
|
|
|
+let stopConnectionStateListener: (() => void) | null = null;
|
|
|
let searchTimeout: number | null = null;
|
|
let searchTimeout: number | null = null;
|
|
|
|
|
|
|
|
const toast = (title: string) => {
|
|
const toast = (title: string) => {
|
|
@@ -88,8 +91,9 @@ const toast = (title: string) => {
|
|
|
|
|
|
|
|
const updateDeviceList = (device: any) => {
|
|
const updateDeviceList = (device: any) => {
|
|
|
if (!device?.deviceId) return;
|
|
if (!device?.deviceId) return;
|
|
|
- if (device.name.startsWith('未知或不支持的设备')) return;
|
|
|
|
|
- if (!device.name.startsWith('GP-')) return;
|
|
|
|
|
|
|
+ const deviceName = device.name || '';
|
|
|
|
|
+ if (deviceName.startsWith('未知或不支持的设备')) return;
|
|
|
|
|
+ if (!deviceName.startsWith('GP-')) return;
|
|
|
const idx = devices.value.findIndex((d) => d.deviceId === device.deviceId);
|
|
const idx = devices.value.findIndex((d) => d.deviceId === device.deviceId);
|
|
|
if (idx >= 0) {
|
|
if (idx >= 0) {
|
|
|
devices.value[idx] = { ...devices.value[idx], ...device };
|
|
devices.value[idx] = { ...devices.value[idx], ...device };
|
|
@@ -134,12 +138,33 @@ const initBluetooth = async () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+const setupConnectionStateListener = () => {
|
|
|
|
|
+ if (stopConnectionStateListener) return;
|
|
|
|
|
+
|
|
|
|
|
+ stopConnectionStateListener = onBLEConnectionStateChange(async (res: any) => {
|
|
|
|
|
+ if (!res?.deviceId || res.connected) return;
|
|
|
|
|
+ if (connectedDevice.value?.deviceId !== res.deviceId) return;
|
|
|
|
|
+
|
|
|
|
|
+ const disconnectedDeviceId = connectedDevice.value.deviceId;
|
|
|
|
|
+ connectedDevice.value = null;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ await closeBLEConnection(disconnectedDeviceId);
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ // ignore
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ emit('disconnected', { deviceId: disconnectedDeviceId, reason: 'connection-lost' });
|
|
|
|
|
+ toast('设备连接已断开');
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
const handleStartSearch = async () => {
|
|
const handleStartSearch = async () => {
|
|
|
if (isSearching.value) return;
|
|
if (isSearching.value) return;
|
|
|
|
|
|
|
|
if (!isInitialized.value) {
|
|
if (!isInitialized.value) {
|
|
|
- toast('请先初始化蓝牙,再开始搜索');
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ await initBluetooth();
|
|
|
|
|
+ if (!isInitialized.value) return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
isSearching.value = true;
|
|
isSearching.value = true;
|
|
@@ -188,13 +213,31 @@ const handleConnectDevice = async (device: any) => {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (isConnecting.value) {
|
|
|
|
|
+ toast('正在连接,请稍候');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (connectedDevice.value?.deviceId === device.deviceId) {
|
|
if (connectedDevice.value?.deviceId === device.deviceId) {
|
|
|
toast('已连接该设备');
|
|
toast('已连接该设备');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
|
|
+ isConnecting.value = true;
|
|
|
|
|
+ connectingDeviceId.value = device.deviceId;
|
|
|
|
|
+
|
|
|
await stopSearch();
|
|
await stopSearch();
|
|
|
|
|
+
|
|
|
|
|
+ if (connectedDevice.value?.deviceId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await closeBLEConnection(connectedDevice.value.deviceId);
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ // ignore
|
|
|
|
|
+ }
|
|
|
|
|
+ connectedDevice.value = null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
await connectBLEDevice(device.deviceId);
|
|
await connectBLEDevice(device.deviceId);
|
|
|
|
|
|
|
|
const { services, characteristicsMap } = await getBLEDeviceServicesAndCharacteristics(device.deviceId);
|
|
const { services, characteristicsMap } = await getBLEDeviceServicesAndCharacteristics(device.deviceId);
|
|
@@ -232,24 +275,33 @@ const handleConnectDevice = async (device: any) => {
|
|
|
characteristicId,
|
|
characteristicId,
|
|
|
};
|
|
};
|
|
|
updateDeviceList(connectedDevice.value);
|
|
updateDeviceList(connectedDevice.value);
|
|
|
|
|
+ emit('connected', connectedDevice.value);
|
|
|
|
|
|
|
|
toast('蓝牙已连接');
|
|
toast('蓝牙已连接');
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
console.error('连接失败', error);
|
|
console.error('连接失败', error);
|
|
|
toast(error?.message || '设备连接失败,请重试');
|
|
toast(error?.message || '设备连接失败,请重试');
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ isConnecting.value = false;
|
|
|
|
|
+ connectingDeviceId.value = '';
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const handleDisconnect = async () => {
|
|
|
|
|
|
|
+const handleDisconnect = async (silent = false) => {
|
|
|
if (!connectedDevice.value?.deviceId) return;
|
|
if (!connectedDevice.value?.deviceId) return;
|
|
|
|
|
|
|
|
|
|
+ const deviceId = connectedDevice.value.deviceId;
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
- await closeBLEConnection(connectedDevice.value.deviceId);
|
|
|
|
|
- toast('已断开连接');
|
|
|
|
|
|
|
+ await closeBLEConnection(deviceId);
|
|
|
|
|
+ if (!silent) {
|
|
|
|
|
+ toast('已断开连接');
|
|
|
|
|
+ }
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.warn('断开连接失败', error);
|
|
console.warn('断开连接失败', error);
|
|
|
}
|
|
}
|
|
|
connectedDevice.value = null;
|
|
connectedDevice.value = null;
|
|
|
|
|
+ emit('disconnected', { deviceId, reason: 'manual-disconnect' });
|
|
|
};
|
|
};
|
|
|
const nextSteps = () => {
|
|
const nextSteps = () => {
|
|
|
if (!connectedDevice.value || !connectedDevice.value?.deviceId || !connectedDevice.value?.serviceId) {
|
|
if (!connectedDevice.value || !connectedDevice.value?.deviceId || !connectedDevice.value?.serviceId) {
|
|
@@ -272,10 +324,16 @@ const prevSteps = () => {
|
|
|
});
|
|
});
|
|
|
};
|
|
};
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
|
|
+ setupConnectionStateListener();
|
|
|
initBluetooth();
|
|
initBluetooth();
|
|
|
});
|
|
});
|
|
|
-onBeforeUnmount(() => {
|
|
|
|
|
- stopSearch();
|
|
|
|
|
|
|
+onBeforeUnmount(async () => {
|
|
|
|
|
+ await stopSearch();
|
|
|
|
|
+ if (connectedDevice.value?.deviceId) {
|
|
|
|
|
+ await handleDisconnect(true);
|
|
|
|
|
+ }
|
|
|
|
|
+ stopConnectionStateListener?.();
|
|
|
|
|
+ stopConnectionStateListener = null;
|
|
|
});
|
|
});
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|