import { lefuService } from '../../lefu/index' import type { ScannedDevice } from '../../lefu/index' import type { RawDevice } from '../../lefu/types' /** 展示用设备项(仅存入 setData,不含复杂对象) */ interface DeviceItem { name: string connected: boolean } /** 页面状态 */ type DeviceStatus = 'idle' | 'searching' | 'found' | 'empty' /** 页面级原始设备缓存,不进入 setData 避免序列化异常 */ let _rawDevices: ScannedDevice[] = [] const TAG = '[connectedDevice]' Page({ data: { status: 'idle' as DeviceStatus, deviceList: [] as DeviceItem[], /** 防止权限弹框重入 */ _modalLock: false, /** 自动连接缓存设备的一次性标记,防止扫描回调反复触发 */ _autoConnectTried: false, }, onShow() { console.log(TAG, 'onShow') }, onHide() { console.log(TAG, 'onHide, 停止扫描') // _rawDevices = [] // this.setData({ status: 'idle', deviceList: [] }) lefuService.stopScan() }, onUnload() { console.log(TAG, 'onUnload, 停止扫描') lefuService.stopScan() }, /** 点击「开始搜索 / 重新搜索」按钮:先验权限,再扫描 */ async onStartSearch() { console.log(TAG, 'onStartSearch, _modalLock:', this.data._modalLock) if (this.data._modalLock) return _rawDevices = [] this.setData({ status: 'searching', deviceList: [], _autoConnectTried: false }) await this._checkPermissionAndScan() }, /** 检查蓝牙 + 位置权限,通过后开始扫描 */ async _checkPermissionAndScan() { console.log(TAG, '_checkPermissionAndScan 开始') try { const { authSetting } = await wx.getSetting() const setting = authSetting as Record const hasBle = setting['scope.bluetooth'] const hasLoc = setting['scope.userLocation'] console.log(TAG, '权限状态 → 蓝牙:', hasBle, '位置:', hasLoc) if (hasBle && hasLoc) { await this._openAdapterAndScan() return } // 逐个申请缺失权限 const missing: Array<{ scope: string; label: string }> = [] if (!hasBle) missing.push({ scope: 'scope.bluetooth', label: '蓝牙' }) if (!hasLoc) missing.push({ scope: 'scope.userLocation', label: '位置' }) console.log(TAG, '缺失权限:', missing.map(m => m.label)) try { for (const item of missing) { console.log(TAG, '申请权限:', item.scope) await wx.authorize({ scope: item.scope }) console.log(TAG, '权限申请成功:', item.scope) } await this._openAdapterAndScan() } catch (err) { console.warn(TAG, '权限申请被拒绝:', err) this._showPermissionModal(missing.map(m => m.label).join('和')) } } catch (err) { console.error(TAG, 'getSetting 失败:', err) wx.showToast({ title: '获取权限设置失败', icon: 'none' }) this.setData({ status: 'idle' }) } }, /** 引导用户去设置页开启权限 */ _showPermissionModal(permissionNames: string) { console.log(TAG, '弹出权限引导框, 缺失:', permissionNames) this.setData({ _modalLock: true }) wx.showModal({ title: '需要授权', content: `小程序需要您的${permissionNames}权限才能搜索蓝牙设备,请前往手机设置开启。`, confirmText: '去开启', cancelText: '取消', success: (res) => { console.log(TAG, '权限弹框结果:', res.confirm ? '去开启' : '取消') this.setData({ _modalLock: false, status: 'idle' }) if (res.confirm) { wx.openSetting({ success: () => this.onStartSearch(), }) } }, fail: () => { this.setData({ _modalLock: false, status: 'idle' }) }, }) }, /** 打开蓝牙适配器,成功后启动扫描 */ async _openAdapterAndScan() { console.log(TAG, 'wx.openBluetoothAdapter() 开始') try { await wx.openBluetoothAdapter() console.log(TAG, 'wx.openBluetoothAdapter() 成功') this._startScan() } catch (err: any) { console.error(TAG, 'wx.openBluetoothAdapter() 失败, errCode:', err?.errCode, err?.errMsg) if (err?.errCode === 10001) { wx.showModal({ title: '蓝牙未开启', content: '请先开启手机蓝牙后重试', showCancel: false, confirmText: '知道了', success: () => this.setData({ status: 'idle' }), }) } else { wx.showToast({ title: '蓝牙初始化失败', icon: 'none' }) this.setData({ status: 'idle' }) } } }, /** 权限已就绪,注册设备列表回调并启动扫描 */ _startScan() { console.log(TAG, '_startScan 启动') lefuService.onDevicesList((devices) => { console.log(TAG, 'onDevicesList 回调, 设备数:', devices.length, devices.map(d => d.name)) if (!devices.length) { _rawDevices = [] this.setData({ status: 'empty', deviceList: [] }) return } _rawDevices = devices // 保留已连接设备的状态,避免扫描刷新时把 connected 重置为 false const connectedName = this.data.deviceList.find(d => d.connected)?.name const list: DeviceItem[] = devices.map(d => ({ name: d.name, connected: d.name === connectedName, })) this.setData({ status: 'found', deviceList: list }) // 缓存设备命中:自动连接一次 if (this.data._autoConnectTried) return const cached = wx.getStorageSync('connectDeviceInfo') as RawDevice | null const cachedDeviceId = cached?.deviceId if (!cachedDeviceId) return const matchedIndex = devices.findIndex(d => d.raw.deviceId === cachedDeviceId) if (matchedIndex < 0) return console.log(TAG, '命中缓存设备, deviceId:', cachedDeviceId, 'index:', matchedIndex) this.setData({ _autoConnectTried: true }) this._autoConnectByIndex(matchedIndex) }) lefuService.startScan() console.log(TAG, 'lefuService.startScan() 已调用') }, /** 缓存设备自动连接(与 onConnect 共享连接流程) */ _autoConnectByIndex(index: number) { const raw = _rawDevices[index] if (!raw) return wx.showLoading({ title: '连接中...', mask: true }) lefuService.stopScan() lefuService.connect(raw.raw) lefuService.onConnectState((state) => { if (state === lefuService.BLUE_STATE.CONNECTFAILED) { wx.hideLoading() wx.showToast({ title: '连接失败,请重试', icon: 'none' }) } }) lefuService.onDeviceConnect(() => { wx.setStorageSync('connectDeviceInfo', { ...raw.raw, scaleDeviceName: raw.raw.name }) const list = this.data.deviceList.map((item, i) => ({ ...item, connected: i === index, })) this.setData({ deviceList: list }) wx.hideLoading() console.log(TAG, '缓存设备已自动连接(不跳转)') }) }, /** 点击整张卡片:已连接 → 跳转配网页;未连接 → 走手动连接流程 */ onTapCard(e: WechatMiniprogram.TouchEvent) { const connected = e.currentTarget.dataset.connected as boolean console.log(TAG, 'onTapCard, connected:', connected) if (connected) { wx.navigateTo({ url: '/pages/connectedWifi/connectedWifi' }) return } this.onConnect(e) }, /** 连接指定设备 */ onConnect(e: WechatMiniprogram.TouchEvent) { const index = e.currentTarget.dataset.index as number const raw = _rawDevices[index] console.log(TAG, 'onConnect, index:', index, 'device:', raw) if (!raw) { console.warn(TAG, 'onConnect: 找不到对应 raw device, index:', index) return } wx.showLoading({ title: '连接中...', mask: true }) lefuService.connect(raw.raw) lefuService.onConnectState((state) => { if (state === lefuService.BLUE_STATE.CONNECTFAILED) { wx.hideLoading() wx.showToast({ title: '连接失败,请重试', icon: 'none' }) } }) lefuService.onDeviceConnect(() => { wx.setStorageSync('connectDeviceInfo', { ...raw.raw, scaleDeviceName: raw.raw.name }) const list = this.data.deviceList.map((item, i) => ({ ...item, connected: i === index, })) this.setData({ deviceList: list }) wx.hideLoading() console.log(TAG, '设备连接就绪,跳转配网页') wx.navigateTo({ url: '/pages/connectedWifi/connectedWifi' }) }) }, /** 断开当前连接 */ onDisconnect() { console.log(TAG, 'onDisconnect') const list = this.data.deviceList.map(item => ({ ...item, connected: false })) this.setData({ deviceList: list }) lefuService.disconnect() }, /** 查看帮助 */ onOpenHelp() { wx.showToast({ title: '请确保设备已开机且在附近', icon: 'none' }) }, })