diff --git a/internal/bootstrap/services.go b/internal/bootstrap/services.go index 3aedcdb..3368620 100644 --- a/internal/bootstrap/services.go +++ b/internal/bootstrap/services.go @@ -129,12 +129,12 @@ func initServices(s *stores, deps *Dependencies) *services { ) stopResumeService := iotCardSvc.NewStopResumeService(deps.Redis, s.IotCard, s.PackageUsage, s.DeviceSimBinding, deps.GatewayClient, deps.Logger) - device := deviceSvc.New(deps.DB, deps.Redis, s.Device, s.DeviceSimBinding, s.IotCard, s.Shop, s.AssetAllocationRecord, s.ShopPackageAllocation, s.ShopSeriesAllocation, s.PackageSeries, deps.GatewayClient) + device := deviceSvc.New(deps.DB, deps.Redis, s.Device, s.DeviceSimBinding, s.IotCard, s.Shop, s.AssetAllocationRecord, s.ShopPackageAllocation, s.ShopSeriesAllocation, s.PackageSeries, deps.GatewayClient, s.AssetIdentifier) return &services{ Account: account, AccountAudit: accountAudit, - Role: roleSvc.New(s.Role, s.Permission, s.RolePermission), + Role: roleSvc.New(s.Role, s.Permission, s.RolePermission, s.AccountRole, s.ShopRole), Permission: permissionSvc.New(s.Permission, s.AccountRole, s.RolePermission, account, deps.Redis), PersonalCustomer: personalCustomerSvc.NewService(s.PersonalCustomer, s.PersonalCustomerPhone, deps.Logger), ClientAuth: clientAuthSvc.New( @@ -194,7 +194,7 @@ func initServices(s *stores, deps *Dependencies) *services { ShopSeriesGrant: shopSeriesGrantSvc.New(deps.DB, s.ShopSeriesAllocation, s.ShopPackageAllocation, s.ShopPackageAllocationPriceHistory, s.Shop, s.Package, s.PackageSeries, deps.Logger), CommissionStats: commissionStatsSvc.New(s.ShopSeriesCommissionStats), PurchaseValidation: purchaseValidation, - Order: orderSvc.New(deps.DB, deps.Redis, s.Order, s.OrderItem, s.AgentWallet, s.AssetWallet, purchaseValidation, s.ShopPackageAllocation, s.ShopSeriesAllocation, s.IotCard, s.Device, s.PackageSeries, s.PackageUsage, s.Package, wechatConfig, deps.WechatPayment, deps.QueueClient, deps.Logger), + Order: orderSvc.New(deps.DB, deps.Redis, s.Order, s.OrderItem, s.AgentWallet, s.AssetWallet, purchaseValidation, s.ShopPackageAllocation, s.ShopSeriesAllocation, s.IotCard, s.Device, s.PackageSeries, s.PackageUsage, s.Package, wechatConfig, deps.WechatPayment, deps.QueueClient, deps.Logger, s.AssetIdentifier), Exchange: exchangeSvc.New(deps.DB, s.ExchangeOrder, s.IotCard, s.Device, s.AssetWallet, s.AssetWalletTransaction, s.PackageUsage, s.PackageUsageDailyRecord, s.ResourceTag, s.PersonalCustomerDevice, deps.Logger), Recharge: rechargeSvc.New(deps.DB, s.AssetRecharge, s.AssetWallet, s.AssetWalletTransaction, s.IotCard, s.Device, s.ShopSeriesAllocation, s.PackageSeries, s.CommissionRecord, wechatConfig, deps.Logger, deps.QueueClient), PollingConfig: pollingSvc.NewConfigService(s.PollingConfig), @@ -203,7 +203,7 @@ func initServices(s *stores, deps *Dependencies) *services { PollingAlert: pollingSvc.NewAlertService(s.PollingAlertRule, s.PollingAlertHistory, deps.Redis, deps.Logger), PollingCleanup: pollingSvc.NewCleanupService(s.DataCleanupConfig, s.DataCleanupLog, deps.Logger), PollingManualTrigger: pollingSvc.NewManualTriggerService(s.PollingManualTriggerLog, s.IotCard, deps.Redis, deps.Logger), - Asset: assetSvc.New(deps.DB, s.Device, s.IotCard, s.PackageUsage, s.Package, s.PackageSeries, s.DeviceSimBinding, s.Shop, deps.Redis, iotCard, deps.GatewayClient), + Asset: assetSvc.New(deps.DB, s.Device, s.IotCard, s.PackageUsage, s.Package, s.PackageSeries, s.DeviceSimBinding, s.Shop, deps.Redis, iotCard, deps.GatewayClient, s.AssetIdentifier, s.Order, s.OrderItem, s.ExchangeOrder), AssetLifecycle: assetSvc.NewLifecycleService(deps.DB, s.IotCard, s.Device), AssetWallet: assetWalletSvc.New(s.AssetWallet, s.AssetWalletTransaction), StopResumeService: stopResumeService, diff --git a/internal/service/role/service.go b/internal/service/role/service.go index a256bf4..6573fd4 100644 --- a/internal/service/role/service.go +++ b/internal/service/role/service.go @@ -23,14 +23,18 @@ 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) *Service { +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, } } @@ -126,7 +130,6 @@ func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdateRoleReques // Delete 软删除角色 func (s *Service) Delete(ctx context.Context, id uint) error { - // 检查角色存在 _, err := s.roleStore.GetByID(ctx, id) if err != nil { if err == gorm.ErrRecordNotFound { @@ -135,6 +138,20 @@ func (s *Service) Delete(ctx context.Context, id uint) error { 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, "删除角色失败") } diff --git a/internal/store/postgres/account_role_store.go b/internal/store/postgres/account_role_store.go index bbf7560..3b719f2 100644 --- a/internal/store/postgres/account_role_store.go +++ b/internal/store/postgres/account_role_store.go @@ -121,3 +121,15 @@ func (s *AccountRoleStore) CountByAccountID(ctx context.Context, accountID uint) } return count, nil } + +// CountByRoleID 统计持有指定角色的账号数量 +func (s *AccountRoleStore) CountByRoleID(ctx context.Context, roleID uint) (int64, error) { + var count int64 + if err := s.db.WithContext(ctx). + Model(&model.AccountRole{}). + Where("role_id = ?", roleID). + Count(&count).Error; err != nil { + return 0, err + } + return count, nil +} diff --git a/internal/store/postgres/shop_role_store.go b/internal/store/postgres/shop_role_store.go index 2c69732..05fc143 100644 --- a/internal/store/postgres/shop_role_store.go +++ b/internal/store/postgres/shop_role_store.go @@ -61,6 +61,18 @@ func (s *ShopRoleStore) DeleteByShopID(ctx context.Context, shopID uint) error { return nil } +// CountByRoleID 统计持有指定角色的店铺数量 +func (s *ShopRoleStore) CountByRoleID(ctx context.Context, roleID uint) (int64, error) { + var count int64 + if err := s.db.WithContext(ctx). + Model(&model.ShopRole{}). + Where("role_id = ?", roleID). + Count(&count).Error; err != nil { + return 0, err + } + return count, nil +} + func (s *ShopRoleStore) GetByShopID(ctx context.Context, shopID uint) ([]*model.ShopRole, error) { var srs []*model.ShopRole query := s.db.WithContext(ctx).Where("shop_id = ?", shopID) diff --git a/pkg/errors/codes.go b/pkg/errors/codes.go index 1e1ce07..b2a537f 100644 --- a/pkg/errors/codes.go +++ b/pkg/errors/codes.go @@ -37,6 +37,7 @@ const ( CodeInvalidPermCode = 1025 // 权限编码格式不正确 CodeRoleAlreadyAssigned = 1026 // 角色已分配 CodePermAlreadyAssigned = 1027 // 权限已分配 + CodeRoleInUse = 1028 // 角色使用中,无法删除 // 认证相关错误 (1040-1049) CodeInvalidCredentials = 1040 // 用户名或密码错误 @@ -201,6 +202,7 @@ var allErrorCodes = []int{ CodeInvalidPermCode, CodeRoleAlreadyAssigned, CodePermAlreadyAssigned, + CodeRoleInUse, CodeShopNotFound, CodeShopCodeExists, CodeShopLevelExceeded, @@ -340,6 +342,7 @@ var errorMessages = map[int]string{ CodeInvalidPermCode: "权限编码格式不正确(应为 module:action 格式)", CodeRoleAlreadyAssigned: "角色已分配", CodePermAlreadyAssigned: "权限已分配", + CodeRoleInUse: "角色使用中,无法删除", CodeShopNotFound: "店铺不存在", CodeShopCodeExists: "店铺编号已存在", CodeShopLevelExceeded: "店铺层级不能超过 7 级",