package service import ( "context" "errors" "photography-backend/internal/model/entity" "photography-backend/internal/repository/interfaces" "go.uber.org/zap" ) type CategoryService struct { categoryRepo interfaces.CategoryRepository logger *zap.Logger } func NewCategoryService(categoryRepo interfaces.CategoryRepository, logger *zap.Logger) *CategoryService { return &CategoryService{ categoryRepo: categoryRepo, logger: logger, } } // GetCategories 获取分类列表 func (s *CategoryService) GetCategories(ctx context.Context, parentID *uint) ([]*entity.Category, error) { categories, err := s.categoryRepo.List(ctx, parentID) if err != nil { s.logger.Error("Failed to get categories", zap.Error(err)) return nil, err } return categories, nil } // GetCategoryTree 获取分类树 func (s *CategoryService) GetCategoryTree(ctx context.Context) ([]*entity.CategoryTree, error) { tree, err := s.categoryRepo.GetTree(ctx) if err != nil { s.logger.Error("Failed to get category tree", zap.Error(err)) return nil, err } return tree, nil } // GetCategoryByID 根据ID获取分类 func (s *CategoryService) GetCategoryByID(ctx context.Context, id uint) (*entity.Category, error) { category, err := s.categoryRepo.GetByID(ctx, id) if err != nil { s.logger.Error("Failed to get category by ID", zap.Error(err), zap.Uint("id", id)) return nil, err } return category, nil } // GetCategoryBySlug 根据slug获取分类 func (s *CategoryService) GetCategoryBySlug(ctx context.Context, slug string) (*entity.Category, error) { category, err := s.categoryRepo.GetBySlug(ctx, slug) if err != nil { s.logger.Error("Failed to get category by slug", zap.Error(err), zap.String("slug", slug)) return nil, err } return category, nil } // CreateCategory 创建分类 func (s *CategoryService) CreateCategory(ctx context.Context, req *entity.CreateCategoryRequest) (*entity.Category, error) { // 验证slug唯一性 if err := s.categoryRepo.ValidateSlugUnique(ctx, req.Slug, 0); err != nil { return nil, err } // 验证父分类存在性 if req.ParentID != nil { if err := s.categoryRepo.ValidateParentCategory(ctx, 0, *req.ParentID); err != nil { return nil, err } } // 获取排序顺序 sortOrder, err := s.categoryRepo.GetNextSortOrder(ctx, req.ParentID) if err != nil { return nil, err } category := &entity.Category{ Name: req.Name, Slug: req.Slug, Description: req.Description, ParentID: req.ParentID, SortOrder: sortOrder, IsActive: true, } if err := s.categoryRepo.Create(ctx, category); err != nil { s.logger.Error("Failed to create category", zap.Error(err)) return nil, err } s.logger.Info("Category created successfully", zap.Uint("id", category.ID)) return category, nil } // UpdateCategory 更新分类 func (s *CategoryService) UpdateCategory(ctx context.Context, id uint, req *entity.UpdateCategoryRequest) (*entity.Category, error) { // 检查分类是否存在 category, err := s.categoryRepo.GetByID(ctx, id) if err != nil { s.logger.Error("Failed to get category", zap.Error(err), zap.Uint("id", id)) return nil, err } // 验证slug唯一性 if req.Slug != nil && *req.Slug != category.Slug { if err := s.categoryRepo.ValidateSlugUnique(ctx, *req.Slug, id); err != nil { return nil, err } } // 验证父分类(防止循环引用) if req.ParentID != nil { // 检查是否有变更 if (category.ParentID == nil && *req.ParentID != 0) || (category.ParentID != nil && *req.ParentID != *category.ParentID) { if err := s.categoryRepo.ValidateParentCategory(ctx, id, *req.ParentID); err != nil { return nil, err } } } // 更新字段 if req.Name != nil { category.Name = *req.Name } if req.Slug != nil { category.Slug = *req.Slug } if req.Description != nil { category.Description = *req.Description } if req.ParentID != nil { if *req.ParentID == 0 { category.ParentID = nil } else { category.ParentID = req.ParentID } } if req.SortOrder != nil { category.SortOrder = *req.SortOrder } if req.IsActive != nil { category.IsActive = *req.IsActive } // 保存更新 if err := s.categoryRepo.Update(ctx, category); err != nil { s.logger.Error("Failed to update category", zap.Error(err)) return nil, err } s.logger.Info("Category updated successfully", zap.Uint("id", id)) return category, nil } // DeleteCategory 删除分类 func (s *CategoryService) DeleteCategory(ctx context.Context, id uint) error { // 检查分类是否存在 _, err := s.categoryRepo.GetByID(ctx, id) if err != nil { s.logger.Error("Failed to get category", zap.Error(err), zap.Uint("id", id)) return err } // 检查是否有子分类 children, err := s.categoryRepo.GetChildren(ctx, id) if err != nil { return err } if len(children) > 0 { return errors.New("cannot delete category with subcategories") } // 直接删除分类,在Repository层检查照片关联 if err := s.categoryRepo.Delete(ctx, id); err != nil { s.logger.Error("Failed to delete category", zap.Error(err)) return err } s.logger.Info("Category deleted successfully", zap.Uint("id", id)) return nil } // ReorderCategories 重新排序分类 func (s *CategoryService) ReorderCategories(ctx context.Context, parentID *uint, categoryIDs []uint) error { if len(categoryIDs) == 0 { return nil } // 重新排序分类 if err := s.categoryRepo.Reorder(ctx, parentID, categoryIDs); err != nil { s.logger.Error("Failed to reorder categories", zap.Error(err)) return err } s.logger.Info("Categories reordered successfully", zap.Int("count", len(categoryIDs))) return nil } // GetCategoryStats 获取分类统计信息 func (s *CategoryService) GetCategoryStats(ctx context.Context) (*entity.CategoryStats, error) { stats, err := s.categoryRepo.GetStats(ctx) if err != nil { s.logger.Error("Failed to get category stats", zap.Error(err)) return nil, err } return stats, nil } // GenerateSlug 生成唯一slug func (s *CategoryService) GenerateSlug(ctx context.Context, name string) (string, error) { slug, err := s.categoryRepo.GenerateUniqueSlug(ctx, name) if err != nil { s.logger.Error("Failed to generate unique slug", zap.Error(err)) return "", err } return slug, nil }