feat(userManagement): 接入用户同步到设备,恢复清空设备用户能力
- service 恢复 clearDeviceMembers/syncMembersToDevice,操作中断开立即失败 - syncMembersToDevice 只负责逐个下发,参数由业务层组装 - _doReconnect 增加蓝牙不可用判断 - userManagement 接入真实同步(连接状态实时同步 + 进度弹框) - equipment 页增加用户管理入口 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
db865748f2
commit
9a81092c99
@@ -7,4 +7,5 @@ export type {
|
||||
LeFuConfig,
|
||||
DeviceSetting,
|
||||
DeviceInfo,
|
||||
SyncUserData,
|
||||
} from './types'
|
||||
|
||||
@@ -9,6 +9,7 @@ import type {
|
||||
LockData,
|
||||
LeFuConfig,
|
||||
DeviceInfo,
|
||||
SyncUserData,
|
||||
} from './types'
|
||||
|
||||
/** 顶层加载插件(对齐 demo,requirePlugin 必须在文件顶层调用) */
|
||||
@@ -358,6 +359,84 @@ class LeFuService {
|
||||
})
|
||||
}
|
||||
|
||||
// ─── 用户同步 ─────────────────────────────
|
||||
/**
|
||||
* 清空设备内的用户数据
|
||||
* 下发清空指令,让设备清除已录入的所有成员。
|
||||
*/
|
||||
clearDeviceMembers(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._activeProtocol) { reject(new Error('设备未连接')); return }
|
||||
|
||||
let settled = false
|
||||
const settle = (err: Error | null) => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
clearTimeout(timer)
|
||||
this._onDisconnectedCbs.delete(onDisconnect)
|
||||
err ? reject(err) : resolve()
|
||||
}
|
||||
// 操作中设备断开:立即失败,不等超时
|
||||
const onDisconnect = () => settle(new Error('设备已断开'))
|
||||
this._onDisconnectedCbs.add(onDisconnect)
|
||||
const timer = setTimeout(() => settle(new Error('请求超时')), 15000)
|
||||
|
||||
this._activeProtocol.codeClearDeviceData('01', (res: number) => {
|
||||
settle(res === 0 ? null : new Error('请求失败'))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步成员到设备(只负责逐个下发)
|
||||
* 参数列表由调用方组装好,本方法不做字段转换,onProgress 回调已完成的用户数。
|
||||
*/
|
||||
syncMembersToDevice(list: SyncUserData[], onProgress?: (current: number, total: number) => void): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._activeProtocol) { reject(new Error('设备未连接')); return }
|
||||
if (!list.length) { reject(new Error('无用户可同步')); return }
|
||||
|
||||
let settled = false
|
||||
let index = 0
|
||||
let syncTimer: number | null = null
|
||||
|
||||
const settle = (err: Error | null) => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
if (syncTimer !== null) clearTimeout(syncTimer)
|
||||
this._onDisconnectedCbs.delete(onDisconnect)
|
||||
err ? reject(err) : resolve()
|
||||
}
|
||||
// 操作中设备断开:立即失败,不等超时
|
||||
const onDisconnect = () => settle(new Error('设备已断开'))
|
||||
this._onDisconnectedCbs.add(onDisconnect)
|
||||
|
||||
const resetTimer = () => {
|
||||
if (syncTimer !== null) clearTimeout(syncTimer)
|
||||
syncTimer = setTimeout(() => settle(new Error('请求超时')), 15000)
|
||||
}
|
||||
const syncNext = () => {
|
||||
if (settled) return
|
||||
if (index >= list.length) {
|
||||
settle(null)
|
||||
return
|
||||
}
|
||||
resetTimer()
|
||||
this._activeProtocol.dataSyncUserInfo(list[index], (res: number) => {
|
||||
if (settled) return
|
||||
if (res !== 0) {
|
||||
settle(new Error('请求失败'))
|
||||
return
|
||||
}
|
||||
index++
|
||||
onProgress?.(index, list.length)
|
||||
syncNext()
|
||||
})
|
||||
}
|
||||
syncNext()
|
||||
})
|
||||
}
|
||||
|
||||
// ─── 私有:保活与重连 ───────────────────────
|
||||
/** 启动保活心跳:文档建议每 10s 发送一次 keepAlive,防止设备主动断开 */
|
||||
private _startKeepAlive(): void {
|
||||
@@ -400,6 +479,12 @@ class LeFuService {
|
||||
console.log(TAG, `_doReconnect 第 ${this._reconnectCount} 次`)
|
||||
this._stopReconnectTimer()
|
||||
this._reconnectTimer = setTimeout(() => {
|
||||
// 延时期间蓝牙可能已不可用,重连前再判断一次
|
||||
if (this._connectState === plugin.BLUE_STATE.UNAVAILABLE) {
|
||||
console.warn(TAG, '蓝牙不可用,放弃重连')
|
||||
this._onDisconnectedCbs.forEach(cb => cb())
|
||||
return
|
||||
}
|
||||
plugin.Blue.clearProtocol()
|
||||
plugin.Blue.createBLEConnection(this._lastRawDevice!)
|
||||
}, 2000)
|
||||
|
||||
@@ -88,3 +88,27 @@ export interface DeviceInfo {
|
||||
serialNumber: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
/** 下发到设备的单个用户数据(dataSyncUserInfo 参数,业务层组装后传入) */
|
||||
export interface SyncUserData {
|
||||
/** 主用户 ID */
|
||||
userID: string
|
||||
/** 用户名 */
|
||||
userName: string
|
||||
/** 成员 ID,主用户为空 */
|
||||
memberID: string
|
||||
/** 年龄 */
|
||||
age: number
|
||||
/** 性别:1=男,0=女 */
|
||||
gender: number
|
||||
/** 身高(cm) */
|
||||
height: number
|
||||
/** 是否运动员模式 */
|
||||
isAthleteMode: number
|
||||
/** 设备内索引 */
|
||||
deviceHeaderIndex: number
|
||||
currentWeight: string
|
||||
targetWeight: string
|
||||
idealWeight: string
|
||||
recentData: any[]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user