package controller import ( "context" "net/http" "strconv" "time" "dubbo.apache.org/dubbo-go/v3/client" "dubbo.apache.org/dubbo-go/v3/common/constant" "github.com/gin-gonic/gin" "github.com/topfans/backend/gateway/pkg/response" pbRanking "github.com/topfans/backend/pkg/proto/ranking" pbCommon "github.com/topfans/backend/pkg/proto/common" "github.com/topfans/backend/pkg/logger" "go.uber.org/zap" ) // RankingController 排行榜控制器 type RankingController struct { rankingService pbRanking.RankingService } // NewRankingController 创建排行榜控制器 func NewRankingController(dubboClient *client.Client) (*RankingController, error) { // 创建 RankingService 客户端 rankingService, err := pbRanking.NewRankingService(dubboClient) if err != nil { return nil, err } return &RankingController{ rankingService: rankingService, }, nil } // GetHotRanking 获取热度排行榜 // @Summary 获取热度排行榜 // @Description 获取热度排行榜,支持按维度筛选(displaying:展示中, month:本月, total:全部) // @Tags rankings // @Accept json // @Produce json // @Security BearerAuth // @Param dimension query string false "统计维度: displaying(展示中), month(本月), total(全部),默认total" // @Param star_id query int64 false "粉丝身份ID,不传则使用当前身份" // @Param page query int false "页码,默认1" // @Param page_size query int false "每页数量,默认10" // @Success 200 {object} response.Response // @Router /api/v1/rankings/hot [get] func (ctrl *RankingController) GetHotRanking(c *gin.Context) { // 从上下文获取用户信息 userID, exists := c.Get("user_id") if !exists { response.Error(c, http.StatusUnauthorized, "未授权") return } starID, exists := c.Get("star_id") if !exists { response.Error(c, http.StatusUnauthorized, "未授权") return } // 解析查询参数 dimension := c.DefaultQuery("dimension", "total") starIDParam := c.Query("star_id") var starIDParamInt int64 if starIDParam != "" { var err error starIDParamInt, err = strconv.ParseInt(starIDParam, 10, 64) if err != nil { response.Error(c, http.StatusBadRequest, "star_id 参数错误") return } } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10")) // 如果传了 star_id 参数,使用传入的值;否则使用当前用户的 star_id reqStarID := starID.(int64) if starIDParamInt > 0 { reqStarID = starIDParamInt } logger.Logger.Info("GetHotRanking request", zap.Int64("user_id", userID.(int64)), zap.Int64("star_id", reqStarID), zap.String("dimension", dimension), zap.Int("page", page), zap.Int("page_size", pageSize), ) // 设置上下文 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]interface{}{ "user_id": strconv.FormatInt(userID.(int64), 10), "star_id": strconv.FormatInt(reqStarID, 10), }) // 调用 RPC resp, err := ctrl.rankingService.GetHotRanking(ctx, &pbRanking.GetRankingRequest{ Dimension: dimension, StarId: reqStarID, Page: int32(page), PageSize: int32(pageSize), UserId: userID.(int64), }) if err != nil { logger.Logger.Error("GetHotRanking RPC failed", zap.Error(err), ) response.Error(c, http.StatusInternalServerError, "获取排行榜失败") return } if resp.Base.Code != pbCommon.StatusCode_STATUS_OK { response.ErrorWithCode(c, int(resp.Base.Code), resp.Base.Message) return } // 转换响应 data := convertRankingResponse(resp) response.Success(c, data) } // GetOriginalRanking 获取自制排行榜 // @Summary 获取自制排行榜 // @Description 获取自制藏品排行榜,支持按维度筛选(displaying:展示中, month:本月, total:全部) // @Tags rankings // @Accept json // @Produce json // @Security BearerAuth // @Param dimension query string false "统计维度: displaying(展示中), month(本月), total(全部),默认total" // @Param star_id query int64 false "粉丝身份ID,不传则使用当前身份" // @Param page query int false "页码,默认1" // @Param page_size query int false "每页数量,默认10" // @Success 200 {object} response.Response // @Router /api/v1/rankings/original [get] func (ctrl *RankingController) GetOriginalRanking(c *gin.Context) { // 从上下文获取用户信息 userID, exists := c.Get("user_id") if !exists { response.Error(c, http.StatusUnauthorized, "未授权") return } starID, exists := c.Get("star_id") if !exists { response.Error(c, http.StatusUnauthorized, "未授权") return } // 解析查询参数 dimension := c.DefaultQuery("dimension", "total") starIDParam := c.Query("star_id") var starIDParamInt int64 if starIDParam != "" { var err error starIDParamInt, err = strconv.ParseInt(starIDParam, 10, 64) if err != nil { response.Error(c, http.StatusBadRequest, "star_id 参数错误") return } } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10")) // 如果传了 star_id 参数,使用传入的值;否则使用当前用户的 star_id reqStarID := starID.(int64) if starIDParamInt > 0 { reqStarID = starIDParamInt } logger.Logger.Info("GetOriginalRanking request", zap.Int64("user_id", userID.(int64)), zap.Int64("star_id", reqStarID), zap.String("dimension", dimension), zap.Int("page", page), zap.Int("page_size", pageSize), ) // 设置上下文 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]interface{}{ "user_id": strconv.FormatInt(userID.(int64), 10), "star_id": strconv.FormatInt(reqStarID, 10), }) // 调用 RPC resp, err := ctrl.rankingService.GetOriginalRanking(ctx, &pbRanking.GetRankingRequest{ Dimension: dimension, StarId: reqStarID, Page: int32(page), PageSize: int32(pageSize), UserId: userID.(int64), }) if err != nil { logger.Logger.Error("GetOriginalRanking RPC failed", zap.Error(err), ) response.Error(c, http.StatusInternalServerError, "获取自制排行榜失败") return } if resp.Base.Code != pbCommon.StatusCode_STATUS_OK { response.ErrorWithCode(c, int(resp.Base.Code), resp.Base.Message) return } // 转换响应 data := convertRankingResponse(resp) response.Success(c, data) } // convertRankingResponse 转换排行榜响应 func convertRankingResponse(resp *pbRanking.GetRankingResponse) map[string]interface{} { // 转换 items items := make([]map[string]interface{}, 0, len(resp.Items)) for _, item := range resp.Items { items = append(items, map[string]interface{}{ "rank": item.Rank, "asset_id": item.AssetId, "asset_name": item.AssetName, "cover_url": item.CoverUrl, "owner_uid": item.OwnerUid, "owner_nickname": item.OwnerNickname, "owner_avatar": item.OwnerAvatar, "like_count": item.LikeCount, "is_original": item.IsOriginal, }) } // 转换 my_ranking var myRanking map[string]interface{} if resp.MyRanking != nil { myRanking = map[string]interface{}{ "rank": resp.MyRanking.Rank, "asset_id": resp.MyRanking.AssetId, "asset_name": resp.MyRanking.AssetName, "cover_url": resp.MyRanking.CoverUrl, "like_count": resp.MyRanking.LikeCount, "status": resp.MyRanking.Status, "diff_to_rank": resp.MyRanking.DiffToRank, "owner_nickname": resp.MyRanking.OwnerNickname, "owner_avatar": resp.MyRanking.OwnerAvatar, } } return map[string]interface{}{ "my_ranking": myRanking, "items": items, "page": resp.Page, "page_size": resp.PageSize, "total": resp.Total, } }