// Package role 提供角色管理的业务逻辑服务 // 包含角色创建、查询、更新、删除、角色权限关联等功能 package role import ( "context" "fmt" "strings" "time" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" "github.com/break/junhong_cmp_fiber/internal/store" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/middleware" "gorm.io/gorm" ) // Service 角色业务服务 type Service struct { roleStore *postgres.RoleStore permissionStore *postgres.PermissionStore rolePermissionStore *postgres.RolePermissionStore accountRoleStore *postgres.AccountRoleStore shopRoleStore *postgres.ShopRoleStore } // New 创建角色服务 func New(roleStore *postgres.RoleStore, permissionStore *postgres.PermissionStore, rolePermissionStore *postgres.RolePermissionStore, accountRoleStore *postgres.AccountRoleStore, shopRoleStore *postgres.ShopRoleStore) *Service { return &Service{ roleStore: roleStore, permissionStore: permissionStore, rolePermissionStore: rolePermissionStore, accountRoleStore: accountRoleStore, shopRoleStore: shopRoleStore, } } // Create 创建角色 func (s *Service) Create(ctx context.Context, req *dto.CreateRoleRequest) (*dto.RoleResponse, error) { // 获取当前用户 ID currentUserID := middleware.GetUserIDFromContext(ctx) if currentUserID == 0 { return nil, errors.New(errors.CodeUnauthorized, "未授权访问") } // 检查角色名是否已存在 exists, err := s.roleStore.ExistsByName(ctx, req.RoleName, 0) if err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "检查角色名失败") } if exists { return nil, errors.New(errors.CodeRoleNameExists) } // 创建角色 role := &model.Role{ RoleName: req.RoleName, RoleDesc: req.RoleDesc, RoleType: req.RoleType, Status: constants.StatusEnabled, } if err := s.roleStore.Create(ctx, role); err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "创建角色失败") } return toResponse(role), nil } // Get 获取角色 func (s *Service) Get(ctx context.Context, id uint) (*dto.RoleResponse, error) { role, err := s.roleStore.GetByID(ctx, id) if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeRoleNotFound, "角色不存在") } return nil, errors.Wrap(errors.CodeInternalError, err, "获取角色失败") } return toResponse(role), nil } // Update 更新角色 func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdateRoleRequest) (*dto.RoleResponse, error) { // 获取当前用户 ID currentUserID := middleware.GetUserIDFromContext(ctx) if currentUserID == 0 { return nil, errors.New(errors.CodeUnauthorized, "未授权访问") } // 获取现有角色 role, err := s.roleStore.GetByID(ctx, id) if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeRoleNotFound, "角色不存在") } return nil, errors.Wrap(errors.CodeInternalError, err, "获取角色失败") } // 如果修改了角色名,检查是否与其他角色重复 if req.RoleName != nil && *req.RoleName != role.RoleName { exists, err := s.roleStore.ExistsByName(ctx, *req.RoleName, id) if err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "检查角色名失败") } if exists { return nil, errors.New(errors.CodeRoleNameExists) } role.RoleName = *req.RoleName } // 更新其他字段 if req.RoleDesc != nil { role.RoleDesc = *req.RoleDesc } if req.Status != nil { role.Status = *req.Status } role.Updater = currentUserID if err := s.roleStore.Update(ctx, role); err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "更新角色失败") } return toResponse(role), nil } // Delete 软删除角色 func (s *Service) Delete(ctx context.Context, id uint) error { _, err := s.roleStore.GetByID(ctx, id) if err != nil { if err == gorm.ErrRecordNotFound { return errors.New(errors.CodeRoleNotFound, "角色不存在") } return errors.Wrap(errors.CodeInternalError, err, "获取角色失败") } accountCount, err := s.accountRoleStore.CountByRoleID(ctx, id) if err != nil { return errors.Wrap(errors.CodeInternalError, err, "检查角色分配情况失败") } shopCount, err := s.shopRoleStore.CountByRoleID(ctx, id) if err != nil { return errors.Wrap(errors.CodeInternalError, err, "检查角色分配情况失败") } if accountCount > 0 || shopCount > 0 { return errors.New(errors.CodeRoleInUse, fmt.Sprintf("该角色已分配给 %d 个账号、%d 个店铺,请先移除相关分配后再删除", accountCount, shopCount)) } if err := s.roleStore.Delete(ctx, id); err != nil { return errors.Wrap(errors.CodeInternalError, err, "删除角色失败") } return nil } // List 查询角色列表 func (s *Service) List(ctx context.Context, req *dto.RoleListRequest) ([]*model.Role, int64, error) { opts := &store.QueryOptions{ Page: req.Page, PageSize: req.PageSize, OrderBy: "id DESC", } if opts.Page == 0 { opts.Page = 1 } if opts.PageSize == 0 { opts.PageSize = constants.DefaultPageSize } filters := make(map[string]interface{}) if req.RoleName != "" { filters["role_name"] = req.RoleName } if req.RoleType != nil { filters["role_type"] = *req.RoleType } if req.Status != nil { filters["status"] = *req.Status } return s.roleStore.List(ctx, opts, filters) } // AssignPermissions 为角色分配权限 func (s *Service) AssignPermissions(ctx context.Context, roleID uint, permIDs []uint) ([]*model.RolePermission, error) { currentUserID := middleware.GetUserIDFromContext(ctx) if currentUserID == 0 { return nil, errors.New(errors.CodeUnauthorized, "未授权访问") } role, err := s.roleStore.GetByID(ctx, roleID) if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeRoleNotFound, "角色不存在") } return nil, errors.Wrap(errors.CodeInternalError, err, "获取角色失败") } permissions, err := s.permissionStore.GetByIDs(ctx, permIDs) if err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "获取权限失败") } if len(permissions) != len(permIDs) { return nil, errors.New(errors.CodePermissionNotFound, "部分权限不存在") } roleTypeStr := fmt.Sprintf("%d", role.RoleType) var invalidPermIDs []uint for _, perm := range permissions { if !contains(perm.AvailableForRoleTypes, roleTypeStr) { invalidPermIDs = append(invalidPermIDs, perm.ID) } } if len(invalidPermIDs) > 0 { return nil, errors.New(errors.CodeInvalidParam, fmt.Sprintf("权限 %v 不适用于此角色类型", invalidPermIDs)) } // 批量获取已有权限集合,避免逐条 Exists 查询 existingPermIDs, err := s.rolePermissionStore.GetPermIDsByRoleID(ctx, roleID) if err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "获取已有权限失败") } existingSet := make(map[uint]bool, len(existingPermIDs)) for _, id := range existingPermIDs { existingSet[id] = true } var rps []*model.RolePermission for _, permID := range permIDs { if existingSet[permID] { continue } rp := &model.RolePermission{ RoleID: roleID, PermID: permID, Status: constants.StatusEnabled, } if err := s.rolePermissionStore.Create(ctx, rp); err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "创建角色-权限关联失败") } rps = append(rps, rp) } return rps, nil } // GetPermissions 获取角色的所有权限 func (s *Service) GetPermissions(ctx context.Context, roleID uint) ([]*model.Permission, error) { // 检查角色存在 _, err := s.roleStore.GetByID(ctx, roleID) if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeRoleNotFound, "角色不存在") } return nil, errors.Wrap(errors.CodeInternalError, err, "获取角色失败") } // 获取权限 ID 列表 permIDs, err := s.rolePermissionStore.GetPermIDsByRoleID(ctx, roleID) if err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "获取角色权限 ID 失败") } if len(permIDs) == 0 { return []*model.Permission{}, nil } // 获取权限详情 return s.permissionStore.GetByIDs(ctx, permIDs) } // RemovePermission 移除角色的权限 func (s *Service) RemovePermission(ctx context.Context, roleID, permID 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.Delete(ctx, roleID, permID); err != nil { return errors.Wrap(errors.CodeInternalError, 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) if currentUserID == 0 { return errors.New(errors.CodeUnauthorized, "未授权访问") } role, err := s.roleStore.GetByID(ctx, id) if err != nil { if err == gorm.ErrRecordNotFound { return errors.New(errors.CodeRoleNotFound, "角色不存在") } return errors.Wrap(errors.CodeInternalError, err, "获取角色失败") } // 禁用角色时检查是否已有分配 if status == constants.StatusDisabled { accountCount, err := s.accountRoleStore.CountByRoleID(ctx, id) if err != nil { return errors.Wrap(errors.CodeInternalError, err, "检查角色分配情况失败") } shopCount, err := s.shopRoleStore.CountByRoleID(ctx, id) if err != nil { return errors.Wrap(errors.CodeInternalError, err, "检查角色分配情况失败") } if accountCount > 0 || shopCount > 0 { return errors.New(errors.CodeRoleInUse, fmt.Sprintf("该角色已分配给 %d 个账号、%d 个店铺,请先移除相关分配后再禁用", accountCount, shopCount)) } } role.Status = status role.Updater = currentUserID if err := s.roleStore.Update(ctx, role); err != nil { return errors.Wrap(errors.CodeInternalError, err, "更新角色状态失败") } return nil } // toResponse 将 model.Role 转换为 dto.RoleResponse func toResponse(role *model.Role) *dto.RoleResponse { return &dto.RoleResponse{ ID: role.ID, RoleName: role.RoleName, RoleDesc: role.RoleDesc, RoleType: role.RoleType, Status: role.Status, Creator: role.Creator, Updater: role.Updater, CreatedAt: role.CreatedAt.Format(time.RFC3339), UpdatedAt: role.UpdatedAt.Format(time.RFC3339), } } func contains(availableForRoleTypes, roleTypeStr string) bool { types := strings.Split(availableForRoleTypes, ",") for _, t := range types { if strings.TrimSpace(t) == roleTypeStr { return true } } return false }