import { get } from '../../utils/request/index' import { lefuService } from '../../lefu/index' import type { DeviceMember } from '../../lefu/index' /** GET /weighingScale/v3/selectUserBySn/user 返回的 result 单条结构 */ interface SysUserDevice { id: string userId: string parentUserId: string | null scaleDeviceId: string deviceId: string | null deviceType: string dataType: number /** 用户类型:1=主用户 0=子用户 */ userType: number idCard: string height: number weight: number birthday: string /** 性别:1=男 2=女 */ sex: number avatar: string | null phone: string | null thirdId: string | null realname: string bmi: number createBy: string | null createTime: string | null updateBy: string | null updateTime: string | null delFlag: number sn: string | null workNo: string | null remark: string | null connectDeviceInfo: string | null /** 关系标记:1=本人 2=自己添加 3=他人添加 */ relationType: number | null } /** 页面展示用成员模型 */ interface MemberDisplay { id: string realname: string /** '男' | '女' */ sex_dictText: string /** 周岁,由 birthday 计算而来 */ ageDisplay: string height: number /** 1=本人 2=自己添加 3=他人添加 */ relationType: number userType: number avatar: string | null /** 原始 sex 数值,供 lefu 层转换使用 */ sex: number /** 周岁数值,供 lefu 层使用 */ age: number } /** 设备卡展示模型 */ interface DeviceCard { /** 设备 SN,来自接口返回的 scaleDeviceId */ name: string capacityUsed: number capacityTotal: number } /** * 从生日字符串(YYYY-MM-DD)计算周岁 * @param birthday 生日字符串 */ function calcAge(birthday: string): number { if (!birthday) return 0 const parts = birthday.split('-').map(Number) const [year, month, day] = parts if (!year || !month || !day) return 0 const now = new Date() let age = now.getFullYear() - year const nowMonth = now.getMonth() + 1 const nowDay = now.getDate() if (nowMonth < month || (nowMonth === month && nowDay < day)) age -= 1 return Math.max(0, age) } /** * MemberDisplay → DeviceMember 转换,供 lefu 同步层使用 * @param m 展示用成员 */ function toDeviceMember(m: MemberDisplay): DeviceMember { return { id: m.id, name: m.realname, gender: m.sex === 1 ? 1 : 0, age: m.age, height: m.height, isSelf: m.relationType === 1, } } /** * 将成员列表全量同步到设备 * @param members 展示用成员列表 */ function syncToDevice(members: MemberDisplay[]): void { const deviceMembers = members.map(toDeviceMember) wx.showLoading({ title: '正在同步成员...', mask: true }) lefuService.syncMembersToDevice(deviceMembers) .then(() => { wx.hideLoading() wx.showToast({ title: '成员同步成功', icon: 'success' }) }) .catch((err: Error) => { wx.hideLoading() wx.showToast({ title: err.message || '同步失败,请重试', icon: 'none' }) }) } /** * 设备成员管理页 * 通过 URL 参数 sn + 缓存中的 userId 拉取成员列表 * 连接状态实时读取 lefuService */ Page({ data: { connected: false, /** 当前设备 SN,由 onLoad 从 URL 参数写入 */ sn: '', loading: false, deviceCard: { name: '', capacityUsed: 0, capacityTotal: 10, } as DeviceCard, memberList: [] as MemberDisplay[], }, onLoad(options: Record) { const sn = options.sn ?? '' this.setData({ sn, // 读取 lefuService 当前连接状态作为初始值 connected: lefuService.isConnected, }) // 监听蓝牙连接/断连,实时更新状态 lefuService.onDeviceConnect(() => { this.setData({ connected: true }) }) lefuService.onDisconnected(() => { this.setData({ connected: false }) }) }, onShow() { // 每次页面显示(含首次进入和从子页返回)均刷新列表 if (this.data.sn) { this._loadData(this.data.sn) } }, onUnload() { // 页面销毁时清空回调,避免对已卸载页面调用 setData lefuService.onDeviceConnect(() => {}) lefuService.onDisconnected(() => {}) }, /** * 调 v3 接口拉取成员列表,成功后更新设备名与成员数据 * @param sn 设备 SN */ _loadData(sn: string) { const userInfo = wx.getStorageSync('userInfo') as { userId?: string } | null const userId = userInfo?.userId ?? '' this.setData({ loading: true }) get('weighingScale/v3/selectUserBySn/user', { sn, userId }) .then(res => { const list = res.result.map(item => { const age = calcAge(item.birthday) return { id: item.id, realname: item.realname, sex_dictText: item.sex === 1 ? '男' : '女', ageDisplay: String(age), height: item.height, relationType: item.relationType ?? 2, userType: item.userType, avatar: item.avatar, sex: item.sex, age, } }) // 设备名取首条记录的 scaleDeviceId,兜底用传入的 sn const name = res.result[0]?.scaleDeviceId ?? sn this.setData({ memberList: list, 'deviceCard.name': name, 'deviceCard.capacityUsed': list.length, }) // 列表有变更且已连接时才同步到设备 const hasChange = JSON.stringify(this.data.memberList) !== JSON.stringify(list) if (this.data.connected && hasChange) { syncToDevice(list) } }) .finally(() => { this.setData({ loading: false }) }) }, /** 编辑成员(接口待接入) */ onTapEdit(e: WechatMiniprogram.TouchEvent) { const id = e.currentTarget.dataset.id as string wx.showToast({ title: `编辑 ${id}`, icon: 'none' }) }, /** 删除成员(接口待接入) */ onTapDelete(e: WechatMiniprogram.TouchEvent) { const id = e.currentTarget.dataset.id as string wx.showModal({ title: '提示', content: '确定删除该成员?', success: (res) => { if (!res.confirm) return wx.showToast({ title: '删除功能待接入', icon: 'none' }) }, }) }, /** 添加成员:未连接态禁用 */ onTapAddMember() { if (!this.data.connected) return wx.navigateTo({ url: '/pages/addMember/addMember' }) }, })