package services import ( "context" "fmt" "go.uber.org/zap" "tyapi-server/internal/domains/user/entities" "tyapi-server/internal/domains/user/repositories" "tyapi-server/internal/domains/user/repositories/queries" "tyapi-server/internal/shared/interfaces" ) // UserAggregateService 用户聚合服务接口 // 负责用户聚合根的生命周期管理和业务规则验证 type UserAggregateService interface { // 聚合根管理 CreateUser(ctx context.Context, phone, password string) (*entities.User, error) LoadUser(ctx context.Context, userID string) (*entities.User, error) SaveUser(ctx context.Context, user *entities.User) error LoadUserByPhone(ctx context.Context, phone string) (*entities.User, error) // 业务规则验证 ValidateBusinessRules(ctx context.Context, user *entities.User) error CheckInvariance(ctx context.Context, user *entities.User) error // 查询方法 ExistsByPhone(ctx context.Context, phone string) (bool, error) ExistsByID(ctx context.Context, userID string) (bool, error) // 用户管理方法 GetUserByID(ctx context.Context, userID string) (*entities.User, error) UpdateLoginStats(ctx context.Context, userID string) error ListUsers(ctx context.Context, query *queries.ListUsersQuery) ([]*entities.User, int64, error) GetUserStats(ctx context.Context) (*repositories.UserStats, error) // 企业信息管理 CreateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error UpdateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error GetUserWithEnterpriseInfo(ctx context.Context, userID string) (*entities.User, error) ValidateEnterpriseInfo(ctx context.Context, userID string) error CheckUnifiedSocialCodeExists(ctx context.Context, unifiedSocialCode string, excludeUserID string) (bool, error) // 认证域专用:写入/覆盖企业信息 CreateOrUpdateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error CompleteCertification(ctx context.Context, userID string) error } // UserAggregateServiceImpl 用户聚合服务实现 type UserAggregateServiceImpl struct { userRepo repositories.UserRepository eventBus interfaces.EventBus logger *zap.Logger } // NewUserAggregateService 创建用户聚合服务 func NewUserAggregateService( userRepo repositories.UserRepository, eventBus interfaces.EventBus, logger *zap.Logger, ) UserAggregateService { return &UserAggregateServiceImpl{ userRepo: userRepo, eventBus: eventBus, logger: logger, } } // ================ 聚合根管理 ================ // CreateUser 创建用户 func (s *UserAggregateServiceImpl) CreateUser(ctx context.Context, phone, password string) (*entities.User, error) { s.logger.Debug("创建用户聚合根", zap.String("phone", phone)) // 1. 检查手机号是否已注册 exists, err := s.ExistsByPhone(ctx, phone) if err != nil { return nil, fmt.Errorf("检查手机号失败: %w", err) } if exists { return nil, fmt.Errorf("手机号已注册") } // 2. 创建用户聚合根 user, err := entities.NewUser(phone, password) if err != nil { return nil, fmt.Errorf("创建用户失败: %w", err) } // 3. 调用聚合根方法进行注册 if err := user.Register(); err != nil { return nil, fmt.Errorf("用户注册失败: %w", err) } // 4. 验证业务规则 if err := s.ValidateBusinessRules(ctx, user); err != nil { return nil, fmt.Errorf("业务规则验证失败: %w", err) } // 5. 保存到仓储 if err := s.SaveUser(ctx, user); err != nil { return nil, fmt.Errorf("保存用户失败: %w", err) } s.logger.Info("用户创建成功", zap.String("user_id", user.ID), zap.String("phone", phone), ) return user, nil } // LoadUser 根据ID加载用户聚合根 func (s *UserAggregateServiceImpl) LoadUser(ctx context.Context, userID string) (*entities.User, error) { s.logger.Debug("加载用户聚合根", zap.String("user_id", userID)) user, err := s.userRepo.GetByID(ctx, userID) if err != nil { return nil, fmt.Errorf("用户不存在: %w", err) } // 验证业务规则 if err := s.ValidateBusinessRules(ctx, &user); err != nil { s.logger.Warn("用户业务规则验证失败", zap.String("user_id", userID), zap.Error(err), ) } return &user, nil } // SaveUser 保存用户聚合根 func (s *UserAggregateServiceImpl) SaveUser(ctx context.Context, user *entities.User) error { s.logger.Debug("保存用户聚合根", zap.String("user_id", user.ID)) // 1. 验证业务规则 if err := s.ValidateBusinessRules(ctx, user); err != nil { return fmt.Errorf("业务规则验证失败: %w", err) } // 2. 检查聚合根是否存在 exists, err := s.userRepo.Exists(ctx, user.ID) if err != nil { return fmt.Errorf("检查用户存在性失败: %w", err) } // 3. 保存到仓储 if exists { err = s.userRepo.Update(ctx, *user) if err != nil { s.logger.Error("更新用户聚合根失败", zap.Error(err)) return fmt.Errorf("更新用户失败: %w", err) } } else { createdUser, err := s.userRepo.Create(ctx, *user) if err != nil { s.logger.Error("创建用户聚合根失败", zap.Error(err)) return fmt.Errorf("创建用户失败: %w", err) } // 更新用户ID(如果仓储生成了新的ID) if createdUser.ID != "" { user.ID = createdUser.ID } } // 4. 发布领域事件 if err := s.publishDomainEvents(ctx, user); err != nil { s.logger.Error("发布领域事件失败", zap.Error(err)) // 不返回错误,因为数据已保存成功 } s.logger.Debug("用户聚合根保存成功", zap.String("user_id", user.ID)) return nil } // LoadUserByPhone 根据手机号加载用户聚合根 func (s *UserAggregateServiceImpl) LoadUserByPhone(ctx context.Context, phone string) (*entities.User, error) { s.logger.Debug("根据手机号加载用户聚合根", zap.String("phone", phone)) user, err := s.userRepo.GetByPhone(ctx, phone) if err != nil { return nil, fmt.Errorf("用户不存在: %w", err) } // 验证业务规则 if err := s.ValidateBusinessRules(ctx, user); err != nil { s.logger.Warn("用户业务规则验证失败", zap.String("phone", phone), zap.Error(err), ) } return user, nil } // ================ 业务规则验证 ================ // ValidateBusinessRules 验证业务规则 func (s *UserAggregateServiceImpl) ValidateBusinessRules(ctx context.Context, user *entities.User) error { s.logger.Debug("验证用户业务规则", zap.String("user_id", user.ID)) // 1. 实体内部业务规则验证 if err := user.ValidateBusinessRules(); err != nil { return fmt.Errorf("实体业务规则验证失败: %w", err) } // 2. 跨聚合根业务规则验证 if err := s.validateCrossAggregateRules(ctx, user); err != nil { return fmt.Errorf("跨聚合根业务规则验证失败: %w", err) } // 3. 领域级业务规则验证 if err := s.validateDomainRules(ctx, user); err != nil { return fmt.Errorf("领域业务规则验证失败: %w", err) } return nil } // CheckInvariance 检查聚合根不变量 func (s *UserAggregateServiceImpl) CheckInvariance(ctx context.Context, user *entities.User) error { s.logger.Debug("检查用户聚合根不变量", zap.String("user_id", user.ID)) // 1. 检查手机号唯一性 exists, err := s.ExistsByPhone(ctx, user.Phone) if err != nil { return fmt.Errorf("检查手机号唯一性失败: %w", err) } if exists { // 检查是否是同一个用户 existingUser, err := s.LoadUserByPhone(ctx, user.Phone) if err != nil { return fmt.Errorf("获取现有用户失败: %w", err) } if existingUser.ID != user.ID { return fmt.Errorf("手机号已被其他用户使用") } } return nil } // validateCrossAggregateRules 验证跨聚合根业务规则 func (s *UserAggregateServiceImpl) validateCrossAggregateRules(ctx context.Context, user *entities.User) error { // 1. 检查手机号唯一性(排除自己) existingUser, err := s.userRepo.GetByPhone(ctx, user.Phone) if err == nil && existingUser.ID != user.ID { return fmt.Errorf("手机号已被其他用户使用") } return nil } // validateDomainRules 验证领域级业务规则 func (s *UserAggregateServiceImpl) validateDomainRules(ctx context.Context, user *entities.User) error { // 这里可以添加领域级的业务规则验证 // 比如:检查手机号是否在黑名单中、检查用户权限等 return nil } // ================ 查询方法 ================ // ExistsByPhone 检查手机号是否存在 func (s *UserAggregateServiceImpl) ExistsByPhone(ctx context.Context, phone string) (bool, error) { _, err := s.userRepo.GetByPhone(ctx, phone) if err != nil { return false, nil // 用户不存在,返回false } return true, nil } // ExistsByID 检查用户ID是否存在 func (s *UserAggregateServiceImpl) ExistsByID(ctx context.Context, userID string) (bool, error) { return s.userRepo.Exists(ctx, userID) } // GetUserByID 根据ID获取用户聚合根 func (s *UserAggregateServiceImpl) GetUserByID(ctx context.Context, userID string) (*entities.User, error) { return s.LoadUser(ctx, userID) } // UpdateLoginStats 更新用户登录统计 func (s *UserAggregateServiceImpl) UpdateLoginStats(ctx context.Context, userID string) error { user, err := s.LoadUser(ctx, userID) if err != nil { return fmt.Errorf("用户不存在: %w", err) } user.IncrementLoginCount() if err := s.SaveUser(ctx, user); err != nil { s.logger.Error("更新用户登录统计失败", zap.Error(err)) return fmt.Errorf("更新用户登录统计失败: %w", err) } s.logger.Info("用户登录统计更新成功", zap.String("user_id", userID)) return nil } // ================ 企业信息管理 ================ // CreateEnterpriseInfo 创建企业信息 func (s *UserAggregateServiceImpl) CreateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error { s.logger.Debug("创建企业信息", zap.String("user_id", userID)) // 1. 加载用户聚合根 user, err := s.LoadUser(ctx, userID) if err != nil { return fmt.Errorf("用户不存在: %w", err) } // 2. 检查是否已有企业信息 if user.HasEnterpriseInfo() { return fmt.Errorf("用户已有企业信息") } // 3. 检查统一社会信用代码唯一性 exists, err := s.CheckUnifiedSocialCodeExists(ctx, unifiedSocialCode, userID) if err != nil { return fmt.Errorf("检查统一社会信用代码失败: %w", err) } if exists { return fmt.Errorf("统一社会信用代码已被使用") } // 4. 使用聚合根方法创建企业信息 err = user.CreateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress) if err != nil { return fmt.Errorf("创建企业信息失败: %w", err) } // 5. 验证业务规则 if err := s.ValidateBusinessRules(ctx, user); err != nil { return fmt.Errorf("业务规则验证失败: %w", err) } // 6. 保存聚合根 err = s.SaveUser(ctx, user) if err != nil { s.logger.Error("保存用户聚合根失败", zap.Error(err)) return fmt.Errorf("保存企业信息失败: %w", err) } s.logger.Info("企业信息创建成功", zap.String("user_id", userID)) return nil } // UpdateEnterpriseInfo 更新企业信息 func (s *UserAggregateServiceImpl) UpdateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string) error { s.logger.Debug("更新企业信息", zap.String("user_id", userID)) // 1. 加载用户聚合根 user, err := s.LoadUser(ctx, userID) if err != nil { return fmt.Errorf("用户不存在: %w", err) } // 2. 检查是否有企业信息 if !user.HasEnterpriseInfo() { return fmt.Errorf("用户暂无企业信息") } // 3. 检查统一社会信用代码唯一性(排除自己) exists, err := s.CheckUnifiedSocialCodeExists(ctx, unifiedSocialCode, userID) if err != nil { return fmt.Errorf("检查统一社会信用代码失败: %w", err) } if exists { return fmt.Errorf("统一社会信用代码已被其他用户使用") } // 4. 使用聚合根方法更新企业信息 err = user.UpdateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress) if err != nil { return fmt.Errorf("更新企业信息失败: %w", err) } // 5. 验证业务规则 if err := s.ValidateBusinessRules(ctx, user); err != nil { return fmt.Errorf("业务规则验证失败: %w", err) } // 6. 保存聚合根 err = s.SaveUser(ctx, user) if err != nil { s.logger.Error("保存用户聚合根失败", zap.Error(err)) return fmt.Errorf("保存企业信息失败: %w", err) } s.logger.Info("企业信息更新成功", zap.String("user_id", userID)) return nil } // GetUserWithEnterpriseInfo 获取用户信息(包含企业信息) func (s *UserAggregateServiceImpl) GetUserWithEnterpriseInfo(ctx context.Context, userID string) (*entities.User, error) { s.logger.Debug("获取用户信息(包含企业信息)", zap.String("user_id", userID)) // 加载用户聚合根(包含企业信息) user, err := s.userRepo.GetByIDWithEnterpriseInfo(ctx, userID) if err != nil { return nil, fmt.Errorf("用户不存在: %w", err) } // 验证业务规则 if err := s.ValidateBusinessRules(ctx, &user); err != nil { s.logger.Warn("用户业务规则验证失败", zap.String("user_id", userID), zap.Error(err), ) } return &user, nil } // ValidateEnterpriseInfo 验证企业信息 func (s *UserAggregateServiceImpl) ValidateEnterpriseInfo(ctx context.Context, userID string) error { s.logger.Debug("验证企业信息", zap.String("user_id", userID)) // 1. 加载用户聚合根 user, err := s.LoadUser(ctx, userID) if err != nil { return fmt.Errorf("用户不存在: %w", err) } // 2. 使用聚合根方法验证企业信息 err = user.ValidateEnterpriseInfo() if err != nil { return fmt.Errorf("企业信息验证失败: %w", err) } return nil } // CheckUnifiedSocialCodeExists 检查统一社会信用代码是否存在 func (s *UserAggregateServiceImpl) CheckUnifiedSocialCodeExists(ctx context.Context, unifiedSocialCode string, excludeUserID string) (bool, error) { s.logger.Debug("检查统一社会信用代码是否存在", zap.String("unified_social_code", unifiedSocialCode), zap.String("exclude_user_id", excludeUserID), ) // 参数验证 if unifiedSocialCode == "" { return false, fmt.Errorf("统一社会信用代码不能为空") } // 通过用户仓库查询统一社会信用代码是否存在 exists, err := s.userRepo.ExistsByUnifiedSocialCode(ctx, unifiedSocialCode, excludeUserID) if err != nil { s.logger.Error("查询统一社会信用代码失败", zap.Error(err)) return false, fmt.Errorf("查询企业信息失败: %w", err) } if exists { s.logger.Info("统一社会信用代码已存在", zap.String("unified_social_code", unifiedSocialCode), zap.String("exclude_user_id", excludeUserID), ) } else { s.logger.Debug("统一社会信用代码不存在", zap.String("unified_social_code", unifiedSocialCode), ) } return exists, nil } // CreateOrUpdateEnterpriseInfo 认证域专用:写入/覆盖企业信息 func (s *UserAggregateServiceImpl) CreateOrUpdateEnterpriseInfo( ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress string, ) error { user, err := s.LoadUser(ctx, userID) if err != nil { return fmt.Errorf("用户不存在: %w", err) } if user.EnterpriseInfo == nil { enterpriseInfo, err := entities.NewEnterpriseInfo(userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress) if err != nil { return err } user.EnterpriseInfo = enterpriseInfo } else { err := user.EnterpriseInfo.UpdateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress) if err != nil { return err } } return s.SaveUser(ctx, user) } // CompleteCertification 完成认证 func (s *UserAggregateServiceImpl) CompleteCertification(ctx context.Context, userID string) error { user, err := s.LoadUser(ctx, userID) if err != nil { return fmt.Errorf("用户不存在: %w", err) } user.CompleteCertification() return s.SaveUser(ctx, user) } // ListUsers 获取用户列表 func (s *UserAggregateServiceImpl) ListUsers(ctx context.Context, query *queries.ListUsersQuery) ([]*entities.User, int64, error) { s.logger.Debug("获取用户列表", zap.Int("page", query.Page), zap.Int("page_size", query.PageSize), ) // 直接调用仓储层查询用户列表 users, total, err := s.userRepo.ListUsers(ctx, query) if err != nil { s.logger.Error("查询用户列表失败", zap.Error(err)) return nil, 0, fmt.Errorf("查询用户列表失败: %w", err) } s.logger.Info("用户列表查询成功", zap.Int("count", len(users)), zap.Int64("total", total), ) return users, total, nil } // GetUserStats 获取用户统计信息 func (s *UserAggregateServiceImpl) GetUserStats(ctx context.Context) (*repositories.UserStats, error) { s.logger.Debug("获取用户统计信息") // 直接调用仓储层查询用户统计信息 stats, err := s.userRepo.GetStats(ctx) if err != nil { s.logger.Error("查询用户统计信息失败", zap.Error(err)) return nil, fmt.Errorf("查询用户统计信息失败: %w", err) } s.logger.Info("用户统计信息查询成功", zap.Int64("total_users", stats.TotalUsers), zap.Int64("active_users", stats.ActiveUsers), zap.Int64("certified_users", stats.CertifiedUsers), ) return stats, nil } // ================ 私有方法 ================ // publishDomainEvents 发布领域事件 func (s *UserAggregateServiceImpl) publishDomainEvents(ctx context.Context, user *entities.User) error { events := user.GetDomainEvents() if len(events) == 0 { return nil } for _, event := range events { // 这里需要将领域事件转换为标准事件格式 // 暂时跳过,后续可以完善事件转换逻辑 s.logger.Debug("发布领域事件", zap.String("user_id", user.ID), zap.Any("event", event), ) } // 清除已发布的事件 user.ClearDomainEvents() return nil }