- 一张榜两个开关:本班 / 本年级 / 全服 × 这周 / 这学期 / 全部,默认本班 · 这学期。 原来最大那张全服 Top100 里,这学期在用的 25 级学生一个都进不去 - 做对一样多的不再按「提交少的在前」排,改成先做到的在前;名次旁边写比周一升降了几名 - 「你」那张卡:第几名、再做对几道上领奖台,要追的人早你几秒、追你的人晚你几秒 - 本年级 / 全服只列前面一段和你附近一段,中间折起来,点开再看 - 班级对抗按人均做对比,另有我和对手的名次走势、这周本班、每周冠军 - 老师不上榜,选班看;每行「⋯」能把怀疑抄代码的学生设成不计入排名(新增 user.rank_hidden_at, 首页周榜同样不算他),随时能恢复 - 去掉全服 Top10、日活两张图、在线人数和班级详情弹框里的统计词,以及它们背后的旧接口 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
新增匿名可读的 GET /api/site/online,一条 ZCOUNT 让 Redis 自己数, 不拉成员、也不写(清理过期成员留给后台列表,匿名接口不带写操作)。 榜单页进页面拉一次,为 0 时不显示。 /rankings/users 的 isOnline 是三态:null 表示「这个调用方不该知道」, 只有老师及以上拿到 true/false。写成普通 boolean 的话学生看到的 false 和真的离线分不开,等于默认把每个人的在线状态摊给全校同学看。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017xu912Rv5JUUuy6MqMcQW2
在线状态库里没有、会话也判定不了 —— session 的 TTL 是 7 天且每次请求续期, 「有会话」只说明这人一周内来过。新开一个 Redis sorted set(auth/presence.ts) 记最后活动时间,5 分钟内有活动算在线。 写入全搭在已有的 pipeline 上,不多一趟往返:登录、每个带鉴权请求的续期、 以及 touchSession —— 只挂着 WebSocket 不发请求的人靠最后这条,sweepSessions 每 60 秒一轮,所以窗口取 5 分钟,明显大于那个间隔。登出、改密码、禁用账号 会立刻把人摘掉;过期成员在后台读列表时顺手清理(整个 key 不能设 TTL, ZADD 不重置 key 的 TTL,到期会把还在线的人一起抹掉)。 排序 orderBy=-online 先捞在线 id,SQL 里 case when 分两档,档内继续按 最近登录排;没人在线时那个 case 恒等于 1,直接省掉。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017xu912Rv5JUUuy6MqMcQW2