package handler import ( "errors" "net/http" "strconv" "strings" "github.com/freefire/jiang13-bbs/middleware" "github.com/freefire/jiang13-bbs/model" "github.com/freefire/jiang13-bbs/service" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // ===== 用户管理(RequireStaff + PermUsers 兜底,前端不做权限判定) ===== // AdminListUsers 用户分页列表(搜索/角色/状态筛选 + 全站汇总) func (h *Handlers) AdminListUsers(c *gin.Context) { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) size, _ := strconv.Atoi(c.DefaultQuery("size", "20")) res, err := h.AdminUser.List(service.AdminUserListQuery{ Page: page, Size: size, Keyword: strings.TrimSpace(c.Query("q")), Role: c.Query("role"), Status: c.Query("status"), Sort: c.Query("sort"), Dir: c.Query("order"), }) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取用户列表失败"}) return } c.JSON(http.StatusOK, gin.H{ "users": res.Users, "total": res.Total, "page": res.Page, "size": res.Size, "summary": res.Summary, }) } // adminStaffBody 角色与板块授权变更请求体 type adminStaffBody struct { Role string `json:"role"` BoardIDs []uint `json:"board_ids"` } type adminUserBanBody struct { Banned bool `json:"banned"` } // AdminUpdateUserRole 设置管理角色与板块授权 func (h *Handlers) AdminUpdateUserRole(c *gin.Context) { id, ok := parseAdminUserID(c) if !ok { return } var body adminStaffBody if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"}) return } user, err := h.AdminUser.SetStaff( middleware.CurrentActor(c), id, model.Role(body.Role), body.BoardIDs, ) if err != nil { respondAdminUserError(c, err) return } c.JSON(http.StatusOK, gin.H{"user": user}) } // AdminSetUserMessages 站长授予/撤销站点消息管理 func (h *Handlers) AdminSetUserMessages(c *gin.Context) { id, ok := parseAdminUserID(c) if !ok { return } var body struct { CanManageMessages bool `json:"can_manage_messages"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"}) return } user, err := h.AdminUser.SetCanManageMessages(middleware.CurrentActor(c), id, body.CanManageMessages) if err != nil { respondAdminUserError(c, err) return } c.JSON(http.StatusOK, gin.H{"user": user}) } // AdminSetUserBan 封禁 / 解封用户 func (h *Handlers) AdminSetUserBan(c *gin.Context) { id, ok := parseAdminUserID(c) if !ok { return } var body adminUserBanBody if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"}) return } user, err := h.AdminUser.SetBanned(middleware.CurrentActor(c), id, body.Banned) if err != nil { respondAdminUserError(c, err) return } c.JSON(http.StatusOK, gin.H{"user": user}) } // AdminUserLoginLogs 某用户的登录历史(IP/UA/成败) func (h *Handlers) AdminUserLoginLogs(c *gin.Context) { id, ok := parseAdminUserID(c) if !ok { return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) logs, total, err := h.AdminUser.ListLoginLogs(id, page, 15) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "获取登录历史失败"}) return } c.JSON(http.StatusOK, gin.H{"logs": nonNilSlice(logs), "total": total, "page": page}) } // AdminGetUserAudit 站长:用户内容档案摘要 func (h *Handlers) AdminGetUserAudit(c *gin.Context) { id, ok := parseAdminUserID(c) if !ok { return } profile, err := h.AdminUser.GetAuditProfile(middleware.CurrentActor(c), id) if err != nil { respondAdminUserError(c, err) return } c.JSON(http.StatusOK, profile) } // AdminUserAuditPosts 站长:用户帖子(含驳回/软删) func (h *Handlers) AdminUserAuditPosts(c *gin.Context) { id, ok := parseAdminUserID(c) if !ok { return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) items, total, page, err := h.AdminUser.ListAuditPosts(middleware.CurrentActor(c), id, page, 20) if err != nil { respondAdminUserError(c, err) return } c.JSON(http.StatusOK, gin.H{"items": nonNilSlice(items), "total": total, "page": page}) } // AdminUserAuditComments 站长:用户评论(含驳回/软删) func (h *Handlers) AdminUserAuditComments(c *gin.Context) { id, ok := parseAdminUserID(c) if !ok { return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) items, total, page, err := h.AdminUser.ListAuditComments(middleware.CurrentActor(c), id, page, 20) if err != nil { respondAdminUserError(c, err) return } c.JSON(http.StatusOK, gin.H{"items": nonNilSlice(items), "total": total, "page": page}) } // AdminUserAuditMessages 站长:用户聊天消息(含撤回/软删) func (h *Handlers) AdminUserAuditMessages(c *gin.Context) { id, ok := parseAdminUserID(c) if !ok { return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) items, total, page, err := h.AdminUser.ListAuditMessages(middleware.CurrentActor(c), id, page, 20) if err != nil { respondAdminUserError(c, err) return } c.JSON(http.StatusOK, gin.H{"items": nonNilSlice(items), "total": total, "page": page}) } // parseAdminUserID 解析路径中的用户 ID,失败时直接写出 400 func parseAdminUserID(c *gin.Context) (uint, bool) { id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil || id == 0 { c.JSON(http.StatusBadRequest, gin.H{"error": "无效的用户 ID"}) return 0, false } return uint(id), true } // respondAdminUserError 统一映射用户管理业务错误到 HTTP 状态码 func respondAdminUserError(c *gin.Context, err error) { switch { case errors.Is(err, gorm.ErrRecordNotFound): c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"}) case errors.Is(err, service.ErrProtectedOwner), errors.Is(err, service.ErrOwnerOnly): c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) case errors.Is(err, service.ErrAdminSelfAction), errors.Is(err, service.ErrInvalidRole), errors.Is(err, service.ErrCannotAssignRole), errors.Is(err, service.ErrBoardRequired), errors.Is(err, service.ErrBoardNotFound): c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": "操作失败"}) } }