Files
bodyWeight/miniprogram/pages/equipment/equipment.ts
T

304 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { get, del } 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
}
/** 获取体重设备列表(运维模式走 ops/listDevice,普通模式走 v6/list/device */
const getDeviceList = () =>
get<ScaleDevice[]>(
getApp<IAppOption>().globalData.operationsEngineer
? 'weighingScale/ops/listDevice'
: 'weighingScale/v6/list/device',
)
/** 取消配对:id 不传则解除所有设备绑定(运维模式走 ops/deleteUser,普通模式走 v6/unbind */
const unbindDevice = (id?: string) => {
const url = getApp<IAppOption>().globalData.operationsEngineer
? 'weighingScale/ops/deleteUser'
: 'weighingScale/v6/unbind'
return del(`${url}${id ? `?id=${id}` : ''}`, {}, { loading: false })
}
/** 展示用设备项 */
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: {
operationsEngineer: false,
devices: [] as DeviceItem[],
loadingShow: false,
loadingTitle: '正在连接设备',
loadingContent: '请确保设备处于开启状态\n请勿离开...'
},
onShow() {
this.setData({ operationsEngineer: getApp<IAppOption>().globalData.operationsEngineer ?? false })
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()
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
}
},
/** 取消配对:解除指定设备绑定 */
onTapUnpair(e: WechatMiniprogram.TouchEvent) {
const item = e.currentTarget.dataset.item as DeviceItem
wx.showModal({
title: '取消配对',
content: '是否确认取消配对当前设备?',
cancelText: '取消',
confirmText: '确定',
confirmColor: '#F24439',
success: (res) => {
if (!res.confirm) return
unbindDevice(item.id)
.then(() => {
const cached = wx.getStorageSync('connectDeviceInfo') as Record<string, any> | null
if (cached?.deviceId === item.deviceId) {
wx.removeStorageSync('connectDeviceInfo')
}
wx.showToast({ title: '已取消配对', icon: 'success' })
this.loadDevices()
})
.catch(() => {})
},
})
},
/** 点击设备状态:已连接则断开,未连接则扫描连接 */
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)}`,
})
},
/** 跳转设备 WiFi 配网页 */
onTapWifi() {
wx.navigateTo({ url: '/pages/connectedWifi/connectedWifi' })
},
/** 数据补传:读取设备端 userId 列表(调试用) */
onTapDataRetransfer() {
leFuService.fetchDeviceUserIds()
.then((list) => {
console.log('[数据补传] userId 列表:', list)
})
.catch(() => {
wx.showToast({ title: '请先连接设备', icon: 'none' })
})
},
onTapAdd() {
wx.navigateTo({ url: '/pages/connectedDevice/connectedDevice' })
},
/** 长按 banner 打开运维模式 */
onLongPressBanner() {
getApp<IAppOption>().globalData.operationsEngineer = true
this.setData({ operationsEngineer: true })
this.loadDevices()
},
/** 关闭运维模式 */
onCloseOps() {
getApp<IAppOption>().globalData.operationsEngineer = false
this.setData({ operationsEngineer: false })
this.loadDevices()
},
/** 取消全部配对:解除所有设备绑定 */
onUnpairAll() {
wx.showModal({
title: '取消全部配对',
content: '是否确认取消全部设备的配对?',
cancelText: '取消',
confirmText: '确定',
confirmColor: '#F24439',
success: (res) => {
if (!res.confirm) return
unbindDevice()
.then(() => {
wx.removeStorageSync('connectDeviceInfo')
wx.showToast({ title: '已取消全部配对', icon: 'success' })
this.loadDevices()
})
.catch(() => {})
},
})
}
})