feat(userManagement): 同步前读设备主用户并支持长按清空重新下发

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
17792275749
2026-08-25 16:11:55 +08:00
co-authored by Claude Opus 4.7
parent f6d6591c69
commit 2595080d9a
3 changed files with 134 additions and 45 deletions
+14
View File
@@ -443,6 +443,20 @@ class LeFuService {
})
}
/**
* 获取设备端主用户的 userId 列表
* 未连接 reject;成功返回主用户 userId 数组,无主用户返回 null
*/
fetchDeviceUserIds(): Promise<string[] | null> {
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 {
@@ -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,49 +229,16 @@ Page({
gender: m.gender === '男' ? 1 : 0, age: m.age, height: m.height, sync: m.sync,
}))),
]
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 为空
const syncDataList: SyncUserData[] = pendingUsers.map((user, index) => ({
userID: mainUser.id,
userName: user.name,
memberID: user.id === mainUser.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(() => {
/** 同步完成后的统一处理:标记同步 + 更新列表状态 + 关闭弹框 */
_handleSyncSuccess(users: SyncUser[], successText: string) {
this.setData({ syncPercent: 100, syncStatus: '同步完成' })
wx.showToast({ title: '用户同步成功', icon: 'success' })
const syncedIds = pendingUsers.map(u => u.userId).filter(Boolean)
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)
@@ -282,13 +257,113 @@ Page({
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 pendingUsers = allUsers.filter(u => u.sync !== '已同步')
if (!pendingUsers.length) {
wx.showToast({ title: '没有需要同步的用户', icon: 'none' })
return
}
// 先读设备端主用户列表,判断设备是否已有主用户
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,
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.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' })
})
},
/** 添加用户 */
onTapAddUser() {
const sn = targetDevice?.sn || ''
@@ -23,7 +23,7 @@
<!-- 已录入用户 + 同步按钮 -->
<view class="section-header">
<view class="section-title">已录入用户({{ memberCount }}/10</view>
<view class="section-title" bind:longpress="onLongPressSectionTitle">已录入用户({{ memberCount }}/10</view>
<view class="sync-btn" bind:tap="onTapSync">同步用户至设备</view>
</view>