fix
This commit is contained in:
430
backend-old/internal/api/handlers/category_handler.go
Normal file
430
backend-old/internal/api/handlers/category_handler.go
Normal file
@ -0,0 +1,430 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"photography-backend/internal/model/entity"
|
||||
"photography-backend/internal/model/dto"
|
||||
"photography-backend/internal/service"
|
||||
"photography-backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type CategoryHandler struct {
|
||||
categoryService *service.CategoryService
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func NewCategoryHandler(categoryService *service.CategoryService, logger *zap.Logger) *CategoryHandler {
|
||||
return &CategoryHandler{
|
||||
categoryService: categoryService,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// GetCategories 获取分类列表
|
||||
// @Summary 获取分类列表
|
||||
// @Description 获取分类列表,可指定父分类
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param parent_id query int false "父分类ID"
|
||||
// @Success 200 {array} models.Category
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories [get]
|
||||
func (h *CategoryHandler) GetCategories(c *gin.Context) {
|
||||
var parentID *uint
|
||||
if parentIDStr := c.Query("parent_id"); parentIDStr != "" {
|
||||
id, err := strconv.ParseUint(parentIDStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, response.Error(http.StatusBadRequest, "Parent ID must be a valid number"))
|
||||
return
|
||||
}
|
||||
parentIDUint := uint(id)
|
||||
parentID = &parentIDUint
|
||||
}
|
||||
|
||||
categories, err := h.categoryService.GetCategories(c.Request.Context(), parentID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get categories", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error(http.StatusInternalServerError, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, categories)
|
||||
}
|
||||
|
||||
// GetCategoryTree 获取分类树
|
||||
// @Summary 获取分类树
|
||||
// @Description 获取完整的分类树结构
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {array} models.CategoryTree
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories/tree [get]
|
||||
func (h *CategoryHandler) GetCategoryTree(c *gin.Context) {
|
||||
tree, err := h.categoryService.GetCategoryTree(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get category tree", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error{
|
||||
Error: "Failed to get category tree",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, tree)
|
||||
}
|
||||
|
||||
// GetCategory 获取分类详情
|
||||
// @Summary 获取分类详情
|
||||
// @Description 根据ID获取分类详情
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "分类ID"
|
||||
// @Success 200 {object} models.Category
|
||||
// @Failure 400 {object} response.Error
|
||||
// @Failure 404 {object} response.Error
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories/{id} [get]
|
||||
func (h *CategoryHandler) GetCategory(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid category ID",
|
||||
Message: "Category ID must be a valid number",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
category, err := h.categoryService.GetCategoryByID(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
if err.Error() == "category not found" {
|
||||
c.JSON(http.StatusNotFound, response.Error{
|
||||
Error: "Category not found",
|
||||
Message: "The requested category does not exist",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Error("Failed to get category", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error{
|
||||
Error: "Failed to get category",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, category)
|
||||
}
|
||||
|
||||
// GetCategoryBySlug 根据slug获取分类
|
||||
// @Summary 根据slug获取分类
|
||||
// @Description 根据slug获取分类详情
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param slug path string true "分类slug"
|
||||
// @Success 200 {object} models.Category
|
||||
// @Failure 404 {object} response.Error
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories/slug/{slug} [get]
|
||||
func (h *CategoryHandler) GetCategoryBySlug(c *gin.Context) {
|
||||
slug := c.Param("slug")
|
||||
|
||||
category, err := h.categoryService.GetCategoryBySlug(c.Request.Context(), slug)
|
||||
if err != nil {
|
||||
if err.Error() == "category not found" {
|
||||
c.JSON(http.StatusNotFound, response.Error{
|
||||
Error: "Category not found",
|
||||
Message: "The requested category does not exist",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Error("Failed to get category by slug", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error{
|
||||
Error: "Failed to get category",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, category)
|
||||
}
|
||||
|
||||
// CreateCategory 创建分类
|
||||
// @Summary 创建分类
|
||||
// @Description 创建新的分类
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param category body models.CreateCategoryRequest true "分类信息"
|
||||
// @Success 201 {object} models.Category
|
||||
// @Failure 400 {object} response.Error
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories [post]
|
||||
func (h *CategoryHandler) CreateCategory(c *gin.Context) {
|
||||
var req entity.CreateCategoryRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Failed to bind JSON", zap.Error(err))
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid request body",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 验证请求数据
|
||||
if err := h.validateCreateCategoryRequest(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid request data",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
category, err := h.categoryService.CreateCategory(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to create category", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error{
|
||||
Error: "Failed to create category",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, category)
|
||||
}
|
||||
|
||||
// UpdateCategory 更新分类
|
||||
// @Summary 更新分类
|
||||
// @Description 更新分类信息
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "分类ID"
|
||||
// @Param category body models.UpdateCategoryRequest true "分类信息"
|
||||
// @Success 200 {object} models.Category
|
||||
// @Failure 400 {object} response.Error
|
||||
// @Failure 404 {object} response.Error
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories/{id} [put]
|
||||
func (h *CategoryHandler) UpdateCategory(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid category ID",
|
||||
Message: "Category ID must be a valid number",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req entity.UpdateCategoryRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Failed to bind JSON", zap.Error(err))
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid request body",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
category, err := h.categoryService.UpdateCategory(c.Request.Context(), uint(id), &req)
|
||||
if err != nil {
|
||||
if err.Error() == "category not found" {
|
||||
c.JSON(http.StatusNotFound, response.Error{
|
||||
Error: "Category not found",
|
||||
Message: "The requested category does not exist",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Error("Failed to update category", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error{
|
||||
Error: "Failed to update category",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, category)
|
||||
}
|
||||
|
||||
// DeleteCategory 删除分类
|
||||
// @Summary 删除分类
|
||||
// @Description 删除分类
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "分类ID"
|
||||
// @Success 204 "No Content"
|
||||
// @Failure 400 {object} response.Error
|
||||
// @Failure 404 {object} response.Error
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories/{id} [delete]
|
||||
func (h *CategoryHandler) DeleteCategory(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid category ID",
|
||||
Message: "Category ID must be a valid number",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err = h.categoryService.DeleteCategory(c.Request.Context(), uint(id))
|
||||
if err != nil {
|
||||
if err.Error() == "category not found" {
|
||||
c.JSON(http.StatusNotFound, response.Error{
|
||||
Error: "Category not found",
|
||||
Message: "The requested category does not exist",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Error("Failed to delete category", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error{
|
||||
Error: "Failed to delete category",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// ReorderCategories 重新排序分类
|
||||
// @Summary 重新排序分类
|
||||
// @Description 重新排序分类
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body models.ReorderCategoriesRequest true "排序请求"
|
||||
// @Success 200 {object} models.SuccessResponse
|
||||
// @Failure 400 {object} response.Error
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories/reorder [post]
|
||||
func (h *CategoryHandler) ReorderCategories(c *gin.Context) {
|
||||
var req entity.ReorderCategoriesRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Failed to bind JSON", zap.Error(err))
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid request body",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.CategoryIDs) == 0 {
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid request",
|
||||
Message: "No category IDs provided",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := h.categoryService.ReorderCategories(c.Request.Context(), req.ParentID, req.CategoryIDs)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to reorder categories", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error{
|
||||
Error: "Failed to reorder categories",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, entity.SuccessResponse{
|
||||
Message: "Categories reordered successfully",
|
||||
})
|
||||
}
|
||||
|
||||
// GetCategoryStats 获取分类统计信息
|
||||
// @Summary 获取分类统计信息
|
||||
// @Description 获取分类统计信息
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} models.CategoryStats
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories/stats [get]
|
||||
func (h *CategoryHandler) GetCategoryStats(c *gin.Context) {
|
||||
stats, err := h.categoryService.GetCategoryStats(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get category stats", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error{
|
||||
Error: "Failed to get category stats",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, stats)
|
||||
}
|
||||
|
||||
// GenerateSlug 生成分类slug
|
||||
// @Summary 生成分类slug
|
||||
// @Description 根据分类名称生成唯一的slug
|
||||
// @Tags categories
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body models.GenerateSlugRequest true "生成slug请求"
|
||||
// @Success 200 {object} models.GenerateSlugResponse
|
||||
// @Failure 400 {object} response.Error
|
||||
// @Failure 500 {object} response.Error
|
||||
// @Router /categories/generate-slug [post]
|
||||
func (h *CategoryHandler) GenerateSlug(c *gin.Context) {
|
||||
var req entity.GenerateSlugRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Failed to bind JSON", zap.Error(err))
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid request body",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name == "" {
|
||||
c.JSON(http.StatusBadRequest, response.Error{
|
||||
Error: "Invalid request",
|
||||
Message: "Name is required",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
slug, err := h.categoryService.GenerateSlug(c.Request.Context(), req.Name)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to generate slug", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, response.Error{
|
||||
Error: "Failed to generate slug",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, entity.GenerateSlugResponse{
|
||||
Slug: slug,
|
||||
})
|
||||
}
|
||||
|
||||
// validateCreateCategoryRequest 验证创建分类请求
|
||||
func (h *CategoryHandler) validateCreateCategoryRequest(req *models.CreateCategoryRequest) error {
|
||||
if req.Name == "" {
|
||||
return errors.New("name is required")
|
||||
}
|
||||
|
||||
if req.Slug == "" {
|
||||
return errors.New("slug is required")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user