2026-05-12 19:34:47 +08:00

172 lines
5.1 KiB
Go

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 创建或更新第三方游戏平台配置;平台密钥后续走单独的密钥托管接口。
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)
}
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 ""
}