From 45d79ed366d8460d5f4f9ac9d1e50d645642a35e Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sat, 10 Oct 2026 10:45:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8E=92=E5=90=8D):=20=E5=85=A8=E6=9C=8D?= =?UTF-8?q?=20100=20=E5=90=8D=E4=BB=A5=E5=A4=96=E4=B8=8D=E6=8A=A5=E5=85=B7?= =?UTF-8?q?=E4=BD=93=E5=90=8D=E6=AC=A1=EF=BC=8C=E5=86=99=E3=80=8C100=20?= =?UTF-8?q?=E5=90=8D=E4=BB=A5=E5=A4=96=E3=80=8D=E5=B9=B6=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E5=86=8D=E5=81=9A=E5=AF=B9=E5=87=A0=E9=81=93=E8=BF=9B=E5=89=8D?= =?UTF-8?q?=20100=EF=BC=9B=E8=B5=9B=E9=81=93=E6=AF=8F=E8=A1=8C=E5=8A=A0?= =?UTF-8?q?=E9=AB=98=EF=BC=8C=E6=9D=A1=E4=B8=8D=E5=86=8D=E8=A2=AB=E6=8C=A4?= =?UTF-8?q?=E6=88=90=E4=B8=80=E5=B0=8F=E6=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 全服排在 100 名以外:「你」卡和下面的小名次写「100 名以外」,不给前一名、后一名和名次走势, 改成「再做对 N 道就进前 100」;名单上没有你这一行,图例和副标题也不再提「你」 - 赛道每行从 18px 加到 28px,头像、字、条都大一号(不必刻意塞进机房一屏); 「前一名 / 后一名 / 进步最大」挂到条的末端,不再单占一列把条挤短;领奖台台阶恢复原来的高度 Co-Authored-By: Claude Opus 5.5 --- apps/api/src/routes/ranking.ts | 10 ++- apps/web/src/oj/rank/components/RankMe.vue | 27 ++++++- .../web/src/oj/rank/components/RankPodium.vue | 5 +- apps/web/src/oj/rank/components/RankTrack.vue | 73 +++++++++++++------ apps/web/src/oj/rank/list.vue | 14 +++- packages/contract/src/ranking.ts | 6 ++ 6 files changed, 98 insertions(+), 37 deletions(-) diff --git a/apps/api/src/routes/ranking.ts b/apps/api/src/routes/ranking.ts index 09bef46..76655d7 100644 --- a/apps/api/src/routes/ranking.ts +++ b/apps/api/src/routes/ranking.ts @@ -202,8 +202,11 @@ rankingRoutes.get("/rankings/board", optionalAuth, async (c) => { ) } + // 全服 100 名以外:不报具体名次,前后一名、走势都不给,只给第 100 名算还差几道 + const beyond = !!(cap && me && me.rank > cap) + let trend: RankBoard["trend"] = null - if (me && period.data !== "week") { + if (me && !beyond && period.data !== "week") { const thisWeek = Date.parse(weekStart()) const points = Array.from( { length: TREND_WEEKS }, @@ -237,9 +240,10 @@ rankingRoutes.get("/rankings/board", optionalAuth, async (c) => { rows: picked.map((row) => rowOf(row)!), complete: picked.length === listable.length, cap, + lastListed: beyond ? rowOf(listable.at(-1)) : null, me: rowOf(me), - ahead: rowOf(meIndex > 0 ? now[meIndex - 1] : undefined), - behind: rowOf(meIndex >= 0 ? now[meIndex + 1] : undefined), + ahead: beyond ? null : rowOf(meIndex > 0 ? now[meIndex - 1] : undefined), + behind: beyond ? null : rowOf(meIndex >= 0 ? now[meIndex + 1] : undefined), trend, hidden: !!mine?.rankHiddenAt, hiddenUsers: hiddenUsers.map((row): SampleUser => sampleUser(row, null)), diff --git a/apps/web/src/oj/rank/components/RankMe.vue b/apps/web/src/oj/rank/components/RankMe.vue index 2f26836..9a7267f 100644 --- a/apps/web/src/oj/rank/components/RankMe.vue +++ b/apps/web/src/oj/rank/components/RankMe.vue @@ -11,6 +11,8 @@ export interface MiniRank { label: string rank: number | null total: number | null + /** 那张榜最多列到第几名(全服 100);名次在这之外就只写「100 名以外」 */ + cap?: number | null go: () => void } @@ -31,6 +33,10 @@ const props = defineProps<{ /** 领奖台第 3 名(我不在台上时用来算「再做对几道上领奖台」) */ third: RankRow | null total: number + /** 名单最多列到第几名(全服 100)。我在这之外只写「100 名以外」,不报具体名次 */ + cap?: number | null + /** 我在 cap 名以外时,名单上最后那一位:算「再做对几道进前 100」 */ + lastListed?: RankRow | null label: string minis: MiniRank[] /** 手机:前后一名的说明换到名字下面一行,别被截断 */ @@ -70,8 +76,12 @@ async function saveMood() { } } +const beyond = computed(() => !!props.cap && props.me.rank > props.cap) + const headline = computed(() => { const { me, ahead, third } = props + if (beyond.value) + return props.lastListed ? `再做对 ${toPass(me, props.lastListed)} 道就进前 ${props.cap}` : "" if (me.rank === 1) return "你是第一名" if (me.rank <= 3 && ahead) return `你在领奖台上 · 再做对 ${toPass(me, ahead)} 道就是第 ${ahead.rank} 名` @@ -105,9 +115,12 @@ function threatNote(me: RankRow, behind: RankRow) {
{{ label }}
- 第{{ me.rank }}名 - / {{ total }} + {{ cap }} 名以外 + ↑{{ me.change }} ↓{{ -me.change! }}
@@ -219,7 +232,8 @@ function threatNote(me: RankRow, behind: RankRow) {