ai-engineering-init 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/code-reviewer.md +139 -0
- package/.claude/agents/project-manager.md +159 -0
- package/.claude/audio/completed.wav +0 -0
- package/.claude/commands/add-todo.md +255 -0
- package/.claude/commands/check.md +210 -0
- package/.claude/commands/crud.md +454 -0
- package/.claude/commands/dev.md +503 -0
- package/.claude/commands/init-docs.md +681 -0
- package/.claude/commands/next.md +251 -0
- package/.claude/commands/progress.md +242 -0
- package/.claude/commands/start.md +199 -0
- package/.claude/commands/sync.md +307 -0
- package/.claude/commands/update-status.md +428 -0
- package/.claude/docs/Mixin/344/275/277/347/224/250/346/214/207/345/215/227.md +299 -0
- package/.claude/docs/README.md +167 -0
- package/.claude/docs//345/211/215/347/253/257/345/274/200/345/217/221/346/214/207/345/215/227.md +599 -0
- package/.claude/docs//345/220/216/347/253/257/345/274/200/345/217/221/346/214/207/345/215/227.md +726 -0
- package/.claude/docs//345/267/245/344/275/234/346/265/201/345/274/200/345/217/221/346/214/207/345/215/227.md +714 -0
- package/.claude/docs//345/267/245/345/205/267/347/261/273/344/275/277/347/224/250/346/214/207/345/215/227.md +463 -0
- package/.claude/docs//346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/350/247/204/350/214/203.md +390 -0
- package/.claude/docs//346/226/260/345/212/237/350/203/275/345/274/200/345/217/221/346/265/201/347/250/213/350/247/204/350/214/203.md +688 -0
- package/.claude/docs//346/226/260/351/241/271/347/233/256/345/274/200/345/217/221/346/265/201/347/250/213.md +365 -0
- package/.claude/docs//346/241/206/346/236/266/350/257/264/346/230/216.md +393 -0
- package/.claude/docs//350/267/257/347/224/261/351/205/215/347/275/256/346/214/207/345/215/227.md +246 -0
- package/.claude/framework-config.json +73 -0
- package/.claude/hooks/pre-tool-use.js +117 -0
- package/.claude/hooks/skill-forced-eval.js +167 -0
- package/.claude/hooks/stop.js +58 -0
- package/.claude/settings.json +41 -0
- package/.claude/skills/add-skill/SKILL.md +352 -0
- package/.claude/skills/api-development/SKILL.md +560 -0
- package/.claude/skills/architecture-design/SKILL.md +756 -0
- package/.claude/skills/backend-annotations/SKILL.md +674 -0
- package/.claude/skills/banana-image/CHANGELOG.md +37 -0
- package/.claude/skills/banana-image/README.md +146 -0
- package/.claude/skills/banana-image/SKILL.md +164 -0
- package/.claude/skills/banana-image/assets/logo.png +0 -0
- package/.claude/skills/banana-image/references/advanced-usage.md +189 -0
- package/.claude/skills/banana-image/scripts/apply_template.py +125 -0
- package/.claude/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/.claude/skills/banana-image/scripts/batch_prep.py +82 -0
- package/.claude/skills/banana-image/scripts/package-lock.json +1437 -0
- package/.claude/skills/banana-image/scripts/package.json +18 -0
- package/.claude/skills/banana-image/scripts/requirements.txt +10 -0
- package/.claude/skills/banana-image/templates/poster.json +22 -0
- package/.claude/skills/banana-image/templates/product.json +17 -0
- package/.claude/skills/banana-image/templates/social.json +22 -0
- package/.claude/skills/banana-image/templates/thumbnail.json +17 -0
- package/.claude/skills/brainstorm/SKILL.md +648 -0
- package/.claude/skills/bug-detective/SKILL.md +1206 -0
- package/.claude/skills/code-patterns/SKILL.md +590 -0
- package/.claude/skills/collaborating-with-codex/SKILL.md +174 -0
- package/.claude/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/.claude/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/.claude/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/.claude/skills/crud-development/SKILL.md +649 -0
- package/.claude/skills/data-permission/SKILL.md +599 -0
- package/.claude/skills/database-ops/SKILL.md +407 -0
- package/.claude/skills/error-handler/SKILL.md +371 -0
- package/.claude/skills/file-oss-management/SKILL.md +863 -0
- package/.claude/skills/git-workflow/SKILL.md +375 -0
- package/.claude/skills/json-serialization/SKILL.md +357 -0
- package/.claude/skills/leniu-api-development/SKILL.md +803 -0
- package/.claude/skills/leniu-architecture-design/SKILL.md +598 -0
- package/.claude/skills/leniu-backend-annotations/SKILL.md +664 -0
- package/.claude/skills/leniu-code-patterns/SKILL.md +365 -0
- package/.claude/skills/leniu-crud-development/SKILL.md +1110 -0
- package/.claude/skills/leniu-data-permission/SKILL.md +256 -0
- package/.claude/skills/leniu-database-ops/SKILL.md +426 -0
- package/.claude/skills/leniu-error-handler/SKILL.md +462 -0
- package/.claude/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/.claude/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.claude/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/.claude/skills/leniu-java-entity/SKILL.md +751 -0
- package/.claude/skills/leniu-java-export/SKILL.md +560 -0
- package/.claude/skills/leniu-java-logging/SKILL.md +832 -0
- package/.claude/skills/leniu-java-mq/SKILL.md +338 -0
- package/.claude/skills/leniu-java-mybatis/SKILL.md +640 -0
- package/.claude/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/.claude/skills/leniu-java-task/SKILL.md +367 -0
- package/.claude/skills/leniu-java-total-line/SKILL.md +195 -0
- package/.claude/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/.claude/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/.claude/skills/leniu-mealtime/SKILL.md +215 -0
- package/.claude/skills/leniu-redis-cache/SKILL.md +316 -0
- package/.claude/skills/leniu-security-guard/SKILL.md +520 -0
- package/.claude/skills/leniu-utils-toolkit/SKILL.md +380 -0
- package/.claude/skills/openspec-apply-change/SKILL.md +156 -0
- package/.claude/skills/openspec-archive-change/SKILL.md +114 -0
- package/.claude/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.claude/skills/openspec-continue-change/SKILL.md +118 -0
- package/.claude/skills/openspec-explore/SKILL.md +290 -0
- package/.claude/skills/openspec-ff-change/SKILL.md +101 -0
- package/.claude/skills/openspec-new-change/SKILL.md +74 -0
- package/.claude/skills/openspec-onboard/SKILL.md +529 -0
- package/.claude/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.claude/skills/openspec-verify-change/SKILL.md +168 -0
- package/.claude/skills/performance-doctor/SKILL.md +627 -0
- package/.claude/skills/project-navigator/SKILL.md +305 -0
- package/.claude/skills/redis-cache/SKILL.md +839 -0
- package/.claude/skills/scheduled-jobs/SKILL.md +633 -0
- package/.claude/skills/security-guard/SKILL.md +748 -0
- package/.claude/skills/sms-mail/SKILL.md +766 -0
- package/.claude/skills/social-login/SKILL.md +668 -0
- package/.claude/skills/store-pc/SKILL.md +366 -0
- package/.claude/skills/task-tracker/SKILL.md +307 -0
- package/.claude/skills/tech-decision/SKILL.md +393 -0
- package/.claude/skills/tenant-management/SKILL.md +603 -0
- package/.claude/skills/test-development/SKILL.md +755 -0
- package/.claude/skills/ui-pc/SKILL.md +438 -0
- package/.claude/skills/utils-toolkit/SKILL.md +615 -0
- package/.claude/skills/websocket-sse/SKILL.md +716 -0
- package/.claude/skills/workflow-engine/SKILL.md +676 -0
- package/.claude/templates//345/276/205/345/212/236/346/270/205/345/215/225/346/250/241/346/235/277.md +56 -0
- package/.claude/templates//351/234/200/346/261/202/346/226/207/346/241/243/346/250/241/346/235/277.md +85 -0
- package/.claude/templates//351/241/271/347/233/256/347/212/266/346/200/201/346/250/241/346/235/277.md +43 -0
- package/.codex/skills/add-skill/SKILL.md +352 -0
- package/.codex/skills/add-todo/SKILL.md +269 -0
- package/.codex/skills/api-development/SKILL.md +693 -0
- package/.codex/skills/architecture-design/SKILL.md +628 -0
- package/.codex/skills/backend-annotations/SKILL.md +664 -0
- package/.codex/skills/banana-image/CHANGELOG.md +37 -0
- package/.codex/skills/banana-image/README.md +146 -0
- package/.codex/skills/banana-image/SKILL.md +164 -0
- package/.codex/skills/banana-image/assets/logo.png +0 -0
- package/.codex/skills/banana-image/references/advanced-usage.md +189 -0
- package/.codex/skills/banana-image/scripts/apply_template.py +125 -0
- package/.codex/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/.codex/skills/banana-image/scripts/batch_prep.py +82 -0
- package/.codex/skills/banana-image/scripts/package-lock.json +1437 -0
- package/.codex/skills/banana-image/scripts/package.json +18 -0
- package/.codex/skills/banana-image/scripts/requirements.txt +10 -0
- package/.codex/skills/banana-image/templates/poster.json +22 -0
- package/.codex/skills/banana-image/templates/product.json +17 -0
- package/.codex/skills/banana-image/templates/social.json +22 -0
- package/.codex/skills/banana-image/templates/thumbnail.json +17 -0
- package/.codex/skills/brainstorm/SKILL.md +648 -0
- package/.codex/skills/bug-detective/SKILL.md +1206 -0
- package/.codex/skills/check/SKILL.md +367 -0
- package/.codex/skills/code-patterns/SKILL.md +442 -0
- package/.codex/skills/collaborating-with-codex/SKILL.md +174 -0
- package/.codex/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/.codex/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/.codex/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/.codex/skills/crud/SKILL.md +265 -0
- package/.codex/skills/crud-development/SKILL.md +637 -0
- package/.codex/skills/data-permission/SKILL.md +591 -0
- package/.codex/skills/database-ops/SKILL.md +553 -0
- package/.codex/skills/dev/SKILL.md +187 -0
- package/.codex/skills/error-handler/SKILL.md +361 -0
- package/.codex/skills/file-oss-management/SKILL.md +863 -0
- package/.codex/skills/git-workflow/SKILL.md +375 -0
- package/.codex/skills/init-docs/SKILL.md +194 -0
- package/.codex/skills/json-serialization/SKILL.md +357 -0
- package/.codex/skills/leniu-api-development/SKILL.md +803 -0
- package/.codex/skills/leniu-architecture-design/SKILL.md +594 -0
- package/.codex/skills/leniu-backend-annotations/SKILL.md +662 -0
- package/.codex/skills/leniu-code-patterns/SKILL.md +365 -0
- package/.codex/skills/leniu-crud-development/SKILL.md +1110 -0
- package/.codex/skills/leniu-data-permission/SKILL.md +256 -0
- package/.codex/skills/leniu-database-ops/SKILL.md +426 -0
- package/.codex/skills/leniu-error-handler/SKILL.md +462 -0
- package/.codex/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/.codex/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.codex/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/.codex/skills/leniu-java-entity/SKILL.md +751 -0
- package/.codex/skills/leniu-java-export/SKILL.md +560 -0
- package/.codex/skills/leniu-java-logging/SKILL.md +832 -0
- package/.codex/skills/leniu-java-mq/SKILL.md +338 -0
- package/.codex/skills/leniu-java-mybatis/SKILL.md +640 -0
- package/.codex/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/.codex/skills/leniu-java-task/SKILL.md +367 -0
- package/.codex/skills/leniu-java-total-line/SKILL.md +195 -0
- package/.codex/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/.codex/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/.codex/skills/leniu-mealtime/SKILL.md +215 -0
- package/.codex/skills/leniu-redis-cache/SKILL.md +316 -0
- package/.codex/skills/leniu-security-guard/SKILL.md +520 -0
- package/.codex/skills/leniu-utils-toolkit/SKILL.md +378 -0
- package/.codex/skills/next/SKILL.md +137 -0
- package/.codex/skills/openspec-apply-change/SKILL.md +156 -0
- package/.codex/skills/openspec-archive-change/SKILL.md +114 -0
- package/.codex/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.codex/skills/openspec-continue-change/SKILL.md +118 -0
- package/.codex/skills/openspec-explore/SKILL.md +290 -0
- package/.codex/skills/openspec-ff-change/SKILL.md +101 -0
- package/.codex/skills/openspec-new-change/SKILL.md +74 -0
- package/.codex/skills/openspec-onboard/SKILL.md +529 -0
- package/.codex/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.codex/skills/openspec-verify-change/SKILL.md +168 -0
- package/.codex/skills/performance-doctor/SKILL.md +627 -0
- package/.codex/skills/progress/SKILL.md +193 -0
- package/.codex/skills/project-navigator/SKILL.md +286 -0
- package/.codex/skills/redis-cache/SKILL.md +829 -0
- package/.codex/skills/scheduled-jobs/SKILL.md +633 -0
- package/.codex/skills/security-guard/SKILL.md +739 -0
- package/.codex/skills/sms-mail/SKILL.md +766 -0
- package/.codex/skills/social-login/SKILL.md +668 -0
- package/.codex/skills/start/SKILL.md +154 -0
- package/.codex/skills/store-pc/SKILL.md +491 -0
- package/.codex/skills/sync/SKILL.md +149 -0
- package/.codex/skills/task-tracker/SKILL.md +307 -0
- package/.codex/skills/tech-decision/SKILL.md +393 -0
- package/.codex/skills/tenant-management/SKILL.md +603 -0
- package/.codex/skills/test-development/SKILL.md +755 -0
- package/.codex/skills/ui-pc/SKILL.md +475 -0
- package/.codex/skills/update-status/SKILL.md +159 -0
- package/.codex/skills/utils-toolkit/SKILL.md +593 -0
- package/.codex/skills/websocket-sse/SKILL.md +716 -0
- package/.codex/skills/workflow-engine/SKILL.md +676 -0
- package/.cursor/agents/code-reviewer.md +139 -0
- package/.cursor/agents/project-manager.md +159 -0
- package/.cursor/commands/opsx-apply.md +152 -0
- package/.cursor/commands/opsx-archive.md +157 -0
- package/.cursor/commands/opsx-bulk-archive.md +242 -0
- package/.cursor/commands/opsx-continue.md +114 -0
- package/.cursor/commands/opsx-explore.md +174 -0
- package/.cursor/commands/opsx-ff.md +94 -0
- package/.cursor/commands/opsx-new.md +69 -0
- package/.cursor/commands/opsx-onboard.md +525 -0
- package/.cursor/commands/opsx-sync.md +134 -0
- package/.cursor/commands/opsx-verify.md +164 -0
- package/.cursor/mcp.json +22 -0
- package/.cursor/skills/add-skill/SKILL.md +352 -0
- package/.cursor/skills/api-development/SKILL.md +560 -0
- package/.cursor/skills/architecture-design/SKILL.md +756 -0
- package/.cursor/skills/backend-annotations/SKILL.md +674 -0
- package/.cursor/skills/banana-image/CHANGELOG.md +37 -0
- package/.cursor/skills/banana-image/README.md +146 -0
- package/.cursor/skills/banana-image/SKILL.md +164 -0
- package/.cursor/skills/banana-image/assets/logo.png +0 -0
- package/.cursor/skills/banana-image/references/advanced-usage.md +189 -0
- package/.cursor/skills/banana-image/scripts/apply_template.py +125 -0
- package/.cursor/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/.cursor/skills/banana-image/scripts/batch_prep.py +82 -0
- package/.cursor/skills/banana-image/scripts/package-lock.json +1437 -0
- package/.cursor/skills/banana-image/scripts/package.json +18 -0
- package/.cursor/skills/banana-image/scripts/requirements.txt +10 -0
- package/.cursor/skills/banana-image/templates/poster.json +22 -0
- package/.cursor/skills/banana-image/templates/product.json +17 -0
- package/.cursor/skills/banana-image/templates/social.json +22 -0
- package/.cursor/skills/banana-image/templates/thumbnail.json +17 -0
- package/.cursor/skills/brainstorm/SKILL.md +648 -0
- package/.cursor/skills/bug-detective/SKILL.md +1206 -0
- package/.cursor/skills/code-patterns/SKILL.md +590 -0
- package/.cursor/skills/collaborating-with-codex/SKILL.md +174 -0
- package/.cursor/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/.cursor/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/.cursor/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/.cursor/skills/crud-development/SKILL.md +649 -0
- package/.cursor/skills/data-permission/SKILL.md +599 -0
- package/.cursor/skills/database-ops/SKILL.md +407 -0
- package/.cursor/skills/error-handler/SKILL.md +371 -0
- package/.cursor/skills/file-oss-management/SKILL.md +863 -0
- package/.cursor/skills/git-workflow/SKILL.md +375 -0
- package/.cursor/skills/json-serialization/SKILL.md +357 -0
- package/.cursor/skills/leniu-api-development/SKILL.md +803 -0
- package/.cursor/skills/leniu-architecture-design/SKILL.md +598 -0
- package/.cursor/skills/leniu-backend-annotations/SKILL.md +664 -0
- package/.cursor/skills/leniu-code-patterns/SKILL.md +365 -0
- package/.cursor/skills/leniu-crud-development/SKILL.md +1110 -0
- package/.cursor/skills/leniu-data-permission/SKILL.md +256 -0
- package/.cursor/skills/leniu-database-ops/SKILL.md +426 -0
- package/.cursor/skills/leniu-error-handler/SKILL.md +462 -0
- package/.cursor/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/.cursor/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.cursor/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/.cursor/skills/leniu-java-entity/SKILL.md +751 -0
- package/.cursor/skills/leniu-java-export/SKILL.md +560 -0
- package/.cursor/skills/leniu-java-logging/SKILL.md +832 -0
- package/.cursor/skills/leniu-java-mq/SKILL.md +338 -0
- package/.cursor/skills/leniu-java-mybatis/SKILL.md +640 -0
- package/.cursor/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/.cursor/skills/leniu-java-task/SKILL.md +367 -0
- package/.cursor/skills/leniu-java-total-line/SKILL.md +195 -0
- package/.cursor/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/.cursor/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/.cursor/skills/leniu-mealtime/SKILL.md +215 -0
- package/.cursor/skills/leniu-redis-cache/SKILL.md +316 -0
- package/.cursor/skills/leniu-security-guard/SKILL.md +520 -0
- package/.cursor/skills/leniu-utils-toolkit/SKILL.md +380 -0
- package/.cursor/skills/openspec-apply-change/SKILL.md +156 -0
- package/.cursor/skills/openspec-archive-change/SKILL.md +114 -0
- package/.cursor/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.cursor/skills/openspec-continue-change/SKILL.md +118 -0
- package/.cursor/skills/openspec-explore/SKILL.md +290 -0
- package/.cursor/skills/openspec-ff-change/SKILL.md +101 -0
- package/.cursor/skills/openspec-new-change/SKILL.md +74 -0
- package/.cursor/skills/openspec-onboard/SKILL.md +529 -0
- package/.cursor/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.cursor/skills/openspec-verify-change/SKILL.md +168 -0
- package/.cursor/skills/performance-doctor/SKILL.md +627 -0
- package/.cursor/skills/project-navigator/SKILL.md +305 -0
- package/.cursor/skills/redis-cache/SKILL.md +839 -0
- package/.cursor/skills/scheduled-jobs/SKILL.md +633 -0
- package/.cursor/skills/security-guard/SKILL.md +748 -0
- package/.cursor/skills/sms-mail/SKILL.md +766 -0
- package/.cursor/skills/social-login/SKILL.md +668 -0
- package/.cursor/skills/store-pc/SKILL.md +366 -0
- package/.cursor/skills/task-tracker/SKILL.md +307 -0
- package/.cursor/skills/tech-decision/SKILL.md +393 -0
- package/.cursor/skills/tenant-management/SKILL.md +603 -0
- package/.cursor/skills/test-development/SKILL.md +755 -0
- package/.cursor/skills/ui-pc/SKILL.md +438 -0
- package/.cursor/skills/utils-toolkit/SKILL.md +615 -0
- package/.cursor/skills/websocket-sse/SKILL.md +716 -0
- package/.cursor/skills/workflow-engine/SKILL.md +676 -0
- package/AGENTS.md +669 -0
- package/CLAUDE.md +205 -0
- package/README.md +205 -0
- package/bin/index.js +179 -0
- package/init.sh +178 -0
- package/package.json +27 -0
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
# 工作流开发指南
|
|
2
|
+
|
|
3
|
+
> **重要提示**: 本项目是 RuoYi-Vue-Plus **纯后端项目**,采用**三层架构**。
|
|
4
|
+
> 工作流模块基于 **WarmFlow** 实现,提供流程定义、流程实例、任务管理等功能。
|
|
5
|
+
|
|
6
|
+
最后更新: 2026-02-09
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 🏗️ 核心架构
|
|
11
|
+
|
|
12
|
+
### 模块信息
|
|
13
|
+
|
|
14
|
+
| 项目 | 规范 |
|
|
15
|
+
|------|------|
|
|
16
|
+
| **模块位置** | `ruoyi-modules/ruoyi-workflow/` |
|
|
17
|
+
| **包路径** | `org.dromara.workflow` |
|
|
18
|
+
| **表前缀** | `flow_` |
|
|
19
|
+
| **架构** | 三层:Controller → Service → Mapper(无 DAO 层) |
|
|
20
|
+
| **工作流引擎** | WarmFlow |
|
|
21
|
+
|
|
22
|
+
### 架构图
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
26
|
+
│ Controller Layer │
|
|
27
|
+
│ FlwTaskController | FlwInstanceController | FlwDefinitionController
|
|
28
|
+
│ FlwCategoryController | FlwSpelController | TestLeaveController │
|
|
29
|
+
└─────────────────────────────┬───────────────────────────────────┘
|
|
30
|
+
│
|
|
31
|
+
┌─────────────────────────────▼───────────────────────────────────┐
|
|
32
|
+
│ Service Layer │
|
|
33
|
+
│ FlwTaskService | FlwInstanceService | FlwDefinitionService │
|
|
34
|
+
│ FlwCategoryService | FlwSpelService | TestLeaveService │
|
|
35
|
+
│ │ │
|
|
36
|
+
│ ┌───────────────────────────▼─────────────────────────────────┐│
|
|
37
|
+
│ │ WarmFlow Core (FlowEngine) ││
|
|
38
|
+
│ │ TaskService | InsService | DefService | NodeService ││
|
|
39
|
+
│ └─────────────────────────────────────────────────────────────┘│
|
|
40
|
+
└─────────────────────────────┬───────────────────────────────────┘
|
|
41
|
+
│
|
|
42
|
+
┌─────────────────────────────▼───────────────────────────────────┐
|
|
43
|
+
│ Mapper Layer │
|
|
44
|
+
│ FlwCategoryMapper | FlwSpelMapper | TestLeaveMapper │
|
|
45
|
+
│ FlwInstanceMapper | FlwTaskMapper | FlwInstanceBizExtMapper │
|
|
46
|
+
└─────────────────────────────┬───────────────────────────────────┘
|
|
47
|
+
│
|
|
48
|
+
┌─────────────────────────────▼───────────────────────────────────┐
|
|
49
|
+
│ Listener & Handler │
|
|
50
|
+
│ WorkflowGlobalListener (任务监听) | FlowProcessEventHandler (事件发布)
|
|
51
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 📁 模块目录结构
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/
|
|
60
|
+
├── controller/
|
|
61
|
+
│ ├── FlwTaskController.java # 任务管理
|
|
62
|
+
│ ├── FlwInstanceController.java # 实例管理
|
|
63
|
+
│ ├── FlwDefinitionController.java # 流程定义
|
|
64
|
+
│ ├── FlwCategoryController.java # 流程分类
|
|
65
|
+
│ ├── FlwSpelController.java # SpEL表达式
|
|
66
|
+
│ └── TestLeaveController.java # 请假示例
|
|
67
|
+
├── service/
|
|
68
|
+
│ ├── IFlwTaskService.java
|
|
69
|
+
│ ├── IFlwInstanceService.java
|
|
70
|
+
│ ├── IFlwDefinitionService.java
|
|
71
|
+
│ ├── IFlwCategoryService.java
|
|
72
|
+
│ ├── IFlwSpelService.java
|
|
73
|
+
│ ├── IFlwTaskAssigneeService.java
|
|
74
|
+
│ ├── IFlwNodeExtService.java
|
|
75
|
+
│ ├── IFlwCommonService.java
|
|
76
|
+
│ ├── ITestLeaveService.java
|
|
77
|
+
│ └── impl/
|
|
78
|
+
│ ├── FlwTaskServiceImpl.java
|
|
79
|
+
│ ├── FlwInstanceServiceImpl.java
|
|
80
|
+
│ ├── FlwDefinitionServiceImpl.java
|
|
81
|
+
│ ├── FlwCategoryServiceImpl.java
|
|
82
|
+
│ ├── FlwSpelServiceImpl.java
|
|
83
|
+
│ ├── FlwTaskAssigneeServiceImpl.java
|
|
84
|
+
│ ├── FlwNodeExtServiceImpl.java
|
|
85
|
+
│ ├── FlwCommonServiceImpl.java
|
|
86
|
+
│ ├── TestLeaveServiceImpl.java
|
|
87
|
+
│ └── WorkflowServiceImpl.java # 通用工作流服务
|
|
88
|
+
├── mapper/ # Mapper 层(非 DAO)
|
|
89
|
+
│ ├── FlwCategoryMapper.java
|
|
90
|
+
│ ├── FlwSpelMapper.java
|
|
91
|
+
│ ├── FlwTaskMapper.java
|
|
92
|
+
│ ├── FlwInstanceMapper.java
|
|
93
|
+
│ ├── FlwInstanceBizExtMapper.java
|
|
94
|
+
│ └── TestLeaveMapper.java
|
|
95
|
+
├── listener/
|
|
96
|
+
│ └── WorkflowGlobalListener.java # 全局监听器
|
|
97
|
+
├── handler/
|
|
98
|
+
│ ├── FlowProcessEventHandler.java # 事件发布
|
|
99
|
+
│ └── WorkflowPermissionHandler.java # 权限处理
|
|
100
|
+
├── rule/
|
|
101
|
+
│ └── SpelRuleComponent.java # SpEL 规则组件
|
|
102
|
+
├── domain/
|
|
103
|
+
│ ├── FlowCategory.java
|
|
104
|
+
│ ├── FlowSpel.java
|
|
105
|
+
│ ├── FlowInstanceBizExt.java
|
|
106
|
+
│ ├── TestLeave.java
|
|
107
|
+
│ ├── bo/ # 业务对象
|
|
108
|
+
│ │ ├── StartProcessBo.java
|
|
109
|
+
│ │ ├── CompleteTaskBo.java
|
|
110
|
+
│ │ ├── BackProcessBo.java
|
|
111
|
+
│ │ ├── TaskOperationBo.java
|
|
112
|
+
│ │ └── ...
|
|
113
|
+
│ └── vo/ # 视图对象
|
|
114
|
+
│ ├── FlowTaskVo.java
|
|
115
|
+
│ ├── FlowHisTaskVo.java
|
|
116
|
+
│ ├── FlowInstanceVo.java
|
|
117
|
+
│ └── ...
|
|
118
|
+
├── config/
|
|
119
|
+
│ └── WarmFlowConfig.java # WarmFlow 配置
|
|
120
|
+
└── common/
|
|
121
|
+
├── ConditionalOnEnable.java # 条件注解
|
|
122
|
+
├── constant/
|
|
123
|
+
│ └── FlowConstant.java # 常量
|
|
124
|
+
└── enums/
|
|
125
|
+
├── TaskStatusEnum.java # 任务状态
|
|
126
|
+
├── TaskAssigneeEnum.java # 办理人类型
|
|
127
|
+
├── TaskAssigneeType.java # 办理人类型扩展
|
|
128
|
+
├── MessageTypeEnum.java # 消息类型
|
|
129
|
+
├── ButtonPermissionEnum.java # 按钮权限
|
|
130
|
+
├── CopySettingEnum.java # 抄送设置
|
|
131
|
+
├── NodeExtEnum.java # 节点扩展
|
|
132
|
+
└── VariablesEnum.java # 变量枚举
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 🔧 核心组件
|
|
138
|
+
|
|
139
|
+
### 1. FlowEngine 服务访问
|
|
140
|
+
|
|
141
|
+
```java
|
|
142
|
+
import org.dromara.warm.flow.core.FlowEngine;
|
|
143
|
+
|
|
144
|
+
// 任务服务
|
|
145
|
+
FlowEngine.taskService()
|
|
146
|
+
|
|
147
|
+
// 实例服务
|
|
148
|
+
FlowEngine.insService()
|
|
149
|
+
|
|
150
|
+
// 流程定义服务
|
|
151
|
+
FlowEngine.defService()
|
|
152
|
+
|
|
153
|
+
// 节点服务
|
|
154
|
+
FlowEngine.nodeService()
|
|
155
|
+
|
|
156
|
+
// 历史任务服务
|
|
157
|
+
FlowEngine.hisTaskService()
|
|
158
|
+
|
|
159
|
+
// 用户服务
|
|
160
|
+
FlowEngine.userService()
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 2. 任务状态枚举
|
|
164
|
+
|
|
165
|
+
```java
|
|
166
|
+
package org.dromara.workflow.common.enums;
|
|
167
|
+
|
|
168
|
+
public enum TaskStatusEnum {
|
|
169
|
+
CANCEL("cancel", "撤销"),
|
|
170
|
+
PASS("pass", "通过"),
|
|
171
|
+
WAITING("waiting", "待审核"),
|
|
172
|
+
INVALID("invalid", "作废"),
|
|
173
|
+
BACK("back", "退回"),
|
|
174
|
+
TERMINATION("termination", "终止"),
|
|
175
|
+
TRANSFER("transfer", "转办"),
|
|
176
|
+
DEPUTE("depute", "委托"),
|
|
177
|
+
COPY("copy", "抄送"),
|
|
178
|
+
SIGN("sign", "加签"),
|
|
179
|
+
SIGN_OFF("sign_off", "减签"),
|
|
180
|
+
TIMEOUT("timeout", "超时");
|
|
181
|
+
|
|
182
|
+
private final String status;
|
|
183
|
+
private final String desc;
|
|
184
|
+
|
|
185
|
+
// 判断状态是否为通过或退回
|
|
186
|
+
public static boolean isPassOrBack(String status) {
|
|
187
|
+
return PASS.getStatus().equals(status) || BACK.getStatus().equals(status);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 3. 办理人类型枚举
|
|
193
|
+
|
|
194
|
+
> ⚠️ **注意**:USER 和 SPEL 类型没有前缀!
|
|
195
|
+
|
|
196
|
+
```java
|
|
197
|
+
package org.dromara.workflow.common.enums;
|
|
198
|
+
|
|
199
|
+
public enum TaskAssigneeEnum {
|
|
200
|
+
USER("用户", ""), // ⚠️ 用户没有前缀
|
|
201
|
+
ROLE("角色", "role:"),
|
|
202
|
+
DEPT("部门", "dept:"),
|
|
203
|
+
POST("岗位", "post:"),
|
|
204
|
+
SPEL("SpEL表达式", ""); // ⚠️ SpEL 没有前缀,通过 $ 或 # 开头判断
|
|
205
|
+
|
|
206
|
+
private final String desc;
|
|
207
|
+
private final String code;
|
|
208
|
+
|
|
209
|
+
// 判断是否为 SPEL 表达式(以 $ 或 # 开头)
|
|
210
|
+
public static boolean isSpelExpression(String value) {
|
|
211
|
+
return StringUtils.startsWith(value, "$") || StringUtils.startsWith(value, "#");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**storageId 格式示例**:
|
|
217
|
+
```
|
|
218
|
+
123 → 用户ID 123(无前缀)
|
|
219
|
+
role:456 → 角色ID 456
|
|
220
|
+
dept:789 → 部门ID 789
|
|
221
|
+
post:101 → 岗位ID 101
|
|
222
|
+
#{expression} → SpEL表达式(# 开头)
|
|
223
|
+
${variable} → 默认变量策略($ 开头)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 4. 流程常量
|
|
227
|
+
|
|
228
|
+
```java
|
|
229
|
+
package org.dromara.workflow.common.constant;
|
|
230
|
+
|
|
231
|
+
public interface FlowConstant {
|
|
232
|
+
// 基础常量
|
|
233
|
+
String INITIATOR = "initiator"; // 流程发起人
|
|
234
|
+
String INITIATOR_DEPT_ID = "initiatorDeptId"; // 发起人部门ID
|
|
235
|
+
String BUSINESS_ID = "businessId"; // 业务ID
|
|
236
|
+
String BUSINESS_CODE = "businessCode"; // 业务编码
|
|
237
|
+
String SUBMIT = "submit"; // 申请人提交标识
|
|
238
|
+
|
|
239
|
+
// 任务操作类型
|
|
240
|
+
String DELEGATE_TASK = "delegateTask"; // 委托任务
|
|
241
|
+
String TRANSFER_TASK = "transferTask"; // 转办任务
|
|
242
|
+
String ADD_SIGNATURE = "addSignature"; // 加签
|
|
243
|
+
String REDUCTION_SIGNATURE = "reductionSignature"; // 减签
|
|
244
|
+
|
|
245
|
+
// 抄送与消息
|
|
246
|
+
String FLOW_COPY_LIST = "flowCopyList"; // 抄送人列表
|
|
247
|
+
String MESSAGE_TYPE = "messageType"; // 消息类型
|
|
248
|
+
String MESSAGE_NOTICE = "messageNotice"; // 消息内容
|
|
249
|
+
|
|
250
|
+
// 自动化配置
|
|
251
|
+
String AUTO_PASS = "autoPass"; // 自动通过标识
|
|
252
|
+
|
|
253
|
+
// 忽略标识
|
|
254
|
+
String VAR_IGNORE = "ignore"; // 忽略办理权限校验
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## 📋 常用操作
|
|
261
|
+
|
|
262
|
+
### 1. 启动流程
|
|
263
|
+
|
|
264
|
+
```java
|
|
265
|
+
@Autowired
|
|
266
|
+
private IFlwTaskService flwTaskService;
|
|
267
|
+
|
|
268
|
+
// 方式一:使用 FlwTaskService
|
|
269
|
+
public void startProcess() {
|
|
270
|
+
StartProcessBo bo = new StartProcessBo();
|
|
271
|
+
bo.setFlowCode("leave_apply"); // 流程编码
|
|
272
|
+
bo.setBusinessId("order_123"); // 业务ID
|
|
273
|
+
bo.setVariables(Map.of("amount", 1000)); // 流程变量
|
|
274
|
+
|
|
275
|
+
StartProcessReturnDTO result = flwTaskService.startWorkFlow(bo);
|
|
276
|
+
Long instanceId = result.getProcessInstanceId();
|
|
277
|
+
Long taskId = result.getTaskId();
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
```java
|
|
282
|
+
@Autowired
|
|
283
|
+
private WorkflowService workflowService;
|
|
284
|
+
|
|
285
|
+
// 方式二:使用 WorkflowService(供其他模块调用)
|
|
286
|
+
public void startProcess() {
|
|
287
|
+
StartProcessDTO dto = new StartProcessDTO();
|
|
288
|
+
dto.setFlowCode("leave_apply");
|
|
289
|
+
dto.setBusinessId("order_123");
|
|
290
|
+
dto.setVariables(Map.of("amount", 1000));
|
|
291
|
+
|
|
292
|
+
StartProcessReturnDTO result = workflowService.startWorkFlow(dto);
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 2. 办理任务
|
|
297
|
+
|
|
298
|
+
```java
|
|
299
|
+
public void completeTask() {
|
|
300
|
+
CompleteTaskBo bo = new CompleteTaskBo();
|
|
301
|
+
bo.setTaskId(taskId); // 任务ID
|
|
302
|
+
bo.setMessage("同意"); // 审批意见
|
|
303
|
+
bo.setVariables(Map.of("approved", true)); // 流程变量
|
|
304
|
+
|
|
305
|
+
// 指定下一节点办理人(可选)
|
|
306
|
+
bo.setAssigneeMap(Map.of(
|
|
307
|
+
"pass:nodeCode", "user:1,user:2"
|
|
308
|
+
));
|
|
309
|
+
|
|
310
|
+
flwTaskService.completeTask(bo);
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### 3. 驳回任务
|
|
315
|
+
|
|
316
|
+
```java
|
|
317
|
+
public void rejectTask() {
|
|
318
|
+
BackProcessBo bo = new BackProcessBo();
|
|
319
|
+
bo.setTaskId(taskId);
|
|
320
|
+
bo.setNodeCode("apply_node"); // 驳回到的节点
|
|
321
|
+
bo.setMessage("资料不完整");
|
|
322
|
+
|
|
323
|
+
flwTaskService.backProcess(bo);
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### 4. 转办/委派
|
|
328
|
+
|
|
329
|
+
```java
|
|
330
|
+
// 转办(转给他人办理,自己不再参与)
|
|
331
|
+
TaskOperationBo transferBo = new TaskOperationBo();
|
|
332
|
+
transferBo.setTaskId(taskId);
|
|
333
|
+
transferBo.setUserId("targetUserId");
|
|
334
|
+
transferBo.setMessage("转交处理");
|
|
335
|
+
flwTaskService.taskOperation(transferBo, FlowConstant.TRANSFER_TASK);
|
|
336
|
+
|
|
337
|
+
// 委派(委托他人代办,最终还需自己确认)
|
|
338
|
+
TaskOperationBo deputeBo = new TaskOperationBo();
|
|
339
|
+
deputeBo.setTaskId(taskId);
|
|
340
|
+
deputeBo.setUserId("targetUserId");
|
|
341
|
+
deputeBo.setMessage("请协助处理");
|
|
342
|
+
flwTaskService.taskOperation(deputeBo, FlowConstant.DELEGATE_TASK);
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### 5. 加签/减签
|
|
346
|
+
|
|
347
|
+
```java
|
|
348
|
+
// 加签(增加办理人)
|
|
349
|
+
TaskOperationBo addBo = new TaskOperationBo();
|
|
350
|
+
addBo.setTaskId(taskId);
|
|
351
|
+
addBo.setUserIds(List.of("user1", "user2"));
|
|
352
|
+
addBo.setMessage("增加会签人员");
|
|
353
|
+
flwTaskService.taskOperation(addBo, FlowConstant.ADD_SIGNATURE);
|
|
354
|
+
|
|
355
|
+
// 减签(减少办理人)
|
|
356
|
+
TaskOperationBo reduceBo = new TaskOperationBo();
|
|
357
|
+
reduceBo.setTaskId(taskId);
|
|
358
|
+
reduceBo.setUserIds(List.of("user1"));
|
|
359
|
+
reduceBo.setMessage("减少会签人员");
|
|
360
|
+
flwTaskService.taskOperation(reduceBo, FlowConstant.REDUCTION_SIGNATURE);
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 6. 查询待办/已办任务
|
|
364
|
+
|
|
365
|
+
```java
|
|
366
|
+
@Autowired
|
|
367
|
+
private IFlwTaskService flwTaskService;
|
|
368
|
+
|
|
369
|
+
// 查询当前用户待办任务
|
|
370
|
+
public TableDataInfo<FlowTaskVo> getTodoList(FlowTaskBo bo, PageQuery pageQuery) {
|
|
371
|
+
return flwTaskService.pageByTaskWait(bo, pageQuery);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// 查询当前用户已办任务
|
|
375
|
+
public TableDataInfo<FlowHisTaskVo> getDoneList(FlowTaskBo bo, PageQuery pageQuery) {
|
|
376
|
+
return flwTaskService.pageByTaskFinish(bo, pageQuery);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 查询所有待办任务(管理员)
|
|
380
|
+
public TableDataInfo<FlowTaskVo> getAllTodoList(FlowTaskBo bo, PageQuery pageQuery) {
|
|
381
|
+
return flwTaskService.pageByAllTaskWait(bo, pageQuery);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 查询抄送任务
|
|
385
|
+
public TableDataInfo<FlowTaskVo> getCopyList(FlowTaskBo bo, PageQuery pageQuery) {
|
|
386
|
+
return flwTaskService.pageByTaskCopy(bo, pageQuery);
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## 🎯 业务集成
|
|
393
|
+
|
|
394
|
+
### 1. 监听流程事件
|
|
395
|
+
|
|
396
|
+
> 事件类位于 `org.dromara.common.core.domain.event` 包
|
|
397
|
+
|
|
398
|
+
```java
|
|
399
|
+
import org.springframework.context.event.EventListener;
|
|
400
|
+
import org.dromara.common.core.domain.event.ProcessEvent;
|
|
401
|
+
import org.dromara.common.core.domain.event.ProcessTaskEvent;
|
|
402
|
+
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
|
|
403
|
+
|
|
404
|
+
@Component
|
|
405
|
+
public class OrderWorkflowListener {
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* 监听流程状态变更
|
|
409
|
+
*/
|
|
410
|
+
@EventListener(condition = "#event.flowCode == 'order_approve'")
|
|
411
|
+
public void onProcessEvent(ProcessEvent event) {
|
|
412
|
+
String businessId = event.getBusinessId();
|
|
413
|
+
String status = event.getStatus();
|
|
414
|
+
boolean isSubmit = event.isSubmit();
|
|
415
|
+
|
|
416
|
+
// 申请人提交
|
|
417
|
+
if (isSubmit) {
|
|
418
|
+
orderService.updateStatus(businessId, "PENDING");
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// 根据流程状态更新业务数据
|
|
423
|
+
switch (status) {
|
|
424
|
+
case "finish" -> orderService.updateStatus(businessId, "APPROVED");
|
|
425
|
+
case "back" -> orderService.updateStatus(businessId, "REJECTED");
|
|
426
|
+
case "cancel" -> orderService.updateStatus(businessId, "CANCELLED");
|
|
427
|
+
case "termination" -> orderService.updateStatus(businessId, "TERMINATED");
|
|
428
|
+
case "invalid" -> orderService.updateStatus(businessId, "INVALID");
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* 监听任务创建(发送通知)
|
|
434
|
+
*/
|
|
435
|
+
@EventListener(condition = "#event.flowCode == 'order_approve'")
|
|
436
|
+
public void onTaskCreated(ProcessTaskEvent event) {
|
|
437
|
+
Long taskId = event.getTaskId();
|
|
438
|
+
String businessId = event.getBusinessId();
|
|
439
|
+
// 获取待办人并发送通知
|
|
440
|
+
sendNotification(taskId);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* 监听流程删除
|
|
445
|
+
*/
|
|
446
|
+
@EventListener(condition = "#event.flowCode == 'order_approve'")
|
|
447
|
+
public void onProcessDeleted(ProcessDeleteEvent event) {
|
|
448
|
+
String businessId = event.getBusinessId();
|
|
449
|
+
// 清理业务相关数据
|
|
450
|
+
orderService.cleanupWorkflowData(businessId);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### 2. 事件类型说明
|
|
456
|
+
|
|
457
|
+
| 事件类 | 触发时机 | 主要字段 |
|
|
458
|
+
|-------|---------|---------|
|
|
459
|
+
| `ProcessEvent` | 流程状态变更(提交、通过、驳回、撤销、终止、作废、完成) | flowCode, businessId, status, submit |
|
|
460
|
+
| `ProcessTaskEvent` | 任务创建时 | flowCode, businessId, taskId, nodeCode |
|
|
461
|
+
| `ProcessDeleteEvent` | 流程删除时 | flowCode, businessId |
|
|
462
|
+
|
|
463
|
+
### 3. 完整业务集成示例
|
|
464
|
+
|
|
465
|
+
```java
|
|
466
|
+
@Service
|
|
467
|
+
@RequiredArgsConstructor
|
|
468
|
+
public class LeaveServiceImpl implements ILeaveService {
|
|
469
|
+
|
|
470
|
+
private final LeaveMapper baseMapper; // ✅ 三层架构,直接注入 Mapper
|
|
471
|
+
private final WorkflowService workflowService;
|
|
472
|
+
|
|
473
|
+
@Override
|
|
474
|
+
@Transactional(rollbackFor = Exception.class)
|
|
475
|
+
public boolean submitLeave(LeaveBo bo) {
|
|
476
|
+
// 1. 保存业务数据
|
|
477
|
+
Leave leave = MapstructUtils.convert(bo, Leave.class); // ✅ 使用 MapstructUtils
|
|
478
|
+
baseMapper.insert(leave);
|
|
479
|
+
|
|
480
|
+
// 2. 启动流程
|
|
481
|
+
StartProcessDTO startProcess = new StartProcessDTO();
|
|
482
|
+
startProcess.setBusinessId(String.valueOf(leave.getId()));
|
|
483
|
+
startProcess.setFlowCode("leave");
|
|
484
|
+
startProcess.setVariables(Map.of(
|
|
485
|
+
"days", leave.getDays(),
|
|
486
|
+
"reason", leave.getReason()
|
|
487
|
+
));
|
|
488
|
+
|
|
489
|
+
StartProcessReturnDTO result = workflowService.startWorkFlow(startProcess);
|
|
490
|
+
|
|
491
|
+
// 3. 办理第一个任务(申请人节点)
|
|
492
|
+
workflowService.completeTask(result.getTaskId(), "提交申请");
|
|
493
|
+
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## 📡 消息通知
|
|
502
|
+
|
|
503
|
+
### 通知类型
|
|
504
|
+
|
|
505
|
+
```java
|
|
506
|
+
package org.dromara.workflow.common.enums;
|
|
507
|
+
|
|
508
|
+
public enum MessageTypeEnum {
|
|
509
|
+
SYSTEM_MESSAGE("system", "系统消息(SSE推送)"),
|
|
510
|
+
EMAIL_MESSAGE("email", "邮件"),
|
|
511
|
+
SMS_MESSAGE("sms", "短信");
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### 配置消息通知
|
|
516
|
+
|
|
517
|
+
在流程变量中设置:
|
|
518
|
+
|
|
519
|
+
```java
|
|
520
|
+
Map<String, Object> variable = new HashMap<>();
|
|
521
|
+
variable.put(FlowConstant.MESSAGE_TYPE, List.of("system", "email")); // SSE + 邮件
|
|
522
|
+
variable.put(FlowConstant.MESSAGE_NOTICE, "您有新的审批任务");
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## 🌐 API 接口
|
|
528
|
+
|
|
529
|
+
### 任务管理 (/workflow/task)
|
|
530
|
+
|
|
531
|
+
| 接口 | 方法 | 说明 |
|
|
532
|
+
|------|------|------|
|
|
533
|
+
| `/startWorkFlow` | POST | 启动流程 |
|
|
534
|
+
| `/completeTask` | POST | 办理任务 |
|
|
535
|
+
| `/pageByTaskWait` | GET | 当前用户待办任务 |
|
|
536
|
+
| `/pageByTaskFinish` | GET | 当前用户已办任务 |
|
|
537
|
+
| `/pageByAllTaskWait` | GET | 所有待办任务 |
|
|
538
|
+
| `/pageByAllTaskFinish` | GET | 所有已办任务 |
|
|
539
|
+
| `/pageByTaskCopy` | GET | 抄送任务列表 |
|
|
540
|
+
| `/getTask/{taskId}` | GET | 获取任务详情 |
|
|
541
|
+
| `/getNextNodeList` | POST | 获取下一节点列表 |
|
|
542
|
+
| `/backProcess` | POST | 驳回任务 |
|
|
543
|
+
| `/getBackTaskNode/{definitionId}/{nodeCode}` | GET | 获取可驳回节点 |
|
|
544
|
+
| `/terminationTask` | POST | 终止流程 |
|
|
545
|
+
| `/taskOperation/{type}` | POST | 任务操作(委托/转办/加签/减签) |
|
|
546
|
+
| `/currentTaskAllUser/{taskId}` | GET | 获取任务所有办理人 |
|
|
547
|
+
| `/updateAssignee/{userId}` | PUT | 修改任务办理人 |
|
|
548
|
+
| `/urgeTask` | POST | 催办任务 |
|
|
549
|
+
|
|
550
|
+
### 实例管理 (/workflow/instance)
|
|
551
|
+
|
|
552
|
+
| 接口 | 方法 | 说明 |
|
|
553
|
+
|------|------|------|
|
|
554
|
+
| `/pageRunningInstance` | GET | 运行中的流程实例 |
|
|
555
|
+
| `/pageFinishInstance` | GET | 已完成的流程实例 |
|
|
556
|
+
| `/pageCurrentInstance` | GET | 当前用户发起的流程 |
|
|
557
|
+
| `/queryByBusinessId/{businessId}` | GET | 根据业务ID查询实例 |
|
|
558
|
+
| `/flowHisTaskList/{businessId}` | GET | 获取审批历史 |
|
|
559
|
+
| `/cancelProcessApply` | POST | 撤销流程 |
|
|
560
|
+
| `/processInvalid` | POST | 作废流程 |
|
|
561
|
+
| `/deleteInstance` | DELETE | 删除流程实例 |
|
|
562
|
+
| `/deleteHisInstance` | DELETE | 删除已完成的流程实例 |
|
|
563
|
+
| `/instanceVariable/{instanceId}` | GET | 获取流程变量 |
|
|
564
|
+
| `/updateVariable` | PUT | 更新流程变量 |
|
|
565
|
+
|
|
566
|
+
### 流程定义 (/workflow/definition)
|
|
567
|
+
|
|
568
|
+
| 接口 | 方法 | 说明 |
|
|
569
|
+
|------|------|------|
|
|
570
|
+
| `/pageDefinitions` | GET | 已发布的流程定义 |
|
|
571
|
+
| `/pageUnPublishDefinitions` | GET | 未发布的流程定义 |
|
|
572
|
+
| `/publish/{id}` | PUT | 发布流程定义 |
|
|
573
|
+
| `/importJson` | POST | 导入流程定义 |
|
|
574
|
+
| `/exportDef/{id}` | GET | 导出流程定义 |
|
|
575
|
+
| `/removeDef` | DELETE | 删除流程定义 |
|
|
576
|
+
|
|
577
|
+
### 流程分类 (/workflow/category)
|
|
578
|
+
|
|
579
|
+
| 接口 | 方法 | 说明 |
|
|
580
|
+
|------|------|------|
|
|
581
|
+
| `/list` | GET | 分页查询分类 |
|
|
582
|
+
| `/{id}` | GET | 获取分类详情 |
|
|
583
|
+
| `` | POST | 新增分类 |
|
|
584
|
+
| `` | PUT | 修改分类 |
|
|
585
|
+
| `/{ids}` | DELETE | 删除分类 |
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
## 🔄 全局监听器
|
|
590
|
+
|
|
591
|
+
`WorkflowGlobalListener` 实现 `GlobalListener` 接口:
|
|
592
|
+
|
|
593
|
+
```java
|
|
594
|
+
@Component
|
|
595
|
+
public class WorkflowGlobalListener implements GlobalListener {
|
|
596
|
+
|
|
597
|
+
@Override
|
|
598
|
+
public void create(ListenerVariable listenerVariable) {
|
|
599
|
+
// 任务创建时执行
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
@Override
|
|
603
|
+
public void start(ListenerVariable listenerVariable) {
|
|
604
|
+
// 任务开始办理时执行
|
|
605
|
+
// 处理:抄送设置、自定义变量
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
@Override
|
|
609
|
+
public void assignment(ListenerVariable listenerVariable) {
|
|
610
|
+
// 分派监听器,动态修改待办任务办理人
|
|
611
|
+
// 处理:指定办理人、申请节点办理人设置
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
@Override
|
|
615
|
+
public void finish(ListenerVariable listenerVariable) {
|
|
616
|
+
// 任务完成后执行
|
|
617
|
+
// 处理:状态更新、消息通知、抄送、事件发布
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
## ✅ 检查清单
|
|
625
|
+
|
|
626
|
+
- [ ] 是否正确使用 `FlowEngine` 访问核心服务?
|
|
627
|
+
- [ ] 是否使用 `ProcessEvent`/`ProcessTaskEvent` 监听流程状态变更?
|
|
628
|
+
- [ ] 是否正确配置办理人(注意:用户ID无前缀,角色/部门/岗位有前缀)?
|
|
629
|
+
- [ ] 是否在业务模块中正确集成 `WorkflowService`?
|
|
630
|
+
- [ ] 是否处理了流程各状态(通过、驳回、撤销、终止)的业务逻辑?
|
|
631
|
+
- [ ] 是否使用 `MapstructUtils.convert()` 进行对象转换?
|
|
632
|
+
- [ ] Service 是否直接注入 Mapper(无 DAO 层)?
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
## ❓ 常见问题
|
|
637
|
+
|
|
638
|
+
### Q1: 用户ID和角色ID在办理人配置中的区别?
|
|
639
|
+
|
|
640
|
+
```java
|
|
641
|
+
// ✅ 用户ID - 无前缀
|
|
642
|
+
"123" // 直接是用户ID
|
|
643
|
+
|
|
644
|
+
// ✅ 角色ID - 有 role: 前缀
|
|
645
|
+
"role:456" // 角色ID
|
|
646
|
+
|
|
647
|
+
// ✅ 部门ID - 有 dept: 前缀
|
|
648
|
+
"dept:789" // 部门ID
|
|
649
|
+
|
|
650
|
+
// ✅ 岗位ID - 有 post: 前缀
|
|
651
|
+
"post:101" // 岗位ID
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
### Q2: 如何判断是否为 SpEL 表达式?
|
|
655
|
+
|
|
656
|
+
```java
|
|
657
|
+
// SpEL 表达式以 # 或 $ 开头
|
|
658
|
+
TaskAssigneeEnum.isSpelExpression("#{initiator}") // true
|
|
659
|
+
TaskAssigneeEnum.isSpelExpression("${deptLeader}") // true
|
|
660
|
+
TaskAssigneeEnum.isSpelExpression("user:123") // false
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### Q3: 如何忽略办理权限校验?
|
|
664
|
+
|
|
665
|
+
```java
|
|
666
|
+
Map<String, Object> variable = new HashMap<>();
|
|
667
|
+
variable.put(FlowConstant.VAR_IGNORE, true); // 忽略办理权限校验
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Q4: 如何实现自动审批?
|
|
671
|
+
|
|
672
|
+
在流程变量中设置 `autoPass: true`,当办理人是发起人自己时,系统会自动通过该节点。
|
|
673
|
+
|
|
674
|
+
### Q5: 如何动态指定办理人?
|
|
675
|
+
|
|
676
|
+
1. 使用流程变量:`variables.put("nextAssignee", userId)`
|
|
677
|
+
2. 使用 SpEL 表达式:配置办理人为 `#{nextAssignee}`
|
|
678
|
+
3. 在办理时指定:通过 `assigneeMap` 指定下一步办理人
|
|
679
|
+
|
|
680
|
+
---
|
|
681
|
+
|
|
682
|
+
## 🎯 最佳实践
|
|
683
|
+
|
|
684
|
+
### ✅ 应该做
|
|
685
|
+
|
|
686
|
+
- ✅ 业务ID 使用雪花ID,确保唯一性
|
|
687
|
+
- ✅ 流程编码使用有意义的英文命名(如 `leave`、`expense`)
|
|
688
|
+
- ✅ 通过事件监听机制同步业务状态
|
|
689
|
+
- ✅ 使用 `@Transactional` 确保业务数据和流程数据的一致性
|
|
690
|
+
- ✅ 使用 `MapstructUtils.convert()` 进行对象转换
|
|
691
|
+
- ✅ Service 层直接注入 Mapper(三层架构)
|
|
692
|
+
|
|
693
|
+
### ❌ 不应该做
|
|
694
|
+
|
|
695
|
+
- ❌ 不要在业务代码中直接操作 WarmFlow 的底层 API
|
|
696
|
+
- ❌ 不要在流程变量中存储敏感信息
|
|
697
|
+
- ❌ 不要频繁查询流程状态,使用事件驱动
|
|
698
|
+
- ❌ 不要使用 BeanUtils 进行对象转换
|
|
699
|
+
- ❌ 不要创建 DAO 层(本项目是三层架构)
|
|
700
|
+
|
|
701
|
+
---
|
|
702
|
+
|
|
703
|
+
## 📚 参考实现
|
|
704
|
+
|
|
705
|
+
| 类型 | 参考文件 |
|
|
706
|
+
|------|---------|
|
|
707
|
+
| 请假示例 Controller | `org.dromara.workflow.controller.TestLeaveController` |
|
|
708
|
+
| 请假示例 Service | `org.dromara.workflow.service.impl.TestLeaveServiceImpl` |
|
|
709
|
+
| 请假示例 Entity | `org.dromara.workflow.domain.TestLeave` |
|
|
710
|
+
| 任务服务实现 | `org.dromara.workflow.service.impl.FlwTaskServiceImpl` |
|
|
711
|
+
| 全局监听器 | `org.dromara.workflow.listener.WorkflowGlobalListener` |
|
|
712
|
+
| 事件处理器 | `org.dromara.workflow.handler.FlowProcessEventHandler` |
|
|
713
|
+
|
|
714
|
+
<!-- 抓蛙师 -->
|