fix
This commit is contained in:
@@ -15,6 +15,7 @@ type ArticleApplicationService interface {
|
||||
DeleteArticle(ctx context.Context, cmd *commands.DeleteArticleCommand) error
|
||||
GetArticleByID(ctx context.Context, query *appQueries.GetArticleQuery) (*responses.ArticleInfoResponse, error)
|
||||
ListArticles(ctx context.Context, query *appQueries.ListArticleQuery) (*responses.ArticleListResponse, error)
|
||||
ListArticlesForAdmin(ctx context.Context, query *appQueries.ListArticleQuery) (*responses.ArticleListResponse, error)
|
||||
|
||||
// 文章状态管理
|
||||
PublishArticle(ctx context.Context, cmd *commands.PublishArticleCommand) error
|
||||
|
||||
@@ -223,6 +223,43 @@ func (s *ArticleApplicationServiceImpl) ListArticles(ctx context.Context, query
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ListArticlesForAdmin 获取文章列表(管理员端)
|
||||
func (s *ArticleApplicationServiceImpl) ListArticlesForAdmin(ctx context.Context, query *appQueries.ListArticleQuery) (*responses.ArticleListResponse, error) {
|
||||
// 1. 构建仓储查询
|
||||
repoQuery := &repoQueries.ListArticleQuery{
|
||||
Page: query.Page,
|
||||
PageSize: query.PageSize,
|
||||
Status: query.Status,
|
||||
CategoryID: query.CategoryID,
|
||||
TagID: query.TagID,
|
||||
Title: query.Title,
|
||||
Summary: query.Summary,
|
||||
IsFeatured: query.IsFeatured,
|
||||
OrderBy: query.OrderBy,
|
||||
OrderDir: query.OrderDir,
|
||||
}
|
||||
|
||||
// 2. 调用仓储
|
||||
articles, total, err := s.articleRepo.ListArticlesForAdmin(ctx, repoQuery)
|
||||
if err != nil {
|
||||
s.logger.Error("获取文章列表失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("获取文章列表失败: %w", err)
|
||||
}
|
||||
|
||||
// 3. 转换为响应对象
|
||||
items := responses.FromArticleEntitiesToListItemList(articles)
|
||||
|
||||
response := &responses.ArticleListResponse{
|
||||
Total: total,
|
||||
Page: query.Page,
|
||||
Size: query.PageSize,
|
||||
Items: items,
|
||||
}
|
||||
|
||||
s.logger.Info("获取文章列表成功", zap.Int64("total", total))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
|
||||
// PublishArticle 发布文章
|
||||
func (s *ArticleApplicationServiceImpl) PublishArticle(ctx context.Context, cmd *commands.PublishArticleCommand) error {
|
||||
|
||||
@@ -18,6 +18,7 @@ type ArticleRepository interface {
|
||||
FindFeatured(ctx context.Context) ([]*entities.Article, error)
|
||||
Search(ctx context.Context, query *queries.SearchArticleQuery) ([]*entities.Article, int64, error)
|
||||
ListArticles(ctx context.Context, query *queries.ListArticleQuery) ([]*entities.Article, int64, error)
|
||||
ListArticlesForAdmin(ctx context.Context, query *queries.ListArticleQuery) ([]*entities.Article, int64, error)
|
||||
|
||||
// 统计方法
|
||||
CountByCategoryID(ctx context.Context, categoryID string) (int64, error)
|
||||
|
||||
@@ -263,11 +263,100 @@ func (r *GormArticleRepository) Search(ctx context.Context, query *repoQueries.S
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// ListArticles 获取文章列表
|
||||
// ListArticles 获取文章列表(用户端)
|
||||
func (r *GormArticleRepository) ListArticles(ctx context.Context, query *repoQueries.ListArticleQuery) ([]*entities.Article, int64, error) {
|
||||
var articles []entities.Article
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.Article{}).
|
||||
Select("id, title, summary, cover_image, category_id, status, is_featured, published_at, created_at, updated_at, scheduled_at")
|
||||
|
||||
// 用户端不显示归档文章
|
||||
dbQuery = dbQuery.Where("status != ?", entities.ArticleStatusArchived)
|
||||
|
||||
// 应用筛选条件
|
||||
if query.Status != "" {
|
||||
dbQuery = dbQuery.Where("status = ?", query.Status)
|
||||
}
|
||||
|
||||
if query.CategoryID != "" {
|
||||
// 如果指定了分类ID,只查询该分类的文章(包括没有分类的文章,当CategoryID为空字符串时)
|
||||
if query.CategoryID == "null" || query.CategoryID == "" {
|
||||
// 查询没有分类的文章
|
||||
dbQuery = dbQuery.Where("category_id IS NULL OR category_id = ''")
|
||||
} else {
|
||||
// 查询指定分类的文章
|
||||
dbQuery = dbQuery.Where("category_id = ?", query.CategoryID)
|
||||
}
|
||||
}
|
||||
|
||||
if query.TagID != "" {
|
||||
// 如果指定了标签ID,只查询有关联该标签的文章
|
||||
// 使用子查询而不是JOIN,避免影响其他查询条件
|
||||
subQuery := r.db.WithContext(ctx).Table("article_tag_relations").
|
||||
Select("article_id").
|
||||
Where("tag_id = ?", query.TagID)
|
||||
dbQuery = dbQuery.Where("id IN (?)", subQuery)
|
||||
}
|
||||
|
||||
if query.Title != "" {
|
||||
dbQuery = dbQuery.Where("title ILIKE ?", "%"+query.Title+"%")
|
||||
}
|
||||
|
||||
if query.Summary != "" {
|
||||
dbQuery = dbQuery.Where("summary ILIKE ?", "%"+query.Summary+"%")
|
||||
}
|
||||
|
||||
if query.IsFeatured != nil {
|
||||
dbQuery = dbQuery.Where("is_featured = ?", *query.IsFeatured)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
if err := dbQuery.Count(&total).Error; err != nil {
|
||||
r.logger.Error("获取文章列表总数失败", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 应用排序
|
||||
if query.OrderBy != "" {
|
||||
orderDir := "DESC"
|
||||
if query.OrderDir != "" {
|
||||
orderDir = strings.ToUpper(query.OrderDir)
|
||||
}
|
||||
dbQuery = dbQuery.Order(fmt.Sprintf("%s %s", query.OrderBy, orderDir))
|
||||
} else {
|
||||
dbQuery = dbQuery.Order("created_at DESC")
|
||||
}
|
||||
|
||||
// 应用分页
|
||||
if query.Page > 0 && query.PageSize > 0 {
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
dbQuery = dbQuery.Offset(offset).Limit(query.PageSize)
|
||||
}
|
||||
|
||||
// 预加载关联数据
|
||||
dbQuery = dbQuery.Preload("Category").Preload("Tags")
|
||||
|
||||
// 获取数据
|
||||
if err := dbQuery.Find(&articles).Error; err != nil {
|
||||
r.logger.Error("获取文章列表失败", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 转换为指针切片
|
||||
result := make([]*entities.Article, len(articles))
|
||||
for i := range articles {
|
||||
result[i] = &articles[i]
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// ListArticlesForAdmin 获取文章列表(管理员端)
|
||||
func (r *GormArticleRepository) ListArticlesForAdmin(ctx context.Context, query *repoQueries.ListArticleQuery) ([]*entities.Article, int64, error) {
|
||||
var articles []entities.Article
|
||||
var total int64
|
||||
|
||||
dbQuery := r.db.WithContext(ctx).Model(&entities.Article{}).
|
||||
Select("id, title, summary, cover_image, category_id, status, is_featured, published_at, view_count, created_at, updated_at, scheduled_at")
|
||||
|
||||
|
||||
@@ -146,6 +146,55 @@ func (h *ArticleHandler) ListArticles(c *gin.Context) {
|
||||
h.responseBuilder.Success(c, response, "获取文章列表成功")
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize <= 0 {
|
||||
query.PageSize = 10
|
||||
}
|
||||
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 更新文章
|
||||
|
||||
@@ -68,6 +68,9 @@ func (r *ArticleRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
// 统计信息
|
||||
adminArticleGroup.GET("/stats", r.handler.GetArticleStats) // 获取文章统计
|
||||
|
||||
// 文章列表查询
|
||||
adminArticleGroup.GET("", r.handler.ListArticlesForAdmin) // 获取文章列表(管理员端,包含所有状态)
|
||||
|
||||
// 文章管理
|
||||
adminArticleGroup.POST("", r.handler.CreateArticle) // 创建文章
|
||||
adminArticleGroup.PUT("/:id", r.handler.UpdateArticle) // 更新文章
|
||||
|
||||
Reference in New Issue
Block a user