fix(device): 修复设备连接与配网多场景问题,同名设备用 deviceId 区分

- 连接中关闭蓝牙立即结束 loading,不再卡到超时
- onShow 已连接时同步标记,重新搜索不误标已连接设备
- 连接中防重入,搜索中切后台重置状态
- 配网成功立即退出配网模式,密码必填且 8-16 位
- 配网失败重试定时器可清理
- 同名设备改用 deviceId 唯一标识并展示

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
17792275749
2026-08-21 09:35:18 +08:00
co-authored by Claude Opus 4.7
parent d6e59df4e9
commit db865748f2
6 changed files with 146 additions and 90 deletions
@@ -200,84 +200,98 @@
.device-card {
width: 100%;
height: 150rpx;
display: flex;
align-items: center;
padding: 0 30rpx;
background-color: #FFFFFF;
border: 2rpx solid #E6E6EA;
padding: 30rpx;
border-radius: 16rpx;
box-sizing: border-box;
margin-bottom: 24rpx;
background-color: #FFFFFF;
border: 2rpx solid #E6E6EA;
.card-icon {
width: 90rpx;
.device-card-top {
width: 100%;
height: 90rpx;
overflow: hidden;
border-radius: 24rpx;
margin-right: 24rpx;
}
.card-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
flex-wrap: nowrap;
align-items: center;
.card-name {
color: #252535;
font-size: 32rpx;
font-weight: bold;
height: 32rpx;
line-height: 32rpx;
.card-icon {
width: 90rpx;
height: 90rpx;
overflow: hidden;
border-radius: 24rpx;
margin-right: 24rpx;
}
.card-status {
margin-top: 18rpx;
.card-info {
flex: 1;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
.card-dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background-color: #2AC79F;
margin-right: 15rpx;
.card-name {
color: #252535;
font-size: 32rpx;
font-weight: bold;
height: 32rpx;
line-height: 32rpx;
}
.card-status-text {
color: #2AC79F;
height: 28rpx;
font-size: 28rpx;
font-weight: 500;
line-height: 28rpx;
.card-status {
margin-top: 18rpx;
display: flex;
align-items: center;
.card-dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background-color: #2AC79F;
margin-right: 15rpx;
}
.card-status-text {
color: #2AC79F;
height: 28rpx;
font-size: 28rpx;
font-weight: 500;
line-height: 28rpx;
}
}
}
.card-btn-primary {
color: #FFFFFF;
font-size: 24rpx;
font-weight: 500;
width: 88rpx;
height: 48rpx;
line-height: 48rpx;
text-align: center;
border-radius: 8rpx;
background-color: #2AC79F;
}
.card-btn-danger {
color: #F24439;
font-size: 24rpx;
font-weight: 500;
width: 120rpx;
height: 48rpx;
line-height: 44rpx;
text-align: center;
border: 2rpx solid #F24439;
border-radius: 8rpx;
box-sizing: border-box;
}
}
.card-btn-primary {
color: #FFFFFF;
font-size: 24rpx;
font-weight: 500;
width: 88rpx;
height: 48rpx;
line-height: 48rpx;
text-align: center;
border-radius: 8rpx;
background-color: #2AC79F;
}
.card-btn-danger {
color: #F24439;
font-size: 24rpx;
font-weight: 500;
width: 120rpx;
height: 48rpx;
line-height: 44rpx;
text-align: center;
border: 2rpx solid #F24439;
border-radius: 8rpx;
box-sizing: border-box;
.device-card-bottom {
color: #B6B6B6;
height: 22rpx;
font-size: 22rpx;
font-weight: normal;
line-height: 22rpx;
margin-top: 10rpx;
}
}
}
@@ -4,6 +4,7 @@ import type { RawDevice } from '../../lefu/types'
/** 渲染用的设备项(RawDevice 含复杂对象,不进 setData */
interface DeviceItem {
deviceId: string
name: string
connected: boolean
}
@@ -34,13 +35,19 @@ Page({
onShow() {
// 从其他页面返回时同步连接状态
if (!leFuService.isConnected) {
if (leFuService.isConnected) {
this._markConnected()
} else {
this._markAllDisconnected()
}
},
onHide() {
leFuService.stopScan()
// 搜索中切后台:停止扫描后重置状态,避免回来显示「搜索中」假状态
if (this.data.status === 'searching') {
this.setData({ status: 'idle' })
}
},
onUnload() {
@@ -91,16 +98,19 @@ Page({
})
},
/** 获取当前已连接设备的 deviceId(未连接返回空字符串) */
_getConnectedId(): string {
if (!leFuService.isConnected) return ''
const cached = wx.getStorageSync('connectDeviceInfo') as Record<string, any> | null
return cached?.deviceId || ''
},
/** 连接成功后把对应设备卡片标记为已连接(覆盖手动连接与自动重连) */
_markConnected() {
const cached = wx.getStorageSync('connectDeviceInfo') as Record<string, any> | null
const name = leFuService.deviceInfo?.modelNumber
|| cached?.scaleDeviceName
|| cached?.name
|| cached?.deviceName
if (!name) return
const id = this._getConnectedId()
if (!id) return
this.setData({
deviceList: this.data.deviceList.map(item => ({ ...item, connected: item.name === name })),
deviceList: this.data.deviceList.map(item => ({ ...item, connected: item.deviceId === id })),
})
},
@@ -174,10 +184,14 @@ Page({
this.setData({ status: 'empty', deviceList: [] })
return
}
const connectedName = this.data.deviceList.find(d => d.connected)?.name
const connectedId = this._getConnectedId()
this.setData({
status: 'found',
deviceList: devices.map(d => ({ name: d.name, connected: d.name === connectedName })),
deviceList: devices.map(d => ({
deviceId: d.raw.deviceId || '',
name: d.name,
connected: !!connectedId && d.raw.deviceId === connectedId,
})),
})
this._tryAutoConnect()
})
@@ -193,6 +207,8 @@ Page({
/** 命中缓存设备时自动连接一次 */
_tryAutoConnect() {
if (autoConnectTried) return
// 已连接时不自动重连,避免触发断开重连
if (leFuService.isConnected) return
const cached = wx.getStorageSync('connectDeviceInfo') as RawDevice | null
if (!cached?.deviceId) return
const index = scannedDevices.findIndex(d => d.raw.deviceId === cached.deviceId)
@@ -205,6 +221,8 @@ Page({
_connectByIndex(index: number, isAuto: boolean) {
const scanned = scannedDevices[index]
if (!scanned) return
// 连接中:防止重复点击导致连接流程被重复触发
if (connectCleanup) return
wx.showLoading({ title: '连接中...', mask: true })
leFuService.stopScan()
@@ -230,6 +248,10 @@ Page({
if (state === leFuService.BLUE_STATE.CONNECTFAILED) {
finish()
wx.showToast({ title: '连接失败,请重试', icon: 'none' })
} else if (state === leFuService.BLUE_STATE.UNAVAILABLE) {
// 连接过程中蓝牙被关闭:立即结束 loading,避免卡到超时
finish()
wx.showToast({ title: '蓝牙已断开,请重新开启', icon: 'none' })
}
})
@@ -54,26 +54,29 @@
<!-- 找到设备:统一循环,内部按 connected 切换 UI -->
<block wx:if="{{ status === 'found' }}">
<view class="device-list">
<block wx:for="{{ deviceList }}" wx:key="name">
<block wx:for="{{ deviceList }}" wx:key="deviceId">
<view class="device-card" data-index="{{ index }}" data-connected="{{ item.connected }}" bind:tap="onTapCard">
<view class="card-icon">
<image src="/images/device/{{ item.name }}.png" mode="aspectFit" style="width:100%;height:100%;"></image>
</view>
<view class="card-info">
<view class="card-name">{{ item.name }}</view>
<view class="device-card-top">
<view class="card-icon">
<image src="/images/device/{{ item.name }}.png" mode="aspectFit" style="width:100%;height:100%;"></image>
</view>
<view class="card-info">
<view class="card-name">{{ item.name }}</view>
<block wx:if="{{ item.connected }}">
<view class="card-status">
<view class="card-dot"></view>
<text class="card-status-text">已连接</text>
</view>
</block>
</view>
<block wx:if="{{ item.connected }}">
<view class="card-status">
<view class="card-dot"></view>
<text class="card-status-text">已连接</text>
</view>
<view class="card-btn-danger" catch:tap="onDisconnect">断开连接</view>
</block>
<block wx:else>
<view class="card-btn-primary" data-index="{{ index }}" catch:tap="onConnect">连接</view>
</block>
</view>
<block wx:if="{{ item.connected }}">
<view class="card-btn-danger" catch:tap="onDisconnect">断开连接</view>
</block>
<block wx:else>
<view class="card-btn-primary" data-index="{{ index }}" catch:tap="onConnect">连接</view>
</block>
<view class="device-card-bottom">deviceId{{ item.deviceId }}</view>
</view>
</block>
</view>