From 2595080d9a3b6dbd55c44eeec653b3cc94654376 Mon Sep 17 00:00:00 2001 From: 17792275749 <812100002@qq.com> Date: Tue, 25 Aug 2026 16:11:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(userManagement):=20=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E5=89=8D=E8=AF=BB=E8=AE=BE=E5=A4=87=E4=B8=BB=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=B9=B6=E6=94=AF=E6=8C=81=E9=95=BF=E6=8C=89=E6=B8=85=E7=A9=BA?= =?UTF-8?q?=E9=87=8D=E6=96=B0=E4=B8=8B=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- miniprogram/lefu/service.ts | 14 ++ .../pages/userManagement/userManagement.ts | 163 +++++++++++++----- .../pages/userManagement/userManagement.wxml | 2 +- 3 files changed, 134 insertions(+), 45 deletions(-) diff --git a/miniprogram/lefu/service.ts b/miniprogram/lefu/service.ts index 1d350c6..e4c669a 100644 --- a/miniprogram/lefu/service.ts +++ b/miniprogram/lefu/service.ts @@ -443,6 +443,20 @@ class LeFuService { }) } + /** + * 获取设备端主用户的 userId 列表 + * 未连接 reject;成功返回主用户 userId 数组,无主用户返回 null + */ + fetchDeviceUserIds(): Promise { + return new Promise((resolve, reject) => { + if (!this._activeProtocol) { reject(new Error('设备未连接')); return } + this._activeProtocol.dataFetchUserID((res: any) => { + console.log(TAG, 'dataFetchUserID:', res) + resolve(res ?? null) + }) + }) + } + // ─── 私有:保活与重连 ─────────────────────── /** 启动保活心跳:文档建议每 10s 发送一次 keepAlive,防止设备主动断开 */ private _startKeepAlive(): void { diff --git a/miniprogram/pages/userManagement/userManagement.ts b/miniprogram/pages/userManagement/userManagement.ts index 9f6a1a9..0eb2124 100644 --- a/miniprogram/pages/userManagement/userManagement.ts +++ b/miniprogram/pages/userManagement/userManagement.ts @@ -21,6 +21,17 @@ interface SysUserDevice { syncStatus?: number } +/** 同步用的用户项 */ +interface SyncUser { + id: string + userId: string + name: string + gender: number + age: number + height: number + sync: string +} + /** 展示用成员项 */ interface MemberItem { id: string @@ -204,13 +215,10 @@ Page({ }) }, - /** 同步用户至设备:只下发「待同步」的用户 */ - onTapSync() { - if (!this._ensureConnected()) return - - // 组装所有用户(本人第一个,作为主用户),性别:男=1 女=0 + /** 组装所有用户(本人第一个,作为主用户),性别:男=1 女=0 */ + _buildAllUsers(): SyncUser[] { const self = this.data.self - const allUsers = [ + return [ ...(self ? [{ id: self.id, userId: self.userId, name: self.name, gender: self.gender === '男' ? 1 : 0, @@ -221,19 +229,112 @@ Page({ gender: m.gender === '男' ? 1 : 0, age: m.age, height: m.height, sync: m.sync, }))), ] + }, + + /** 同步完成后的统一处理:标记同步 + 更新列表状态 + 关闭弹框 */ + _handleSyncSuccess(users: SyncUser[], successText: string) { + this.setData({ syncPercent: 100, syncStatus: '同步完成' }) + wx.showToast({ title: successText, icon: 'success' }) + const syncedIds = users.map(u => u.userId).filter(Boolean) + if (targetDevice?.sn && syncedIds.length) { + markSynced({ sn: targetDevice.sn, list: syncedIds }) + .then(() => { + const syncedSet = new Set(syncedIds) + this.setData({ + self: this.data.self && syncedSet.has(this.data.self.userId) + ? { ...this.data.self, sync: '已同步', syncClass: 'done' } + : this.data.self, + groups: this.data.groups.map(g => ({ + ...g, + members: g.members.map(m => syncedSet.has(m.userId) ? { ...m, sync: '已同步', syncClass: 'done' } : m), + })), + }) + }) + .catch(() => {}) + } + if (syncCloseTimer !== null) { clearTimeout(syncCloseTimer); syncCloseTimer = null } + syncCloseTimer = setTimeout(() => { + syncCloseTimer = null + this.setData({ syncShow: false }) + }, 1000) + }, + + /** 同步用户至设备:只下发「待同步」的用户 */ + onTapSync() { + if (!this._ensureConnected()) return + + const allUsers = this._buildAllUsers() if (!allUsers.length) { wx.showToast({ title: '暂无用户可同步', icon: 'none' }) return } - const mainUser = allUsers[0] // 只下发「待同步」的用户 const pendingUsers = allUsers.filter(u => u.sync !== '已同步') if (!pendingUsers.length) { wx.showToast({ title: '没有需要同步的用户', icon: 'none' }) return } - // 组装下发参数(SyncUserData),主用户 memberID 为空 + + // 先读设备端主用户列表,判断设备是否已有主用户 + leFuService.fetchDeviceUserIds() + .then((deviceUserIds) => this._syncUsers(pendingUsers, deviceUserIds)) + .catch(() => { + wx.showToast({ title: '读取设备用户失败', icon: 'none' }) + }) + }, + + /** 根据设备端主用户情况组装并下发(一主九子,子用户挂在主用户下) */ + _syncUsers(pendingUsers: SyncUser[], deviceUserIds: any) { + // dataFetchUserID 只返回主用户,非空表示设备已有主用户 + const userIds = Array.isArray(deviceUserIds) ? deviceUserIds : [deviceUserIds].filter(Boolean) + const hasMainUser = userIds.length > 0 + // 主用户 ID:已有主用户用设备端的,否则用第一个用户作为主用户 + const mainUserId = hasMainUser ? String(userIds[0]) : pendingUsers[0].id + const syncDataList: SyncUserData[] = pendingUsers.map((user, index) => ({ + userID: mainUserId, + userName: user.name, + memberID: hasMainUser ? user.id : (user.id === pendingUsers[0].id ? '' : user.id), + age: user.age, + gender: user.gender, + height: user.height, + isAthleteMode: 0, + deviceHeaderIndex: index, + currentWeight: '', + targetWeight: '', + idealWeight: '', + recentData: [], + })) + + this.setData({ syncShow: true, syncPercent: 0, syncStatus: '正在同步信息,请勿离开...' }) + leFuService.syncMembersToDevice(syncDataList, (current, total) => { + this.setData({ + syncPercent: Math.round((current / total) * 100), + syncStatus: `正在同步 ${current}/${total}...`, + }) + }) + .then(() => this._handleSyncSuccess(pendingUsers, '用户同步成功')) + .catch((err: Error) => { + this.setData({ syncShow: false }) + wx.showToast({ title: err.message || '同步失败,请重试', icon: 'none' }) + }) + }, + + /** 长按标题:清除设备用户信息并全部重新下发 */ + onLongPressSectionTitle() { + if (!this._ensureConnected()) return + const allUsers = this._buildAllUsers() + if (!allUsers.length) { + wx.showToast({ title: '暂无用户可下发', icon: 'none' }) + return + } + this._resendAllUsers(allUsers) + }, + + /** 清除设备用户后全部重新下发 */ + _resendAllUsers(allUsers: SyncUser[]) { + const mainUser = allUsers[0] + const syncDataList: SyncUserData[] = allUsers.map((user, index) => ({ userID: mainUser.id, userName: user.name, memberID: user.id === mainUser.id ? '' : user.id, @@ -248,44 +349,18 @@ Page({ recentData: [], })) - // 直接下发待同步用户(不清空) - this.setData({ syncShow: true, syncPercent: 0, syncStatus: '正在同步信息,请勿离开...' }) - leFuService.syncMembersToDevice(syncDataList, (current, total) => { - this.setData({ - syncPercent: Math.round((current / total) * 100), - syncStatus: `正在同步 ${current}/${total}...`, - }) - }) - .then(() => { - this.setData({ syncPercent: 100, syncStatus: '同步完成' }) - wx.showToast({ title: '用户同步成功', icon: 'success' }) - const syncedIds = pendingUsers.map(u => u.userId).filter(Boolean) - if (targetDevice?.sn && syncedIds.length) { - markSynced({ sn: targetDevice.sn, list: syncedIds }) - .then(() => { - // 标记成功后,把对应成员更新为「已同步」 - const syncedSet = new Set(syncedIds) - this.setData({ - self: this.data.self && syncedSet.has(this.data.self.userId) - ? { ...this.data.self, sync: '已同步', syncClass: 'done' } - : this.data.self, - groups: this.data.groups.map(g => ({ - ...g, - members: g.members.map(m => syncedSet.has(m.userId) ? { ...m, sync: '已同步', syncClass: 'done' } : m), - })), - }) - }) - .catch(() => {}) - } - if (syncCloseTimer !== null) { clearTimeout(syncCloseTimer); syncCloseTimer = null } - syncCloseTimer = setTimeout(() => { - syncCloseTimer = null - this.setData({ syncShow: false }) - }, 1000) - }) + this.setData({ syncShow: true, syncPercent: 0, syncStatus: '正在清空并重新下发...' }) + leFuService.clearDeviceMembers() + .then(() => leFuService.syncMembersToDevice(syncDataList, (current, total) => { + this.setData({ + syncPercent: Math.round((current / total) * 100), + syncStatus: `正在同步 ${current}/${total}...`, + }) + })) + .then(() => this._handleSyncSuccess(allUsers, '重新下发成功')) .catch((err: Error) => { this.setData({ syncShow: false }) - wx.showToast({ title: err.message || '同步失败,请重试', icon: 'none' }) + wx.showToast({ title: err.message || '重新下发失败', icon: 'none' }) }) }, diff --git a/miniprogram/pages/userManagement/userManagement.wxml b/miniprogram/pages/userManagement/userManagement.wxml index e86d72c..cfec3c4 100644 --- a/miniprogram/pages/userManagement/userManagement.wxml +++ b/miniprogram/pages/userManagement/userManagement.wxml @@ -23,7 +23,7 @@ - 已录入用户({{ memberCount }}/10) + 已录入用户({{ memberCount }}/10) 同步用户至设备