feat: 新增排行榜模块
- 新增 leaderboard 服务与 handler、前端排行榜页面 - 路由与首页入口适配
This commit is contained in:
@@ -759,6 +759,79 @@ export async function fetchBoardSidebar(
|
||||
return res.json();
|
||||
}
|
||||
|
||||
/** 榜单周期:本周 | 本月 | 总榜 */
|
||||
export type LeaderboardPeriod = "week" | "month" | "all";
|
||||
/** 榜单维度:全部(综合)| 发帖最多 | 回复最多 | 获赞最多 | 最佳答案 */
|
||||
export type LeaderboardMetric = "all" | "post" | "comment" | "like" | "answer";
|
||||
|
||||
/** 排行榜单条(领奖台/列表通用;level 由后端按累计积分计算) */
|
||||
export interface LeaderboardEntry {
|
||||
rank: number;
|
||||
id: number;
|
||||
username: string;
|
||||
nickname: string;
|
||||
avatar: string;
|
||||
total_points: number;
|
||||
points: number;
|
||||
level: number;
|
||||
post_count: number;
|
||||
comment_count: number;
|
||||
like_count: number;
|
||||
answer_count: number;
|
||||
score: number;
|
||||
}
|
||||
|
||||
/** /api/leaderboard 响应 */
|
||||
export interface LeaderboardResponse {
|
||||
period: LeaderboardPeriod;
|
||||
metric: LeaderboardMetric;
|
||||
entries: LeaderboardEntry[];
|
||||
}
|
||||
|
||||
/** 我的排名(rank=0 未上榜;change 正=上升负=下降,has_change=false 表示无上一周期对比) */
|
||||
export interface LeaderboardMe {
|
||||
period: LeaderboardPeriod;
|
||||
metric: LeaderboardMetric;
|
||||
rank: number;
|
||||
total: number;
|
||||
score: number;
|
||||
change: number;
|
||||
has_change: boolean;
|
||||
}
|
||||
|
||||
/** SSR 排行榜;失败时抛错,由页面降级为空榜 */
|
||||
export async function fetchLeaderboard(
|
||||
period: LeaderboardPeriod,
|
||||
metric: LeaderboardMetric,
|
||||
cookieHeader?: string
|
||||
): Promise<LeaderboardResponse> {
|
||||
const res = await fetch(
|
||||
`${API_BASE}/api/leaderboard?period=${period}&metric=${metric}`,
|
||||
ssrInit(cookieHeaders(cookieHeader))
|
||||
);
|
||||
if (!res.ok) throw new Error("获取排行榜失败");
|
||||
return res.json();
|
||||
}
|
||||
|
||||
/** SSR 我的排名;游客/失败返回 null(不抛错) */
|
||||
export async function fetchMyRank(
|
||||
period: LeaderboardPeriod,
|
||||
metric: LeaderboardMetric,
|
||||
cookieHeader?: string
|
||||
): Promise<LeaderboardMe | null> {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${API_BASE}/api/leaderboard/me?period=${period}&metric=${metric}`,
|
||||
ssrInit(cookieHeaders(cookieHeader))
|
||||
);
|
||||
if (!res.ok) return null;
|
||||
const data = (await res.json()) as { me: LeaderboardMe | null };
|
||||
return data.me ?? null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchBoards(): Promise<{ boards: BoardWithCount[] }> {
|
||||
const res = await fetch(`${API_BASE}/api/boards`, ssrInit());
|
||||
if (!res.ok) throw new Error("获取板块失败");
|
||||
|
||||
Reference in New Issue
Block a user