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" "github.com/topfans/backend/pkg/logger" pb "github.com/topfans/backend/pkg/proto/statistic" "go.uber.org/zap" ) // StatisticController 数据看板 HTTP controller(gateway → statisticService 7 RPC) type StatisticController struct { statisticService pb.StatisticService } // NewStatisticController 构造 func NewStatisticController(dubboClient *client.Client) (*StatisticController, error) { svc, err := pb.NewStatisticService(dubboClient) if err != nil { return nil, err } return &StatisticController{statisticService: svc}, nil } // parseStarID 解析 query 中的 star_id func parseStarID(c *gin.Context) (int64, bool) { v := c.Query("star_id") if v == "" { response.Error(c, http.StatusBadRequest, "star_id 是必填参数") return 0, false } n, err := strconv.ParseInt(v, 10, 64) if err != nil { response.Error(c, http.StatusBadRequest, "star_id 参数错误") return 0, false } return n, true } // buildCtx 构造带 user_id 透传的 ctx(Dubbo attachment) func buildCtx(c *gin.Context) context.Context { ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second) _ = cancel userID, _ := c.Get("user_id") if userID != nil { ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]interface{}{ "user_id": strconv.FormatInt(toInt64(userID), 10), }) } return ctx } func toInt64(v interface{}) int64 { switch x := v.(type) { case int64: return x case int: return int64(x) case string: n, _ := strconv.ParseInt(x, 10, 64) return n } return 0 } // ===== 1. 今日概览 ===== func (ctrl *StatisticController) GetTodayOverview(c *gin.Context) { starID, ok := parseStarID(c) if !ok { return } logger.Logger.Info("GetTodayOverview", zap.Int64("star_id", starID)) resp, err := ctrl.statisticService.GetTodayOverview(buildCtx(c), &pb.GetTodayOverviewRequest{StarId: starID}) if err != nil { logger.Logger.Error("GetTodayOverview RPC failed", zap.Error(err)) response.Error(c, http.StatusInternalServerError, "获取今日概览失败") return } response.Success(c, resp) } // ===== 2. 七日收益曲线 ===== func (ctrl *StatisticController) Get7DayIncomeCurve(c *gin.Context) { starID, ok := parseStarID(c) if !ok { return } resp, err := ctrl.statisticService.Get7DayIncomeCurve(buildCtx(c), &pb.Get7DayIncomeCurveRequest{StarId: starID}) if err != nil { response.Error(c, http.StatusInternalServerError, "获取七日收益曲线失败") return } response.Success(c, resp) } // ===== 3. 展出收益中心 ===== func (ctrl *StatisticController) GetExhibitionIncomeSummary(c *gin.Context) { starID, ok := parseStarID(c) if !ok { return } resp, err := ctrl.statisticService.GetExhibitionIncomeSummary(buildCtx(c), &pb.GetExhibitionIncomeSummaryRequest{StarId: starID}) if err != nil { response.Error(c, http.StatusInternalServerError, "获取展出收益中心失败") return } response.Success(c, resp) } // ===== 4. 点赞收益按等级 ===== func (ctrl *StatisticController) GetLikeIncomeByLevel(c *gin.Context) { starID, ok := parseStarID(c) if !ok { return } resp, err := ctrl.statisticService.GetLikeIncomeByLevel(buildCtx(c), &pb.GetLikeIncomeByLevelRequest{StarId: starID}) if err != nil { response.Error(c, http.StatusInternalServerError, "获取点赞等级收益失败") return } response.Success(c, resp) } // ===== 5. 藏品 TOP5 ===== func (ctrl *StatisticController) GetTopAssets(c *gin.Context) { starID, ok := parseStarID(c) if !ok { return } resp, err := ctrl.statisticService.GetTopAssetsByEarning(buildCtx(c), &pb.GetTopAssetsByEarningRequest{StarId: starID}) if err != nil { response.Error(c, http.StatusInternalServerError, "获取藏品 TOP5 失败") return } response.Success(c, resp) } // ===== 6. 藏品等级分布 ===== func (ctrl *StatisticController) GetLevelDistribution(c *gin.Context) { starID, ok := parseStarID(c) if !ok { return } resp, err := ctrl.statisticService.GetAssetLevelDistribution(buildCtx(c), &pb.GetAssetLevelDistributionRequest{StarId: starID}) if err != nil { response.Error(c, http.StatusInternalServerError, "获取等级分布失败") return } response.Success(c, resp) } // ===== 7. 升级进度 ===== func (ctrl *StatisticController) GetUpgradeProgress(c *gin.Context) { starID, ok := parseStarID(c) if !ok { return } resp, err := ctrl.statisticService.GetAssetUpgradeProgress(buildCtx(c), &pb.GetAssetUpgradeProgressRequest{StarId: starID}) if err != nil { response.Error(c, http.StatusInternalServerError, "获取升级进度失败") return } response.Success(c, resp) }