feat: 排行榜虚拟领奖台 + 勋章对齐与尺寸统一

- 领奖台数据不足 3 名时显示虚拟空位(虚线轮廓+虚位以待)
- 领奖台勋章与昵称对齐改为等高盒结构性修复(移除 margin 盲推)
- 全 app 成就勋章图标尺寸统一为 30rpx(前三名/列表/设置页/记录页一致)
- 勋章 SVG 按包围盒精确居中(utils/icons.js)
- 设置页/记录页勋章展示配套调整
This commit is contained in:
2026-08-04 11:23:48 +08:00
parent bce796d893
commit b52db87ddf
17 changed files with 690 additions and 67 deletions
+24 -1
View File
@@ -56,6 +56,9 @@ Page({
completionStreak: 0,
completionLevel: 'normal',
completionMessage: '',
// 完成弹窗科学提示(config.scienceTips 按本次时长选段)
completionTipValue: '',
completionTipRisk: '',
icons: iconsMod.build()
},
@@ -700,6 +703,22 @@ Page({
this._saveAndShowCompletion(elapsed)
},
/**
* 按本次实际训练时长从 config.scienceTips 选一段提示。
* 命中第一条 maxSeconds 大于 elapsed 的配置;缺失配置时返回空(不显示)。
*/
_pickScienceTip(elapsed) {
const tips = config.scienceTips || []
const sec = Math.max(0, Number(elapsed) || 0)
for (const t of tips) {
const max = t && t.maxSeconds == null ? Infinity : (t && t.maxSeconds)
if (sec < max) {
return { value: (t && t.value) || '', risk: (t && t.risk) || '' }
}
}
return { value: '', risk: '' }
},
/**
* Persist the just-finished training and pop the big completion modal.
* Called from finishTraining (the user manually ends; the timer keeps
@@ -743,6 +762,7 @@ Page({
try { wx.setStorageSync('_lb_force_refresh', true) } catch (e) {}
const finalStreak = storage.getStreak().count
const scienceTip = this._pickScienceTip(elapsed)
this.setData({
// Background effects keep playing behind the modal
@@ -761,7 +781,10 @@ Page({
completionOvertime: this.data.isCircuitMode ? 0 : Math.max(0, elapsed - this.data.duration),
completionStreak: finalStreak,
completionLevel: level,
completionMessage: message
completionMessage: message,
// 科学提示(按时长分段;无配置时为空字符串,wx:if 不渲染)
completionTipValue: scienceTip.value,
completionTipRisk: scienceTip.risk
})
// Animate the big number from 0 to elapsed
+9 -1
View File
@@ -197,7 +197,6 @@
<text class="completion-number {{completionElapsed >= 60 ? 'completion-number--long' : ''}}">{{fmt.numPart(completionElapsed)}}</text>
<text class="completion-unit">{{fmt.unitPart(completionElapsed)}}</text>
</view>
<text class="completion-label">本次训练</text>
<view class="completion-overtime" wx:if="{{completionOvertime > 0}}">
<text class="overtime-plus">+{{completionOvertime}}</text>
@@ -209,6 +208,15 @@
<text class="streak-text">连续打卡 {{completionStreak}} 天</text>
</view>
<!-- 科学提示:价值行 + 弱化风险行(config.scienceTips 按时长选段) -->
<view class="completion-tip" wx:if="{{completionTipValue}}">
<text class="completion-tip-value">{{completionTipValue}}</text>
<view class="completion-tip-risk" wx:if="{{completionTipRisk}}">
<text class="completion-tip-risk-tag">小贴士</text>
<text class="completion-tip-risk-text">{{completionTipRisk}}</text>
</view>
</view>
<view class="completion-actions">
<view class="completion-btn completion-btn--primary" bindtap="onTrainAgain">
<text>再来一次</text>
+50 -7
View File
@@ -474,7 +474,8 @@
display: flex;
align-items: baseline;
justify-content: center;
margin-bottom: 8rpx;
/* 8rpx 原间距 + 24rpx 原 completion-label 的 margin-bottom,删除标签后合并到这里 */
margin-bottom: 32rpx;
}
.completion-number {
@@ -499,12 +500,6 @@
margin-left: 8rpx;
}
.completion-label {
font-size: 26rpx;
color: var(--text-secondary);
margin-bottom: 24rpx;
}
.completion-overtime {
display: flex;
align-items: baseline;
@@ -552,6 +547,54 @@
font-weight: 500;
}
.completion-tip {
width: 100%;
box-sizing: border-box;
background: rgba(var(--primary-rgb), 0.08);
border-radius: 20rpx;
padding: 20rpx 24rpx;
margin-bottom: 28rpx;
animation: tipIn 0.4s ease 1.0s both;
}
@keyframes tipIn {
0% { opacity: 0; transform: translateY(12rpx); }
100% { opacity: 1; transform: translateY(0); }
}
.completion-tip-value {
display: block;
font-size: 26rpx;
line-height: 1.5;
color: var(--text);
font-weight: 500;
}
.completion-tip-risk {
display: flex;
align-items: flex-start;
gap: 8rpx;
margin-top: 10rpx;
}
.completion-tip-risk-tag {
flex-shrink: 0;
font-size: 22rpx;
line-height: 1.4;
color: var(--primary);
background: rgba(var(--primary-rgb), 0.14);
border-radius: 8rpx;
padding: 2rpx 10rpx;
margin-top: 2rpx;
}
.completion-tip-risk-text {
flex: 1;
font-size: 24rpx;
line-height: 1.5;
color: var(--text-secondary);
}
.completion-actions {
display: flex;
gap: 20rpx;