refactor(health): 状态转换验证统一到 validation 模块
- article/dialysis/lab_report 审核流程改用 validation 函数校验状态转换 - 移除 article_service/approve/reject/unpublish 中硬编码的 if 检查 - dialysis review 和 lab report review 新增前置状态校验 - 修正 article 状态转换图:pending_review → published(直接发布,无中间 approved)
This commit is contained in:
@@ -15,6 +15,7 @@ use crate::entity::article;
|
||||
use crate::entity::article_article_tag;
|
||||
use crate::entity::article_tag;
|
||||
use crate::error::{HealthError, HealthResult};
|
||||
use crate::service::validation;
|
||||
use crate::state::HealthState;
|
||||
|
||||
/// 文章列表(管理端,支持状态/分类/标签/关键词筛选)
|
||||
@@ -130,9 +131,7 @@ pub async fn submit_article(
|
||||
let next_ver = check_version(expected_version, model.version)
|
||||
.map_err(|_| HealthError::VersionMismatch)?;
|
||||
|
||||
if model.status != "draft" && model.status != "rejected" {
|
||||
return Err(HealthError::InvalidStatusTransition(format!("无法从 {} 提交审核", model.status)));
|
||||
}
|
||||
validation::validate_article_status_transition(&model.status, "pending_review")?;
|
||||
|
||||
let mut active: article::ActiveModel = model.into();
|
||||
active.status = Set("pending_review".into());
|
||||
@@ -164,9 +163,7 @@ pub async fn approve_article(
|
||||
let next_ver = check_version(expected_version, model.version)
|
||||
.map_err(|_| HealthError::VersionMismatch)?;
|
||||
|
||||
if model.status != "pending_review" {
|
||||
return Err(HealthError::InvalidStatusTransition(format!("无法从 {} 审核通过", model.status)));
|
||||
}
|
||||
validation::validate_article_status_transition(&model.status, "published")?;
|
||||
|
||||
let now = Utc::now();
|
||||
let mut active: article::ActiveModel = model.into();
|
||||
@@ -203,9 +200,7 @@ pub async fn reject_article(
|
||||
let next_ver = check_version(expected_version, model.version)
|
||||
.map_err(|_| HealthError::VersionMismatch)?;
|
||||
|
||||
if model.status != "pending_review" {
|
||||
return Err(HealthError::InvalidStatusTransition(format!("无法从 {} 审核拒绝", model.status)));
|
||||
}
|
||||
validation::validate_article_status_transition(&model.status, "rejected")?;
|
||||
|
||||
let now = Utc::now();
|
||||
let mut active: article::ActiveModel = model.into();
|
||||
@@ -240,9 +235,7 @@ pub async fn unpublish_article(
|
||||
let next_ver = check_version(expected_version, model.version)
|
||||
.map_err(|_| HealthError::VersionMismatch)?;
|
||||
|
||||
if model.status != "published" {
|
||||
return Err(HealthError::InvalidStatusTransition(format!("无法从 {} 撤回发布", model.status)));
|
||||
}
|
||||
validation::validate_article_status_transition(&model.status, "draft")?;
|
||||
|
||||
let mut active: article::ActiveModel = model.into();
|
||||
active.status = Set("draft".into());
|
||||
|
||||
@@ -15,6 +15,7 @@ use erp_core::types::PaginatedResponse;
|
||||
use crate::dto::dialysis_dto::*;
|
||||
use crate::entity::{dialysis_record, patient};
|
||||
use crate::error::{HealthError, HealthResult};
|
||||
use crate::service::validation;
|
||||
use crate::state::HealthState;
|
||||
|
||||
pub async fn list_dialysis_records(
|
||||
@@ -221,6 +222,8 @@ pub async fn review_dialysis_record(
|
||||
let next_ver = check_version(expected_version, model.version)
|
||||
.map_err(|_| HealthError::VersionMismatch)?;
|
||||
|
||||
validation::validate_dialysis_status_transition(&model.status, "reviewed")?;
|
||||
|
||||
let mut active: dialysis_record::ActiveModel = model.into();
|
||||
active.status = Set("reviewed".to_string());
|
||||
active.reviewed_by = Set(Some(reviewer_id));
|
||||
|
||||
@@ -16,7 +16,7 @@ use erp_core::types::PaginatedResponse;
|
||||
use crate::dto::health_data_dto::*;
|
||||
use crate::entity::{doctor_profile, health_record, lab_report, patient, patient_doctor_relation, vital_signs};
|
||||
use crate::error::{HealthError, HealthResult};
|
||||
use crate::service::validation::validate_record_type;
|
||||
use crate::service::validation::{validate_record_type, validate_lab_report_status_transition};
|
||||
use crate::state::HealthState;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -512,6 +512,8 @@ pub async fn review_lab_report(
|
||||
let next_ver = check_version(expected_version, model.version)
|
||||
.map_err(|_| HealthError::VersionMismatch)?;
|
||||
|
||||
validate_lab_report_status_transition(&model.status, "reviewed")?;
|
||||
|
||||
let mut active: lab_report::ActiveModel = model.into();
|
||||
active.status = Set("reviewed".to_string());
|
||||
active.reviewed_by = Set(Some(reviewer_id));
|
||||
|
||||
@@ -141,8 +141,7 @@ pub fn validate_article_status(value: &str) -> HealthResult<()> {
|
||||
|
||||
/// article.status 状态转换
|
||||
/// draft → pending_review, rejected → pending_review
|
||||
/// pending_review → approved / rejected
|
||||
/// approved → published
|
||||
/// pending_review → published / rejected(审核通过直接发布,或拒绝)
|
||||
/// published → draft (下架)
|
||||
pub fn validate_article_status_transition(current: &str, new: &str) -> HealthResult<()> {
|
||||
if current == new {
|
||||
@@ -150,8 +149,7 @@ pub fn validate_article_status_transition(current: &str, new: &str) -> HealthRes
|
||||
}
|
||||
let allowed = match current {
|
||||
"draft" => matches!(new, "pending_review"),
|
||||
"pending_review" => matches!(new, "approved" | "rejected"),
|
||||
"approved" => matches!(new, "published"),
|
||||
"pending_review" => matches!(new, "published" | "rejected"),
|
||||
"rejected" => matches!(new, "pending_review"),
|
||||
"published" => matches!(new, "draft"),
|
||||
_ => false,
|
||||
@@ -369,19 +367,17 @@ mod tests {
|
||||
#[test]
|
||||
fn art_draft_to_published_fails() { assert!(validate_article_status_transition("draft", "published").is_err()); }
|
||||
#[test]
|
||||
fn art_pending_review_to_approved() { assert!(validate_article_status_transition("pending_review", "approved").is_ok()); }
|
||||
fn art_pending_review_to_published() { assert!(validate_article_status_transition("pending_review", "published").is_ok()); }
|
||||
#[test]
|
||||
fn art_pending_review_to_rejected() { assert!(validate_article_status_transition("pending_review", "rejected").is_ok()); }
|
||||
#[test]
|
||||
fn art_pending_review_to_draft_fails() { assert!(validate_article_status_transition("pending_review", "draft").is_err()); }
|
||||
#[test]
|
||||
fn art_approved_to_published() { assert!(validate_article_status_transition("approved", "published").is_ok()); }
|
||||
#[test]
|
||||
fn art_rejected_to_pending_review() { assert!(validate_article_status_transition("rejected", "pending_review").is_ok()); }
|
||||
#[test]
|
||||
fn art_published_to_draft() { assert!(validate_article_status_transition("published", "draft").is_ok()); }
|
||||
#[test]
|
||||
fn art_published_to_approved_fails() { assert!(validate_article_status_transition("published", "approved").is_err()); }
|
||||
fn art_published_to_pending_fails() { assert!(validate_article_status_transition("published", "pending_review").is_err()); }
|
||||
#[test]
|
||||
fn art_same_status_ok() { assert!(validate_article_status_transition("draft", "draft").is_ok()); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user