add timed

This commit is contained in:
2025-09-02 16:37:28 +08:00
parent 2f3817c8f0
commit c7c4ab7a19
28 changed files with 478 additions and 2373 deletions

View File

@@ -53,19 +53,19 @@ func (h *ArticleHandler) CreateArticle(c *gin.Context) {
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
// 验证用户是否已登录
if _, exists := c.Get("user_id"); !exists {
h.responseBuilder.Unauthorized(c, "用户未登录")
return
}
if err := h.appService.CreateArticle(c.Request.Context(), &cmd); err != nil {
h.logger.Error("创建文章失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Created(c, nil, "文章创建成功")
}
@@ -83,19 +83,19 @@ func (h *ArticleHandler) CreateArticle(c *gin.Context) {
// @Router /api/v1/articles/{id} [get]
func (h *ArticleHandler) GetArticleByID(c *gin.Context) {
var query appQueries.GetArticleQuery
query.ID = c.Param("id")
if query.ID == "" {
h.responseBuilder.BadRequest(c, "文章ID不能为空")
// 绑定URI参数文章ID
if err := h.validator.ValidateParam(c, &query); err != nil {
return
}
response, err := h.appService.GetArticleByID(c.Request.Context(), &query)
if err != nil {
h.logger.Error("获取文章详情失败", zap.Error(err))
h.responseBuilder.NotFound(c, "文章不存在")
return
}
h.responseBuilder.Success(c, response, "获取文章详情成功")
}
@@ -124,7 +124,7 @@ func (h *ArticleHandler) ListArticles(c *gin.Context) {
if err := h.validator.ValidateQuery(c, &query); err != nil {
return
}
// 设置默认值
if query.Page <= 0 {
query.Page = 1
@@ -135,14 +135,14 @@ func (h *ArticleHandler) ListArticles(c *gin.Context) {
if query.PageSize > 100 {
query.PageSize = 100
}
response, err := h.appService.ListArticles(c.Request.Context(), &query)
if err != nil {
h.logger.Error("获取文章列表失败", zap.Error(err))
h.responseBuilder.InternalError(c, "获取文章列表失败")
return
}
h.responseBuilder.Success(c, response, "获取文章列表成功")
}
@@ -173,7 +173,7 @@ func (h *ArticleHandler) ListArticlesForAdmin(c *gin.Context) {
if err := h.validator.ValidateQuery(c, &query); err != nil {
return
}
// 设置默认值
if query.Page <= 0 {
query.Page = 1
@@ -184,19 +184,17 @@ func (h *ArticleHandler) ListArticlesForAdmin(c *gin.Context) {
if query.PageSize > 100 {
query.PageSize = 100
}
response, err := h.appService.ListArticlesForAdmin(c.Request.Context(), &query)
if err != nil {
h.logger.Error("获取文章列表失败", zap.Error(err))
h.responseBuilder.InternalError(c, "获取文章列表失败")
return
}
h.responseBuilder.Success(c, response, "获取文章列表成功")
}
// UpdateArticle 更新文章
// @Summary 更新文章
// @Description 更新文章信息
@@ -214,21 +212,23 @@ func (h *ArticleHandler) ListArticlesForAdmin(c *gin.Context) {
// @Router /api/v1/admin/articles/{id} [put]
func (h *ArticleHandler) UpdateArticle(c *gin.Context) {
var cmd commands.UpdateArticleCommand
cmd.ID = c.Param("id")
if cmd.ID == "" {
h.responseBuilder.BadRequest(c, "文章ID不能为空")
// 先绑定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.UpdateArticle(c.Request.Context(), &cmd); err != nil {
h.logger.Error("更新文章失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "文章更新成功")
}
@@ -251,13 +251,13 @@ func (h *ArticleHandler) DeleteArticle(c *gin.Context) {
if err := h.validator.ValidateParam(c, &cmd); err != nil {
return
}
if err := h.appService.DeleteArticle(c.Request.Context(), &cmd); err != nil {
h.logger.Error("删除文章失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "文章删除成功")
}
@@ -280,19 +280,19 @@ func (h *ArticleHandler) PublishArticle(c *gin.Context) {
if err := h.validator.ValidateParam(c, &cmd); err != nil {
return
}
if err := h.appService.PublishArticle(c.Request.Context(), &cmd); err != nil {
h.logger.Error("发布文章失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "文章发布成功")
}
// SchedulePublishArticle 定时发布文章
// @Summary 定时发布文章
// @Description 设置文章的定时发布时间
// @Description 设置文章的定时发布时间支持格式YYYY-MM-DD HH:mm:ss
// @Tags 文章管理-管理端
// @Accept json
// @Produce json
@@ -307,22 +307,57 @@ func (h *ArticleHandler) PublishArticle(c *gin.Context) {
// @Router /api/v1/admin/articles/{id}/schedule-publish [post]
func (h *ArticleHandler) SchedulePublishArticle(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.SchedulePublishArticle(c.Request.Context(), &cmd); err != nil {
h.logger.Error("设置定时发布失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "定时发布设置成功")
}
// 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, "取消定时发布成功")
}
// ArchiveArticle 归档文章
// @Summary 归档文章
// @Description 将已发布文章归档
@@ -342,13 +377,13 @@ func (h *ArticleHandler) ArchiveArticle(c *gin.Context) {
if err := h.validator.ValidateParam(c, &cmd); err != nil {
return
}
if err := h.appService.ArchiveArticle(c.Request.Context(), &cmd); err != nil {
h.logger.Error("归档文章失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "文章归档成功")
}
@@ -369,19 +404,23 @@ func (h *ArticleHandler) ArchiveArticle(c *gin.Context) {
// @Router /api/v1/admin/articles/{id}/featured [put]
func (h *ArticleHandler) SetFeatured(c *gin.Context) {
var cmd commands.SetFeaturedCommand
// 先绑定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.SetFeatured(c.Request.Context(), &cmd); err != nil {
h.logger.Error("设置推荐状态失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "设置推荐状态成功")
}
@@ -403,11 +442,10 @@ func (h *ArticleHandler) GetArticleStats(c *gin.Context) {
h.responseBuilder.InternalError(c, "获取文章统计失败")
return
}
h.responseBuilder.Success(c, response, "获取统计成功")
}
// ==================== 分类相关方法 ====================
// ListCategories 获取分类列表
@@ -426,7 +464,7 @@ func (h *ArticleHandler) ListCategories(c *gin.Context) {
h.responseBuilder.InternalError(c, "获取分类列表失败")
return
}
h.responseBuilder.Success(c, response, "获取分类列表成功")
}
@@ -444,19 +482,19 @@ func (h *ArticleHandler) ListCategories(c *gin.Context) {
// @Router /api/v1/article-categories/{id} [get]
func (h *ArticleHandler) GetCategoryByID(c *gin.Context) {
var query appQueries.GetCategoryQuery
query.ID = c.Param("id")
if query.ID == "" {
h.responseBuilder.BadRequest(c, "分类ID不能为空")
// 绑定URI参数分类ID
if err := h.validator.ValidateParam(c, &query); err != nil {
return
}
response, err := h.appService.GetCategoryByID(c.Request.Context(), &query)
if err != nil {
h.logger.Error("获取分类详情失败", zap.Error(err))
h.responseBuilder.NotFound(c, "分类不存在")
return
}
h.responseBuilder.Success(c, response, "获取分类详情成功")
}
@@ -478,13 +516,13 @@ func (h *ArticleHandler) CreateCategory(c *gin.Context) {
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
if err := h.appService.CreateCategory(c.Request.Context(), &cmd); err != nil {
h.logger.Error("创建分类失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Created(c, nil, "分类创建成功")
}
@@ -505,21 +543,23 @@ func (h *ArticleHandler) CreateCategory(c *gin.Context) {
// @Router /api/v1/admin/article-categories/{id} [put]
func (h *ArticleHandler) UpdateCategory(c *gin.Context) {
var cmd commands.UpdateCategoryCommand
cmd.ID = c.Param("id")
if cmd.ID == "" {
h.responseBuilder.BadRequest(c, "分类ID不能为空")
// 先绑定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.UpdateCategory(c.Request.Context(), &cmd); err != nil {
h.logger.Error("更新分类失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "分类更新成功")
}
@@ -542,13 +582,13 @@ func (h *ArticleHandler) DeleteCategory(c *gin.Context) {
if err := h.validator.ValidateParam(c, &cmd); err != nil {
return
}
if err := h.appService.DeleteCategory(c.Request.Context(), &cmd); err != nil {
h.logger.Error("删除分类失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "分类删除成功")
}
@@ -570,7 +610,7 @@ func (h *ArticleHandler) ListTags(c *gin.Context) {
h.responseBuilder.InternalError(c, "获取标签列表失败")
return
}
h.responseBuilder.Success(c, response, "获取标签列表成功")
}
@@ -588,19 +628,19 @@ func (h *ArticleHandler) ListTags(c *gin.Context) {
// @Router /api/v1/article-tags/{id} [get]
func (h *ArticleHandler) GetTagByID(c *gin.Context) {
var query appQueries.GetTagQuery
query.ID = c.Param("id")
if query.ID == "" {
h.responseBuilder.BadRequest(c, "标签ID不能为空")
// 绑定URI参数标签ID
if err := h.validator.ValidateParam(c, &query); err != nil {
return
}
response, err := h.appService.GetTagByID(c.Request.Context(), &query)
if err != nil {
h.logger.Error("获取标签详情失败", zap.Error(err))
h.responseBuilder.NotFound(c, "标签不存在")
return
}
h.responseBuilder.Success(c, response, "获取标签详情成功")
}
@@ -622,13 +662,13 @@ func (h *ArticleHandler) CreateTag(c *gin.Context) {
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
if err := h.appService.CreateTag(c.Request.Context(), &cmd); err != nil {
h.logger.Error("创建标签失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Created(c, nil, "标签创建成功")
}
@@ -649,21 +689,23 @@ func (h *ArticleHandler) CreateTag(c *gin.Context) {
// @Router /api/v1/admin/article-tags/{id} [put]
func (h *ArticleHandler) UpdateTag(c *gin.Context) {
var cmd commands.UpdateTagCommand
cmd.ID = c.Param("id")
if cmd.ID == "" {
h.responseBuilder.BadRequest(c, "标签ID不能为空")
// 先绑定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.UpdateTag(c.Request.Context(), &cmd); err != nil {
h.logger.Error("更新标签失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "标签更新成功")
}
@@ -686,12 +728,12 @@ func (h *ArticleHandler) DeleteTag(c *gin.Context) {
if err := h.validator.ValidateParam(c, &cmd); err != nil {
return
}
if err := h.appService.DeleteTag(c.Request.Context(), &cmd); err != nil {
h.logger.Error("删除标签失败", zap.Error(err))
h.responseBuilder.BadRequest(c, err.Error())
return
}
h.responseBuilder.Success(c, nil, "标签删除成功")
}