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 }