feat(userManagement): 同步前读设备主用户并支持长按清空重新下发
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
f6d6591c69
commit
2595080d9a
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user