diff --git a/.idea/claudeCodeTabState.xml b/.idea/claudeCodeTabState.xml index ba4c915..faec8fa 100644 --- a/.idea/claudeCodeTabState.xml +++ b/.idea/claudeCodeTabState.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/miniprogram/app.ts b/miniprogram/app.ts index 28d4986..514a129 100644 --- a/miniprogram/app.ts +++ b/miniprogram/app.ts @@ -1,5 +1,3 @@ -import { lefuService } from './lefu/index' - App({ globalData: { /** 当前已连接设备的蓝牙状态,页面可读取 */ @@ -7,8 +5,6 @@ App({ }, onLaunch() { - // 初始化乐福蓝牙 SDK - lefuService.init() // 已登录则跳过登录页 // const userInfo = wx.getStorageSync('userInfo') diff --git a/miniprogram/images/connectedWifi/noData.png b/miniprogram/images/connectedWifi/noData.png index 9a7fab2..37783f3 100644 Binary files a/miniprogram/images/connectedWifi/noData.png and b/miniprogram/images/connectedWifi/noData.png differ diff --git a/miniprogram/lefu/service.ts b/miniprogram/lefu/service.ts index 2fabe85..fbdb864 100644 --- a/miniprogram/lefu/service.ts +++ b/miniprogram/lefu/service.ts @@ -14,14 +14,17 @@ import type { FirmwareVersion, } from './types' +/** 顶层加载插件(对齐 demo,requirePlugin 必须在文件顶层调用) */ +const plugin = requirePlugin('ppScale-plugin') as LeFuPlugin + /** 乐福 SDK 配置 */ const LEFU_CONFIG: LeFuConfig = { key: 'lefudc91611833e18d94', secret: 'eQ50JYimMp0X7uhNLj6D3lTEk4TUUvEG7dvaqKM9t1U=', - domain1: 'http://192.168.1.31:8889', // 测试环境(老版本 无鉴权) - domain2: 'http://192.168.1.31:8889/weight', // 测试环境(新版本 有鉴权) - // domain1: 'http://device.shuziweidao.com:80/gateway', // 正式环境 - // domain2: 'http://device.shuziweidao.com:80/weight', // 正式环境 + domain1: 'http://192.168.1.31:8889', + domain2: 'http://192.168.1.31:8889/weight', + // domain1: 'http://device.shuziweidao.com:80/gateway', + // domain2: 'http://device.shuziweidao.com:80/weight', } /** 支持的设备型号配置列表(5款) */ @@ -71,25 +74,17 @@ const DEVICE_SETTINGS: DeviceSetting[] = [ const TAG = '[LeFuService]' class LeFuService { - private _plugin: LeFuPlugin | null = null - /** 设备协议对象,devicesModel 事件返回,用于 WiFi 配网等高级操作 */ private _activeProtocol: any = null + private _connectState = '' + private _deviceInfo: DeviceInfo | null = null + private _busSubscribed = false + private _intentionalConnect = false - /** 重连次数 */ private _reconnectCount = 0 private readonly _maxReconnect = 3 private _reconnectTimer: number | null = null - - /** 保活心跳定时器 */ private _keepAliveTimer: number | null = null - /** 连接后从 deviceInfo 事件获取的固件信息 */ - private _deviceInfo: DeviceInfo | null = null - - /** bus 事件是否已订阅(防止多次 startScan 重复 subscribe 累积) */ - private _busSubscribed = false - - /** 回调注册(页面通过 on* 方法注册,stopScan 时清空) */ private _onDevicesListCb: ((devices: ScannedDevice[]) => void) | null = null private _onConnectStateCb: ((state: string) => void) | null = null private _onDeviceConnectCb: (() => void) | null = null @@ -98,142 +93,63 @@ class LeFuService { private _onDisconnectedCb: (() => void) | null = null private _onDeviceInfoCb: ((info: DeviceInfo) => void) | null = null - /** 在 app.ts onLaunch 中调用,加载 ppScale-plugin */ - init(): void { - console.log(TAG, 'init() 开始加载插件') - this._plugin = requirePlugin('ppScale-plugin') as LeFuPlugin - console.log(TAG, 'init() 插件加载完成:', !!this._plugin) - } - - /** 获取插件(未初始化时抛出) */ - private get _p(): LeFuPlugin { - if (!this._plugin) throw new Error('[LeFu] 服务未初始化,请先调用 init()') - return this._plugin - } - - /** 乐福配置(供体成分分析等外部使用) */ - get config(): LeFuConfig { - return LEFU_CONFIG - } + get config(): LeFuConfig { return LEFU_CONFIG } + get isConnected(): boolean { return !!this._activeProtocol } + get connectState(): string { return this._connectState } + get BLUE_STATE(): Record { return plugin.BLUE_STATE ?? {} } + get deviceInfo(): DeviceInfo | null { return this._deviceInfo } // ─── 回调注册 ───────────────────────────────── - - /** 注册设备列表回调(扫描到设备时触发) */ - onDevicesList(cb: (devices: ScannedDevice[]) => void): void { - console.log(TAG, 'onDevicesList 回调已注册') - this._onDevicesListCb = cb - } - - /** 注册蓝牙连接状态回调 */ - onConnectState(cb: (state: string) => void): void { - console.log(TAG, 'onConnectState 回调已注册') - this._onConnectStateCb = cb - } - - /** 注册设备连接就绪回调(activeProtocol 可用时触发) */ - onDeviceConnect(cb: () => void): void { - console.log(TAG, 'onDeviceConnect 回调已注册') - this._onDeviceConnectCb = cb - } - - /** 当前蓝牙连接状态(connectState bus 事件实时更新) */ - private _connectState = '' - - /** 设备是否已连接(activeProtocol 就绪) */ - get isConnected(): boolean { - return !!this._activeProtocol - } - - /** 当前蓝牙连接状态字符串 */ - get connectState(): string { - return this._connectState - } - - /** 插件 BLUE_STATE 常量对象(供页面 wxml 条件判断用) */ - get BLUE_STATE(): Record { - return this._plugin?.BLUE_STATE ?? {} - } - - /** 连接后从 deviceInfo 事件获取的设备信息(含 modelNumber / serialNumber 等) */ - get deviceInfo(): DeviceInfo | null { - return this._deviceInfo - } - - /** 注册实时测量回调(测量过程中多次触发) */ - onMeasuring(cb: (data: ProgressData) => void): void { - this._onProgressCb = cb - } - - /** 注册测量完成回调(数据锁定,触发一次) */ - onLocked(cb: (data: LockData) => void): void { - this._onLockedCb = cb - } - - /** 注册设备断开回调 */ - onDisconnected(cb: () => void): void { - this._onDisconnectedCb = cb - } - - /** 注册 deviceInfo 就绪回调(设备名/固件信息可用时触发) */ - onDeviceInfo(cb: (info: DeviceInfo) => void): void { - this._onDeviceInfoCb = cb - } + onDevicesList(cb: (devices: ScannedDevice[]) => void): void { this._onDevicesListCb = cb } + onConnectState(cb: (state: string) => void): void { this._onConnectStateCb = cb } + onDeviceConnect(cb: () => void): void { this._onDeviceConnectCb = cb } + onMeasuring(cb: (data: ProgressData) => void): void { this._onProgressCb = cb } + onLocked(cb: (data: LockData) => void): void { this._onLockedCb = cb } + onDisconnected(cb: () => void): void { this._onDisconnectedCb = cb } + onDeviceInfo(cb: (info: DeviceInfo) => void): void { this._onDeviceInfoCb = cb } // ─── 扫描与连接 ─────────────────────────────── - - /** - * 开始蓝牙扫描 - * 对齐 master:先 setDeviceSetting → start,再 subscribe(master searchDevice.js 顺序) - */ startScan(): void { - console.log(TAG, 'startScan() 开始,busSubscribed:', this._busSubscribed) - const plugin = this._p - - // ① 先设置设备配置并启动扫描(必须在 subscribe 之前,与 master 一致) + console.log(TAG, 'startScan()') plugin.Blue.setDeviceSetting(DEVICE_SETTINGS) - const deviceNames = DEVICE_SETTINGS.map(s => s.deviceName) - console.log(TAG, 'plugin.Blue.start() 调用,设备名称:', deviceNames) - plugin.Blue.start(deviceNames, false) + this._subscribeBus() + plugin.Blue.start(DEVICE_SETTINGS.map(s => s.deviceName), false) + } - // bus 订阅只注册一次,stopScan 时重置,避免多次搜索导致订阅累积 + private _subscribeBus(): void { if (this._busSubscribed) { - console.log(TAG, 'bus 已订阅,跳过重复注册') + console.log(TAG, 'bus 已订阅,跳过') return } this._busSubscribed = true - // ② 启动后再订阅设备列表(master 也是 start 后才 subscribe) plugin.bus.subscribe('devicesList', (devList: RawDevice[]) => { - console.log(TAG, 'bus[devicesList] 触发,原始设备数:', devList?.length, devList?.map((d: RawDevice) => d.name || d.deviceName)) - if (!devList || !devList.length) { + console.log(TAG, 'bus[devicesList],设备数:', devList?.length) + if (!devList?.length) { this._onDevicesListCb?.([]) return } - // 直接用原始列表转换,不调用 getDeviceModel(master 也是直接传 res) const devices: ScannedDevice[] = devList.map((item: RawDevice) => ({ name: item.name || item.deviceName || '未知设备', raw: item, model: {}, })) - console.log(TAG, '转换后设备列表:', devices.map(d => d.name)) this._onDevicesListCb?.(devices) }) - // 设备模型信息(含 mac 等,仅用于日志/调试) plugin.bus.subscribe('devicesModel', (res: any) => { - console.log(TAG, 'bus[devicesModel] 触发,deviceMac:', res?.deviceMac) + console.log(TAG, 'bus[devicesModel] 完整数据:', JSON.stringify(res)) }) - // 连接成功后获取固件信息(用于后续 OTA 版本比对) plugin.bus.subscribe('deviceInfo', (res: DeviceInfo) => { - console.log(TAG, 'bus[deviceInfo] 触发:',res, res?.firmwareRevision, res?.modelNumber) + console.log(TAG, 'bus[deviceInfo]:', res?.modelNumber) this._deviceInfo = res this._onDeviceInfoCb?.(res) }) - // 连接建立:从 ScaleAction 获取 activeProtocol,启动数据进度(对齐 master configureDevice.js) plugin.bus.subscribe('deviceConnect', () => { - console.log(TAG, 'bus[deviceConnect] 触发,获取 activeProtocol,启动数据进度') + console.log(TAG, 'bus[deviceConnect]') + this._intentionalConnect = false this._reconnectCount = 0 plugin.ScaleAction.startDataProgress(true) this._activeProtocol = plugin.ScaleAction.getActiveProtocol() @@ -241,228 +157,144 @@ class LeFuService { this._onDeviceConnectCb?.() }) - // 连接状态变化:CONNECTSUCCESS 时启动保活,CONNECTFAILED 时重连 plugin.bus.subscribe('connectState', (res: string) => { - console.log(TAG, 'bus[connectState] 触发:', res) + console.log(TAG, 'bus[connectState]:', res) this._connectState = res this._onConnectStateCb?.(res) if (res === plugin.BLUE_STATE.CONNECTSUCCESS) { - console.log(TAG, '连接成功,启动保活心跳') this._startKeepAlive() } if (res === plugin.BLUE_STATE.CONNECTFAILED) { - console.warn(TAG, '连接失败,触发重连逻辑') this._stopKeepAlive() - this._doReconnect() + if (!this._intentionalConnect) { + this._doReconnect() + } } }) - // 实时测量数据 plugin.bus.subscribe('progressData', (res: ProgressData) => { - console.log(TAG, 'bus[progressData] 体重(g):', res?.weight) this._onProgressCb?.(res) }) - // 测量锁定(完成) plugin.bus.subscribe('lockData', (res: LockData) => { - console.log(TAG, 'bus[lockData] 测量完成,体重(g):', res?.weight, '阻抗:', res?.resistance) this._onLockedCb?.(res) }) - // 设备自动断开 plugin.bus.subscribe('deviceWillDisconnect', () => { - console.warn(TAG, 'bus[deviceWillDisconnect] 设备断开,触发重连') + console.warn(TAG, 'bus[deviceWillDisconnect],intentionalConnect:', this._intentionalConnect) this._stopKeepAlive() this._onDisconnectedCb?.() - this._doReconnect() + if (!this._intentionalConnect) { + this._doReconnect() + } }) } - /** - * 主动连接指定设备(对齐 master:直接调 createBLEConnection,不判断 deviceConnectType) - */ connect(device: ScannedDevice): void { - console.log(TAG, 'connect() 设备:', device.name) - this._p.Blue.createBLEConnection(device.raw) - } - - /** 主动断开当前连接 */ - disconnect(): void { - console.log(TAG, 'disconnect() 主动断开') + console.log(TAG, 'connect():', device.name) + this._intentionalConnect = true this._stopKeepAlive() - this._p.Blue.disconnect() + this._stopReconnectTimer() + this._activeProtocol = null + this._connectState = '' + this._deviceInfo = null + this._onDeviceInfoCb = null + this._onDeviceConnectCb = null + plugin.Blue.stopBluetoothDevicesDiscovery() + plugin.Blue.createBLEConnection(device.raw) + } + + disconnect(): void { + console.log(TAG, 'disconnect()') + this._stopKeepAlive() + plugin.Blue.disconnect() } - /** - * 停止扫描(仅停止设备发现,不清连接态) - * connectedDevice onHide / onUnload 时调用 - */ stopScan(): void { - console.log(TAG, 'stopScan() 停止扫描') + console.log(TAG, 'stopScan()') this._stopReconnectTimer() - this._busSubscribed = false wx.stopBluetoothDevicesDiscovery() this._onDevicesListCb = null this._onDeviceConnectCb = null } // ─── WiFi 配网 ──────────────────────────────── - - /** - * 获取设备上报的 WiFi 列表(需设备已连接) - * 内部延迟 2 秒后调用,15 秒超时 - */ getWifiList(): Promise { - console.log(TAG, 'getWifiList() 开始') + console.log(TAG, 'getWifiList()') return new Promise((resolve, reject) => { if (!this._activeProtocol) { reject(new Error('[LeFu] 设备未连接,无法获取 WiFi 列表')) return } - - const timer = setTimeout(() => { - reject(new Error('[LeFu] 获取 WiFi 列表超时')) - }, 15000) - - // 延迟 2 秒,等待设备就绪后再请求 + const timer = setTimeout(() => reject(new Error('[LeFu] 获取 WiFi 列表超时')), 15000) setTimeout(() => { this._activeProtocol.dataFindSurroundDevice((res: any[]) => { clearTimeout(timer) - console.log(TAG, 'getWifiList 原始结果:', res) - if (!res || res.length === 0) { + console.log(TAG, 'getWifiList 结果:', res) + if (!res?.length) { this._activeProtocol.dataExitWifiConfig(() => {}) resolve([]) return } - const list: LeFuWifiItem[] = res.map((item: any) => ({ - ssid: item.ssid || item.name || '', - signal: item.signal, - })) - console.log(TAG, 'getWifiList 解析结果:', list.map(w => w.ssid)) - resolve(list) + resolve(res.map((item: any) => ({ ssid: item.ssid || item.name || '', signal: item.signal }))) }) }, 2000) }) } - /** - * 将 WiFi 配置写入设备 - * @param ssid WiFi 名称 - * @param password WiFi 密码 - * @param version 协议版本:domain1(无鉴权)| domain2(有鉴权) - * 返回码 23 = 配网成功 - */ configWifi(ssid: string, password: string, version: WifiVersion): Promise { - console.log(TAG, 'configWifi() ssid:', ssid, 'version:', version) + console.log(TAG, 'configWifi():', ssid, version) return new Promise((resolve, reject) => { if (!this._activeProtocol) { reject(new Error('[LeFu] 设备未连接,无法配网')) return } - const callback = (res: number) => { - console.log(TAG, 'configWifi 回调 res:', res) - if (res === 23) { - console.log(TAG, 'configWifi 成功') - resolve() - } else { - console.error(TAG, 'configWifi 失败,错误码:', res) - reject(new Error(`[LeFu] 配网失败,错误码:${res}`)) - } + console.log(TAG, 'configWifi 回调:', res) + res === 23 ? resolve() : reject(new Error(`[LeFu] 配网失败,错误码:${res}`)) } - if (version === 'domain1') { - this._activeProtocol.dataConfigNetWork( - { domain: LEFU_CONFIG.domain1, ssid, password }, - callback, - ) + this._activeProtocol.dataConfigNetWork({ domain: LEFU_CONFIG.domain1, ssid, password }, callback) } else { this._activeProtocol.dataConfigUserNetWork( - { - domain: LEFU_CONFIG.domain2, - ssid, - password, - userName: 'apiUser', - userPassword: '3acebb95eb49577e9c2a2082589b9bd6', - }, + { domain: LEFU_CONFIG.domain2, ssid, password, userName: 'apiUser', userPassword: '3acebb95eb49577e9c2a2082589b9bd6' }, callback, ) } }) } - /** - * 查询设备是否已完成配网 - * 返回 true = 已配网(0x01),false = 未配网 - */ checkWifiConfig(): Promise { - console.log(TAG, 'checkWifiConfig() 查询配网状态') return new Promise((resolve, reject) => { - if (!this._activeProtocol) { - reject(new Error('[LeFu] 设备未连接')) - return - } + if (!this._activeProtocol) { reject(new Error('[LeFu] 设备未连接')); return } this._activeProtocol.codeFetchWifiConfig((res: number | undefined | null) => { - console.log(TAG, 'checkWifiConfig 回调 res:', res, '已配网:', res === 0x01) resolve(res === 0x01) }) }) } // ─── OTA 升级 ───────────────────────────────── - - /** - * 检查固件版本并按需触发 OTA 升级 - * @returns true = 已触发升级,false = 无需升级 - * 调用时机由业务层决定,不自动触发 - */ checkAndUpgrade(): Promise { - console.log(TAG, 'checkAndUpgrade() 开始检查固件版本') return new Promise((resolve, reject) => { - if (!this._activeProtocol) { - reject(new Error('[LeFu] 设备未连接')) - return - } - if (!this._deviceInfo) { - reject(new Error('[LeFu] 固件信息未就绪,请稍后重试')) - return - } + if (!this._activeProtocol) { reject(new Error('[LeFu] 设备未连接')); return } + if (!this._deviceInfo) { reject(new Error('[LeFu] 固件信息未就绪')); return } const { firmwareRevision, modelNumber } = this._deviceInfo - console.log(TAG, '当前固件:', firmwareRevision, '型号:', modelNumber) const [mcuVer, bleVer, wifiVer, resVer] = (firmwareRevision || '').split('.') - - // 设备单段版本(如 "006")vs 服务端 x.y.z 格式(如 "0.0.6")比对 - const isServerNewer = (deviceVer: string, serverVer: string): boolean => { - const deviceNum = parseInt(deviceVer, 10) - const serverNum = (serverVer || '').split('.').map(v => parseInt(v, 10)).reduce((acc, v) => acc * 1000 + v, 0) - return serverNum > deviceNum + const isServerNewer = (dv: string, sv: string) => { + const dn = parseInt(dv, 10) + const sn = (sv || '').split('.').map(v => parseInt(v, 10)).reduce((a, v) => a * 1000 + v, 0) + return sn > dn } get('weighingScale/v2/firmware/version', { type: modelNumber }, { loading: false }) .then(res => { const { mcuVersion, bleVersion, wifiVersion, resVersion } = res.result - console.log(TAG, '服务端固件版本:', { mcuVersion, bleVersion, wifiVersion, resVersion }) - const needUpdate = - isServerNewer(mcuVer, mcuVersion) || - isServerNewer(bleVer, bleVersion) || - isServerNewer(wifiVer, wifiVersion) || - isServerNewer(resVer, resVersion) - - console.log(TAG, '需要 OTA 升级:', needUpdate) - if (!needUpdate) { - resolve(false) - return - } - - // status: false = 成功,true = 失败 + const needUpdate = isServerNewer(mcuVer, mcuVersion) || isServerNewer(bleVer, bleVersion) + || isServerNewer(wifiVer, wifiVersion) || isServerNewer(resVer, resVersion) + if (!needUpdate) { resolve(false); return } this._activeProtocol.codeOtaUpdate((status: boolean) => { - console.log(TAG, 'OTA 升级回调 status:', status) - if (!status) { - resolve(true) - } else { - reject(new Error('[LeFu] OTA 升级失败')) - } + status ? reject(new Error('[LeFu] OTA 升级失败')) : resolve(true) }) }) .catch(reject) @@ -470,20 +302,15 @@ class LeFuService { } // ─── 私有:保活与重连 ───────────────────────── - private _startKeepAlive(): void { this._stopKeepAlive() - console.log(TAG, '_startKeepAlive 保活心跳启动') - this._keepAliveTimer = setInterval(() => { - this._activeProtocol?.sendKeepAliveCode?.() - }, 15000) + this._keepAliveTimer = setInterval(() => { this._activeProtocol?.sendKeepAliveCode?.() }, 15000) } private _stopKeepAlive(): void { if (this._keepAliveTimer !== null) { clearInterval(this._keepAliveTimer) this._keepAliveTimer = null - console.log(TAG, '_stopKeepAlive 保活心跳停止') } } @@ -495,115 +322,62 @@ class LeFuService { this._reconnectCount = 0 } - /** 自动重连,最多 _maxReconnect 次,超限后等待用户手动重试 */ private _doReconnect(): void { if (this._reconnectCount >= this._maxReconnect) { - console.warn(TAG, '重连次数已达上限:', this._maxReconnect) + console.warn(TAG, '重连次数已达上限') return } this._reconnectCount++ - console.log(TAG, `_doReconnect 第 ${this._reconnectCount} 次重连`) + console.log(TAG, `_doReconnect 第 ${this._reconnectCount} 次`) this._stopReconnectTimer() this._reconnectTimer = setTimeout(() => { - this._plugin?.Blue?.disconnect((res: any) => { - console.log(TAG, '重连 disconnect 回调:', res?.errCode) - if (res?.errCode === 0) { - this._plugin?.Blue?.startBluetoothDevicesDiscovery() - } + plugin.Blue.disconnect((res: any) => { + if (res?.errCode === 0) plugin.Blue.startBluetoothDevicesDiscovery() }) }, 2000) } // ─── 成员同步 ───────────────────────────────── - - /** - * 全量将成员列表同步到设备 - * 流程:清除设备成员数据 → 逐个下发(顺序执行) - * 每步 15 秒超时保护,失败时自动重试当前成员 - * @param members 成员列表,必须包含且仅包含一个 isSelf=true 的主用户 - */ syncMembersToDevice(members: DeviceMember[]): Promise { - console.log(TAG, 'syncMembersToDevice() 成员数:', members.length) return new Promise((resolve, reject) => { - if (!this._activeProtocol) { - reject(new Error('[LeFu] 设备未连接,无法同步成员')) - return - } - + if (!this._activeProtocol) { reject(new Error('[LeFu] 设备未连接')); return } const mainUser = members.find(m => m.isSelf) - if (!mainUser) { - reject(new Error('[LeFu] 成员列表中缺少主用户(isSelf=true)')) - return - } - - // 第一步:清除设备上的所有成员数据("01" 仅清成员,保留历史) - const clearTimer = setTimeout(() => { - reject(new Error('[LeFu] 清除设备成员超时')) - }, 15000) + if (!mainUser) { reject(new Error('[LeFu] 缺少主用户')); return } + const clearTimer = setTimeout(() => reject(new Error('[LeFu] 清除设备成员超时')), 15000) this._activeProtocol.codeClearDeviceData('01', (clearRes: number) => { clearTimeout(clearTimer) - console.log(TAG, 'codeClearDeviceData 回调:', clearRes) - if (clearRes !== 0x00) { - reject(new Error('[LeFu] 清除设备成员失败')) - return - } + if (clearRes !== 0x00) { reject(new Error('[LeFu] 清除设备成员失败')); return } - // 第二步:逐个下发成员(顺序执行,失败自动重试当前) let index = 0 let syncTimer: number | null = null - const resetTimer = () => { if (syncTimer !== null) clearTimeout(syncTimer) - syncTimer = setTimeout(() => { - reject(new Error(`[LeFu] 第 ${index + 1} 个成员下发超时`)) - }, 15000) + syncTimer = setTimeout(() => reject(new Error(`[LeFu] 第 ${index + 1} 个成员下发超时`)), 15000) } - const syncNext = () => { if (index >= members.length) { if (syncTimer !== null) clearTimeout(syncTimer) - console.log(TAG, 'syncMembersToDevice 全部同步完成') resolve() return } - const member = members[index] - console.log(TAG, `下发第 ${index + 1}/${members.length} 个成员:`, member.name) resetTimer() - this._activeProtocol.dataSyncUserInfo( { - userID: mainUser.id, - userName: member.name, - // 主用户 memberID 为空,子用户用自己的 id + userID: mainUser.id, userName: member.name, memberID: member.isSelf ? '' : member.id, - age: member.age, - gender: member.gender, - height: member.height, - isAthleteMode: 0, - deviceHeaderIndex: index, - currentWeight: '', - targetWeight: '', - idealWeight: '', - recentData: [], - }, - (res: number) => { - console.log(TAG, `第 ${index + 1} 个成员同步回调:`, res) - if (res === 0) { - index++ - } - // 成功进下一个,失败重试当前(index 不变) - syncNext() + age: member.age, gender: member.gender, height: member.height, + isAthleteMode: 0, deviceHeaderIndex: index, + currentWeight: '', targetWeight: '', idealWeight: '', recentData: [], }, + (res: number) => { if (res === 0) index++; syncNext() }, ) } - syncNext() }) }) } } -/** 全局单例,整个小程序共享同一个蓝牙服务实例 */ export const lefuService = new LeFuService() diff --git a/miniprogram/pages/connectedDevice/connectedDevice.ts b/miniprogram/pages/connectedDevice/connectedDevice.ts index cc273b2..6f056f5 100644 --- a/miniprogram/pages/connectedDevice/connectedDevice.ts +++ b/miniprogram/pages/connectedDevice/connectedDevice.ts @@ -29,6 +29,8 @@ Page({ onHide() { console.log(TAG, 'onHide, 停止扫描') + _rawDevices = [] + this.setData({ status: 'idle', deviceList: [] }) lefuService.stopScan() }, diff --git a/miniprogram/pages/connectedWifi/connectedWifi.ts b/miniprogram/pages/connectedWifi/connectedWifi.ts index 2b20495..90c1732 100644 --- a/miniprogram/pages/connectedWifi/connectedWifi.ts +++ b/miniprogram/pages/connectedWifi/connectedWifi.ts @@ -1,75 +1,29 @@ import { lefuService } from '../../lefu/index' import type { LeFuWifiItem, WifiVersion } from '../../lefu/index' -/** WiFi 展示项 */ interface WifiItem { ssid: string - /** 是否已通过本页配网成功 */ connected: boolean } -/** 当前已连接设备(顶部卡片) */ -interface CurrentDevice { - id: string - name: string -} - -/** 密码态选中的 WiFi */ -interface SelectedWifi { - ssid: string -} - -/** 页面状态 */ type WifiStatus = 'idle' | 'searching' | 'list' | 'empty' | 'password' | 'configuring' +type BleStatus = 'connected' | 'failed' | 'connecting' Page({ - /** 配网协议版本,两种都支持,默认 domain2(有鉴权) */ _wifiVersion: 'domain2' as WifiVersion, data: { - /** - * 页面状态 - * - idle: 未搜索 - * - searching: 正在从设备获取 WiFi 列表 - * - list: 列表已就绪 - * - empty: 设备未扫描到任何 WiFi - * - password: 选中某项,正在输入密码 - * - configuring: 正在将 WiFi 写入设备 - */ status: 'idle' as WifiStatus, - - /** 顶部固定卡片 */ - currentDevice: { - id: '', - name: '智能体重秤', - } as CurrentDevice, - - /** 蓝牙连接状态常量(从插件获取,供 wxml 做条件判断) */ - BLUE_STATE: {} as Record, - - /** 当前蓝牙连接状态(实时更新) */ - connectState: '', - - /** 顶部卡片蓝牙状态:connected / failed / connecting */ - bleStatus: 'connected' as 'connected' | 'failed' | 'connecting', - - /** WiFi 列表 */ + deviceName: '智能体重秤', + bleStatus: 'connected' as BleStatus, wifiList: [] as WifiItem[], - - /** 是否已有任一 WiFi 配网成功 */ hasConnected: false, - - /** 当前密码态选中的 WiFi */ - selectedWifi: { ssid: '' } as SelectedWifi, - - /** 密码输入框值 */ + selectedSsid: '', selectWifiPWD: '', - - /** 密码框明文/密文切换:true 为密文(默认) */ type: true, }, - _toBleStatus(state: string): 'connected' | 'failed' | 'connecting' { + _toBleStatus(state: string): BleStatus { const bs = lefuService.BLUE_STATE if (state === bs.CONNECTSUCCESS || state === bs.WIFISUCCESS) return 'connected' if (state === bs.CONNECTFAILED) return 'failed' @@ -77,9 +31,13 @@ Page({ }, onLoad() { + // 尽早注册 deviceInfo 回调,防止 onShow 前已触发而错过 + lefuService.onDeviceInfo((info) => { + this.setData({ deviceName: info.modelNumber }) + }) this.setData({ bleStatus: this._toBleStatus(lefuService.connectState), - currentDevice: { id: '', name: lefuService.deviceInfo?.modelNumber ?? '智能体重秤' }, + deviceName: lefuService.deviceInfo?.modelNumber ?? '智能体重秤', }) this.onStartSearch() }, @@ -87,14 +45,10 @@ Page({ onShow() { lefuService.onConnectState((state) => { const bs = lefuService.BLUE_STATE - // 只处理明确的连接/断开状态,忽略蓝牙初始化过程中的中间状态 if (state === bs.CONNECTSUCCESS || state === bs.WIFISUCCESS || state === bs.CONNECTFAILED) { this.setData({ bleStatus: this._toBleStatus(state) }) } }) - lefuService.onDeviceInfo((info) => { - this.setData({ currentDevice: { id: '', name: info.modelNumber } }) - }) }, onUnload() { @@ -104,11 +58,9 @@ Page({ } }, - /** 从设备获取 WiFi 列表 */ onStartSearch() { this.setData({ status: 'searching', wifiList: [] }) wx.showLoading({ title: '正在获取 WiFi 列表...', mask: true }) - lefuService.getWifiList() .then((items: LeFuWifiItem[]) => { wx.hideLoading() @@ -116,11 +68,10 @@ Page({ this.setData({ status: 'empty' }) return } - const list: WifiItem[] = items.map(item => ({ - ssid: item.ssid, - connected: false, - })) - this.setData({ status: 'list', wifiList: list }) + this.setData({ + status: 'list', + wifiList: items.map(item => ({ ssid: item.ssid, connected: false })), + }) }) .catch(() => { wx.hideLoading() @@ -128,64 +79,42 @@ Page({ }) }, - /** 空态刷新 */ onRefresh() { this.onStartSearch() }, - /** 点击 WiFi 项 → 进密码态 */ onTapWifi(e: WechatMiniprogram.TouchEvent) { const ssid = e.currentTarget.dataset.ssid as string const target = this.data.wifiList.find(item => item.ssid === ssid) if (!target || target.connected) return - - this.setData({ - status: 'password', - selectedWifi: { ssid }, - selectWifiPWD: '', - type: true, - }) + this.setData({ status: 'password', selectedSsid: ssid, selectWifiPWD: '', type: true }) }, - /** 密码输入 */ passwordInput(e: WechatMiniprogram.Input) { this.setData({ selectWifiPWD: e.detail.value }) }, - /** 明文/密文切换 */ inputTypeChange() { this.setData({ type: !this.data.type }) }, - /** 密码态「取消」→ 回列表 */ onCancelPwd() { - this.setData({ - status: 'list', - selectedWifi: { ssid: '' }, - selectWifiPWD: '', - }) + this.setData({ status: 'list', selectedSsid: '', selectWifiPWD: '' }) }, - /** 密码态「连接」→ 将 WiFi 写入设备 */ onConfirmPwd() { - const { selectedWifi, selectWifiPWD } = this.data - if (!selectedWifi.ssid) return - + const { selectedSsid, selectWifiPWD } = this.data + if (!selectedSsid) return this.setData({ status: 'configuring' }) wx.showLoading({ title: '正在配网...', mask: true }) - - lefuService.configWifi(selectedWifi.ssid, selectWifiPWD, this._wifiVersion) + lefuService.configWifi(selectedSsid, selectWifiPWD, this._wifiVersion) .then(() => { wx.hideLoading() - const next = this.data.wifiList.map(item => ({ - ...item, - connected: item.ssid === selectedWifi.ssid, - })) this.setData({ status: 'list', - wifiList: next, + wifiList: this.data.wifiList.map(item => ({ ...item, connected: item.ssid === selectedSsid })), hasConnected: true, - selectedWifi: { ssid: '' }, + selectedSsid: '', selectWifiPWD: '', }) }) @@ -196,7 +125,6 @@ Page({ }) }, - /** 底部「确认」:已有 WiFi 配网成功才可点击 */ onConfirm() { if (!this.data.hasConnected) return wx.navigateTo({ url: '/pages/supplementPersonal/supplementPersonal' }) diff --git a/miniprogram/pages/connectedWifi/connectedWifi.wxml b/miniprogram/pages/connectedWifi/connectedWifi.wxml index d901ab7..b6abd97 100644 --- a/miniprogram/pages/connectedWifi/connectedWifi.wxml +++ b/miniprogram/pages/connectedWifi/connectedWifi.wxml @@ -7,7 +7,7 @@ - {{selectedWifi.ssid}} + {{selectedSsid}} 密码 @@ -46,7 +46,7 @@ - {{currentDevice.name}} + {{deviceName}} diff --git a/project.config.json b/project.config.json index 66ce98a..37e394e 100644 --- a/project.config.json +++ b/project.config.json @@ -1,51 +1,51 @@ { - "description": "项目配置文件", - "miniprogramRoot": "miniprogram/", - "compileType": "miniprogram", - "setting": { - "useCompilerPlugins": [ - "typescript", - "less" - ], - "babelSetting": { - "ignore": [], - "disablePlugins": [], - "outputPath": "" + "description": "项目配置文件", + "miniprogramRoot": "miniprogram/", + "compileType": "miniprogram", + "setting": { + "useCompilerPlugins": [ + "typescript", + "less" + ], + "babelSetting": { + "ignore": [], + "disablePlugins": [], + "outputPath": "" + }, + "coverView": false, + "postcss": false, + "minified": false, + "enhance": true, + "showShadowRootInWxmlPanel": false, + "packNpmRelationList": [], + "ignoreUploadUnusedFiles": true, + "compileHotReLoad": false, + "skylineRenderEnable": true, + "es6": true, + "compileWorklet": false, + "uglifyFileName": false, + "uploadWithSourceMap": true, + "packNpmManually": false, + "minifyWXSS": true, + "minifyWXML": true, + "localPlugins": false, + "condition": false, + "swc": false, + "disableSWC": true, + "disableUseStrict": false }, - "coverView": false, - "postcss": false, - "minified": false, - "enhance": false, - "showShadowRootInWxmlPanel": false, - "packNpmRelationList": [], - "ignoreUploadUnusedFiles": true, - "compileHotReLoad": false, - "skylineRenderEnable": true, - "es6": false, - "compileWorklet": false, - "uglifyFileName": false, - "uploadWithSourceMap": true, - "packNpmManually": false, - "minifyWXSS": true, - "minifyWXML": true, - "localPlugins": false, - "condition": false, - "swc": false, - "disableSWC": true, - "disableUseStrict": false - }, - "simulatorType": "wechat", - "simulatorPluginLibVersion": {}, - "condition": {}, - "srcMiniprogramRoot": "miniprogram/", - "editorSetting": { - "tabIndent": "insertSpaces", - "tabSize": 4 - }, - "libVersion": "2.32.3", - "packOptions": { - "ignore": [], - "include": [] - }, - "appid": "wx6c71f3ebcdcddffd" + "simulatorType": "wechat", + "simulatorPluginLibVersion": {}, + "condition": {}, + "srcMiniprogramRoot": "miniprogram/", + "editorSetting": { + "tabIndent": "insertSpaces", + "tabSize": 4 + }, + "libVersion": "2.32.3", + "packOptions": { + "ignore": [], + "include": [] + }, + "appid": "wx6c71f3ebcdcddffd" } \ No newline at end of file diff --git a/project.private.config.json b/project.private.config.json index 7c2ff81..357d19c 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -2,7 +2,7 @@ "libVersion": "2.32.3", "projectname": "bodyWeight", "setting": { - "urlCheck": true, + "urlCheck": false, "coverView": false, "lazyloadPlaceholderEnable": false, "skylineRenderEnable": true,