Skip to content

排行榜页面 ​

这个 Recipe 适合游戏结算页、挑战榜、耗时榜等场景:公开榜单可以直接读取;当前用户记录和成绩提交由平台代管能力自行校验 Host 登录状态。

基础封装 ​

ts
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'

const LEADERBOARD_KEY = 'cube_run_total'

export async function loadLeaderboard(cursor?: string) {
  const page = await hbSDK.cloud.leaderboard.getList({
    key: LEADERBOARD_KEY,
    limit: 20,
    cursor,
  })

  let current
  try {
    current = await hbSDK.cloud.leaderboard.getCurrentUserEntry({
      key: LEADERBOARD_KEY,
    })
  } catch (error) {
    // 未登录(401)与平台限流(RATE_LIMITED / RATE_LIMITED_BY_RUNTIME)都不应阻断公开列表。
    if (
      !(error instanceof HbMiniProgramSDKError) ||
      !['UNAUTHORIZED', 'RATE_LIMITED', 'RATE_LIMITED_BY_RUNTIME'].includes(error.code)
    ) {
      throw error
    }
  }

  return {
    entries: page.entries,
    current,
    cursor: page.cursor,
    hasMore: page.hasMore,
  }
}

export async function submitScore(score: number) {
  try {
    return await hbSDK.cloud.leaderboard.submit({
      key: LEADERBOARD_KEY,
      score,
    })
  } catch (error) {
    if (error instanceof HbMiniProgramSDKError) {
      console.log('[leaderboard]', error.code, error.message)
      return undefined
    }

    throw error
  }
}

提交后刷新 ​

ts
async function handleGameFinished(totalScore: number) {
  const entry = await submitScore(totalScore)
  if (!entry) return

  console.log(entry.ranked ? `当前排名:${entry.rank}` : '已保存成绩')
  renderLeaderboard(await loadLeaderboard())
}

注意事项 ​

  • 不要仅为探测登录态而预先调用用户资料 API。submit() 和当前用户记录读取会在未登录时返回 UNAUTHORIZED,业务按正常错误提示处理。
  • 遇到 RATE_LIMITED(上游 403/429 或 Runtime 熔断窗口)或 RATE_LIMITED_BY_RUNTIME(Runtime 本地配额 / 循环检测拒绝)时不要立即重试:按 error.data.retryAfterMs(可能缺失)退避,或直接展示「稍后再试」;反复重试会把用户 IP 打成被网关封禁。
  • auth.login() 是获取后端授权码的入口,不依赖 network,也不是排行榜平台代管身份的必需前置步骤。
  • 公开榜单读取不要求登录;当前用户记录失败不应阻断公开列表展示。
  • cursor 只能原样传回下一页请求。
  • ranked: false 时不要把 rank: 0 展示成真实排名。

附带用户展示资料 ​

需要展示昵称、头像时,额外声明 userInfo 权限(见权限声明),读取资料并随成绩写入 extra:

ts
export async function submitScoreWithProfile(score: number) {
  const result = await hbSDK.user.getInfo()
  const profile = result.isHeyboxAppLoggedIn ? result.userInfo?.profile : null

  return hbSDK.cloud.leaderboard.submit({
    key: LEADERBOARD_KEY,
    score,
    extra: profile
      ? { nickname: profile.nickname, avatar: profile.avatar }
      : {},
  })
}

读取榜单时,从 entry.extra.nickname、entry.extra.avatar 取出展示,缺失时使用默认值。 用户资料是可选展示信息,未取得时可以只提交分数。资料是随成绩保存的快照,提交相同或更差的分数也不会更新 extra。

对应 API:hbSDK.cloud.leaderboard、LeaderboardEntry。