Files
2026-10-25 22:47:13 +08:00

374 lines
8.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package rbachdl 是后台 RBAC 管理(管理员 / 角色 / 权限)的 HTTP 接入层。
package rbachdl
import (
"strconv"
"github.com/gin-gonic/gin"
"portal-mini-go/internal/middleware"
"portal-mini-go/internal/pkg/errors"
"portal-mini-go/internal/pkg/response"
"portal-mini-go/internal/service/admin/rbac"
)
// Handler 聚合管理员 / 角色 / 权限三类管理接口。
type Handler struct {
adminSvc *rbac.AdminService
roleSvc *rbac.RoleService
permSvc *rbac.PermissionService
}
func NewHandler(adminSvc *rbac.AdminService, roleSvc *rbac.RoleService, permSvc *rbac.PermissionService) *Handler {
return &Handler{adminSvc: adminSvc, roleSvc: roleSvc, permSvc: permSvc}
}
// ---- 管理员 ----
// CreateAdmin 新建管理员。
func (h *Handler) CreateAdmin(c *gin.Context) {
var req rbac.CreateAdminReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
u, err := h.adminSvc.Create(c.Request.Context(), req)
if err != nil {
c.Error(err)
return
}
response.OK(c, u)
}
// ListAdmins 分页查询管理员。支持 query:keyword、status、page、size。
func (h *Handler) ListAdmins(c *gin.Context) {
keyword := c.Query("keyword")
status, _ := strconv.ParseInt(c.DefaultQuery("status", "-1"), 10, 8)
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
list, total, err := h.adminSvc.List(c.Request.Context(), rbac.AdminListReq{
Keyword: keyword,
Status: int8(status),
Page: page,
Size: size,
})
if err != nil {
c.Error(err)
return
}
response.OK(c, gin.H{"list": list, "total": total, "page": page, "size": size})
}
// GetAdmin 查询单个管理员。
func (h *Handler) GetAdmin(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
u, err := h.adminSvc.GetByID(c.Request.Context(), id)
if err != nil {
c.Error(err)
return
}
response.OK(c, u)
}
// UpdateAdmin 编辑管理员昵称 / 状态。
func (h *Handler) UpdateAdmin(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req rbac.UpdateAdminReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
u, err := h.adminSvc.Update(c.Request.Context(), id, req)
if err != nil {
c.Error(err)
return
}
response.OK(c, u)
}
// DeleteAdmin 删除管理员。
func (h *Handler) DeleteAdmin(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
if err := h.adminSvc.Delete(c.Request.Context(), id); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// AssignAdminRoles 为管理员分配角色。
func (h *Handler) AssignAdminRoles(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req struct {
RoleIDs []uint64 `json:"role_ids" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
if err := h.adminSvc.SetRoles(c.Request.Context(), id, req.RoleIDs); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// ResetAdminPassword 重置管理员密码。
func (h *Handler) ResetAdminPassword(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req struct {
Password string `json:"password" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
if err := h.adminSvc.ResetPassword(c.Request.Context(), id, req.Password); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// ---- 角色 ----
// CreateRole 新建角色。
func (h *Handler) CreateRole(c *gin.Context) {
var req rbac.CreateRoleReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
r, err := h.roleSvc.Create(c.Request.Context(), req)
if err != nil {
c.Error(err)
return
}
response.OK(c, r)
}
// ListRoles 分页查询角色。支持 query:keyword、status、page、size。
func (h *Handler) ListRoles(c *gin.Context) {
keyword := c.Query("keyword")
status, _ := strconv.ParseInt(c.DefaultQuery("status", "-1"), 10, 8)
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
list, total, err := h.roleSvc.List(c.Request.Context(), rbac.RoleListReq{
Keyword: keyword,
Status: int8(status),
Page: page,
Size: size,
})
if err != nil {
c.Error(err)
return
}
response.OK(c, gin.H{"list": list, "total": total, "page": page, "size": size})
}
// GetRole 查询单个角色。
func (h *Handler) GetRole(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
r, err := h.roleSvc.GetByID(c.Request.Context(), id)
if err != nil {
c.Error(err)
return
}
response.OK(c, r)
}
// UpdateRole 编辑角色。
func (h *Handler) UpdateRole(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req rbac.UpdateRoleReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
r, err := h.roleSvc.Update(c.Request.Context(), id, req)
if err != nil {
c.Error(err)
return
}
response.OK(c, r)
}
// DeleteRole 删除角色。
func (h *Handler) DeleteRole(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
if err := h.roleSvc.Delete(c.Request.Context(), id); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// AssignRolePermissions 为角色分配权限。
func (h *Handler) AssignRolePermissions(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req struct {
PermissionIDs []uint64 `json:"permission_ids" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
if err := h.roleSvc.SetPermissions(c.Request.Context(), id, req.PermissionIDs); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// ---- 权限 ----
// ListPermissions 分页查询权限。支持 query:type(api/menu)、keyword、page、size。
func (h *Handler) ListPermissions(c *gin.Context) {
permType := c.Query("type")
keyword := c.Query("keyword")
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
list, total, err := h.permSvc.List(c.Request.Context(), rbac.PermListReq{
Type: permType,
Keyword: keyword,
Page: page,
Size: size,
})
if err != nil {
c.Error(err)
return
}
response.OK(c, gin.H{"list": list, "total": total, "page": page, "size": size})
}
// CreatePermission 新建权限。
func (h *Handler) CreatePermission(c *gin.Context) {
var req rbac.CreatePermReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
p, err := h.permSvc.Create(c.Request.Context(), req)
if err != nil {
c.Error(err)
return
}
response.OK(c, p)
}
// GetPermission 查询单个权限。
func (h *Handler) GetPermission(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
p, err := h.permSvc.GetByID(c.Request.Context(), id)
if err != nil {
c.Error(err)
return
}
response.OK(c, p)
}
// UpdatePermission 编辑权限。
func (h *Handler) UpdatePermission(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req rbac.UpdatePermReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
p, err := h.permSvc.Update(c.Request.Context(), id, req)
if err != nil {
c.Error(err)
return
}
response.OK(c, p)
}
// DeletePermission 删除权限。
func (h *Handler) DeletePermission(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
if err := h.permSvc.Delete(c.Request.Context(), id); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
func parseID(c *gin.Context) (uint64, bool) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
c.Error(errors.ErrBadRequest)
return 0, false
}
return id, true
}
// Register 注册后台 RBAC 管理路由,各资源按权限粒度挂载守卫。
func Register(g *gin.RouterGroup, h *Handler) {
// 管理员
ag := g.Group("/rbac/admins", middleware.RequirePerm(middleware.PermAdminManage))
{
ag.POST("", h.CreateAdmin)
ag.GET("", h.ListAdmins)
ag.GET("/:id", h.GetAdmin)
ag.PUT("/:id", h.UpdateAdmin)
ag.DELETE("/:id", h.DeleteAdmin)
ag.POST("/:id/roles", h.AssignAdminRoles)
ag.POST("/:id/reset-pwd", h.ResetAdminPassword)
}
// 角色
rg := g.Group("/rbac/roles", middleware.RequirePerm(middleware.PermRoleManage))
{
rg.POST("", h.CreateRole)
rg.GET("", h.ListRoles)
rg.GET("/:id", h.GetRole)
rg.PUT("/:id", h.UpdateRole)
rg.DELETE("/:id", h.DeleteRole)
rg.POST("/:id/permissions", h.AssignRolePermissions)
}
// 权限
pg := g.Group("/rbac/permissions", middleware.RequirePerm(middleware.PermPermManage))
{
pg.POST("", h.CreatePermission)
pg.GET("", h.ListPermissions)
pg.GET("/:id", h.GetPermission)
pg.PUT("/:id", h.UpdatePermission)
pg.DELETE("/:id", h.DeletePermission)
}
}