package admin import ( "net/http" "strconv" "time" "bindbox-game/internal/code" "bindbox-game/internal/pkg/core" "bindbox-game/internal/pkg/validation" "bindbox-game/internal/repository/mysql/model" ) type listSystemTitlesRequest struct { Page int `form:"page"` PageSize int `form:"page_size"` Name string `form:"name"` Status *int32 `form:"status"` } type listSystemTitlesResponse struct { Page int `json:"page"` PageSize int `json:"page_size"` Total int64 `json:"total"` List []*model.SystemTitles `json:"list"` } // ListSystemTitles 系统称号列表 func (h *handler) ListSystemTitles() core.HandlerFunc { return func(ctx core.Context) { req := new(listSystemTitlesRequest) rsp := new(listSystemTitlesResponse) if err := ctx.ShouldBindForm(req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } if req.Page <= 0 { req.Page = 1 } if req.PageSize <= 0 { req.PageSize = 20 } if req.PageSize > 100 { req.PageSize = 100 } q := h.readDB.SystemTitles.WithContext(ctx.RequestContext()).ReadDB() if req.Name != "" { q = q.Where(h.readDB.SystemTitles.Name.Like("%" + req.Name + "%")) } if req.Status != nil { q = q.Where(h.readDB.SystemTitles.Status.Eq(*req.Status)) } total, err := q.Count() if err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, 30101, err.Error())) return } rows, err := q.Order(h.readDB.SystemTitles.ID.Desc()). Offset((req.Page-1)*req.PageSize).Limit(req.PageSize).Find() if err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, 30102, err.Error())) return } rsp.Page = req.Page rsp.PageSize = req.PageSize rsp.Total = total rsp.List = rows ctx.Payload(rsp) } } type createSystemTitleRequest struct { Name string `json:"name" binding:"required,min=1"` Description string `json:"description"` Status int32 `json:"status"` ObtainRulesJSON string `json:"obtain_rules_json"` ScopesJSON string `json:"scopes_json"` } type modifySystemTitleRequest struct { Name string `json:"name"` Description string `json:"description"` Status *int32 `json:"status"` ObtainRulesJSON string `json:"obtain_rules_json"` ScopesJSON string `json:"scopes_json"` } type simpleMessageResponseTitle struct { Message string `json:"message"` } func (h *handler) CreateSystemTitle() core.HandlerFunc { return func(ctx core.Context) { var req createSystemTitleRequest if err := ctx.ShouldBindJSON(&req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } if req.ObtainRulesJSON == "" { req.ObtainRulesJSON = "{}" } if req.ScopesJSON == "" { req.ScopesJSON = "{}" } it := &model.SystemTitles{ Name: req.Name, Description: req.Description, Status: req.Status, ObtainRulesJSON: req.ObtainRulesJSON, ScopesJSON: req.ScopesJSON, } if err := h.writeDB.SystemTitles.WithContext(ctx.RequestContext()).Create(it); err != nil { ctx.AbortWithError(core.Error(http.StatusInternalServerError, 30106, "创建称号失败")) return } ctx.Payload(&simpleMessageResponseTitle{Message: "创建成功"}) } } func (h *handler) ModifySystemTitle() core.HandlerFunc { return func(ctx core.Context) { titleID, err := strconv.ParseInt(ctx.Param("title_id"), 10, 64) if err != nil || titleID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递称号ID")) return } var req modifySystemTitleRequest if err := ctx.ShouldBindJSON(&req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } row, err := h.readDB.SystemTitles.WithContext(ctx.RequestContext()).Where(h.readDB.SystemTitles.ID.Eq(titleID)).First() if err != nil || row == nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, 30107, "称号不存在")) return } if req.Name != "" { row.Name = req.Name } row.Description = req.Description if req.Status != nil { row.Status = *req.Status } if req.ObtainRulesJSON != "" { row.ObtainRulesJSON = req.ObtainRulesJSON } if req.ScopesJSON != "" { row.ScopesJSON = req.ScopesJSON } if err := h.writeDB.SystemTitles.Save(row); err != nil { ctx.AbortWithError(core.Error(http.StatusInternalServerError, 30108, "修改称号失败")) return } ctx.Payload(&simpleMessageResponseTitle{Message: "修改成功"}) } } func (h *handler) DeleteSystemTitle() core.HandlerFunc { return func(ctx core.Context) { titleID, err := strconv.ParseInt(ctx.Param("title_id"), 10, 64) if err != nil || titleID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递称号ID")) return } del := &model.SystemTitles{ID: titleID} if _, err := h.writeDB.SystemTitles.Delete(del); err != nil { ctx.AbortWithError(core.Error(http.StatusInternalServerError, 30109, "删除称号失败")) return } ctx.Payload(&simpleMessageResponseTitle{Message: "删除成功"}) } } type listEffectsResponse struct { List []*model.SystemTitleEffects `json:"list"` Total int64 `json:"total"` } func (h *handler) ListSystemTitleEffects() core.HandlerFunc { return func(ctx core.Context) { titleID, err := strconv.ParseInt(ctx.Param("title_id"), 10, 64) if err != nil || titleID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递称号ID")) return } rows, err := h.readDB.SystemTitleEffects.WithContext(ctx.RequestContext()).Where(h.readDB.SystemTitleEffects.TitleID.Eq(titleID)).Order(h.readDB.SystemTitleEffects.Sort).Find() if err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, 30110, err.Error())) return } total := int64(len(rows)) ctx.Payload(&listEffectsResponse{List: rows, Total: total}) } } type createEffectRequest struct { EffectType int32 `json:"effect_type" binding:"required"` ParamsJSON string `json:"params_json" binding:"required"` StackingStrategy int32 `json:"stacking_strategy"` CapValueX1000 int32 `json:"cap_value_x1000"` ScopesJSON string `json:"scopes_json"` Sort int32 `json:"sort"` Status int32 `json:"status"` } func (h *handler) CreateSystemTitleEffect() core.HandlerFunc { return func(ctx core.Context) { titleID, err := strconv.ParseInt(ctx.Param("title_id"), 10, 64) if err != nil || titleID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递称号ID")) return } var req createEffectRequest if err := ctx.ShouldBindJSON(&req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } if req.ParamsJSON == "" { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "params_json不能为空")); return } if req.ScopesJSON == "" { req.ScopesJSON = "{}" } existed, _ := h.readDB.SystemTitleEffects.WithContext(ctx.RequestContext()). Where(h.readDB.SystemTitleEffects.TitleID.Eq(titleID)). Where(h.readDB.SystemTitleEffects.EffectType.Eq(req.EffectType)).First() if existed != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, 30115, "同类型效果已存在")) return } sanitized, verr := h.title.ValidateEffectParams(req.EffectType, req.ParamsJSON) if verr != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, verr.Error())) return } ef := &model.SystemTitleEffects{ TitleID: titleID, EffectType: req.EffectType, ParamsJSON: sanitized, StackingStrategy: req.StackingStrategy, CapValueX1000: req.CapValueX1000, ScopesJSON: req.ScopesJSON, Sort: req.Sort, Status: req.Status, } if err := h.writeDB.SystemTitleEffects.WithContext(ctx.RequestContext()).Create(ef); err != nil { ctx.AbortWithError(core.Error(http.StatusInternalServerError, 30111, "创建效果失败")) return } ctx.Payload(&simpleMessageResponseTitle{Message: "创建成功"}) } } type modifyEffectRequest struct { EffectType *int32 `json:"effect_type"` ParamsJSON string `json:"params_json"` StackingStrategy *int32 `json:"stacking_strategy"` CapValueX1000 *int32 `json:"cap_value_x1000"` ScopesJSON string `json:"scopes_json"` Sort *int32 `json:"sort"` Status *int32 `json:"status"` } func (h *handler) ModifySystemTitleEffect() core.HandlerFunc { return func(ctx core.Context) { titleID, err := strconv.ParseInt(ctx.Param("title_id"), 10, 64) if err != nil || titleID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递称号ID")) return } effectID, err := strconv.ParseInt(ctx.Param("effect_id"), 10, 64) if err != nil || effectID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递效果ID")) return } var req modifyEffectRequest if err := ctx.ShouldBindJSON(&req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } row, err := h.readDB.SystemTitleEffects.WithContext(ctx.RequestContext()).Where(h.readDB.SystemTitleEffects.ID.Eq(effectID)).Where(h.readDB.SystemTitleEffects.TitleID.Eq(titleID)).First() if err != nil || row == nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, 30112, "效果不存在")) return } if req.EffectType != nil { existed, _ := h.readDB.SystemTitleEffects.WithContext(ctx.RequestContext()). Where(h.readDB.SystemTitleEffects.TitleID.Eq(titleID)). Where(h.readDB.SystemTitleEffects.EffectType.Eq(*req.EffectType)). Where(h.readDB.SystemTitleEffects.ID.Neq(effectID)).First() if existed != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, 30116, "同类型效果已存在")) return } row.EffectType = *req.EffectType } if req.ParamsJSON != "" { et := row.EffectType if req.EffectType != nil { et = *req.EffectType } sanitized, verr := h.title.ValidateEffectParams(et, req.ParamsJSON) if verr != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, verr.Error())) return } row.ParamsJSON = sanitized } if req.StackingStrategy != nil { row.StackingStrategy = *req.StackingStrategy } if req.CapValueX1000 != nil { row.CapValueX1000 = *req.CapValueX1000 } if req.ScopesJSON != "" { row.ScopesJSON = req.ScopesJSON } if req.Sort != nil { row.Sort = *req.Sort } if req.Status != nil { row.Status = *req.Status } if err := h.writeDB.SystemTitleEffects.Save(row); err != nil { ctx.AbortWithError(core.Error(http.StatusInternalServerError, 30113, "修改效果失败")) return } ctx.Payload(&simpleMessageResponseTitle{Message: "修改成功"}) } } func (h *handler) DeleteSystemTitleEffect() core.HandlerFunc { return func(ctx core.Context) { titleID, err := strconv.ParseInt(ctx.Param("title_id"), 10, 64) if err != nil || titleID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递称号ID")) return } effectID, err := strconv.ParseInt(ctx.Param("effect_id"), 10, 64) if err != nil || effectID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递效果ID")) return } del := &model.SystemTitleEffects{ID: effectID, TitleID: titleID} if _, err := h.writeDB.SystemTitleEffects.Delete(del); err != nil { ctx.AbortWithError(core.Error(http.StatusInternalServerError, 30114, "删除效果失败")) return } ctx.Payload(&simpleMessageResponseTitle{Message: "删除成功"}) } } type assignUserTitleRequest struct { TitleID int64 `json:"title_id" binding:"required,min=1"` ExpiresAt *string `json:"expires_at"` // RFC3339 字符串,可空 Remark string `json:"remark"` } type assignUserTitleResponse struct { Message string `json:"message"` } // AssignUserTitle 给用户分配称号(存在则更新有效期与备注,并激活) func (h *handler) AssignUserTitle() core.HandlerFunc { return func(ctx core.Context) { userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64) if err != nil || userID <= 0 { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID")) return } var req assignUserTitleRequest if err := ctx.ShouldBindJSON(&req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } var expPtr *time.Time if req.ExpiresAt != nil && *req.ExpiresAt != "" { t, perr := time.Parse(time.RFC3339, *req.ExpiresAt) if perr != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "expires_at格式错误")) return } expPtr = &t } if err := h.title.AssignUserTitle(ctx.RequestContext(), userID, req.TitleID, expPtr, req.Remark); err != nil { if err.Error() == "already_owned" { ctx.AbortWithError(core.Error(http.StatusBadRequest, 30117, "该用户已拥有该称号")) return } ctx.AbortWithError(core.Error(http.StatusInternalServerError, 30105, "分配称号失败")) return } ctx.Payload(&assignUserTitleResponse{Message: "分配称号成功"}) } }