package notification import ( "context" "sort" "gorm.io/gorm" shopapp "github.com/break/junhong_cmp_fiber/internal/application/shop" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) // DynamicRecipientResolver 按稳定账号、平台角色或店铺解析当前可用后台账号。 type DynamicRecipientResolver struct { db *gorm.DB shopResolver shopapp.NotificationRecipientResolver } // NewDynamicRecipientResolver 创建后台通知动态接收人解析 Adapter。 func NewDynamicRecipientResolver(db *gorm.DB, shopResolver shopapp.NotificationRecipientResolver) *DynamicRecipientResolver { return &DynamicRecipientResolver{db: db, shopResolver: shopResolver} } // Resolve 根据受控目标类型返回去重且按账号 ID 排序的当前可用接收人。 func (r *DynamicRecipientResolver) Resolve(ctx context.Context, targetKind string, targetID uint) ([]uint, error) { if targetID == 0 { return nil, errors.New(errors.CodeInvalidParam) } var ids []uint var err error switch targetKind { case constants.NotificationTargetKindAccount: ids, err = r.resolveAccount(ctx, targetID) case constants.NotificationTargetKindPlatformRole: ids, err = r.resolvePlatformRole(ctx, targetID) case constants.NotificationTargetKindShop: if r.shopResolver == nil { return nil, errors.New(errors.CodeInternalError, "店铺通知接收人解析器未配置") } ids, err = r.shopResolver.ResolveNotificationRecipients(ctx, targetID) default: return nil, errors.New(errors.CodeInvalidParam, "通知接收目标类型不受支持") } if err != nil { return nil, err } return uniqueSortedIDs(ids), nil } func (r *DynamicRecipientResolver) resolveAccount(ctx context.Context, accountID uint) ([]uint, error) { var account model.Account err := r.db.WithContext(ctx).Select("id"). Where("id = ? AND status = ?", accountID, constants.StatusEnabled).Take(&account).Error if err == gorm.ErrRecordNotFound { return []uint{}, nil } if err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询通知申请人失败") } return []uint{account.ID}, nil } func (r *DynamicRecipientResolver) resolvePlatformRole(ctx context.Context, roleID uint) ([]uint, error) { var accounts []model.Account err := r.db.WithContext(ctx).Model(&model.Account{}). Select("tb_account.id"). Joins("JOIN tb_account_role ar ON ar.account_id = tb_account.id AND ar.deleted_at IS NULL AND ar.status = ?", constants.StatusEnabled). Joins("JOIN tb_role r ON r.id = ar.role_id AND r.deleted_at IS NULL AND r.status = ? AND r.role_type = ?", constants.StatusEnabled, constants.RoleTypePlatform). Where("ar.role_id = ? AND tb_account.status = ? AND tb_account.user_type IN ?", roleID, constants.StatusEnabled, []int{constants.UserTypeSuperAdmin, constants.UserTypePlatform}). Find(&accounts).Error if err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询平台角色通知接收人失败") } ids := make([]uint, 0, len(accounts)) for _, account := range accounts { ids = append(ids, account.ID) } return ids, nil } func uniqueSortedIDs(ids []uint) []uint { seen := make(map[uint]struct{}, len(ids)) result := make([]uint, 0, len(ids)) for _, id := range ids { if id == 0 { continue } if _, exists := seen[id]; exists { continue } seen[id] = struct{}{} result = append(result, id) } sort.Slice(result, func(i, j int) bool { return result[i] < result[j] }) return result }