package admin import ( "net/http" "strconv" "bindbox-game/internal/code" "bindbox-game/internal/pkg/core" "bindbox-game/internal/pkg/validation" channelsvc "bindbox-game/internal/service/channel" ) type createChannelRequest struct { Name string `json:"name" binding:"required"` Code string `json:"code" binding:"required"` Type string `json:"type"` Remarks string `json:"remarks"` } type createChannelResponse struct { ID int64 `json:"id"` Message string `json:"message"` } // CreateChannel 创建渠道 func (h *handler) CreateChannel() core.HandlerFunc { return func(ctx core.Context) { req := new(createChannelRequest) res := new(createChannelResponse) if err := ctx.ShouldBindJSON(req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } item, err := h.channel.Create(ctx.RequestContext(), channelsvc.CreateInput{Name: req.Name, Code: req.Code, Type: req.Type, Remarks: req.Remarks}) if err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } res.ID = item.ID res.Message = "操作成功" ctx.Payload(res) } } type channelStatsRequest struct { Days int `form:"days"` StartDate string `form:"start_date"` EndDate string `form:"end_date"` } // ChannelStats 渠道数据分析 func (h *handler) ChannelStats() core.HandlerFunc { return func(ctx core.Context) { req := new(channelStatsRequest) if err := ctx.ShouldBindForm(req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } idStr := ctx.Param("channel_id") id, _ := strconv.ParseInt(idStr, 10, 64) stats, err := h.channel.GetStats(ctx.RequestContext(), id, req.Days, req.StartDate, req.EndDate) if err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } ctx.Payload(stats) } } type modifyChannelRequest struct { Name *string `json:"name"` Type *string `json:"type"` Remarks *string `json:"remarks"` } // ModifyChannel 修改渠道 func (h *handler) ModifyChannel() core.HandlerFunc { return func(ctx core.Context) { req := new(modifyChannelRequest) if err := ctx.ShouldBindJSON(req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } idStr := ctx.Param("channel_id") id, _ := strconv.ParseInt(idStr, 10, 64) if err := h.channel.Modify(ctx.RequestContext(), id, channelsvc.ModifyInput{Name: req.Name, Type: req.Type, Remarks: req.Remarks}); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } ctx.Payload(pcSimpleMessage{Message: "操作成功"}) } } // DeleteChannel 删除渠道 func (h *handler) DeleteChannel() core.HandlerFunc { return func(ctx core.Context) { idStr := ctx.Param("channel_id") id, _ := strconv.ParseInt(idStr, 10, 64) if err := h.channel.Delete(ctx.RequestContext(), id); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } ctx.Payload(pcSimpleMessage{Message: "操作成功"}) } } type listChannelsRequest struct { Name string `form:"name"` Page int `form:"page"` PageSize int `form:"page_size"` } type channelItem struct { ID int64 `json:"id"` Name string `json:"name"` Code string `json:"code"` Type string `json:"type"` Remarks string `json:"remarks"` UserCount int64 `json:"user_count"` PaidAmountCents int64 `json:"paid_amount_cents"` PaidAmount int64 `json:"paid_amount"` CreatedAt string `json:"created_at"` } type listChannelsResponse struct { Page int `json:"page"` PageSize int `json:"page_size"` Total int64 `json:"total"` List []channelItem `json:"list"` } // ListChannels 查看渠道列表 func (h *handler) ListChannels() core.HandlerFunc { return func(ctx core.Context) { req := new(listChannelsRequest) res := new(listChannelsResponse) if err := ctx.ShouldBindForm(req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } items, total, err := h.channel.List(ctx.RequestContext(), channelsvc.ListInput{Name: req.Name, Page: req.Page, PageSize: req.PageSize}) if err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } res.Page = req.Page res.PageSize = req.PageSize res.Total = total res.List = make([]channelItem, len(items)) for i, it := range items { res.List[i] = channelItem{ ID: it.ID, Name: it.Name, Code: it.Code, Type: it.Type, Remarks: it.Remarks, UserCount: it.UserCount, PaidAmountCents: it.PaidAmountCents, PaidAmount: it.PaidAmount, CreatedAt: it.CreatedAt.Format("2006-01-02 15:04:05"), } } ctx.Payload(res) } } type searchChannelUsersRequest struct { Keyword string `form:"keyword"` ChannelID int64 `form:"channel_id"` Page int `form:"page"` PageSize int `form:"page_size"` } type searchChannelUsersResponse struct { Page int `json:"page"` PageSize int `json:"page_size"` Total int64 `json:"total"` List []channelsvc.ChannelUserItem `json:"list"` } // SearchChannelUsers 搜索用户(用于渠道手动添加) func (h *handler) SearchChannelUsers() core.HandlerFunc { return func(ctx core.Context) { req := new(searchChannelUsersRequest) if err := ctx.ShouldBindForm(req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } items, total, err := h.channel.SearchUsers(ctx.RequestContext(), channelsvc.SearchUsersInput{ Keyword: req.Keyword, ChannelID: req.ChannelID, Page: req.Page, PageSize: req.PageSize, }) if err != nil { if err == channelsvc.ErrSearchKeywordEmpty { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "keyword 与 channel_id 不能同时为空")) return } ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } page := req.Page if page <= 0 { page = 1 } pageSize := req.PageSize if pageSize <= 0 { pageSize = 20 } if pageSize > 50 { pageSize = 50 } res := &searchChannelUsersResponse{ Page: page, PageSize: pageSize, Total: total, List: make([]channelsvc.ChannelUserItem, len(items)), } for i, item := range items { res.List[i] = *item } ctx.Payload(res) } } type bindChannelUsersRequest struct { UserIDs []int64 `json:"user_ids" binding:"required"` } // BindChannelUsers 手动批量绑定渠道用户 func (h *handler) BindChannelUsers() core.HandlerFunc { return func(ctx core.Context) { req := new(bindChannelUsersRequest) if err := ctx.ShouldBindJSON(req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } idStr := ctx.Param("channel_id") channelID, parseErr := strconv.ParseInt(idStr, 10, 64) if parseErr != nil || channelID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "渠道ID无效")) return } out, err := h.channel.BindUsers(ctx.RequestContext(), channelID, req.UserIDs) if err != nil { switch err { case channelsvc.ErrChannelNotFound: ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "渠道不存在")) return case channelsvc.ErrBindUsersEmpty: ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "user_ids 不能为空")) return case channelsvc.ErrBindUsersTooMany: ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "单次最多绑定200个用户")) return default: ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } } ctx.Payload(out) } }