feat: 新增排行榜模块

- 新增 leaderboard 服务与 handler、前端排行榜页面
- 路由与首页入口适配
This commit is contained in:
2026-09-25 18:28:12 +08:00
parent 4ae57d9392
commit cab8230803
9 changed files with 1112 additions and 2 deletions

View File

@@ -0,0 +1,71 @@
package handler
import (
"net/http"
"strconv"
"github.com/freefire/jiang13-bbs/service"
"github.com/gin-gonic/gin"
)
// 榜单参数白名单
var (
lbPeriods = map[string]bool{service.PeriodWeek: true, service.PeriodMonth: true, service.PeriodAll: true}
lbMetrics = map[string]bool{service.MetricAll: true, service.MetricPost: true,
service.MetricComment: true, service.MetricLike: true, service.MetricAnswer: true}
)
// lbParams 解析并校验 period/metric,非法值回退默认并标记 400
func lbParams(c *gin.Context) (period, metric string, bad bool) {
period = c.DefaultQuery("period", service.PeriodAll)
metric = c.DefaultQuery("metric", service.MetricAll)
if !lbPeriods[period] || !lbMetrics[metric] {
return "", "", true
}
return period, metric, false
}
// Leaderboard 用户贡献榜:period=week|month|all × metric=all|post|comment|like|answer(公开接口)
func (h *Handlers) Leaderboard(c *gin.Context) {
period, metric, bad := lbParams(c)
if bad {
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的榜单参数"})
return
}
limit := 50
if v := c.Query("limit"); v != "" {
if n, err := strconv.Atoi(v); err == nil && n > 0 {
limit = n
}
}
if limit > 100 {
limit = 100
}
res, err := h.LeaderboardSvc.Board(period, metric, limit)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取排行榜失败"})
return
}
c.JSON(http.StatusOK, res)
}
// LeaderboardMe 当前用户在指定榜单的排名(可选登录;游客返回 me:null)
func (h *Handlers) LeaderboardMe(c *gin.Context) {
period, metric, bad := lbParams(c)
if bad {
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的榜单参数"})
return
}
if v, ok := c.Get("user"); ok {
if claims, ok := v.(*service.UserClaims); ok && claims.ID > 0 {
res, err := h.LeaderboardSvc.MyRank(period, metric, claims.ID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取排名失败"})
return
}
c.JSON(http.StatusOK, gin.H{"me": res})
return
}
}
c.JSON(http.StatusOK, gin.H{"me": nil})
}