package product import ( "context" "go.uber.org/zap" "tyapi-server/internal/application/product/dto/commands" appQueries "tyapi-server/internal/application/product/dto/queries" "tyapi-server/internal/application/product/dto/responses" "tyapi-server/internal/domains/product/entities" repoQueries "tyapi-server/internal/domains/product/repositories/queries" product_service "tyapi-server/internal/domains/product/services" user_repositories "tyapi-server/internal/domains/user/repositories" ) // SubscriptionApplicationServiceImpl 订阅应用服务实现 // 负责业务流程编排、事务管理、数据转换,不直接操作仓库 type SubscriptionApplicationServiceImpl struct { productSubscriptionService *product_service.ProductSubscriptionService userRepo user_repositories.UserRepository logger *zap.Logger } // NewSubscriptionApplicationService 创建订阅应用服务 func NewSubscriptionApplicationService( productSubscriptionService *product_service.ProductSubscriptionService, userRepo user_repositories.UserRepository, logger *zap.Logger, ) SubscriptionApplicationService { return &SubscriptionApplicationServiceImpl{ productSubscriptionService: productSubscriptionService, userRepo: userRepo, logger: logger, } } // UpdateSubscriptionPrice 更新订阅价格 // 业务流程:1. 获取订阅 2. 更新价格 3. 保存订阅 func (s *SubscriptionApplicationServiceImpl) UpdateSubscriptionPrice(ctx context.Context, cmd *commands.UpdateSubscriptionPriceCommand) error { return s.productSubscriptionService.UpdateSubscriptionPrice(ctx, cmd.ID, cmd.Price) } // CreateSubscription 创建订阅 // 业务流程:1. 创建订阅 func (s *SubscriptionApplicationServiceImpl) CreateSubscription(ctx context.Context, cmd *commands.CreateSubscriptionCommand) error { _, err := s.productSubscriptionService.CreateSubscription(ctx, cmd.UserID, cmd.ProductID) return err } // GetSubscriptionByID 根据ID获取订阅 // 业务流程:1. 获取订阅信息 2. 构建响应数据 func (s *SubscriptionApplicationServiceImpl) GetSubscriptionByID(ctx context.Context, query *appQueries.GetSubscriptionQuery) (*responses.SubscriptionInfoResponse, error) { subscription, err := s.productSubscriptionService.GetSubscriptionByID(ctx, query.ID) if err != nil { return nil, err } return s.convertToSubscriptionInfoResponse(subscription), nil } // ListSubscriptions 获取订阅列表(管理员用) // 业务流程:1. 获取订阅列表 2. 构建响应数据 func (s *SubscriptionApplicationServiceImpl) ListSubscriptions(ctx context.Context, query *appQueries.ListSubscriptionsQuery) (*responses.SubscriptionListResponse, error) { repoQuery := &repoQueries.ListSubscriptionsQuery{ Page: query.Page, PageSize: query.PageSize, UserID: query.UserID, // 管理员可以按用户筛选 Keyword: query.Keyword, SortBy: query.SortBy, SortOrder: query.SortOrder, CompanyName: query.CompanyName, ProductName: query.ProductName, StartTime: query.StartTime, EndTime: query.EndTime, } subscriptions, total, err := s.productSubscriptionService.ListSubscriptions(ctx, repoQuery) if err != nil { return nil, err } items := make([]responses.SubscriptionInfoResponse, len(subscriptions)) for i := range subscriptions { resp := s.convertToSubscriptionInfoResponse(subscriptions[i]) if resp != nil { items[i] = *resp // 解引用指针 } } return &responses.SubscriptionListResponse{ Total: total, Page: query.Page, Size: query.PageSize, Items: items, }, nil } // ListMySubscriptions 获取我的订阅列表(用户用) // 业务流程:1. 获取用户订阅列表 2. 构建响应数据 func (s *SubscriptionApplicationServiceImpl) ListMySubscriptions(ctx context.Context, userID string, query *appQueries.ListSubscriptionsQuery) (*responses.SubscriptionListResponse, error) { repoQuery := &repoQueries.ListSubscriptionsQuery{ Page: query.Page, PageSize: query.PageSize, UserID: userID, // 强制设置为当前用户ID Keyword: query.Keyword, SortBy: query.SortBy, SortOrder: query.SortOrder, CompanyName: query.CompanyName, ProductName: query.ProductName, StartTime: query.StartTime, EndTime: query.EndTime, } subscriptions, total, err := s.productSubscriptionService.ListSubscriptions(ctx, repoQuery) if err != nil { return nil, err } items := make([]responses.SubscriptionInfoResponse, len(subscriptions)) for i := range subscriptions { resp := s.convertToSubscriptionInfoResponse(subscriptions[i]) if resp != nil { items[i] = *resp // 解引用指针 } } return &responses.SubscriptionListResponse{ Total: total, Page: query.Page, Size: query.PageSize, Items: items, }, nil } // GetUserSubscriptions 获取用户订阅 // 业务流程:1. 获取用户订阅 2. 构建响应数据 func (s *SubscriptionApplicationServiceImpl) GetUserSubscriptions(ctx context.Context, query *appQueries.GetUserSubscriptionsQuery) ([]*responses.SubscriptionInfoResponse, error) { subscriptions, err := s.productSubscriptionService.GetUserSubscriptions(ctx, query.UserID) if err != nil { return nil, err } // 转换为响应对象 items := make([]*responses.SubscriptionInfoResponse, len(subscriptions)) for i := range subscriptions { items[i] = s.convertToSubscriptionInfoResponse(subscriptions[i]) } return items, nil } // GetProductSubscriptions 获取产品订阅 // 业务流程:1. 获取产品订阅 2. 构建响应数据 func (s *SubscriptionApplicationServiceImpl) GetProductSubscriptions(ctx context.Context, query *appQueries.GetProductSubscriptionsQuery) ([]*responses.SubscriptionInfoResponse, error) { // 这里需要扩展领域服务来支持按产品查询订阅 // 暂时返回空列表 return []*responses.SubscriptionInfoResponse{}, nil } // GetSubscriptionUsage 获取订阅使用情况 // 业务流程:1. 获取订阅使用情况 2. 构建响应数据 func (s *SubscriptionApplicationServiceImpl) GetSubscriptionUsage(ctx context.Context, subscriptionID string) (*responses.SubscriptionUsageResponse, error) { subscription, err := s.productSubscriptionService.GetSubscriptionByID(ctx, subscriptionID) if err != nil { return nil, err } return &responses.SubscriptionUsageResponse{ ID: subscription.ID, ProductID: subscription.ProductID, APIUsed: subscription.APIUsed, }, nil } // GetSubscriptionStats 获取订阅统计信息 // 业务流程:1. 获取订阅统计 2. 构建响应数据 func (s *SubscriptionApplicationServiceImpl) GetSubscriptionStats(ctx context.Context) (*responses.SubscriptionStatsResponse, error) { stats, err := s.productSubscriptionService.GetSubscriptionStats(ctx) if err != nil { return nil, err } return &responses.SubscriptionStatsResponse{ TotalSubscriptions: stats["total_subscriptions"].(int64), TotalRevenue: stats["total_revenue"].(float64), }, nil } // GetMySubscriptionStats 获取我的订阅统计信息 // 业务流程:1. 获取用户订阅统计 2. 构建响应数据 func (s *SubscriptionApplicationServiceImpl) GetMySubscriptionStats(ctx context.Context, userID string) (*responses.SubscriptionStatsResponse, error) { stats, err := s.productSubscriptionService.GetUserSubscriptionStats(ctx, userID) if err != nil { return nil, err } return &responses.SubscriptionStatsResponse{ TotalSubscriptions: stats["total_subscriptions"].(int64), TotalRevenue: stats["total_revenue"].(float64), }, nil } // convertToSubscriptionInfoResponse 转换为订阅信息响应 func (s *SubscriptionApplicationServiceImpl) convertToSubscriptionInfoResponse(subscription *entities.Subscription) *responses.SubscriptionInfoResponse { // 查询用户信息 var userInfo *responses.UserSimpleResponse if subscription.UserID != "" { user, err := s.userRepo.GetByIDWithEnterpriseInfo(context.Background(), subscription.UserID) if err == nil { companyName := "未知公司" if user.EnterpriseInfo != nil { companyName = user.EnterpriseInfo.CompanyName } userInfo = &responses.UserSimpleResponse{ ID: user.ID, CompanyName: companyName, Phone: user.Phone, } } } return &responses.SubscriptionInfoResponse{ ID: subscription.ID, UserID: subscription.UserID, ProductID: subscription.ProductID, Price: subscription.Price.InexactFloat64(), User: userInfo, Product: s.convertToProductSimpleResponse(subscription.Product), APIUsed: subscription.APIUsed, CreatedAt: subscription.CreatedAt, UpdatedAt: subscription.UpdatedAt, } } // convertToProductSimpleResponse 转换为产品简单信息响应 func (s *SubscriptionApplicationServiceImpl) convertToProductSimpleResponse(product *entities.Product) *responses.ProductSimpleResponse { return &responses.ProductSimpleResponse{ ID: product.ID, Name: product.Name, Code: product.Code, Description: product.Description, Price: product.Price.InexactFloat64(), Category: s.convertToCategorySimpleResponse(product.Category), IsPackage: product.IsPackage, } } // convertToCategorySimpleResponse 转换为分类简单信息响应 func (s *SubscriptionApplicationServiceImpl) convertToCategorySimpleResponse(category *entities.ProductCategory) *responses.CategorySimpleResponse { return &responses.CategorySimpleResponse{ ID: category.ID, Name: category.Name, } }