package service import ( "context" "errors" "gorm.io/gorm" "github.com/user-management-system/internal/domain" "github.com/user-management-system/internal/repository" ) // RoleService 角色服务 type RoleService struct { roleRepo *repository.RoleRepository rolePermissionRepo *repository.RolePermissionRepository } // NewRoleService 创建角色服务 func NewRoleService( roleRepo *repository.RoleRepository, rolePermissionRepo *repository.RolePermissionRepository, ) *RoleService { return &RoleService{ roleRepo: roleRepo, rolePermissionRepo: rolePermissionRepo, } } // CreateRoleRequest 创建角色请求 type CreateRoleRequest struct { Name string `json:"name" binding:"required"` Code string `json:"code" binding:"required"` Description string `json:"description"` ParentID *int64 `json:"parent_id"` } // UpdateRoleRequest 更新角色请求 type UpdateRoleRequest struct { Name string `json:"name"` Description string `json:"description"` ParentID *int64 `json:"parent_id"` } // CreateRole 创建角色 func (s *RoleService) CreateRole(ctx context.Context, req *CreateRoleRequest) (*domain.Role, error) { // 检查角色代码是否已存在 exists, err := s.roleRepo.ExistsByCode(ctx, req.Code) if err != nil { return nil, err } if exists { return nil, errors.New("角色代码已存在") } // 设置角色层级 level := 1 if req.ParentID != nil { parentRole, err := s.roleRepo.GetByID(ctx, *req.ParentID) if err != nil { return nil, errors.New("父角色不存在") } level = parentRole.Level + 1 } // 创建角色 role := &domain.Role{ Name: req.Name, Code: req.Code, Description: req.Description, ParentID: req.ParentID, Level: level, Status: domain.RoleStatusEnabled, } if err := s.roleRepo.Create(ctx, role); err != nil { return nil, err } return role, nil } const maxRoleDepth = 5 // 角色继承深度上限,可配置 // UpdateRole 更新角色 func (s *RoleService) UpdateRole(ctx context.Context, roleID int64, req *UpdateRoleRequest) (*domain.Role, error) { role, err := s.roleRepo.GetByID(ctx, roleID) if err != nil { return nil, errors.New("角色不存在") } // 检查父角色是否存在 if req.ParentID != nil { if *req.ParentID == roleID { return nil, errors.New("不能将角色设置为自己的父角色") } // 检测循环继承:检查新父角色的祖先链是否包含当前角色 if err := s.checkCircularInheritance(ctx, roleID, *req.ParentID); err != nil { return nil, err } // 检测继承深度:计算新父角色的深度 + 1 if err := s.checkInheritanceDepth(ctx, *req.ParentID, maxRoleDepth-1); err != nil { return nil, err } role.ParentID = req.ParentID } // 更新字段 if req.Name != "" { role.Name = req.Name } if req.Description != "" { role.Description = req.Description } if err := s.roleRepo.Update(ctx, role); err != nil { return nil, err } return role, nil } // checkCircularInheritance 检测循环继承 // 如果将 childID 的父角色设为 parentID,检查 parentID 的祖先链是否包含 childID func (s *RoleService) checkCircularInheritance(ctx context.Context, childID, parentID int64) error { ancestorIDs, err := s.roleRepo.GetAncestorIDs(ctx, parentID) if err != nil { return err } for _, ancestorID := range ancestorIDs { if ancestorID == childID { return errors.New("检测到循环继承,操作被拒绝") } } return nil } // checkInheritanceDepth 检测继承深度是否超限 func (s *RoleService) checkInheritanceDepth(ctx context.Context, roleID int64, maxDepth int) error { if maxDepth <= 0 { return errors.New("继承深度超限,最大支持5层") } depth := 0 currentID := roleID for { role, err := s.roleRepo.GetByID(ctx, currentID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { break } return err } if role.ParentID == nil { break } depth++ if depth > maxDepth { return errors.New("继承深度超限,最大支持5层") } currentID = *role.ParentID } return nil } // DeleteRole 删除角色 func (s *RoleService) DeleteRole(ctx context.Context, roleID int64) error { role, err := s.roleRepo.GetByID(ctx, roleID) if err != nil { return errors.New("角色不存在") } // 系统角色不能删除 if role.IsSystem { return errors.New("系统角色不能删除") } // 检查是否有子角色 children, err := s.roleRepo.ListByParentID(ctx, roleID) if err == nil && len(children) > 0 { return errors.New("存在子角色,无法删除") } // 删除角色权限关联 if err := s.rolePermissionRepo.DeleteByRoleID(ctx, roleID); err != nil { return err } // 删除角色 return s.roleRepo.Delete(ctx, roleID) } // GetRole 获取角色信息 func (s *RoleService) GetRole(ctx context.Context, roleID int64) (*domain.Role, error) { return s.roleRepo.GetByID(ctx, roleID) } // ListRoles 获取角色列表 type ListRoleRequest struct { Page int `json:"page"` PageSize int `json:"page_size"` Status int `json:"status"` Keyword string `json:"keyword"` } func (s *RoleService) ListRoles(ctx context.Context, req *ListRoleRequest) ([]*domain.Role, int64, error) { if req.Page <= 0 { req.Page = 1 } if req.PageSize <= 0 { req.PageSize = 20 } offset := (req.Page - 1) * req.PageSize if req.Keyword != "" { return s.roleRepo.Search(ctx, req.Keyword, offset, req.PageSize) } // Status > 0 表示按状态过滤;0 表示不过滤(查全部) if req.Status > 0 { return s.roleRepo.ListByStatus(ctx, domain.RoleStatus(req.Status), offset, req.PageSize) } return s.roleRepo.List(ctx, offset, req.PageSize) } // UpdateRoleStatus 更新角色状态 func (s *RoleService) UpdateRoleStatus(ctx context.Context, roleID int64, status domain.RoleStatus) error { role, err := s.roleRepo.GetByID(ctx, roleID) if err != nil { return errors.New("角色不存在") } // 系统角色不能禁用 if role.IsSystem && status == domain.RoleStatusDisabled { return errors.New("系统角色不能禁用") } return s.roleRepo.UpdateStatus(ctx, roleID, status) } // GetRolePermissions 获取角色权限(包含继承的父角色权限) func (s *RoleService) GetRolePermissions(ctx context.Context, roleID int64) ([]*domain.Permission, error) { // 收集所有角色ID(包括当前角色和所有父角色) allRoleIDs := []int64{roleID} ancestorIDs, err := s.roleRepo.GetAncestorIDs(ctx, roleID) if err != nil { return nil, err } allRoleIDs = append(allRoleIDs, ancestorIDs...) // 批量获取所有角色的权限ID permissionIDs, err := s.rolePermissionRepo.GetPermissionIDsByRoleIDs(ctx, allRoleIDs) if err != nil { return nil, err } // 批量获取权限详情 permissions, err := s.rolePermissionRepo.GetPermissionsByIDs(ctx, permissionIDs) if err != nil { return nil, err } return permissions, nil } // AssignPermissions 分配权限 func (s *RoleService) AssignPermissions(ctx context.Context, roleID int64, permissionIDs []int64) error { // 删除原有权限 if err := s.rolePermissionRepo.DeleteByRoleID(ctx, roleID); err != nil { return err } // 创建新权限关联 var rolePermissions []*domain.RolePermission for _, permissionID := range permissionIDs { rolePermissions = append(rolePermissions, &domain.RolePermission{ RoleID: roleID, PermissionID: permissionID, }) } return s.rolePermissionRepo.BatchCreate(ctx, rolePermissions) }