feat(userManagement): 接入用户同步到设备,恢复清空设备用户能力

- service 恢复 clearDeviceMembers/syncMembersToDevice,操作中断开立即失败
- syncMembersToDevice 只负责逐个下发,参数由业务层组装
- _doReconnect 增加蓝牙不可用判断
- userManagement 接入真实同步(连接状态实时同步 + 进度弹框)
- equipment 页增加用户管理入口

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
17792275749
2026-08-21 11:08:04 +08:00
co-authored by Claude Opus 4.7
parent db865748f2
commit 9a81092c99
6 changed files with 233 additions and 10 deletions
@@ -1,11 +1,19 @@
// pages/userManagement/userManagement.ts
import { leFuService } from '../../lefu/index'
import type { SyncUserData } from '../../lefu/index'
/** 连接状态订阅句柄 */
let unsubDeviceConnect: (() => void) | null = null
let unsubDisconnected: (() => void) | null = null
/** 同步完成关闭弹框定时器 */
let syncCloseTimer: number | null = null
Page({
data: {
device: {
name: '家庭蓝牙体脂秤 S1',
connected: true,
model: 'BS-A100',
serial: 'BL2024B00321'
name: '智能体重秤',
connected: false,
model: '',
serial: ''
},
memberCount: 5,
hasData: true,
@@ -38,12 +46,110 @@ Page({
syncStatus: ''
},
onLoad() {
this._updateDeviceInfo()
this._subscribeDeviceState()
},
onUnload() {
unsubDeviceConnect?.()
unsubDisconnected?.()
unsubDeviceConnect = null
unsubDisconnected = null
if (syncCloseTimer !== null) { clearTimeout(syncCloseTimer); syncCloseTimer = null }
},
/** 从 service 读取设备信息 + 连接状态 */
_updateDeviceInfo() {
const info = leFuService.deviceInfo
this.setData({
'device.name': info?.modelNumber || '智能体重秤',
'device.model': info?.modelNumber || '',
'device.serial': info?.serialNumber || '',
'device.connected': leFuService.isConnected,
})
},
/** 订阅连接状态,实时同步设备卡 */
_subscribeDeviceState() {
unsubDeviceConnect?.()
unsubDisconnected?.()
unsubDeviceConnect = leFuService.onDeviceConnect(() => {
this._updateDeviceInfo()
})
unsubDisconnected = leFuService.onDisconnected(() => {
this.setData({ 'device.connected': false })
})
},
/** 校验设备连接状态:未连接则同步状态 + 提示 */
_ensureConnected(): boolean {
if (leFuService.isConnected) return true
this.setData({ 'device.connected': false })
wx.showToast({ title: '请先连接设备', icon: 'none' })
return false
},
/** 同步用户至设备 */
onTapSync() {
this.setData({ syncShow: true, syncPercent: 32, syncStatus: '正在同步信息,请勿离开...' })
setTimeout(() => {
this.setData({ syncPercent: 100, syncStatus: '同步完成' })
}, 2000)
if (!this._ensureConnected()) return
// 组装所有用户(self 第一个,作为主用户),性别:男=1 女=0
const allUsers = [
{
id: 'self', name: this.data.self.name,
gender: this.data.self.gender === '男' ? 1 : 0,
age: this.data.self.age, height: this.data.self.height,
},
...this.data.groups.flatMap(g => g.members.map(m => ({
id: String(m.id), name: m.name,
gender: m.gender === '男' ? 1 : 0, age: m.age, height: m.height,
}))),
]
const mainUser = allUsers[0]
// 组装下发参数(SyncUserData),第一个为主用户(memberID 为空)
const syncDataList: SyncUserData[] = allUsers.map((user, index) => ({
userID: mainUser.id,
userName: user.name,
memberID: index === 0 ? '' : user.id,
age: user.age,
gender: user.gender,
height: user.height,
isAthleteMode: 0,
deviceHeaderIndex: index,
currentWeight: '',
targetWeight: '',
idealWeight: '',
recentData: [],
}))
// 阶段1:清空设备用户,进度 0% → 100%
this.setData({ syncShow: true, syncPercent: 0, syncStatus: '正在清空设备用户...' })
leFuService.clearDeviceMembers()
.then(() => {
this.setData({ syncPercent: 100, syncStatus: '清空完成' })
// 阶段2:下发用户,进度从 0% 重新开始
this.setData({ syncPercent: 0, syncStatus: '正在同步信息,请勿离开...' })
return 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' })
if (syncCloseTimer !== null) { clearTimeout(syncCloseTimer); syncCloseTimer = null }
syncCloseTimer = setTimeout(() => {
syncCloseTimer = null
this.setData({ syncShow: false })
}, 1000)
})
.catch((err: Error) => {
this.setData({ syncShow: false })
wx.showToast({ title: err.message || '同步失败,请重试', icon: 'none' })
})
},
/** 添加用户 */