// 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) } }