Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
241 lines
7.9 KiB
TypeScript
241 lines
7.9 KiB
TypeScript
import { get } from '../../utils/request/index'
|
||
import { leFuService } from '../../lefu/index'
|
||
import type { UserInfo } from '../../api/index'
|
||
|
||
/** 体重设备(对应 /weighingScale/list/device 返回的 result 元素) */
|
||
interface ScaleDevice {
|
||
/** 记录 ID */
|
||
id: string
|
||
/** 设备 SN */
|
||
scaleDeviceId: string
|
||
/** 连接设备信息(JSON 字符串,含 name、deviceId) */
|
||
connectDeviceInfo: string
|
||
/** 用户数量 */
|
||
userNum: number
|
||
/** 状态 */
|
||
status: false
|
||
}
|
||
|
||
/** 获取体重设备列表 */
|
||
const getDeviceList = (userId: string) =>
|
||
get<ScaleDevice[]>('weighingScale/v3/list/device', { userId })
|
||
|
||
/** 展示用设备项 */
|
||
interface DeviceItem {
|
||
id: string
|
||
name: string
|
||
status: boolean
|
||
deviceId: string
|
||
sn: string
|
||
userNum: number
|
||
connectDeviceInfo: string
|
||
}
|
||
|
||
let unsubDevicesList: (() => void) | null = null
|
||
let unsubConnect: (() => void) | null = null
|
||
let unsubDisconnected: (() => void) | null = null
|
||
let scanTimer: number | null = null
|
||
|
||
Page({
|
||
data: {
|
||
devices: [] as DeviceItem[],
|
||
loadingShow: false,
|
||
loadingTitle: '正在连接设备',
|
||
loadingContent: '请确保设备处于开启状态\n请勿离开...'
|
||
},
|
||
|
||
onShow() {
|
||
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 })),
|
||
})
|
||
})
|
||
},
|
||
|
||
/** 拉取体重设备列表 */
|
||
async loadDevices() {
|
||
const raw = wx.getStorageSync('userInfo') as UserInfo | null
|
||
if (!raw?.userId) return
|
||
try {
|
||
const res = await getDeviceList(raw.userId)
|
||
this.setData({
|
||
devices: res.result.map(item => {
|
||
let info: Record<string, any> = {}
|
||
try {
|
||
info = JSON.parse(item.connectDeviceInfo || '{}')
|
||
} catch {}
|
||
return {
|
||
id: item.id,
|
||
name: info.name ?? '',
|
||
status: leFuService.isConnected && leFuService.lastRawDevice?.deviceId === info.deviceId,
|
||
deviceId: info.deviceId ?? '',
|
||
sn: item.scaleDeviceId,
|
||
userNum: item.userNum ?? 0,
|
||
connectDeviceInfo: item.connectDeviceInfo ?? '',
|
||
}
|
||
}),
|
||
})
|
||
} catch {
|
||
// 请求失败已由 request 层统一 toast
|
||
}
|
||
},
|
||
|
||
/** 取消配对:使用小程序自带 showModal */
|
||
onTapUnpair() {
|
||
wx.showModal({
|
||
title: '取消配对',
|
||
content: '是否确认取消配对当前设备?',
|
||
cancelText: '取消',
|
||
confirmText: '确定',
|
||
confirmColor: '#F24439'
|
||
})
|
||
},
|
||
|
||
/** 点击设备状态:已连接则断开,未连接则扫描连接 */
|
||
onTapStatus(e: WechatMiniprogram.TouchEvent) {
|
||
const item = e.currentTarget.dataset.item as DeviceItem
|
||
if (item.status) {
|
||
leFuService.disconnect()
|
||
this._updateStatus(item.deviceId, false)
|
||
return
|
||
}
|
||
this._connectDevice(item)
|
||
},
|
||
|
||
/** 扫描蓝牙,找到 deviceId 匹配的设备后连接 */
|
||
_connectDevice(item: DeviceItem) {
|
||
const targetDeviceId = item.deviceId
|
||
if (!targetDeviceId) return
|
||
if (leFuService.isConnected) {
|
||
leFuService.disconnect()
|
||
// 断开后全部置未连接,等新设备连上再标回
|
||
this.setData({
|
||
devices: this.data.devices.map(d => ({ ...d, status: false })),
|
||
})
|
||
}
|
||
|
||
// 清理上一次连接流程的订阅与定时器,避免重复订阅累积
|
||
unsubDevicesList?.()
|
||
unsubDevicesList = null
|
||
unsubConnect?.()
|
||
unsubConnect = null
|
||
if (scanTimer !== null) { clearTimeout(scanTimer); scanTimer = null }
|
||
|
||
wx.showLoading({ title: '连接中...', mask: true })
|
||
wx.openBluetoothAdapter({
|
||
success: () => {
|
||
scanTimer = setTimeout(() => {
|
||
unsubDevicesList?.()
|
||
unsubDevicesList = null
|
||
wx.hideLoading()
|
||
wx.showToast({ title: '未找到设备', icon: 'none' })
|
||
}, 15000)
|
||
|
||
unsubDevicesList = leFuService.onDevicesList((devices) => {
|
||
const matched = devices.find(d => d.raw.deviceId === targetDeviceId)
|
||
if (!matched) return
|
||
if (scanTimer !== null) { clearTimeout(scanTimer); scanTimer = null }
|
||
unsubDevicesList?.()
|
||
unsubDevicesList = null
|
||
leFuService.stopScan()
|
||
leFuService.connect(matched.raw)
|
||
unsubConnect = leFuService.onDeviceConnect(() => {
|
||
unsubConnect?.()
|
||
unsubConnect = null
|
||
wx.hideLoading()
|
||
wx.setStorageSync('connectDeviceInfo', matched.raw)
|
||
this._updateStatus(targetDeviceId, true)
|
||
})
|
||
})
|
||
leFuService.startScan()
|
||
},
|
||
fail: () => {
|
||
wx.hideLoading()
|
||
wx.showToast({ title: '蓝牙未开启', icon: 'none' })
|
||
},
|
||
})
|
||
},
|
||
|
||
_updateStatus(deviceId: string, status: boolean) {
|
||
this.setData({
|
||
devices: this.data.devices.map(item =>
|
||
item.deviceId === deviceId ? { ...item, status } : item
|
||
),
|
||
})
|
||
},
|
||
|
||
/** 底部操作:数据补传 / 设备连接 弹 loading */
|
||
onTapAction(e: WechatMiniprogram.TouchEvent) {
|
||
const action = e.currentTarget.dataset.action as string
|
||
if (action === '数据补传') {
|
||
this.setData({
|
||
loadingShow: true,
|
||
loadingTitle: '正在获取设备本地未上传数据',
|
||
loadingContent: '请稍等...'
|
||
})
|
||
} else if (action === '设备连接') {
|
||
this.setData({
|
||
loadingShow: true,
|
||
loadingTitle: '正在连接设备',
|
||
loadingContent: '请确保设备处于开启状态\n请勿离开...'
|
||
})
|
||
}
|
||
},
|
||
|
||
onCloseLoading() {
|
||
this.setData({ loadingShow: false })
|
||
},
|
||
|
||
/** 用户管理 */
|
||
onTapUser(e: WechatMiniprogram.TouchEvent) {
|
||
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() {
|
||
wx.navigateTo({ url: '/pages/connectedDevice/connectedDevice' })
|
||
},
|
||
|
||
/** 关闭运维模式 */
|
||
onCloseOps() {
|
||
// 关闭运维模式(待接入)
|
||
},
|
||
|
||
/** 取消全部配对 */
|
||
onUnpairAll() {
|
||
wx.showModal({
|
||
title: '取消全部配对',
|
||
content: '是否确认取消全部设备的配对?',
|
||
cancelText: '取消',
|
||
confirmText: '确定',
|
||
confirmColor: '#F24439'
|
||
})
|
||
}
|
||
})
|