Files
erp/plans/stateless-swimming-perlis.md
iven 97d3c9026b fix: resolve remaining clippy warnings and improve workflow frontend
- Collapse nested if-let in user_service.rs search filter
- Suppress dead_code warning on ApiDoc struct
- Refactor server routing: nest all routes under /api/v1 prefix
- Simplify health check route path
- Improve workflow ProcessDesigner with edit mode and loading states
- Update workflow pages with enhanced UX
- Add Phase 2 implementation plan document
2026-04-11 12:59:43 +08:00

14 KiB
Raw Blame History

Phase 4: 工作流引擎模块 — 实施计划

Context

Phase 1基础设施、Phase 2身份与权限和 Phase 3系统配置已完成。Phase 4 需要实现工作流引擎模块erp-workflow提供流程定义、流程实例管理、任务审批、Token 驱动的执行引擎和可视化流程设计器。当前 erp-workflow 仅为 placeholder。

用户选择"完整实施"方案,包括 BPMN 子集解析器、Token 驱动执行引擎、完整 CRUD 端点和 React Flow 可视化设计器。


Task 1: erp-workflow 骨架 + WorkflowState + Error

目标: 创建可编译的最小 crate注册到 erp-server。

创建/修改文件:

  • 修改: crates/erp-workflow/Cargo.toml — 添加完整依赖
  • 修改: crates/erp-workflow/src/lib.rs — 模块声明 + re-export
  • 创建: crates/erp-workflow/src/workflow_state.rsWorkflowState { db, event_bus }
  • 创建: crates/erp-workflow/src/error.rs — WorkflowError 枚举
  • 创建: crates/erp-workflow/src/module.rs — WorkflowModule + ErpModule trait
  • 创建: crates/erp-workflow/src/dto.rs — 占位
  • 创建: crates/erp-workflow/src/entity/mod.rs — 占位
  • 创建: crates/erp-workflow/src/service/mod.rs — 占位
  • 创建: crates/erp-workflow/src/handler/mod.rs — 占位
  • 创建: crates/erp-workflow/src/engine/mod.rs — 占位
  • 修改: crates/erp-server/Cargo.toml — 确认 erp-workflow 依赖
  • 修改: crates/erp-server/src/state.rs — 添加 FromRef<AppState> for WorkflowState
  • 修改: crates/erp-server/src/main.rs — 注册 WorkflowModule

依赖:

