fix(device): 修复设备切换连接订阅累积与自动重连,连接后更新缓存

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
17792275749
2026-08-24 17:06:27 +08:00
co-authored by Claude Sonnet 4.6
parent 6ffda3f3f3
commit f750d15150
4 changed files with 120 additions and 25 deletions
+3 -4
View File
@@ -94,6 +94,7 @@ class LeFuService {
*/
startScan(): void {
console.log(TAG, 'startScan()')
this._intentionalConnect = true
plugin.Blue.setDeviceSetting(DEVICE_SETTINGS)
this._subscribeBus()
plugin.Blue.start(DEVICE_SETTINGS.map(s => s.deviceName), false)
@@ -185,11 +186,9 @@ class LeFuService {
}
return
}
// 蓝牙就绪:如有缓存设备且非主动断开,尝试重连
// 蓝牙就绪:非主动操作(意外断开)且有缓存设备时自动重连,主动扫描/连接期间不重连
if (res === plugin.BLUE_STATE.READY) {
if (this._intentionalConnect) {
this._intentionalConnect = false
} else if (this._lastRawDevice && !this._activeProtocol) {
if (!this._intentionalConnect && this._lastRawDevice && !this._activeProtocol && this._onDevicesListCbs.size === 0) {
this._stopReconnectTimer()
wx.openBluetoothAdapter({
success: () => this.connect(this._lastRawDevice!),
+8 -9
View File
@@ -128,7 +128,6 @@
overflow: hidden;
margin-right: 24rpx;
border-radius: 24rpx;
background-color: #1385FA;
}
.device-info {
@@ -187,17 +186,17 @@
font-size: 22rpx;
line-height: 22rpx;
}
}
&.connected {
background-color: #EAFAF6;
.connected {
background-color: #EAFAF6 !important;
&.status-dot {
background-color: #2AC79F;
}
.status-dot {
background-color: #2AC79F !important;
}
&.status-text {
color: #2AC79F;
}
.status-text {
color: #2AC79F !important;
}
}
}
+79 -1
View File
@@ -1,4 +1,5 @@
import { get } from '../../utils/request/index'
import { leFuService } from '../../lefu/index'
import type { UserInfo } from '../../api/index'
/** 体重设备(对应 /weighingScale/list/device 返回的 result 元素) */
@@ -30,6 +31,10 @@ interface DeviceItem {
connectDeviceInfo: string
}
let unsubDevicesList: (() => void) | null = null
let unsubConnect: (() => void) | null = null
let scanTimer: number | null = null
Page({
data: {
devices: [] as DeviceItem[],
@@ -57,7 +62,7 @@ Page({
return {
id: item.id,
name: info.name ?? '',
status: false,
status: leFuService.isConnected && leFuService.lastRawDevice?.deviceId === info.deviceId,
deviceId: info.deviceId ?? '',
sn: item.scaleDeviceId,
userNum: item.userNum ?? 0,
@@ -81,6 +86,79 @@ Page({
})
},
/** 点击设备状态:已连接则断开,未连接则扫描连接 */
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
+30 -11
View File
@@ -1,9 +1,9 @@
<view class="equipment">
<!-- 运维模式提示行 -->
<!-- <view class="ops-bar">-->
<!-- <view class="ops-mode">当前为:运维模式</view>-->
<!-- <view class="ops-btn ops-btn&#45;&#45;blue" bind:tap="onCloseOps">关闭运维模式</view>-->
<!-- </view>-->
<view class="ops-bar">
<view class="ops-mode">当前为:运维模式</view>
<view class="ops-btn ops-btn--blue" bind:tap="onCloseOps">关闭运维模式</view>
</view>
<!-- 顶部卡片(渐变背景 + 设备图片占位) -->
<view class="top-banner">
@@ -22,17 +22,26 @@
</view>
<!-- 设备列表 -->
<!-- <view class="device">
<scroll-view class="scrollView" scroll-y>
<view class="scrollViewContent">
</view>
</scroll-view>
</view> -->
<block wx:if="{{ devices && devices.length }}">
<block wx:for="{{ devices }}" wx:key="id">
<view class="device-card">
<view class="device-top">
<view class="device-icon"></view>
<view class="device-icon">
<image src="/images/device/{{ item.name }}.png"/>
</view>
<view class="device-info">
<view class="device-info_">
<view class="device-name">{{ item.name }}</view>
<view class="device-unpair" bind:tap="onTapUnpair">取消配对</view>
</view>
<view class="device-status">
<view class="device-status" bind:tap="onTapStatus" data-item="{{ item }}">
<view class="device-status_ {{item.status ? 'connected' : ''}}">
<view class="status-dot"></view>
<view class="status-text">{{ item.status ? '已连接' : '未连接' }}</view>
@@ -53,12 +62,22 @@
</view>
<view class="device-actions">
<view class="device-action-btn">
<view>
<image src="/images/equipment/wifi.png"/>
<block wx:if="{{item.status}}">
<view class="device-action-btn">
<view>
<image src="/images/equipment/wifi.png"/>
</view>
<view>设备WIFI</view>
</view>
<view>设备WIFI</view>
</view>
</block>
<block wx:else>
<view class="device-action-btn" bind:tap="onTapStatus" data-item="{{ item }}">
<view>
<image src="/images/equipment/bluetooth.png"/>
</view>
<view>设备连接</view>
</view>
</block>
<view class="device-action-btn" bind:tap="onTapUser">
<view>
<image src="/images/equipment/users.png"/>