package gamemanagement import ( "strconv" "strings" "hyapp-admin-server/internal/integration/gameclient" "hyapp-admin-server/internal/modules/shared" "hyapp-admin-server/internal/response" gamev1 "hyapp.local/api/proto/game/v1" "github.com/gin-gonic/gin" ) type Handler struct { game gameclient.Client audit shared.OperationLogger } func New(game gameclient.Client, audit shared.OperationLogger) *Handler { return &Handler{game: game, audit: audit} } // ListPlatforms 返回后台游戏平台筛选项和平台配置列表。 func (h *Handler) ListPlatforms(c *gin.Context) { resp, err := h.game.ListPlatforms(c.Request.Context(), &gamev1.ListPlatformsRequest{ Meta: requestMeta(c), Status: strings.TrimSpace(c.Query("status")), }) if err != nil { response.ServerError(c, "获取游戏平台失败") return } items := make([]platformDTO, 0, len(resp.GetPlatforms())) for _, item := range resp.GetPlatforms() { items = append(items, platformFromProto(item)) } response.OK(c, gin.H{"items": items, "serverTimeMs": resp.GetServerTimeMs()}) } func (h *Handler) CreatePlatform(c *gin.Context) { h.upsertPlatform(c, "") } func (h *Handler) UpdatePlatform(c *gin.Context) { h.upsertPlatform(c, strings.TrimSpace(c.Param("platform_code"))) } // upsertPlatform 创建或更新第三方游戏平台配置;callbackSecret 非空时才会轮换厂商密钥。 func (h *Handler) upsertPlatform(c *gin.Context, platformCode string) { var req platformRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "游戏平台参数不正确") return } resp, err := h.game.UpsertPlatform(c.Request.Context(), &gamev1.UpsertPlatformRequest{ Meta: requestMeta(c), Platform: req.toProto(platformCode), }) if err != nil { response.BadRequest(c, err.Error()) return } item := platformFromProto(resp.GetPlatform()) h.auditLog(c, "upsert-game-platform", "game_platforms", item.PlatformCode, item.PlatformName) response.OK(c, item) } // ListCatalog 返回游戏目录;当前 game-service 使用 cursor 扩展点,后台先按 pageSize 截断。 func (h *Handler) ListCatalog(c *gin.Context) { pageSize := int32(parsePositiveInt(firstQuery(c, "pageSize", "page_size"), 50)) resp, err := h.game.ListCatalog(c.Request.Context(), &gamev1.ListCatalogRequest{ Meta: requestMeta(c), PlatformCode: strings.TrimSpace(firstQuery(c, "platformCode", "platform_code")), Status: strings.TrimSpace(c.Query("status")), PageSize: pageSize, Cursor: strings.TrimSpace(c.Query("cursor")), }) if err != nil { response.ServerError(c, "获取游戏列表失败") return } items := make([]catalogDTO, 0, len(resp.GetGames())) for _, item := range resp.GetGames() { items = append(items, catalogFromProto(item)) } response.OK(c, gin.H{ "items": items, "nextCursor": resp.GetNextCursor(), "pageSize": pageSize, "serverTimeMs": resp.GetServerTimeMs(), }) } func (h *Handler) CreateCatalog(c *gin.Context) { h.upsertCatalog(c, "") } func (h *Handler) UpdateCatalog(c *gin.Context) { h.upsertCatalog(c, strings.TrimSpace(c.Param("game_id"))) } // upsertCatalog 创建或更新内部 game_id 到 provider_game_id 的映射。 func (h *Handler) upsertCatalog(c *gin.Context, gameID string) { var req catalogRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "游戏参数不正确") return } resp, err := h.game.UpsertCatalog(c.Request.Context(), &gamev1.UpsertCatalogRequest{ Meta: requestMeta(c), Game: req.toProto(gameID), }) if err != nil { response.BadRequest(c, err.Error()) return } item := catalogFromProto(resp.GetGame()) h.auditLog(c, "upsert-game-catalog", "game_catalog", item.GameID, item.GameName) response.OK(c, item) } // SetGameStatus 只处理 active/maintenance/disabled 状态,不删除历史订单关联的游戏目录。 func (h *Handler) SetGameStatus(c *gin.Context) { gameID := strings.TrimSpace(c.Param("game_id")) if gameID == "" { response.BadRequest(c, "游戏 ID 参数不正确") return } var req statusRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "状态参数不正确") return } resp, err := h.game.SetGameStatus(c.Request.Context(), &gamev1.SetGameStatusRequest{ Meta: requestMeta(c), GameId: gameID, Status: strings.TrimSpace(req.Status), }) if err != nil { response.BadRequest(c, err.Error()) return } item := catalogFromProto(resp.GetGame()) h.auditLog(c, "set-game-status", "game_catalog", item.GameID, item.Status) response.OK(c, item) } // DeleteCatalog 删除后台游戏目录记录,同时由 game-service 清理展示规则;历史订单和启动会话保留用于审计。 func (h *Handler) DeleteCatalog(c *gin.Context) { gameID := strings.TrimSpace(c.Param("game_id")) if gameID == "" { response.BadRequest(c, "游戏 ID 参数不正确") return } if _, err := h.game.DeleteCatalog(c.Request.Context(), &gamev1.DeleteCatalogRequest{ Meta: requestMeta(c), GameId: gameID, }); err != nil { response.BadRequest(c, err.Error()) return } h.auditLog(c, "delete-game-catalog", "game_catalog", gameID, "deleted") response.OK(c, gin.H{"gameId": gameID}) } func (h *Handler) auditLog(c *gin.Context, action string, resource string, resourceID string, detail string) { shared.OperationLogWithResourceID(c, h.audit, action, resource, resourceID, "success", detail) } func parsePositiveInt(raw string, fallback int) int { value, err := strconv.Atoi(strings.TrimSpace(raw)) if err != nil || value <= 0 { return fallback } if value > 200 { return 200 } return value } func firstQuery(c *gin.Context, keys ...string) string { for _, key := range keys { if value := c.Query(key); value != "" { return value } } return "" }