import { useEffect, useState } from 'react' import Taro from '@tarojs/taro' import { View, Text } from '@tarojs/components' import { Navbar } from '@/components/navbar' import { useBle } from '@/ble/hooks/useBle' import { navigateTo } from '@/utils/navigation' import { ROUTES } from '@/constants/routes' import { getErrorMessage } from '@/utils/error' import { DEVICE_ACTION_KEYS, ACTION_REGISTRY, isEp832Device } from '@/constants/deviceActions' import type { BleDevice } from '@/ble/hooks/useBle' import styles from './ble-config.module.scss' export default function DeviceBleConfig() { const { state, discovery } = useBle() const [preparingId, setPreparingId] = useState('') // 页面隐藏/卸载时清理搜索(对齐旧版 onHide/onUnload),连接保持供配网页使用 useEffect(() => { return () => { if (discovery.getState().isSearching) { discovery.stopSearch(false) } } // eslint-disable-next-line react-hooks/exhaustive-deps }, []) const startScan = async () => { if (state.searching) { await discovery.stopSearch() return } // startSearch 内部自动完成:Android 定位权限检查 + 适配器初始化 + // 服务 UUID 过滤扫描(00F4/F400/FFF4)+ 4s 无结果兜底全扫 + 30s 自动停止 try { await discovery.startSearch() } catch { // startSearch 内部已 toast 具体错误码,此处不再重复提示 } } // 点击"网络配置":连接 → 发现服务特征 → 订阅 F301(厂家确认无需鉴权)→ 打开配网页 const openWifiPanel = async (deviceId: string) => { if (preparingId) return setPreparingId(deviceId) Taro.showLoading({ title: '连接设备中', mask: true }) let prepError: unknown = null try { await discovery.prepareWifiConfig(deviceId) navigateTo(ROUTES.DEVICE_CONFIG) } catch (error) { prepError = error } finally { setPreparingId('') // showLoading 与 showToast 共用同一遮罩层,必须先 hideLoading 再弹提示 Taro.hideLoading() } if (prepError) { // 连接/订阅失败用模态弹窗,需用户主动确认,确保错误诊断信息可见可读 Taro.showModal({ title: '设备连接失败', content: getErrorMessage(prepError), showCancel: false, confirmText: '知道了' }) } } const invokeAction = (key: string, deviceId: string) => { if (key === 'WIFI') openWifiPanel(deviceId) // PARAMS/SERVER 仅占位,后续接入 } const isActionBusy = (key: string, deviceId: string) => key === 'WIFI' && preparingId === deviceId const renderDevice = (device: BleDevice) => { const actions = (DEVICE_ACTION_KEYS[isEp832Device(device) ? 'EP832' : 'DEFAULT'] ?? DEVICE_ACTION_KEYS.DEFAULT) .map((key) => ({ key, ...ACTION_REGISTRY[key] })) return ( {String(device.showName ?? device.deviceId)} {device.hasTargetService ? ( 00F4 ) : device.matchedByName || device.matchedByPayload ? ( 名称匹配 ) : null} {String(device.deviceId)} {actions.map((action) => { const busy = isActionBusy(action.key, device.deviceId) return ( !busy && invokeAction(action.key, device.deviceId)} > {busy ? action.busyLabel : action.label} ) })} ) } return ( {state.searching ? '搜索中' : '搜索'} *手机需开启蓝牙功能,Android手机还需开启定位功能 搜索到的设备列表 {state.deviceList.length === 0 ? ( 暂无搜索结果 ) : ( state.deviceList.map(renderDevice) )} ) }