feat: 新增批量移除角色权限接口
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled

- 新增 DELETE /api/admin/roles/:role_id/permissions 接口
- Store 层新增 BatchDelete 方法,单次 SQL 批量软删除
- Service 层新增 BatchRemovePermissions 方法
- Handler 层新增 BatchRemovePermissions 处理函数
- DTO 新增 BatchRemovePermissionsRequest/Params
- 修复 openapi generator 对 DELETE 方法 requestBody 不生成的问题
- RouteSpec 新增 Body 字段,支持显式指定 JSON 请求体

💘 Generated with Crush

Assisted-by: Claude Sonnet 4.6 via Crush <crush@charm.land>
This commit is contained in:
2026-04-09 11:41:58 +08:00
parent a7dfe858c7
commit 384a54164b
8 changed files with 159 additions and 7 deletions

View File

@@ -197,6 +197,35 @@ func (h *RoleHandler) RemovePermission(c *fiber.Ctx) error {
return response.Success(c, nil)
}
// BatchRemovePermissions 批量移除角色的权限
// DELETE /api/admin/roles/:role_id/permissions
func (h *RoleHandler) BatchRemovePermissions(c *fiber.Ctx) error {
roleID, err := strconv.ParseUint(c.Params("role_id"), 10, 64)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的角色 ID")
}
var req dto.BatchRemovePermissionsRequest
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
if err := h.validator.Struct(&req); err != nil {
logger.GetAppLogger().Warn("参数验证失败",
zap.String("path", c.Path()),
zap.String("method", c.Method()),
zap.Error(err),
)
return errors.New(errors.CodeInvalidParam)
}
if err := h.service.BatchRemovePermissions(c.UserContext(), uint(roleID), req.PermIDs); err != nil {
return err
}
return response.Success(c, nil)
}
// UpdateStatus 更新角色状态
// PUT /api/admin/roles/:id/status
func (h *RoleHandler) UpdateStatus(c *fiber.Ctx) error {

View File

@@ -67,6 +67,17 @@ type RemovePermissionParams struct {
PermID uint `path:"perm_id" required:"true" description:"权限ID"`
}
// BatchRemovePermissionsRequest 批量移除权限请求
type BatchRemovePermissionsRequest struct {
PermIDs []uint `json:"perm_ids" validate:"required,min=1" required:"true" minItems:"1" description:"权限ID列表"`
}
// BatchRemovePermissionsParams 批量移除权限参数聚合
type BatchRemovePermissionsParams struct {
RoleID uint `path:"role_id" required:"true" description:"角色ID"`
BatchRemovePermissionsRequest
}
// UpdateRoleStatusRequest 更新角色状态请求
type UpdateRoleStatusRequest struct {
Status *int `json:"status" validate:"required,min=0,max=1" description:"状态 (0:禁用, 1:启用)"`

View File

@@ -20,6 +20,7 @@ type RouteSpec struct {
Summary string // 简短摘要(中文,一行)
Description string // 详细说明,支持 Markdown 语法(可选)
Input interface{} // 请求参数结构体 (Query/Path/Body)
Body interface{} // 显式 JSON 请求体(用于 DELETE 等方法,库不自动生成 requestBody 的场景)
Output interface{} // 响应参数结构体
Tags []string // 分类标签
Auth bool // 是否需要认证图标 (预留)
@@ -54,7 +55,7 @@ func Register(router fiber.Router, doc *openapi.Generator, basePath, method, pat
}
doc.AddMultipartOperation(method, openapiPath, spec.Summary, spec.Description, spec.Input, spec.Output, spec.Auth, fileFields, spec.Tags...)
} else {
doc.AddOperation(method, openapiPath, spec.Summary, spec.Description, spec.Input, spec.Output, spec.Auth, spec.Tags...)
doc.AddOperation(method, openapiPath, spec.Summary, spec.Description, spec.Input, spec.Body, spec.Output, spec.Auth, spec.Tags...)
}
}
}

View File

@@ -87,4 +87,13 @@ func registerRoleRoutes(api fiber.Router, h *admin.RoleHandler, doc *openapi.Gen
Output: nil,
Auth: true,
})
Register(roles, doc, groupPath, "DELETE", "/:role_id/permissions", h.BatchRemovePermissions, RouteSpec{
Summary: "批量移除权限",
Tags: []string{"角色"},
Input: new(dto.BatchRemovePermissionsParams),
Body: new(dto.BatchRemovePermissionsRequest),
Output: nil,
Auth: true,
})
}

View File

@@ -286,6 +286,23 @@ func (s *Service) RemovePermission(ctx context.Context, roleID, permID uint) err
return nil
}
// BatchRemovePermissions 批量移除角色的权限
func (s *Service) BatchRemovePermissions(ctx context.Context, roleID uint, permIDs []uint) error {
_, err := s.roleStore.GetByID(ctx, roleID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return errors.New(errors.CodeRoleNotFound, "角色不存在")
}
return errors.Wrap(errors.CodeInternalError, err, "获取角色失败")
}
if err := s.rolePermissionStore.BatchDelete(ctx, roleID, permIDs); err != nil {
return errors.Wrap(errors.CodeInternalError, err, "批量删除角色-权限关联失败")
}
return nil
}
// UpdateStatus 更新角色状态
func (s *Service) UpdateStatus(ctx context.Context, id uint, status int) error {
currentUserID := middleware.GetUserIDFromContext(ctx)

View File

@@ -58,6 +58,17 @@ func (s *RolePermissionStore) Delete(ctx context.Context, roleID, permID uint) e
return nil
}
// BatchDelete 批量软删除角色-权限关联
func (s *RolePermissionStore) BatchDelete(ctx context.Context, roleID uint, permIDs []uint) error {
if err := s.db.WithContext(ctx).
Where("role_id = ? AND perm_id IN ?", roleID, permIDs).
Delete(&model.RolePermission{}).Error; err != nil {
return err
}
s.clearRoleUsersCaches(ctx, roleID)
return nil
}
// DeleteByRoleID 删除角色的所有权限关联
func (s *RolePermissionStore) DeleteByRoleID(ctx context.Context, roleID uint) error {
if err := s.db.WithContext(ctx).