feat: 用户徽章与等级体系,积分经济管理重构
- 新增徽章系统:badge 服务与 handler、管理端配置页、BadgeChip/LevelBadge 展示组件 - 新增等级模型:model/level 及前端 levels 元数据 - 管理端经济模块拆分为 points/badges/levels 独立页面,EconomySettings 迁入设置 - 积分、签到、评论等服务适配等级与徽章逻辑
This commit is contained in:
151
backend/handler/badge.go
Normal file
151
backend/handler/badge.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/freefire/jiang13-bbs/middleware"
|
||||
"github.com/freefire/jiang13-bbs/service"
|
||||
)
|
||||
|
||||
type badgeRequest struct {
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
type badgeGrantRequest struct {
|
||||
UserID uint `json:"user_id" binding:"required"`
|
||||
}
|
||||
|
||||
// badgeError 按业务错误映射响应
|
||||
func badgeError(c *gin.Context, err error) {
|
||||
switch {
|
||||
case errors.Is(err, service.ErrBadgeNotFound):
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
case errors.Is(err, service.ErrBadgeNameExists):
|
||||
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
|
||||
case errors.Is(err, service.ErrBadgeInvalid):
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "徽章名称(1-16 字)或颜色无效"})
|
||||
case errors.Is(err, service.ErrBadgeUserGone):
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
default:
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "徽章操作失败"})
|
||||
}
|
||||
}
|
||||
|
||||
// AdminListBadges 全部徽章(含持有数)
|
||||
func (h *Handlers) AdminListBadges(c *gin.Context) {
|
||||
badges, err := h.Badge.List()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取徽章列表失败"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"badges": badges})
|
||||
}
|
||||
|
||||
// AdminCreateBadge 新建徽章
|
||||
func (h *Handlers) AdminCreateBadge(c *gin.Context) {
|
||||
var req badgeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
|
||||
return
|
||||
}
|
||||
badge, err := h.Badge.Create(req.Name, req.Icon, req.Color)
|
||||
if err != nil {
|
||||
badgeError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"badge": badge})
|
||||
}
|
||||
|
||||
// AdminUpdateBadge 修改徽章
|
||||
func (h *Handlers) AdminUpdateBadge(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
|
||||
return
|
||||
}
|
||||
var req badgeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
|
||||
return
|
||||
}
|
||||
badge, err := h.Badge.Update(uint(id), req.Name, req.Icon, req.Color)
|
||||
if err != nil {
|
||||
badgeError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"badge": badge})
|
||||
}
|
||||
|
||||
// AdminDeleteBadge 删除徽章(级联删除授予记录)
|
||||
func (h *Handlers) AdminDeleteBadge(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
|
||||
return
|
||||
}
|
||||
if err := h.Badge.Delete(uint(id)); err != nil {
|
||||
badgeError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// AdminGrantBadge 授予徽章(幂等)
|
||||
func (h *Handlers) AdminGrantBadge(c *gin.Context) {
|
||||
claims := middleware.CurrentUser(c)
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
|
||||
return
|
||||
}
|
||||
var req badgeGrantRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
|
||||
return
|
||||
}
|
||||
if err := h.Badge.Grant(uint(id), req.UserID, claims.ID); err != nil {
|
||||
badgeError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// AdminRevokeBadge 撤销授予
|
||||
func (h *Handlers) AdminRevokeBadge(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
|
||||
return
|
||||
}
|
||||
userID, err := strconv.ParseUint(c.Param("userId"), 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
|
||||
return
|
||||
}
|
||||
if err := h.Badge.Revoke(uint(id), uint(userID)); err != nil {
|
||||
badgeError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// AdminBadgeHolders 某徽章全部持有者(后台授予面板用)
|
||||
func (h *Handlers) AdminBadgeHolders(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
|
||||
return
|
||||
}
|
||||
holders, err := h.Badge.Holders(uint(id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取持有者失败"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"holders": holders})
|
||||
}
|
||||
Reference in New Issue
Block a user