完善后端联调链路与模拟器多通道支持
This commit is contained in:
3
miniprogram/pages/result/result.json
Normal file
3
miniprogram/pages/result/result.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"navigationBarTitleText": "结果"
|
||||
}
|
||||
134
miniprogram/pages/result/result.ts
Normal file
134
miniprogram/pages/result/result.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { loadBackendAuthTokens, loadBackendBaseUrl } from '../../utils/backendAuth'
|
||||
import { getMyResults, getSessionResult, type BackendSessionResultView } from '../../utils/backendApi'
|
||||
|
||||
type ResultPageData = {
|
||||
sessionId: string
|
||||
statusText: string
|
||||
sessionTitleText: string
|
||||
sessionSubtitleText: string
|
||||
rows: Array<{ label: string; value: string }>
|
||||
recentResults: BackendSessionResultView[]
|
||||
}
|
||||
|
||||
function getAccessToken(): string | null {
|
||||
const app = getApp<IAppOption>()
|
||||
const tokens = app.globalData && app.globalData.backendAuthTokens
|
||||
? app.globalData.backendAuthTokens
|
||||
: loadBackendAuthTokens()
|
||||
return tokens && tokens.accessToken ? tokens.accessToken : null
|
||||
}
|
||||
|
||||
function formatValue(value: unknown): string {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '--'
|
||||
}
|
||||
return String(value)
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
sessionId: '',
|
||||
statusText: '准备加载结果',
|
||||
sessionTitleText: '结果页',
|
||||
sessionSubtitleText: '未加载',
|
||||
rows: [],
|
||||
recentResults: [],
|
||||
} as ResultPageData,
|
||||
|
||||
onLoad(query: { sessionId?: string }) {
|
||||
const sessionId = query && query.sessionId ? decodeURIComponent(query.sessionId) : ''
|
||||
this.setData({ sessionId })
|
||||
if (sessionId) {
|
||||
this.loadSingleResult(sessionId)
|
||||
return
|
||||
}
|
||||
this.loadRecentResults()
|
||||
},
|
||||
|
||||
async loadSingleResult(sessionId: string) {
|
||||
const accessToken = getAccessToken()
|
||||
if (!accessToken) {
|
||||
wx.redirectTo({ url: '/pages/login/login' })
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
statusText: '正在加载单局结果',
|
||||
})
|
||||
|
||||
try {
|
||||
const result = await getSessionResult({
|
||||
baseUrl: loadBackendBaseUrl(),
|
||||
accessToken,
|
||||
sessionId,
|
||||
})
|
||||
this.setData({
|
||||
statusText: '单局结果加载完成',
|
||||
sessionTitleText: result.session.eventName || result.session.eventDisplayName || result.session.eventId || result.session.id || result.session.sessionId,
|
||||
sessionSubtitleText: `${result.session.status || result.session.sessionStatus} / ${result.result.status}`,
|
||||
rows: [
|
||||
{ label: '最终得分', value: formatValue(result.result.finalScore) },
|
||||
{ label: '最终用时(秒)', value: formatValue(result.result.finalDurationSec) },
|
||||
{ label: '完成点数', value: formatValue(result.result.completedControls) },
|
||||
{ label: '总点数', value: formatValue(result.result.totalControls) },
|
||||
{ label: '累计里程(m)', value: formatValue(result.result.distanceMeters) },
|
||||
{ label: '平均速度(km/h)', value: formatValue(result.result.averageSpeedKmh) },
|
||||
{ label: '最大心率', value: formatValue(result.result.maxHeartRateBpm) },
|
||||
],
|
||||
})
|
||||
} catch (error) {
|
||||
const message = error && (error as { message?: string }).message ? (error as { message: string }).message : '未知错误'
|
||||
this.setData({
|
||||
statusText: `结果加载失败:${message}`,
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async loadRecentResults() {
|
||||
const accessToken = getAccessToken()
|
||||
if (!accessToken) {
|
||||
wx.redirectTo({ url: '/pages/login/login' })
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
statusText: '正在加载最近结果',
|
||||
})
|
||||
|
||||
try {
|
||||
const results = await getMyResults({
|
||||
baseUrl: loadBackendBaseUrl(),
|
||||
accessToken,
|
||||
limit: 20,
|
||||
})
|
||||
this.setData({
|
||||
statusText: '最近结果加载完成',
|
||||
sessionSubtitleText: '最近结果列表',
|
||||
recentResults: results,
|
||||
})
|
||||
} catch (error) {
|
||||
const message = error && (error as { message?: string }).message ? (error as { message: string }).message : '未知错误'
|
||||
this.setData({
|
||||
statusText: `结果加载失败:${message}`,
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
handleOpenResult(event: WechatMiniprogram.TouchEvent) {
|
||||
const sessionId = event.currentTarget.dataset.sessionId as string | undefined
|
||||
if (!sessionId) {
|
||||
return
|
||||
}
|
||||
wx.redirectTo({
|
||||
url: `/pages/result/result?sessionId=${encodeURIComponent(sessionId)}`,
|
||||
})
|
||||
},
|
||||
|
||||
handleBackToList() {
|
||||
this.setData({
|
||||
sessionId: '',
|
||||
rows: [],
|
||||
})
|
||||
this.loadRecentResults()
|
||||
},
|
||||
})
|
||||
33
miniprogram/pages/result/result.wxml
Normal file
33
miniprogram/pages/result/result.wxml
Normal file
@@ -0,0 +1,33 @@
|
||||
<scroll-view class="page" scroll-y>
|
||||
<view class="shell">
|
||||
<view class="hero">
|
||||
<view class="hero__eyebrow">Result</view>
|
||||
<view class="hero__title">{{sessionTitleText}}</view>
|
||||
<view class="hero__desc">{{sessionSubtitleText}}</view>
|
||||
</view>
|
||||
|
||||
<view class="panel">
|
||||
<view class="panel__title">当前状态</view>
|
||||
<view class="summary">{{statusText}}</view>
|
||||
<button wx:if="{{sessionId}}" class="btn btn--ghost" bindtap="handleBackToList">返回最近结果</button>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{rows.length}}" class="panel">
|
||||
<view class="panel__title">单局摘要</view>
|
||||
<view wx:for="{{rows}}" wx:key="label" class="row">
|
||||
<view class="row__label">{{item.label}}</view>
|
||||
<view class="row__value">{{item.value}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{!sessionId}}" class="panel">
|
||||
<view class="panel__title">最近结果</view>
|
||||
<view wx:if="{{!recentResults.length}}" class="summary">当前没有结果记录</view>
|
||||
<view wx:for="{{recentResults}}" wx:key="session.id" class="result-card" bindtap="handleOpenResult" data-session-id="{{item.session.id}}">
|
||||
<view class="result-card__title">{{item.session.eventName || item.session.id}}</view>
|
||||
<view class="result-card__meta">{{item.result.status}} / {{item.session.status}}</view>
|
||||
<view class="result-card__meta">得分 {{item.result.finalScore || '--'}} / 用时 {{item.result.finalDurationSec || '--'}}s</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
114
miniprogram/pages/result/result.wxss
Normal file
114
miniprogram/pages/result/result.wxss
Normal file
@@ -0,0 +1,114 @@
|
||||
page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(180deg, #eff4fb 0%, #e8eff7 100%);
|
||||
}
|
||||
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.shell {
|
||||
display: grid;
|
||||
gap: 24rpx;
|
||||
padding: 28rpx 24rpx 40rpx;
|
||||
}
|
||||
|
||||
.hero,
|
||||
.panel {
|
||||
display: grid;
|
||||
gap: 16rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
.hero {
|
||||
background: linear-gradient(135deg, #163a66 0%, #1f5da1 100%);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.hero__eyebrow {
|
||||
font-size: 22rpx;
|
||||
letter-spacing: 0.16em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.hero__title {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.hero__desc {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.84);
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
box-shadow: 0 14rpx 32rpx rgba(40, 63, 95, 0.08);
|
||||
}
|
||||
|
||||
.panel__title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #17345a;
|
||||
}
|
||||
|
||||
.summary,
|
||||
.row__label,
|
||||
.row__value,
|
||||
.result-card__meta {
|
||||
font-size: 24rpx;
|
||||
line-height: 1.6;
|
||||
color: #30465f;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
padding: 10rpx 0;
|
||||
border-bottom: 2rpx solid #edf2f7;
|
||||
}
|
||||
|
||||
.row:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.row__value {
|
||||
font-weight: 700;
|
||||
color: #17345a;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
display: grid;
|
||||
gap: 8rpx;
|
||||
padding: 18rpx;
|
||||
border-radius: 18rpx;
|
||||
background: #f6f9fc;
|
||||
}
|
||||
|
||||
.result-card__title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #17345a;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 0;
|
||||
min-height: 76rpx;
|
||||
padding: 0 24rpx;
|
||||
line-height: 76rpx;
|
||||
border-radius: 18rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.btn::after {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.btn--ghost {
|
||||
background: #ffffff;
|
||||
color: #52657d;
|
||||
border: 2rpx solid #d8e2ec;
|
||||
}
|
||||
Reference in New Issue
Block a user