Improve heart rate device reconnect flow

This commit is contained in:
2026-03-24 17:17:29 +08:00
parent 71ad6c6535
commit 0ccf7daf50
8 changed files with 831 additions and 72 deletions

View File

@@ -31,9 +31,10 @@ type MapPageData = MapEngineViewState & {
showRightButtonGroups: boolean
showBottomDebugButton: boolean
}
const INTERNAL_BUILD_VERSION = 'map-build-175'
const INTERNAL_BUILD_VERSION = 'map-build-195'
const REMOTE_GAME_CONFIG_URL = 'https://oss-mbh5.colormaprun.com/wxmini/test/game.json'
let mapEngine: MapEngine | null = null
let stageCanvasAttached = false
function buildSideButtonVisibility(mode: SideButtonMode) {
return {
sideButtonMode: mode,
@@ -114,6 +115,8 @@ Page({
mockBridgeUrlDraft: 'wss://gs.gotomars.xyz/mock-gps',
mockCoordText: '--',
mockSpeedText: '--',
heartRateScanText: '未扫描',
heartRateDiscoveredDevices: [],
panelSpeedValueText: '0',
panelTelemetryTone: 'blue',
panelHeartRateZoneNameText: '--',
@@ -150,7 +153,7 @@ Page({
compassTicks: buildCompassTicks(),
compassLabels: buildCompassLabels(),
...buildSideButtonVisibility('left'),
} as MapPageData,
} as unknown as MapPageData,
onLoad() {
const systemInfo = wx.getSystemInfoSync()
@@ -239,15 +242,29 @@ Page({
},
onReady() {
stageCanvasAttached = false
this.measureStageAndCanvas()
this.loadMapConfigFromRemote()
},
onShow() {
if (mapEngine) {
mapEngine.handleAppShow()
}
},
onHide() {
if (mapEngine) {
mapEngine.handleAppHide()
}
},
onUnload() {
if (mapEngine) {
mapEngine.destroy()
mapEngine = null
}
stageCanvasAttached = false
},
loadMapConfigFromRemote() {
@@ -295,6 +312,10 @@ Page({
currentEngine.setStage(rect)
if (stageCanvasAttached) {
return
}
const canvasQuery = wx.createSelectorQuery().in(page)
canvasQuery.select('#mapCanvas').fields({ node: true, size: true })
canvasQuery.select('#routeLabelCanvas').fields({ node: true, size: true })
@@ -317,6 +338,7 @@ Page({
dpr,
labelCanvasRef && labelCanvasRef.node ? labelCanvasRef.node : undefined,
)
stageCanvasAttached = true
} catch (error) {
page.setData({
statusText: `WebGL 鍒濆鍖栧け璐?(${INTERNAL_BUILD_VERSION})`,
@@ -453,11 +475,23 @@ Page({
}
},
handleDisconnectHeartRate() {
if (mapEngine) {
mapEngine.handleDisconnectHeartRate()
}
},
handleDisconnectHeartRate() {
if (mapEngine) {
mapEngine.handleDisconnectHeartRate()
}
},
handleConnectHeartRateDevice(event: WechatMiniprogram.BaseEvent<{ deviceId?: string }>) {
if (mapEngine && event.currentTarget && event.currentTarget.dataset && event.currentTarget.dataset.deviceId) {
mapEngine.handleConnectHeartRateDevice(event.currentTarget.dataset.deviceId)
}
},
handleClearPreferredHeartRateDevice() {
if (mapEngine) {
mapEngine.handleClearPreferredHeartRateDevice()
}
},
handleDebugHeartRateBlue() {
if (mapEngine) {

View File

@@ -78,28 +78,28 @@
<cover-view class="map-side-column map-side-column--left map-side-column--left-group" wx:if="{{!showDebugPanel && showLeftButtonGroup}}" style="top: {{topInsetHeight}}px;">
<cover-view class="map-side-button map-side-button--icon" bindtap="handleToggleMapRotateMode"><cover-image class="map-side-button__rotate-image {{orientationMode === 'heading-up' ? 'map-side-button__rotate-image--active' : ''}}" src="../../assets/btn_map_rotate_cropped.png"></cover-image></cover-view>
<cover-view class="map-side-button map-side-button--muted"><cover-view class="map-side-button__text">LOC</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">LOCK</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">SUN</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">EXIT</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--muted"><cover-view class="map-side-button__text">1</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">2</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">3</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">4</cover-view></cover-view>
</cover-view>
<cover-view class="map-side-column map-side-column--right-main" wx:if="{{!showDebugPanel && showRightButtonGroups}}" style="top: {{topInsetHeight}}px;">
<cover-view class="map-side-button"><cover-view class="map-side-button__text">N</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">DIR</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">COMP</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">GUIDE</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--muted"><cover-view class="map-side-button__text">NET</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">GO</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">5</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">6</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">7</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">8</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--muted"><cover-view class="map-side-button__text">9</cover-view></cover-view>
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">10</cover-view></cover-view>
</cover-view>
<cover-view class="map-side-column map-side-column--right-sub" wx:if="{{!showDebugPanel && showRightButtonGroups}}" style="top: {{topInsetHeight}}px;">
<cover-view class="map-side-button"><cover-view class="map-side-button__text">INFO</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">SET</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">m</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">PIN</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">LIST</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">USER</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">11</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">12</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">13</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">14</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">15</cover-view></cover-view>
<cover-view class="map-side-button"><cover-view class="map-side-button__text">16</cover-view></cover-view>
</cover-view>
<cover-view class="map-punch-button {{punchButtonEnabled ? 'map-punch-button--active' : ''}} {{punchButtonFxClass}}" wx:if="{{!showDebugPanel}}" bindtap="handlePunchAction">
@@ -332,6 +332,29 @@
<text class="info-panel__label">HR Device</text>
<text class="info-panel__value">{{heartRateDeviceText}}</text>
</view>
<view class="info-panel__row">
<text class="info-panel__label">HR Scan</text>
<text class="info-panel__value">{{heartRateScanText}}</text>
</view>
<view class="debug-device-list" wx:if="{{heartRateDiscoveredDevices.length}}">
<view class="debug-device-card" wx:for="{{heartRateDiscoveredDevices}}" wx:key="deviceId">
<view class="debug-device-card__main">
<view class="debug-device-card__title-row">
<text class="debug-device-card__name">{{item.name}}</text>
<text class="debug-device-card__badge" wx:if="{{item.preferred}}">首选</text>
</view>
<text class="debug-device-card__meta">{{item.rssiText}}</text>
</view>
<view class="debug-device-card__action {{item.connected ? 'debug-device-card__action--active' : ''}}" data-device-id="{{item.deviceId}}" bindtap="handleConnectHeartRateDevice">{{item.connected ? '已连接' : '连接'}}</view>
</view>
</view>
<view class="control-row">
<view class="control-chip {{heartRateConnected ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleConnectHeartRate">{{heartRateConnected ? '心率带已连接' : '连接心率带'}}</view>
<view class="control-chip control-chip--secondary" bindtap="handleDisconnectHeartRate">断开心率带</view>
</view>
<view class="control-row">
<view class="control-chip control-chip--secondary" bindtap="handleClearPreferredHeartRateDevice">清除首选</view>
</view>
<view class="info-panel__row">
<text class="info-panel__label">Heading Mode</text>
<text class="info-panel__value">{{orientationModeText}}</text>
@@ -346,14 +369,12 @@
</view>
<view class="control-row">
<view class="control-chip {{gpsTracking ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleToggleGpsTracking">{{gpsTracking ? '停止定位' : '开启定位'}}</view>
<view class="control-chip {{heartRateConnected ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleConnectHeartRate">{{heartRateConnected ? '心率带已连接' : '连接心率带'}}</view>
</view>
<view class="control-row">
<view class="control-chip {{locationSourceMode === 'real' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetRealLocationMode">真实定位</view>
<view class="control-chip {{locationSourceMode === 'mock' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetMockLocationMode">模拟定位</view>
</view>
<view class="control-row">
<view class="control-chip control-chip--secondary" bindtap="handleDisconnectHeartRate">断开心率带</view>
<view class="control-chip control-chip--secondary" bindtap="handleCycleNorthReferenceMode">{{northReferenceButtonText}}</view>
</view>
</view>

View File

@@ -1194,6 +1194,81 @@
gap: 14rpx;
}
.debug-device-list {
display: flex;
flex-direction: column;
gap: 12rpx;
margin-top: 16rpx;
}
.debug-device-card {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
padding: 16rpx 18rpx;
border-radius: 18rpx;
background: rgba(255, 255, 255, 0.82);
box-shadow: inset 0 0 0 2rpx rgba(22, 48, 32, 0.06);
}
.debug-device-card__main {
flex: 1;
min-width: 0;
}
.debug-device-card__title-row {
display: flex;
align-items: center;
gap: 10rpx;
}
.debug-device-card__name {
flex: 1;
min-width: 0;
font-size: 24rpx;
line-height: 1.3;
font-weight: 700;
color: #163020;
word-break: break-all;
}
.debug-device-card__badge {
flex-shrink: 0;
padding: 4rpx 10rpx;
border-radius: 999rpx;
background: rgba(45, 106, 79, 0.14);
color: #2d6a4f;
font-size: 18rpx;
line-height: 1;
font-weight: 700;
}
.debug-device-card__meta {
margin-top: 8rpx;
font-size: 20rpx;
line-height: 1.2;
color: #6a826f;
}
.debug-device-card__action {
flex-shrink: 0;
min-width: 96rpx;
padding: 16rpx 18rpx;
border-radius: 999rpx;
background: #eef6ea;
color: #2d6a4f;
font-size: 22rpx;
line-height: 1;
text-align: center;
font-weight: 700;
}
.debug-device-card__action--active {
background: #2d6a4f;
color: #f7fbf2;
}
.control-row {
display: flex;
gap: 14rpx;