feat(userManagement): 设备成员管理接入成员列表接口与同步标记
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
f750d15150
commit
a80a5cd939
@@ -226,6 +226,9 @@
|
|||||||
height: 26rpx;
|
height: 26rpx;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
line-height: 26rpx;
|
line-height: 26rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ interface DeviceItem {
|
|||||||
|
|
||||||
let unsubDevicesList: (() => void) | null = null
|
let unsubDevicesList: (() => void) | null = null
|
||||||
let unsubConnect: (() => void) | null = null
|
let unsubConnect: (() => void) | null = null
|
||||||
|
let unsubDisconnected: (() => void) | null = null
|
||||||
let scanTimer: number | null = null
|
let scanTimer: number | null = null
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
@@ -45,6 +46,34 @@ Page({
|
|||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
this.loadDevices()
|
this.loadDevices()
|
||||||
|
this._subscribeDisconnected()
|
||||||
|
},
|
||||||
|
|
||||||
|
onHide() {
|
||||||
|
leFuService.stopScan()
|
||||||
|
unsubDisconnected?.()
|
||||||
|
unsubDisconnected = null
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnload() {
|
||||||
|
leFuService.stopScan()
|
||||||
|
unsubDisconnected?.()
|
||||||
|
unsubDisconnected = null
|
||||||
|
unsubDevicesList?.()
|
||||||
|
unsubDevicesList = null
|
||||||
|
unsubConnect?.()
|
||||||
|
unsubConnect = null
|
||||||
|
if (scanTimer !== null) { clearTimeout(scanTimer); scanTimer = null }
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 订阅断开事件:设备长时间未操作或意外断开时,同步页面状态为未连接 */
|
||||||
|
_subscribeDisconnected() {
|
||||||
|
unsubDisconnected?.()
|
||||||
|
unsubDisconnected = leFuService.onDisconnected(() => {
|
||||||
|
this.setData({
|
||||||
|
devices: this.data.devices.map(d => ({ ...d, status: false })),
|
||||||
|
})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 拉取体重设备列表 */
|
/** 拉取体重设备列表 */
|
||||||
@@ -182,8 +211,11 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
/** 用户管理 */
|
/** 用户管理 */
|
||||||
onTapUser() {
|
onTapUser(e: WechatMiniprogram.TouchEvent) {
|
||||||
wx.navigateTo({ url: '/pages/userManagement/userManagement' })
|
const item = e.currentTarget.dataset.item as DeviceItem
|
||||||
|
wx.navigateTo({
|
||||||
|
url: `/pages/userManagement/userManagement?sn=${encodeURIComponent(item.sn)}&deviceId=${encodeURIComponent(item.deviceId)}&name=${encodeURIComponent(item.name)}&status=${item.status}&connectDeviceInfo=${encodeURIComponent(item.connectDeviceInfo)}`,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onTapAdd() {
|
onTapAdd() {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
<view>设备连接</view>
|
<view>设备连接</view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
<view class="device-action-btn" bind:tap="onTapUser">
|
<view class="device-action-btn" bind:tap="onTapUser" data-item="{{ item }}">
|
||||||
<view>
|
<view>
|
||||||
<image src="/images/equipment/users.png"/>
|
<image src="/images/equipment/users.png"/>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
.device-card {
|
.device-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 30rpx;
|
padding: 30rpx 24rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
background-color: #FFFFFF;
|
background-color: #FFFFFF;
|
||||||
@@ -24,9 +24,8 @@
|
|||||||
width: 88rpx;
|
width: 88rpx;
|
||||||
height: 88rpx;
|
height: 88rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-right: 24rpx;
|
margin-right: 20rpx;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
background-color: #1385FA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.device-info {
|
.device-info {
|
||||||
@@ -49,35 +48,57 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.device-status {
|
.device-status {
|
||||||
height: 40rpx;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0 16rpx;
|
flex-wrap: nowrap;
|
||||||
border-radius: 20rpx;
|
|
||||||
align-items: center;
|
|
||||||
background-color: #EAFAF6;
|
|
||||||
|
|
||||||
.status-dot {
|
.device-status_ {
|
||||||
width: 12rpx;
|
height: 40rpx;
|
||||||
height: 12rpx;
|
padding: 0 16rpx;
|
||||||
border-radius: 50%;
|
display: flex;
|
||||||
background-color: #2AC79F;
|
flex-wrap: nowrap;
|
||||||
margin-right: 8rpx;
|
align-items: center;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #F2F3F6;
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 12rpx;
|
||||||
|
height: 12rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #77849E;
|
||||||
|
margin-right: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
color: #77849E;
|
||||||
|
height: 22rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
line-height: 22rpx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-text {
|
.connected {
|
||||||
color: #2AC79F;
|
background-color: #EAFAF6 !important;
|
||||||
height: 22rpx;
|
|
||||||
font-size: 22rpx;
|
.status-dot {
|
||||||
line-height: 22rpx;
|
background-color: #2AC79F !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
color: #2AC79F !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.device-meta {
|
.device-meta {
|
||||||
color: #808080;
|
color: #808080;
|
||||||
height: 26rpx;
|
height: 24rpx;
|
||||||
font-size: 26rpx;
|
font-size: 24rpx;
|
||||||
line-height: 26rpx;
|
line-height: 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,6 +197,11 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
margin-right: 24rpx;
|
margin-right: 24rpx;
|
||||||
|
color: #252535;
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 88rpx;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
&.member-avatar--male {
|
&.member-avatar--male {
|
||||||
background-color: #C6E6FF;
|
background-color: #C6E6FF;
|
||||||
|
|||||||
@@ -1,54 +1,88 @@
|
|||||||
|
import { get, post } from '../../utils/request/index'
|
||||||
import { leFuService } from '../../lefu/index'
|
import { leFuService } from '../../lefu/index'
|
||||||
import type { SyncUserData } from '../../lefu/index'
|
import type { SyncUserData } from '../../lefu/index'
|
||||||
|
import { calcAge } from '../../utils/idCard/index'
|
||||||
|
|
||||||
/** 连接状态订阅句柄 */
|
/** 连接状态订阅句柄 */
|
||||||
let unsubDeviceConnect: (() => void) | null = null
|
let unsubDeviceConnect: (() => void) | null = null
|
||||||
let unsubDisconnected: (() => void) | null = null
|
let unsubDisconnected: (() => void) | null = null
|
||||||
/** 同步完成关闭弹框定时器 */
|
/** 同步完成关闭弹框定时器 */
|
||||||
let syncCloseTimer: number | null = null
|
let syncCloseTimer: number | null = null
|
||||||
|
/** selectUserBySn/user 返回的单条结构 */
|
||||||
|
interface SysUserDevice {
|
||||||
|
id: string
|
||||||
|
userId: string
|
||||||
|
realname: string
|
||||||
|
height: number
|
||||||
|
birthday: string
|
||||||
|
sex: number
|
||||||
|
dataType: number
|
||||||
|
relationType: number | null
|
||||||
|
syncStatus?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 展示用成员项 */
|
||||||
|
interface MemberItem {
|
||||||
|
id: string
|
||||||
|
userId: string
|
||||||
|
name: string
|
||||||
|
gender: string
|
||||||
|
age: number
|
||||||
|
height: number
|
||||||
|
sync: string
|
||||||
|
syncClass: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 展示用分组 */
|
||||||
|
interface GroupItem {
|
||||||
|
title: string
|
||||||
|
members: MemberItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取设备成员列表 */
|
||||||
|
const getDeviceMembers = (sn: string, userId: string) =>
|
||||||
|
get<SysUserDevice[]>('weighingScale/v3/selectUserBySn/user', { sn, userId })
|
||||||
|
|
||||||
|
/** 标记用户已同步到设备 */
|
||||||
|
const markSynced = (data: { sn: string; list: string[] }) =>
|
||||||
|
post('weighingScale/v6/markSynced', data, { loading: false })
|
||||||
|
|
||||||
|
/** equipment 页传入的目标设备 */
|
||||||
|
let targetDevice: { sn: string; deviceId: string; name: string; connected: boolean; connectDeviceInfo: string } | null = null
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
device: {
|
device: {
|
||||||
name: '智能体重秤',
|
name: '智能体重秤',
|
||||||
connected: false,
|
status: false,
|
||||||
model: '',
|
deviceId: '',
|
||||||
serial: ''
|
sn: ''
|
||||||
},
|
},
|
||||||
memberCount: 5,
|
memberCount: 0,
|
||||||
hasData: true,
|
hasData: false,
|
||||||
self: {
|
self: null as null | MemberItem,
|
||||||
name: '张晓敏',
|
groups: [] as GroupItem[],
|
||||||
gender: '男',
|
|
||||||
age: 36,
|
|
||||||
height: 172,
|
|
||||||
sync: '已同步',
|
|
||||||
syncClass: 'done'
|
|
||||||
},
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
title: '员工',
|
|
||||||
members: [
|
|
||||||
{ id: 2, name: '李建国', gender: '男', age: 36, height: 182, sync: '已同步', syncClass: 'done' },
|
|
||||||
{ id: 5, name: '赵明亮', gender: '男', age: 32, height: 172, sync: '已同步', syncClass: 'done' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '家庭用户',
|
|
||||||
members: [
|
|
||||||
{ id: 3, name: '吉夏', gender: '女', age: 28, height: 165, sync: '已同步', syncClass: 'done' },
|
|
||||||
{ id: 4, name: '张雪', gender: '女', age: 32, height: 158, sync: '未同步', syncClass: 'pending' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
syncShow: false,
|
syncShow: false,
|
||||||
syncPercent: 0,
|
syncPercent: 0,
|
||||||
syncStatus: ''
|
syncStatus: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad(options: Record<string, string>) {
|
||||||
this._updateDeviceInfo()
|
targetDevice = {
|
||||||
|
sn: decodeURIComponent(options.sn || ''),
|
||||||
|
deviceId: decodeURIComponent(options.deviceId || ''),
|
||||||
|
name: decodeURIComponent(options.name || ''),
|
||||||
|
connected: options.status === 'true',
|
||||||
|
connectDeviceInfo: decodeURIComponent(options.connectDeviceInfo || ''),
|
||||||
|
}
|
||||||
|
this.setData({
|
||||||
|
'device.name': targetDevice.name || '智能体重秤',
|
||||||
|
'device.deviceId': targetDevice.deviceId,
|
||||||
|
'device.sn': targetDevice.sn,
|
||||||
|
'device.status': targetDevice.connected,
|
||||||
|
})
|
||||||
this._subscribeDeviceState()
|
this._subscribeDeviceState()
|
||||||
|
this._loadMembers()
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload() {
|
onUnload() {
|
||||||
@@ -59,59 +93,150 @@ Page({
|
|||||||
if (syncCloseTimer !== null) { clearTimeout(syncCloseTimer); syncCloseTimer = 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() {
|
_subscribeDeviceState() {
|
||||||
unsubDeviceConnect?.()
|
unsubDeviceConnect?.()
|
||||||
unsubDisconnected?.()
|
unsubDisconnected?.()
|
||||||
unsubDeviceConnect = leFuService.onDeviceConnect(() => {
|
unsubDeviceConnect = leFuService.onDeviceConnect(() => {
|
||||||
this._updateDeviceInfo()
|
this.setData({ 'device.status': leFuService.lastRawDevice?.deviceId === targetDevice?.deviceId })
|
||||||
})
|
})
|
||||||
unsubDisconnected = leFuService.onDisconnected(() => {
|
unsubDisconnected = leFuService.onDisconnected(() => {
|
||||||
this.setData({ 'device.connected': false })
|
this.setData({ 'device.status': false })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 校验设备连接状态:未连接则同步状态 + 提示 */
|
/** 拉取设备成员列表,映射到本人 + 员工/家庭用户分组 */
|
||||||
|
_loadMembers() {
|
||||||
|
if (!targetDevice?.sn) return
|
||||||
|
const userInfo = wx.getStorageSync('userInfo') as { userId?: string } | null
|
||||||
|
const userId = userInfo?.userId ?? ''
|
||||||
|
if (!userId) return
|
||||||
|
|
||||||
|
getDeviceMembers(targetDevice.sn, userId)
|
||||||
|
.then(res => {
|
||||||
|
const list = res.result
|
||||||
|
const toMember = (item: SysUserDevice): MemberItem => ({
|
||||||
|
id: item.id,
|
||||||
|
userId: item.userId,
|
||||||
|
name: item.realname,
|
||||||
|
gender: item.sex === 1 ? '男' : '女',
|
||||||
|
age: calcAge(item.birthday),
|
||||||
|
height: item.height,
|
||||||
|
sync: item.syncStatus === 1 ? '已同步' : '待同步',
|
||||||
|
syncClass: item.syncStatus === 1 ? 'done' : 'pending',
|
||||||
|
})
|
||||||
|
const self = list.find(m => m.relationType === 1)
|
||||||
|
this.setData({
|
||||||
|
self: self ? toMember(self) : null,
|
||||||
|
groups: [
|
||||||
|
{ title: '员工', members: list.filter(m => m.relationType !== 1 && m.dataType === 0).map(toMember) },
|
||||||
|
{ title: '家庭用户', members: list.filter(m => m.relationType !== 1 && m.dataType === 1).map(toMember) },
|
||||||
|
].filter(g => g.members.length),
|
||||||
|
memberCount: list.length,
|
||||||
|
hasData: list.length > 0,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
wx.showToast({ title: '加载用户列表失败', icon: 'none' })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 校验是否连接的是目标设备:不是则弹框提示连接/取消 */
|
||||||
_ensureConnected(): boolean {
|
_ensureConnected(): boolean {
|
||||||
if (leFuService.isConnected) return true
|
const connected = leFuService.isConnected && leFuService.lastRawDevice?.deviceId === targetDevice?.deviceId
|
||||||
this.setData({ 'device.connected': false })
|
if (connected) return true
|
||||||
wx.showToast({ title: '请先连接设备', icon: 'none' })
|
this.setData({ 'device.status': false })
|
||||||
|
wx.showModal({
|
||||||
|
title: '未连接设备',
|
||||||
|
content: '请先连接该设备后再同步用户',
|
||||||
|
cancelText: '取消同步',
|
||||||
|
confirmText: '连接设备',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
this._connectTargetDevice()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 同步用户至设备 */
|
/** 本页面扫描并连接目标设备 */
|
||||||
|
_connectTargetDevice() {
|
||||||
|
const targetDeviceId = targetDevice?.deviceId
|
||||||
|
if (!targetDeviceId) return
|
||||||
|
if (leFuService.isConnected) leFuService.disconnect()
|
||||||
|
|
||||||
|
wx.showLoading({ title: '连接中...', mask: true })
|
||||||
|
wx.openBluetoothAdapter({
|
||||||
|
success: () => {
|
||||||
|
let unsubList: (() => void) | null = null
|
||||||
|
let unsubConnect: (() => void) | null = null
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
unsubList?.()
|
||||||
|
unsubList = null
|
||||||
|
wx.hideLoading()
|
||||||
|
wx.showToast({ title: '未找到设备', icon: 'none' })
|
||||||
|
}, 15000)
|
||||||
|
|
||||||
|
unsubList = leFuService.onDevicesList((devices) => {
|
||||||
|
const matched = devices.find(d => d.raw.deviceId === targetDeviceId)
|
||||||
|
if (!matched) return
|
||||||
|
clearTimeout(timer)
|
||||||
|
unsubList?.()
|
||||||
|
unsubList = null
|
||||||
|
leFuService.stopScan()
|
||||||
|
leFuService.connect(matched.raw)
|
||||||
|
unsubConnect = leFuService.onDeviceConnect(() => {
|
||||||
|
unsubConnect?.()
|
||||||
|
unsubConnect = null
|
||||||
|
wx.hideLoading()
|
||||||
|
wx.setStorageSync('connectDeviceInfo', matched.raw)
|
||||||
|
this.setData({ 'device.status': true })
|
||||||
|
this.onTapSync()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
leFuService.startScan()
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
wx.hideLoading()
|
||||||
|
wx.showToast({ title: '蓝牙未开启', icon: 'none' })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 同步用户至设备:只下发「待同步」的用户 */
|
||||||
onTapSync() {
|
onTapSync() {
|
||||||
if (!this._ensureConnected()) return
|
if (!this._ensureConnected()) return
|
||||||
|
|
||||||
// 组装所有用户(self 第一个,作为主用户),性别:男=1 女=0
|
// 组装所有用户(本人第一个,作为主用户),性别:男=1 女=0
|
||||||
|
const self = this.data.self
|
||||||
const allUsers = [
|
const allUsers = [
|
||||||
{
|
...(self ? [{
|
||||||
id: 'self', name: this.data.self.name,
|
id: self.id, userId: self.userId, name: self.name,
|
||||||
gender: this.data.self.gender === '男' ? 1 : 0,
|
gender: self.gender === '男' ? 1 : 0,
|
||||||
age: this.data.self.age, height: this.data.self.height,
|
age: self.age, height: self.height, sync: self.sync,
|
||||||
},
|
}] : []),
|
||||||
...this.data.groups.flatMap(g => g.members.map(m => ({
|
...this.data.groups.flatMap(g => g.members.map(m => ({
|
||||||
id: String(m.id), name: m.name,
|
id: String(m.id), userId: m.userId, name: m.name,
|
||||||
gender: m.gender === '男' ? 1 : 0, age: m.age, height: m.height,
|
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 mainUser = allUsers[0]
|
||||||
// 组装下发参数(SyncUserData),第一个为主用户(memberID 为空)
|
// 只下发「待同步」的用户
|
||||||
const syncDataList: SyncUserData[] = allUsers.map((user, index) => ({
|
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,
|
userID: mainUser.id,
|
||||||
userName: user.name,
|
userName: user.name,
|
||||||
memberID: index === 0 ? '' : user.id,
|
memberID: user.id === mainUser.id ? '' : user.id,
|
||||||
age: user.age,
|
age: user.age,
|
||||||
gender: user.gender,
|
gender: user.gender,
|
||||||
height: user.height,
|
height: user.height,
|
||||||
@@ -123,23 +248,35 @@ Page({
|
|||||||
recentData: [],
|
recentData: [],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// 阶段1:清空设备用户,进度 0% → 100%
|
// 直接下发待同步用户(不清空)
|
||||||
this.setData({ syncShow: true, syncPercent: 0, syncStatus: '正在清空设备用户...' })
|
this.setData({ syncShow: true, syncPercent: 0, syncStatus: '正在同步信息,请勿离开...' })
|
||||||
leFuService.clearDeviceMembers()
|
leFuService.syncMembersToDevice(syncDataList, (current, total) => {
|
||||||
.then(() => {
|
this.setData({
|
||||||
this.setData({ syncPercent: 100, syncStatus: '清空完成' })
|
syncPercent: Math.round((current / total) * 100),
|
||||||
// 阶段2:下发用户,进度从 0% 重新开始
|
syncStatus: `正在同步 ${current}/${total}...`,
|
||||||
this.setData({ syncPercent: 0, syncStatus: '正在同步信息,请勿离开...' })
|
|
||||||
return leFuService.syncMembersToDevice(syncDataList, (current, total) => {
|
|
||||||
this.setData({
|
|
||||||
syncPercent: Math.round((current / total) * 100),
|
|
||||||
syncStatus: `正在同步 ${current}/${total}...`,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setData({ syncPercent: 100, syncStatus: '同步完成' })
|
this.setData({ syncPercent: 100, syncStatus: '同步完成' })
|
||||||
wx.showToast({ title: '用户同步成功', icon: 'success' })
|
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 }
|
if (syncCloseTimer !== null) { clearTimeout(syncCloseTimer); syncCloseTimer = null }
|
||||||
syncCloseTimer = setTimeout(() => {
|
syncCloseTimer = setTimeout(() => {
|
||||||
syncCloseTimer = null
|
syncCloseTimer = null
|
||||||
|
|||||||
@@ -3,17 +3,21 @@
|
|||||||
<view class="header">
|
<view class="header">
|
||||||
<!-- 设备卡片 -->
|
<!-- 设备卡片 -->
|
||||||
<view class="device-card">
|
<view class="device-card">
|
||||||
<view class="device-icon"></view>
|
<view class="device-icon">
|
||||||
|
<image src="/images/device/{{ device.name }}.png" mode="aspectFit"/>
|
||||||
|
</view>
|
||||||
<view class="device-info">
|
<view class="device-info">
|
||||||
<view class="device-name-row">
|
<view class="device-name-row">
|
||||||
<view class="device-name">{{ device.name }}</view>
|
<view class="device-name">{{ device.name }}</view>
|
||||||
<view class="device-status">
|
<view class="device-status">
|
||||||
<view class="status-dot"></view>
|
<view class="device-status_ {{ device.status ? 'connected' : '' }}">
|
||||||
<view class="status-text">{{ device.connected ? '已连接' : '未连接' }}</view>
|
<view class="status-dot"></view>
|
||||||
|
<view class="status-text">{{ device.status ? '已连接' : '未连接' }}</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="device-meta" style="margin-bottom: 20rpx">型号:{{ device.model }}</view>
|
<view class="device-meta" style="margin-bottom: 20rpx">设备ID:{{ device.deviceId }}</view>
|
||||||
<view class="device-meta">设备编号:{{ device.serial }}</view>
|
<view class="device-meta">设备SN:{{ device.sn }}</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -32,9 +36,9 @@
|
|||||||
<scroll-view scroll-y class="scrollView" wx:if="{{ hasData }}">
|
<scroll-view scroll-y class="scrollView" wx:if="{{ hasData }}">
|
||||||
<view class="scrollViewContent">
|
<view class="scrollViewContent">
|
||||||
<!-- 本人 -->
|
<!-- 本人 -->
|
||||||
<view class="member-card">
|
<view class="member-card" wx:if="{{ self }}">
|
||||||
<view class="member-top">
|
<view class="member-top">
|
||||||
<view class="member-avatar member-avatar--male"></view>
|
<view class="member-avatar {{ self.gender === '女' ? 'member-avatar--female' : 'member-avatar--male' }}">{{ self.name[0] }}</view>
|
||||||
<view class="member-info">
|
<view class="member-info">
|
||||||
<view class="member-name-row">
|
<view class="member-name-row">
|
||||||
<view class="member-name">{{ self.name }}</view>
|
<view class="member-name">{{ self.name }}</view>
|
||||||
@@ -59,7 +63,7 @@
|
|||||||
<block wx:for="{{ group.members }}" wx:key="id" wx:for-item="member">
|
<block wx:for="{{ group.members }}" wx:key="id" wx:for-item="member">
|
||||||
<view class="member-card">
|
<view class="member-card">
|
||||||
<view class="member-top">
|
<view class="member-top">
|
||||||
<view class="member-avatar {{ member.gender === '女' ? 'member-avatar--female' : 'member-avatar--male' }}"></view>
|
<view class="member-avatar {{ member.gender === '女' ? 'member-avatar--female' : 'member-avatar--male' }}">{{ member.name[0] }}</view>
|
||||||
<view class="member-info">
|
<view class="member-info">
|
||||||
<view class="member-name-row">
|
<view class="member-name-row">
|
||||||
<view class="member-name">{{ member.name }} <text>(他人添加)</text></view>
|
<view class="member-name">{{ member.name }} <text>(他人添加)</text></view>
|
||||||
|
|||||||
Reference in New Issue
Block a user