feat(ui): 排行榜与首页打卡卡片多项优化

排行榜性能:
- 客户端乐观缓存:进页面/切周期秒显旧数据,后台静默刷新,消除 2-3s 空白
- 云函数实例缓存 TTL 60s -> 5min,降低全表扫描频率

排行榜 UI:
- 空状态重设计:奖杯光环插画(径向光晕 + 闪光漂浮)
- 领奖台 slot 撑满对齐列表、金银铜底座配色、角标与昵称间距修复、底线对齐

首页打卡卡片:
- 火焰光晕脉动 + 72rpx 大数字 + 分段进度格子
- 计划 >10 天时进度退化为里程碑连续条

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-27 17:28:53 +08:00
parent 4b5f195a18
commit e2becc24aa
9 changed files with 329 additions and 121 deletions
+40 -1
View File
@@ -418,6 +418,43 @@ const getTodayRecord = () => {
return hasRecord ? { date: today, duration: totalDuration } : null
}
/**
* Leaderboard display cache, keyed by period ('day' | 'month' | 'year').
*
* Why: building the board requires a full-collection scan in the cloud
* function (cursor-paginated 100/page, serial), which takes 2-3s when
* the function's in-instance cache is cold. This client cache lets the
* page paint the last-rendered result instantly on re-entry / period
* switch while the cloud refreshes in the background.
*
* Freshness: entries older than LB_CACHE_MAX_AGE are treated as misses -
* the cached avatarUrl is a cloud:// temp URL (~2h TTL) and stale links
* render as broken images. 30min stays safely inside that window while
* still covering the common "switch tab / switch period" re-entry case.
*/
const LEADERBOARD_CACHE_KEY = 'leaderboard_cache'
const LB_CACHE_MAX_AGE = 30 * 60 * 1000
const getLeaderboardCache = (period) => {
if (!period) return null
try {
const all = wx.getStorageSync(LEADERBOARD_CACHE_KEY) || {}
const entry = all[period]
if (!entry) return null
if (Date.now() - (entry.cachedAt || 0) > LB_CACHE_MAX_AGE) return null
return entry
} catch (e) { return null }
}
const setLeaderboardCache = (period, payload) => {
if (!period || !payload) return
try {
const all = wx.getStorageSync(LEADERBOARD_CACHE_KEY) || {}
all[period] = { ...payload, cachedAt: Date.now() }
wx.setStorageSync(LEADERBOARD_CACHE_KEY, all)
} catch (e) {}
}
module.exports = {
getRecords,
saveRecord,
@@ -439,5 +476,7 @@ module.exports = {
_markLocalChanged,
getToday,
getDateOffset,
getTodayRecord
getTodayRecord,
getLeaderboardCache,
setLeaderboardCache
}