feat(workflow): add workflow engine module (Phase 4)

Implement complete workflow engine with BPMN subset support:

Backend (erp-workflow crate):
- Token-driven execution engine with exclusive/parallel gateway support
- BPMN parser with flow graph validation
- Expression evaluator for conditional branching
- Process definition CRUD with draft/publish lifecycle
- Process instance management (start, suspend, terminate)
- Task service (pending, complete, delegate)
- PostgreSQL advisory locks for concurrent safety
- 5 database tables: process_definitions, process_instances,
  tokens, tasks, process_variables
- 13 API endpoints with RBAC protection
- Timeout checker framework (placeholder)

Frontend:
- Workflow page with 4 tabs (definitions, pending, completed, monitor)
- React Flow visual process designer (@xyflow/react)
- Process viewer with active node highlighting
- 3 API client modules for workflow endpoints
- Sidebar menu integration
This commit is contained in:
iven
2026-04-11 09:54:02 +08:00
parent 0cbd08eb78
commit 91ecaa3ed7
51 changed files with 4826 additions and 12 deletions

View File

@@ -0,0 +1,49 @@
use erp_core::error::AppError;
/// Workflow module error types.
#[derive(Debug, thiserror::Error)]
pub enum WorkflowError {
#[error("验证失败: {0}")]
Validation(String),
#[error("资源未找到: {0}")]
NotFound(String),
#[error("流程定义已存在: {0}")]
DuplicateDefinition(String),
#[error("流程图无效: {0}")]
InvalidDiagram(String),
#[error("流程状态错误: {0}")]
InvalidState(String),
#[error("表达式求值失败: {0}")]
ExpressionError(String),
}
impl From<sea_orm::TransactionError<WorkflowError>> for WorkflowError {
fn from(err: sea_orm::TransactionError<WorkflowError>) -> Self {
match err {
sea_orm::TransactionError::Connection(err) => {
WorkflowError::Validation(err.to_string())
}
sea_orm::TransactionError::Transaction(inner) => inner,
}
}
}
impl From<WorkflowError> for AppError {
fn from(err: WorkflowError) -> Self {
match err {
WorkflowError::Validation(s) => AppError::Validation(s),
WorkflowError::NotFound(s) => AppError::NotFound(s),
WorkflowError::DuplicateDefinition(s) => AppError::Conflict(s),
WorkflowError::InvalidDiagram(s) => AppError::Validation(s),
WorkflowError::InvalidState(s) => AppError::Validation(s),
WorkflowError::ExpressionError(s) => AppError::Validation(s),
}
}
}
pub type WorkflowResult<T> = Result<T, WorkflowError>;