feat(leaderboard): 新增耐力榜(全局单次最久 top10) + 领奖台日期两行 + 顶部哲理文案
- 云函数支持 endurance 周期:遍历全部 records 取 max(duration) 及 bestDate - 客户端新增耐力榜 tab(maxRank=10),未上榜时在底部 my-bar 显示最佳成绩+产生时间 - 领奖台底座(耐力榜)单次日期拆成「日期+时间」两行,统一三阶底座高度修复第3名贴顶 - 领奖台顶部新增哲理文案,配置进 config.js(leaderboardPodiumSlogan),斜体金句卡片样式
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user