From b00fe4488011166fb9f89a698883b84f02b9b8dd Mon Sep 17 00:00:00 2001 From: iven Date: Thu, 30 Apr 2026 10:53:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(health):=20=E6=B7=BB=E5=8A=A0=E6=96=87?= =?UTF-8?q?=E7=AB=A0=E4=BF=AE=E8=AE=A2=E5=8E=86=E5=8F=B2=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=20API=20=E2=80=94=20GET=20/health/articles/{id}/revisions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补全 ArticleRevision 实体的读取查询(之前仅有写入 save_revision), 新增 list_revisions service + handler + 路由,支持分页。 --- crates/erp-health/src/dto/article_dto.rs | 15 ++++++ .../erp-health/src/handler/article_handler.rs | 26 ++++++++++ crates/erp-health/src/module.rs | 4 ++ .../erp-health/src/service/article_service.rs | 51 +++++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/crates/erp-health/src/dto/article_dto.rs b/crates/erp-health/src/dto/article_dto.rs index 172b296..947fe5c 100644 --- a/crates/erp-health/src/dto/article_dto.rs +++ b/crates/erp-health/src/dto/article_dto.rs @@ -144,6 +144,21 @@ impl ReviewArticleReq { } } +// --------------------------------------------------------------------------- +// 修订历史 DTOs +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +pub struct ArticleRevisionResp { + pub id: Uuid, + pub article_id: Uuid, + pub revision_number: i32, + pub title: String, + pub summary: Option, + pub created_by: Option, + pub created_at: chrono::DateTime, +} + // --------------------------------------------------------------------------- // 分类 DTOs // --------------------------------------------------------------------------- diff --git a/crates/erp-health/src/handler/article_handler.rs b/crates/erp-health/src/handler/article_handler.rs index 9506ced..c28872d 100644 --- a/crates/erp-health/src/handler/article_handler.rs +++ b/crates/erp-health/src/handler/article_handler.rs @@ -203,3 +203,29 @@ where article_service::increment_view_count(&state, ctx.tenant_id, id).await?; Ok(Json(ApiResponse::ok(()))) } + +#[derive(Debug, serde::Deserialize)] +pub struct ListRevisionsQuery { + pub page: Option, + pub page_size: Option, +} + +/// 查询文章修订历史 +pub async fn list_revisions( + State(state): State, + Extension(ctx): Extension, + Path(id): Path, + Query(params): Query, +) -> Result>>, AppError> +where + HealthState: FromRef, + S: Clone + Send + Sync + 'static, +{ + require_permission(&ctx, "health.articles.list")?; + let page = params.page.unwrap_or(1); + let page_size = params.page_size.unwrap_or(20); + let result = article_service::list_revisions( + &state, ctx.tenant_id, id, page, page_size, + ).await?; + Ok(Json(ApiResponse::ok(result))) +} diff --git a/crates/erp-health/src/module.rs b/crates/erp-health/src/module.rs index 6740e64..b6a403c 100644 --- a/crates/erp-health/src/module.rs +++ b/crates/erp-health/src/module.rs @@ -433,6 +433,10 @@ impl HealthModule { "/health/articles/{id}/view", axum::routing::post(article_handler::view_article), ) + .route( + "/health/articles/{id}/revisions", + axum::routing::get(article_handler::list_revisions), + ) // 资讯分类 .route( "/health/article-categories", diff --git a/crates/erp-health/src/service/article_service.rs b/crates/erp-health/src/service/article_service.rs index 6119699..0bbca01 100644 --- a/crates/erp-health/src/service/article_service.rs +++ b/crates/erp-health/src/service/article_service.rs @@ -588,3 +588,54 @@ async fn save_revision( active.insert(&state.db).await?; Ok(()) } + +pub async fn list_revisions( + state: &HealthState, + tenant_id: Uuid, + article_id: Uuid, + page: u64, + page_size: u64, +) -> HealthResult> { + use crate::entity::article_revision; + + let page = page.max(1); + let page_size = page_size.clamp(1, 100); + + let condition = article_revision::Column::ArticleId + .eq(article_id) + .and(article_revision::Column::TenantId.eq(tenant_id)); + + let total = article_revision::Entity::find() + .filter(condition.clone()) + .count(&state.db) + .await?; + + let items = article_revision::Entity::find() + .filter(condition) + .order_by_desc(article_revision::Column::RevisionNumber) + .offset(((page - 1) * page_size) as u64) + .limit(page_size) + .all(&state.db) + .await?; + + let data = items + .into_iter() + .map(|m| crate::dto::article_dto::ArticleRevisionResp { + id: m.id, + article_id: m.article_id, + revision_number: m.revision_number, + title: m.title, + summary: m.summary, + created_by: m.created_by, + created_at: m.created_at, + }) + .collect(); + + Ok(PaginatedResponse { + data, + total, + page, + page_size, + total_pages: ((total as f64) / (page_size as f64)).ceil() as u64, + }) +}