Files
photography/backend/internal/service/category_service.go
xujiang 39a42695d3 refactor: 重构后端架构为 go-zero 框架,优化项目结构
主要变更:
- 采用 go-zero 框架替代 Gin,提升开发效率
- 重构项目结构,API 文件模块化组织
- 将 model 移至 api/internal/model 目录
- 移除 common 包,改为标准 pkg 目录结构
- 实现统一的仓储模式,支持配置驱动数据库切换
- 简化测试策略,专注 API 集成测试
- 更新 CLAUDE.md 文档,提供详细的开发指导

技术栈更新:
- 框架: Gin → go-zero v1.6.0+
- 代码生成: 引入 goctl 工具
- 架构模式: 四层架构 → go-zero 三层架构 (Handler→Logic→Model)
- 项目布局: 遵循 Go 社区标准和 go-zero 最佳实践
2025-07-10 15:05:52 +08:00

233 lines
6.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}