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
+17
View File
@@ -150,6 +150,19 @@ const _buildFromScan = async (latestByOpenid, period, limit, myOpenid) => {
const openid = doc._openid || 'unknown'
const records = doc.records || {}
// 勋章等级 = 累计去重训练日(遍历该用户全部记录,与榜单周期无关)。
// 客户端据此映射最新解锁勋章,让全榜用户都能看到彼此的勋章。
const trainedDays = new Set()
for (const monthKey of Object.keys(records)) {
const arr = records[monthKey]
if (!Array.isArray(arr)) continue
for (const r of arr) {
if (!r || typeof r.date !== 'string') continue
trainedDays.add(r.date.substring(0, 10))
}
}
const totalDays = trainedDays.size
if (period === 'endurance') {
// 全局单次最久:遍历该用户全部月份的 records,取 max(duration) 那条,
// 并记下其 r.date 作为"产生时间"。不做日/月/年过滤、不累加。
@@ -173,6 +186,7 @@ const _buildFromScan = async (latestByOpenid, period, limit, myOpenid) => {
duration: bestDuration,
bestDate,
sessions: total,
totalDays,
nickname: profile.nickname || '',
avatarUrl: profile.avatarUrl || ''
})
@@ -210,6 +224,7 @@ const _buildFromScan = async (latestByOpenid, period, limit, myOpenid) => {
openid,
duration,
sessions,
totalDays,
nickname: profile.nickname || '',
avatarUrl: profile.avatarUrl || ''
})
@@ -240,6 +255,7 @@ const _buildFromScan = async (latestByOpenid, period, limit, myOpenid) => {
duration: item.duration,
sessions: item.sessions,
bestDate: item.bestDate || '',
totalDays: item.totalDays || 0,
avatarUrl: item.avatarUrl || ''
}))
@@ -264,6 +280,7 @@ const _buildFromScan = async (latestByOpenid, period, limit, myOpenid) => {
duration: myEntryRaw.duration,
sessions: myEntryRaw.sessions,
bestDate: myEntryRaw.bestDate || '',
totalDays: myEntryRaw.totalDays || 0,
avatarUrl: myEntryRaw.avatarUrl || ''
} : null