erp-core.workspace = true
tokio = { workspace = true, features = ["full"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
uuid = { workspace = true, features = ["v7", "serde"] }
chrono = { workspace = true, features = ["serde"] }
axum = { workspace = true }
sea-orm = { workspace = true, features = ["sqlx-postgres", "runtime-tokio-rustls", "with-uuid", "with-chrono", "with-json"] }
tracing = { workspace = true }
thiserror = { workspace = true }
utoipa = { workspace = true, features = ["uuid", "chrono"] }
async-trait = { workspace = true }

验证: cargo check 通过


Task 2: 数据库迁移5 张表)

创建文件(crates/erp-server/migration/src/

  • m20260412_000018_create_process_definitions.rs
  • m20260412_000019_create_process_instances.rs
  • m20260412_000020_create_tokens.rs
  • m20260412_000021_create_tasks.rs
  • m20260412_000022_create_process_variables.rs
  • 修改: lib.rs — 注册新迁移

process_definitions

类型 说明
id uuid PK UUIDv7
tenant_id uuid NOT NULL 租户 ID
name string NOT NULL 流程名称
key string NOT NULL 流程唯一编码
version int NOT NULL DEFAULT 1 版本号
category string NULL 分类(如 leave, expense
description text NULL 描述
nodes jsonb NOT NULL DEFAULT '[]' 节点定义BPMN 子集)
edges jsonb NOT NULL DEFAULT '[]' 连线定义
status string NOT NULL DEFAULT 'draft' draft/published/deprecated
+ 标准审计字段
唯一索引: (tenant_id, key, version) WHERE deleted_at IS NULL

process_instances

类型 说明
id uuid PK UUIDv7
tenant_id uuid NOT NULL
definition_id uuid NOT NULL FK → process_definitions
business_key string NULL 业务关联键(如请假单 ID
status string NOT NULL DEFAULT 'running' running/suspended/completed/terminated
started_by uuid NOT NULL 发起人 user_id
started_at timestamptz NOT NULL DEFAULT NOW()
completed_at timestamptz NULL
+ 标准审计字段
索引: idx_instances_status (tenant_id, status)

tokens

类型 说明
id uuid PK UUIDv7
tenant_id uuid NOT NULL
instance_id uuid NOT NULL FK → process_instances
node_id string NOT NULL 当前所在节点 ID
status string NOT NULL DEFAULT 'active' active/consumed/terminated
created_at timestamptz NOT NULL DEFAULT NOW()
consumed_at timestamptz NULL
索引: idx_tokens_instance (instance_id)

tasks

类型 说明
id uuid PK UUIDv7
tenant_id uuid NOT NULL
instance_id uuid NOT NULL FK → process_instances
token_id uuid NOT NULL FK → tokens
node_id string NOT NULL 对应的流程节点
node_name string NULL 节点名称(冗余,便于查询)
assignee_id uuid NULL 指定处理人
candidate_groups jsonb NULL 候选角色组
status string NOT NULL DEFAULT 'pending' pending/approved/rejected/delegated
outcome string NULL 审批结果
form_data jsonb NULL 表单数据
due_date timestamptz NULL 到期时间
completed_at timestamptz NULL
+ 标准审计字段
索引: idx_tasks_assignee (tenant_id, assignee_id, status)
索引: idx_tasks_instance (instance_id)

process_variables

类型 说明
id uuid PK UUIDv7
tenant_id uuid NOT NULL
instance_id uuid NOT NULL FK → process_instances
name string NOT NULL 变量名
var_type string NOT NULL DEFAULT 'string' string/number/boolean/date/json
value_string text NULL
value_number double precision NULL
value_boolean boolean NULL
value_date timestamptz NULL
唯一索引: (instance_id, name)

验证: cargo run -p erp-server 启动后 \dt 可见新表


Task 3: SeaORM Entity

创建文件(crates/erp-workflow/src/entity/

  • mod.rs — 导出所有实体
  • process_definition.rs
  • process_instance.rs
  • token.rs
  • task.rs
  • process_variable.rs

模式: 参考 erp-config/src/entity/numbering_rule.rs,包含 Relation 和 Related。

验证: cargo check 通过


Task 4: DTO 定义

修改文件: crates/erp-workflow/src/dto.rs

包含:

  • 流程定义:ProcessDefinitionResp, CreateProcessDefinitionReq, UpdateProcessDefinitionReq, PublishDefinitionReq
  • 流程实例:ProcessInstanceResp, StartInstanceReq
  • 任务:TaskResp, CompleteTaskReq(含 outcome + form_data
  • 流程变量:ProcessVariableResp, SetVariableReq
  • 流程图:NodeDefBPMN 节点), EdgeDef(连线), FlowDiagram(完整图)

节点类型: StartEvent, EndEvent, UserTask, ServiceTask, ExclusiveGateway, ParallelGateway 连线条件: condition 字段为可选表达式字符串(如 amount > 1000

验证: cargo check 通过


Task 5: BPMN 解析器 + 表达式引擎

创建文件(crates/erp-workflow/src/engine/

  • model.rs — 流程图内存模型FlowDiagram, FlowNode, FlowEdge, NodeType 枚举)
  • parser.rs — 解析 JSON nodes/edges 为内存模型,验证流程图合法性
  • expression.rs — 简单表达式求值器(支持比较运算和流程变量引用)

关键逻辑:

  • FlowDiagram::validate() — 检查:恰好 1 个 StartEvent至少 1 个 EndEvent无悬空连线网关分支/汇合配对
  • ExpressionEvaluator::eval(expr, variables) -> bool — 支持 var > 1000, status == "approved", amount <= budget 格式
  • 解析器将 nodesedges jsonb 反序列化为 Vec<FlowNode>Vec<FlowEdge>

验证: 单元测试覆盖:合法流程验证、缺少 StartEvent 报错、表达式求值


Task 6: Token 驱动执行引擎

创建文件: crates/erp-workflow/src/engine/executor.rs

核心逻辑:

start(instance_id, definition) → 在 StartEvent 创建 token
advance(token_id, instance_id, definition, variables) → 消费当前 token在下一节点创建新 token
  - 到达 EndEvent → 消费 token检查实例是否所有 token 都完成 → 完成实例
  - 到达 UserTask → 创建 token + 创建 task 记录
  - 到达 ServiceTask → 创建 token + 执行动作(占位,发布事件)
  - 到达 ExclusiveGateway → 求值条件,选择一条分支
  - 到达 ParallelGateway分支→ 为每条出边创建 token
  - 到达 ParallelGateway汇合→ 消费当前 token等待所有入边 token 到达后创建新 token

并发安全: 使用 pg_advisory_xact_lock 保护 token 操作(参考 NumberingService 模式)

验证: 单元测试覆盖:直线流程、排他网关分支、并行网关分支与汇合


Task 7: Service 层

创建文件(crates/erp-workflow/src/service/

  • definition_service.rs — 流程定义 CRUD + 发布 + 版本管理
  • instance_service.rs — 启动实例 + 查询 + 挂起/恢复/终止
  • task_service.rs — 查询待办 + 完成任务 + 委派 + 查询已办

关键逻辑:

  • DefinitionService::publish — draft → published验证流程图合法性
  • InstanceService::start — 创建实例 + 初始化变量 + 调用 executor.start
  • TaskService::complete — 更新 task 状态 + 调用 executor.advance + 处理下一节点

Task 8: Handler 层

创建文件(crates/erp-workflow/src/handler/

  • definition_handler.rs — 5 个端点
  • instance_handler.rs — 4 个端点
  • task_handler.rs — 4 个端点

端点映射:

GET/POST  /workflow/definitions
GET       /workflow/definitions/{id}
PUT       /workflow/definitions/{id}
POST      /workflow/definitions/{id}/publish
POST      /workflow/instances
GET       /workflow/instances
GET       /workflow/instances/{id}
POST      /workflow/instances/{id}/suspend
POST      /workflow/instances/{id}/terminate
GET       /workflow/tasks/pending          — 我的待办
GET       /workflow/tasks/completed        — 我的已办
POST      /workflow/tasks/{id}/complete    — 完成任务
POST      /workflow/tasks/{id}/delegate    — 委派任务

RBAC 所有端点使用 require_permission(&ctx, "workflow:xxx")


Task 9: 模块注册 + 种子数据

修改文件:

  • crates/erp-workflow/src/module.rs — 填充真实路由12 个端点)
  • crates/erp-auth/src/service/seed.rs — 添加工作流权限
  • crates/erp-server/src/main.rs — 注册 WorkflowModule合并路由

新增种子权限8 个):

  • workflow:create, workflow:list, workflow:read, workflow:update
  • workflow:publish, workflow:start, workflow:approve, workflow:delegate

验证: cargo check + cargo test 通过


Task 10: 前端 API 层 + 工作流页面

创建文件(apps/web/src/

  • api/workflowDefinitions.ts — 流程定义 API
  • api/workflowInstances.ts — 流程实例 API
  • api/workflowTasks.ts — 任务 API
  • pages/Workflow.tsx — Tab 壳页面(流程定义 | 我的待办 | 我的已办 | 流程监控)

修改文件:

  • App.tsx — 添加 workflow 路由
  • MainLayout.tsx — 侧边栏添加工作流菜单

Task 11: React Flow 可视化设计器

创建文件(apps/web/src/pages/workflow/

  • ProcessDesigner.tsx — React Flow 画布 + 节点面板 + 属性面板
  • nodes/ — 自定义节点组件StartEvent, EndEvent, UserTask, ServiceTask, Gateway
  • edges/ — 条件标签连线组件
  • hooks/useFlowValidation.ts — 流程图前端验证

依赖: @xyflow/react npm 包

功能:

  • 拖拽添加节点到画布
  • 连线编辑(含条件表达式)
  • 节点属性编辑面板
  • 导出为 JSON nodes/edges 格式(匹配后端 DTO
  • 流程图合法性前端验证

Task 12: 流程图查看器 + 超时框架

创建文件(apps/web/src/pages/workflow/

  • ProcessViewer.tsx — 只读 React Flow 渲染,高亮当前活跃节点
  • InstanceDetail.tsx — 实例详情页(流程图 + 变量 + 任务历史)

超时框架(后端占位):

  • crates/erp-workflow/src/engine/timeout.rs — 超时检查接口
  • Task 表 due_date 字段已支持

验证: pnpm dev 启动,工作流设计器可拖拽节点、连线、保存


依赖图

Task 1骨架
     |
Task 2迁移→ Task 3Entity→ Task 4DTO
                                      |
                      +---------------+---------------+
                      |                               |
              Task 5BPMN 解析器)          Task 6执行引擎
                      |                               |
                      +---------------+---------------+
                                      |
                              Task 7Service
                                      |
                              Task 8Handler
                                      |
                              Task 9集成+种子)
                                      |
                      +---------------+---------------+
                      |                               |
              Task 10前端页面             Task 11可视化设计器
                      |                               |
                      +---------------+---------------+
                                      |
                              Task 12查看器+超时)

验证清单

  • cargo check 全 workspace 通过
  • cargo test --workspace 全部通过
  • Docker 环境正常启动
  • 所有迁移可正/反向执行
  • 12 个工作流 API 端点可测试
  • 前端工作流设计器可拖拽节点和连线
  • 流程图保存和加载正常
  • 所有代码已提交

关键参考文件

用途 文件路径
Service 模式 crates/erp-config/src/service/numbering_service.rs
Handler 模式 crates/erp-config/src/handler/numbering_handler.rs
State 桥接 crates/erp-server/src/state.rs
模块注册 crates/erp-config/src/module.rs
迁移模式 crates/erp-server/migration/src/m20260412_000016_create_settings.rs
Advisory Lock crates/erp-config/src/service/numbering_service.rs (generate_number)
前端 Table CRUD apps/web/src/pages/Roles.tsx
前端树形展示 apps/web/src/pages/Organizations.tsx
RBAC crates/erp-core/src/rbac.rs