feat: 实现完整的板块级RBAC内容审核系统

- 新增站长/超级管理员/管理员/板块管理员四级角色体系
- 实现实时权限快照加载与细粒度权限校验
- 新增内容审核队列与前后端页面
- 重构用户权限管理与站点管理逻辑
- 新增评论/帖子审核状态与通知推送
- 优化前端权限控制与角色徽章展示
- 修正数据库迁移与默认值问题
This commit is contained in:
2026-09-15 04:47:34 +08:00
parent 6da4309453
commit a7b6421840
44 changed files with 3149 additions and 585 deletions

View File

@@ -0,0 +1,85 @@
package handler
import (
"errors"
"net/http"
"strconv"
"github.com/freefire/jiang13-bbs/middleware"
"github.com/freefire/jiang13-bbs/service"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// ===== 内容审核队列(RequireStaff 基础鉴权,板块范围由 service 按 Actor 隔离) =====
// AdminPendingPosts 待审核帖子分页
func (h *Handlers) AdminPendingPosts(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
posts, total, err := h.Moderation.PendingPosts(middleware.CurrentActor(c), page, 15)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取待审帖子失败"})
return
}
c.JSON(http.StatusOK, gin.H{"posts": posts, "total": total, "page": page})
}
// AdminPendingComments 待审核评论分页
func (h *Handlers) AdminPendingComments(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
comments, total, err := h.Moderation.PendingComments(middleware.CurrentActor(c), page, 15)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取待审评论失败"})
return
}
c.JSON(http.StatusOK, gin.H{"comments": comments, "total": total, "page": page})
}
// AdminPendingCounts 当前操作者可见的待审数量(导航角标)
func (h *Handlers) AdminPendingCounts(c *gin.Context) {
posts, comments := h.Moderation.PendingCounts(middleware.CurrentActor(c))
c.JSON(http.StatusOK, gin.H{"posts": posts, "comments": comments})
}
// AdminApprovePost 通过帖子
func (h *Handlers) AdminApprovePost(c *gin.Context) {
h.execModeration(c, h.Moderation.ApprovePost)
}
// AdminRejectPost 拒绝帖子
func (h *Handlers) AdminRejectPost(c *gin.Context) {
h.execModeration(c, h.Moderation.RejectPost)
}
// AdminApproveComment 通过评论
func (h *Handlers) AdminApproveComment(c *gin.Context) {
h.execModeration(c, h.Moderation.ApproveComment)
}
// AdminRejectComment 拒绝评论
func (h *Handlers) AdminRejectComment(c *gin.Context) {
h.execModeration(c, h.Moderation.RejectComment)
}
// execModeration 统一解析 :id 并映射审核业务错误
func (h *Handlers) execModeration(c *gin.Context, fn func(*service.Actor, uint) error) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 ID"})
return
}
if err := fn(middleware.CurrentActor(c), uint(id)); err != nil {
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
c.JSON(http.StatusNotFound, gin.H{"error": "内容不存在"})
case errors.Is(err, service.ErrModerationForbidden):
c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
case errors.Is(err, service.ErrNotPending):
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
default:
c.JSON(http.StatusInternalServerError, gin.H{"error": "操作失败"})
}
return
}
c.JSON(http.StatusOK, gin.H{"message": "操作成功"})
}