- ErpModule trait hooks now accept db and event_bus parameters - AuthModule.on_tenant_created: seeds default roles, permissions, and admin user for new tenants using existing seed_tenant_auth() - AuthModule.on_tenant_deleted: soft-deletes all users for the tenant - Updated all other modules (config, workflow, message) to match the new trait signature
160 lines
4.7 KiB
Rust
160 lines
4.7 KiB
Rust
use axum::Router;
|
|
use axum::routing::{get, post};
|
|
use std::time::Duration;
|
|
use uuid::Uuid;
|
|
|
|
use erp_core::error::AppResult;
|
|
use erp_core::events::EventBus;
|
|
use erp_core::module::ErpModule;
|
|
|
|
use crate::handler::{definition_handler, instance_handler, task_handler};
|
|
|
|
/// Workflow module implementing the `ErpModule` trait.
|
|
///
|
|
/// Manages workflow definitions, process instances, tasks,
|
|
/// and the token-driven execution engine.
|
|
pub struct WorkflowModule;
|
|
|
|
impl WorkflowModule {
|
|
pub fn new() -> Self {
|
|
Self
|
|
}
|
|
|
|
/// Build protected (authenticated) routes for the workflow module.
|
|
pub fn protected_routes<S>() -> Router<S>
|
|
where
|
|
crate::workflow_state::WorkflowState: axum::extract::FromRef<S>,
|
|
S: Clone + Send + Sync + 'static,
|
|
{
|
|
Router::new()
|
|
// Definition routes
|
|
.route(
|
|
"/workflow/definitions",
|
|
get(definition_handler::list_definitions)
|
|
.post(definition_handler::create_definition),
|
|
)
|
|
.route(
|
|
"/workflow/definitions/{id}",
|
|
get(definition_handler::get_definition).put(definition_handler::update_definition),
|
|
)
|
|
.route(
|
|
"/workflow/definitions/{id}/publish",
|
|
post(definition_handler::publish_definition),
|
|
)
|
|
// Instance routes
|
|
.route(
|
|
"/workflow/instances",
|
|
post(instance_handler::start_instance).get(instance_handler::list_instances),
|
|
)
|
|
.route(
|
|
"/workflow/instances/{id}",
|
|
get(instance_handler::get_instance),
|
|
)
|
|
.route(
|
|
"/workflow/instances/{id}/suspend",
|
|
post(instance_handler::suspend_instance),
|
|
)
|
|
.route(
|
|
"/workflow/instances/{id}/resume",
|
|
post(instance_handler::resume_instance),
|
|
)
|
|
.route(
|
|
"/workflow/instances/{id}/terminate",
|
|
post(instance_handler::terminate_instance),
|
|
)
|
|
// Task routes
|
|
.route(
|
|
"/workflow/tasks/pending",
|
|
get(task_handler::list_pending_tasks),
|
|
)
|
|
.route(
|
|
"/workflow/tasks/completed",
|
|
get(task_handler::list_completed_tasks),
|
|
)
|
|
.route(
|
|
"/workflow/tasks/{id}/complete",
|
|
post(task_handler::complete_task),
|
|
)
|
|
.route(
|
|
"/workflow/tasks/{id}/delegate",
|
|
post(task_handler::delegate_task),
|
|
)
|
|
}
|
|
|
|
/// 启动超时检查后台任务。
|
|
///
|
|
/// 每 60 秒扫描一次 tasks 表,查找 due_date 已过期但仍处于 pending 状态的任务。
|
|
/// 发现超时任务时记录 warning 日志,后续迭代将实现自动完成/升级逻辑。
|
|
pub fn start_timeout_checker(db: sea_orm::DatabaseConnection) {
|
|
tokio::spawn(async move {
|
|
let mut interval = tokio::time::interval(Duration::from_secs(60));
|
|
|
|
// 首次跳过,等一个完整间隔再执行
|
|
interval.tick().await;
|
|
|
|
loop {
|
|
interval.tick().await;
|
|
|
|
match crate::engine::timeout::TimeoutChecker::find_all_overdue_tasks(&db).await {
|
|
Ok(overdue) => {
|
|
if !overdue.is_empty() {
|
|
tracing::warn!(
|
|
count = overdue.len(),
|
|
task_ids = ?overdue,
|
|
"发现超时未完成的任务 — TODO: 实现自动完成/升级逻辑"
|
|
);
|
|
}
|
|
}
|
|
Err(e) => {
|
|
tracing::warn!(error = %e, "超时检查任务执行失败");
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
impl Default for WorkflowModule {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl ErpModule for WorkflowModule {
|
|
fn name(&self) -> &str {
|
|
"workflow"
|
|
}
|
|
|
|
fn version(&self) -> &str {
|
|
env!("CARGO_PKG_VERSION")
|
|
}
|
|
|
|
fn dependencies(&self) -> Vec<&str> {
|
|
vec!["auth"]
|
|
}
|
|
|
|
fn register_event_handlers(&self, _bus: &EventBus) {}
|
|
|
|
async fn on_tenant_created(
|
|
&self,
|
|
_tenant_id: Uuid,
|
|
_db: &sea_orm::DatabaseConnection,
|
|
_event_bus: &EventBus,
|
|
) -> AppResult<()> {
|
|
Ok(())
|
|
}
|
|
|
|
async fn on_tenant_deleted(
|
|
&self,
|
|
_tenant_id: Uuid,
|
|
_db: &sea_orm::DatabaseConnection,
|
|
) -> AppResult<()> {
|
|
Ok(())
|
|
}
|
|
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|