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 .router import router
from fastapi import Depends, Path, Query, Security from fastapi import Depends, Path, Query, Security
from pydantic import BaseModel
from sqlmodel import col, select from sqlmodel import col, select
from sqlmodel.ext.asyncio.session import AsyncSession 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( @router.get(
"/rankings/{ruleset}/{type}", "/rankings/{ruleset}/{type}",
response_model=list[UserStatisticsResp], response_model=TopUsersResponse,
name="获取排行榜", name="获取用户排行榜",
description="获取在指定模式下的用户排行榜", description="获取在指定模式下的用户排行榜",
tags=["排行榜"], tags=["排行榜"],
) )
@@ -46,7 +106,9 @@ async def get_user_ranking(
.limit(50) .limit(50)
.offset(50 * (page - 1)) .offset(50 * (page - 1))
) )
return [ return TopUsersResponse(
await UserStatisticsResp.from_db(statistics, session, None) ranking=[
for statistics in statistics_list await UserStatisticsResp.from_db(statistics, session, None)
] for statistics in statistics_list
]
)