feat(leaderboard): 新增耐力榜(全局单次最久 top10) + 领奖台日期两行 + 顶部哲理文案

- 云函数支持 endurance 周期:遍历全部 records 取 max(duration) 及 bestDate
- 客户端新增耐力榜 tab(maxRank=10),未上榜时在底部 my-bar 显示最佳成绩+产生时间
- 领奖台底座(耐力榜)单次日期拆成「日期+时间」两行,统一三阶底座高度修复第3名贴顶
- 领奖台顶部新增哲理文案,配置进 config.js(leaderboardPodiumSlogan),斜体金句卡片样式
This commit is contained in:
2026-07-31 09:30:30 +08:00
parent fca3e32d04
commit 1589d6c387
5 changed files with 174 additions and 30 deletions
+35 -2
View File
@@ -149,6 +149,37 @@ const _buildFromScan = async (latestByOpenid, period, limit, myOpenid) => {
for (const doc of latestByOpenid.values()) {
const openid = doc._openid || 'unknown'
const records = doc.records || {}
if (period === 'endurance') {
// 全局单次最久:遍历该用户全部月份的 records,取 max(duration) 那条,
// 并记下其 r.date 作为"产生时间"。不做日/月/年过滤、不累加。
let bestDuration = 0
let bestDate = ''
let total = 0
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
total++
const dur = Number(r.duration) || 0
if (dur > bestDuration) { bestDuration = dur; bestDate = r.date }
}
}
if (bestDuration > 0) {
const profile = doc.profile || {}
userMap.set(openid, {
openid,
duration: bestDuration,
bestDate,
sessions: total,
nickname: profile.nickname || '',
avatarUrl: profile.avatarUrl || ''
})
}
continue
}
let duration = 0
let sessions = 0
@@ -208,6 +239,7 @@ const _buildFromScan = async (latestByOpenid, period, limit, myOpenid) => {
name: _displayName(item),
duration: item.duration,
sessions: item.sessions,
bestDate: item.bestDate || '',
avatarUrl: item.avatarUrl || ''
}))
@@ -231,6 +263,7 @@ const _buildFromScan = async (latestByOpenid, period, limit, myOpenid) => {
name: _displayName(myEntryRaw),
duration: myEntryRaw.duration,
sessions: myEntryRaw.sessions,
bestDate: myEntryRaw.bestDate || '',
avatarUrl: myEntryRaw.avatarUrl || ''
} : null
@@ -294,7 +327,7 @@ const _serveFromSnapshot = async (period, limit, myOpenid) => {
*/
const _rebuildSnapshots = async () => {
const latestByOpenid = await _fetchLatestByOpenid(true)
for (const p of ['day', 'month', 'year']) {
for (const p of ['day', 'month', 'year', 'endurance']) {
const result = await _buildFromScan(latestByOpenid, p, SNAPSHOT_TOP, null)
console.log('[leaderboard] rebuilt', p, 'rankedLen=', (result && result.ranked) ? result.ranked.length : 'undef')
await _persistSnapshot(p, result)
@@ -328,7 +361,7 @@ exports.main = async (event) => {
const { period, maxRank, force } = event || {}
const limit = Math.max(1, Math.min(parseInt(maxRank) || DEFAULT_MAX_RANK, 500))
if (!period) return { err: 'missing period' }
if (period !== 'day' && period !== 'month' && period !== 'year') return { err: 'invalid period' }
if (period !== 'day' && period !== 'month' && period !== 'year' && period !== 'endurance') return { err: 'invalid period' }
const myOpenid = cloud.getWXContext().OPENID