feat(ranking): support country leaderboard

This commit is contained in:
MingxuanGame
2025-08-14 14:55:51 +00:00
parent c38ab7fd6d
commit 134f3335c5

View File

@@ -11,14 +11,74 @@ from app.models.score import GameMode
from .router import router
from fastapi import Depends, Path, Query, Security
from pydantic import BaseModel
from sqlmodel import col, select
from sqlmodel.ext.asyncio.session import AsyncSession
class CountryStatistics(BaseModel):
country_code: str
active_users: int
play_count: int
ranked_score: int
performance: int
class CountryResponse(BaseModel):
ranking: list[CountryStatistics]
@router.get(
"/rankings/{ruleset}/country",
response_model=CountryResponse,
name="获取地区排行榜",
description="获取在指定模式下的地区排行榜",
tags=["排行榜"],
)
async def get_country_ranking(
ruleset: GameMode = Path(..., description="指定 ruleset"),
page: int = Query(1, ge=1, description="页码"), # TODO
current_user: User = Security(get_current_user, scopes=["public"]),
session: AsyncSession = Depends(get_db),
):
response = CountryResponse(ranking=[])
countries = (await session.exec(select(User.country_code).distinct())).all()
for country in countries:
statistics = (
await session.exec(
select(UserStatistics).where(
UserStatistics.mode == ruleset,
col(UserStatistics.user).has(country_code=country),
)
)
).all()
pp = 0
country_stats = CountryStatistics(
country_code=country,
active_users=0,
play_count=0,
ranked_score=0,
performance=0,
)
for stat in statistics:
country_stats.active_users += 1
country_stats.play_count += stat.play_count
country_stats.ranked_score += stat.ranked_score
pp += stat.pp
country_stats.performance = round(pp)
response.ranking.append(country_stats)
response.ranking.sort(key=lambda x: x.performance, reverse=True)
return response
class TopUsersResponse(BaseModel):
ranking: list[UserStatisticsResp]
@router.get(
"/rankings/{ruleset}/{type}",
response_model=list[UserStatisticsResp],
name="获取排行榜",
response_model=TopUsersResponse,
name="获取用户排行榜",
description="获取在指定模式下的用户排行榜",
tags=["排行榜"],
)
@@ -46,7 +106,9 @@ async def get_user_ranking(
.limit(50)
.offset(50 * (page - 1))
)
return [
await UserStatisticsResp.from_db(statistics, session, None)
for statistics in statistics_list
]
return TopUsersResponse(
ranking=[
await UserStatisticsResp.from_db(statistics, session, None)
for statistics in statistics_list
]
)