| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | //nolint:unused | 
					
						
							|  |  |  |  | package handlers | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"tyapi-server/internal/application/article" | 
					
						
							|  |  |  |  | 	"tyapi-server/internal/application/article/dto/commands" | 
					
						
							|  |  |  |  | 	appQueries "tyapi-server/internal/application/article/dto/queries" | 
					
						
							|  |  |  |  | 	_ "tyapi-server/internal/application/article/dto/responses" | 
					
						
							|  |  |  |  | 	"tyapi-server/internal/shared/interfaces" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	"github.com/gin-gonic/gin" | 
					
						
							|  |  |  |  | 	"go.uber.org/zap" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ArticleHandler 文章HTTP处理器 | 
					
						
							|  |  |  |  | type ArticleHandler struct { | 
					
						
							|  |  |  |  | 	appService      article.ArticleApplicationService | 
					
						
							|  |  |  |  | 	responseBuilder interfaces.ResponseBuilder | 
					
						
							|  |  |  |  | 	validator       interfaces.RequestValidator | 
					
						
							|  |  |  |  | 	logger          *zap.Logger | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // NewArticleHandler 创建文章HTTP处理器 | 
					
						
							|  |  |  |  | func NewArticleHandler( | 
					
						
							|  |  |  |  | 	appService article.ArticleApplicationService, | 
					
						
							|  |  |  |  | 	responseBuilder interfaces.ResponseBuilder, | 
					
						
							|  |  |  |  | 	validator interfaces.RequestValidator, | 
					
						
							|  |  |  |  | 	logger *zap.Logger, | 
					
						
							|  |  |  |  | ) *ArticleHandler { | 
					
						
							|  |  |  |  | 	return &ArticleHandler{ | 
					
						
							|  |  |  |  | 		appService:      appService, | 
					
						
							|  |  |  |  | 		responseBuilder: responseBuilder, | 
					
						
							|  |  |  |  | 		validator:       validator, | 
					
						
							|  |  |  |  | 		logger:          logger, | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // CreateArticle 创建文章 | 
					
						
							|  |  |  |  | // @Summary 创建文章 | 
					
						
							|  |  |  |  | // @Description 创建新的文章 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param request body commands.CreateArticleCommand true "创建文章请求" | 
					
						
							|  |  |  |  | // @Success 201 {object} map[string]interface{} "文章创建成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Router /api/v1/admin/articles [post] | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | func (h *ArticleHandler) CreateArticle(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.CreateArticleCommand | 
					
						
							|  |  |  |  | 	if err := h.validator.BindAndValidate(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	// 验证用户是否已登录 | 
					
						
							|  |  |  |  | 	if _, exists := c.Get("user_id"); !exists { | 
					
						
							|  |  |  |  | 		h.responseBuilder.Unauthorized(c, "用户未登录") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.CreateArticle(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("创建文章失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Created(c, nil, "文章创建成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GetArticleByID 获取文章详情 | 
					
						
							|  |  |  |  | // @Summary 获取文章详情 | 
					
						
							|  |  |  |  | // @Description 根据ID获取文章详情 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-用户端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Param id path string true "文章ID" | 
					
						
							|  |  |  |  | // @Success 200 {object} responses.ArticleInfoResponse "获取文章详情成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "文章不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/articles/{id} [get] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) GetArticleByID(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var query appQueries.GetArticleQuery | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 绑定URI参数(文章ID) | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &query); err != nil { | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	response, err := h.appService.GetArticleByID(c.Request.Context(), &query) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("获取文章详情失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.NotFound(c, "文章不存在") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, response, "获取文章详情成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ListArticles 获取文章列表 | 
					
						
							|  |  |  |  | // @Summary 获取文章列表 | 
					
						
							|  |  |  |  | // @Description 分页获取文章列表,支持多种筛选条件 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-用户端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Param page query int false "页码" default(1) | 
					
						
							|  |  |  |  | // @Param page_size query int false "每页数量" default(10) | 
					
						
							|  |  |  |  | // @Param status query string false "文章状态" | 
					
						
							|  |  |  |  | // @Param category_id query string false "分类ID" | 
					
						
							|  |  |  |  | // @Param tag_id query string false "标签ID" | 
					
						
							|  |  |  |  | // @Param title query string false "标题关键词" | 
					
						
							|  |  |  |  | // @Param summary query string false "摘要关键词" | 
					
						
							|  |  |  |  | // @Param is_featured query bool false "是否推荐" | 
					
						
							|  |  |  |  | // @Param order_by query string false "排序字段" | 
					
						
							|  |  |  |  | // @Param order_dir query string false "排序方向" | 
					
						
							|  |  |  |  | // @Success 200 {object} responses.ArticleListResponse "获取文章列表成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/articles [get] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) ListArticles(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var query appQueries.ListArticleQuery | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateQuery(c, &query); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	// 设置默认值 | 
					
						
							|  |  |  |  | 	if query.Page <= 0 { | 
					
						
							|  |  |  |  | 		query.Page = 1 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if query.PageSize <= 0 { | 
					
						
							|  |  |  |  | 		query.PageSize = 10 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if query.PageSize > 100 { | 
					
						
							|  |  |  |  | 		query.PageSize = 100 | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	response, err := h.appService.ListArticles(c.Request.Context(), &query) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("获取文章列表失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.InternalError(c, "获取文章列表失败") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, response, "获取文章列表成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 21:15:15 +08:00
										 |  |  |  | // ListArticlesForAdmin 获取文章列表(管理员端) | 
					
						
							|  |  |  |  | // @Summary 获取文章列表(管理员端) | 
					
						
							|  |  |  |  | // @Description 分页获取文章列表,支持多种筛选条件,包含所有状态的文章 | 
					
						
							|  |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							|  |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param page query int false "页码" default(1) | 
					
						
							|  |  |  |  | // @Param page_size query int false "每页数量" default(10) | 
					
						
							|  |  |  |  | // @Param status query string false "文章状态" | 
					
						
							|  |  |  |  | // @Param category_id query string false "分类ID" | 
					
						
							|  |  |  |  | // @Param tag_id query string false "标签ID" | 
					
						
							|  |  |  |  | // @Param title query string false "标题关键词" | 
					
						
							|  |  |  |  | // @Param summary query string false "摘要关键词" | 
					
						
							|  |  |  |  | // @Param is_featured query bool false "是否推荐" | 
					
						
							|  |  |  |  | // @Param order_by query string false "排序字段" | 
					
						
							|  |  |  |  | // @Param order_dir query string false "排序方向" | 
					
						
							|  |  |  |  | // @Success 200 {object} responses.ArticleListResponse "获取文章列表成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/articles [get] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) ListArticlesForAdmin(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var query appQueries.ListArticleQuery | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateQuery(c, &query); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 21:15:15 +08:00
										 |  |  |  | 	// 设置默认值 | 
					
						
							|  |  |  |  | 	if query.Page <= 0 { | 
					
						
							|  |  |  |  | 		query.Page = 1 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if query.PageSize <= 0 { | 
					
						
							|  |  |  |  | 		query.PageSize = 10 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if query.PageSize > 100 { | 
					
						
							|  |  |  |  | 		query.PageSize = 100 | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 21:15:15 +08:00
										 |  |  |  | 	response, err := h.appService.ListArticlesForAdmin(c.Request.Context(), &query) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("获取文章列表失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.InternalError(c, "获取文章列表失败") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 21:15:15 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, response, "获取文章列表成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // UpdateArticle 更新文章 | 
					
						
							|  |  |  |  | // @Summary 更新文章 | 
					
						
							|  |  |  |  | // @Description 更新文章信息 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "文章ID" | 
					
						
							|  |  |  |  | // @Param request body commands.UpdateArticleCommand true "更新文章请求" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "文章更新成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "文章不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Router /api/v1/admin/articles/{id} [put] | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | func (h *ArticleHandler) UpdateArticle(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.UpdateArticleCommand | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 先绑定URI参数(文章ID) | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 再绑定JSON请求体(文章信息) | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.validator.BindAndValidate(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.UpdateArticle(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("更新文章失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "文章更新成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // DeleteArticle 删除文章 | 
					
						
							|  |  |  |  | // @Summary 删除文章 | 
					
						
							|  |  |  |  | // @Description 删除指定文章 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "文章ID" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "文章删除成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "文章不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Router /api/v1/admin/articles/{id} [delete] | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | func (h *ArticleHandler) DeleteArticle(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.DeleteArticleCommand | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.DeleteArticle(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("删除文章失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "文章删除成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // PublishArticle 发布文章 | 
					
						
							|  |  |  |  | // @Summary 发布文章 | 
					
						
							|  |  |  |  | // @Description 将草稿文章发布 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "文章ID" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "文章发布成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "文章不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Router /api/v1/admin/articles/{id}/publish [post] | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | func (h *ArticleHandler) PublishArticle(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.PublishArticleCommand | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.PublishArticle(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("发布文章失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "文章发布成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // SchedulePublishArticle 定时发布文章 | 
					
						
							|  |  |  |  | // @Summary 定时发布文章 | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | // @Description 设置文章的定时发布时间,支持格式:YYYY-MM-DD HH:mm:ss | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "文章ID" | 
					
						
							|  |  |  |  | // @Param request body commands.SchedulePublishCommand true "定时发布请求" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "定时发布设置成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "文章不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/articles/{id}/schedule-publish [post] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) SchedulePublishArticle(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.SchedulePublishCommand | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 先绑定URI参数(文章ID) | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 再绑定JSON请求体(定时发布时间) | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.validator.BindAndValidate(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.SchedulePublishArticle(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("设置定时发布失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "定时发布设置成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | // CancelSchedulePublishArticle 取消定时发布文章 | 
					
						
							|  |  |  |  | // @Summary 取消定时发布文章 | 
					
						
							|  |  |  |  | // @Description 取消文章的定时发布设置 | 
					
						
							|  |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							|  |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "文章ID" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "取消定时发布成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "文章不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/articles/{id}/cancel-schedule [post] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) CancelSchedulePublishArticle(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.CancelScheduleCommand | 
					
						
							|  |  |  |  | 	 | 
					
						
							|  |  |  |  | 	// 绑定URI参数(文章ID) | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	 | 
					
						
							|  |  |  |  | 	if err := h.appService.CancelSchedulePublishArticle(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("取消定时发布失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	 | 
					
						
							|  |  |  |  | 	h.responseBuilder.Success(c, nil, "取消定时发布成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // ArchiveArticle 归档文章 | 
					
						
							|  |  |  |  | // @Summary 归档文章 | 
					
						
							|  |  |  |  | // @Description 将已发布文章归档 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "文章ID" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "文章归档成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "文章不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Router /api/v1/admin/articles/{id}/archive [post] | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | func (h *ArticleHandler) ArchiveArticle(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.ArchiveArticleCommand | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.ArchiveArticle(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("归档文章失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "文章归档成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // SetFeatured 设置推荐状态 | 
					
						
							|  |  |  |  | // @Summary 设置推荐状态 | 
					
						
							|  |  |  |  | // @Description 设置文章的推荐状态 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "文章ID" | 
					
						
							|  |  |  |  | // @Param request body commands.SetFeaturedCommand true "设置推荐状态请求" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "设置推荐状态成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "文章不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Router /api/v1/admin/articles/{id}/featured [put] | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | func (h *ArticleHandler) SetFeatured(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.SetFeaturedCommand | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 先绑定URI参数(文章ID) | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 再绑定JSON请求体(推荐状态) | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.validator.BindAndValidate(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.SetFeatured(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("设置推荐状态失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "设置推荐状态成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GetArticleStats 获取文章统计 | 
					
						
							|  |  |  |  | // @Summary 获取文章统计 | 
					
						
							|  |  |  |  | // @Description 获取文章相关统计数据 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Success 200 {object} responses.ArticleStatsResponse "获取统计成功" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/articles/stats [get] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) GetArticleStats(c *gin.Context) { | 
					
						
							|  |  |  |  | 	response, err := h.appService.GetArticleStats(c.Request.Context()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("获取文章统计失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.InternalError(c, "获取文章统计失败") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, response, "获取统计成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-03 13:51:52 +08:00
										 |  |  |  | // UpdateSchedulePublishArticle 修改定时发布时间 | 
					
						
							|  |  |  |  | // @Summary 修改定时发布时间 | 
					
						
							|  |  |  |  | // @Description 修改文章的定时发布时间 | 
					
						
							|  |  |  |  | // @Tags 文章管理-管理端 | 
					
						
							|  |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "文章ID" | 
					
						
							|  |  |  |  | // @Param request body commands.SchedulePublishCommand true "修改定时发布请求" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "修改定时发布时间成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "文章不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/articles/{id}/update-schedule-publish [post] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) UpdateSchedulePublishArticle(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.SchedulePublishCommand | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 先绑定URI参数(文章ID) | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 再绑定JSON请求体(定时发布时间) | 
					
						
							|  |  |  |  | 	if err := h.validator.BindAndValidate(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if err := h.appService.UpdateSchedulePublishArticle(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("修改定时发布时间失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	h.responseBuilder.Success(c, nil, "修改定时发布时间成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // ==================== 分类相关方法 ==================== | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ListCategories 获取分类列表 | 
					
						
							|  |  |  |  | // @Summary 获取分类列表 | 
					
						
							|  |  |  |  | // @Description 获取所有文章分类 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章分类-用户端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Success 200 {object} responses.CategoryListResponse "获取分类列表成功" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/article-categories [get] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) ListCategories(c *gin.Context) { | 
					
						
							|  |  |  |  | 	response, err := h.appService.ListCategories(c.Request.Context()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("获取分类列表失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.InternalError(c, "获取分类列表失败") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, response, "获取分类列表成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GetCategoryByID 获取分类详情 | 
					
						
							|  |  |  |  | // @Summary 获取分类详情 | 
					
						
							|  |  |  |  | // @Description 根据ID获取分类详情 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章分类-用户端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Param id path string true "分类ID" | 
					
						
							|  |  |  |  | // @Success 200 {object} responses.CategoryInfoResponse "获取分类详情成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "分类不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/article-categories/{id} [get] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) GetCategoryByID(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var query appQueries.GetCategoryQuery | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 绑定URI参数(分类ID) | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &query); err != nil { | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	response, err := h.appService.GetCategoryByID(c.Request.Context(), &query) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("获取分类详情失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.NotFound(c, "分类不存在") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, response, "获取分类详情成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // CreateCategory 创建分类 | 
					
						
							|  |  |  |  | // @Summary 创建分类 | 
					
						
							|  |  |  |  | // @Description 创建新的文章分类 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章分类-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param request body commands.CreateCategoryCommand true "创建分类请求" | 
					
						
							|  |  |  |  | // @Success 201 {object} map[string]interface{} "分类创建成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/article-categories [post] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) CreateCategory(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.CreateCategoryCommand | 
					
						
							|  |  |  |  | 	if err := h.validator.BindAndValidate(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.CreateCategory(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("创建分类失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Created(c, nil, "分类创建成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // UpdateCategory 更新分类 | 
					
						
							|  |  |  |  | // @Summary 更新分类 | 
					
						
							|  |  |  |  | // @Description 更新分类信息 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章分类-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "分类ID" | 
					
						
							|  |  |  |  | // @Param request body commands.UpdateCategoryCommand true "更新分类请求" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "分类更新成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "分类不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/article-categories/{id} [put] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) UpdateCategory(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.UpdateCategoryCommand | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 先绑定URI参数(分类ID) | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 再绑定JSON请求体(分类信息) | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.validator.BindAndValidate(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.UpdateCategory(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("更新分类失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "分类更新成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // DeleteCategory 删除分类 | 
					
						
							|  |  |  |  | // @Summary 删除分类 | 
					
						
							|  |  |  |  | // @Description 删除指定分类 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章分类-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "分类ID" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "分类删除成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "分类不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/article-categories/{id} [delete] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) DeleteCategory(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.DeleteCategoryCommand | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.DeleteCategory(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("删除分类失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "分类删除成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ==================== 标签相关方法 ==================== | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ListTags 获取标签列表 | 
					
						
							|  |  |  |  | // @Summary 获取标签列表 | 
					
						
							|  |  |  |  | // @Description 获取所有文章标签 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章标签-用户端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Success 200 {object} responses.TagListResponse "获取标签列表成功" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/article-tags [get] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) ListTags(c *gin.Context) { | 
					
						
							|  |  |  |  | 	response, err := h.appService.ListTags(c.Request.Context()) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("获取标签列表失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.InternalError(c, "获取标签列表失败") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, response, "获取标签列表成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GetTagByID 获取标签详情 | 
					
						
							|  |  |  |  | // @Summary 获取标签详情 | 
					
						
							|  |  |  |  | // @Description 根据ID获取标签详情 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章标签-用户端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Param id path string true "标签ID" | 
					
						
							|  |  |  |  | // @Success 200 {object} responses.TagInfoResponse "获取标签详情成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "标签不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/article-tags/{id} [get] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) GetTagByID(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var query appQueries.GetTagQuery | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 绑定URI参数(标签ID) | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &query); err != nil { | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	response, err := h.appService.GetTagByID(c.Request.Context(), &query) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("获取标签详情失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.NotFound(c, "标签不存在") | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, response, "获取标签详情成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // CreateTag 创建标签 | 
					
						
							|  |  |  |  | // @Summary 创建标签 | 
					
						
							|  |  |  |  | // @Description 创建新的文章标签 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章标签-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param request body commands.CreateTagCommand true "创建标签请求" | 
					
						
							|  |  |  |  | // @Success 201 {object} map[string]interface{} "标签创建成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/article-tags [post] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) CreateTag(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.CreateTagCommand | 
					
						
							|  |  |  |  | 	if err := h.validator.BindAndValidate(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.CreateTag(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("创建标签失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Created(c, nil, "标签创建成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // UpdateTag 更新标签 | 
					
						
							|  |  |  |  | // @Summary 更新标签 | 
					
						
							|  |  |  |  | // @Description 更新标签信息 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章标签-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "标签ID" | 
					
						
							|  |  |  |  | // @Param request body commands.UpdateTagCommand true "更新标签请求" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "标签更新成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "标签不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/article-tags/{id} [put] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) UpdateTag(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.UpdateTagCommand | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 先绑定URI参数(标签ID) | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 再绑定JSON请求体(标签信息) | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.validator.BindAndValidate(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.UpdateTag(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("更新标签失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "标签更新成功") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // DeleteTag 删除标签 | 
					
						
							|  |  |  |  | // @Summary 删除标签 | 
					
						
							|  |  |  |  | // @Description 删除指定标签 | 
					
						
							| 
									
										
										
										
											2025-09-01 20:46:56 +08:00
										 |  |  |  | // @Tags 文章标签-管理端 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | // @Accept json | 
					
						
							|  |  |  |  | // @Produce json | 
					
						
							|  |  |  |  | // @Security Bearer | 
					
						
							|  |  |  |  | // @Param id path string true "标签ID" | 
					
						
							|  |  |  |  | // @Success 200 {object} map[string]interface{} "标签删除成功" | 
					
						
							|  |  |  |  | // @Failure 400 {object} map[string]interface{} "请求参数错误" | 
					
						
							|  |  |  |  | // @Failure 401 {object} map[string]interface{} "未认证" | 
					
						
							|  |  |  |  | // @Failure 404 {object} map[string]interface{} "标签不存在" | 
					
						
							|  |  |  |  | // @Failure 500 {object} map[string]interface{} "服务器内部错误" | 
					
						
							|  |  |  |  | // @Router /api/v1/admin/article-tags/{id} [delete] | 
					
						
							|  |  |  |  | func (h *ArticleHandler) DeleteTag(c *gin.Context) { | 
					
						
							|  |  |  |  | 	var cmd commands.DeleteTagCommand | 
					
						
							|  |  |  |  | 	if err := h.validator.ValidateParam(c, &cmd); err != nil { | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	if err := h.appService.DeleteTag(c.Request.Context(), &cmd); err != nil { | 
					
						
							|  |  |  |  | 		h.logger.Error("删除标签失败", zap.Error(err)) | 
					
						
							|  |  |  |  | 		h.responseBuilder.BadRequest(c, err.Error()) | 
					
						
							|  |  |  |  | 		return | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-02 16:37:28 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-01 18:29:59 +08:00
										 |  |  |  | 	h.responseBuilder.Success(c, nil, "标签删除成功") | 
					
						
							|  |  |  |  | } |