From f1208474f771a1c233d7425c8ed13fbaa0d521ac Mon Sep 17 00:00:00 2001
From: baoshiwei <baoshiwei@shlanbao.cn>
Date: 星期三, 12 三月 2025 09:35:13 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/5.X' into 5.X

---
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java           |   37 
 ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java                 |   15 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java                    |    8 
 ruoyi-admin/zhFonts/.uuid                                                                                               |    1 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java                                         |    2 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java                    |   22 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java                            |    2 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java                     |   42 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java                           |   10 
 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml                                                  |    2 
 ruoyi-admin/zhFonts/fonts.scale                                                                                         |    4 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java                      |    4 
 script/leave/leave2.json                                                                                                |  111 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java                            |   99 
 ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java              |    8 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java                           |   20 
 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java                       |    9 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java                     |    7 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java                     |    2 
 .run/ruoyi-snailjob-server.run.xml                                                                                      |    2 
 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java        |    9 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java                         |  104 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java                       |   20 
 ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java                                           |    4 
 ruoyi-admin/Dockerfile                                                                                                  |    6 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java                        |  102 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java                           |    8 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java                                |    8 
 ruoyi-admin/src/main/resources/application-prod.yml                                                                     |   30 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java                    |  687 ++
 script/sql/ry_job.sql                                                                                                   |   11 
 ruoyi-common/ruoyi-common-redis/pom.xml                                                                                 |   12 
 ruoyi-admin/src/main/resources/application-dev.yml                                                                      |   10 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java                    |  130 
 script/sql/postgres/postgres_ry_job.sql                                                                                 |   19 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java                      |  109 
 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml                                   |   11 
 ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java            |    4 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java                                |    2 
 pom.xml                                                                                                                 |   96 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java                                    |    4 
 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java                           |   31 
 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java                  |   21 
 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml                                       |  115 
 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java                         |    6 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java            |  165 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java                   |  133 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java                                   |   12 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java                   |  157 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java                        |    8 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java                      |  121 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java                    |   82 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java                            |   33 
 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java                  |    4 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java                        |    3 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java                            |    7 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java                                         |    8 
 script/leave/leave4.json                                                                                                |   90 
 ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java                                               |    4 
 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml                                               |   11 
 ruoyi-common/ruoyi-common-mybatis/pom.xml                                                                               |    5 
 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java                 |   16 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java                     |    7 
 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java                          |    3 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java                           |   10 
 script/docker/database.yml                                                                                              |    2 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java                                    |   32 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java                                       |    7 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java    |   27 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java                            |  244 +
 .run/ruoyi-server.run.xml                                                                                               |    6 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java                    |   71 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java                           |    2 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java                   |    3 
 ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java                                |   14 
 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java                    |   24 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java                             |   31 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java                               |    5 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java                           |   67 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java             |   50 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java                        |   32 
 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamSource.java                   |    2 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java                        |    8 
 ruoyi-common/ruoyi-common-excel/pom.xml                                                                                 |    5 
 script/sql/oracle/oracle_ry_vue_5.X.sql                                                                                 |   49 
 ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java                             |    2 
 ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java          |    2 
 ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java                                                |   17 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java                   |    9 
 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java                            |   48 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java                                |  363 
 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml                                              |   11 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java                |   19 
 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java                       |   27 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java                    |   48 
 ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java              |    4 
 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java |    2 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java                           |   60 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java                 |    2 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java                                         |   24 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java                        |   52 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java                          |   48 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java                             |   60 
 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java                    |  135 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java             |   28 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java               |    4 
 ruoyi-common/ruoyi-common-bom/pom.xml                                                                                   |    2 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java                         |   14 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java                  |    3 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java                  |   73 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java             |    5 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java       |  208 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java                        |   29 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java                        |  159 
 script/sql/sqlserver/sqlserver_ry_job.sql                                                                               |   47 
 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java                             |   27 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java                  |   26 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java                  |    2 
 script/leave/leave5.json                                                                                                |  121 
 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/SequenceUtils.java                         |  165 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java                             |   17 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java                           |    9 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java                   |  132 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java                 |   18 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java                     |    2 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java                       |   11 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java                |  451 +
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java                      |   10 
 script/sql/postgres/postgres_ry_workflow.sql                                                                            |  405 +
 script/sql/oracle/oracle_ry_job.sql                                                                                     |   19 
 script/sql/ry_vue_5.X.sql                                                                                               |   51 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java                                 |   12 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java                       |  113 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java                           |   55 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java                             |   25 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java                             |    2 
 ruoyi-modules/ruoyi-workflow/pom.xml                                                                                    |   57 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java                 |    7 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java                                    |    8 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java                                     |    6 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java                           |  137 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java                            |   46 
 ruoyi-extend/ruoyi-snailjob-server/Dockerfile                                                                           |    4 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java                               |    6 
 script/leave/leave3.json                                                                                                |  121 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java                               |    6 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java                               |  176 
 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java                            |   18 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java                      |    2 
 ruoyi-common/ruoyi-common-websocket/pom.xml                                                                             |    6 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java                   |    4 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java                |    6 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java                            |    6 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java                                   |   34 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java                    |    3 
 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java             |   24 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java                 |  194 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailController.java                                  |   20 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java                    |  101 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java                               |   55 
 ruoyi-common/ruoyi-common-web/pom.xml                                                                                   |   13 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java                            |   31 
 ruoyi-admin/src/main/resources/application.yml                                                                          |   40 
 ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml                                                 |    4 
 ruoyi-modules/ruoyi-generator/pom.xml                                                                                   |    6 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java                               |  257 
 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java                           |   28 
 ruoyi-extend/ruoyi-monitor-admin/Dockerfile                                                                             |    4 
 ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java                                             |   31 
 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml                                   |   36 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java                                         |    2 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java                                   |   32 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java                                   |   13 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java                       |  201 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java      |    7 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java                           |   19 
 ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java                                          |    4 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java                        |   62 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java                     |   19 
 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm                                            |    4 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java                        |   95 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java              |   34 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java                                |    8 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java                            |    7 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java                             |  146 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java                       |   76 
 script/leave/leave1.json                                                                                                |   75 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java                               |   57 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java                            |  191 
 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java                     |    2 
 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java          |    6 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java                           |   47 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java                      |   29 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java                                       |    2 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java                                   |    7 
 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java              |    4 
 script/docker/docker-compose.yml                                                                                        |   10 
 ruoyi-admin/src/main/resources/logback-plus.xml                                                                         |    2 
 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java       |    3 
 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm                                                     |    2 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java                        |  112 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java                      |   49 
 script/sql/sqlserver/sqlserver_ry_vue_5.X.sql                                                                           |   86 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java                            |   37 
 ruoyi-extend/ruoyi-snailjob-server/pom.xml                                                                              |   12 
 ruoyi-admin/zhFonts/fonts.dir                                                                                           |    4 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java                           |    2 
 script/sql/postgres/postgres_ry_vue_5.X.sql                                                                             |   53 
 ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml                                                    |    4 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java                   |   45 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java                           |   27 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java                   |   14 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java                    |   14 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java                            |   10 
 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java                                  |  162 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java                      |   79 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java              |  266 +
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java                                  |    2 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java                              |   16 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java           |   37 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java                                |   58 
 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java                      |   10 
 ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java                   |    2 
 .run/ruoyi-monitor-admin.run.xml                                                                                        |    2 
 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java                            |    6 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java                         |   10 
 ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java                                                  |   23 
 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java       |    8 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java                      |   75 
 README.md                                                                                                               |   15 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java               |   34 
 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java                          |   45 
 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java                                |   11 
 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java                   |   23 
 script/sql/oracle/oracle_ry_workflow.sql                                                                                |  414 +
 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java             |   63 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java                           |   10 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java                     |    6 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java                |  269 +
 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml                                           |   11 
 ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java                 |   12 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java                |  168 
 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java                       |  108 
 script/sql/ry_workflow.sql                                                                                              |  253 +
 ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java               |    2 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java                 |   56 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java                    |    4 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java                        |    5 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java                  |   62 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java                              |    1 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java                        |   15 
 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java                  |   26 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java                              |    5 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java                                       |    2 
 ruoyi-admin/zhFonts/SIMSUN.TTC                                                                                          |    0 
 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java                             |   23 
 script/sql/sqlserver/sqlserver_ry_workflow.sql                                                                          | 1336 +++++
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java                              |    2 
 ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java                       |   12 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java                                     |    6 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java                    |    4 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java                                      |   10 
 /dev/null                                                                                                               |  456 -
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java                          |    3 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java                      |   79 
 ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java                |   10 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java                          |   65 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java                      |   12 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java              |   30 
 ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml                                                     |    8 
 ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java                                        |    4 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java                                    |    4 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java                        |   64 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java                    |   45 
 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java                    |   26 
 ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java                                             |    4 
 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java                          |   11 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java                         |   12 
 278 files changed, 12,274 insertions(+), 2,164 deletions(-)

diff --git a/.run/ruoyi-monitor-admin.run.xml b/.run/ruoyi-monitor-admin.run.xml
index 478b4f3..c399b29 100644
--- a/.run/ruoyi-monitor-admin.run.xml
+++ b/.run/ruoyi-monitor-admin.run.xml
@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.2" />
+        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.3.0" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
       </settings>
diff --git a/.run/ruoyi-server.run.xml b/.run/ruoyi-server.run.xml
index 541800d..5dbde4e 100644
--- a/.run/ruoyi-server.run.xml
+++ b/.run/ruoyi-server.run.xml
@@ -1,12 +1,12 @@
 <component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="婕旂ず鏈�">
+  <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-server:5.2.2" />
+        <option name="imageTag" value="ruoyi/ruoyi-server:5.3.0" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
       </settings>
     </deployment>
     <method v="2" />
   </configuration>
-</component>
\ No newline at end of file
+</component>
diff --git a/.run/ruoyi-snailjob-server.run.xml b/.run/ruoyi-snailjob-server.run.xml
index 5221eef..e1e13fc 100644
--- a/.run/ruoyi-snailjob-server.run.xml
+++ b/.run/ruoyi-snailjob-server.run.xml
@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.2" />
+        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.3.0" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
       </settings>
diff --git a/README.md b/README.md
index eeb3f7b..fc3131a 100644
--- a/README.md
+++ b/README.md
@@ -6,22 +6,24 @@
 
 [![鐮佷簯Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus)
 [![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus)
+[![Star](https://gitcode.com/dromara/RuoYi-Vue-Plus/star/badge.svg)](https://gitcode.com/dromara/RuoYi-Vue-Plus)
 [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
 [![浣跨敤IntelliJ IDEA寮�鍙戠淮鎶(https://img.shields.io/badge/IntelliJ%20IDEA-鎻愪緵鏀寔-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
 <br>
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
-[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]()
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.3.0-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
+[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.4-blue.svg)]()
 [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
 [![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()
 
-> RuoYi-Vue-Plus 鏄噸鍐� RuoYi-Vue 閽堝 `鍒嗗竷寮忛泦缇や笌澶氱鎴穈 鍦烘櫙鍏ㄦ柟浣嶅崌绾�(涓嶅吋瀹瑰師妗嗘灦)
+> Dromara RuoYi-Vue-Plus 鏄噸鍐� RuoYi-Vue 閽堝 `鍒嗗竷寮忛泦缇や笌澶氱鎴穈 鍦烘櫙鍏ㄦ柟浣嶅崌绾�(涓嶅吋瀹瑰師妗嗘灦)
 
 > 椤圭洰浠g爜銆佹枃妗� 鍧囧紑婧愬厤璐瑰彲鍟嗙敤 閬靛惊寮�婧愬崗璁湪椤圭洰涓繚鐣欏紑婧愬崗璁枃浠跺嵆鍙�<br>
 娲诲埌鑰佸啓鍒拌�� 涓哄叴瓒h�屽紑婧� 涓哄涔犺�屽紑婧� 涓鸿澶у鐪熸鍙互瀛﹀埌鎶�鏈�屽紑婧�
 
 > 绯荤粺婕旂ず: [浼犻�侀棬](https://plus-doc.dromara.org/#/common/demo_system)
 
-> 鍓嶇椤圭洰鍦板潃: [plus-ui](https://gitee.com/JavaLionLi/plus-ui)
+> 瀹樻柟鍓嶇椤圭洰鍦板潃: [plus-ui](https://gitee.com/JavaLionLi/plus-ui)<br>
+> 鎴愬憳鍓嶇椤圭洰鍦板潃: 鍩轰簬vben5 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5)
 
 > 鏂囨。鍦板潃: [plus-doc](https://plus-doc.dromara.org)
 
@@ -31,6 +33,7 @@
 CCFlow 椹拌仒浣庝唬鐮�-娴佺▼-琛ㄥ崟 - https://gitee.com/opencc/RuoYi-JFlow <br>
 鏁拌埖绉戞妧 杞欢瀹氬埗寮�鍙慉PP灏忕▼搴忕瓑 - http://www.shuduokeji.com/ <br>
 寮曡繄淇℃伅 杞欢寮�鍙戝钩鍙� - https://www.jnpfsoft.com/index.html?from=plus-doc <br>
+<font color="red">**鍚北鍟嗗煄绯荤粺 澶氱鎴峰晢鍩庢簮鐮佸彲鍏嶈垂鍟嗙敤鍙簩娆″紑鍙� - https://www.73app.cn/** </font><br>
 [濡備綍鎴愪负璧炲姪鍟� 鍔犵兢鑱旂郴浣滆�呰璋圿(https://plus-doc.dromara.org/#/common/add_group)
 
 # 鏈鏋朵笌RuoYi鐨勫姛鑳藉樊寮�
@@ -165,8 +168,8 @@
 | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "灞忓箷鎴浘") |
 | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "灞忓箷鎴浘") |
 | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "灞忓箷鎴浘") |
-| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078982294090567/b31c343d_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079000642440444/77ca82a9_1766278.png "灞忓箷鎴浘") |
-| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079020995074177/03b7d52e_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079039367822173/76811806_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1735829153637063344/3c21fd4c_1419627.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1735829181303499815/4522cefa_1419627.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1735829377205259767/76a705d7_1419627.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1722959592856812900/e2d0d342_1419627.png "灞忓箷鎴浘") |
 | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "灞忓箷鎴浘") |
 
 
diff --git a/pom.xml b/pom.xml
index 3824322..4c37b04 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,51 +13,49 @@
     <description>鍏板疂杞﹂棿璐ㄩ噺绠$悊绯荤粺</description>
 
     <properties>
-        <revision>5.2.2</revision>
-        <spring-boot.version>3.2.9</spring-boot.version>
+        <revision>5.3.0</revision>
+        <spring-boot.version>3.4.2</spring-boot.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>17</java.version>
         <mybatis.version>3.5.16</mybatis.version>
-        <springdoc.version>2.6.0</springdoc.version>
+        <springdoc.version>2.8.4</springdoc.version>
         <therapi-javadoc.version>0.15.0</therapi-javadoc.version>
-        <easyexcel.version>4.0.2</easyexcel.version>
+        <easyexcel.version>4.0.3</easyexcel.version>
         <velocity.version>2.3</velocity.version>
-        <satoken.version>1.38.0</satoken.version>
-        <mybatis-plus.version>3.5.7</mybatis-plus.version>
+        <satoken.version>1.40.0</satoken.version>
+        <mybatis-plus.version>3.5.10</mybatis-plus.version>
         <p6spy.version>3.9.1</p6spy.version>
-        <hutool.version>5.8.31</hutool.version>
-        <okhttp.version>4.10.0</okhttp.version>
-        <spring-boot-admin.version>3.2.3</spring-boot-admin.version>
-        <redisson.version>3.34.1</redisson.version>
+        <hutool.version>5.8.35</hutool.version>
+        <spring-boot-admin.version>3.4.1</spring-boot-admin.version>
+        <redisson.version>3.44.0</redisson.version>
         <lock4j.version>2.2.7</lock4j.version>
         <dynamic-ds.version>4.3.1</dynamic-ds.version>
-        <snailjob.version>1.1.2</snailjob.version>
-        <mapstruct-plus.version>1.4.4</mapstruct-plus.version>
+        <snailjob.version>1.3.0</snailjob.version>
+        <mapstruct-plus.version>1.4.6</mapstruct-plus.version>
         <mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
-        <lombok.version>1.18.34</lombok.version>
+        <lombok.version>1.18.36</lombok.version>
         <bouncycastle.version>1.76</bouncycastle.version>
-        <justauth.version>1.16.6</justauth.version>
+        <justauth.version>1.16.7</justauth.version>
         <!-- 绂荤嚎IP鍦板潃瀹氫綅搴� -->
         <ip2region.version>2.7.0</ip2region.version>
-        <undertow.version>2.3.15.Final</undertow.version>
 
         <!-- OSS 閰嶇疆 -->
-        <aws.sdk.version>2.25.15</aws.sdk.version>
-        <aws.crt.version>0.29.13</aws.crt.version>
+        <aws.sdk.version>2.28.22</aws.sdk.version>
+        <aws.crt.version>0.31.3</aws.crt.version>
         <!-- SMS 閰嶇疆 -->
-        <sms4j.version>3.3.2</sms4j.version>
+        <sms4j.version>3.3.3</sms4j.version>
         <!-- 闄愬埗妗嗘灦涓殑fastjson鐗堟湰 -->
         <fastjson.version>1.2.83</fastjson.version>
         <!-- 闈㈠悜杩愯鏃剁殑D-ORM渚濊禆 -->
-        <anyline.version>8.7.2-20240808</anyline.version>
+        <anyline.version>8.7.2-20250101</anyline.version>
         <!--宸ヤ綔娴侀厤缃�-->
-        <flowable.version>7.0.1</flowable.version>
+        <warm-flow.version>1.6.6</warm-flow.version>
 
         <!-- 鎻掍欢鐗堟湰 -->
         <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
         <maven-war-plugin.version>3.2.2</maven-war-plugin.version>
-        <maven-compiler-plugin.verison>3.11.0</maven-compiler-plugin.verison>
+        <maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
         <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
         <flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
     </properties>
@@ -69,6 +67,8 @@
                 <!-- 鐜鏍囪瘑锛岄渶瑕佷笌閰嶇疆鏂囦欢鐨勫悕绉扮浉瀵瑰簲 -->
                 <profiles.active>local</profiles.active>
                 <logging.level>info</logging.level>
+                <monitor.username>ruoyi</monitor.username>
+                <monitor.password>123456</monitor.password>
             </properties>
         </profile>
         <profile>
@@ -77,6 +77,8 @@
                 <!-- 鐜鏍囪瘑锛岄渶瑕佷笌閰嶇疆鏂囦欢鐨勫悕绉扮浉瀵瑰簲 -->
                 <profiles.active>dev</profiles.active>
                 <logging.level>info</logging.level>
+                <monitor.username>ruoyi</monitor.username>
+                <monitor.password>123456</monitor.password>
             </properties>
             <activation>
                 <!-- 榛樿鐜 -->
@@ -88,6 +90,8 @@
             <properties>
                 <profiles.active>prod</profiles.active>
                 <logging.level>warn</logging.level>
+                <monitor.username>ruoyi</monitor.username>
+                <monitor.password>123456</monitor.password>
             </properties>
         </profile>
     </profiles>
@@ -114,12 +118,16 @@
                 <scope>import</scope>
             </dependency>
 
+            <!-- Warm-Flow鍥戒骇宸ヤ綔娴佸紩鎿�, 鍦ㄧ嚎鏂囨。锛歨ttp://warm-flow.cn/ -->
             <dependency>
-                <groupId>org.flowable</groupId>
-                <artifactId>flowable-bom</artifactId>
-                <version>${flowable.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
+                <groupId>org.dromara.warm</groupId>
+                <artifactId>warm-flow-mybatis-plus-sb3-starter</artifactId>
+                <version>${warm-flow.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.dromara.warm</groupId>
+                <artifactId>warm-flow-plugin-ui-sb-web</artifactId>
+                <version>${warm-flow.version}</version>
             </dependency>
 
             <!-- JustAuth 鐨勪緷璧栭厤缃�-->
@@ -214,6 +222,12 @@
 
             <dependency>
                 <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-jsqlparser</artifactId>
+                <version>${mybatis-plus.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.baomidou</groupId>
                 <artifactId>mybatis-plus-annotation</artifactId>
                 <version>${mybatis-plus.version}</version>
             </dependency>
@@ -223,12 +237,6 @@
                 <groupId>p6spy</groupId>
                 <artifactId>p6spy</artifactId>
                 <version>${p6spy.version}</version>
-            </dependency>
-
-            <dependency>
-                <groupId>com.squareup.okhttp3</groupId>
-                <artifactId>okhttp</artifactId>
-                <version>${okhttp.version}</version>
             </dependency>
 
             <!--  AWS SDK for Java 2.x  -->
@@ -313,25 +321,9 @@
             </dependency>
 
             <dependency>
-                <groupId>io.undertow</groupId>
-                <artifactId>undertow-core</artifactId>
-                <version>${undertow.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>io.undertow</groupId>
-                <artifactId>undertow-servlet</artifactId>
-                <version>${undertow.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>io.undertow</groupId>
-                <artifactId>undertow-websockets-jsr</artifactId>
-                <version>${undertow.version}</version>
-            </dependency>
-
-            <dependency>
-                <artifactId>commons-compress</artifactId>
-                <groupId>org.apache.commons</groupId>
-                <version>1.26.2</version>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>2.15.0</version>
             </dependency>
 
             <dependency>
@@ -394,7 +386,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>${maven-compiler-plugin.verison}</version>
+                <version>${maven-compiler-plugin.version}</version>
                 <configuration>
                     <source>${java.version}</source>
                     <target>${java.version}</target>
diff --git a/ruoyi-admin/Dockerfile b/ruoyi-admin/Dockerfile
index 737cbfc..b489ab5 100644
--- a/ruoyi-admin/Dockerfile
+++ b/ruoyi-admin/Dockerfile
@@ -1,6 +1,6 @@
 # 璐濆皵瀹為獙瀹� Spring 瀹樻柟鎺ㄨ崘闀滃儚 JDK涓嬭浇鍦板潃 https://bell-sw.com/pages/downloads/
 FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
-#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.5-cds
 #FROM findepi/graalvm:java17-native
 
 LABEL maintainer="Lion Li"
@@ -16,6 +16,10 @@
 EXPOSE ${SERVER_PORT}
 
 ADD ./target/ruoyi-admin.jar ./app.jar
+# 宸ヤ綔娴佸瓧浣撴枃浠�
+ADD ./zhFonts/ /usr/share/fonts/zhFonts/
+
+SHELL ["/bin/bash", "-c"]
 
 ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
            # 搴旂敤鍚嶇О 濡傛灉鎯冲尯鍒嗛泦缇よ妭鐐圭洃鎺� 鏀规垚涓嶅悓鐨勫悕绉板嵆鍙�
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
index 984ee32..f7cd82d 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
@@ -2,6 +2,7 @@
 
 import cn.dev33.satoken.annotation.SaIgnore;
 import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.codec.Base64;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
@@ -12,7 +13,7 @@
 import me.zhyd.oauth.model.AuthUser;
 import me.zhyd.oauth.request.AuthRequest;
 import me.zhyd.oauth.utils.AuthStateUtils;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.domain.model.LoginBody;
 import org.dromara.common.core.domain.model.RegisterBody;
@@ -92,7 +93,7 @@
         if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
             log.info("瀹㈡埛绔痠d: {} 璁よ瘉绫诲瀷锛歿} 寮傚父!.", clientId, grantType);
             return R.fail(MessageUtils.message("auth.grant.type.error"));
-        } else if (!UserConstants.NORMAL.equals(client.getStatus())) {
+        } else if (!SystemConstants.NORMAL.equals(client.getStatus())) {
             return R.fail(MessageUtils.message("auth.grant.type.blocked"));
         }
         // 鏍¢獙绉熸埛
@@ -111,7 +112,7 @@
     }
 
     /**
-     * 绗笁鏂圭櫥褰曡姹�
+     * 鑾峰彇璺宠浆URL
      *
      * @param source 鐧诲綍鏉ユ簮
      * @return 缁撴灉
@@ -133,13 +134,15 @@
     }
 
     /**
-     * 绗笁鏂圭櫥褰曞洖璋冧笟鍔″鐞� 缁戝畾鎺堟潈
+     * 鍓嶇鍥炶皟缁戝畾鎺堟潈(闇�瑕乼oken)
      *
      * @param loginBody 璇锋眰浣�
      * @return 缁撴灉
      */
     @PostMapping("/social/callback")
     public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) {
+        // 鏍¢獙token
+        StpUtil.checkLogin();
         // 鑾峰彇绗笁鏂圭櫥褰曚俊鎭�
         AuthResponse<AuthUser> response = SocialUtils.loginAuth(
                 loginBody.getSource(), loginBody.getSocialCode(),
@@ -155,12 +158,14 @@
 
 
     /**
-     * 鍙栨秷鎺堟潈
+     * 鍙栨秷鎺堟潈(闇�瑕乼oken)
      *
      * @param socialId socialId
      */
     @DeleteMapping(value = "/unlock/{socialId}")
     public R<Void> unlockSocial(@PathVariable Long socialId) {
+        // 鏍¢獙token
+        StpUtil.checkLogin();
         Boolean rows = socialUserService.deleteWithValidById(socialId);
         return rows ? R.ok() : R.fail("鍙栨秷鎺堟潈澶辫触");
     }
@@ -226,7 +231,7 @@
         }
         // 鏍规嵁鍩熷悕杩涜绛涢��
         List<TenantListVo> list = StreamUtils.filter(voList, vo ->
-                StringUtils.equals(vo.getDomain(), host));
+            StringUtils.equalsIgnoreCase(vo.getDomain(), host));
         result.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
         return R.ok(result);
     }
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
index c7ad917..41a802b 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
@@ -12,11 +12,12 @@
 import me.zhyd.oauth.model.AuthUser;
 import org.dromara.common.core.constant.CacheConstants;
 import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.domain.dto.PostDTO;
 import org.dromara.common.core.domain.dto.RoleDTO;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.enums.LoginType;
-import org.dromara.common.core.enums.TenantStatus;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.user.UserException;
 import org.dromara.common.core.utils.*;
@@ -60,6 +61,7 @@
     private final ISysSocialService sysSocialService;
     private final ISysRoleService roleService;
     private final ISysDeptService deptService;
+    private final ISysPostService postService;
     private final SysUserMapper userMapper;
 
 
@@ -148,21 +150,24 @@
      */
     public LoginUser buildLoginUser(SysUserVo user) {
         LoginUser loginUser = new LoginUser();
+        Long userId = user.getUserId();
         loginUser.setTenantId(user.getTenantId());
-        loginUser.setUserId(user.getUserId());
+        loginUser.setUserId(userId);
         loginUser.setDeptId(user.getDeptId());
         loginUser.setUsername(user.getUserName());
         loginUser.setNickname(user.getNickName());
         loginUser.setUserType(user.getUserType());
-        loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
-        loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
+        loginUser.setMenuPermission(permissionService.getMenuPermission(userId));
+        loginUser.setRolePermission(permissionService.getRolePermission(userId));
         if (ObjectUtil.isNotNull(user.getDeptId())) {
             Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById);
             loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
             loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
         }
-        List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId());
+        List<SysRoleVo> roles = roleService.selectRolesByUserId(userId);
+        List<SysPostVo> posts = postService.selectPostsByUserId(userId);
         loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
+        loginUser.setPosts(BeanUtil.copyToList(posts, PostDTO.class));
         return loginUser;
     }
 
@@ -223,17 +228,17 @@
         if (!TenantHelper.isEnable()) {
             return;
         }
-        if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
-            return;
-        }
         if (StringUtils.isBlank(tenantId)) {
             throw new TenantException("tenant.number.not.blank");
+        }
+        if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
+            return;
         }
         SysTenantVo tenant = tenantService.queryByTenantId(tenantId);
         if (ObjectUtil.isNull(tenant)) {
             log.info("鐧诲綍绉熸埛锛歿} 涓嶅瓨鍦�.", tenantId);
             throw new TenantException("tenant.not.exists");
-        } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) {
+        } else if (SystemConstants.DISABLE.equals(tenant.getStatus())) {
             log.info("鐧诲綍绉熸埛锛歿} 宸茶鍋滅敤.", tenantId);
             throw new TenantException("tenant.blocked");
         } else if (ObjectUtil.isNotNull(tenant.getExpireTime())
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
index ddab279..9ec0813 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
@@ -84,11 +84,11 @@
         String captcha = RedisUtils.getCacheObject(verifyKey);
         RedisUtils.deleteObject(verifyKey);
         if (captcha == null) {
-            recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.expire"));
+            recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
             throw new CaptchaExpireException();
         }
         if (!code.equalsIgnoreCase(captcha)) {
-            recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.error"));
+            recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
             throw new CaptchaException();
         }
     }
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
index b5a2497..1bed4f3 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
@@ -8,10 +8,10 @@
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.constant.Constants;
 import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.model.EmailLoginBody;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.enums.LoginType;
-import org.dromara.common.core.enums.UserStatus;
 import org.dromara.common.core.exception.user.CaptchaExpireException;
 import org.dromara.common.core.exception.user.UserException;
 import org.dromara.common.core.utils.MessageUtils;
@@ -92,7 +92,7 @@
         if (ObjectUtil.isNull(user)) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", email);
             throw new UserException("user.not.exists", email);
-        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+        } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", email);
             throw new UserException("user.blocked", email);
         }
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
index f28024f..e8e60e1 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
@@ -9,10 +9,10 @@
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.constant.Constants;
 import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.domain.model.PasswordLoginBody;
 import org.dromara.common.core.enums.LoginType;
-import org.dromara.common.core.enums.UserStatus;
 import org.dromara.common.core.exception.user.CaptchaException;
 import org.dromara.common.core.exception.user.CaptchaExpireException;
 import org.dromara.common.core.exception.user.UserException;
@@ -113,7 +113,7 @@
         if (ObjectUtil.isNull(user)) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", username);
             throw new UserException("user.not.exists", username);
-        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+        } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", username);
             throw new UserException("user.blocked", username);
         }
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
index 89f8462..2ffda35 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
@@ -8,10 +8,10 @@
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.constant.Constants;
 import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.domain.model.SmsLoginBody;
 import org.dromara.common.core.enums.LoginType;
-import org.dromara.common.core.enums.UserStatus;
 import org.dromara.common.core.exception.user.CaptchaExpireException;
 import org.dromara.common.core.exception.user.UserException;
 import org.dromara.common.core.utils.MessageUtils;
@@ -92,7 +92,7 @@
         if (ObjectUtil.isNull(user)) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", phonenumber);
             throw new UserException("user.not.exists", phonenumber);
-        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+        } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", phonenumber);
             throw new UserException("user.blocked", phonenumber);
         }
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
index 8463026..419dbd6 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
@@ -11,9 +11,9 @@
 import lombok.extern.slf4j.Slf4j;
 import me.zhyd.oauth.model.AuthResponse;
 import me.zhyd.oauth.model.AuthUser;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.domain.model.SocialLoginBody;
-import org.dromara.common.core.enums.UserStatus;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.user.UserException;
 import org.dromara.common.core.utils.StreamUtils;
@@ -121,7 +121,7 @@
         if (ObjectUtil.isNull(user)) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", "");
             throw new UserException("user.not.exists", "");
-        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+        } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", "");
             throw new UserException("user.blocked", "");
         }
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java
index aa8be73..fa9b618 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java
@@ -5,13 +5,20 @@
 import cn.hutool.core.util.ObjectUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthRequest;
+import me.zhyd.oauth.request.AuthWechatMiniProgramRequest;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.model.XcxLoginBody;
 import org.dromara.common.core.domain.model.XcxLoginUser;
-import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.ValidatorUtils;
 import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
-import org.dromara.system.domain.SysClient;
 import org.dromara.system.domain.vo.SysClientVo;
 import org.dromara.system.domain.vo.SysUserVo;
 import org.dromara.web.domain.vo.LoginVo;
@@ -40,12 +47,24 @@
         // 澶氫釜灏忕▼搴忚瘑鍒娇鐢�
         String appid = loginBody.getAppid();
 
-        // todo 浠ヤ笅鑷瀹炵幇
         // 鏍¢獙 appid + appsrcret + xcxCode 璋冪敤鐧诲綍鍑瘉鏍¢獙鎺ュ彛 鑾峰彇 session_key 涓� openid
-        String openid = "";
+        AuthRequest authRequest = new AuthWechatMiniProgramRequest(AuthConfig.builder()
+            .clientId(appid).clientSecret("鑷濉啓瀵嗛挜 鍙牴鎹笉鍚宎ppid濉叆涓嶅悓瀵嗛挜")
+            .ignoreCheckRedirectUri(true).ignoreCheckState(true).build());
+        AuthCallback authCallback = new AuthCallback();
+        authCallback.setCode(xcxCode);
+        AuthResponse<AuthUser> resp = authRequest.login(authCallback);
+        String openid, unionId;
+        if (resp.ok()) {
+            AuthToken token = resp.getData().getToken();
+            openid = token.getOpenId();
+            // 寰俊灏忕▼搴忓彧鏈夊叧鑱斿埌寰俊寮�鏀惧钩鍙颁笅涔嬪悗鎵嶈兘鑾峰彇鍒� unionId锛屽洜姝nionId涓嶄竴瀹氳兘杩斿洖銆�
+            unionId = token.getUnionId();
+        } else {
+            throw new ServiceException(resp.getMsg());
+        }
         // 妗嗘灦鐧诲綍涓嶉檺鍒朵粠浠�涔堣〃鏌ヨ 鍙鏈�缁堟瀯寤哄嚭 LoginUser 鍗冲彲
         SysUserVo user = loadUserByOpenid(openid);
-
         // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
         XcxLoginUser loginUser = new XcxLoginUser();
         loginUser.setTenantId(user.getTenantId());
@@ -82,7 +101,7 @@
         if (ObjectUtil.isNull(user)) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", openid);
             // todo 鐢ㄦ埛涓嶅瓨鍦� 涓氬姟閫昏緫鑷瀹炵幇
-        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+        } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", openid);
             // todo 鐢ㄦ埛宸茶鍋滅敤 涓氬姟閫昏緫鑷瀹炵幇
         }
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index b634908..8bc5b94 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -8,8 +8,8 @@
     metadata:
       username: ${spring.boot.admin.client.username}
       userpassword: ${spring.boot.admin.client.password}
-  username: ruoyi
-  password: 123456
+  username: @monitor.username@
+  password: @monitor.password@
 
 --- # snail-job 閰嶇疆
 snail-job:
@@ -25,6 +25,10 @@
   namespace: ${spring.profiles.active}
   # 闅忎富搴旂敤绔彛椋橀��
   port: 2${server.port}
+  # 瀹㈡埛绔痠p鎸囧畾
+  host:
+  # RPC绫诲瀷: netty, grpc
+  rpc-type: grpc
 
 --- # 鏁版嵁婧愰厤缃�
 spring:
@@ -198,7 +202,7 @@
       redirect-uri: ${justauth.address}/social-callback?source=maxkey
     topiam:
       # topiam 鏈嶅姟鍣ㄥ湴鍧�
-      server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol
+      server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol
       client-id: 449c4*********937************759
       client-secret: ac7***********1e0************28d
       redirect-uri: ${justauth.address}/social-callback?source=topiam
diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml
index 2823bba..80c1f96 100644
--- a/ruoyi-admin/src/main/resources/application-prod.yml
+++ b/ruoyi-admin/src/main/resources/application-prod.yml
@@ -11,23 +11,27 @@
     metadata:
       username: ${spring.boot.admin.client.username}
       userpassword: ${spring.boot.admin.client.password}
-  username: ruoyi
-  password: 123456
+  username: @monitor.username@
+  password: @monitor.password@
 
 --- # snail-job 閰嶇疆
 snail-job:
   enabled: true
   # 闇�瑕佸湪 SnailJob 鍚庡彴缁勭鐞嗗垱寤哄搴斿悕绉扮殑缁�,鐒跺悗鍒涘缓浠诲姟鐨勬椂鍊欓�夋嫨瀵瑰簲鐨勭粍,鎵嶈兘姝g‘鍒嗘淳浠诲姟
   group: "ruoyi_group"
-  # SnailJob 鎺ュ叆楠岃瘉浠ょ墝 璇﹁ script/sql/snail_job.sql `sj_group_config` 琛�
+  # SnailJob 鎺ュ叆楠岃瘉浠ょ墝 璇﹁ script/sql/ry_job.sql `sj_group_config`琛�
   token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
   server:
     host: 127.0.0.1
     port: 17888
-  # 璇﹁ script/sql/snail_job.sql `sj_namespace` 琛�
+  # 鍛藉悕绌洪棿UUID 璇﹁ script/sql/ry_job.sql `sj_namespace`琛╜unique_id`瀛楁
   namespace: ${spring.profiles.active}
-  # 闅忎富搴旂敤绔彛椋橀��
+  # 闅忎富搴旂敤绔彛婕傜Щ
   port: 2${server.port}
+  # 瀹㈡埛绔痠p鎸囧畾
+  host:
+  # RPC绫诲瀷: netty, grpc
+  rpc-type: grpc
 
 --- # 鏁版嵁婧愰厤缃�
 spring:
@@ -51,14 +55,14 @@
           url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
           username: root
           password: root
-        # 浠庡簱鏁版嵁婧�
-        slave:
-          lazy: true
-          type: ${spring.datasource.type}
-          driverClassName: com.mysql.cj.jdbc.Driver
-          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
-          username:
-          password:
+#        # 浠庡簱鏁版嵁婧�
+#        slave:
+#          lazy: true
+#          type: ${spring.datasource.type}
+#          driverClassName: com.mysql.cj.jdbc.Driver
+#          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+#          username:
+#          password:
 #        oracle:
 #          type: ${spring.datasource.type}
 #          driverClassName: oracle.jdbc.OracleDriver
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 18f2bdd..f293140 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -121,6 +121,7 @@
     # swagger 鏂囨。閰嶇疆
     - /*/api-docs
     - /*/api-docs/**
+    - /warm-flow-ui/token-name
 
 # 澶氱鎴烽厤缃�
 tenant:
@@ -141,6 +142,8 @@
 # MyBatisPlus閰嶇疆
 # https://baomidou.com/config/
 mybatis-plus:
+  # 鑷畾涔夐厤缃� 鏄惁鍏ㄥ眬寮�鍚�昏緫鍒犻櫎 鍏抽棴鍚� 鎵�鏈夐�昏緫鍒犻櫎鍔熻兘灏嗗け鏁�
+  enableLogicDelete: true
   # 澶氬寘鍚嶄娇鐢� 渚嬪 org.dromara.**.mapper,org.xxx.**.mapper
   mapperPackage: org.dromara.**.mapper,cn.shlanbao.**.mapper
   # 瀵瑰簲鐨� XML 鏂囦欢浣嶇疆
@@ -217,7 +220,9 @@
       packages-to-scan: org.dromara.system
     - group: 4.浠g爜鐢熸垚妯″潡
       packages-to-scan: org.dromara.generator
-    - group: 5.璐ㄩ噺妯″潡
+    - group: 5.宸ヤ綔娴佹ā鍧�
+      packages-to-scan: org.dromara.workflow
+    - group: 6.璐ㄩ噺妯″潡
       packages-to-scan: cn.shlanbao.qms
 
 # 闃叉XSS鏀诲嚮
@@ -225,9 +230,9 @@
   # 杩囨护寮�鍏�
   enabled: true
   # 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
-  excludes: /system/notice
-  # 鍖归厤閾炬帴
-  urlPatterns: /system/*,/monitor/*,/tool/*
+  excludeUrls:
+    - /system/notice
+    - /warm-flow/save-xml
 
 # 鍏ㄥ眬绾跨▼姹犵浉鍏抽厤缃�
 # 濡備娇鐢↗DK21璇风洿鎺ヤ娇鐢ㄨ櫄鎷熺嚎绋� 涓嶈寮�鍚閰嶇疆
@@ -272,24 +277,11 @@
   # 璁剧疆璁块棶婧愬湴鍧�
   allowedOrigins: '*'
 
---- #flowable閰嶇疆
-flowable:
-  # 寮�鍏� 鐢ㄤ簬鍚姩/鍋滅敤宸ヤ綔娴�
+--- # warm-flow宸ヤ綔娴侀厤缃�
+warm-flow:
+  # 鏄惁寮�鍚伐浣滄祦锛岄粯璁rue
   enabled: true
-  process.enabled: ${flowable.enabled}
-  eventregistry.enabled: ${flowable.enabled}
-  async-executor-activate: false #鍏抽棴瀹氭椂浠诲姟JOB
-  #  灏哾atabaseSchemaUpdate璁剧疆涓簍rue銆傚綋Flowable鍙戠幇搴撲笌鏁版嵁搴撹〃缁撴瀯涓嶄竴鑷存椂锛屼細鑷姩灏嗘暟鎹簱琛ㄧ粨鏋勫崌绾ц嚦鏂扮増鏈��
-  database-schema-update: true
-  activity-font-name: 瀹嬩綋
-  label-font-name: 瀹嬩綋
-  annotation-font-name: 瀹嬩綋
-  # 鍏抽棴鍚勪釜妯″潡鐢熸垚琛紝鐩墠鍙娇鐢ㄥ伐浣滄祦鍩虹琛�
-  idm:
-    enabled: false
-  cmmn:
-    enabled: false
-  dmn:
-    enabled: false
-  app:
-    enabled: false
+  # 鏄惁寮�鍚璁″櫒ui
+  ui: true
+  # 榛樿Authorization锛屽鏋滄湁澶氫釜token锛岀敤閫楀彿鍒嗛殧
+  token-name: ${sa-token.token-name},clientid
diff --git a/ruoyi-admin/src/main/resources/logback-plus.xml b/ruoyi-admin/src/main/resources/logback-plus.xml
index 40fa33b..b74289e 100644
--- a/ruoyi-admin/src/main/resources/logback-plus.xml
+++ b/ruoyi-admin/src/main/resources/logback-plus.xml
@@ -2,7 +2,7 @@
 <configuration>
     <property name="log.path" value="./logs"/>
     <property name="console.log.pattern"
-              value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+              value="%cyan(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
     <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
 
     <!-- 鎺у埗鍙拌緭鍑� -->
diff --git a/ruoyi-admin/zhFonts/.uuid b/ruoyi-admin/zhFonts/.uuid
new file mode 100644
index 0000000..cee5cdd
--- /dev/null
+++ b/ruoyi-admin/zhFonts/.uuid
@@ -0,0 +1 @@
+3f2ee348-0303-40ca-bf03-03f48d2d2141
\ No newline at end of file
diff --git a/ruoyi-admin/zhFonts/SIMSUN.TTC b/ruoyi-admin/zhFonts/SIMSUN.TTC
new file mode 100644
index 0000000..6ca8de3
--- /dev/null
+++ b/ruoyi-admin/zhFonts/SIMSUN.TTC
Binary files differ
diff --git a/ruoyi-admin/zhFonts/fonts.dir b/ruoyi-admin/zhFonts/fonts.dir
new file mode 100644
index 0000000..fed9544
--- /dev/null
+++ b/ruoyi-admin/zhFonts/fonts.dir
@@ -0,0 +1,4 @@
+3
+SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso10646-1
+SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso8859-1
+SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-koi8-r
diff --git a/ruoyi-admin/zhFonts/fonts.scale b/ruoyi-admin/zhFonts/fonts.scale
new file mode 100644
index 0000000..fed9544
--- /dev/null
+++ b/ruoyi-admin/zhFonts/fonts.scale
@@ -0,0 +1,4 @@
+3
+SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso10646-1
+SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso8859-1
+SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-koi8-r
diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml
index 455408d..24acb08 100644
--- a/ruoyi-common/ruoyi-common-bom/pom.xml
+++ b/ruoyi-common/ruoyi-common-bom/pom.xml
@@ -14,7 +14,7 @@
     </description>
 
     <properties>
-        <revision>5.2.2</revision>
+        <revision>5.3.0</revision>
     </properties>
 
     <dependencyManagement>
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
index b4d4528..2630485 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
@@ -4,11 +4,13 @@
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.concurrent.BasicThreadFactory;
 import org.dromara.common.core.config.properties.ThreadPoolProperties;
+import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.Threads;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
+import org.springframework.core.task.VirtualThreadTaskExecutor;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
 import java.util.concurrent.ScheduledExecutorService;
@@ -49,8 +51,15 @@
      */
     @Bean(name = "scheduledExecutorService")
     protected ScheduledExecutorService scheduledExecutorService() {
+        // daemon 蹇呴』涓� true
+        BasicThreadFactory.Builder builder = new BasicThreadFactory.Builder().daemon(true);
+        if (SpringUtils.isVirtual()) {
+            builder.namingPattern("virtual-schedule-pool-%d").wrappedFactory(new VirtualThreadTaskExecutor().getVirtualThreadFactory());
+        } else {
+            builder.namingPattern("schedule-pool-%d");
+        }
         ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core,
-            new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
+            builder.build(),
             new ThreadPoolExecutor.CallerRunsPolicy()) {
             @Override
             protected void afterExecute(Runnable r, Throwable t) {
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java
index 28ba177..bf8efc5 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java
@@ -61,6 +61,16 @@
     String SYS_OSS = "sys_oss#30d";
 
     /**
+     * 瑙掕壊鑷畾涔夋潈闄�
+     */
+    String SYS_ROLE_CUSTOM = "sys_role_custom#30d";
+
+    /**
+     * 閮ㄩ棬鍙婁互涓嬫潈闄�
+     */
+    String SYS_DEPT_AND_CHILD = "sys_dept_and_child#30d";
+
+    /**
      * OSS閰嶇疆
      */
     String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config";
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java
index cdbda89..273c734 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java
@@ -68,12 +68,7 @@
     Integer CAPTCHA_EXPIRATION = 2;
 
     /**
-     * 浠ょ墝
-     */
-    String TOKEN = "token";
-
-    /**
-     * 椤剁骇閮ㄩ棬id
+     * 椤剁骇鐖剁骇id
      */
     Long TOP_PARENT_ID = 0L;
 
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java
new file mode 100644
index 0000000..55240bb
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java
@@ -0,0 +1,75 @@
+package org.dromara.common.core.constant;
+
+/**
+ * 绯荤粺甯搁噺淇℃伅
+ *
+ * @author Lion Li
+ */
+public interface SystemConstants {
+
+    /**
+     * 姝e父鐘舵��
+     */
+    String NORMAL = "0";
+
+    /**
+     * 寮傚父鐘舵��
+     */
+    String DISABLE = "1";
+
+    /**
+     * 鏄惁涓虹郴缁熼粯璁わ紙鏄級
+     */
+    String YES = "Y";
+
+    /**
+     * 鏄惁涓虹郴缁熼粯璁わ紙鍚︼級
+     */
+    String NO = "N";
+
+    /**
+     * 鏄惁鑿滃崟澶栭摼锛堟槸锛�
+     */
+    String YES_FRAME = "0";
+
+    /**
+     * 鏄惁鑿滃崟澶栭摼锛堝惁锛�
+     */
+    String NO_FRAME = "1";
+
+    /**
+     * 鑿滃崟绫诲瀷锛堢洰褰曪級
+     */
+    String TYPE_DIR = "M";
+
+    /**
+     * 鑿滃崟绫诲瀷锛堣彍鍗曪級
+     */
+    String TYPE_MENU = "C";
+
+    /**
+     * 鑿滃崟绫诲瀷锛堟寜閽級
+     */
+    String TYPE_BUTTON = "F";
+
+    /**
+     * Layout缁勪欢鏍囪瘑
+     */
+    String LAYOUT = "Layout";
+
+    /**
+     * ParentView缁勪欢鏍囪瘑
+     */
+    String PARENT_VIEW = "ParentView";
+
+    /**
+     * InnerLink缁勪欢鏍囪瘑
+     */
+    String INNER_LINK = "InnerLink";
+
+    /**
+     * 瓒呯骇绠$悊鍛業D
+     */
+    Long SUPER_ADMIN_ID = 1L;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java
index 86b63c9..33ce0cf 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java
@@ -8,16 +8,6 @@
 public interface TenantConstants {
 
     /**
-     * 绉熸埛姝e父鐘舵��
-     */
-    String NORMAL = "0";
-
-    /**
-     * 绉熸埛灏佺鐘舵��
-     */
-    String DISABLE = "1";
-
-    /**
      * 瓒呯骇绠$悊鍛業D
      */
     Long SUPER_ADMIN_ID = 1L;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
deleted file mode 100644
index 76f6dd4..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
+++ /dev/null
@@ -1,152 +0,0 @@
-package org.dromara.common.core.constant;
-
-/**
- * 鐢ㄦ埛甯搁噺淇℃伅
- *
- * @author ruoyi
- */
-public interface UserConstants {
-
-    /**
-     * 骞冲彴鍐呯郴缁熺敤鎴风殑鍞竴鏍囧織
-     */
-    String SYS_USER = "SYS_USER";
-
-    /**
-     * 姝e父鐘舵��
-     */
-    String NORMAL = "0";
-
-    /**
-     * 寮傚父鐘舵��
-     */
-    String EXCEPTION = "1";
-
-    /**
-     * 鐢ㄦ埛姝e父鐘舵��
-     */
-    String USER_NORMAL = "0";
-
-    /**
-     * 鐢ㄦ埛灏佺鐘舵��
-     */
-    String USER_DISABLE = "1";
-
-    /**
-     * 瑙掕壊姝e父鐘舵��
-     */
-    String ROLE_NORMAL = "0";
-
-    /**
-     * 瑙掕壊灏佺鐘舵��
-     */
-    String ROLE_DISABLE = "1";
-
-    /**
-     * 閮ㄩ棬姝e父鐘舵��
-     */
-    String DEPT_NORMAL = "0";
-
-    /**
-     * 閮ㄩ棬鍋滅敤鐘舵��
-     */
-    String DEPT_DISABLE = "1";
-
-    /**
-     * 宀椾綅姝e父鐘舵��
-     */
-    String POST_NORMAL = "0";
-
-    /**
-     * 宀椾綅鍋滅敤鐘舵��
-     */
-    String POST_DISABLE = "1";
-
-    /**
-     * 瀛楀吀姝e父鐘舵��
-     */
-    String DICT_NORMAL = "0";
-
-    /**
-     * 閫氱敤瀛樺湪鏍囧織
-     */
-    String DEL_FLAG_NORMAL = "0";
-
-    /**
-     * 閫氱敤鍒犻櫎鏍囧織
-     */
-    String DEL_FLAG_REMOVED  = "2";
-
-    /**
-     * 鏄惁涓虹郴缁熼粯璁わ紙鏄級
-     */
-    String YES = "Y";
-
-    /**
-     * 鏄惁鑿滃崟澶栭摼锛堟槸锛�
-     */
-    String YES_FRAME = "0";
-
-    /**
-     * 鏄惁鑿滃崟澶栭摼锛堝惁锛�
-     */
-    String NO_FRAME = "1";
-
-    /**
-     * 鑿滃崟姝e父鐘舵��
-     */
-    String MENU_NORMAL = "0";
-
-    /**
-     * 鑿滃崟鍋滅敤鐘舵��
-     */
-    String MENU_DISABLE = "1";
-
-    /**
-     * 鑿滃崟绫诲瀷锛堢洰褰曪級
-     */
-    String TYPE_DIR = "M";
-
-    /**
-     * 鑿滃崟绫诲瀷锛堣彍鍗曪級
-     */
-    String TYPE_MENU = "C";
-
-    /**
-     * 鑿滃崟绫诲瀷锛堟寜閽級
-     */
-    String TYPE_BUTTON = "F";
-
-    /**
-     * Layout缁勪欢鏍囪瘑
-     */
-    String LAYOUT = "Layout";
-
-    /**
-     * ParentView缁勪欢鏍囪瘑
-     */
-    String PARENT_VIEW = "ParentView";
-
-    /**
-     * InnerLink缁勪欢鏍囪瘑
-     */
-    String INNER_LINK = "InnerLink";
-
-    /**
-     * 鐢ㄦ埛鍚嶉暱搴﹂檺鍒�
-     */
-    int USERNAME_MIN_LENGTH = 2;
-    int USERNAME_MAX_LENGTH = 20;
-
-    /**
-     * 瀵嗙爜闀垮害闄愬埗
-     */
-    int PASSWORD_MIN_LENGTH = 5;
-    int PASSWORD_MAX_LENGTH = 20;
-
-    /**
-     * 瓒呯骇绠$悊鍛業D
-     */
-    Long SUPER_ADMIN_ID = 1L;
-
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java
new file mode 100644
index 0000000..2e63f8a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java
@@ -0,0 +1,71 @@
+package org.dromara.common.core.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 鍔炵悊浠诲姟璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class CompleteTaskDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟id
+     */
+    private Long taskId;
+
+    /**
+     * 闄勪欢id
+     */
+    private String fileId;
+
+    /**
+     * 鎶勯�佷汉鍛�
+     */
+    private List<FlowCopyDTO> flowCopyList;
+
+    /**
+     * 娑堟伅绫诲瀷
+     */
+    private List<String> messageType;
+
+    /**
+     * 鍔炵悊鎰忚
+     */
+    private String message;
+
+    /**
+     * 娑堟伅閫氱煡
+     */
+    private String notice;
+
+    /**
+     * 娴佺▼鍙橀噺
+     */
+    private Map<String, Object> variables;
+
+    /**
+     * 鎵╁睍鍙橀噺(姝ゅ涓洪�楀彿鍒嗛殧鐨刼ssId)
+     */
+    private String ext;
+
+    public Map<String, Object> getVariables() {
+        if (variables == null) {
+            return new HashMap<>(16);
+        }
+        variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
+        return variables;
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java
new file mode 100644
index 0000000..65c012f
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java
@@ -0,0 +1,37 @@
+package org.dromara.common.core.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 閮ㄩ棬
+ *
+ * @author AprilWind
+ */
+
+@Data
+@NoArgsConstructor
+public class DeptDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    private Long deptId;
+
+    /**
+     * 鐖堕儴闂↖D
+     */
+    private Long parentId;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    private String deptName;
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java
similarity index 75%
copy from ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java
copy to ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java
index 88a5a21..2f20b21 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java
@@ -1,9 +1,10 @@
-package org.dromara.workflow.domain.vo;
+package org.dromara.common.core.domain.dto;
 
 import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
+
 
 /**
  * 鎶勯��
@@ -11,7 +12,7 @@
  * @author may
  */
 @Data
-public class WfCopy implements Serializable {
+public class FlowCopyDTO implements Serializable {
 
     @Serial
     private static final long serialVersionUID = 1L;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java
new file mode 100644
index 0000000..7536ee3
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java
@@ -0,0 +1,46 @@
+package org.dromara.common.core.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 宀椾綅
+ *
+ * @author AprilWind
+ */
+@Data
+@NoArgsConstructor
+public class PostDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 宀椾綅ID
+     */
+    private Long postId;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    private Long deptId;
+
+    /**
+     * 宀椾綅缂栫爜
+     */
+    private String postCode;
+
+    /**
+     * 宀椾綅鍚嶇О
+     */
+    private String postName;
+
+    /**
+     * 宀椾綅绫诲埆缂栫爜
+     */
+    private String postCategory;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java
new file mode 100644
index 0000000..3934ada
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java
@@ -0,0 +1,45 @@
+package org.dromara.common.core.domain.dto;
+
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 鍚姩娴佺▼瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class StartProcessDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓氬姟鍞竴鍊糹d
+     */
+    private String businessId;
+
+    /**
+     * 娴佺▼瀹氫箟缂栫爜
+     */
+    private String flowCode;
+
+    /**
+     * 娴佺▼鍙橀噺锛屽墠绔細鎻愪氦涓�涓厓绱爗'entity': {涓氬姟璇︽儏鏁版嵁瀵硅薄}}
+     */
+    private Map<String, Object> variables;
+
+    public Map<String, Object> getVariables() {
+        if (variables == null) {
+            return new HashMap<>(16);
+        }
+        variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
+        return variables;
+    }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java
new file mode 100644
index 0000000..9bcbd12
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java
@@ -0,0 +1,30 @@
+package org.dromara.common.core.domain.dto;
+
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鍚姩娴佺▼杩斿洖瀵硅薄
+ *
+ * @author Lion Li
+ */
+@Data
+public class StartProcessReturnDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼瀹炰緥id
+     */
+    private Long processInstanceId;
+
+    /**
+     * 浠诲姟id
+     */
+    private Long taskId;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java
new file mode 100644
index 0000000..85893e1
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java
@@ -0,0 +1,101 @@
+package org.dromara.common.core.domain.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 浠诲姟鍙楄浜�
+ *
+ * @author AprilWind
+ */
+@Data
+@NoArgsConstructor
+public class TaskAssigneeDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鎬诲ぇ灏�
+     */
+    private Long total = 0L;
+
+    /**
+     *
+     */
+    private List<TaskHandler> list;
+
+    public TaskAssigneeDTO(Long total, List<TaskHandler> list) {
+        this.total = total;
+        this.list = list;
+    }
+
+    /**
+     * 灏嗘簮鍒楄〃杞崲涓� TaskHandler 鍒楄〃
+     *
+     * @param <T>              閫氱敤绫诲瀷
+     * @param sourceList       寰呰浆鎹㈢殑婧愬垪琛�
+     * @param storageId        鎻愬彇 storageId 鐨勫嚱鏁�
+     * @param handlerCode      鎻愬彇 handlerCode 鐨勫嚱鏁�
+     * @param handlerName      鎻愬彇 handlerName 鐨勫嚱鏁�
+     * @param groupName        鎻愬彇 groupName 鐨勫嚱鏁�
+     * @param createTimeMapper 鎻愬彇 createTime 鐨勫嚱鏁�
+     * @return 杞崲鍚庣殑 TaskHandler 鍒楄〃
+     */
+    public static <T> List<TaskHandler> convertToHandlerList(
+        List<T> sourceList,
+        Function<T, Long> storageId,
+        Function<T, String> handlerCode,
+        Function<T, String> handlerName,
+        Function<T, Long> groupName,
+        Function<T, Date> createTimeMapper) {
+        return sourceList.stream()
+            .map(item -> new TaskHandler(
+                String.valueOf(storageId.apply(item)),
+                handlerCode.apply(item),
+                handlerName.apply(item),
+                groupName != null ? String.valueOf(groupName.apply(item)) : null,
+                createTimeMapper.apply(item)
+            )).collect(Collectors.toList());
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class TaskHandler {
+
+        /**
+         * 涓婚敭
+         */
+        private String storageId;
+
+        /**
+         * 鏉冮檺缂栫爜
+         */
+        private String handlerCode;
+
+        /**
+         * 鏉冮檺鍚嶇О
+         */
+        private String handlerName;
+
+        /**
+         * 鏉冮檺鍒嗙粍
+         */
+        private String groupName;
+
+        /**
+         * 鍒涘缓鏃堕棿
+         */
+        private Date createTime;
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java
new file mode 100644
index 0000000..d570c31
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java
@@ -0,0 +1,34 @@
+package org.dromara.common.core.domain.event;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鍒犻櫎娴佺▼鐩戝惉
+ *
+ * @author AprilWind
+ */
+@Data
+public class ProcessDeleteEvent implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 娴佺▼瀹氫箟缂栫爜
+     */
+    private String flowCode;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessId;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java
index 61c7efc..6329b9c 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java
@@ -4,13 +4,13 @@
 
 import java.io.Serial;
 import java.io.Serializable;
+import java.util.Map;
 
 /**
  * 鎬讳綋娴佺▼鐩戝惉
  *
  * @author may
  */
-
 @Data
 public class ProcessEvent implements Serializable {
 
@@ -18,14 +18,19 @@
     private static final long serialVersionUID = 1L;
 
     /**
-     * 娴佺▼瀹氫箟key
+     * 绉熸埛ID
      */
-    private String key;
+    private String tenantId;
+
+    /**
+     * 娴佺▼瀹氫箟缂栫爜
+     */
+    private String flowCode;
 
     /**
      * 涓氬姟id
      */
-    private String businessKey;
+    private String businessId;
 
     /**
      * 鐘舵��
@@ -33,9 +38,13 @@
     private String status;
 
     /**
+     * 鍔炵悊鍙傛暟
+     */
+    private Map<String, Object> params;
+
+    /**
      * 褰撲负true鏃朵负鐢宠浜鸿妭鐐瑰姙鐞�
      */
     private boolean submit;
-
 
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java
index 019ca82..33bc6e5 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java
@@ -10,7 +10,6 @@
  *
  * @author may
  */
-
 @Data
 public class ProcessTaskEvent implements Serializable {
 
@@ -18,23 +17,28 @@
     private static final long serialVersionUID = 1L;
 
     /**
-     * 娴佺▼瀹氫箟key
+     * 绉熸埛ID
      */
-    private String key;
+    private String tenantId;
 
     /**
-     * 瀹℃壒鑺傜偣key
+     * 娴佺▼瀹氫箟缂栫爜
      */
-    private String taskDefinitionKey;
+    private String flowCode;
+
+    /**
+     * 瀹℃壒鑺傜偣缂栫爜
+     */
+    private String nodeCode;
 
     /**
      * 浠诲姟id
      */
-    private String taskId;
+    private Long taskId;
 
     /**
      * 涓氬姟id
      */
-    private String businessKey;
+    private String businessId;
 
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java
index c723e76..338d4d7 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java
@@ -1,8 +1,9 @@
 package org.dromara.common.core.domain.model;
 
-import org.dromara.common.core.domain.dto.RoleDTO;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.dromara.common.core.domain.dto.PostDTO;
+import org.dromara.common.core.domain.dto.RoleDTO;
 
 import java.io.Serial;
 import java.io.Serializable;
@@ -112,6 +113,11 @@
     private List<RoleDTO> roles;
 
     /**
+     * 宀椾綅瀵硅薄
+     */
+    private List<PostDTO> posts;
+
+    /**
      * 鏁版嵁鏉冮檺 褰撳墠瑙掕壊ID
      */
     private Long roleId;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java
index 22de8f2..87d0e8e 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java
@@ -5,8 +5,6 @@
 import lombok.EqualsAndHashCode;
 import org.hibernate.validator.constraints.Length;
 
-import static org.dromara.common.core.constant.UserConstants.*;
-
 /**
  * 瀵嗙爜鐧诲綍瀵硅薄
  *
@@ -20,14 +18,14 @@
      * 鐢ㄦ埛鍚�
      */
     @NotBlank(message = "{user.username.not.blank}")
-    @Length(min = USERNAME_MIN_LENGTH, max = USERNAME_MAX_LENGTH, message = "{user.username.length.valid}")
+    @Length(min = 2, max = 20, message = "{user.username.length.valid}")
     private String username;
 
     /**
      * 鐢ㄦ埛瀵嗙爜
      */
     @NotBlank(message = "{user.password.not.blank}")
-    @Length(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
+    @Length(min = 5, max = 20, message = "{user.password.length.valid}")
     private String password;
 
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java
index 440422b..6ea8a76 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java
@@ -5,8 +5,6 @@
 import lombok.EqualsAndHashCode;
 import org.hibernate.validator.constraints.Length;
 
-import static org.dromara.common.core.constant.UserConstants.*;
-
 /**
  * 鐢ㄦ埛娉ㄥ唽瀵硅薄
  *
@@ -20,14 +18,14 @@
      * 鐢ㄦ埛鍚�
      */
     @NotBlank(message = "{user.username.not.blank}")
-    @Length(min = USERNAME_MIN_LENGTH, max = USERNAME_MAX_LENGTH, message = "{user.username.length.valid}")
+    @Length(min = 2, max = 20, message = "{user.username.length.valid}")
     private String username;
 
     /**
      * 鐢ㄦ埛瀵嗙爜
      */
     @NotBlank(message = "{user.password.not.blank}")
-    @Length(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
+    @Length(min = 5, max = 20, message = "{user.password.length.valid}")
     private String password;
 
     private String userType;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java
new file mode 100644
index 0000000..0cbed2f
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java
@@ -0,0 +1,56 @@
+package org.dromara.common.core.domain.model;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 浠诲姟鍙楄浜�
+ *
+ * @author AprilWind
+ */
+@Data
+@NoArgsConstructor
+public class TaskAssigneeBody implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鏉冮檺缂栫爜
+     */
+    private String handlerCode;
+
+    /**
+     * 鏉冮檺鍚嶇О
+     */
+    private String handlerName;
+
+    /**
+     * 鏉冮檺鍒嗙粍
+     */
+    private String groupId;
+
+    /**
+     * 寮�濮嬫椂闂�
+     */
+    private String beginTime;
+
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    private String endTime;
+
+    /**
+     * 褰撳墠椤�
+     */
+    private Integer pageNum = 1;
+
+    /**
+     * 姣忛〉鏄剧ず鏉℃暟
+     */
+    private Integer pageSize = 10;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java
index 0af943a..c1660ee 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java
@@ -7,6 +7,10 @@
 import org.dromara.common.core.utils.StringUtils;
 
 import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * 涓氬姟鐘舵�佹灇涓�
@@ -16,30 +20,37 @@
 @Getter
 @AllArgsConstructor
 public enum BusinessStatusEnum {
+
     /**
      * 宸叉挙閿�
      */
     CANCEL("cancel", "宸叉挙閿�"),
+
     /**
      * 鑽夌
      */
     DRAFT("draft", "鑽夌"),
+
     /**
      * 寰呭鏍�
      */
     WAITING("waiting", "寰呭鏍�"),
+
     /**
      * 宸插畬鎴�
      */
     FINISH("finish", "宸插畬鎴�"),
+
     /**
      * 宸蹭綔搴�
      */
     INVALID("invalid", "宸蹭綔搴�"),
+
     /**
      * 宸查��鍥�
      */
     BACK("back", "宸查��鍥�"),
+
     /**
      * 宸茬粓姝�
      */
@@ -55,20 +66,72 @@
      */
     private final String desc;
 
+    private static final Map<String, BusinessStatusEnum> STATUS_MAP = Arrays.stream(BusinessStatusEnum.values())
+        .collect(Collectors.toConcurrentMap(BusinessStatusEnum::getStatus, Function.identity()));
+
     /**
-     * 鑾峰彇涓氬姟鐘舵��
+     * 鏍规嵁鐘舵�佽幏鍙栧搴旂殑 BusinessStatusEnum 鏋氫妇
      *
-     * @param status 鐘舵��
+     * @param status 涓氬姟鐘舵�佺爜
+     * @return 瀵瑰簲鐨� BusinessStatusEnum 鏋氫妇锛屽鏋滄壘涓嶅埌鍒欒繑鍥� null
+     */
+    public static BusinessStatusEnum getByStatus(String status) {
+        // 浣跨敤 STATUS_MAP 鑾峰彇瀵瑰簲鐨勬灇涓撅紝鑻ユ壘涓嶅埌鍒欒繑鍥� null
+        return STATUS_MAP.get(status);
+    }
+
+    /**
+     * 鏍规嵁鐘舵�佽幏鍙栧搴旂殑涓氬姟鐘舵�佹弿杩颁俊鎭�
+     *
+     * @param status 涓氬姟鐘舵�佺爜
+     * @return 杩斿洖涓氬姟鐘舵�佹弿杩帮紝鑻ョ姸鎬佺爜涓虹┖鎴栨湭鎵惧埌瀵瑰簲鐨勬灇涓撅紝杩斿洖绌哄瓧绗︿覆
      */
     public static String findByStatus(String status) {
         if (StringUtils.isBlank(status)) {
             return StrUtil.EMPTY;
         }
-        return Arrays.stream(BusinessStatusEnum.values())
-            .filter(statusEnum -> statusEnum.getStatus().equals(status))
-            .findFirst()
-            .map(BusinessStatusEnum::getDesc)
-            .orElse(StrUtil.EMPTY);
+        BusinessStatusEnum statusEnum = STATUS_MAP.get(status);
+        return (statusEnum != null) ? statusEnum.getDesc() : StrUtil.EMPTY;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁涓烘寚瀹氱殑鐘舵�佷箣涓�锛氳崏绋裤�佸凡鎾ら攢鎴栧凡閫�鍥�
+     *
+     * @param status 瑕佹鏌ョ殑鐘舵��
+     * @return 濡傛灉鐘舵�佷负鑽夌銆佸凡鎾ら攢鎴栧凡閫�鍥炰箣涓�锛屽垯杩斿洖 true锛涘惁鍒欒繑鍥� false
+     */
+    public static boolean isDraftOrCancelOrBack(String status) {
+        return DRAFT.status.equals(status) || CANCEL.status.equals(status) || BACK.status.equals(status);
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁涓烘挙閿�锛岄��鍥烇紝浣滃簾锛岀粓姝�
+     *
+     * @param status status
+     * @return 缁撴灉
+     */
+    public static boolean initialState(String status) {
+        return CANCEL.status.equals(status) || BACK.status.equals(status) || INVALID.status.equals(status) || TERMINATION.status.equals(status);
+    }
+
+    /**
+     * 鑾峰彇杩愯涓殑瀹炰緥鐘舵�佸垪琛�
+     *
+     * @return 鍖呭惈杩愯涓疄渚嬬姸鎬佺殑涓嶅彲鍙樺垪琛�
+     * 锛堝寘鍚� DRAFT銆乄AITING銆丅ACK 鍜� CANCEL 鐘舵�侊級
+     */
+    public static List<String> runningStatus() {
+        return Arrays.asList(DRAFT.status, WAITING.status, BACK.status, CANCEL.status);
+    }
+
+    /**
+     * 鑾峰彇缁撴潫瀹炰緥鐨勭姸鎬佸垪琛�
+     *
+     * @return 鍖呭惈缁撴潫瀹炰緥鐘舵�佺殑涓嶅彲鍙樺垪琛�
+     * 锛堝寘鍚� FINISH銆両NVALID 鍜� TERMINATION 鐘舵�侊級
+     */
+    public static List<String> finishStatus() {
+        return Arrays.asList(FINISH.status, INVALID.status, TERMINATION.status);
     }
 
     /**
@@ -148,5 +211,5 @@
             throw new ServiceException("娴佺▼鐘舵�佷负绌猴紒");
         }
     }
-}
 
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java
new file mode 100644
index 0000000..8d4b6d9
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java
@@ -0,0 +1,146 @@
+package org.dromara.common.core.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.dromara.common.core.utils.StringUtils;
+
+/*
+ * 鏃ユ湡鏍煎紡
+ * "yyyy"锛�4浣嶆暟鐨勫勾浠斤紝渚嬪锛�2023骞磋〃绀轰负"2023"銆�
+ * "yy"锛�2浣嶆暟鐨勫勾浠斤紝渚嬪锛�2023骞磋〃绀轰负"23"銆�
+ * "MM"锛�2浣嶆暟鐨勬湀浠斤紝鍙栧�艰寖鍥翠负01鍒�12锛屼緥濡傦細7鏈堣〃绀轰负"07"銆�
+ * "M"锛氫笉甯﹀墠瀵奸浂鐨勬湀浠斤紝鍙栧�艰寖鍥翠负1鍒�12锛屼緥濡傦細7鏈堣〃绀轰负"7"銆�
+ * "dd"锛�2浣嶆暟鐨勬棩鏈燂紝鍙栧�艰寖鍥翠负01鍒�31锛屼緥濡傦細22鏃ヨ〃绀轰负"22"銆�
+ * "d"锛氫笉甯﹀墠瀵奸浂鐨勬棩鏈燂紝鍙栧�艰寖鍥翠负1鍒�31锛屼緥濡傦細22鏃ヨ〃绀轰负"22"銆�
+ * "EEEE"锛氭槦鏈熺殑鍏ㄥ悕锛屼緥濡傦細鏄熸湡涓夎〃绀轰负"Wednesday"銆�
+ * "E"锛氭槦鏈熺殑缂╁啓锛屼緥濡傦細鏄熸湡涓夎〃绀轰负"Wed"銆�
+ * "DDD" 鎴� "D"锛氫竴骞翠腑鐨勭鍑犲ぉ锛屽彇鍊艰寖鍥翠负001鍒�366锛屼緥濡傦細绗�200澶╄〃绀轰负"200"銆�
+ * 鏃堕棿鏍煎紡
+ * "HH"锛�24灏忔椂鍒剁殑灏忔椂鏁帮紝鍙栧�艰寖鍥翠负00鍒�23锛屼緥濡傦細涓嬪崍5鐐硅〃绀轰负"17"銆�
+ * "hh"锛�12灏忔椂鍒剁殑灏忔椂鏁帮紝鍙栧�艰寖鍥翠负01鍒�12锛屼緥濡傦細涓嬪崍5鐐硅〃绀轰负"05"銆�
+ * "mm"锛氬垎閽熸暟锛屽彇鍊艰寖鍥翠负00鍒�59锛屼緥濡傦細30鍒嗛挓琛ㄧず涓�"30"銆�
+ * "ss"锛氱鏁帮紝鍙栧�艰寖鍥翠负00鍒�59锛屼緥濡傦細45绉掕〃绀轰负"45"銆�
+ * "SSS"锛氭绉掓暟锛屽彇鍊艰寖鍥翠负000鍒�999锛屼緥濡傦細123姣琛ㄧず涓�"123"銆�
+ */
+
+/**
+ * 鏃ユ湡鏍煎紡涓庢椂闂存牸寮忔灇涓�
+ */
+@Getter
+@AllArgsConstructor
+public enum FormatsType {
+
+    /**
+     * 渚嬪锛�2023骞磋〃绀轰负"23"
+     */
+    YY("yy"),
+
+    /**
+     * 渚嬪锛�2023骞磋〃绀轰负"2023"
+     */
+    YYYY("yyyy"),
+
+    /**
+     * 渚嬩緥濡傦紝2023骞�7鏈堝彲浠ヨ〃绀轰负 "2023-07"
+     */
+    YYYY_MM("yyyy-MM"),
+
+    /**
+     * 渚嬪锛屾棩鏈� "2023骞�7鏈�22鏃�" 鍙互琛ㄧず涓� "2023-07-22"
+     */
+    YYYY_MM_DD("yyyy-MM-dd"),
+
+    /**
+     * 渚嬪锛屽綋鍓嶆椂闂村鏋滄槸 "2023骞�7鏈�22鏃ヤ笅鍗�3鐐�30鍒�"锛屽垯鍙互琛ㄧず涓� "2023-07-22 15:30"
+     */
+    YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm"),
+
+    /**
+     * 渚嬪锛屽綋鍓嶆椂闂村鏋滄槸 "2023骞�7鏈�22鏃ヤ笅鍗�3鐐�30鍒�45绉�"锛屽垯鍙互琛ㄧず涓� "2023-07-22 15:30:45"
+     */
+    YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss"),
+
+    /**
+     * 渚嬪锛氫笅鍗�3鐐�30鍒�45绉掞紝琛ㄧず涓� "15:30:45"
+     */
+    HH_MM_SS("HH:mm:ss"),
+
+    /**
+     * 渚嬩緥濡傦紝2023骞�7鏈堝彲浠ヨ〃绀轰负 "2023/07"
+     */
+    YYYY_MM_SLASH("yyyy/MM"),
+
+    /**
+     * 渚嬪锛屾棩鏈� "2023骞�7鏈�22鏃�" 鍙互琛ㄧず涓� "2023/07/22"
+     */
+    YYYY_MM_DD_SLASH("yyyy/MM/dd"),
+
+    /**
+     * 渚嬪锛屽綋鍓嶆椂闂村鏋滄槸 "2023骞�7鏈�22鏃ヤ笅鍗�3鐐�30鍒�45绉�"锛屽垯鍙互琛ㄧず涓� "2023/07/22 15:30:45"
+     */
+    YYYY_MM_DD_HH_MM_SLASH("yyyy/MM/dd HH:mm"),
+
+    /**
+     * 渚嬪锛屽綋鍓嶆椂闂村鏋滄槸 "2023骞�7鏈�22鏃ヤ笅鍗�3鐐�30鍒�45绉�"锛屽垯鍙互琛ㄧず涓� "2023/07/22 15:30:45"
+     */
+    YYYY_MM_DD_HH_MM_SS_SLASH("yyyy/MM/dd HH:mm:ss"),
+
+    /**
+     * 渚嬩緥濡傦紝2023骞�7鏈堝彲浠ヨ〃绀轰负 "2023.07"
+     */
+    YYYY_MM_DOT("yyyy.MM"),
+
+    /**
+     * 渚嬪锛屾棩鏈� "2023骞�7鏈�22鏃�" 鍙互琛ㄧず涓� "2023.07.22"
+     */
+    YYYY_MM_DD_DOT("yyyy.MM.dd"),
+
+    /**
+     * 渚嬪锛屽綋鍓嶆椂闂村鏋滄槸 "2023骞�7鏈�22鏃ヤ笅鍗�3鐐�30鍒�"锛屽垯鍙互琛ㄧず涓� "2023.07.22 15:30"
+     */
+    YYYY_MM_DD_HH_MM_DOT("yyyy.MM.dd HH:mm"),
+
+    /**
+     * 渚嬪锛屽綋鍓嶆椂闂村鏋滄槸 "2023骞�7鏈�22鏃ヤ笅鍗�3鐐�30鍒�45绉�"锛屽垯鍙互琛ㄧず涓� "2023.07.22 15:30:45"
+     */
+    YYYY_MM_DD_HH_MM_SS_DOT("yyyy.MM.dd HH:mm:ss"),
+
+    /**
+     * 渚嬪锛�2023骞�7鏈堝彲浠ヨ〃绀轰负 "202307"
+     */
+    YYYYMM("yyyyMM"),
+
+    /**
+     * 渚嬪锛�2023骞�7鏈�22鏃ュ彲浠ヨ〃绀轰负 "20230722"
+     */
+    YYYYMMDD("yyyyMMdd"),
+
+    /**
+     * 渚嬪锛�2023骞�7鏈�22鏃ヤ笅鍗�3鐐瑰彲浠ヨ〃绀轰负 "2023072215"
+     */
+    YYYYMMDDHH("yyyyMMddHH"),
+
+    /**
+     * 渚嬪锛�2023骞�7鏈�22鏃ヤ笅鍗�3鐐�30鍒嗗彲浠ヨ〃绀轰负 "202307221530"
+     */
+    YYYYMMDDHHMM("yyyyMMddHHmm"),
+
+    /**
+     * 渚嬪锛�2023骞�7鏈�22鏃ヤ笅鍗�3鐐�30鍒�45绉掑彲浠ヨ〃绀轰负 "20230722153045"
+     */
+    YYYYMMDDHHMMSS("yyyyMMddHHmmss");
+
+    /**
+     * 鏃堕棿鏍煎紡
+     */
+    private final String timeFormat;
+
+    public static FormatsType getFormatsType(String str) {
+        for (FormatsType value : values()) {
+            if (StringUtils.contains(str, value.getTimeFormat())) {
+                return value;
+            }
+        }
+        throw new RuntimeException("'FormatsType' not found By " + str);
+    }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/TenantStatus.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/TenantStatus.java
deleted file mode 100644
index 400a399..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/TenantStatus.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.dromara.common.core.enums;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * 鐢ㄦ埛鐘舵��
- *
- * @author LionLi
- */
-@Getter
-@AllArgsConstructor
-public enum TenantStatus {
-    /**
-     * 姝e父
-     */
-    OK("0", "姝e父"),
-    /**
-     * 鍋滅敤
-     */
-    DISABLE("1", "鍋滅敤"),
-    /**
-     * 鍒犻櫎
-     */
-    DELETED("2", "鍒犻櫎");
-
-    private final String code;
-    private final String info;
-
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java
new file mode 100644
index 0000000..a76e16d
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java
@@ -0,0 +1,62 @@
+package org.dromara.common.core.exception;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+
+/**
+ * sse 鐗瑰埗寮傚父
+ *
+ * @author LionLi
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public final class SseException extends RuntimeException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 閿欒鐮�
+     */
+    private Integer code;
+
+    /**
+     * 閿欒鎻愮ず
+     */
+    private String message;
+
+    /**
+     * 閿欒鏄庣粏锛屽唴閮ㄨ皟璇曢敊璇�
+     */
+    private String detailMessage;
+
+    public SseException(String message) {
+        this.message = message;
+    }
+
+    public SseException(String message, Integer code) {
+        this.message = message;
+        this.code = code;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public SseException setMessage(String message) {
+        this.message = message;
+        return this;
+    }
+
+    public SseException setDetailMessage(String detailMessage) {
+        this.detailMessage = detailMessage;
+        return this;
+    }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java
index db9463e..f93d177 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java
@@ -1,5 +1,9 @@
 package org.dromara.common.core.service;
 
+import org.dromara.common.core.domain.dto.DeptDTO;
+
+import java.util.List;
+
 /**
  * 閫氱敤 閮ㄩ棬鏈嶅姟
  *
@@ -15,4 +19,19 @@
      */
     String selectDeptNameByIds(String deptIds);
 
+    /**
+     * 鏍规嵁閮ㄩ棬ID鏌ヨ閮ㄩ棬璐熻矗浜�
+     *
+     * @param deptId 閮ㄩ棬ID锛岀敤浜庢寚瀹氶渶瑕佹煡璇㈢殑閮ㄩ棬
+     * @return 杩斿洖璇ラ儴闂ㄧ殑璐熻矗浜篒D
+     */
+    Long selectDeptLeaderById(Long deptId);
+
+    /**
+     * 鏌ヨ閮ㄩ棬
+     *
+     * @return 閮ㄩ棬鍒楄〃
+     */
+    List<DeptDTO> selectDeptsByList();
+
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java
new file mode 100644
index 0000000..41d4e83
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java
@@ -0,0 +1,10 @@
+package org.dromara.common.core.service;
+
+/**
+ * 閫氱敤 宀椾綅鏈嶅姟
+ *
+ * @author AprilWind
+ */
+public interface PostService {
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java
new file mode 100644
index 0000000..ba62c82
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java
@@ -0,0 +1,10 @@
+package org.dromara.common.core.service;
+
+/**
+ * 閫氱敤 瑙掕壊鏈嶅姟
+ *
+ * @author AprilWind
+ */
+public interface RoleService {
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java
new file mode 100644
index 0000000..9af6691
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java
@@ -0,0 +1,45 @@
+package org.dromara.common.core.service;
+
+import org.dromara.common.core.domain.dto.TaskAssigneeDTO;
+import org.dromara.common.core.domain.model.TaskAssigneeBody;
+
+/**
+ * 宸ヤ綔娴佽璁″櫒鑾峰彇浠诲姟鎵ц浜�
+ *
+ * @author Lion Li
+ */
+public interface TaskAssigneeService {
+
+    /**
+     * 鏌ヨ瑙掕壊骞惰繑鍥炰换鍔℃寚娲剧殑鍒楄〃锛屾敮鎸佸垎椤�
+     *
+     * @param taskQuery 鏌ヨ鏉′欢
+     * @return 鍔炵悊浜�
+     */
+    TaskAssigneeDTO selectRolesByTaskAssigneeList(TaskAssigneeBody taskQuery);
+
+    /**
+     * 鏌ヨ宀椾綅骞惰繑鍥炰换鍔℃寚娲剧殑鍒楄〃锛屾敮鎸佸垎椤�
+     *
+     * @param taskQuery 鏌ヨ鏉′欢
+     * @return 鍔炵悊浜�
+     */
+    TaskAssigneeDTO selectPostsByTaskAssigneeList(TaskAssigneeBody taskQuery);
+
+    /**
+     * 鏌ヨ閮ㄩ棬骞惰繑鍥炰换鍔℃寚娲剧殑鍒楄〃锛屾敮鎸佸垎椤�
+     *
+     * @param taskQuery 鏌ヨ鏉′欢
+     * @return 鍔炵悊浜�
+     */
+    TaskAssigneeDTO selectDeptsByTaskAssigneeList(TaskAssigneeBody taskQuery);
+
+    /**
+     * 鏌ヨ鐢ㄦ埛骞惰繑鍥炰换鍔℃寚娲剧殑鍒楄〃锛屾敮鎸佸垎椤�
+     *
+     * @param taskQuery 鏌ヨ鏉′欢
+     * @return 鍔炵悊浜�
+     */
+    TaskAssigneeDTO selectUsersByTaskAssigneeList(TaskAssigneeBody taskQuery);
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
index 43aef28..67cd54f 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
@@ -82,4 +82,13 @@
      * @return 鐢ㄦ埛
      */
     List<UserDTO> selectUsersByDeptIds(List<Long> deptIds);
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ鐢ㄦ埛
+     *
+     * @param postIds 宀椾綅ids
+     * @return 鐢ㄦ埛
+     */
+    List<UserDTO> selectUsersByPostIds(List<Long> postIds);
+
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java
index 4e556c9..abbcbff 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java
@@ -1,5 +1,9 @@
 package org.dromara.common.core.service;
 
+import org.dromara.common.core.domain.dto.CompleteTaskDTO;
+import org.dromara.common.core.domain.dto.StartProcessDTO;
+import org.dromara.common.core.domain.dto.StartProcessReturnDTO;
+
 import java.util.List;
 import java.util.Map;
 
@@ -13,64 +17,70 @@
     /**
      * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
      *
-     * @param businessKeys 涓氬姟id
+     * @param businessIds 涓氬姟id
      * @return 缁撴灉
      */
-    boolean deleteRunAndHisInstance(List<String> businessKeys);
+    boolean deleteInstance(List<Long> businessIds);
 
     /**
      * 鑾峰彇褰撳墠娴佺▼鐘舵��
      *
      * @param taskId 浠诲姟id
+     * @return 鐘舵��
      */
-    String getBusinessStatusByTaskId(String taskId);
+    String getBusinessStatusByTaskId(Long taskId);
 
     /**
      * 鑾峰彇褰撳墠娴佺▼鐘舵��
      *
-     * @param businessKey 涓氬姟id
+     * @param businessId 涓氬姟id
+     * @return 鐘舵��
      */
-    String getBusinessStatus(String businessKey);
+    String getBusinessStatus(String businessId);
 
     /**
-     * 璁剧疆娴佺▼鍙橀噺(鍏ㄥ眬鍙橀噺)
+     * 璁剧疆娴佺▼鍙橀噺
      *
-     * @param taskId       浠诲姟id
-     * @param variableName 鍙橀噺鍚嶇О
-     * @param value        鍙橀噺鍊�
+     * @param instanceId 娴佺▼瀹炰緥id
+     * @param variable   娴佺▼鍙橀噺
      */
-    void setVariable(String taskId, String variableName, Object value);
+    void setVariable(Long instanceId, Map<String, Object> variable);
 
     /**
-     * 璁剧疆娴佺▼鍙橀噺(鍏ㄥ眬鍙橀噺)
+     * 鑾峰彇娴佺▼鍙橀噺
      *
-     * @param taskId    浠诲姟id
-     * @param variables 娴佺▼鍙橀噺
+     * @param instanceId 娴佺▼瀹炰緥id
      */
-    void setVariables(String taskId, Map<String, Object> variables);
-
-    /**
-     * 璁剧疆娴佺▼鍙橀噺(鏈湴鍙橀噺,闈炲叏灞�鍙橀噺)
-     *
-     * @param taskId       浠诲姟id
-     * @param variableName 鍙橀噺鍚嶇О
-     * @param value        鍙橀噺鍊�
-     */
-    void setVariableLocal(String taskId, String variableName, Object value);
-
-    /**
-     * 璁剧疆娴佺▼鍙橀噺(鏈湴鍙橀噺,闈炲叏灞�鍙橀噺)
-     *
-     * @param taskId    浠诲姟id
-     * @param variables 娴佺▼鍙橀噺
-     */
-    void setVariablesLocal(String taskId, Map<String, Object> variables);
+    Map<String, Object> instanceVariable(Long instanceId);
 
     /**
      * 鎸夌収涓氬姟id鏌ヨ娴佺▼瀹炰緥id
      *
-     * @param businessKey 涓氬姟id
+     * @param businessId 涓氬姟id
      * @return 缁撴灉
      */
-    String getInstanceIdByBusinessKey(String businessKey);
+    Long getInstanceIdByBusinessId(String businessId);
+
+    /**
+     * 鏂板绉熸埛娴佺▼瀹氫箟
+     *
+     * @param tenantId 绉熸埛id
+     */
+    void syncDef(String tenantId);
+
+    /**
+     * 鍚姩娴佺▼
+     *
+     * @param startProcess 鍙傛暟
+     * @return 缁撴灉
+     */
+    StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess);
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTask 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean completeTask(CompleteTaskDTO completeTask);
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
index 72178a7..41d0f6c 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
@@ -1,106 +1,157 @@
 package org.dromara.common.core.utils;
 
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
 import org.apache.commons.lang3.time.DateFormatUtils;
+import org.dromara.common.core.enums.FormatsType;
+import org.dromara.common.core.exception.ServiceException;
 
 import java.lang.management.ManagementFactory;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
+import java.time.*;
 import java.util.Date;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 鏃堕棿宸ュ叿绫�
  *
  * @author ruoyi
  */
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
-
-    public static final String YYYY = "yyyy";
-
-    public static final String YYYY_MM = "yyyy-MM";
-
-    public static final String YYYY_MM_DD = "yyyy-MM-dd";
-
-    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
-
-    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
-
     private static final String[] PARSE_PATTERNS = {
         "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
         "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
         "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
 
+    @Deprecated
+    private DateUtils() {
+    }
+
     /**
-     * 鑾峰彇褰撳墠Date鍨嬫棩鏈�
+     * 鑾峰彇褰撳墠鏃ユ湡鍜屾椂闂�
      *
-     * @return Date() 褰撳墠鏃ユ湡
+     * @return 褰撳墠鏃ユ湡鍜屾椂闂寸殑 Date 瀵硅薄琛ㄧず
      */
     public static Date getNowDate() {
         return new Date();
     }
 
     /**
-     * 鑾峰彇褰撳墠鏃ユ湡, 榛樿鏍煎紡涓簓yyy-MM-dd
+     * 鑾峰彇褰撳墠鏃ユ湡鐨勫瓧绗︿覆琛ㄧず锛屾牸寮忎负YYYY-MM-DD
      *
-     * @return String
+     * @return 褰撳墠鏃ユ湡鐨勫瓧绗︿覆琛ㄧず
      */
     public static String getDate() {
-        return dateTimeNow(YYYY_MM_DD);
+        return dateTimeNow(FormatsType.YYYY_MM_DD);
     }
 
+    /**
+     * 鑾峰彇褰撳墠鏃ユ湡鐨勫瓧绗︿覆琛ㄧず锛屾牸寮忎负yyyyMMdd
+     *
+     * @return 褰撳墠鏃ユ湡鐨勫瓧绗︿覆琛ㄧず
+     */
+    public static String getCurrentDate() {
+        return DateFormatUtils.format(new Date(), FormatsType.YYYYMMDD.getTimeFormat());
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鏃ユ湡鐨勮矾寰勬牸寮忓瓧绗︿覆锛屾牸寮忎负"yyyy/MM/dd"
+     *
+     * @return 褰撳墠鏃ユ湡鐨勮矾寰勬牸寮忓瓧绗︿覆
+     */
+    public static String datePath() {
+        Date now = new Date();
+        return DateFormatUtils.format(now, FormatsType.YYYY_MM_DD_SLASH.getTimeFormat());
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鏃堕棿鐨勫瓧绗︿覆琛ㄧず锛屾牸寮忎负YYYY-MM-DD HH:MM:SS
+     *
+     * @return 褰撳墠鏃堕棿鐨勫瓧绗︿覆琛ㄧず
+     */
     public static String getTime() {
-        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
+        return dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS);
     }
 
+    /**
+     * 鑾峰彇褰撳墠鏃堕棿鐨勫瓧绗︿覆琛ㄧず锛屾牸寮忎负 "HH:MM:SS"
+     *
+     * @return 褰撳墠鏃堕棿鐨勫瓧绗︿覆琛ㄧず锛屾牸寮忎负 "HH:MM:SS"
+     */
+    public static String getTimeWithHourMinuteSecond() {
+        return dateTimeNow(FormatsType.HH_MM_SS);
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鏃ユ湡鍜屾椂闂寸殑瀛楃涓茶〃绀猴紝鏍煎紡涓篩YYYMMDDHHMMSS
+     *
+     * @return 褰撳墠鏃ユ湡鍜屾椂闂寸殑瀛楃涓茶〃绀�
+     */
     public static String dateTimeNow() {
-        return dateTimeNow(YYYYMMDDHHMMSS);
+        return dateTimeNow(FormatsType.YYYYMMDDHHMMSS);
     }
 
-    public static String dateTimeNow(final String format) {
+    /**
+     * 鑾峰彇褰撳墠鏃ユ湡鍜屾椂闂寸殑鎸囧畾鏍煎紡鐨勫瓧绗︿覆琛ㄧず
+     *
+     * @param format 鏃ユ湡鏃堕棿鏍煎紡锛屼緥濡�"YYYY-MM-DD HH:MM:SS"
+     * @return 褰撳墠鏃ユ湡鍜屾椂闂寸殑瀛楃涓茶〃绀�
+     */
+    public static String dateTimeNow(final FormatsType format) {
         return parseDateToStr(format, new Date());
     }
 
-    public static String dateTime(final Date date) {
-        return parseDateToStr(YYYY_MM_DD, date);
+    /**
+     * 灏嗘寚瀹氭棩鏈熸牸寮忓寲涓� YYYY-MM-DD 鏍煎紡鐨勫瓧绗︿覆
+     *
+     * @param date 瑕佹牸寮忓寲鐨勬棩鏈熷璞�
+     * @return 鏍煎紡鍖栧悗鐨勬棩鏈熷瓧绗︿覆
+     */
+    public static String formatDate(final Date date) {
+        return parseDateToStr(FormatsType.YYYY_MM_DD, date);
     }
 
-    public static String parseDateToStr(final String format, final Date date) {
-        return new SimpleDateFormat(format).format(date);
+    /**
+     * 灏嗘寚瀹氭棩鏈熸牸寮忓寲涓� YYYY-MM-DD HH:MM:SS 鏍煎紡鐨勫瓧绗︿覆
+     *
+     * @param date 瑕佹牸寮忓寲鐨勬棩鏈熷璞�
+     * @return 鏍煎紡鍖栧悗鐨勬棩鏈熸椂闂村瓧绗︿覆
+     */
+    public static String formatDateTime(final Date date) {
+        return parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, date);
     }
 
-    public static Date dateTime(final String format, final String ts) {
+    /**
+     * 灏嗘寚瀹氭棩鏈熸寜鐓ф寚瀹氭牸寮忚繘琛屾牸寮忓寲
+     *
+     * @param format 瑕佷娇鐢ㄧ殑鏃ユ湡鏃堕棿鏍煎紡锛屼緥濡�"YYYY-MM-DD HH:MM:SS"
+     * @param date   瑕佹牸寮忓寲鐨勬棩鏈熷璞�
+     * @return 鏍煎紡鍖栧悗鐨勬棩鏈熸椂闂村瓧绗︿覆
+     */
+    public static String parseDateToStr(final FormatsType format, final Date date) {
+        return new SimpleDateFormat(format.getTimeFormat()).format(date);
+    }
+
+    /**
+     * 灏嗘寚瀹氭牸寮忕殑鏃ユ湡鏃堕棿瀛楃涓茶浆鎹负 Date 瀵硅薄
+     *
+     * @param format 瑕佽В鏋愮殑鏃ユ湡鏃堕棿鏍煎紡锛屼緥濡�"YYYY-MM-DD HH:MM:SS"
+     * @param ts     瑕佽В鏋愮殑鏃ユ湡鏃堕棿瀛楃涓�
+     * @return 瑙f瀽鍚庣殑 Date 瀵硅薄
+     * @throws RuntimeException 濡傛灉瑙f瀽杩囩▼涓彂鐢熷紓甯�
+     */
+    public static Date parseDateTime(final FormatsType format, final String ts) {
         try {
-            return new SimpleDateFormat(format).parse(ts);
+            return new SimpleDateFormat(format.getTimeFormat()).parse(ts);
         } catch (ParseException e) {
             throw new RuntimeException(e);
         }
     }
 
     /**
-     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�2018/08/08
-     */
-    public static String datePath() {
-        Date now = new Date();
-        return DateFormatUtils.format(now, "yyyy/MM/dd");
-    }
-
-    /**
-     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�20180808
-     */
-    public static String dateTime() {
-        Date now = new Date();
-        return DateFormatUtils.format(now, "yyyyMMdd");
-    }
-
-    /**
-     * 鏃ユ湡鍨嬪瓧绗︿覆杞寲涓烘棩鏈� 鏍煎紡
+     * 灏嗗璞¤浆鎹负鏃ユ湡瀵硅薄
+     *
+     * @param str 瑕佽浆鎹㈢殑瀵硅薄锛岄�氬父鏄瓧绗︿覆
+     * @return 杞崲鍚庣殑鏃ユ湡瀵硅薄锛屽鏋滆浆鎹㈠け璐ユ垨杈撳叆涓簄ull锛屽垯杩斿洖null
      */
     public static Date parseDate(Object str) {
         if (str == null) {
@@ -115,6 +166,8 @@
 
     /**
      * 鑾峰彇鏈嶅姟鍣ㄥ惎鍔ㄦ椂闂�
+     *
+     * @return 鏈嶅姟鍣ㄥ惎鍔ㄦ椂闂寸殑 Date 瀵硅薄琛ㄧず
      */
     public static Date getServerStartDate() {
         long time = ManagementFactory.getRuntimeMXBean().getStartTime();
@@ -122,35 +175,66 @@
     }
 
     /**
-     * 璁$畻鐩稿樊澶╂暟
+     * 璁$畻涓や釜鏃ユ湡涔嬮棿鐨勫ぉ鏁板樊锛堜互姣涓哄崟浣嶏級
+     *
+     * @param date1 绗竴涓棩鏈�
+     * @param date2 绗簩涓棩鏈�
+     * @return 涓や釜鏃ユ湡涔嬮棿鐨勫ぉ鏁板樊鐨勭粷瀵瑰��
      */
     public static int differentDaysByMillisecond(Date date1, Date date2) {
         return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
     }
 
     /**
-     * 璁$畻涓や釜鏃堕棿宸�
+     * 璁$畻涓や釜鏃ユ湡涔嬮棿鐨勬椂闂村樊锛屽苟浠ュぉ銆佸皬鏃跺拰鍒嗛挓鐨勬牸寮忚繑鍥�
+     *
+     * @param endDate 缁撴潫鏃ユ湡
+     * @param nowDate 褰撳墠鏃ユ湡
+     * @return 琛ㄧず鏃堕棿宸殑瀛楃涓诧紝鏍煎紡涓�"澶� 灏忔椂 鍒嗛挓"
      */
     public static String getDatePoor(Date endDate, Date nowDate) {
-        long nd = 1000 * 24 * 60 * 60;
-        long nh = 1000 * 60 * 60;
-        long nm = 1000 * 60;
-        // long ns = 1000;
-        // 鑾峰緱涓や釜鏃堕棿鐨勬绉掓椂闂村樊寮�
-        long diff = endDate.getTime() - nowDate.getTime();
-        // 璁$畻宸灏戝ぉ
-        long day = diff / nd;
-        // 璁$畻宸灏戝皬鏃�
-        long hour = diff % nd / nh;
-        // 璁$畻宸灏戝垎閽�
-        long min = diff % nd % nh / nm;
-        // 璁$畻宸灏戠//杈撳嚭缁撴灉
-        // long sec = diff % nd % nh % nm / ns;
-        return day + "澶�" + hour + "灏忔椂" + min + "鍒嗛挓";
+        long diffInMillis = endDate.getTime() - nowDate.getTime();
+        long day = TimeUnit.MILLISECONDS.toDays(diffInMillis);
+        long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24;
+        long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
+        return String.format("%d澶� %d灏忔椂 %d鍒嗛挓", day, hour, min);
     }
 
     /**
-     * 澧炲姞 LocalDateTime ==> Date
+     * 璁$畻涓や釜鏃堕棿鐐圭殑宸�硷紙澶┿�佸皬鏃躲�佸垎閽熴�佺锛夛紝褰撳�间负0鏃朵笉鏄剧ず璇ュ崟浣�
+     *
+     * @param endDate 缁撴潫鏃堕棿
+     * @param nowDate 褰撳墠鏃堕棿
+     * @return 鏃堕棿宸瓧绗︿覆锛屾牸寮忎负 "x澶� x灏忔椂 x鍒嗛挓 x绉�"锛岃嫢涓� 0 鍒欎笉鏄剧ず
+     */
+    public static String getTimeDifference(Date endDate, Date nowDate) {
+        long diffInMillis = endDate.getTime() - nowDate.getTime();
+        long day = TimeUnit.MILLISECONDS.toDays(diffInMillis);
+        long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24;
+        long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
+        long sec = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60;
+        // 鏋勫缓鏃堕棿宸瓧绗︿覆锛屾潯浠舵槸鍊间笉涓�0鎵嶆樉绀�
+        StringBuilder result = new StringBuilder();
+        if (day > 0) {
+            result.append(String.format("%d澶� ", day));
+        }
+        if (hour > 0) {
+            result.append(String.format("%d灏忔椂 ", hour));
+        }
+        if (min > 0) {
+            result.append(String.format("%d鍒嗛挓 ", min));
+        }
+        if (sec > 0) {
+            result.append(String.format("%d绉�", sec));
+        }
+        return result.length() > 0 ? result.toString().trim() : "0绉�";
+    }
+
+    /**
+     * 灏� LocalDateTime 瀵硅薄杞崲涓� Date 瀵硅薄
+     *
+     * @param temporalAccessor 瑕佽浆鎹㈢殑 LocalDateTime 瀵硅薄
+     * @return 杞崲鍚庣殑 Date 瀵硅薄
      */
     public static Date toDate(LocalDateTime temporalAccessor) {
         ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
@@ -158,11 +242,46 @@
     }
 
     /**
-     * 澧炲姞 LocalDate ==> Date
+     * 灏� LocalDate 瀵硅薄杞崲涓� Date 瀵硅薄
+     *
+     * @param temporalAccessor 瑕佽浆鎹㈢殑 LocalDate 瀵硅薄
+     * @return 杞崲鍚庣殑 Date 瀵硅薄
      */
     public static Date toDate(LocalDate temporalAccessor) {
         LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
         ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
         return Date.from(zdt.toInstant());
     }
+
+    /**
+     * 鏍¢獙鏃ユ湡鑼冨洿
+     *
+     * @param startDate 寮�濮嬫棩鏈�
+     * @param endDate   缁撴潫鏃ユ湡
+     * @param maxValue  鏈�澶ф椂闂磋法搴︾殑闄愬埗鍊�
+     * @param unit      鏃堕棿璺ㄥ害鐨勫崟浣嶏紝鍙�夋嫨 "DAYS"銆�"HOURS" 鎴� "MINUTES"
+     */
+    public static void validateDateRange(Date startDate, Date endDate, int maxValue, TimeUnit unit) {
+        // 鏍¢獙缁撴潫鏃ユ湡涓嶈兘鏃╀簬寮�濮嬫棩鏈�
+        if (endDate.before(startDate)) {
+            throw new ServiceException("缁撴潫鏃ユ湡涓嶈兘鏃╀簬寮�濮嬫棩鏈�");
+        }
+
+        // 璁$畻鏃堕棿璺ㄥ害
+        long diffInMillis = endDate.getTime() - startDate.getTime();
+
+        // 鏍规嵁鍗曚綅杞崲鏃堕棿璺ㄥ害
+        long diff = switch (unit) {
+            case DAYS -> TimeUnit.MILLISECONDS.toDays(diffInMillis);
+            case HOURS -> TimeUnit.MILLISECONDS.toHours(diffInMillis);
+            case MINUTES -> TimeUnit.MILLISECONDS.toMinutes(diffInMillis);
+            default -> throw new IllegalArgumentException("涓嶆敮鎸佺殑鏃堕棿鍗曚綅");
+        };
+
+        // 鏍¢獙鏃堕棿璺ㄥ害涓嶈秴杩囨渶澶ч檺鍒�
+        if (diff > maxValue) {
+            throw new ServiceException("鏈�澶ф椂闂磋法搴︿负 " + maxValue + " " + unit.toString().toLowerCase());
+        }
+    }
+
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java
new file mode 100644
index 0000000..93617b0
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java
@@ -0,0 +1,60 @@
+package org.dromara.common.core.utils;
+
+import cn.hutool.core.util.ObjectUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.function.Function;
+
+/**
+ * 瀵硅薄宸ュ叿绫�
+ *
+ * @author 绉嬭緸鏈瘨
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ObjectUtils extends ObjectUtil {
+
+    /**
+     * 濡傛灉瀵硅薄涓嶄负绌猴紝鍒欒幏鍙栧璞′腑鐨勬煇涓瓧娈� ObjectUtils.notNullGetter(user, User::getName);
+     *
+     * @param obj 瀵硅薄
+     * @param func 鑾峰彇鏂规硶
+     * @return 瀵硅薄瀛楁
+     */
+    public static <T, E> E notNullGetter(T obj, Function<T, E> func) {
+        if (isNotNull(obj) && isNotNull(func)) {
+            return func.apply(obj);
+        }
+        return null;
+    }
+
+    /**
+     * 濡傛灉瀵硅薄涓嶄负绌猴紝鍒欒幏鍙栧璞′腑鐨勬煇涓瓧娈碉紝鍚﹀垯杩斿洖榛樿鍊�
+     *
+     * @param obj          瀵硅薄
+     * @param func         鑾峰彇鏂规硶
+     * @param defaultValue 榛樿鍊�
+     * @return 瀵硅薄瀛楁
+     */
+    public static <T, E> E notNullGetter(T obj, Function<T, E> func, E defaultValue) {
+        if (isNotNull(obj) && isNotNull(func)) {
+            return func.apply(obj);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * 濡傛灉鍊间笉涓虹┖锛屽垯杩斿洖鍊硷紝鍚﹀垯杩斿洖榛樿鍊�
+     *
+     * @param obj          瀵硅薄
+     * @param defaultValue 榛樿鍊�
+     * @return 瀵硅薄瀛楁
+     */
+    public static <T> T notNull(T obj, T defaultValue) {
+        if (isNotNull(obj)) {
+            return obj;
+        }
+        return defaultValue;
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
index a1316eb..bd1aab8 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
@@ -25,7 +25,7 @@
 import java.util.Map;
 
 /**
- * 瀹㈡埛绔伐鍏风被
+ * 瀹㈡埛绔伐鍏风被锛屾彁渚涜幏鍙栬姹傚弬鏁般�佸搷搴斿鐞嗐�佸ご閮ㄤ俊鎭瓑甯哥敤鎿嶄綔
  *
  * @author ruoyi
  */
@@ -33,52 +33,73 @@
 public class ServletUtils extends JakartaServletUtil {
 
     /**
-     * 鑾峰彇String鍙傛暟
+     * 鑾峰彇鎸囧畾鍚嶇О鐨� String 绫诲瀷鐨勮姹傚弬鏁�
+     *
+     * @param name 鍙傛暟鍚�
+     * @return 鍙傛暟鍊�
      */
     public static String getParameter(String name) {
         return getRequest().getParameter(name);
     }
 
     /**
-     * 鑾峰彇String鍙傛暟
+     * 鑾峰彇鎸囧畾鍚嶇О鐨� String 绫诲瀷鐨勮姹傚弬鏁帮紝鑻ュ弬鏁颁笉瀛樺湪锛屽垯杩斿洖榛樿鍊�
+     *
+     * @param name         鍙傛暟鍚�
+     * @param defaultValue 榛樿鍊�
+     * @return 鍙傛暟鍊兼垨榛樿鍊�
      */
     public static String getParameter(String name, String defaultValue) {
         return Convert.toStr(getRequest().getParameter(name), defaultValue);
     }
 
     /**
-     * 鑾峰彇Integer鍙傛暟
+     * 鑾峰彇鎸囧畾鍚嶇О鐨� Integer 绫诲瀷鐨勮姹傚弬鏁�
+     *
+     * @param name 鍙傛暟鍚�
+     * @return 鍙傛暟鍊�
      */
     public static Integer getParameterToInt(String name) {
         return Convert.toInt(getRequest().getParameter(name));
     }
 
     /**
-     * 鑾峰彇Integer鍙傛暟
+     * 鑾峰彇鎸囧畾鍚嶇О鐨� Integer 绫诲瀷鐨勮姹傚弬鏁帮紝鑻ュ弬鏁颁笉瀛樺湪锛屽垯杩斿洖榛樿鍊�
+     *
+     * @param name         鍙傛暟鍚�
+     * @param defaultValue 榛樿鍊�
+     * @return 鍙傛暟鍊兼垨榛樿鍊�
      */
     public static Integer getParameterToInt(String name, Integer defaultValue) {
         return Convert.toInt(getRequest().getParameter(name), defaultValue);
     }
 
     /**
-     * 鑾峰彇Boolean鍙傛暟
+     * 鑾峰彇鎸囧畾鍚嶇О鐨� Boolean 绫诲瀷鐨勮姹傚弬鏁�
+     *
+     * @param name 鍙傛暟鍚�
+     * @return 鍙傛暟鍊�
      */
     public static Boolean getParameterToBool(String name) {
         return Convert.toBool(getRequest().getParameter(name));
     }
 
     /**
-     * 鑾峰彇Boolean鍙傛暟
+     * 鑾峰彇鎸囧畾鍚嶇О鐨� Boolean 绫诲瀷鐨勮姹傚弬鏁帮紝鑻ュ弬鏁颁笉瀛樺湪锛屽垯杩斿洖榛樿鍊�
+     *
+     * @param name         鍙傛暟鍚�
+     * @param defaultValue 榛樿鍊�
+     * @return 鍙傛暟鍊兼垨榛樿鍊�
      */
     public static Boolean getParameterToBool(String name, Boolean defaultValue) {
         return Convert.toBool(getRequest().getParameter(name), defaultValue);
     }
 
     /**
-     * 鑾峰緱鎵�鏈夎姹傚弬鏁�
+     * 鑾峰彇鎵�鏈夎姹傚弬鏁帮紙浠� Map 鐨勫舰寮忚繑鍥烇級
      *
      * @param request 璇锋眰瀵硅薄{@link ServletRequest}
-     * @return Map
+     * @return 璇锋眰鍙傛暟鐨� Map锛岄敭涓哄弬鏁板悕锛屽�间负鍙傛暟鍊兼暟缁�
      */
     public static Map<String, String[]> getParams(ServletRequest request) {
         final Map<String, String[]> map = request.getParameterMap();
@@ -86,10 +107,10 @@
     }
 
     /**
-     * 鑾峰緱鎵�鏈夎姹傚弬鏁�
+     * 鑾峰彇鎵�鏈夎姹傚弬鏁帮紙浠� Map 鐨勫舰寮忚繑鍥烇紝鍊间负瀛楃涓插舰寮忕殑鎷兼帴锛�
      *
      * @param request 璇锋眰瀵硅薄{@link ServletRequest}
-     * @return Map
+     * @return 璇锋眰鍙傛暟鐨� Map锛岄敭涓哄弬鏁板悕锛屽�间负鎷兼帴鍚庣殑瀛楃涓�
      */
     public static Map<String, String> getParamMap(ServletRequest request) {
         Map<String, String> params = new HashMap<>();
@@ -100,7 +121,9 @@
     }
 
     /**
-     * 鑾峰彇request
+     * 鑾峰彇褰撳墠 HTTP 璇锋眰瀵硅薄
+     *
+     * @return 褰撳墠 HTTP 璇锋眰瀵硅薄
      */
     public static HttpServletRequest getRequest() {
         try {
@@ -111,7 +134,9 @@
     }
 
     /**
-     * 鑾峰彇response
+     * 鑾峰彇褰撳墠 HTTP 鍝嶅簲瀵硅薄
+     *
+     * @return 褰撳墠 HTTP 鍝嶅簲瀵硅薄
      */
     public static HttpServletResponse getResponse() {
         try {
@@ -122,12 +147,25 @@
     }
 
     /**
-     * 鑾峰彇session
+     * 鑾峰彇褰撳墠璇锋眰鐨� HttpSession 瀵硅薄
+     * <p>
+     * 濡傛灉褰撳墠璇锋眰宸茬粡鍏宠仈浜嗕竴涓細璇濓紙鍗冲凡缁忓瓨鍦ㄦ湁鏁堢殑 session ID锛夛紝
+     * 鍒欒繑鍥炶浼氳瘽瀵硅薄锛涘鏋滄病鏈夊叧鑱斾細璇濓紝鍒欎細鍒涘缓涓�涓柊鐨勪細璇濆璞″苟杩斿洖銆�
+     * <p>
+     * HttpSession 鐢ㄤ簬瀛樺偍浼氳瘽绾у埆鐨勬暟鎹紝濡傜敤鎴风櫥褰曚俊鎭�佽喘鐗╄溅鍐呭绛夛紝
+     * 鍙互鍦ㄥ涓姹備箣闂村叡浜細璇濇暟鎹�
+     *
+     * @return 褰撳墠璇锋眰鐨� HttpSession 瀵硅薄
      */
     public static HttpSession getSession() {
         return getRequest().getSession();
     }
 
+    /**
+     * 鑾峰彇褰撳墠璇锋眰鐨勮姹傚睘鎬�
+     *
+     * @return {@link ServletRequestAttributes} 璇锋眰灞炴�у璞�
+     */
     public static ServletRequestAttributes getRequestAttributes() {
         try {
             RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
@@ -137,6 +175,13 @@
         }
     }
 
+    /**
+     * 鑾峰彇鎸囧畾璇锋眰澶寸殑鍊硷紝濡傛灉澶撮儴涓虹┖鍒欒繑鍥炵┖瀛楃涓�
+     *
+     * @param request 璇锋眰瀵硅薄
+     * @param name    澶撮儴鍚嶇О
+     * @return 澶撮儴鍊�
+     */
     public static String getHeader(HttpServletRequest request, String name) {
         String value = request.getHeader(name);
         if (StringUtils.isEmpty(value)) {
@@ -145,6 +190,12 @@
         return urlDecode(value);
     }
 
+    /**
+     * 鑾峰彇鎵�鏈夎姹傚ご鐨� Map锛岄敭涓哄ご閮ㄥ悕绉帮紝鍊间负澶撮儴鍊�
+     *
+     * @param request 璇锋眰瀵硅薄
+     * @return 璇锋眰澶寸殑 Map
+     */
     public static Map<String, String> getHeaders(HttpServletRequest request) {
         Map<String, String> map = new LinkedCaseInsensitiveMap<>();
         Enumeration<String> enumeration = request.getHeaderNames();
@@ -159,7 +210,7 @@
     }
 
     /**
-     * 灏嗗瓧绗︿覆娓叉煋鍒板鎴风
+     * 灏嗗瓧绗︿覆娓叉煋鍒板鎴风锛堜互 JSON 鏍煎紡杩斿洖锛�
      *
      * @param response 娓叉煋瀵硅薄
      * @param string   寰呮覆鏌撶殑瀛楃涓�
@@ -176,37 +227,47 @@
     }
 
     /**
-     * 鏄惁鏄疉jax寮傛璇锋眰
+     * 鍒ゆ柇褰撳墠璇锋眰鏄惁涓� Ajax 寮傛璇锋眰
      *
-     * @param request
+     * @param request 璇锋眰瀵硅薄
+     * @return 鏄惁涓� Ajax 璇锋眰
      */
     public static boolean isAjaxRequest(HttpServletRequest request) {
 
+        // 鍒ゆ柇 Accept 澶撮儴鏄惁鍖呭惈 application/json
         String accept = request.getHeader("accept");
         if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) {
             return true;
         }
 
+        // 鍒ゆ柇 X-Requested-With 澶撮儴鏄惁鍖呭惈 XMLHttpRequest
         String xRequestedWith = request.getHeader("X-Requested-With");
         if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) {
             return true;
         }
 
+        // 鍒ゆ柇 URI 鍚庣紑鏄惁涓� .json 鎴� .xml
         String uri = request.getRequestURI();
         if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) {
             return true;
         }
 
+        // 鍒ゆ柇璇锋眰鍙傛暟 __ajax 鏄惁涓� json 鎴� xml
         String ajax = request.getParameter("__ajax");
         return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml");
     }
 
+    /**
+     * 鑾峰彇瀹㈡埛绔� IP 鍦板潃
+     *
+     * @return 瀹㈡埛绔� IP 鍦板潃
+     */
     public static String getClientIP() {
         return getClientIP(getRequest());
     }
 
     /**
-     * 鍐呭缂栫爜
+     * 瀵瑰唴瀹硅繘琛� URL 缂栫爜
      *
      * @param str 鍐呭
      * @return 缂栫爜鍚庣殑鍐呭
@@ -216,7 +277,7 @@
     }
 
     /**
-     * 鍐呭瑙g爜
+     * 瀵瑰唴瀹硅繘琛� URL 瑙g爜
      *
      * @param str 鍐呭
      * @return 瑙g爜鍚庣殑鍐呭
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java
index dd6ebb1..0363ad4 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java
@@ -4,8 +4,6 @@
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.StrUtil;
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
 import org.springframework.util.AntPathMatcher;
 
 import java.util.*;
@@ -17,12 +15,15 @@
  *
  * @author Lion Li
  */
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class StringUtils extends org.apache.commons.lang3.StringUtils {
 
     public static final String SEPARATOR = ",";
 
     public static final String SLASH = "/";
+
+    @Deprecated
+    private StringUtils() {
+    }
 
     /**
      * 鑾峰彇鍙傛暟涓嶄负绌哄��
@@ -317,7 +318,25 @@
             .stream()
             .filter(Objects::nonNull)
             .map(mapper)
+            .filter(Objects::nonNull)
             .collect(Collectors.toList());
     }
 
+    /**
+     * 涓嶅尯鍒嗗ぇ灏忓啓妫�鏌� CharSequence 鏄惁浠ユ寚瀹氱殑鍓嶇紑寮�澶淬��
+     *
+     * @param str     瑕佹鏌ョ殑 CharSequence 鍙兘涓� null
+     * @param prefixs 瑕佹煡鎵剧殑鍓嶇紑鍙兘涓� null
+     * @return 鏄惁鍖呭惈
+     */
+    public static boolean startWithAnyIgnoreCase(CharSequence str, CharSequence... prefixs) {
+        // 鍒ゆ柇鏄惁鏄互鎸囧畾瀛楃涓插紑澶�
+        for (CharSequence prefix : prefixs) {
+            if (StringUtils.startsWithIgnoreCase(str, prefix)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java
index ae6cfa3..82ea5ca 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java
@@ -14,18 +14,6 @@
 @Slf4j
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class Threads {
-
-    /**
-     * sleep绛夊緟,鍗曚綅涓烘绉�
-     */
-    public static void sleep(long milliseconds) {
-        try {
-            Thread.sleep(milliseconds);
-        } catch (InterruptedException e) {
-            return;
-        }
-    }
-
     /**
      * 鍋滄绾跨▼姹�
      * 鍏堜娇鐢╯hutdown, 鍋滄鎺ユ敹鏂颁换鍔″苟灏濊瘯瀹屾垚鎵�鏈夊凡瀛樺湪浠诲姟.
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java
index d0163e6..2ab42cb 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java
@@ -5,11 +5,13 @@
 import cn.hutool.core.lang.tree.TreeNodeConfig;
 import cn.hutool.core.lang.tree.TreeUtil;
 import cn.hutool.core.lang.tree.parser.NodeParser;
-import org.dromara.common.core.utils.reflect.ReflectUtils;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
 
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * 鎵╁睍 hutool TreeUtil 灏佽绯荤粺鏍戞瀯寤�
@@ -24,12 +26,71 @@
      */
     public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label");
 
+    /**
+     * 鏋勫缓鏍戝舰缁撴瀯
+     *
+     * @param <T>        杈撳叆鑺傜偣鐨勭被鍨�
+     * @param <K>        鑺傜偣ID鐨勭被鍨�
+     * @param list       鑺傜偣鍒楄〃锛屽叾涓寘鍚簡瑕佹瀯寤烘爲褰㈢粨鏋勭殑鎵�鏈夎妭鐐�
+     * @param nodeParser 瑙f瀽鍣紝鐢ㄤ簬灏嗚緭鍏ヨ妭鐐硅浆鎹负鏍戣妭鐐�
+     * @return 鏋勫缓濂界殑鏍戝舰缁撴瀯鍒楄〃
+     */
     public static <T, K> List<Tree<K>> build(List<T> list, NodeParser<T, K> nodeParser) {
         if (CollUtil.isEmpty(list)) {
-            return null;
+            return CollUtil.newArrayList();
         }
         K k = ReflectUtils.invokeGetter(list.get(0), "parentId");
         return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser);
     }
 
+    /**
+     * 鏋勫缓鏍戝舰缁撴瀯
+     *
+     * @param <T>        杈撳叆鑺傜偣鐨勭被鍨�
+     * @param <K>        鑺傜偣ID鐨勭被鍨�
+     * @param parentId   椤剁骇鑺傜偣
+     * @param list       鑺傜偣鍒楄〃锛屽叾涓寘鍚簡瑕佹瀯寤烘爲褰㈢粨鏋勭殑鎵�鏈夎妭鐐�
+     * @param nodeParser 瑙f瀽鍣紝鐢ㄤ簬灏嗚緭鍏ヨ妭鐐硅浆鎹负鏍戣妭鐐�
+     * @return 鏋勫缓濂界殑鏍戝舰缁撴瀯鍒楄〃
+     */
+    public static <T, K> List<Tree<K>> build(List<T> list, K parentId, NodeParser<T, K> nodeParser) {
+        if (CollUtil.isEmpty(list)) {
+            return CollUtil.newArrayList();
+        }
+        return TreeUtil.build(list, parentId, DEFAULT_CONFIG, nodeParser);
+    }
+
+    /**
+     * 鑾峰彇鑺傜偣鍒楄〃涓墍鏈夎妭鐐圭殑鍙跺瓙鑺傜偣
+     *
+     * @param <K>   鑺傜偣ID鐨勭被鍨�
+     * @param nodes 鑺傜偣鍒楄〃
+     * @return 鍖呭惈鎵�鏈夊彾瀛愯妭鐐圭殑鍒楄〃
+     */
+    public static <K> List<Tree<K>> getLeafNodes(List<Tree<K>> nodes) {
+        if (CollUtil.isEmpty(nodes)) {
+            return CollUtil.newArrayList();
+        }
+        return nodes.stream()
+            .flatMap(TreeBuildUtils::extractLeafNodes)
+            .collect(Collectors.toList());
+    }
+
+    /**
+     * 鑾峰彇鎸囧畾鑺傜偣涓嬬殑鎵�鏈夊彾瀛愯妭鐐�
+     *
+     * @param <K>  鑺傜偣ID鐨勭被鍨�
+     * @param node 瑕佹煡鎵惧彾瀛愯妭鐐圭殑鏍硅妭鐐�
+     * @return 鍖呭惈鎵�鏈夊彾瀛愯妭鐐圭殑鍒楄〃
+     */
+    private static <K> Stream<Tree<K>> extractLeafNodes(Tree<K> node) {
+        if (!node.hasChild()) {
+            return Stream.of(node);
+        } else {
+            // 閫掑綊璋冪敤锛岃幏鍙栨墍鏈夊瓙鑺傜偣鐨勫彾瀛愯妭鐐�
+            return node.getChildren().stream()
+                .flatMap(TreeBuildUtils::extractLeafNodes);
+        }
+    }
+
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java
index b8b12d4..6dde129 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java
@@ -21,7 +21,8 @@
      */
     public static String extractFromString(String input, String regex, String defaultInput) {
         try {
-            return ReUtil.get(regex, input, 1);
+            String str = ReUtil.get(regex, input, 1);
+            return str == null ? defaultInput : str;
         } catch (Exception e) {
             return defaultInput;
         }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java
index 3e109b2..1020c81 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java
@@ -15,7 +15,7 @@
     /**
      * 瀹氫箟甯哥敤鐨� sql鍏抽敭瀛�
      */
-    public static final String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
+    public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
 
     /**
      * 浠呮敮鎸佸瓧姣嶃�佹暟瀛椼�佷笅鍒掔嚎銆佺┖鏍笺�侀�楀彿銆佸皬鏁扮偣锛堟敮鎸佸涓瓧娈垫帓搴忥級
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java
new file mode 100644
index 0000000..d4f1c3d
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java
@@ -0,0 +1,48 @@
+package org.dromara.common.core.validate.enumd;
+
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.*;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * 鑷畾涔夋灇涓炬牎楠�
+ *
+ * @author 绉嬭緸鏈瘨
+ * @date 2024-12-09
+ */
+@Documented
+@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+@Retention(RUNTIME)
+@Repeatable(EnumPattern.List.class) // 鍏佽鍦ㄥ悓涓�鍏冪礌涓婂娆′娇鐢ㄨ娉ㄨВ
+@Constraint(validatedBy = {EnumPatternValidator.class})
+public @interface EnumPattern {
+
+    /**
+     * 闇�瑕佹牎楠岀殑鏋氫妇绫诲瀷
+     */
+    Class<? extends Enum<?>> type();
+
+    /**
+     * 鏋氫妇绫诲瀷鏍¢獙鍊煎瓧娈靛悕绉�
+     * 闇�纭繚璇ュ瓧娈靛疄鐜颁簡 getter 鏂规硶
+     */
+    String fieldName();
+
+    String message() default "杈撳叆鍊间笉鍦ㄦ灇涓捐寖鍥村唴";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+
+    @Documented
+    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
+    @Retention(RUNTIME)
+    @interface List {
+        EnumPattern[] value();
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java
new file mode 100644
index 0000000..6cfa11a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java
@@ -0,0 +1,37 @@
+package org.dromara.common.core.validate.enumd;
+
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+
+/**
+ * 鑷畾涔夋灇涓炬牎楠屾敞瑙e疄鐜�
+ *
+ * @author 绉嬭緸鏈瘨
+ * @date 2024-12-09
+ */
+public class EnumPatternValidator implements ConstraintValidator<EnumPattern, String> {
+
+    private EnumPattern annotation;;
+
+    @Override
+    public void initialize(EnumPattern annotation) {
+        ConstraintValidator.super.initialize(annotation);
+        this.annotation = annotation;
+    }
+
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
+        if (StringUtils.isNotBlank(value)) {
+            String fieldName = annotation.fieldName();
+            for (Object e : annotation.type().getEnumConstants()) {
+                if (value.equals(ReflectUtils.invokeGetter(e, fieldName))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java
index a6d3cf9..b5f194d 100644
--- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java
@@ -1,11 +1,11 @@
 package org.dromara.common.encrypt.core;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ReflectUtil;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.ibatis.io.Resources;
+import org.dromara.common.core.utils.ObjectUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.encrypt.annotation.EncryptField;
 import org.springframework.context.ConfigurableApplicationContext;
@@ -17,7 +17,10 @@
 import org.springframework.util.ClassUtils;
 
 import java.lang.reflect.Field;
-import java.util.*;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
@@ -34,7 +37,7 @@
     /**
      * 缂撳瓨鍔犲瘑鍣�
      */
-    Map<EncryptContext, IEncryptor> encryptorMap = new ConcurrentHashMap<>();
+    Map<Integer, IEncryptor> encryptorMap = new ConcurrentHashMap<>();
 
     /**
      * 绫诲姞瀵嗗瓧娈电紦瀛�
@@ -55,10 +58,7 @@
      * 鑾峰彇绫诲姞瀵嗗瓧娈电紦瀛�
      */
     public Set<Field> getFieldCache(Class<?> sourceClazz) {
-        if (ObjectUtil.isNotNull(fieldCache)) {
-            return fieldCache.get(sourceClazz);
-        }
-        return null;
+        return ObjectUtils.notNullGetter(fieldCache, f -> f.get(sourceClazz));
     }
 
     /**
@@ -67,11 +67,12 @@
      * @param encryptContext 鍔犲瘑鎵ц鑰呴渶瑕佺殑鐩稿叧閰嶇疆鍙傛暟
      */
     public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) {
-        if (encryptorMap.containsKey(encryptContext)) {
-            return encryptorMap.get(encryptContext);
+        int key = encryptContext.hashCode();
+        if (encryptorMap.containsKey(key)) {
+            return encryptorMap.get(key);
         }
         IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext);
-        encryptorMap.put(encryptContext, encryptor);
+        encryptorMap.put(key, encryptor);
         return encryptor;
     }
 
@@ -81,7 +82,7 @@
      * @param encryptContext 鍔犲瘑鎵ц鑰呴渶瑕佺殑鐩稿叧閰嶇疆鍙傛暟
      */
     public void removeEncryptor(EncryptContext encryptContext) {
-        this.encryptorMap.remove(encryptContext);
+        this.encryptorMap.remove(encryptContext.hashCode());
     }
 
     /**
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java
index 9835132..79d58da 100644
--- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java
@@ -99,7 +99,7 @@
                 }
             }
         } catch (Exception e) {
-            throw new RuntimeException(e);
+            return null;
         }
         return null;
     }
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java
index 8e34843..2a096ee 100644
--- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java
@@ -19,10 +19,12 @@
  * @author 鑰侀┈
  */
 public class EncryptUtils {
+
     /**
      * 鍏挜
      */
     public static final String PUBLIC_KEY = "publicKey";
+
     /**
      * 绉侀挜
      */
@@ -51,7 +53,7 @@
     /**
      * AES鍔犲瘑
      *
-     * @param data     寰呰В瀵嗘暟鎹�
+     * @param data     寰呭姞瀵嗘暟鎹�
      * @param password 绉橀挜瀛楃涓�
      * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Base64缂栫爜
      */
@@ -70,7 +72,7 @@
     /**
      * AES鍔犲瘑
      *
-     * @param data     寰呰В瀵嗘暟鎹�
+     * @param data     寰呭姞瀵嗘暟鎹�
      * @param password 绉橀挜瀛楃涓�
      * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Hex缂栫爜
      */
@@ -208,7 +210,7 @@
     /**
      * sm2绉侀挜瑙e瘑
      *
-     * @param data       寰呭姞瀵嗘暟鎹�
+     * @param data       寰呰В瀵嗘暟鎹�
      * @param privateKey 绉侀挜
      * @return 瑙e瘑鍚庡瓧绗︿覆
      */
@@ -266,7 +268,7 @@
     /**
      * rsa绉侀挜瑙e瘑
      *
-     * @param data       寰呭姞瀵嗘暟鎹�
+     * @param data       寰呰В瀵嗘暟鎹�
      * @param privateKey 绉侀挜
      * @return 瑙e瘑鍚庡瓧绗︿覆
      */
diff --git a/ruoyi-common/ruoyi-common-excel/pom.xml b/ruoyi-common/ruoyi-common-excel/pom.xml
index 14b9410..dd4a5ee 100644
--- a/ruoyi-common/ruoyi-common-excel/pom.xml
+++ b/ruoyi-common/ruoyi-common-excel/pom.xml
@@ -25,11 +25,6 @@
             <groupId>com.alibaba</groupId>
             <artifactId>easyexcel</artifactId>
         </dependency>
-        <dependency>
-            <artifactId>commons-compress</artifactId>
-            <groupId>org.apache.commons</groupId>
-            <version>1.26.2</version>
-        </dependency>
     </dependencies>
 
 </project>
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java
new file mode 100644
index 0000000..f358afc
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java
@@ -0,0 +1,24 @@
+package org.dromara.common.excel.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 鎵规敞
+ * @author guzhouyanyu
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelNotation {
+
+    /**
+     * col index
+     */
+    int index() default -1;
+    /**
+     * 鎵规敞鍐呭
+     */
+    String value() default "";
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java
new file mode 100644
index 0000000..15784e1
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java
@@ -0,0 +1,26 @@
+package org.dromara.common.excel.annotation;
+
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 鏄惁蹇呭~
+ * @author guzhouyanyu
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelRequired {
+
+    /**
+     * col index
+     */
+    int index() default -1;
+    /**
+     * 瀛椾綋棰滆壊
+     */
+    IndexedColors fontColor() default IndexedColors.RED;
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
index b3f68ed..32fee7a 100644
--- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
@@ -55,6 +55,7 @@
      * 涓嬫媺鍙�夐」
      */
     private final List<DropDownOptions> dropDownOptions;
+    private final DictService dictService;
     /**
      * 褰撳墠鍗曢�夎繘搴�
      */
@@ -63,7 +64,6 @@
      * 褰撳墠鑱斿姩閫夋嫨杩涘害
      */
     private int currentLinkedOptionsSheetIndex;
-    private final DictService dictService;
 
     public ExcelDownHandler(List<DropDownOptions> options) {
         this.dropDownOptions = options;
@@ -139,8 +139,8 @@
             } else if (everyOptions.getOptions().size() > 10) {
                 // 褰撲竴绾ч�夐」鍙傛暟涓暟澶т簬10锛屼娇鐢ㄩ澶栬〃鐨勫舰寮�
                 dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions());
-            } else if (everyOptions.getOptions().size() != 0) {
-                // 褰撲竴绾ч�夐」涓暟涓嶄负绌猴紝浣跨敤榛樿褰㈠紡
+            } else {
+                // 鍚﹀垯浣跨敤榛樿褰㈠紡
                 dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions());
             }
         });
@@ -171,9 +171,23 @@
         Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName));
         // 灏嗕笅鎷夎〃闅愯棌
         workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true);
-        // 瀹屽杽妯悜鐨勪竴绾ч�夐」鏁版嵁琛�
+        // 閫夐」鏁版嵁
         List<String> firstOptions = options.getOptions();
         Map<String, List<String>> secoundOptionsMap = options.getNextOptions();
+
+        // 閲囩敤鎸夎濉厖鏁版嵁鐨勬柟寮忥紝閬垮厤EasyExcel鍑虹幇鏁版嵁鏃犳硶鍐欏叆鐨勯棶棰�
+        // Attempting to write a row in the range that is already written to disk
+
+        // 浣跨敤ArrayList璁拌浇鏁版嵁锛岄槻姝贡搴�
+        List<String> columnNames = new ArrayList<>();
+        // 鍐欏叆绗竴琛岋紝鍗崇涓�绾х殑鏁版嵁
+        Row firstRow = linkedOptionsDataSheet.createRow(0);
+        for (int columnIndex = 0; columnIndex < firstOptions.size(); columnIndex++) {
+            String columnName = firstOptions.get(columnIndex);
+            firstRow.createCell(columnIndex)
+                .setCellValue(columnName);
+            columnNames.add(columnName);
+        }
 
         // 鍒涘缓鍚嶇О绠$悊鍣�
         Name name = workbook.createName();
@@ -190,28 +204,12 @@
         // 璁剧疆鏁版嵁鏍¢獙涓哄簭鍒楁ā寮忥紝寮曠敤鐨勬槸鍚嶇О绠$悊鍣ㄤ腑鐨勫埆鍚�
         this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName));
 
-        for (int columIndex = 0; columIndex < firstOptions.size(); columIndex++) {
-            // 鍏堟彁鍙栦富琛ㄤ腑涓�绾т笅鎷夌殑鍒楀悕
+        // 鍒涘缓浜岀骇閫夐」鐨勫悕绉扮鐞嗗櫒
+        for (int columIndex = 0; columIndex < columnNames.size(); columIndex++) {
+            // 鍒楀悕
             String firstOptionsColumnName = getExcelColumnName(columIndex);
-            // 涓�娆″惊鐜槸姣忎竴涓竴绾ч�夐」
-            int finalI = columIndex;
-            // 鏈寰幆鐨勪竴绾ч�夐」鍊�
-            String thisFirstOptionsValue = firstOptions.get(columIndex);
-            // 鍒涘缓绗竴琛岀殑鏁版嵁
-            Optional.ofNullable(linkedOptionsDataSheet.getRow(0))
-                // 濡傛灉涓嶅瓨鍦ㄥ垯鍒涘缓绗竴琛�
-                .orElseGet(() -> linkedOptionsDataSheet.createRow(finalI))
-                // 绗竴琛屽綋鍓嶅垪
-                .createCell(columIndex)
-                // 璁剧疆鍊间负褰撳墠涓�绾ч�夐」鍊�
-                .setCellValue(thisFirstOptionsValue);
-
-            // 绗簩琛屽紑濮嬶紝璁剧疆绗簩绾у埆閫夐」鍙傛暟
-            List<String> secondOptions = secoundOptionsMap.get(thisFirstOptionsValue);
-            if (CollUtil.isEmpty(secondOptions)) {
-                // 蹇呴』淇濊瘉鑷冲皯鏈変竴涓叧鑱旈�夐」锛屽惁鍒欏皢瀵艰嚧Excel瑙f瀽閿欒
-                secondOptions = Collections.singletonList("鏆傛棤_0");
-            }
+            // 瀵瑰簲鐨勪竴绾у��
+            String thisFirstOptionsValue = columnNames.get(columIndex);
 
             // 浠ヨ涓�绾ч�夐」鍊煎垱寤哄瓙鍚嶇О绠$悊鍣�
             Name sonName = workbook.createName();
@@ -222,7 +220,9 @@
                 linkedOptionsSheetName,
                 firstOptionsColumnName,
                 firstOptionsColumnName,
-                secondOptions.size() + 1
+                // 浜岀骇閫夐」瀛樺湪鍒欒缃负(閫夐」涓暟+1)琛岋紝鍚﹀垯璁剧疆涓�2琛�
+                Math.max(Optional.ofNullable(secoundOptionsMap.get(thisFirstOptionsValue))
+                    .orElseGet(ArrayList::new).size(), 1) + 1
             );
             // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑寮曠敤浣嶇疆
             sonName.setRefersToFormula(sonFunction);
@@ -235,25 +235,51 @@
                 // 浜岀骇鍙兘涓昏〃姣忎竴琛岀殑姣忎竴鍒楁坊鍔犱簩绾ф牎楠�
                 markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction));
             }
+        }
 
-            for (int rowIndex = 0; rowIndex < secondOptions.size(); rowIndex++) {
-                // 浠庣浜岃寮�濮嬪~鍏呬簩绾ч�夐」
-                int finalRowIndex = rowIndex + 1;
-                int finalColumIndex = columIndex;
-
-                Row row = Optional.ofNullable(linkedOptionsDataSheet.getRow(finalRowIndex))
-                    // 娌℃湁鍒欏垱寤�
-                    .orElseGet(() -> linkedOptionsDataSheet.createRow(finalRowIndex));
-                Optional
-                    // 鍦ㄦ湰绾т竴绾ч�夐」鎵�鍦ㄧ殑鍒�
-                    .ofNullable(row.getCell(finalColumIndex))
-                    // 涓嶅瓨鍦ㄥ垯鍒涘缓
-                    .orElseGet(() -> row.createCell(finalColumIndex))
-                    // 璁剧疆浜岀骇閫夐」鍊�
-                    .setCellValue(secondOptions.get(rowIndex));
+        // 灏嗕簩绾ф暟鎹鐞嗕负鎸夎鍖哄垎
+        Map<Integer, List<String>> columnValueMap = new HashMap<>();
+        int currentRow = 1;
+        while (currentRow >= 0) {
+            boolean flag = false;
+            List<String> rowData = new ArrayList<>();
+            for (String columnName : columnNames) {
+                List<String> data = secoundOptionsMap.get(columnName);
+                if (CollUtil.isEmpty(data)) {
+                    // 娣诲姞绌哄瓧绗︿覆濉厖浣嶇疆
+                    rowData.add(" ");
+                    continue;
+                }
+                // 鍙栫涓�涓�
+                String str = data.get(0);
+                rowData.add(str);
+                // 閫氳繃绉婚櫎鐨勬柟寮忛伩鍏嶉噸澶�
+                data.remove(0);
+                // 璁剧疆鍙互缁х画
+                flag = true;
+            }
+            columnValueMap.put(currentRow, rowData);
+            // 鍙互缁х画锛屽垯澧炲姞琛屾暟锛屽惁鍒欑疆涓鸿礋鏁拌烦鍑哄惊鐜�
+            if (flag) {
+                currentRow++;
+            } else {
+                currentRow = -1;
             }
         }
 
+        // 濉厖绗簩绾ч�夐」鏁版嵁
+        columnValueMap.forEach((rowIndex, rowValues) -> {
+            Row row = linkedOptionsDataSheet.createRow(rowIndex);
+            for (int columnIndex = 0; columnIndex < rowValues.size(); columnIndex++) {
+                String rowValue = rowValues.get(columnIndex);
+                // 濉厖浣嶇疆鐨勯儴鍒嗕笉娓叉煋
+                if (StrUtil.isNotBlank(rowValue)) {
+                    row.createCell(columnIndex)
+                        .setCellValue(rowValue);
+                }
+            }
+        });
+
         currentLinkedOptionsSheetIndex++;
     }
 
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java
new file mode 100644
index 0000000..a2aa495
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java
@@ -0,0 +1,135 @@
+package org.dromara.common.excel.handler;
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.excel.metadata.data.DataFormatData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.util.StyleUtil;
+import com.alibaba.excel.write.handler.CellWriteHandler;
+import com.alibaba.excel.write.handler.SheetWriteHandler;
+import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
+import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
+import com.alibaba.excel.write.metadata.style.WriteCellStyle;
+import com.alibaba.excel.write.metadata.style.WriteFont;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+import org.dromara.common.excel.annotation.ExcelNotation;
+import org.dromara.common.excel.annotation.ExcelRequired;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 鎵规敞銆佸繀濉�
+ *
+ * @author guzhouyanyu
+ */
+public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler {
+
+    /**
+     * 鎵规敞
+     */
+    private final Map<Integer, String> notationMap;
+
+    /**
+     * 澶村垪瀛椾綋棰滆壊
+     */
+    private final Map<Integer, Short> headColumnMap;
+
+
+    public DataWriteHandler(Class<?> clazz) {
+        notationMap = getNotationMap(clazz);
+        headColumnMap = getRequiredMap(clazz);
+    }
+
+    @Override
+    public void afterCellDispose(CellWriteHandlerContext context) {
+        if (CollUtil.isEmpty(notationMap) && CollUtil.isEmpty(headColumnMap)) {
+            return;
+        }
+        WriteCellData<?> cellData = context.getFirstCellData();
+        WriteCellStyle writeCellStyle = cellData.getOrCreateStyle();
+
+        DataFormatData dataFormatData = new DataFormatData();
+        // 鍗曞厓鏍艰缃负鏂囨湰鏍煎紡
+        dataFormatData.setIndex((short) 49);
+        writeCellStyle.setDataFormatData(dataFormatData);
+
+        if (context.getHead()) {
+            Cell cell = context.getCell();
+            WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder();
+            Sheet sheet = writeSheetHolder.getSheet();
+            Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
+            Drawing<?> drawing = sheet.createDrawingPatriarch();
+            // 璁剧疆鏍囬瀛椾綋鏍峰紡
+            WriteFont headWriteFont = new WriteFont();
+            // 鍔犵矖
+            headWriteFont.setBold(true);
+            if (CollUtil.isNotEmpty(headColumnMap) && headColumnMap.containsKey(cell.getColumnIndex())) {
+                // 璁剧疆瀛椾綋棰滆壊
+                headWriteFont.setColor(headColumnMap.get(cell.getColumnIndex()));
+            }
+            writeCellStyle.setWriteFont(headWriteFont);
+            CellStyle cellStyle = StyleUtil.buildCellStyle(workbook, null, writeCellStyle);
+            cell.setCellStyle(cellStyle);
+
+            if (CollUtil.isNotEmpty(notationMap) && notationMap.containsKey(cell.getColumnIndex())) {
+                // 鎵规敞鍐呭
+                String notationContext = notationMap.get(cell.getColumnIndex());
+                // 鍒涘缓缁樺浘瀵硅薄
+                Comment comment = drawing.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), 0, (short) 5, 5));
+                comment.setString(new XSSFRichTextString(notationContext));
+                cell.setCellComment(comment);
+            }
+        }
+    }
+
+    /**
+     * 鑾峰彇蹇呭~鍒�
+     */
+    private static Map<Integer, Short> getRequiredMap(Class<?> clazz) {
+        Map<Integer, Short> requiredMap = new HashMap<>();
+        Field[] fields = clazz.getDeclaredFields();
+        // 妫�鏌� fields 鏁扮粍鏄惁涓虹┖
+        if (fields.length == 0) {
+            return requiredMap;
+        }
+        Field[] filteredFields = ReflectUtils.getFields(clazz, field -> !"serialVersionUID".equals(field.getName()));
+
+        for (int i = 0; i < filteredFields.length; i++) {
+            Field field = filteredFields[i];
+            if (!field.isAnnotationPresent(ExcelRequired.class)) {
+                continue;
+            }
+            ExcelRequired excelRequired = field.getAnnotation(ExcelRequired.class);
+            int columnIndex =  excelRequired.index() == -1 ? i : excelRequired.index();
+            requiredMap.put(columnIndex, excelRequired.fontColor().getIndex());
+        }
+        return requiredMap;
+    }
+
+    /**
+     * 鑾峰彇鎵规敞
+     */
+    private static Map<Integer, String> getNotationMap(Class<?> clazz) {
+        Map<Integer, String> notationMap = new HashMap<>();
+        Field[] fields = clazz.getDeclaredFields();
+        // 妫�鏌� fields 鏁扮粍鏄惁涓虹┖
+        if (fields.length == 0) {
+            return notationMap;
+        }
+        Field[] filteredFields = ReflectUtils.getFields(clazz, field -> !"serialVersionUID".equals(field.getName()));
+        for (int i = 0; i < filteredFields.length; i++) {
+            Field field = filteredFields[i];
+            if (!field.isAnnotationPresent(ExcelNotation.class)) {
+                continue;
+            }
+            ExcelNotation excelNotation = field.getAnnotation(ExcelNotation.class);
+            int columnIndex =  excelNotation.index() == -1 ? i : excelNotation.index();
+            notationMap.put(columnIndex, excelNotation.value());
+        }
+        return notationMap;
+    }
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java
index a6c14ad..b22e6f9 100644
--- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java
@@ -18,6 +18,7 @@
 import org.dromara.common.core.utils.file.FileUtils;
 import org.dromara.common.excel.convert.ExcelBigNumberConvert;
 import org.dromara.common.excel.core.*;
+import org.dromara.common.excel.handler.DataWriteHandler;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -191,6 +192,7 @@
             .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
             // 澶ф暟鍊艰嚜鍔ㄨ浆鎹� 闃叉澶辩湡
             .registerConverter(new ExcelBigNumberConvert())
+            .registerWriteHandler(new DataWriteHandler(clazz))
             .sheet(sheetName);
         if (merge) {
             // 鍚堝苟澶勭悊鍣�
@@ -211,7 +213,7 @@
      * @param data         妯℃澘闇�瑕佺殑鏁版嵁
      * @param response     鍝嶅簲浣�
      */
-    public static void exportTemplate(List<Object> data, String filename, String templatePath, HttpServletResponse response) {
+    public static <T> void exportTemplate(List<T> data, String filename, String templatePath, HttpServletResponse response) {
         try {
             resetResponse(filename, response);
             ServletOutputStream os = response.getOutputStream();
@@ -230,20 +232,21 @@
      * @param data         妯℃澘闇�瑕佺殑鏁版嵁
      * @param os           杈撳嚭娴�
      */
-    public static void exportTemplate(List<Object> data, String templatePath, OutputStream os) {
+    public static <T> void exportTemplate(List<T> data, String templatePath, OutputStream os) {
+        if (CollUtil.isEmpty(data)) {
+            throw new IllegalArgumentException("鏁版嵁涓虹┖");
+        }
         ClassPathResource templateResource = new ClassPathResource(templatePath);
         ExcelWriter excelWriter = EasyExcel.write(os)
             .withTemplate(templateResource.getStream())
             .autoCloseStream(false)
             // 澶ф暟鍊艰嚜鍔ㄨ浆鎹� 闃叉澶辩湡
             .registerConverter(new ExcelBigNumberConvert())
+            .registerWriteHandler(new DataWriteHandler(data.get(0).getClass()))
             .build();
         WriteSheet writeSheet = EasyExcel.writerSheet().build();
-        if (CollUtil.isEmpty(data)) {
-            throw new IllegalArgumentException("鏁版嵁涓虹┖");
-        }
         // 鍗曡〃澶氭暟鎹鍑� 妯℃澘鏍煎紡涓� {.灞炴�
-        for (Object d : data) {
+        for (T d : data) {
             excelWriter.fill(d, writeSheet);
         }
         excelWriter.finish();
@@ -299,6 +302,9 @@
      * @param os           杈撳嚭娴�
      */
     public static void exportTemplateMultiList(Map<String, Object> data, String templatePath, OutputStream os) {
+        if (CollUtil.isEmpty(data)) {
+            throw new IllegalArgumentException("鏁版嵁涓虹┖");
+        }
         ClassPathResource templateResource = new ClassPathResource(templatePath);
         ExcelWriter excelWriter = EasyExcel.write(os)
             .withTemplate(templateResource.getStream())
@@ -307,9 +313,6 @@
             .registerConverter(new ExcelBigNumberConvert())
             .build();
         WriteSheet writeSheet = EasyExcel.writerSheet().build();
-        if (CollUtil.isEmpty(data)) {
-            throw new IllegalArgumentException("鏁版嵁涓虹┖");
-        }
         for (Map.Entry<String, Object> map : data.entrySet()) {
             // 璁剧疆鍒楄〃鍚庣画杩樻湁鏁版嵁
             FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
@@ -333,6 +336,9 @@
      * @param os           杈撳嚭娴�
      */
     public static void exportTemplateMultiSheet(List<Map<String, Object>> data, String templatePath, OutputStream os) {
+        if (CollUtil.isEmpty(data)) {
+            throw new IllegalArgumentException("鏁版嵁涓虹┖");
+        }
         ClassPathResource templateResource = new ClassPathResource(templatePath);
         ExcelWriter excelWriter = EasyExcel.write(os)
             .withTemplate(templateResource.getStream())
@@ -340,9 +346,6 @@
             // 澶ф暟鍊艰嚜鍔ㄨ浆鎹� 闃叉澶辩湡
             .registerConverter(new ExcelBigNumberConvert())
             .build();
-        if (CollUtil.isEmpty(data)) {
-            throw new IllegalArgumentException("鏁版嵁涓虹┖");
-        }
         for (int i = 0; i < data.size(); i++) {
             WriteSheet writeSheet = EasyExcel.writerSheet(i).build();
             for (Map.Entry<String, Object> map : data.get(i).entrySet()) {
diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java
index f2a7c2d..8752353 100644
--- a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java
+++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java
@@ -32,7 +32,7 @@
 
     @Override
     public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException {
-        // 瓒呭嚭鑼冨洿 搴忓垪鍖栦綅瀛楃涓�
+        // 瓒呭嚭鑼冨洿 搴忓垪鍖栦负瀛楃涓�
         if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {
             super.serialize(value, gen, provider);
         } else {
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
index cdbd00f..8ab2719 100644
--- a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
+++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
@@ -100,7 +100,7 @@
 
             if (e != null) {
                 operLog.setStatus(BusinessStatus.FAIL.ordinal());
-                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
+                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 3800));
             }
             // 璁剧疆鏂规硶鍚嶇О
             String className = joinPoint.getTarget().getClass().getName();
@@ -113,13 +113,12 @@
             // 璁剧疆娑堣�楁椂闂�
             StopWatch stopWatch = KEY_CACHE.get();
             stopWatch.stop();
-            operLog.setCostTime(stopWatch.getTime());
+            operLog.setCostTime(stopWatch.getDuration().toMillis());
             // 鍙戝竷浜嬩欢淇濆瓨鏁版嵁搴�
             SpringUtils.context().publishEvent(operLog);
         } catch (Exception exp) {
             // 璁板綍鏈湴寮傚父鏃ュ織
             log.error("寮傚父淇℃伅:{}", exp.getMessage());
-            exp.printStackTrace();
         } finally {
             KEY_CACHE.remove();
         }
@@ -146,7 +145,7 @@
         }
         // 鏄惁闇�瑕佷繚瀛榬esponse锛屽弬鏁板拰鍊�
         if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) {
-            operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000));
+            operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 3800));
         }
     }
 
@@ -159,14 +158,13 @@
     private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception {
         Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
         String requestMethod = operLog.getRequestMethod();
-        if (MapUtil.isEmpty(paramsMap)
-                && HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
+        if (MapUtil.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())) {
             String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
-            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
+            operLog.setOperParam(StringUtils.substring(params, 0, 3800));
         } else {
             MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES);
             MapUtil.removeAny(paramsMap, excludeParamNames);
-            operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 2000));
+            operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 3800));
         }
     }
 
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java
index d0e78a2..e44aa3d 100644
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java
+++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java
@@ -43,7 +43,13 @@
     private String pass;
 
     /**
-     * 鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯
+     * 鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯<br>
+     * 鍙戜欢浜哄彲浠ユ槸浠ヤ笅褰㈠紡锛�
+     *
+     * <pre>
+     * 1. user@xxx.xx
+     * 2.  name &lt;user@xxx.xx&gt;
+     * </pre>
      */
     private String from;
 
diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml
index a58064a..d79ba28 100644
--- a/ruoyi-common/ruoyi-common-mybatis/pom.xml
+++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml
@@ -37,6 +37,11 @@
             <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-jsqlparser</artifactId>
+        </dependency>
+
         <!-- sql鎬ц兘鍒嗘瀽鎻掍欢 -->
         <dependency>
             <groupId>p6spy</groupId>
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java
new file mode 100644
index 0000000..1c83cc3
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java
@@ -0,0 +1,50 @@
+package org.dromara.common.mybatis.aspect;
+
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.helper.DataPermissionHelper;
+
+/**
+ * 鏁版嵁鏉冮檺澶勭悊
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Aspect
+public class DataPermissionAspect {
+
+    /**
+     * 澶勭悊璇锋眰鍓嶆墽琛�
+     */
+    @Before(value = "@annotation(dataPermission)")
+    public void doBefore(JoinPoint joinPoint, DataPermission dataPermission) {
+        DataPermissionHelper.setPermission(dataPermission);
+    }
+
+    /**
+     * 澶勭悊瀹岃姹傚悗鎵ц
+     *
+     * @param joinPoint 鍒囩偣
+     */
+    @AfterReturning(pointcut = "@annotation(dataPermission)")
+    public void doAfterReturning(JoinPoint joinPoint, DataPermission dataPermission) {
+        DataPermissionHelper.removePermission();
+    }
+
+    /**
+     * 鎷︽埅寮傚父鎿嶄綔
+     *
+     * @param joinPoint 鍒囩偣
+     * @param e         寮傚父
+     */
+    @AfterThrowing(value = "@annotation(dataPermission)", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, DataPermission dataPermission, Exception e) {
+        DataPermissionHelper.removePermission();
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
index 0bc5b66..00c2691 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
@@ -2,6 +2,7 @@
 
 import cn.hutool.core.net.NetUtil;
 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler;
 import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
 import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
@@ -10,8 +11,10 @@
 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
 import org.dromara.common.core.factory.YmlPropertySourceFactory;
 import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.mybatis.aspect.DataPermissionAspect;
 import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler;
 import org.dromara.common.mybatis.handler.MybatisExceptionHandler;
+import org.dromara.common.mybatis.handler.PlusPostInitTableInfoHandler;
 import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.beans.BeansException;
@@ -55,6 +58,14 @@
     }
 
     /**
+     * 鏁版嵁鏉冮檺鍒囬潰澶勭悊鍣�
+     */
+    @Bean
+    public DataPermissionAspect dataPermissionAspect() {
+        return new DataPermissionAspect();
+    }
+
+    /**
      * 鍒嗛〉鎻掍欢锛岃嚜鍔ㄨ瘑鍒暟鎹簱绫诲瀷
      */
     public PaginationInnerInterceptor paginationInnerInterceptor() {
@@ -97,6 +108,14 @@
     }
 
     /**
+     * 鍒濆鍖栬〃瀵硅薄澶勭悊鍣�
+     */
+    @Bean
+    public PostInitTableInfoHandler postInitTableInfoHandler() {
+        return new PlusPostInitTableInfoHandler();
+    }
+
+    /**
      * PaginationInnerInterceptor 鍒嗛〉鎻掍欢锛岃嚜鍔ㄨ瘑鍒暟鎹簱绫诲瀷
      * https://baomidou.com/pages/97710a/
      * OptimisticLockerInnerInterceptor 涔愯閿佹彃浠�
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java
index 956be9f..24557ed 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java
@@ -18,9 +18,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.function.Function;
-import java.util.stream.Collectors;
 
 /**
  * 鑷畾涔� Mapper 鎺ュ彛, 瀹炵幇 鑷畾涔夋墿灞�
@@ -69,9 +67,7 @@
      * @return 鎻掑叆鎿嶄綔鏄惁鎴愬姛鐨勫竷灏斿��
      */
     default boolean insertBatch(Collection<T> entityList) {
-        Db.saveBatch(entityList);
-        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
-        return true;
+        return Db.saveBatch(entityList);
     }
 
     /**
@@ -81,9 +77,7 @@
      * @return 鏇存柊鎿嶄綔鏄惁鎴愬姛鐨勫竷灏斿��
      */
     default boolean updateBatchById(Collection<T> entityList) {
-        Db.updateBatchById(entityList);
-        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
-        return true;
+        return Db.updateBatchById(entityList);
     }
 
     /**
@@ -93,9 +87,7 @@
      * @return 鎻掑叆鎴栨洿鏂版搷浣滄槸鍚︽垚鍔熺殑甯冨皵鍊�
      */
     default boolean insertOrUpdateBatch(Collection<T> entityList) {
-        Db.saveOrUpdateBatch(entityList);
-        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
-        return true;
+        return Db.saveOrUpdateBatch(entityList);
     }
 
     /**
@@ -106,9 +98,7 @@
      * @return 鎻掑叆鎿嶄綔鏄惁鎴愬姛鐨勫竷灏斿��
      */
     default boolean insertBatch(Collection<T> entityList, int batchSize) {
-        Db.saveBatch(entityList, batchSize);
-        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
-        return true;
+        return Db.saveBatch(entityList, batchSize);
     }
 
     /**
@@ -119,9 +109,7 @@
      * @return 鏇存柊鎿嶄綔鏄惁鎴愬姛鐨勫竷灏斿��
      */
     default boolean updateBatchById(Collection<T> entityList, int batchSize) {
-        Db.updateBatchById(entityList, batchSize);
-        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
-        return true;
+        return Db.updateBatchById(entityList, batchSize);
     }
 
     /**
@@ -132,9 +120,7 @@
      * @return 鎻掑叆鎴栨洿鏂版搷浣滄槸鍚︽垚鍔熺殑甯冨皵鍊�
      */
     default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
-        Db.saveOrUpdateBatch(entityList, batchSize);
-        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
-        return true;
+        return Db.saveOrUpdateBatch(entityList, batchSize);
     }
 
     /**
@@ -169,8 +155,8 @@
      * @param idList 涓婚敭ID闆嗗悎
      * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒楄〃
      */
-    default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) {
-        return selectVoBatchIds(idList, this.currentVoClass());
+    default List<V> selectVoByIds(Collection<? extends Serializable> idList) {
+        return selectVoByIds(idList, this.currentVoClass());
     }
 
     /**
@@ -181,8 +167,8 @@
      * @param <C>     VO绫荤殑绫诲瀷
      * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒楄〃锛岀粡杩囪浆鎹负鎸囧畾鐨刅O绫诲悗杩斿洖
      */
-    default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) {
-        List<T> list = this.selectBatchIds(idList);
+    default <C> List<C> selectVoByIds(Collection<? extends Serializable> idList, Class<C> voClass) {
+        List<T> list = this.selectByIds(idList);
         if (CollUtil.isEmpty(list)) {
             return CollUtil.newArrayList();
         }
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
index 6ca9b27..1d5c3c9 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
@@ -4,6 +4,7 @@
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.metadata.OrderItem;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Data;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.StringUtils;
@@ -113,8 +114,14 @@
         return list;
     }
 
+    @JsonIgnore
     public Integer getFirstNum() {
         return (pageNum - 1) * pageSize;
     }
 
+    public PageQuery(Integer pageSize, Integer pageNum) {
+        this.pageSize = pageSize;
+        this.pageNum = pageNum;
+    }
+
 }
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java
index 8ecfb54..370f479 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java
@@ -50,6 +50,8 @@
     public TableDataInfo(List<T> list, long total) {
         this.rows = list;
         this.total = total;
+        this.code = HttpStatus.HTTP_OK;
+        this.msg = "鏌ヨ鎴愬姛";
     }
 
     /**
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
index 981bd42..02a5f48 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
@@ -48,7 +48,12 @@
     /**
      * 浠呮湰浜烘暟鎹潈闄�
      */
-    SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 ");
+    SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "),
+
+    /**
+     * 閮ㄩ棬鍙婁互涓嬫垨鏈汉鏁版嵁鏉冮檺
+     */
+    DEPT_AND_CHILD_OR_SELF("6", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} ) OR #{#userName} = #{#user.userId} ", " 1 = 0 ");
 
     private final String code;
 
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
index 7d44d26..fec2579 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
@@ -7,6 +7,7 @@
 import org.apache.ibatis.reflection.MetaObject;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.ObjectUtils;
 import org.dromara.common.mybatis.core.domain.BaseEntity;
 import org.dromara.common.satoken.utils.LoginHelper;
 
@@ -31,8 +32,7 @@
         try {
             if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
                 // 鑾峰彇褰撳墠鏃堕棿浣滀负鍒涘缓鏃堕棿鍜屾洿鏂版椂闂达紝濡傛灉鍒涘缓鏃堕棿涓嶄负绌猴紝鍒欎娇鐢ㄥ垱寤烘椂闂达紝鍚﹀垯浣跨敤褰撳墠鏃堕棿
-                Date current = ObjectUtil.isNotNull(baseEntity.getCreateTime())
-                    ? baseEntity.getCreateTime() : new Date();
+                Date current = ObjectUtils.notNull(baseEntity.getCreateTime(), new Date());
                 baseEntity.setCreateTime(current);
                 baseEntity.setUpdateTime(current);
 
@@ -44,8 +44,7 @@
                         // 濉厖鍒涘缓浜恒�佹洿鏂颁汉鍜屽垱寤洪儴闂ㄤ俊鎭�
                         baseEntity.setCreateBy(userId);
                         baseEntity.setUpdateBy(userId);
-                        baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept())
-                            ? baseEntity.getCreateDept() : loginUser.getDeptId());
+                        baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
                     }
                 }
             } else {
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
index 5ac74c3..a354707 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
@@ -3,11 +3,12 @@
 import cn.hutool.core.annotation.AnnotationUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
+import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import net.sf.jsqlparser.JSQLParserException;
 import net.sf.jsqlparser.expression.Expression;
-import net.sf.jsqlparser.expression.Parenthesis;
 import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
+import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
 import net.sf.jsqlparser.parser.CCJSqlParserUtil;
 import org.apache.ibatis.io.Resources;
 import org.dromara.common.core.domain.dto.RoleDTO;
@@ -28,19 +29,13 @@
 import org.springframework.core.io.support.ResourcePatternResolver;
 import org.springframework.core.type.ClassMetadata;
 import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
-import org.springframework.expression.BeanResolver;
-import org.springframework.expression.ExpressionParser;
-import org.springframework.expression.ParserContext;
+import org.springframework.expression.*;
 import org.springframework.expression.common.TemplateParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
 import org.springframework.expression.spel.support.StandardEvaluationContext;
 import org.springframework.util.ClassUtils;
 
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 
@@ -54,7 +49,7 @@
 public class PlusDataPermissionHandler {
 
     /**
-     * 鏂规硶鎴栫被(鍚嶇О) 涓� 娉ㄨВ鐨勬槧灏勫叧绯荤紦瀛�
+     * 绫诲悕绉颁笌娉ㄨВ鐨勬槧灏勫叧绯荤紦瀛�(鐢变簬aop鏃犳硶鎷︽埅mybatis鎺ュ彛绫讳笂鐨勬敞瑙� 鍙兘閫氳繃鍚姩棰勬壂鎻忕殑鏂瑰紡杩涜)
      */
     private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
 
@@ -86,27 +81,27 @@
      * @return 鏁版嵁杩囨护鏉′欢鐨� SQL 鐗囨
      */
     public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
-        // 鑾峰彇鏁版嵁鏉冮檺閰嶇疆
-        DataPermission dataPermission = getDataPermission(mappedStatementId);
-        // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
-        LoginUser currentUser = DataPermissionHelper.getVariable("user");
-        if (ObjectUtil.isNull(currentUser)) {
-            currentUser = LoginHelper.getLoginUser();
-            DataPermissionHelper.setVariable("user", currentUser);
-        }
-        // 濡傛灉鏄秴绾х鐞嗗憳鎴栫鎴风鐞嗗憳锛屽垯涓嶈繃婊ゆ暟鎹�
-        if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
-            return where;
-        }
-        // 鏋勯�犳暟鎹繃婊ゆ潯浠剁殑 SQL 鐗囨
-        String dataFilterSql = buildDataFilter(dataPermission, isSelect);
-        if (StringUtils.isBlank(dataFilterSql)) {
-            return where;
-        }
         try {
+            // 鑾峰彇鏁版嵁鏉冮檺閰嶇疆
+            DataPermission dataPermission = getDataPermission(mappedStatementId);
+            // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
+            LoginUser currentUser = DataPermissionHelper.getVariable("user");
+            if (ObjectUtil.isNull(currentUser)) {
+                currentUser = LoginHelper.getLoginUser();
+                DataPermissionHelper.setVariable("user", currentUser);
+            }
+            // 濡傛灉鏄秴绾х鐞嗗憳鎴栫鎴风鐞嗗憳锛屽垯涓嶈繃婊ゆ暟鎹�
+            if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
+                return where;
+            }
+            // 鏋勯�犳暟鎹繃婊ゆ潯浠剁殑 SQL 鐗囨
+            String dataFilterSql = buildDataFilter(dataPermission, isSelect);
+            if (StringUtils.isBlank(dataFilterSql)) {
+                return where;
+            }
             Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql);
             // 鏁版嵁鏉冮檺浣跨敤鍗曠嫭鐨勬嫭鍙� 闃叉涓庡叾浠栨潯浠跺啿绐�
-            Parenthesis parenthesis = new Parenthesis(expression);
+            ParenthesedExpressionList<Expression> parenthesis = new ParenthesedExpressionList<>(expression);
             if (ObjectUtil.isNotNull(where)) {
                 return new AndExpression(where, parenthesis);
             } else {
@@ -114,6 +109,8 @@
             }
         } catch (JSQLParserException e) {
             throw new ServiceException("鏁版嵁鏉冮檺瑙f瀽寮傚父 => " + e.getMessage());
+        } finally {
+            DataPermissionHelper.removePermission();
         }
     }
 
@@ -132,10 +129,33 @@
             joinStr = " " + dataPermission.joinStr() + " ";
         }
         LoginUser user = DataPermissionHelper.getVariable("user");
-        StandardEvaluationContext context = new StandardEvaluationContext();
+        Object defaultValue = "-1";
+        NullSafeStandardEvaluationContext context = new NullSafeStandardEvaluationContext(defaultValue);
+        context.addPropertyAccessor(new NullSafePropertyAccessor(context.getPropertyAccessors().get(0), defaultValue));
         context.setBeanResolver(beanResolver);
         DataPermissionHelper.getContext().forEach(context::setVariable);
         Set<String> conditions = new HashSet<>();
+        // 浼樺厛璁剧疆鍙橀噺
+        List<String> keys = new ArrayList<>();
+        Map<DataColumn, Boolean> ignoreMap = new HashMap<>();
+        for (DataColumn dataColumn : dataPermission.value()) {
+            if (dataColumn.key().length != dataColumn.value().length) {
+                throw new ServiceException("瑙掕壊鏁版嵁鑼冨洿寮傚父 => key涓巚alue闀垮害涓嶅尮閰�");
+            }
+            // 鍖呭惈鏉冮檺鏍囪瘑绗� 杩欑洿鎺ヨ烦杩�
+            if (StringUtils.isNotBlank(dataColumn.permission()) &&
+                CollUtil.contains(user.getMenuPermission(), dataColumn.permission())
+            ) {
+                ignoreMap.put(dataColumn, Boolean.TRUE);
+                continue;
+            }
+            // 璁剧疆娉ㄨВ鍙橀噺 key 涓鸿〃杈惧紡鍙橀噺 value 涓哄彉閲忓��
+            for (int i = 0; i < dataColumn.key().length; i++) {
+                context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
+            }
+            keys.addAll(Arrays.stream(dataColumn.key()).map(key -> "#" + key).toList());
+        }
+
         for (RoleDTO role : user.getRoles()) {
             user.setRoleId(role.getRoleId());
             // 鑾峰彇瑙掕壊鏉冮檺娉涘瀷
@@ -145,33 +165,30 @@
             }
             // 鍏ㄩ儴鏁版嵁鏉冮檺鐩存帴杩斿洖
             if (type == DataScopeType.ALL) {
-                return "";
+                return StringUtils.EMPTY;
             }
             boolean isSuccess = false;
             for (DataColumn dataColumn : dataPermission.value()) {
-                if (dataColumn.key().length != dataColumn.value().length) {
-                    throw new ServiceException("瑙掕壊鏁版嵁鑼冨洿寮傚父 => key涓巚alue闀垮害涓嶅尮閰�");
-                }
-                // 涓嶅寘鍚� key 鍙橀噺 鍒欎笉澶勭悊
-                if (!StringUtils.containsAny(type.getSqlTemplate(),
-                    Arrays.stream(dataColumn.key()).map(key -> "#" + key).toArray(String[]::new)
-                )) {
-                    continue;
-                }
                 // 鍖呭惈鏉冮檺鏍囪瘑绗� 杩欑洿鎺ヨ烦杩�
-                if (StringUtils.isNotBlank(dataColumn.permission()) &&
-                    CollUtil.contains(user.getMenuPermission(), dataColumn.permission())
-                ) {
+                if (ignoreMap.containsKey(dataColumn)) {
+                    // 淇澶氳鑹蹭笌鏉冮檺鏍囪瘑绗﹀叡鐢ㄩ棶棰� https://gitee.com/dromara/RuoYi-Vue-Plus/issues/IB4CS4
+                    conditions.add(joinStr + " 1 = 1 ");
                     isSuccess = true;
                     continue;
                 }
-                // 璁剧疆娉ㄨВ鍙橀噺 key 涓鸿〃杈惧紡鍙橀噺 value 涓哄彉閲忓��
-                for (int i = 0; i < dataColumn.key().length; i++) {
-                    context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
+                // 涓嶅寘鍚� key 鍙橀噺 鍒欎笉澶勭悊
+                if (!StringUtils.containsAny(type.getSqlTemplate(), keys.toArray(String[]::new))) {
+                    continue;
                 }
-
+                // 褰撳墠娉ㄨВ涓嶆弧瓒虫ā鏉� 涓嶅鐞�
+                if (!StringUtils.containsAny(type.getSqlTemplate(), dataColumn.key())) {
+                    continue;
+                }
+                // 蹇界暐鏁版嵁鏉冮檺 闃叉spel琛ㄨ揪寮忓唴鏈夊叾浠杝ql鏌ヨ瀵艰嚧姝诲惊鐜皟鐢�
+                String sql = DataPermissionHelper.ignore(() ->
+                    parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class)
+                );
                 // 瑙f瀽sql妯℃澘骞跺~鍏�
-                String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class);
                 conditions.add(joinStr + sql);
                 isSuccess = true;
             }
@@ -185,7 +202,7 @@
             String sql = StreamUtils.join(conditions, Function.identity(), "");
             return sql.substring(joinStr.length());
         }
-        return "";
+        return StringUtils.EMPTY;
     }
 
     /**
@@ -212,34 +229,14 @@
                     // 鑾峰彇璧勬簮瀵瑰簲鐨勭被瀵硅薄
                     Class<?> clazz = Resources.classForName(classMetadata.getClassName());
                     // 鏌ユ壘绫讳腑鐨勭壒瀹氭敞瑙�
-                    findAnnotation(clazz);
+                    if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
+                        DataPermission dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
+                        dataPermissionCacheMap.put(clazz.getName(), dataPermission);
+                    }
                 }
             }
         } catch (Exception e) {
             log.error("鍒濆鍖栨暟鎹畨鍏ㄧ紦瀛樻椂鍑洪敊:{}", e.getMessage());
-        }
-    }
-
-    /**
-     * 鍦ㄦ寚瀹氱殑绫讳腑鏌ユ壘鐗瑰畾鐨勬敞瑙� DataPermission锛屽苟灏嗗甫鏈夎繖涓敞瑙g殑鏂规硶鎴栫被瀛樺偍鍒� dataPermissionCacheMap 涓�
-     *
-     * @param clazz 瑕佹煡鎵剧殑绫�
-     */
-    private void findAnnotation(Class<?> clazz) {
-        DataPermission dataPermission;
-        for (Method method : clazz.getMethods()) {
-            if (method.isDefault() || method.isVarArgs()) {
-                continue;
-            }
-            String mappedStatementId = clazz.getName() + "." + method.getName();
-            if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) {
-                dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class);
-                dataPermissionCacheMap.put(mappedStatementId, dataPermission);
-            }
-        }
-        if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
-            dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
-            dataPermissionCacheMap.put(clazz.getName(), dataPermission);
         }
     }
 
@@ -250,9 +247,9 @@
      * @return DataPermission 娉ㄨВ瀵硅薄锛屽鏋滀笉瀛樺湪鍒欒繑鍥� null
      */
     public DataPermission getDataPermission(String mapperId) {
-        // 妫�鏌ョ紦瀛樹腑鏄惁鍖呭惈鏄犲皠璇彞 ID 瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄
-        if (dataPermissionCacheMap.containsKey(mapperId)) {
-            return dataPermissionCacheMap.get(mapperId);
+        // 妫�鏌ヤ笂涓嬫枃涓槸鍚﹀寘鍚槧灏勮鍙� ID 瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄
+        if (DataPermissionHelper.getPermission() != null) {
+            return DataPermissionHelper.getPermission();
         }
         // 濡傛灉缂撳瓨涓笉鍖呭惈鏄犲皠璇彞 ID 瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄锛屽垯灏濊瘯浣跨敤绫诲悕浣滀负閿煡鎵�
         String clazzName = mapperId.substring(0, mapperId.lastIndexOf("."));
@@ -271,4 +268,65 @@
     public boolean invalid(String mapperId) {
         return getDataPermission(mapperId) == null;
     }
+
+    /**
+     * 瀵规墍鏈塶ull鍙橀噺鎵句笉鍒扮殑鍙橀噺杩斿洖榛樿鍊�
+     */
+    @AllArgsConstructor
+    private static class NullSafeStandardEvaluationContext extends StandardEvaluationContext {
+
+        private final Object defaultValue;
+
+        @Override
+        public Object lookupVariable(String name) {
+            Object obj = super.lookupVariable(name);
+            // 濡傛灉璇诲彇鍒扮殑鍊兼槸 null锛屽垯杩斿洖榛樿鍊�
+            if (obj == null) {
+                return defaultValue;
+            }
+            return obj;
+        }
+
+    }
+
+    /**
+     * 瀵规墍鏈塶ull鍙橀噺鎵句笉鍒扮殑鍙橀噺杩斿洖榛樿鍊� 濮旀墭妯″紡 灏嗕笉闇�瑕佸鐞嗙殑鏂规硶濮旀墭缁欏師澶勭悊鍣�
+     */
+    @AllArgsConstructor
+    private static class NullSafePropertyAccessor implements PropertyAccessor {
+
+        private final PropertyAccessor delegate;
+        private final Object defaultValue;
+
+        @Override
+        public Class<?>[] getSpecificTargetClasses() {
+            return delegate.getSpecificTargetClasses();
+        }
+
+        @Override
+        public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
+            return delegate.canRead(context, target, name);
+        }
+
+        @Override
+        public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
+            TypedValue value = delegate.read(context, target, name);
+            // 濡傛灉璇诲彇鍒扮殑鍊兼槸 null锛屽垯杩斿洖榛樿鍊�
+            if (value.getValue() == null) {
+                return new TypedValue(defaultValue);
+            }
+            return value;
+        }
+
+        @Override
+        public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
+            return delegate.canWrite(context, target, name);
+        }
+
+        @Override
+        public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
+            delegate.write(context, target, name, newValue);
+        }
+    }
+
 }
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java
new file mode 100644
index 0000000..60ca20b
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java
@@ -0,0 +1,27 @@
+package org.dromara.common.mybatis.handler;
+
+import cn.hutool.core.convert.Convert;
+import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler;
+import com.baomidou.mybatisplus.core.metadata.TableInfo;
+import org.apache.ibatis.session.Configuration;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+
+/**
+ * 淇敼琛ㄤ俊鎭垵濮嬪寲鏂瑰紡
+ * 鐩墠鐢ㄤ簬鍏ㄥ眬淇敼鏄惁浣跨敤閫昏緫鍒犻櫎
+ *
+ * @author Lion Li
+ */
+public class PlusPostInitTableInfoHandler implements PostInitTableInfoHandler {
+
+    @Override
+    public void postTableInfo(TableInfo tableInfo, Configuration configuration) {
+        String flag = SpringUtils.getProperty("mybatis-plus.enableLogicDelete", "true");
+        // 鍙湁鍏抽棴鏃� 缁熶竴璁剧疆false 涓簍rue鏃秏p鑷姩鍒ゆ柇涓嶅鐞�
+        if (!Convert.toBool(flag)) {
+            ReflectUtils.setFieldValue(tableInfo, "withLogicDelete", false);
+        }
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
index a7cfee5..cd43c68 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
@@ -62,8 +62,8 @@
             // charindex(',100,' , ',0,100,101,') <> 0
             return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2);
         } else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
-            // (select position(',100,' in ',0,100,101,')) <> 0
-            return "(select position(',%s,' in ','||%s||',')) <> 0".formatted(var, var2);
+            // (select strpos(',0,100,101,' , ',100,')) <> 0
+            return "(select strpos(','||%s||',' , ',%s,')) <> 0".formatted(var2, var);
         } else if (dataBasyType == DataBaseType.ORACLE) {
             // instr(',0,100,101,' , ',100,') <> 0
             return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var);
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
index 932f173..f03d74e 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
@@ -9,6 +9,7 @@
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.dromara.common.core.utils.reflect.ReflectUtils;
+import org.dromara.common.mybatis.annotation.DataPermission;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -29,6 +30,33 @@
 
     private static final ThreadLocal<Stack<Integer>> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new);
 
+    private static final ThreadLocal<DataPermission> PERMISSION_CACHE = new ThreadLocal<>();
+
+    /**
+     * 鑾峰彇褰撳墠鎵цmapper鏉冮檺娉ㄨВ
+     *
+     * @return 杩斿洖褰撳墠鎵цmapper鏉冮檺娉ㄨВ
+     */
+    public static DataPermission getPermission() {
+        return PERMISSION_CACHE.get();
+    }
+
+    /**
+     * 璁剧疆褰撳墠鎵цmapper鏉冮檺娉ㄨВ
+     *
+     * @param dataPermission   鏁版嵁鏉冮檺娉ㄨВ
+     */
+    public static void setPermission(DataPermission dataPermission) {
+        PERMISSION_CACHE.set(dataPermission);
+    }
+
+    /**
+     * 鍒犻櫎褰撳墠鎵цmapper鏉冮檺娉ㄨВ
+     */
+    public static void removePermission() {
+        PERMISSION_CACHE.remove();
+    }
+
     /**
      * 浠庝笂涓嬫枃涓幏鍙栨寚瀹氶敭鐨勫彉閲忓�硷紝骞跺皢鍏惰浆鎹负鎸囧畾鐨勭被鍨�
      *
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
index f5dc637..14662e1 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
@@ -24,8 +24,8 @@
       # 涓婚敭绫诲瀷
       # AUTO 鑷 NONE 绌� INPUT 鐢ㄦ埛杈撳叆 ASSIGN_ID 闆姳 ASSIGN_UUID 鍞竴 UUID
       idType: ASSIGN_ID
-      # 閫昏緫宸插垹闄ゅ��(妗嗘灦琛ㄥ潎浣跨敤姝ゅ�� 绂佹闅忔剰淇敼)
-      logicDeleteValue: 2
+      # 閫昏緫宸插垹闄ゅ��(鍙寜闇�姹傞殢鎰忎慨鏀�)
+      logicDeleteValue: 1
       # 閫昏緫鏈垹闄ゅ��
       logicNotDeleteValue: 0
       insertStrategy: NOT_NULL
diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
index 5e300da..e3b20dd 100644
--- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
+++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
@@ -9,21 +9,18 @@
 import org.dromara.common.oss.constant.OssConstant;
 import org.dromara.common.oss.entity.UploadResult;
 import org.dromara.common.oss.enumd.AccessPolicyType;
-import org.dromara.common.oss.enumd.PolicyType;
 import org.dromara.common.oss.exception.OssException;
 import org.dromara.common.oss.properties.OssProperties;
 import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
 import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
 import software.amazon.awssdk.core.ResponseInputStream;
-import software.amazon.awssdk.core.async.AsyncRequestBody;
 import software.amazon.awssdk.core.async.AsyncResponseTransformer;
 import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody;
 import software.amazon.awssdk.regions.Region;
 import software.amazon.awssdk.services.s3.S3AsyncClient;
 import software.amazon.awssdk.services.s3.S3Configuration;
+import software.amazon.awssdk.services.s3.crt.S3CrtHttpConfiguration;
 import software.amazon.awssdk.services.s3.model.GetObjectResponse;
-import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
-import software.amazon.awssdk.services.s3.model.S3Exception;
 import software.amazon.awssdk.services.s3.presigner.S3Presigner;
 import software.amazon.awssdk.transfer.s3.S3TransferManager;
 import software.amazon.awssdk.transfer.s3.model.*;
@@ -35,6 +32,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.time.Duration;
+import java.util.function.Consumer;
 
 /**
  * S3 瀛樺偍鍗忚 鎵�鏈夊吋瀹筍3鍗忚鐨勪簯鍘傚晢鍧囨敮鎸�
@@ -83,10 +81,10 @@
             StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
                 AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
 
-            //MinIO 浣跨敤 HTTPS 闄愬埗浣跨敤鍩熷悕璁块棶锛岀珯鐐瑰~鍩熷悕銆傞渶瑕佸惎鐢ㄨ矾寰勬牱寮忚闂�
+            // MinIO 浣跨敤 HTTPS 闄愬埗浣跨敤鍩熷悕璁块棶锛岀珯鐐瑰~鍩熷悕銆傞渶瑕佸惎鐢ㄨ矾寰勬牱寮忚闂�
             boolean isStyle = !StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE);
 
-            //鍒涘缓AWS鍩轰簬 CRT 鐨� S3 瀹㈡埛绔�
+            // 鍒涘缓AWS鍩轰簬 CRT 鐨� S3 瀹㈡埛绔�
             this.client = S3AsyncClient.crtBuilder()
                 .credentialsProvider(credentialsProvider)
                 .endpointOverride(URI.create(getEndpoint()))
@@ -95,6 +93,9 @@
                 .minimumPartSizeInBytes(10 * 1025 * 1024L)
                 .checksumValidationEnabled(false)
                 .forcePathStyle(isStyle)
+                .httpConfiguration(S3CrtHttpConfiguration.builder()
+                    .connectionTimeout(Duration.ofSeconds(60)) // 璁剧疆杩炴帴瓒呮椂
+                    .build())
                 .build();
 
             //AWS鍩轰簬 CRT 鐨� S3 AsyncClient 瀹炰緥鐢ㄤ綔 S3 浼犺緭绠$悊鍣ㄧ殑搴曞眰瀹㈡埛绔�
@@ -112,50 +113,11 @@
                 .serviceConfiguration(config)
                 .build();
 
-            // 鍒涘缓瀛樺偍妗�
-            createBucket();
         } catch (Exception e) {
             if (e instanceof OssException) {
                 throw e;
             }
             throw new OssException("閰嶇疆閿欒! 璇锋鏌ョ郴缁熼厤缃�:[" + e.getMessage() + "]");
-        }
-    }
-
-    /**
-     * 鍚屾鍒涘缓瀛樺偍妗�
-     * 濡傛灉瀛樺偍妗朵笉瀛樺湪锛屼細杩涜鍒涘缓锛涘鏋滃瓨鍌ㄦ《瀛樺湪锛屼笉鎵ц浠讳綍鎿嶄綔
-     *
-     * @throws OssException 褰撳垱寤哄瓨鍌ㄦ《鏃跺彂鐢熷紓甯告椂鎶涘嚭
-     */
-    public void createBucket() {
-        String bucketName = properties.getBucketName();
-        try {
-            // 灏濊瘯鑾峰彇瀛樺偍妗剁殑淇℃伅
-            client.headBucket(
-                    x -> x.bucket(bucketName)
-                        .build())
-                .join();
-        } catch (Exception ex) {
-            if (ex.getCause() instanceof NoSuchBucketException) {
-                try {
-                    // 瀛樺偍妗朵笉瀛樺湪锛屽皾璇曞垱寤哄瓨鍌ㄦ《
-                    client.createBucket(
-                            x -> x.bucket(bucketName))
-                        .join();
-
-                    // 璁剧疆瀛樺偍妗剁殑璁块棶绛栫暐锛圔ucket Policy锛�
-                    client.putBucketPolicy(
-                            x -> x.bucket(bucketName)
-                                .policy(getPolicy(bucketName, getAccessPolicy().getPolicyType())))
-                        .join();
-                } catch (S3Exception e) {
-                    // 瀛樺偍妗跺垱寤烘垨绛栫暐璁剧疆澶辫触
-                    throw new OssException("鍒涘缓Bucket澶辫触, 璇锋牳瀵归厤缃俊鎭�:[" + e.getMessage() + "]");
-                }
-            } else {
-                throw new OssException("鍒ゆ柇Bucket鏄惁瀛樺湪澶辫触锛岃鏍稿閰嶇疆淇℃伅:[" + ex.getMessage() + "]");
-            }
         }
     }
 
@@ -178,7 +140,9 @@
                             .key(key)
                             .contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
                             .contentType(contentType)
-                            .acl(getAccessPolicy().getObjectCannedACL())
+                            // 鐢ㄤ簬璁剧疆瀵硅薄鐨勮闂帶鍒跺垪琛紙ACL锛夈�備笉鍚屼簯鍘傚晢瀵笰CL鐨勬敮鎸佸拰瀹炵幇鏂瑰紡鏈夋墍涓嶅悓锛�
+                            // 鍥犳鏍规嵁鍏蜂綋鐨勪簯鏈嶅姟鎻愪緵鍟嗭紝浣犲彲鑳介渶瑕佽繘琛屼笉鍚岀殑閰嶇疆锛堣嚜琛屽紑鍚紝闃块噷浜戞湁acl鏉冮檺閰嶇疆锛岃吘璁簯娌℃湁acl鏉冮檺閰嶇疆锛�
+                            //.acl(getAccessPolicy().getObjectCannedACL())
                             .build())
                     .addTransferListener(LoggingTransferListener.create())
                     .source(filePath).build());
@@ -215,7 +179,10 @@
         }
         try {
             // 鍒涘缓寮傛璇锋眰浣擄紙length濡傛灉涓虹┖浼氭姤閿欙級
-            BlockingInputStreamAsyncRequestBody body = AsyncRequestBody.forBlockingInputStream(length);
+            BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder()
+                .contentLength(length)
+                .subscribeTimeout(Duration.ofSeconds(30))
+                .build();
 
             // 浣跨敤 transferManager 杩涜涓婁紶
             Upload upload = transferManager.upload(
@@ -224,7 +191,9 @@
                         y -> y.bucket(properties.getBucketName())
                             .key(key)
                             .contentType(contentType)
-                            .acl(getAccessPolicy().getObjectCannedACL())
+                            // 鐢ㄤ簬璁剧疆瀵硅薄鐨勮闂帶鍒跺垪琛紙ACL锛夈�備笉鍚屼簯鍘傚晢瀵笰CL鐨勬敮鎸佸拰瀹炵幇鏂瑰紡鏈夋墍涓嶅悓锛�
+                            // 鍥犳鏍规嵁鍏蜂綋鐨勪簯鏈嶅姟鎻愪緵鍟嗭紝浣犲彲鑳介渶瑕佽繘琛屼笉鍚岀殑閰嶇疆锛堣嚜琛屽紑鍚紝闃块噷浜戞湁acl鏉冮檺閰嶇疆锛岃吘璁簯娌℃湁acl鏉冮檺閰嶇疆锛�
+                            //.acl(getAccessPolicy().getObjectCannedACL())
                             .build())
                     .build());
 
@@ -271,10 +240,11 @@
      *
      * @param key 鏂囦欢鍦� Amazon S3 涓殑瀵硅薄閿�
      * @param out 杈撳嚭娴�
+     * @param consumer 鑷畾涔夊鐞嗛�昏緫
      * @return 杈撳嚭娴佷腑鍐欏叆鐨勫瓧鑺傛暟锛堥暱搴︼級
      * @throws OssException 濡傛灉涓嬭浇澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
      */
-    public long download(String key, OutputStream out) {
+    public void download(String key, OutputStream out, Consumer<Long> consumer) {
         try {
             // 鏋勫缓涓嬭浇璇锋眰
             DownloadRequest<ResponseInputStream<GetObjectResponse>> downloadRequest = DownloadRequest.builder()
@@ -290,7 +260,10 @@
             Download<ResponseInputStream<GetObjectResponse>> responseFuture = transferManager.download(downloadRequest);
             // 杈撳嚭鍒版祦涓�
             try (ResponseInputStream<GetObjectResponse> responseStream = responseFuture.completionFuture().join().result()) { // auto-closeable stream
-                return responseStream.transferTo(out); // 闃诲璋冪敤绾跨▼ blocks the calling thread
+                if (consumer != null) {
+                    consumer.accept(responseStream.response().contentLength());
+                }
+                responseStream.transferTo(out); // 闃诲璋冪敤绾跨▼ blocks the calling thread
             }
         } catch (Exception e) {
             throw new OssException("鏂囦欢涓嬭浇澶辫触锛岄敊璇俊鎭�:[" + e.getMessage() + "]");
@@ -316,13 +289,13 @@
     /**
      * 鑾峰彇绉佹湁URL閾炬帴
      *
-     * @param objectKey 瀵硅薄KEY
-     * @param second    鎺堟潈鏃堕棿
+     * @param objectKey   瀵硅薄KEY
+     * @param expiredTime 閾炬帴鎺堟潈鍒版湡鏃堕棿
      */
-    public String getPrivateUrl(String objectKey, Integer second) {
+    public String getPrivateUrl(String objectKey, Duration expiredTime) {
         // 浣跨敤 AWS S3 棰勭鍚� URL 鐨勭敓鎴愬櫒 鑾峰彇瀵硅薄鐨勯绛惧悕 URL
         URL url = presigner.presignGetObject(
-                x -> x.signatureDuration(Duration.ofSeconds(second))
+                x -> x.signatureDuration(expiredTime)
                     .getObjectRequest(
                         y -> y.bucket(properties.getBucketName())
                             .key(objectKey)
@@ -340,8 +313,8 @@
      * @return UploadResult 鍖呭惈涓婁紶鍚庣殑鏂囦欢淇℃伅
      * @throws OssException 濡傛灉涓婁紶澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
      */
-    public UploadResult uploadSuffix(byte[] data, String suffix) {
-        return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), FileUtils.getMimeType(suffix));
+    public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) {
+        return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), contentType);
     }
 
     /**
@@ -353,8 +326,8 @@
      * @return UploadResult 鍖呭惈涓婁紶鍚庣殑鏂囦欢淇℃伅
      * @throws OssException 濡傛灉涓婁紶澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
      */
-    public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length) {
-        return upload(inputStream, getPath(properties.getPrefix(), suffix), length, FileUtils.getMimeType(suffix));
+    public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length, String contentType) {
+        return upload(inputStream, getPath(properties.getPrefix(), suffix), length, contentType);
     }
 
     /**
@@ -517,79 +490,6 @@
      */
     public AccessPolicyType getAccessPolicy() {
         return AccessPolicyType.getByType(properties.getAccessPolicy());
-    }
-
-    /**
-     * 鐢熸垚 AWS S3 瀛樺偍妗惰闂瓥鐣�
-     *
-     * @param bucketName 瀛樺偍妗�
-     * @param policyType 妗剁瓥鐣ョ被鍨�
-     * @return 绗﹀悎 AWS S3 瀛樺偍妗惰闂瓥鐣ユ牸寮忕殑瀛楃涓�
-     */
-    private static String getPolicy(String bucketName, PolicyType policyType) {
-        String policy = switch (policyType) {
-            case WRITE -> """
-                {
-                  "Version": "2012-10-17",
-                  "Statement": []
-                }
-                """;
-            case READ_WRITE -> """
-                {
-                  "Version": "2012-10-17",
-                  "Statement": [
-                    {
-                      "Effect": "Allow",
-                      "Principal": "*",
-                      "Action": [
-                        "s3:GetBucketLocation",
-                        "s3:ListBucket",
-                        "s3:ListBucketMultipartUploads"
-                      ],
-                      "Resource": "arn:aws:s3:::bucketName"
-                    },
-                    {
-                      "Effect": "Allow",
-                      "Principal": "*",
-                      "Action": [
-                        "s3:AbortMultipartUpload",
-                        "s3:DeleteObject",
-                        "s3:GetObject",
-                        "s3:ListMultipartUploadParts",
-                        "s3:PutObject"
-                      ],
-                      "Resource": "arn:aws:s3:::bucketName/*"
-                    }
-                  ]
-                }
-                """;
-            case READ -> """
-                {
-                  "Version": "2012-10-17",
-                  "Statement": [
-                    {
-                      "Effect": "Allow",
-                      "Principal": "*",
-                      "Action": ["s3:GetBucketLocation"],
-                      "Resource": "arn:aws:s3:::bucketName"
-                    },
-                    {
-                      "Effect": "Deny",
-                      "Principal": "*",
-                      "Action": ["s3:ListBucket"],
-                      "Resource": "arn:aws:s3:::bucketName"
-                    },
-                    {
-                      "Effect": "Allow",
-                      "Principal": "*",
-                      "Action": "s3:GetObject",
-                      "Resource": "arn:aws:s3:::bucketName/*"
-                    }
-                  ]
-                }
-                """;
-        };
-        return policy.replaceAll("bucketName", bucketName);
     }
 
 }
diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java
index 6d39133..a257bba 100644
--- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java
+++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java
@@ -17,17 +17,17 @@
     /**
      * private
      */
-    PRIVATE("0", BucketCannedACL.PRIVATE, ObjectCannedACL.PRIVATE, PolicyType.WRITE),
+    PRIVATE("0", BucketCannedACL.PRIVATE, ObjectCannedACL.PRIVATE),
 
     /**
      * public
      */
-    PUBLIC("1", BucketCannedACL.PUBLIC_READ_WRITE, ObjectCannedACL.PUBLIC_READ_WRITE, PolicyType.READ_WRITE),
+    PUBLIC("1", BucketCannedACL.PUBLIC_READ_WRITE, ObjectCannedACL.PUBLIC_READ_WRITE),
 
     /**
      * custom
      */
-    CUSTOM("2", BucketCannedACL.PUBLIC_READ, ObjectCannedACL.PUBLIC_READ, PolicyType.READ);
+    CUSTOM("2", BucketCannedACL.PUBLIC_READ, ObjectCannedACL.PUBLIC_READ);
 
     /**
      * 妗� 鏉冮檺绫诲瀷锛堟暟鎹簱鍊硷級
@@ -43,11 +43,6 @@
      * 鏂囦欢瀵硅薄 鏉冮檺绫诲瀷
      */
     private final ObjectCannedACL objectCannedACL;
-
-    /**
-     * 妗剁瓥鐣ョ被鍨�
-     */
-    private final PolicyType policyType;
 
     public static AccessPolicyType getByType(String type) {
         for (AccessPolicyType value : values()) {
diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/PolicyType.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/PolicyType.java
deleted file mode 100644
index fe96341..0000000
--- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/PolicyType.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.dromara.common.oss.enumd;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * minio绛栫暐閰嶇疆
- *
- * @author Lion Li
- */
-@Getter
-@AllArgsConstructor
-public enum PolicyType {
-
-    /**
-     * 鍙
-     */
-    READ("read-only"),
-
-    /**
-     * 鍙啓
-     */
-    WRITE("write-only"),
-
-    /**
-     * 璇诲啓
-     */
-    READ_WRITE("read-write");
-
-    /**
-     * 绫诲瀷
-     */
-    private final String type;
-
-}
diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java
index de09752..79272d4 100644
--- a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java
+++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java
@@ -38,4 +38,10 @@
      * 鎻愮ず娑堟伅 鏀寔鍥介檯鍖� 鏍煎紡涓� {code}
      */
     String message() default "{rate.limiter.message}";
+
+    /**
+     * 闄愭祦绛栫暐瓒呮椂鏃堕棿 榛樿涓�澶�(绛栫暐瀛樻椿鏃堕棿 浼氭竻闄ゅ凡瀛樺湪鐨勭瓥鐣ユ暟鎹�)
+     */
+    int timeout() default 86400;
+
 }
diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
index 1f4904a..2d6d82e 100644
--- a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
+++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
@@ -54,13 +54,14 @@
     public void doBefore(JoinPoint point, RateLimiter rateLimiter) {
         int time = rateLimiter.time();
         int count = rateLimiter.count();
+        int timeout = rateLimiter.timeout();
         try {
             String combineKey = getCombineKey(rateLimiter, point);
             RateType rateType = RateType.OVERALL;
             if (rateLimiter.limitType() == LimitType.CLUSTER) {
                 rateType = RateType.PER_CLIENT;
             }
-            long number = RedisUtils.rateLimiter(combineKey, rateType, count, time);
+            long number = RedisUtils.rateLimiter(combineKey, rateType, count, time, timeout);
             if (number == -1) {
                 String message = rateLimiter.message();
                 if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) {
diff --git a/ruoyi-common/ruoyi-common-redis/pom.xml b/ruoyi-common/ruoyi-common-redis/pom.xml
index f56f8aa..d7d99ca 100644
--- a/ruoyi-common/ruoyi-common-redis/pom.xml
+++ b/ruoyi-common/ruoyi-common-redis/pom.xml
@@ -42,6 +42,18 @@
             <groupId>com.fasterxml.jackson.datatype</groupId>
             <artifactId>jackson-datatype-jsr310</artifactId>
         </dependency>
+
+<!--        &lt;!&ndash; redis搴忓垪鍖栨浛浠f柟妗� 姣攋son蹇棤鏁扮殑璺ㄨ瑷�浜岃繘鍒跺簭鍒楀寲 &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>org.apache.fury</groupId>-->
+<!--            <artifactId>fury-core</artifactId>-->
+<!--            <version>0.9.0</version>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>org.slf4j</groupId>-->
+<!--            <artifactId>slf4j-api</artifactId>-->
+<!--        </dependency>-->
+
     </dependencies>
 
 </project>
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java
index f8fe79a..7ba9475 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java
@@ -53,6 +53,9 @@
             om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
             // 鎸囧畾搴忓垪鍖栬緭鍏ョ殑绫诲瀷锛岀被蹇呴』鏄潪final淇グ鐨勩�傚簭鍒楀寲鏃跺皢瀵硅薄鍏ㄧ被鍚嶄竴璧蜂繚瀛樹笅鏉�
             om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
+//            LoggerFactory.useSlf4jLogging(true);
+//            FuryCodec furyCodec = new FuryCodec();
+//            CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, furyCodec, furyCodec);
             TypedJsonJacksonCodec jsonCodec = new TypedJsonJacksonCodec(Object.class, om);
             // 缁勫悎搴忓垪鍖� key 浣跨敤 String 鍐呭浣跨敤閫氱敤 json 鏍煎紡
             CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec);
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
index 793e21f..6e83df1 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
@@ -44,6 +44,7 @@
     }
 
     @SuppressWarnings("unchecked")
+    @Override
     public <T> T get(Object key, Class<T> type) {
         Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, type));
         return (T) o;
@@ -55,6 +56,7 @@
         cache.put(key, value);
     }
 
+    @Override
     public ValueWrapper putIfAbsent(Object key, Object value) {
         CAFFEINE.invalidate(getUniqueKey(key));
         return cache.putIfAbsent(key, value);
@@ -65,6 +67,7 @@
         evictIfPresent(key);
     }
 
+    @Override
     public boolean evictIfPresent(Object key) {
         boolean b = cache.evictIfPresent(key);
         if (b) {
@@ -78,6 +81,7 @@
         cache.clear();
     }
 
+    @Override
     public boolean invalidate() {
         return cache.invalidate();
     }
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java
index 42a88d6..865ffa5 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java
@@ -1,35 +1,21 @@
 package org.dromara.common.redis.utils;
 
-import org.dromara.common.core.utils.SpringUtils;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.redisson.api.RMap;
+import org.dromara.common.core.utils.SpringUtils;
 import org.springframework.cache.Cache;
 import org.springframework.cache.CacheManager;
 
-import java.util.Set;
-
 /**
- * 缂撳瓨鎿嶄綔宸ュ叿绫� {@link }
+ * 缂撳瓨鎿嶄綔宸ュ叿绫�
  *
  * @author Michelle.Chung
- * @date 2022/8/13
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 @SuppressWarnings(value = {"unchecked"})
 public class CacheUtils {
 
     private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class);
-
-    /**
-     * 鑾峰彇缂撳瓨缁勫唴鎵�鏈夌殑KEY
-     *
-     * @param cacheNames 缂撳瓨缁勫悕绉�
-     */
-    public static Set<Object> keys(String cacheNames) {
-        RMap<Object, Object> rmap = (RMap<Object, Object>) CACHE_MANAGER.getCache(cacheNames).getNativeCache();
-        return rmap.keySet();
-    }
 
     /**
      * 鑾峰彇缂撳瓨鍊�
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java
index e436a46..7c09e31 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java
@@ -174,12 +174,12 @@
      *
      * @param queueName 闃熷垪鍚�
      * @param capacity  瀹归噺
-     * @param destroy   宸插瓨鍦ㄦ槸鍚﹂攢姣�
+     * @param destroy   鏄惁閿�姣�
      */
     public static <T> boolean trySetBoundedQueueCapacity(String queueName, int capacity, boolean destroy) {
         RBoundedBlockingQueue<T> boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName);
-        if (boundedBlockingQueue.isExists() && destroy) {
-            destroyQueue(queueName);
+        if (destroy) {
+            boundedBlockingQueue.delete();
         }
         return boundedBlockingQueue.trySetCapacity(capacity);
     }
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java
index 67be2fb..355cd29 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java
@@ -4,6 +4,7 @@
 import lombok.NoArgsConstructor;
 import org.dromara.common.core.utils.SpringUtils;
 import org.redisson.api.*;
+import org.redisson.api.options.KeysScanOptions;
 
 import java.time.Duration;
 import java.util.Collection;
@@ -36,8 +37,22 @@
      * @return -1 琛ㄧず澶辫触
      */
     public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {
+        return rateLimiter(key, rateType, rate, rateInterval, 0);
+    }
+
+    /**
+     * 闄愭祦
+     *
+     * @param key          闄愭祦key
+     * @param rateType     闄愭祦绫诲瀷
+     * @param rate         閫熺巼
+     * @param rateInterval 閫熺巼闂撮殧
+     * @param timeout      瓒呮椂鏃堕棿
+     * @return -1 琛ㄧず澶辫触
+     */
+    public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval, int timeout) {
         RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
-        rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);
+        rateLimiter.trySetRate(rateType, rate, Duration.ofSeconds(rateInterval), Duration.ofSeconds(timeout));
         if (rateLimiter.tryAcquire()) {
             return rateLimiter.availablePermits();
         } else {
@@ -517,18 +532,39 @@
     }
 
     /**
-     * 鑾峰緱缂撳瓨鐨勫熀鏈璞″垪琛�
-     *
+     * 鑾峰緱缂撳瓨鐨勫熀鏈璞″垪琛�(鍏ㄥ眬鍖归厤蹇界暐绉熸埛 鑷鎷兼帴绉熸埛id)
+     * <P>
+     * limit-璁剧疆鎵弿鐨勯檺鍒舵暟閲�(榛樿涓�0,鏌ヨ鍏ㄩ儴)
+     * pattern-璁剧疆閿殑鍖归厤妯″紡(榛樿涓簄ull)
+     * chunkSize-璁剧疆姣忔鎵弿鐨勫潡澶у皬(榛樿涓�0,鏈柟娉曡缃负1000)
+     * type-璁剧疆閿殑绫诲瀷(榛樿涓簄ull,鏌ヨ鍏ㄩ儴绫诲瀷)
+     * </P>
+     * @see KeysScanOptions
      * @param pattern 瀛楃涓插墠缂�
      * @return 瀵硅薄鍒楄〃
      */
     public static Collection<String> keys(final String pattern) {
-        Stream<String> stream = CLIENT.getKeys().getKeysStreamByPattern(pattern);
-        return stream.collect(Collectors.toList());
+        return  keys(KeysScanOptions.defaults().pattern(pattern).chunkSize(1000));
     }
 
     /**
-     * 鍒犻櫎缂撳瓨鐨勫熀鏈璞″垪琛�
+     * 閫氳繃鎵弿鍙傛暟鑾峰彇缂撳瓨鐨勫熀鏈璞″垪琛�
+     * @param keysScanOptions 鎵弿鍙傛暟
+     * <P>
+     * limit-璁剧疆鎵弿鐨勯檺鍒舵暟閲�(榛樿涓�0,鏌ヨ鍏ㄩ儴)
+     * pattern-璁剧疆閿殑鍖归厤妯″紡(榛樿涓簄ull)
+     * chunkSize-璁剧疆姣忔鎵弿鐨勫潡澶у皬(榛樿涓�0)
+     * type-璁剧疆閿殑绫诲瀷(榛樿涓簄ull,鏌ヨ鍏ㄩ儴绫诲瀷)
+     * </P>
+     * @see KeysScanOptions
+     */
+    public static Collection<String> keys(final KeysScanOptions keysScanOptions) {
+        Stream<String> keysStream = CLIENT.getKeys().getKeysStream(keysScanOptions);
+        return keysStream.collect(Collectors.toList());
+    }
+
+    /**
+     * 鍒犻櫎缂撳瓨鐨勫熀鏈璞″垪琛�(鍏ㄥ眬鍖归厤蹇界暐绉熸埛 鑷鎷兼帴绉熸埛id)
      *
      * @param pattern 瀛楃涓插墠缂�
      */
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/SequenceUtils.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/SequenceUtils.java
new file mode 100644
index 0000000..e28c84e
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/SequenceUtils.java
@@ -0,0 +1,165 @@
+package org.dromara.common.redis.utils;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.redisson.api.RIdGenerator;
+import org.redisson.api.RedissonClient;
+
+import java.time.Duration;
+
+/**
+ * 鍙戝彿鍣ㄥ伐鍏风被
+ *
+ * @author 绉嬭緸鏈瘨
+ * @date 2024-12-10
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class SequenceUtils {
+
+    /**
+     * 榛樿鍒濆鍊�
+     */
+    public static final Long DEFAULT_INIT_VALUE = 1L;
+    /**
+     * 榛樿姝ラ暱
+     */
+    public static final Long DEFAULT_STEP_VALUE = 1L;
+    /**
+     * 榛樿杩囨湡鏃堕棿-澶�
+     */
+    public static final Duration DEFAULT_EXPIRE_TIME_DAY = Duration.ofDays(1);
+    /**
+     * 榛樿杩囨湡鏃堕棿-鍒嗛挓
+     */
+    public static final Duration DEFAULT_EXPIRE_TIME_MINUTE = Duration.ofMinutes(1);
+
+    /**
+     * 鑾峰彇Redisson瀹㈡埛绔疄渚�
+     */
+    private static final RedissonClient REDISSON_CLIENT = SpringUtils.getBean(RedissonClient.class);
+
+    /**
+     * 鑾峰彇ID鐢熸垚鍣�
+     *
+     * @param key        涓氬姟key
+     * @param expireTime 杩囨湡鏃堕棿
+     * @param initValue  ID鍒濆鍊�
+     * @param stepValue  ID姝ラ暱
+     * @return ID鐢熸垚鍣�
+     */
+    private static RIdGenerator getIdGenerator(String key, Duration expireTime, Long initValue, Long stepValue) {
+        if (initValue == null || initValue <= 0) {
+            initValue = DEFAULT_INIT_VALUE;
+        }
+        if (stepValue == null || stepValue <= 0) {
+            stepValue = DEFAULT_STEP_VALUE;
+        }
+        RIdGenerator idGenerator = REDISSON_CLIENT.getIdGenerator(key);
+        // 璁剧疆鍒濆鍊煎拰姝ラ暱
+        idGenerator.tryInit(initValue, stepValue);
+        // 璁剧疆杩囨湡鏃堕棿
+        idGenerator.expire(expireTime);
+        return idGenerator;
+    }
+
+    /**
+     * 鑾峰彇鎸囧畾涓氬姟key鐨勫敮涓�id
+     *
+     * @param key        涓氬姟key
+     * @param expireTime 杩囨湡鏃堕棿
+     * @param initValue  ID鍒濆鍊�
+     * @param stepValue  ID姝ラ暱
+     * @return 鍞竴id
+     */
+    public static long nextId(String key, Duration expireTime, Long initValue, Long stepValue) {
+        return getIdGenerator(key, expireTime, initValue, stepValue).nextId();
+    }
+
+    /**
+     * 鑾峰彇鎸囧畾涓氬姟key鐨勫敮涓�id瀛楃涓�
+     *
+     * @param key        涓氬姟key
+     * @param expireTime 杩囨湡鏃堕棿
+     * @param initValue  ID鍒濆鍊�
+     * @param stepValue  ID姝ラ暱
+     * @return 鍞竴id
+     */
+    public static String nextIdStr(String key, Duration expireTime, Long initValue, Long stepValue) {
+        return String.valueOf(nextId(key, expireTime, initValue, stepValue));
+    }
+
+    /**
+     * 鑾峰彇鎸囧畾涓氬姟key鐨勫敮涓�id (ID鍒濆鍊�=1,ID姝ラ暱=1)
+     *
+     * @param key        涓氬姟key
+     * @param expireTime 杩囨湡鏃堕棿
+     * @return 鍞竴id
+     */
+    public static long nextId(String key, Duration expireTime) {
+        return getIdGenerator(key, expireTime, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE).nextId();
+    }
+
+    /**
+     * 鑾峰彇鎸囧畾涓氬姟key鐨勫敮涓�id瀛楃涓� (ID鍒濆鍊�=1,ID姝ラ暱=1)
+     *
+     * @param key        涓氬姟key
+     * @param expireTime 杩囨湡鏃堕棿
+     * @return 鍞竴id
+     */
+    public static String nextIdStr(String key, Duration expireTime) {
+        return String.valueOf(nextId(key, expireTime));
+    }
+
+    /**
+     * 鑾峰彇 yyyyMMdd 寮�澶寸殑鍞竴id
+     *
+     * @return 鍞竴id
+     */
+    public static String nextIdDate() {
+        return nextIdDate("");
+    }
+
+    /**
+     * 鑾峰彇 prefix + yyyyMMdd 寮�澶寸殑鍞竴id
+     *
+     * @param prefix 涓氬姟鍓嶇紑
+     * @return 鍞竴id
+     */
+    public static String nextIdDate(String prefix) {
+        // 鍓嶇紑+鏃ユ湡 鏋勫缓 prefixKey
+        String prefixKey = StringUtils.format("{}{}", StringUtils.blankToDefault(prefix, ""), DateUtil.format(DateUtil.date(), DatePattern.PURE_DATE_FORMATTER));
+        // 鑾峰彇涓嬩竴涓猧d
+        long nextId = getIdGenerator(prefixKey, DEFAULT_EXPIRE_TIME_DAY, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE).nextId();
+        // 杩斿洖瀹屾暣id
+        return StringUtils.format("{}{}", prefixKey, nextId);
+    }
+
+    /**
+     * 鑾峰彇 yyyyMMddHHmmss 寮�澶寸殑鍞竴id
+     *
+     * @return 鍞竴id
+     */
+    public static String nextIdDateTime() {
+        return nextIdDateTime("");
+    }
+
+    /**
+     * 鑾峰彇 prefix + yyyyMMddHHmmss 寮�澶寸殑鍞竴id
+     *
+     * @param prefix 涓氬姟鍓嶇紑
+     * @return 鍞竴id
+     */
+    public static String nextIdDateTime(String prefix) {
+        // 鍓嶇紑+鏃ユ湡鏃堕棿 鏋勫缓 prefixKey
+        String prefixKey = StringUtils.format("{}{}", StringUtils.blankToDefault(prefix, ""), DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_FORMATTER));
+        // 鑾峰彇涓嬩竴涓猧d
+        long nextId = getIdGenerator(prefixKey, DEFAULT_EXPIRE_TIME_MINUTE, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE).nextId();
+        // 杩斿洖瀹屾暣id
+        return StringUtils.format("{}{}", prefixKey, nextId);
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java
index 38e12c3..a2a1520 100644
--- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java
+++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java
@@ -51,7 +51,11 @@
         if (timeout == NEVER_EXPIRE) {
             RedisUtils.setCacheObject(key, value);
         } else {
-            RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout));
+            if (RedisUtils.hasKey(key)) {
+                RedisUtils.setCacheObject(key, value, true);
+            } else {
+                RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout));
+            }
         }
         CAFFEINE.invalidate(key);
     }
@@ -114,7 +118,11 @@
         if (timeout == NEVER_EXPIRE) {
             RedisUtils.setCacheObject(key, object);
         } else {
-            RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout));
+            if (RedisUtils.hasKey(key)) {
+                RedisUtils.setCacheObject(key, object, true);
+            } else {
+                RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout));
+            }
         }
         CAFFEINE.invalidate(key);
     }
diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
index 4ab7d4e..e2c9236 100644
--- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
+++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
@@ -8,12 +8,13 @@
 import cn.hutool.core.util.ObjectUtil;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.constant.TenantConstants;
-import org.dromara.common.core.constant.UserConstants;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.enums.UserType;
 
 import java.util.Set;
+
 
 /**
  * 鐧诲綍閴存潈鍔╂墜
@@ -89,6 +90,13 @@
     }
 
     /**
+     * 鑾峰彇鐢ㄦ埛id
+     */
+    public static String getUserIdStr() {
+        return Convert.toStr(getExtra(USER_KEY));
+    }
+
+    /**
      * 鑾峰彇鐢ㄦ埛璐︽埛
      */
     public static String getUsername() {
@@ -152,7 +160,7 @@
      * @return 缁撴灉
      */
     public static boolean isSuperAdmin(Long userId) {
-        return UserConstants.SUPER_ADMIN_ID.equals(userId);
+        return SystemConstants.SUPER_ADMIN_ID.equals(userId);
     }
 
     /**
diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
index 5fd49d1..a4e921f 100644
--- a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
+++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
@@ -7,9 +7,11 @@
 import cn.dev33.satoken.router.SaRouter;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.dev33.satoken.util.SaResult;
+import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.constant.HttpStatus;
+import org.dromara.common.core.exception.SseException;
 import org.dromara.common.core.utils.ServletUtils;
 import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -50,11 +52,20 @@
                     .match(allUrlHandler.getUrls())
                     // 瀵规湭鎺掗櫎鐨勮矾寰勮繘琛屾鏌�
                     .check(() -> {
+                        HttpServletRequest request = ServletUtils.getRequest();
                         // 妫�鏌ユ槸鍚︾櫥褰� 鏄惁鏈塼oken
-                        StpUtil.checkLogin();
+                        try {
+                            StpUtil.checkLogin();
+                        } catch (NotLoginException e) {
+                            if (request.getRequestURI().contains("sse")) {
+                                throw new SseException(e.getMessage(), e.getCode());
+                            } else {
+                                throw e;
+                            }
+                        }
 
                         // 妫�鏌� header 涓� param 閲岀殑 clientid 涓� token 閲岀殑鏄惁涓�鑷�
-                        String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
+                        String headerCid = request.getHeader(LoginHelper.CLIENT_KEY);
                         String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
                         String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
                         if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java
index 1dfc896..e75dc5b 100644
--- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java
+++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java
@@ -22,7 +22,13 @@
 public @interface Sensitive {
     SensitiveStrategy strategy();
 
-    String roleKey() default "";
+    /**
+     * 瑙掕壊鏍囪瘑绗� 澶氫釜瑙掕壊婊¤冻涓�涓嵆鍙�
+     */
+    String[] roleKey() default {};
 
-    String perms() default "";
+    /**
+     * 鏉冮檺鏍囪瘑绗� 澶氫釜鏉冮檺婊¤冻涓�涓嵆鍙�
+     */
+    String[] perms() default {};
 }
diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java
index 7b5264b..03a7f9c 100644
--- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java
+++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java
@@ -13,6 +13,6 @@
     /**
      * 鏄惁鑴辨晱
      */
-    boolean isSensitive(String roleKey, String perms);
+    boolean isSensitive(String[] roleKey, String[] perms);
 
 }
diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java
index 995dcbd..7af5cee 100644
--- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java
+++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java
@@ -80,12 +80,12 @@
     FIRST_MASK(DesensitizedUtil::firstMask),
 
     /**
-     * 娓呯┖涓簄ull
+     * 娓呯┖涓�""
      */
     CLEAR(s -> DesensitizedUtil.clear()),
 
     /**
-     * 娓呯┖涓�""
+     * 娓呯┖涓簄ull
      */
     CLEAR_TO_NULL(s -> DesensitizedUtil.clearToNull());
 
diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java
index c76c83a..d454724 100644
--- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java
+++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java
@@ -26,8 +26,8 @@
 public class SensitiveHandler extends JsonSerializer<String> implements ContextualSerializer {
 
     private SensitiveStrategy strategy;
-    private String roleKey;
-    private String perms;
+    private String[] roleKey;
+    private String[] perms;
 
     @Override
     public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java
index 91d8d24..a757655 100644
--- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java
+++ b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java
@@ -66,7 +66,7 @@
      */
     @Override
     public void clean() {
-        RedisUtils.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + "sms:");
+        RedisUtils.deleteKeys(GlobalConstants.GLOBAL_REDIS_KEY + "sms:*");
     }
 
 }
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java
index b95c19e..97774ac 100644
--- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java
@@ -30,7 +30,7 @@
     }
 
     @Override
-    protected AuthToken getAccessToken(AuthCallback authCallback) {
+    public AuthToken getAccessToken(AuthCallback authCallback) {
         String body = doPostAuthorizationCode(authCallback.getCode());
         Dict object = JsonUtils.parseMap(body);
         // oauth/token 楠岃瘉寮傚父
@@ -51,7 +51,7 @@
     }
 
     @Override
-    protected AuthUser getUserInfo(AuthToken authToken) {
+    public AuthUser getUserInfo(AuthToken authToken) {
         String body = doGetUserInfo(authToken);
         Dict object = JsonUtils.parseMap(body);
         // oauth/token 楠岃瘉寮傚父
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java
index 13649f9..080c97a 100644
--- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java
@@ -1,7 +1,10 @@
 package org.dromara.common.social.topiam;
 
+import cn.hutool.core.codec.Base64;
 import cn.hutool.core.lang.Dict;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
 import com.xkcoding.http.support.HttpHeader;
 import lombok.extern.slf4j.Slf4j;
 import me.zhyd.oauth.cache.AuthStateCache;
@@ -16,7 +19,7 @@
 import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.json.utils.JsonUtils;
 
-import static org.dromara.common.social.topiam.AuthTopiamSource.TOPIAM;
+import static org.dromara.common.social.topiam.AuthTopIamSource.TOPIAM;
 
 /**
  * TopIAM 璁よ瘉璇锋眰
@@ -41,7 +44,7 @@
     }
 
     @Override
-    protected AuthToken getAccessToken(AuthCallback authCallback) {
+    public AuthToken getAccessToken(AuthCallback authCallback) {
         String body = doPostAuthorizationCode(authCallback.getCode());
         Dict object = JsonUtils.parseMap(body);
         checkResponse(object);
@@ -55,7 +58,7 @@
     }
 
     @Override
-    protected AuthUser getUserInfo(AuthToken authToken) {
+    public AuthUser getUserInfo(AuthToken authToken) {
         String body = doGetUserInfo(authToken);
         Dict object = JsonUtils.parseMap(body);
         checkResponse(object);
@@ -70,6 +73,16 @@
             .build();
     }
 
+    @Override
+    protected String doPostAuthorizationCode(String code) {
+        HttpRequest request = HttpRequest.post(source.accessToken())
+            .header("Authorization", "Basic " + Base64.encode("%s:%s".formatted(config.getClientId(), config.getClientSecret())))
+            .form("grant_type", "authorization_code")
+            .form("code", code)
+            .form("redirect_uri", config.getRedirectUri());
+        HttpResponse response = request.execute();
+        return response.body();
+    }
 
     @Override
     protected String doGetUserInfo(AuthToken authToken) {
@@ -86,7 +99,7 @@
             .build();
     }
 
-    public static void checkResponse(Dict object) {
+    private static void checkResponse(Dict object) {
         // oauth/token 楠岃瘉寮傚父
         if (object.containsKey("error")) {
             throw new AuthException(object.getStr("error_description"));
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamSource.java
similarity index 95%
rename from ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java
rename to ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamSource.java
index e47d6c6..852d7f5 100644
--- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamSource.java
@@ -9,7 +9,7 @@
  * @author xlsea
  * @since 2024-01-06
  */
-public enum AuthTopiamSource implements AuthSource {
+public enum AuthTopIamSource implements AuthSource {
 
     /**
      * 娴嬭瘯
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
index 9191fca..db696e5 100644
--- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
@@ -58,9 +58,9 @@
             case "linkedin" -> new AuthLinkedinRequest(builder.build(), STATE_CACHE);
             case "microsoft" -> new AuthMicrosoftRequest(builder.build(), STATE_CACHE);
             case "renren" -> new AuthRenrenRequest(builder.build(), STATE_CACHE);
-            case "stack_overflow" -> new AuthStackOverflowRequest(builder.build(), STATE_CACHE);
-            case "huawei" -> new AuthHuaweiRequest(builder.build(), STATE_CACHE);
-            case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeRequest(builder.build(), STATE_CACHE);
+            case "stack_overflow" -> new AuthStackOverflowRequest(builder.stackOverflowKey(obj.getStackOverflowKey()).build(), STATE_CACHE);
+            case "huawei" -> new AuthHuaweiV3Request(builder.build(), STATE_CACHE);
+            case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeRequest(builder.agentId(obj.getAgentId()).build(), STATE_CACHE);
             case "gitlab" -> new AuthGitlabRequest(builder.build(), STATE_CACHE);
             case "wechat_mp" -> new AuthWeChatMpRequest(builder.build(), STATE_CACHE);
             case "aliyun" -> new AuthAliyunRequest(builder.build(), STATE_CACHE);
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java
index 1d37a27..64dfcff 100644
--- a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java
+++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java
@@ -1,14 +1,12 @@
 package org.dromara.common.sse.core;
 
-import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.common.sse.dto.SseMessageDto;
 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
@@ -67,13 +65,20 @@
      * @param token  鐢ㄦ埛鐨勫敮涓�浠ょ墝锛岀敤浜庤瘑鍒叿浣撶殑杩炴帴
      */
     public void disconnect(Long userId, String token) {
+        if (userId == null || token == null) {
+            return;
+        }
         Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.get(userId);
-        if (emitters != null) {
+        if (MapUtil.isNotEmpty(emitters)) {
             try {
-                emitters.get(token).send(SseEmitter.event().comment("disconnected"));
+                SseEmitter sseEmitter = emitters.get(token);
+                sseEmitter.send(SseEmitter.event().comment("disconnected"));
+                sseEmitter.complete();
             } catch (Exception ignore) {
             }
             emitters.remove(token);
+        } else {
+            USER_TOKEN_EMITTERS.remove(userId);
         }
     }
 
@@ -94,7 +99,7 @@
      */
     public void sendMessage(Long userId, String message) {
         Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.get(userId);
-        if (emitters != null) {
+        if (MapUtil.isNotEmpty(emitters)) {
             for (Map.Entry<String, SseEmitter> entry : emitters.entrySet()) {
                 try {
                     entry.getValue().send(SseEmitter.event()
@@ -104,6 +109,8 @@
                     emitters.remove(entry.getKey());
                 }
             }
+        } else {
+            USER_TOKEN_EMITTERS.remove(userId);
         }
     }
 
@@ -124,25 +131,13 @@
      * @param sseMessageDto 瑕佸彂甯冪殑SSE娑堟伅瀵硅薄
      */
     public void publishMessage(SseMessageDto sseMessageDto) {
-        List<Long> unsentUserIds = new ArrayList<>();
-        // 褰撳墠鏈嶅姟鍐呯敤鎴�,鐩存帴鍙戦�佹秷鎭�
-        for (Long userId : sseMessageDto.getUserIds()) {
-            if (USER_TOKEN_EMITTERS.containsKey(userId)) {
-                sendMessage(userId, sseMessageDto.getMessage());
-                continue;
-            }
-            unsentUserIds.add(userId);
-        }
-        // 涓嶅湪褰撳墠鏈嶅姟鍐呯敤鎴�,鍙戝竷璁㈤槄娑堟伅
-        if (CollUtil.isNotEmpty(unsentUserIds)) {
-            SseMessageDto broadcastMessage = new SseMessageDto();
-            broadcastMessage.setMessage(sseMessageDto.getMessage());
-            broadcastMessage.setUserIds(unsentUserIds);
-            RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
-                log.info("SSE鍙戦�佷富棰樿闃呮秷鎭痶opic:{} session keys:{} message:{}",
-                    SSE_TOPIC, unsentUserIds, sseMessageDto.getMessage());
-            });
-        }
+        SseMessageDto broadcastMessage = new SseMessageDto();
+        broadcastMessage.setMessage(sseMessageDto.getMessage());
+        broadcastMessage.setUserIds(sseMessageDto.getUserIds());
+        RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
+            log.info("SSE鍙戦�佷富棰樿闃呮秷鎭痶opic:{} session keys:{} message:{}",
+                SSE_TOPIC, sseMessageDto.getUserIds(), sseMessageDto.getMessage());
+        });
     }
 
     /**
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java
index c6abdc8..5861034 100644
--- a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java
+++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java
@@ -16,7 +16,14 @@
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class SseMessageUtils {
 
-    private final static SseEmitterManager MANAGER = SpringUtils.getBean(SseEmitterManager.class);
+    private final static Boolean SSE_ENABLE = SpringUtils.getProperty("sse.enabled", Boolean.class, true);
+    private static SseEmitterManager MANAGER;
+
+    static {
+        if (isEnable() && MANAGER == null) {
+            MANAGER = SpringUtils.getBean(SseEmitterManager.class);
+        }
+    }
 
     /**
      * 鍚戞寚瀹氱殑WebSocket浼氳瘽鍙戦�佹秷鎭�
@@ -25,6 +32,9 @@
      * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
      */
     public static void sendMessage(Long userId, String message) {
+        if (!isEnable()) {
+            return;
+        }
         MANAGER.sendMessage(userId, message);
     }
 
@@ -34,6 +44,9 @@
      * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
      */
     public static void sendMessage(String message) {
+        if (!isEnable()) {
+            return;
+        }
         MANAGER.sendMessage(message);
     }
 
@@ -43,6 +56,9 @@
      * @param sseMessageDto 瑕佸彂甯冪殑SSE娑堟伅瀵硅薄
      */
     public static void publishMessage(SseMessageDto sseMessageDto) {
+        if (!isEnable()) {
+            return;
+        }
         MANAGER.publishMessage(sseMessageDto);
     }
 
@@ -52,7 +68,17 @@
      * @param message 瑕佸彂甯冪殑娑堟伅鍐呭
      */
     public static void publishAll(String message) {
+        if (!isEnable()) {
+            return;
+        }
         MANAGER.publishAll(message);
     }
 
+    /**
+     * 鏄惁寮�鍚�
+     */
+    public static Boolean isEnable() {
+        return SSE_ENABLE;
+    }
+
 }
diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java
index 07302bc..3767fa2 100644
--- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java
+++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java
@@ -4,7 +4,6 @@
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
 import org.dromara.common.core.utils.reflect.ReflectUtils;
-import org.dromara.common.mybatis.config.MybatisPlusConfig;
 import org.dromara.common.redis.config.RedisConfig;
 import org.dromara.common.redis.config.properties.RedissonProperties;
 import org.dromara.common.tenant.core.TenantSaTokenDao;
@@ -16,7 +15,7 @@
 import org.redisson.config.SingleServerConfig;
 import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.cache.CacheManager;
@@ -33,8 +32,8 @@
 @ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
 public class TenantConfig {
 
-    @ConditionalOnBean(MybatisPlusConfig.class)
-    @AutoConfiguration(after = {MybatisPlusConfig.class})
+    @ConditionalOnClass(TenantLineInnerInterceptor.class)
+    @AutoConfiguration
     static class MybatisPlusConfiguration {
 
         /**
@@ -56,14 +55,12 @@
                 // 浣跨敤鍗曟満妯″紡
                 // 璁剧疆澶氱鎴� redis key鍓嶇紑
                 singleServerConfig.setNameMapper(nameMapper);
-                ReflectUtils.invokeSetter(config, "singleServerConfig", singleServerConfig);
             }
             ClusterServersConfig clusterServersConfig = ReflectUtils.invokeGetter(config, "clusterServersConfig");
             // 闆嗙兢閰嶇疆鏂瑰紡 鍙傝�冧笅鏂规敞閲�
             if (ObjectUtil.isNotNull(clusterServersConfig)) {
                 // 璁剧疆澶氱鎴� redis key鍓嶇紑
                 clusterServersConfig.setNameMapper(nameMapper);
-                ReflectUtils.invokeSetter(config, "clusterServersConfig", clusterServersConfig);
             }
         };
     }
diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java
index 9475398..dcdef6e 100644
--- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java
+++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java
@@ -27,15 +27,20 @@
         if (StringUtils.isBlank(name)) {
             return null;
         }
-        if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
-            return super.map(name);
+        try {
+            if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
+                return super.map(name);
+            }
+        } catch (NoClassDefFoundError ignore) {
+            // 鏈変簺鏈嶅姟涓嶉渶瑕乵p瀵艰嚧绫讳笉瀛樺湪 蹇界暐鍗冲彲
         }
         if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
             return super.map(name);
         }
         String tenantId = TenantHelper.getTenantId();
         if (StringUtils.isBlank(tenantId)) {
-            log.error("鏃犳硶鑾峰彇鏈夋晥鐨勭鎴穒d -> Null");
+            log.debug("鏃犳硶鑾峰彇鏈夋晥鐨勭鎴穒d -> Null");
+            return super.map(name);
         }
         if (StringUtils.startsWith(name, tenantId + "")) {
             // 濡傛灉瀛樺湪鍒欑洿鎺ヨ繑鍥�
@@ -53,15 +58,20 @@
         if (StringUtils.isBlank(unmap)) {
             return null;
         }
-        if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
-            return super.unmap(name);
+        try {
+            if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
+                return unmap;
+            }
+        } catch (NoClassDefFoundError ignore) {
+            // 鏈変簺鏈嶅姟涓嶉渶瑕乵p瀵艰嚧绫讳笉瀛樺湪 蹇界暐鍗冲彲
         }
         if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
-            return super.unmap(name);
+            return unmap;
         }
         String tenantId = TenantHelper.getTenantId();
         if (StringUtils.isBlank(tenantId)) {
-            log.error("鏃犳硶鑾峰彇鏈夋晥鐨勭鎴穒d -> Null");
+            log.debug("鏃犳硶鑾峰彇鏈夋晥鐨勭鎴穒d -> Null");
+            return unmap;
         }
         if (StringUtils.startsWith(unmap, tenantId + "")) {
             // 濡傛灉瀛樺湪鍒欏垹闄�
diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java
index b185612..4b6981a 100644
--- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java
+++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java
@@ -1,6 +1,7 @@
 package org.dromara.common.tenant.helper;
 
-import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.context.model.SaStorage;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.ObjectUtil;
@@ -130,12 +131,13 @@
         if (!isEnable()) {
             return;
         }
-        if (!isLogin() || !global) {
+        if (!LoginHelper.isLogin() || !global) {
             TEMP_DYNAMIC_TENANT.set(tenantId);
             return;
         }
         String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
         RedisUtils.setCacheObject(cacheKey, tenantId);
+        SaHolder.getStorage().set(cacheKey, tenantId);
     }
 
     /**
@@ -147,7 +149,7 @@
         if (!isEnable()) {
             return null;
         }
-        if (!isLogin()) {
+        if (!LoginHelper.isLogin()) {
             return TEMP_DYNAMIC_TENANT.get();
         }
         // 濡傛灉绾跨▼鍐呮湁鍊� 浼樺厛杩斿洖
@@ -155,8 +157,15 @@
         if (StringUtils.isNotBlank(tenantId)) {
             return tenantId;
         }
+        SaStorage storage = SaHolder.getStorage();
         String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
+        tenantId = storage.getString(cacheKey);
+        // 濡傛灉涓� -1 璇存槑宸茬粡鏌ヨ繃redis骞朵笖涓嶅瓨鍦ㄥ�� 鍒欑洿鎺ヨ繑鍥瀗ull
+        if (StringUtils.isNotBlank(tenantId)) {
+            return tenantId.equals("-1") ? null : tenantId;
+        }
         tenantId = RedisUtils.getCacheObject(cacheKey);
+        storage.set(cacheKey, StringUtils.isBlank(tenantId) ? "-1" : tenantId);
         return tenantId;
     }
 
@@ -167,13 +176,14 @@
         if (!isEnable()) {
             return;
         }
-        if (!isLogin()) {
+        if (!LoginHelper.isLogin()) {
             TEMP_DYNAMIC_TENANT.remove();
             return;
         }
         TEMP_DYNAMIC_TENANT.remove();
         String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
         RedisUtils.deleteObject(cacheKey);
+        SaHolder.getStorage().delete(cacheKey);
     }
 
     /**
@@ -216,15 +226,6 @@
             tenantId = LoginHelper.getTenantId();
         }
         return tenantId;
-    }
-
-    private static boolean isLogin() {
-        try {
-            StpUtil.checkLogin();
-            return true;
-        } catch (Exception e) {
-            return false;
-        }
     }
 
 }
diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java
index bb9615b..a90f1e1 100644
--- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java
+++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java
@@ -39,7 +39,7 @@
         if (ObjectUtil.isNotNull(trans)) {
             // 濡傛灉鏄犲皠瀛楁涓嶄负绌� 鍒欏彇鏄犲皠瀛楁鐨勫��
             if (StringUtils.isNotBlank(translation.mapper())) {
-                value = ReflectUtils.invokeGetter(gen.getCurrentValue(), translation.mapper());
+                value = ReflectUtils.invokeGetter(gen.currentValue(), translation.mapper());
             }
             // 濡傛灉涓� null 鐩存帴鍐欏嚭
             if (ObjectUtil.isNull(value)) {
diff --git a/ruoyi-common/ruoyi-common-web/pom.xml b/ruoyi-common/ruoyi-common-web/pom.xml
index 5e366bc..b250fa9 100644
--- a/ruoyi-common/ruoyi-common-web/pom.xml
+++ b/ruoyi-common/ruoyi-common-web/pom.xml
@@ -44,19 +44,6 @@
         </dependency>
 
         <dependency>
-            <groupId>io.undertow</groupId>
-            <artifactId>undertow-core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.undertow</groupId>
-            <artifactId>undertow-servlet</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.undertow</groupId>
-            <artifactId>undertow-websockets-jsr</artifactId>
-        </dependency>
-
-        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java
index 91fff76..32d61df 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java
@@ -1,18 +1,14 @@
 package org.dromara.common.web.config;
 
-import org.dromara.common.core.utils.StringUtils;
+import jakarta.servlet.DispatcherType;
 import org.dromara.common.web.config.properties.XssProperties;
 import org.dromara.common.web.filter.RepeatableFilter;
 import org.dromara.common.web.filter.XssFilter;
-import jakarta.servlet.DispatcherType;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
-
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * Filter閰嶇疆
@@ -23,26 +19,21 @@
 @EnableConfigurationProperties(XssProperties.class)
 public class FilterConfig {
 
-    @SuppressWarnings({"rawtypes", "unchecked"})
     @Bean
     @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
-    public FilterRegistrationBean xssFilterRegistration(XssProperties xssProperties) {
-        FilterRegistrationBean registration = new FilterRegistrationBean();
+    public FilterRegistrationBean<XssFilter> xssFilterRegistration() {
+        FilterRegistrationBean<XssFilter> registration = new FilterRegistrationBean<>();
         registration.setDispatcherTypes(DispatcherType.REQUEST);
         registration.setFilter(new XssFilter());
-        registration.addUrlPatterns(StringUtils.split(xssProperties.getUrlPatterns(), StringUtils.SEPARATOR));
+        registration.addUrlPatterns("/*");
         registration.setName("xssFilter");
-        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
-        Map<String, String> initParameters = new HashMap<>();
-        initParameters.put("excludes", xssProperties.getExcludes());
-        registration.setInitParameters(initParameters);
+        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE + 1);
         return registration;
     }
 
-    @SuppressWarnings({"rawtypes", "unchecked"})
     @Bean
-    public FilterRegistrationBean someFilterRegistration() {
-        FilterRegistrationBean registration = new FilterRegistrationBean();
+    public FilterRegistrationBean<RepeatableFilter> someFilterRegistration() {
+        FilterRegistrationBean<RepeatableFilter> registration = new FilterRegistrationBean<>();
         registration.setFilter(new RepeatableFilter());
         registration.addUrlPatterns("/*");
         registration.setName("repeatableFilter");
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
index ac50dd2..84f88ff 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
@@ -1,6 +1,8 @@
 package org.dromara.common.web.config;
 
 import io.undertow.server.DefaultByteBufferPool;
+import io.undertow.server.handlers.DisallowedMethodsHandler;
+import io.undertow.util.HttpString;
 import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
 import org.dromara.common.core.utils.SpringUtils;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
@@ -16,18 +18,45 @@
 @AutoConfiguration
 public class UndertowConfig implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
 
+    /**
+     * 鑷畾涔� Undertow 閰嶇疆
+     * <p>
+     * 涓昏閰嶇疆鍐呭鍖呮嫭锛�
+     * 1. 閰嶇疆 WebSocket 閮ㄧ讲淇℃伅
+     * 2. 鍦ㄨ櫄鎷熺嚎绋嬫ā寮忎笅浣跨敤铏氭嫙绾跨▼姹�
+     * 3. 绂佺敤涓嶅畨鍏ㄧ殑 HTTP 鏂规硶锛屽 CONNECT銆乀RACE銆乀RACK
+     * </p>
+     *
+     * @param factory Undertow 鐨� Web 鏈嶅姟鍣ㄥ伐鍘�
+     */
     @Override
     public void customize(UndertowServletWebServerFactory factory) {
         factory.addDeploymentInfoCustomizers(deploymentInfo -> {
+            // 閰嶇疆 WebSocket 閮ㄧ讲淇℃伅锛岃缃� WebSocket 浣跨敤鐨勭紦鍐插尯姹�
             WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo();
             webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(true, 1024));
             deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
-            // 浣跨敤铏氭嫙绾跨▼
+
+            // 濡傛灉鍚敤浜嗚櫄鎷熺嚎绋嬶紝閰嶇疆 Undertow 浣跨敤铏氭嫙绾跨▼姹�
             if (SpringUtils.isVirtual()) {
+                // 鍒涘缓铏氭嫙绾跨▼姹狅紝绾跨▼姹犲墠缂�涓� "undertow-"
                 VirtualThreadTaskExecutor executor = new VirtualThreadTaskExecutor("undertow-");
+                // 璁剧疆铏氭嫙绾跨▼姹犱负鎵ц鍣ㄥ拰寮傛鎵ц鍣�
                 deploymentInfo.setExecutor(executor);
                 deploymentInfo.setAsyncExecutor(executor);
             }
+
+            // 閰嶇疆绂佹鏌愪簺涓嶅畨鍏ㄧ殑 HTTP 鏂规硶锛堝 CONNECT銆乀RACE銆乀RACK锛�
+            deploymentInfo.addInitialHandlerChainWrapper(handler -> {
+                // 绂佹涓変釜鏂规硶 CONNECT/TRACE/TRACK 涔熸槸涓嶅畨鍏ㄧ殑 閬垮厤鐖櫕楠氭壈
+                HttpString[] disallowedHttpMethods = {
+                    HttpString.tryFromString("CONNECT"),
+                    HttpString.tryFromString("TRACE"),
+                    HttpString.tryFromString("TRACK")
+                };
+                // 浣跨敤 DisallowedMethodsHandler 鎷︽埅骞舵嫆缁濊繖浜涙柟娉曠殑璇锋眰
+                return new DisallowedMethodsHandler(handler, disallowedHttpMethods);
+            });
         });
     }
 
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java
index ecf4f33..bd3e59b 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java
@@ -3,6 +3,9 @@
 import lombok.Data;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * xss杩囨护 閰嶇疆灞炴��
  *
@@ -13,18 +16,13 @@
 public class XssProperties {
 
     /**
-     * 杩囨护寮�鍏�
+     * Xss寮�鍏�
      */
-    private String enabled;
+    private Boolean enabled;
 
     /**
-     * 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
+     * 鎺掗櫎璺緞
      */
-    private String excludes;
-
-    /**
-     * 鍖归厤閾炬帴
-     */
-    private String urlPatterns;
+    private List<String> excludeUrls = new ArrayList<>();
 
 }
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java
index a6cbe8c..95bcdd9 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java
@@ -1,6 +1,8 @@
 package org.dromara.common.web.filter;
 
+import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.web.config.properties.XssProperties;
 import org.springframework.http.HttpMethod;
 
 import jakarta.servlet.*;
@@ -23,13 +25,8 @@
 
     @Override
     public void init(FilterConfig filterConfig) throws ServletException {
-        String tempExcludes = filterConfig.getInitParameter("excludes");
-        if (StringUtils.isNotEmpty(tempExcludes)) {
-            String[] url = tempExcludes.split(StringUtils.SEPARATOR);
-            for (int i = 0; url != null && i < url.length; i++) {
-                excludes.add(url[i]);
-            }
-        }
+        XssProperties properties = SpringUtils.getBean(XssProperties.class);
+        excludes.addAll(properties.getExcludeUrls());
     }
 
     @Override
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java
index 4a425c5..914e549 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java
@@ -1,19 +1,23 @@
 package org.dromara.common.web.filter;
 
 import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HtmlUtil;
-import org.dromara.common.core.utils.StringUtils;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-
 import jakarta.servlet.ReadListener;
 import jakarta.servlet.ServletInputStream;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletRequestWrapper;
+import org.dromara.common.core.utils.StringUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * XSS杩囨护澶勭悊
@@ -29,18 +33,51 @@
     }
 
     @Override
+    public String getParameter(String name) {
+        String value = super.getParameter(name);
+        if (value == null) {
+            return null;
+        }
+        return HtmlUtil.cleanHtmlTag(value).trim();
+    }
+
+    @Override
+    public Map<String, String[]> getParameterMap() {
+        Map<String, String[]> valueMap = super.getParameterMap();
+        if (MapUtil.isEmpty(valueMap)) {
+            return valueMap;
+        }
+        // 閬垮厤鏌愪簺瀹瑰櫒涓嶅厑璁告敼鍙傛暟鐨勬儏鍐� copy涓�浠介噸鏂版敼
+        Map<String, String[]> map = new HashMap<>(valueMap.size());
+        map.putAll(valueMap);
+        for (Map.Entry<String, String[]> entry : map.entrySet()) {
+            String[] values = entry.getValue();
+            if (values != null) {
+                int length = values.length;
+                String[] escapseValues = new String[length];
+                for (int i = 0; i < length; i++) {
+                    // 闃瞲ss鏀诲嚮鍜岃繃婊ゅ墠鍚庣┖鏍�
+                    escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim();
+                }
+                map.put(entry.getKey(), escapseValues);
+            }
+        }
+        return map;
+    }
+
+    @Override
     public String[] getParameterValues(String name) {
         String[] values = super.getParameterValues(name);
-        if (values != null) {
-            int length = values.length;
-            String[] escapseValues = new String[length];
-            for (int i = 0; i < length; i++) {
-                // 闃瞲ss鏀诲嚮鍜岃繃婊ゅ墠鍚庣┖鏍�
-                escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim();
-            }
-            return escapseValues;
+        if (ArrayUtil.isEmpty(values)) {
+            return values;
         }
-        return super.getParameterValues(name);
+        int length = values.length;
+        String[] escapseValues = new String[length];
+        for (int i = 0; i < length; i++) {
+            // 闃瞲ss鏀诲嚮鍜岃繃婊ゅ墠鍚庣┖鏍�
+            escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim();
+        }
+        return escapseValues;
     }
 
     @Override
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
index 061d3aa..0a60fbc 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
@@ -2,14 +2,17 @@
 
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.http.HttpStatus;
+import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.validation.ConstraintViolation;
 import jakarta.validation.ConstraintViolationException;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.exception.SseException;
 import org.dromara.common.core.exception.base.BaseException;
 import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.json.utils.JsonUtils;
 import org.springframework.context.support.DefaultMessageSourceResolvable;
 import org.springframework.validation.BindException;
 import org.springframework.web.HttpRequestMethodNotSupportedException;
@@ -51,6 +54,27 @@
         log.error(e.getMessage());
         Integer code = e.getCode();
         return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
+    }
+
+    /**
+     * 璁よ瘉澶辫触
+     */
+    @ResponseStatus(org.springframework.http.HttpStatus.UNAUTHORIZED)
+    @ExceptionHandler(SseException.class)
+    public String handleNotLoginException(SseException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.debug("璇锋眰鍦板潃'{}',璁よ瘉澶辫触'{}',鏃犳硶璁块棶绯荤粺璧勬簮", requestURI, e.getMessage());
+        return JsonUtils.toJsonString(R.fail(HttpStatus.HTTP_UNAUTHORIZED, "璁よ瘉澶辫触锛屾棤娉曡闂郴缁熻祫婧�"));
+    }
+
+    /**
+     * servlet寮傚父
+     */
+    @ExceptionHandler(ServletException.class)
+    public R<Void> handleServletException(ServletException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鍙戠敓鏈煡寮傚父.", requestURI, e);
+        return R.fail(e.getMessage());
     }
 
     /**
@@ -152,7 +176,7 @@
     @ExceptionHandler(MethodArgumentNotValidException.class)
     public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
         log.error(e.getMessage());
-        String message = e.getBindingResult().getFieldError().getDefaultMessage();
+        String message = StreamUtils.join(e.getBindingResult().getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", ");
         return R.fail(message);
     }
 
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java
index 614a559..f256015 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java
@@ -2,6 +2,7 @@
 
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.extern.slf4j.Slf4j;
@@ -64,9 +65,11 @@
     @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
         StopWatch stopWatch = KEY_CACHE.get();
-        stopWatch.stop();
-        log.info("[PLUS]缁撴潫璇锋眰 => URL[{}],鑰楁椂:[{}]姣", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
-        KEY_CACHE.remove();
+        if (ObjectUtil.isNotNull(stopWatch)) {
+            stopWatch.stop();
+            log.info("[PLUS]缁撴潫璇锋眰 => URL[{}],鑰楁椂:[{}]姣", request.getMethod() + " " + request.getRequestURI(), stopWatch.getDuration().toMillis());
+            KEY_CACHE.remove();
+        }
     }
 
     /**
diff --git a/ruoyi-common/ruoyi-common-websocket/pom.xml b/ruoyi-common/ruoyi-common-websocket/pom.xml
index db86dcb..0587cd7 100644
--- a/ruoyi-common/ruoyi-common-websocket/pom.xml
+++ b/ruoyi-common/ruoyi-common-websocket/pom.xml
@@ -35,6 +35,12 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-websocket</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
     </dependencies>
 </project>
diff --git a/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java
index 368801c..9c2372b 100644
--- a/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java
+++ b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java
@@ -2,6 +2,7 @@
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.springframework.web.socket.CloseStatus;
 import org.springframework.web.socket.WebSocketSession;
 
 import java.util.Map;
@@ -25,6 +26,7 @@
      * @param session    瑕佹坊鍔犵殑WebSocket浼氳瘽
      */
     public static void addSession(Long sessionKey, WebSocketSession session) {
+        removeSession(sessionKey);
         USER_SESSION_MAP.put(sessionKey, session);
     }
 
@@ -34,8 +36,10 @@
      * @param sessionKey 瑕佺Щ闄ょ殑浼氳瘽閿�
      */
     public static void removeSession(Long sessionKey) {
-        if (USER_SESSION_MAP.containsKey(sessionKey)) {
-            USER_SESSION_MAP.remove(sessionKey);
+        WebSocketSession session = USER_SESSION_MAP.remove(sessionKey);
+        try {
+            session.close(CloseStatus.BAD_DATA);
+        } catch (Exception ignored) {
         }
     }
 
diff --git a/ruoyi-extend/ruoyi-monitor-admin/Dockerfile b/ruoyi-extend/ruoyi-monitor-admin/Dockerfile
index 99aaa74..d55b956 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/Dockerfile
+++ b/ruoyi-extend/ruoyi-monitor-admin/Dockerfile
@@ -1,6 +1,6 @@
 # 璐濆皵瀹為獙瀹� Spring 瀹樻柟鎺ㄨ崘闀滃儚 JDK涓嬭浇鍦板潃 https://bell-sw.com/pages/downloads/
 FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
-#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.5-cds
 #FROM findepi/graalvm:java17-native
 
 LABEL maintainer="Lion Li"
@@ -15,6 +15,8 @@
 
 ADD ./target/ruoyi-monitor-admin.jar ./app.jar
 
+SHELL ["/bin/bash", "-c"]
+
 ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom \
            -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
            -jar app.jar
diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
index beee587..622c93d 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
+++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
@@ -13,8 +13,8 @@
 spring:
   security:
     user:
-      name: ruoyi
-      password: 123456
+      name: @monitor.username@
+      password: @monitor.password@
   boot:
     admin:
       ui:
@@ -44,5 +44,5 @@
     metadata:
       username: ${spring.boot.admin.client.username}
       userpassword: ${spring.boot.admin.client.password}
-  username: ruoyi
-  password: 123456
+  username: @monitor.username@
+  password: @monitor.password@
diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml
index 16bb937..45cbbba 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml
+++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml
@@ -4,7 +4,7 @@
     <contextName>logback</contextName>
     <property name="log.path" value="./logs/ruoyi-monitor-admin"/>
     <property name="console.log.pattern"
-              value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+              value="%cyan(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
     <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
 
     <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
@@ -31,4 +31,4 @@
         <appender-ref ref="file"/>
     </root>
 
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/ruoyi-extend/ruoyi-snailjob-server/Dockerfile b/ruoyi-extend/ruoyi-snailjob-server/Dockerfile
index a66ca66..6f4484d 100644
--- a/ruoyi-extend/ruoyi-snailjob-server/Dockerfile
+++ b/ruoyi-extend/ruoyi-snailjob-server/Dockerfile
@@ -1,6 +1,6 @@
 # 璐濆皵瀹為獙瀹� Spring 瀹樻柟鎺ㄨ崘闀滃儚 JDK涓嬭浇鍦板潃 https://bell-sw.com/pages/downloads/
 FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
-#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.5-cds
 #FROM findepi/graalvm:java17-native
 
 LABEL maintainer="Lion Li"
@@ -16,6 +16,8 @@
 
 ADD ./target/ruoyi-snailjob-server.jar ./app.jar
 
+SHELL ["/bin/bash", "-c"]
+
 ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom \
            -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
            -jar app.jar
diff --git a/ruoyi-extend/ruoyi-snailjob-server/pom.xml b/ruoyi-extend/ruoyi-snailjob-server/pom.xml
index 7348b29..0b3afd3 100644
--- a/ruoyi-extend/ruoyi-snailjob-server/pom.xml
+++ b/ruoyi-extend/ruoyi-snailjob-server/pom.xml
@@ -16,6 +16,18 @@
             <groupId>com.aizuda</groupId>
             <artifactId>snail-job-server-starter</artifactId>
             <version>${snailjob.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.scala-lang</groupId>
+                    <artifactId>scala-library</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.scala-lang</groupId>
+            <artifactId>scala-library</artifactId>
+            <version>2.13.9</version>
         </dependency>
 
         <dependency>
diff --git a/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java b/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java
index 3cae8f5..5196c77 100644
--- a/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java
+++ b/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java
@@ -22,7 +22,7 @@
     public FilterRegistrationBean<ActuatorAuthFilter> actuatorFilterRegistrationBean() {
         FilterRegistrationBean<ActuatorAuthFilter> registrationBean = new FilterRegistrationBean<>();
         registrationBean.setFilter(new ActuatorAuthFilter(username, password));
-        registrationBean.addUrlPatterns("/actuator", "/actuator/**");
+        registrationBean.addUrlPatterns("/actuator", "/actuator/*");
         return registrationBean;
     }
 
diff --git a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml
index cbe40be..32a2cc4 100644
--- a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml
+++ b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml
@@ -20,8 +20,8 @@
   retry-pull-page-size: 1000
   # 鎷夊彇閲嶈瘯鏁版嵁鐨勬瘡鎵规鐨勫ぇ灏�
   job-pull-page-size: 1000
-  # 鏈嶅姟绔痭etty绔彛
-  netty-port: 17888
+  # 鏈嶅姟鍣ㄧ鍙�
+  server-port: 17888
   # 涓�涓鎴风姣忕鏈�澶氭帴鏀剁殑閲嶈瘯鏁伴噺鎸囦护
   limiter: 1000
   # 鍙锋妯″紡涓嬫闀块厤缃�
@@ -34,7 +34,10 @@
     max-count: 288
     #闂撮殧鏃堕棿
     trigger-interval: 900
+  # 閲嶈瘯姣忔鎷夊彇鐨勬鏁�
   retry-max-pull-count: 10
+  # RPC閫氳绫诲瀷: netty,grpc
+  rpc-type: grpc
 
 --- # 鐩戞帶涓績閰嶇疆
 spring.boot.admin.client:
@@ -46,5 +49,5 @@
     metadata:
       username: ${spring.boot.admin.client.username}
       userpassword: ${spring.boot.admin.client.password}
-  username: ruoyi
-  password: 123456
+  username: @monitor.username@
+  password: @monitor.password@
diff --git a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml
index 3ba983c..32a2cc4 100644
--- a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml
+++ b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml
@@ -20,8 +20,8 @@
   retry-pull-page-size: 1000
   # 鎷夊彇閲嶈瘯鏁版嵁鐨勬瘡鎵规鐨勫ぇ灏�
   job-pull-page-size: 1000
-  # 鏈嶅姟绔� netty 绔彛
-  netty-port: 17888
+  # 鏈嶅姟鍣ㄧ鍙�
+  server-port: 17888
   # 涓�涓鎴风姣忕鏈�澶氭帴鏀剁殑閲嶈瘯鏁伴噺鎸囦护
   limiter: 1000
   # 鍙锋妯″紡涓嬫闀块厤缃�
@@ -34,7 +34,10 @@
     max-count: 288
     #闂撮殧鏃堕棿
     trigger-interval: 900
+  # 閲嶈瘯姣忔鎷夊彇鐨勬鏁�
   retry-max-pull-count: 10
+  # RPC閫氳绫诲瀷: netty,grpc
+  rpc-type: grpc
 
 --- # 鐩戞帶涓績閰嶇疆
 spring.boot.admin.client:
@@ -46,5 +49,5 @@
     metadata:
       username: ${spring.boot.admin.client.username}
       userpassword: ${spring.boot.admin.client.password}
-  username: ruoyi
-  password: 123456
+  username: @monitor.username@
+  password: @monitor.password@
diff --git a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml
index a40262c..be58811 100644
--- a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml
+++ b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml
@@ -2,7 +2,7 @@
 <configuration>
     <property name="log.path" value="./logs/ruoyi-snailjob-server" />
     <property name="console.log.pattern"
-              value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+              value="%cyan(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
     <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
 
 
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailController.java
index 47b4349..01f5044 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailController.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailController.java
@@ -1,14 +1,16 @@
 package org.dromara.demo.controller;
 
+import cn.dev33.satoken.annotation.SaIgnore;
+import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.mail.utils.MailUtils;
-import lombok.RequiredArgsConstructor;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.io.File;
+import java.util.Arrays;
 
 
 /**
@@ -16,6 +18,7 @@
  *
  * @author Michelle.Chung
  */
+@SaIgnore
 @Validated
 @RequiredArgsConstructor
 @RestController
@@ -49,4 +52,19 @@
         return R.ok();
     }
 
+    /**
+     * 鍙戦�侀偖浠讹紙澶氶檮浠讹級
+     *
+     * @param to       鎺ユ敹浜�
+     * @param subject  鏍囬
+     * @param text     鍐呭
+     * @param paths    闄勪欢璺緞
+     */
+    @GetMapping("/sendMessageWithAttachments")
+    public R<Void> sendMessageWithAttachments(String to, String subject, String text, String[] paths) {
+        File[] array = Arrays.stream(paths).map(File::new).toArray(File[]::new);
+        MailUtils.sendText(to, subject, text, array);
+        return R.ok();
+    }
+
 }
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java
index 341880c..303cf88 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java
@@ -1,5 +1,6 @@
 package org.dromara.demo.controller;
 
+import cn.hutool.core.thread.ThreadUtil;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.redis.utils.RedisUtils;
@@ -83,11 +84,7 @@
         RedisUtils.setCacheObject(key, value);
         boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10));
         System.out.println("***********" + flag);
-        try {
-            Thread.sleep(11 * 1000);
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
+        ThreadUtil.sleep(11 * 1000);
         Object obj = RedisUtils.getCacheObject(key);
         return R.ok(value.equals(obj));
     }
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java
index b7e0962..237b6ee 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java
@@ -1,5 +1,6 @@
 package org.dromara.demo.controller;
 
+import cn.hutool.core.thread.ThreadUtil;
 import com.baomidou.lock.LockInfo;
 import com.baomidou.lock.LockTemplate;
 import com.baomidou.lock.annotation.Lock4j;
@@ -33,13 +34,9 @@
     @Lock4j(keys = {"#key"})
     @GetMapping("/testLock4j")
     public R<String> testLock4j(String key, String value) {
-        System.out.println("start:" + key + ",time:" + LocalTime.now().toString());
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
-        System.out.println("end :" + key + ",time:" + LocalTime.now().toString());
+        System.out.println("start:" + key + ",time:" + LocalTime.now());
+        ThreadUtil.sleep(10000);
+        System.out.println("end :" + key + ",time:" + LocalTime.now());
         return R.ok("鎿嶄綔鎴愬姛", value);
     }
 
@@ -54,11 +51,7 @@
         }
         // 鑾峰彇閿佹垚鍔燂紝澶勭悊涓氬姟
         try {
-            try {
-                Thread.sleep(8000);
-            } catch (InterruptedException e) {
-                //
-            }
+            ThreadUtil.sleep(8000);
             System.out.println("鎵ц绠�鍗曟柟娉�1 , 褰撳墠绾跨▼:" + Thread.currentThread().getName());
         } finally {
             //閲婃斁閿�
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java
index 95fa0d1..ef9058e 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java
@@ -15,6 +15,9 @@
 import org.dromara.common.excel.convert.ExcelDictConvert;
 import org.dromara.common.excel.convert.ExcelEnumConvert;
 
+import java.io.Serial;
+import java.io.Serializable;
+
 /**
  * 甯︽湁涓嬫媺閫夌殑Excel瀵煎嚭
  *
@@ -24,8 +27,9 @@
 @ExcelIgnoreUnannotated
 @AllArgsConstructor
 @NoArgsConstructor
-public class ExportDemoVo {
+public class ExportDemoVo implements Serializable {
 
+    @Serial
     private static final long serialVersionUID = 1L;
 
     /**
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java
index 016c2f7..e7ea807 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java
@@ -2,6 +2,8 @@
 
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelNotation;
+import org.dromara.common.excel.annotation.ExcelRequired;
 import org.dromara.common.translation.annotation.Translation;
 import org.dromara.common.translation.constant.TransConstant;
 import org.dromara.demo.domain.TestDemo;
@@ -36,30 +38,35 @@
     /**
      * 閮ㄩ棬id
      */
+    @ExcelRequired
     @ExcelProperty(value = "閮ㄩ棬id")
     private Long deptId;
 
     /**
      * 鐢ㄦ埛id
      */
+    @ExcelRequired
     @ExcelProperty(value = "鐢ㄦ埛id")
     private Long userId;
 
     /**
      * 鎺掑簭鍙�
      */
+    @ExcelRequired
     @ExcelProperty(value = "鎺掑簭鍙�")
     private Integer orderNum;
 
     /**
      * key閿�
      */
+    @ExcelNotation(value = "娴嬭瘯key")
     @ExcelProperty(value = "key閿�")
     private String testKey;
 
     /**
      * 鍊�
      */
+    @ExcelNotation(value = "娴嬭瘯value")
     @ExcelProperty(value = "鍊�")
     private String value;
 
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java
index 6aeeb50..19b2d52 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java
@@ -34,21 +34,25 @@
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "user_id")
     })
-    List<TestDemo> selectList(IPage<TestDemo> page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
+    default <P extends IPage<TestDemoVo>> P selectVoPage(IPage<TestDemo> page, Wrapper<TestDemo> wrapper) {
+        return selectVoPage(page, wrapper, this.currentVoClass());
+    }
 
     @Override
     @DataPermission({
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "user_id")
     })
-    List<TestDemo> selectList(@Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
+    default List<TestDemoVo> selectVoList(Wrapper<TestDemo> wrapper) {
+        return selectVoList(wrapper, this.currentVoClass());
+    }
 
     @Override
     @DataPermission(value = {
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "user_id")
     }, joinStr = "AND")
-    List<TestDemo> selectBatchIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
+    List<TestDemo> selectByIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
 
     @Override
     @DataPermission({
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java
index 0240e02..69cf0a8 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java
@@ -1,10 +1,11 @@
 package org.dromara.demo.service.impl;
 
+import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.Data;
 import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.excel.core.DropDownOptions;
 import org.dromara.common.excel.utils.ExcelUtil;
@@ -34,7 +35,7 @@
             // 妯℃嫙鏁版嵁搴撲腑鐨勪竴鏉℃暟鎹�
             ExportDemoVo everyRowData = new ExportDemoVo();
             everyRowData.setNickName("鐢ㄦ埛-" + i);
-            everyRowData.setUserStatus(UserStatus.OK.getCode());
+            everyRowData.setUserStatus(SystemConstants.NORMAL);
             everyRowData.setGender("1");
             everyRowData.setPhoneNumber(String.format("175%08d", i));
             everyRowData.setEmail(String.format("175%08d", i) + "@163.com");
@@ -121,8 +122,9 @@
         List<DemoCityData> provinceList = new ArrayList<>();
 
         // 瀹為檯涓氬姟涓竴鑸噰鐢ㄦ暟鎹簱璇诲彇鐨勫舰寮忥紝杩欓噷鐩存帴鎷兼帴鍒涘缓
-        provinceList.add(new DemoCityData(0, null, "瀹夊窘鐪�"));
-        provinceList.add(new DemoCityData(1, null, "姹熻嫃鐪�"));
+        provinceList.add(new DemoCityData(0, null, "P100000"));
+        provinceList.add(new DemoCityData(1, null, "P200000"));
+        provinceList.add(new DemoCityData(2, null, "P300000"));
 
         return provinceList;
     }
@@ -137,11 +139,11 @@
         List<DemoCityData> cityList = new ArrayList<>();
 
         // 瀹為檯涓氬姟涓竴鑸噰鐢ㄦ暟鎹簱璇诲彇鐨勫舰寮忥紝杩欓噷鐩存帴鎷兼帴鍒涘缓
-        cityList.add(new DemoCityData(0, 0, "鍚堣偉甯�"));
-        cityList.add(new DemoCityData(1, 0, "鑺滄箹甯�"));
-        cityList.add(new DemoCityData(2, 1, "鍗椾含甯�"));
-        cityList.add(new DemoCityData(3, 1, "鏃犻敗甯�"));
-        cityList.add(new DemoCityData(4, 1, "寰愬窞甯�"));
+        cityList.add(new DemoCityData(0, 0, "C110000"));
+        cityList.add(new DemoCityData(1, 0, "C120000"));
+        cityList.add(new DemoCityData(2, 1, "C210000"));
+        cityList.add(new DemoCityData(3, 1, "C220000"));
+        cityList.add(new DemoCityData(4, 1, "C230000"));
 
         selectParentData(provinceList, cityList);
 
@@ -157,17 +159,29 @@
     private List<DemoCityData> getAreaList(List<DemoCityData> cityList) {
         List<DemoCityData> areaList = new ArrayList<>();
 
+        int minCount = 500;
+        int maxCount = 10000;
+
         // 瀹為檯涓氬姟涓竴鑸噰鐢ㄦ暟鎹簱璇诲彇鐨勫舰寮忥紝杩欓噷鐩存帴鎷兼帴鍒涘缓
-        areaList.add(new DemoCityData(0, 0, "鐟舵捣鍖�"));
-        areaList.add(new DemoCityData(1, 0, "搴愭睙鍖�"));
-        areaList.add(new DemoCityData(2, 1, "鍗楀畞鍘�"));
-        areaList.add(new DemoCityData(3, 1, "闀滄箹鍖�"));
-        areaList.add(new DemoCityData(4, 2, "鐜勬鍖�"));
-        areaList.add(new DemoCityData(5, 2, "绉︽樊鍖�"));
-        areaList.add(new DemoCityData(6, 3, "瀹滃叴甯�"));
-        areaList.add(new DemoCityData(7, 3, "鏂板惔鍖�"));
-        areaList.add(new DemoCityData(8, 4, "榧撴ゼ鍖�"));
-        areaList.add(new DemoCityData(9, 4, "涓板幙"));
+        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
+            areaList.add(new DemoCityData(areaList.size(), 0, String.format("A11%04d", i)));
+        }
+
+        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
+            areaList.add(new DemoCityData(areaList.size(), 1, String.format("A12%04d", i)));
+        }
+
+        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
+            areaList.add(new DemoCityData(areaList.size(), 2, String.format("A21%04d", i)));
+        }
+
+        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
+            areaList.add(new DemoCityData(areaList.size(), 3, String.format("A22%04d", i)));
+        }
+
+        for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
+            areaList.add(new DemoCityData(areaList.size(), 4, String.format("A23%04d", i)));
+        }
 
         selectParentData(cityList, areaList);
 
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java
index 3cfde3a..ced141e 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java
@@ -101,7 +101,7 @@
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
         if (isValid) {
             // 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
-            List<TestDemo> list = baseMapper.selectBatchIds(ids);
+            List<TestDemo> list = baseMapper.selectByIds(ids);
             if (list.size() != ids.size()) {
                 throw new ServiceException("鎮ㄦ病鏈夊垹闄ゆ潈闄�!");
             }
diff --git a/ruoyi-modules/ruoyi-generator/pom.xml b/ruoyi-modules/ruoyi-generator/pom.xml
index b7fd94f..4906029 100644
--- a/ruoyi-modules/ruoyi-generator/pom.xml
+++ b/ruoyi-modules/ruoyi-generator/pom.xml
@@ -64,19 +64,19 @@
 <!--        <dependency>-->
 <!--            <groupId>org.anyline</groupId>-->
 <!--            <artifactId>anyline-data-jdbc-oracle</artifactId>-->
-<!--        <version>${anyline.version}</version>-->
+<!--            <version>${anyline.version}</version>-->
 <!--        </dependency>-->
 
 <!--        <dependency>-->
 <!--            <groupId>org.anyline</groupId>-->
 <!--            <artifactId>anyline-data-jdbc-postgresql</artifactId>-->
-<!--        <version>${anyline.version}</version>-->
+<!--            <version>${anyline.version}</version>-->
 <!--        </dependency>-->
 
 <!--        <dependency>-->
 <!--            <groupId>org.anyline</groupId>-->
 <!--            <artifactId>anyline-data-jdbc-mssql</artifactId>-->
-<!--        <version>${anyline.version}</version>-->
+<!--            <version>${anyline.version}</version>-->
 <!--        </dependency>-->
 
     </dependencies>
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java
index c345f22..b9888fb 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java
@@ -56,13 +56,13 @@
      * 鏁版嵁搴撴椂闂寸被鍨�
      */
     String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp", "year", "interval",
-        "smalldatetime", "datetime2", "datetimeoffset"};
+        "smalldatetime", "datetime2", "datetimeoffset", "timestamptz"};
 
     /**
      * 鏁版嵁搴撴暟瀛楃被鍨�
      */
-    String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
-        "bit", "bigint", "float", "double", "decimal", "numeric", "real", "double precision",
+    String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "int2", "int4", "int8", "number", "integer",
+        "bit", "bigint", "float", "float4", "float8", "double", "decimal", "numeric", "real", "double precision",
         "smallserial", "serial", "bigserial", "money", "smallmoney"};
 
     /**
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java
index f792ceb..f2d7257 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java
@@ -162,7 +162,7 @@
      * 涓婄骇鑿滃崟ID瀛楁
      */
     @TableField(exist = false)
-    private String parentMenuId;
+    private Long parentMenuId;
 
     /**
      * 涓婄骇鑿滃崟鍚嶇О瀛楁
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java
index e1560b4..6b2e429 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java
@@ -159,7 +159,7 @@
     }
 
     public boolean isEdit() {
-        return isInsert(this.isEdit);
+        return isEdit(this.isEdit);
     }
 
     public boolean isEdit(String isEdit) {
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java
index 63f4c15..1798b4b 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java
@@ -2,10 +2,8 @@
 
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 import org.dromara.generator.domain.GenTable;
-import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -40,6 +38,14 @@
      */
     GenTable selectGenTableByName(String tableName);
 
+    /**
+     * 鏌ヨ鎸囧畾鏁版嵁婧愪笅鐨勬墍鏈夎〃鍚嶅垪琛�
+     *
+     * @param dataName 鏁版嵁婧愬悕绉帮紝鐢ㄤ簬閫夋嫨涓嶅悓鐨勬暟鎹簮
+     * @return 褰撳墠鏁版嵁搴撲腑鐨勮〃鍚嶅垪琛�
+     *
+     * @DS("") 浣跨敤榛樿鏁版嵁婧愭墽琛屾煡璇㈡搷浣�
+     */
     @DS("")
     List<String> selectTableNameList(String dataName);
 }
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
index 99935f7..6b9e606 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
@@ -29,7 +29,6 @@
 import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.generator.constant.GenConstants;
 import org.dromara.generator.domain.GenTable;
 import org.dromara.generator.domain.GenTableColumn;
@@ -64,7 +63,7 @@
     private final GenTableColumnMapper genTableColumnMapper;
     private final IdentifierGenerator identifierGenerator;
 
-    private static final String[] TABLE_IGNORE = new String[]{"sj_", "act_", "flw_", "gen_"};
+    private static final String[] TABLE_IGNORE = new String[]{"sj_", "flow_", "gen_"};
 
     /**
      * 鏌ヨ涓氬姟瀛楁鍒楄〃
@@ -106,7 +105,8 @@
             .like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
             .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
             .between(params.get("beginTime") != null && params.get("endTime") != null,
-                "create_time", params.get("beginTime"), params.get("endTime"));
+                "create_time", params.get("beginTime"), params.get("endTime"))
+            .orderByDesc("update_time");
         return wrapper;
     }
 
@@ -137,7 +137,7 @@
         }
         // 杩囨护骞惰浆鎹㈣〃鏍兼暟鎹�
         List<GenTable> tables = tablesMap.values().stream()
-            .filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE))
+            .filter(x -> !StringUtils.startWithAnyIgnoreCase(x.getName(), TABLE_IGNORE))
             .filter(x -> {
                 if (CollUtil.isEmpty(tableNames)) {
                     return true;
@@ -162,10 +162,12 @@
                 GenTable gen = new GenTable();
                 gen.setTableName(x.getName());
                 gen.setTableComment(x.getComment());
-                gen.setCreateTime(x.getCreateTime());
+                // postgresql鐨勮〃鍏冩暟鎹病鏈夊垱寤烘椂闂磋繖涓笢瑗�(濂藉钁�) 鍙兘new Date浠f浛
+                gen.setCreateTime(ObjectUtil.defaultIfNull(x.getCreateTime(), new Date()));
                 gen.setUpdateTime(x.getUpdateTime());
                 return gen;
-            }).toList();
+            }).sorted(Comparator.comparing(GenTable::getCreateTime).reversed())
+            .toList();
 
         IPage<GenTable> page = pageQuery.build();
         page.setTotal(tables.size());
@@ -192,7 +194,7 @@
         }
 
         List<Table<?>> tableList = tablesMap.values().stream()
-            .filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE))
+            .filter(x -> !StringUtils.startWithAnyIgnoreCase(x.getName(), TABLE_IGNORE))
             .filter(x -> tableNameSet.contains(x.getName())).toList();
 
         if (CollUtil.isEmpty(tableList)) {
@@ -259,11 +261,10 @@
     @DSTransactional
     @Override
     public void importGenTable(List<GenTable> tableList, String dataName) {
-        Long operId = LoginHelper.getUserId();
         try {
             for (GenTable table : tableList) {
                 String tableName = table.getTableName();
-                GenUtils.initTable(table, operId);
+                GenUtils.initTable(table);
                 table.setDataName(dataName);
                 int row = baseMapper.insert(table);
                 if (row > 0) {
@@ -294,14 +295,18 @@
     @DS("#dataName")
     @Override
     public List<GenTableColumn> selectDbTableColumnsByName(String tableName, String dataName) {
-        LinkedHashMap<String, Column> columns = ServiceProxy.metadata().columns(tableName);
+        Table<?> table = ServiceProxy.metadata().table(tableName);
+        if (ObjectUtil.isNull(table)) {
+            return new ArrayList<>();
+        }
+        LinkedHashMap<String, Column> columns = table.getColumns();
         List<GenTableColumn> tableColumns = new ArrayList<>();
         columns.forEach((columnName, column) -> {
             GenTableColumn tableColumn = new GenTableColumn();
             tableColumn.setIsPk(String.valueOf(column.isPrimaryKey()));
             tableColumn.setColumnName(column.getName());
             tableColumn.setColumnComment(column.getComment());
-            tableColumn.setColumnType(column.getTypeName().toLowerCase());
+            tableColumn.setColumnType(column.getOriginType().toLowerCase());
             tableColumn.setSort(column.getPosition());
             tableColumn.setIsRequired(column.isNullable() == 0 ? "1" : "0");
             tableColumn.setIsIncrement(column.isAutoIncrement() == -1 ? "0" : "1");
@@ -548,7 +553,7 @@
             String treeCode = paramsObj.getStr(GenConstants.TREE_CODE);
             String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE);
             String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
-            String parentMenuId = paramsObj.getStr(GenConstants.PARENT_MENU_ID);
+            Long parentMenuId = paramsObj.getLong(GenConstants.PARENT_MENU_ID);
             String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME);
 
             genTable.setTreeCode(treeCode);
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java
index 2e6b37b..996cf9b 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java
@@ -22,14 +22,15 @@
     /**
      * 鍒濆鍖栬〃淇℃伅
      */
-    public static void initTable(GenTable genTable, Long operId) {
+    public static void initTable(GenTable genTable) {
         genTable.setClassName(convertClassName(genTable.getTableName()));
         genTable.setPackageName(GenConfig.getPackageName());
         genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
         genTable.setBusinessName(getBusinessName(genTable.getTableName()));
         genTable.setFunctionName(replaceText(genTable.getTableComment()));
         genTable.setFunctionAuthor(GenConfig.getAuthor());
-        genTable.setCreateBy(operId);
+        genTable.setCreateTime(null);
+        genTable.setUpdateTime(null);
     }
 
     /**
@@ -37,9 +38,11 @@
      */
     public static void initColumnField(GenTableColumn column, GenTable table) {
         String dataType = getDbType(column.getColumnType());
-        String columnName = column.getColumnName();
+        // 缁熶竴杞皬鍐� 閬垮厤鏈変簺鏁版嵁搴撻粯璁ゅぇ鍐欓棶棰� 濡傛灉闇�瑕佺壒鍒功鍐欐柟寮� 璇峰湪瀹炰綋绫诲鍔犳敞瑙f爣娉ㄥ埆鍚�
+        String columnName = column.getColumnName().toLowerCase();
         column.setTableId(table.getTableId());
-        column.setCreateBy(table.getCreateBy());
+        column.setCreateTime(null);
+        column.setUpdateTime(null);
         // 璁剧疆java瀛楁鍚�
         column.setJavaField(StringUtils.toCamelCase(columnName));
         // 璁剧疆榛樿绫诲瀷
@@ -56,20 +59,9 @@
             column.setHtmlType(GenConstants.HTML_DATETIME);
         } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) {
             column.setHtmlType(GenConstants.HTML_INPUT);
-
-            // 濡傛灉鏄诞鐐瑰瀷 缁熶竴鐢˙igDecimal
-            String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), StringUtils.SEPARATOR);
-            if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) {
-                column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
-            }
-            // 濡傛灉鏄暣褰�
-            else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) {
-                column.setJavaType(GenConstants.TYPE_INTEGER);
-            }
-            // 闀挎暣褰�
-            else {
-                column.setJavaType(GenConstants.TYPE_LONG);
-            }
+            // 鏁版嵁搴撶殑鏁板瓧瀛楁涓巎ava涓嶅尮閰� 涓斿緢澶氭暟鎹簱鐨勬暟瀛楀瓧娈靛緢妯$硦 渚嬪oracle鍙湁number娌℃湁缁嗗垎
+            // 鎵�浠ラ粯璁ゆ暟瀛楃被鍨嬪叏涓篖ong鍙湪鐣岄潰涓婅嚜琛岀紪杈戞兂瑕佺殑绫诲瀷 鏈変粈涔堢壒娈婇渶姹備篃鍙互鍦ㄨ繖閲岀壒娈婂鐞�
+            column.setJavaType(GenConstants.TYPE_LONG);
         }
 
         // BO瀵硅薄 榛樿鎻掑叆鍕鹃��
@@ -79,10 +71,6 @@
         // BO瀵硅薄 榛樿缂栬緫鍕鹃��
         if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
             column.setIsEdit(GenConstants.REQUIRE);
-        }
-        // BO瀵硅薄 榛樿鏄惁蹇呭~鍕鹃��
-        if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
-            column.setIsRequired(GenConstants.REQUIRE);
         }
         // VO瀵硅薄 榛樿杩斿洖鍕鹃��
         if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName)) {
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
index 67690ca..48cc8b1 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
@@ -95,6 +95,10 @@
             ${ClassName}::get$AttrName ,params.get("begin$AttrName"), params.get("end$AttrName"));
 #end
 #end
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#if($column.isPk==1)
+        lqw.orderByAsc(${ClassName}::get$AttrName);
+#end
 #end
         return lqw;
     }
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
index c896afb..5591f97 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
@@ -58,7 +58,7 @@
      * ${column.columnComment}Url
      */
     @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}")
-    private String ${column.javaField}Url";
+    private String ${column.javaField}Url;
 #end
 #end
 #end
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java
index 9b08c2d..1cab232 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java
@@ -19,6 +19,7 @@
 import org.springframework.web.bind.annotation.*;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -43,7 +44,7 @@
     @GetMapping("/list")
     public TableDataInfo<SysUserOnline> list(String ipaddr, String userName) {
         // 鑾峰彇鎵�鏈夋湭杩囨湡鐨� token
-        List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
+        Collection<String> keys = RedisUtils.keys(CacheConstants.ONLINE_TOKEN_KEY + "*");
         List<UserOnlineDTO> userOnlineDTOList = new ArrayList<>();
         for (String key : keys) {
             String token = StringUtils.substringAfterLast(key, ":");
@@ -113,7 +114,7 @@
      * @param tokenId token鍊�
      */
     @Log(title = "鍦ㄧ嚎璁惧", businessType = BusinessType.FORCE)
-    @PostMapping("/{tokenId}")
+    @DeleteMapping("/myself/{tokenId}")
     public R<Void> remove(@PathVariable("tokenId") String tokenId) {
         try {
             // 鑾峰彇鎸囧畾璐﹀彿 id 鐨� token 闆嗗悎
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java
index 13be4a4..eaed068 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java
@@ -97,7 +97,7 @@
     @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.UPDATE)
     @PutMapping("/changeStatus")
     public R<Void> changeStatus(@RequestBody SysClientBo bo) {
-        return toAjax(sysClientService.updateUserStatus(bo.getClientId(), bo.getStatus()));
+        return toAjax(sysClientService.updateClientStatus(bo.getClientId(), bo.getStatus()));
     }
 
     /**
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
index 968bbe9..45b8418 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
@@ -3,7 +3,7 @@
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.hutool.core.convert.Convert;
 import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.log.annotation.Log;
@@ -94,7 +94,7 @@
             return R.fail("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
         } else if (dept.getParentId().equals(deptId)) {
             return R.fail("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛屼笂绾ч儴闂ㄤ笉鑳芥槸鑷繁");
-        } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())) {
+        } else if (StringUtils.equals(SystemConstants.DISABLE, dept.getStatus())) {
             if (deptService.selectNormalChildrenDeptById(deptId) > 0) {
                 return R.fail("璇ラ儴闂ㄥ寘鍚湭鍋滅敤鐨勫瓙閮ㄩ棬!");
             } else if (deptService.checkDeptExistUser(deptId)) {
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java
index e5daa0e..d8cd335 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java
@@ -4,8 +4,9 @@
 import cn.dev33.satoken.annotation.SaCheckRole;
 import cn.dev33.satoken.annotation.SaMode;
 import cn.hutool.core.lang.tree.Tree;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.constant.TenantConstants;
-import org.dromara.common.core.constant.UserConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.log.annotation.Log;
@@ -18,7 +19,6 @@
 import org.dromara.system.domain.vo.RouterVo;
 import org.dromara.system.domain.vo.SysMenuVo;
 import org.dromara.system.service.ISysMenuService;
-import lombok.RequiredArgsConstructor;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -128,7 +128,7 @@
     public R<Void> add(@Validated @RequestBody SysMenuBo menu) {
         if (!menuService.checkMenuNameUnique(menu)) {
             return R.fail("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
-        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
+        } else if (SystemConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
             return R.fail("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
         }
         return toAjax(menuService.insertMenu(menu));
@@ -144,7 +144,7 @@
     public R<Void> edit(@Validated @RequestBody SysMenuBo menu) {
         if (!menuService.checkMenuNameUnique(menu)) {
             return R.fail("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
-        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
+        } else if (SystemConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
             return R.fail("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
         } else if (menu.getMenuId().equals(menu.getParentId())) {
             return R.fail("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屼笂绾ц彍鍗曚笉鑳介�夋嫨鑷繁");
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java
index 73ada3b..81200c1 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java
@@ -53,7 +53,7 @@
      *
      * @param ossIds OSS瀵硅薄ID涓�
      */
-    @SaCheckPermission("system:oss:list")
+    @SaCheckPermission("system:oss:query")
     @GetMapping("/listByIds/{ossIds}")
     public R<List<SysOssVo>> listByIds(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
                                        @PathVariable Long[] ossIds) {
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java
index 782bcfc..5333a4a 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java
@@ -4,7 +4,7 @@
 import cn.hutool.core.util.ObjectUtil;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.excel.utils.ExcelUtil;
 import org.dromara.common.log.annotation.Log;
@@ -91,7 +91,7 @@
             return R.fail("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
         } else if (!postService.checkPostCodeUnique(post)) {
             return R.fail("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
-        } else if (UserConstants.POST_DISABLE.equals(post.getStatus())
+        } else if (SystemConstants.DISABLE.equals(post.getStatus())
             && postService.countUserPostById(post.getPostId()) > 0) {
             return R.fail("璇ュ矖浣嶄笅瀛樺湪宸插垎閰嶇敤鎴凤紝涓嶈兘绂佺敤!");
         }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
index 893b381..5f187cb 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
@@ -98,8 +98,8 @@
         if (BCrypt.checkpw(bo.getNewPassword(), password)) {
             return R.fail("鏂板瘑鐮佷笉鑳戒笌鏃у瘑鐮佺浉鍚�");
         }
-
-        if (userService.resetUserPwd(user.getUserId(), BCrypt.hashpw(bo.getNewPassword())) > 0) {
+        int rows = DataPermissionHelper.ignore(() -> userService.resetUserPwd(user.getUserId(), BCrypt.hashpw(bo.getNewPassword())));
+        if (rows > 0) {
             return R.ok();
         }
         return R.fail("淇敼瀵嗙爜寮傚父锛岃鑱旂郴绠$悊鍛�");
@@ -121,7 +121,8 @@
             }
             SysOssVo oss = ossService.upload(avatarfile);
             String avatar = oss.getUrl();
-            if (userService.updateUserAvatar(LoginHelper.getUserId(), oss.getOssId())) {
+            boolean updateSuccess = DataPermissionHelper.ignore(() -> userService.updateUserAvatar(LoginHelper.getUserId(), oss.getOssId()));
+            if (updateSuccess) {
                 AvatarVo avatarVo = new AvatarVo();
                 avatarVo.setImgUrl(avatar);
                 return R.ok(avatarVo);
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
index bad240c..66c1b7d 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
@@ -59,7 +59,7 @@
      */
     @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
     @SaCheckPermission("system:tenant:export")
-    @Log(title = "绉熸埛", businessType = BusinessType.EXPORT)
+    @Log(title = "绉熸埛绠$悊", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     public void export(SysTenantBo bo, HttpServletResponse response) {
         List<SysTenantVo> list = tenantService.queryList(bo);
@@ -85,7 +85,7 @@
     @ApiEncrypt
     @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
     @SaCheckPermission("system:tenant:add")
-    @Log(title = "绉熸埛", businessType = BusinessType.INSERT)
+    @Log(title = "绉熸埛绠$悊", businessType = BusinessType.INSERT)
     @Lock4j
     @RepeatSubmit()
     @PostMapping()
@@ -101,7 +101,7 @@
      */
     @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
     @SaCheckPermission("system:tenant:edit")
-    @Log(title = "绉熸埛", businessType = BusinessType.UPDATE)
+    @Log(title = "绉熸埛绠$悊", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
     @PutMapping()
     public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysTenantBo bo) {
@@ -117,7 +117,7 @@
      */
     @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
     @SaCheckPermission("system:tenant:edit")
-    @Log(title = "绉熸埛", businessType = BusinessType.UPDATE)
+    @Log(title = "绉熸埛绠$悊", businessType = BusinessType.UPDATE)
     @PutMapping("/changeStatus")
     public R<Void> changeStatus(@RequestBody SysTenantBo bo) {
         tenantService.checkTenantAllowed(bo.getTenantId());
@@ -131,7 +131,7 @@
      */
     @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
     @SaCheckPermission("system:tenant:remove")
-    @Log(title = "绉熸埛", businessType = BusinessType.DELETE)
+    @Log(title = "绉熸埛绠$悊", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
     public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
                           @PathVariable Long[] ids) {
@@ -169,11 +169,25 @@
      */
     @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
     @SaCheckPermission("system:tenant:edit")
-    @Log(title = "绉熸埛", businessType = BusinessType.UPDATE)
+    @Log(title = "绉熸埛绠$悊", businessType = BusinessType.UPDATE)
     @GetMapping("/syncTenantPackage")
     public R<Void> syncTenantPackage(@NotBlank(message = "绉熸埛ID涓嶈兘涓虹┖") String tenantId,
                                      @NotNull(message = "濂楅ID涓嶈兘涓虹┖") Long packageId) {
         return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId)));
     }
 
+    /**
+     * 鍚屾绉熸埛瀛楀吀
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @Log(title = "绉熸埛绠$悊", businessType = BusinessType.INSERT)
+    @GetMapping("/syncTenantDict")
+    public R<Void> syncTenantDict() {
+        if (!TenantHelper.isEnable()) {
+            return R.fail("褰撳墠鏈紑鍚鎴锋ā寮�");
+        }
+        tenantService.syncTenantDict();
+        return R.ok("鍚屾绉熸埛瀛楀吀鎴愬姛");
+    }
+
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
index 36104d6..e1e868a 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
@@ -8,7 +8,7 @@
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.utils.StreamUtils;
@@ -128,13 +128,9 @@
     @SaCheckPermission("system:user:query")
     @GetMapping(value = {"/", "/{userId}"})
     public R<SysUserInfoVo> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
-        userService.checkUserDataScope(userId);
         SysUserInfoVo userInfoVo = new SysUserInfoVo();
-        SysRoleBo roleBo = new SysRoleBo();
-        roleBo.setStatus(UserConstants.ROLE_NORMAL);
-        List<SysRoleVo> roles = roleService.selectRoleList(roleBo);
-        userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));
         if (ObjectUtil.isNotNull(userId)) {
+            userService.checkUserDataScope(userId);
             SysUserVo sysUser = userService.selectUserById(userId);
             userInfoVo.setUser(sysUser);
             userInfoVo.setRoleIds(roleService.selectRoleListByUserId(userId));
@@ -146,6 +142,10 @@
                 userInfoVo.setPostIds(postService.selectPostListByUserId(userId));
             }
         }
+        SysRoleBo roleBo = new SysRoleBo();
+        roleBo.setStatus(SystemConstants.NORMAL);
+        List<SysRoleVo> roles = roleService.selectRoleList(roleBo);
+        userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));
         return R.ok(userInfoVo);
     }
 
@@ -218,7 +218,7 @@
     @GetMapping("/optionselect")
     public R<List<SysUserVo>> optionselect(@RequestParam(required = false) Long[] userIds,
                                            @RequestParam(required = false) Long deptId) {
-        return R.ok(userService.selectUserByIds(userIds == null ? null : List.of(userIds), deptId));
+        return R.ok(userService.selectUserByIds(ArrayUtil.isEmpty(userIds) ? null : List.of(userIds), deptId));
     }
 
     /**
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java
index 0f681be..ee2475d 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java
@@ -68,7 +68,7 @@
     private String status;
 
     /**
-     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�
      */
     @TableLogic
     private String delFlag;
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java
index 48ca682..b94fd8a 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java
@@ -70,7 +70,7 @@
     private String status;
 
     /**
-     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�
      */
     @TableLogic
     private String delFlag;
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java
index 6884fc2..9d83736 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java
@@ -2,10 +2,10 @@
 
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
-import org.dromara.common.core.constant.UserConstants;
-import org.dromara.common.tenant.core.TenantEntity;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import org.dromara.common.core.constant.SystemConstants;
+import org.dromara.common.tenant.core.TenantEntity;
 
 /**
  * 瀛楀吀鏁版嵁琛� sys_dict_data
@@ -65,7 +65,7 @@
     private String remark;
 
     public boolean getDefault() {
-        return UserConstants.YES.equals(this.isDefault);
+        return SystemConstants.YES.equals(this.isDefault);
     }
 
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java
index 6b498a3..2df5596 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java
@@ -3,12 +3,12 @@
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
-import org.dromara.common.core.constant.Constants;
-import org.dromara.common.core.constant.UserConstants;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.mybatis.core.domain.BaseEntity;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.SystemConstants;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -134,8 +134,8 @@
             routerPath = innerLinkReplaceEach(routerPath);
         }
         // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓虹洰褰曪級
-        if (0L == getParentId() && UserConstants.TYPE_DIR.equals(getMenuType())
-            && UserConstants.NO_FRAME.equals(getIsFrame())) {
+        if (0L == getParentId() && SystemConstants.TYPE_DIR.equals(getMenuType())
+            && SystemConstants.NO_FRAME.equals(getIsFrame())) {
             routerPath = "/" + this.path;
         }
         // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓鸿彍鍗曪級
@@ -149,13 +149,13 @@
      * 鑾峰彇缁勪欢淇℃伅
      */
     public String getComponentInfo() {
-        String component = UserConstants.LAYOUT;
+        String component = SystemConstants.LAYOUT;
         if (StringUtils.isNotEmpty(this.component) && !isMenuFrame()) {
             component = this.component;
         } else if (StringUtils.isEmpty(this.component) && getParentId() != 0L && isInnerLink()) {
-            component = UserConstants.INNER_LINK;
+            component = SystemConstants.INNER_LINK;
         } else if (StringUtils.isEmpty(this.component) && isParentView()) {
-            component = UserConstants.PARENT_VIEW;
+            component = SystemConstants.PARENT_VIEW;
         }
         return component;
     }
@@ -164,21 +164,21 @@
      * 鏄惁涓鸿彍鍗曞唴閮ㄨ烦杞�
      */
     public boolean isMenuFrame() {
-        return getParentId() == 0L && UserConstants.TYPE_MENU.equals(menuType) && isFrame.equals(UserConstants.NO_FRAME);
+        return getParentId() == 0L && SystemConstants.TYPE_MENU.equals(menuType) && isFrame.equals(SystemConstants.NO_FRAME);
     }
 
     /**
      * 鏄惁涓哄唴閾剧粍浠�
      */
     public boolean isInnerLink() {
-        return isFrame.equals(UserConstants.NO_FRAME) && StringUtils.ishttp(path);
+        return isFrame.equals(SystemConstants.NO_FRAME) && StringUtils.ishttp(path);
     }
 
     /**
      * 鏄惁涓簆arent_view缁勪欢
      */
     public boolean isParentView() {
-        return getParentId() != 0L && UserConstants.TYPE_DIR.equals(menuType);
+        return getParentId() != 0L && SystemConstants.TYPE_DIR.equals(menuType);
     }
 
     /**
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java
index 2b42464..a7c0ad5 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java
@@ -62,7 +62,7 @@
     private String status;
 
     /**
-     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�
      */
     @TableLogic
     private String delFlag;
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java
index a564a40..9800c30 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java
@@ -95,7 +95,7 @@
     private String status;
 
     /**
-     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�
      */
     @TableLogic
     private String delFlag;
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java
index f7e423f..5f58e3e 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java
@@ -25,28 +25,34 @@
      */
     @TableId(value = "package_id")
     private Long packageId;
+
     /**
      * 濂楅鍚嶇О
      */
     private String packageName;
+
     /**
      * 鍏宠仈鑿滃崟id
      */
     private String menuIds;
+
     /**
      * 澶囨敞
      */
     private String remark;
+
     /**
      * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙 0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀猴級
      */
     private Boolean menuCheckStrictly;
+
     /**
      * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
      */
     private String status;
+
     /**
-     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�
      */
     @TableLogic
     private String delFlag;
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java
index 8dde40b..3712f80 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java
@@ -1,11 +1,11 @@
 package org.dromara.system.domain;
 
 import com.baomidou.mybatisplus.annotation.*;
-import org.dromara.common.core.constant.UserConstants;
-import org.dromara.common.tenant.core.TenantEntity;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
+import org.dromara.common.core.constant.SystemConstants;
+import org.dromara.common.tenant.core.TenantEntity;
 
 import java.util.Date;
 
@@ -83,7 +83,7 @@
     private String status;
 
     /**
-     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�
      */
     @TableLogic
     private String delFlag;
@@ -109,7 +109,7 @@
     }
 
     public boolean isSuperAdmin() {
-        return UserConstants.SUPER_ADMIN_ID.equals(this.userId);
+        return SystemConstants.SUPER_ADMIN_ID.equals(this.userId);
     }
 
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java
index 0c8b4dc..3207bad 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java
@@ -7,7 +7,7 @@
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.mybatis.core.domain.BaseEntity;
 import org.dromara.system.domain.SysRole;
 
@@ -88,7 +88,7 @@
     }
 
     public boolean isSuperAdmin() {
-        return UserConstants.SUPER_ADMIN_ID.equals(this.roleId);
+        return SystemConstants.SUPER_ADMIN_ID.equals(this.roleId);
     }
 
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
index 7ad2759..2669a81 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
@@ -7,7 +7,7 @@
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.xss.Xss;
 import org.dromara.common.mybatis.core.domain.BaseEntity;
 import org.dromara.system.domain.SysUser;
@@ -113,7 +113,7 @@
     }
 
     public boolean isSuperAdmin() {
-        return UserConstants.SUPER_ADMIN_ID.equals(this.userId);
+        return SystemConstants.SUPER_ADMIN_ID.equals(this.userId);
     }
 
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java
index 1e5cd9e..ffb2c6d 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java
@@ -2,12 +2,12 @@
 
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
-import org.dromara.common.core.constant.UserConstants;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.excel.annotation.ExcelDictFormat;
 import org.dromara.common.excel.convert.ExcelDictConvert;
 import org.dromara.system.domain.SysRole;
-import io.github.linpeilie.annotations.AutoMapper;
-import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
@@ -94,7 +94,7 @@
     private boolean flag = false;
 
     public boolean isSuperAdmin() {
-        return UserConstants.SUPER_ADMIN_ID.equals(this.roleId);
+        return SystemConstants.SUPER_ADMIN_ID.equals(this.roleId);
     }
 
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java
index c20a4ec..25b62a9 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java
@@ -3,10 +3,14 @@
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.crypto.digest.BCrypt;
+import cn.hutool.http.HtmlUtil;
 import com.alibaba.excel.context.AnalysisContext;
 import com.alibaba.excel.event.AnalysisEventListener;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.ValidatorUtils;
 import org.dromara.common.excel.core.ExcelListener;
 import org.dromara.common.excel.core.ExcelResult;
@@ -79,8 +83,12 @@
             }
         } catch (Exception e) {
             failureNum++;
-            String msg = "<br/>" + failureNum + "銆佽处鍙� " + userVo.getUserName() + " 瀵煎叆澶辫触锛�";
-            failureMsg.append(msg).append(e.getMessage());
+            String msg = "<br/>" + failureNum + "銆佽处鍙� " + HtmlUtil.cleanHtmlTag(userVo.getUserName()) + " 瀵煎叆澶辫触锛�";
+            String message = e.getMessage();
+            if (e instanceof ConstraintViolationException cvException) {
+                message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
+            }
+            failureMsg.append(msg).append(message);
             log.error(msg, e);
         }
     }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java
index 08dda66..b69624c 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java
@@ -1,13 +1,16 @@
 package org.dromara.system.mapper;
 
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
 import org.dromara.common.mybatis.annotation.DataColumn;
 import org.dromara.common.mybatis.annotation.DataPermission;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
 import org.dromara.system.domain.SysDept;
 import org.dromara.system.domain.vo.SysDeptVo;
-import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -29,12 +32,41 @@
     })
     List<SysDeptVo> selectDeptList(@Param(Constants.WRAPPER) Wrapper<SysDept> queryWrapper);
 
+    /**
+     * 鍒嗛〉鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+     *
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 閮ㄩ棬淇℃伅闆嗗悎
+     */
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+    })
+    Page<SysDeptVo> selectPageDeptList(@Param("page") Page<SysDeptVo> page, @Param(Constants.WRAPPER) Wrapper<SysDept> queryWrapper);
+
+    /**
+     * 缁熻鎸囧畾閮ㄩ棬ID鐨勯儴闂ㄦ暟閲�
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 璇ラ儴闂↖D鐨勯儴闂ㄦ暟閲�
+     */
     @DataPermission({
         @DataColumn(key = "deptName", value = "dept_id")
     })
     long countDeptById(Long deptId);
 
     /**
+     * 鏍规嵁鐖堕儴闂↖D鏌ヨ鍏舵墍鏈夊瓙閮ㄩ棬鐨勫垪琛�
+     *
+     * @param parentId 鐖堕儴闂↖D
+     * @return 鍖呭惈瀛愰儴闂ㄧ殑鍒楄〃
+     */
+    default List<SysDept> selectListByParentId(Long parentId) {
+        return this.selectList(new LambdaQueryWrapper<SysDept>()
+            .select(SysDept::getDeptId)
+            .apply(DataBaseHelper.findInSet(parentId, "ancestors")));
+    }
+
+    /**
      * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
      *
      * @param roleId            瑙掕壊ID
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java
index c2f1a7c..7298db3 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java
@@ -14,6 +14,12 @@
  */
 public interface SysDictDataMapper extends BaseMapperPlus<SysDictData, SysDictDataVo> {
 
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁鍒楄〃
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 绗﹀悎鏉′欢鐨勫瓧鍏告暟鎹垪琛�
+     */
     default List<SysDictDataVo> selectDictDataByType(String dictType) {
         return selectVoList(
             new LambdaQueryWrapper<SysDictData>()
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java
index ac646c0..205413b 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java
@@ -3,11 +3,11 @@
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
-import org.dromara.common.core.constant.UserConstants;
-import org.dromara.system.domain.SysMenu;
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-import org.dromara.system.domain.vo.SysMenuVo;
 import org.apache.ibatis.annotations.Param;
+import org.dromara.common.core.constant.SystemConstants;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysMenu;
+import org.dromara.system.domain.vo.SysMenuVo;
 
 import java.util.List;
 
@@ -49,8 +49,8 @@
      */
     default List<SysMenu> selectMenuTreeAll() {
         LambdaQueryWrapper<SysMenu> lqw = new LambdaQueryWrapper<SysMenu>()
-            .in(SysMenu::getMenuType, UserConstants.TYPE_DIR, UserConstants.TYPE_MENU)
-            .eq(SysMenu::getStatus, UserConstants.MENU_NORMAL)
+            .in(SysMenu::getMenuType, SystemConstants.TYPE_DIR, SystemConstants.TYPE_MENU)
+            .eq(SysMenu::getStatus, SystemConstants.NORMAL)
             .orderByAsc(SysMenu::getParentId)
             .orderByAsc(SysMenu::getOrderNum);
         return this.selectList(lqw);
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java
index f9bf134..60da074 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java
@@ -19,6 +19,13 @@
  */
 public interface SysPostMapper extends BaseMapperPlus<SysPost, SysPostVo> {
 
+    /**
+     * 鍒嗛〉鏌ヨ宀椾綅鍒楄〃
+     *
+     * @param page         鍒嗛〉瀵硅薄
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 鍖呭惈宀椾綅淇℃伅鐨勫垎椤电粨鏋�
+     */
     @DataPermission({
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "create_by")
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java
index ac5a47e..9cb1ea5 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java
@@ -19,6 +19,13 @@
  */
 public interface SysRoleMapper extends BaseMapperPlus<SysRole, SysRoleVo> {
 
+    /**
+     * 鍒嗛〉鏌ヨ瑙掕壊鍒楄〃
+     *
+     * @param page         鍒嗛〉瀵硅薄
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 鍖呭惈瑙掕壊淇℃伅鐨勫垎椤电粨鏋�
+     */
     @DataPermission({
         @DataColumn(key = "deptName", value = "d.dept_id"),
         @DataColumn(key = "userName", value = "r.create_by")
@@ -37,6 +44,12 @@
     })
     List<SysRoleVo> selectRoleList(@Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
 
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ瑙掕壊淇℃伅
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 瀵瑰簲鐨勮鑹蹭俊鎭�
+     */
     @DataPermission({
         @DataColumn(key = "deptName", value = "d.dept_id"),
         @DataColumn(key = "userName", value = "r.create_by")
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
index fc7fc6e..46695aa 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
@@ -20,12 +20,25 @@
  */
 public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
 
+    /**
+     * 鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃锛屽苟杩涜鏁版嵁鏉冮檺鎺у埗
+     *
+     * @param page         鍒嗛〉鍙傛暟
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 鍒嗛〉鐨勭敤鎴蜂俊鎭�
+     */
     @DataPermission({
         @DataColumn(key = "deptName", value = "u.dept_id"),
         @DataColumn(key = "userName", value = "u.user_id")
     })
     Page<SysUserVo> selectPageUserList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
 
+    /**
+     * 鏌ヨ鐢ㄦ埛鍒楄〃锛屽苟杩涜鏁版嵁鏉冮檺鎺у埗
+     *
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎
+     */
     @DataPermission({
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "user_id")
@@ -68,12 +81,25 @@
     })
     Page<SysUserVo> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
 
+    /**
+     * 鏍规嵁鐢ㄦ埛ID缁熻鐢ㄦ埛鏁伴噺
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛鏁伴噺
+     */
     @DataPermission({
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "user_id")
     })
     long countUserById(Long userId);
 
+    /**
+     * 鏍规嵁鏉′欢鏇存柊鐢ㄦ埛鏁版嵁
+     *
+     * @param user          瑕佹洿鏂扮殑鐢ㄦ埛瀹炰綋
+     * @param updateWrapper 鏇存柊鏉′欢灏佽鍣�
+     * @return 鏇存柊鎿嶄綔褰卞搷鐨勮鏁�
+     */
     @Override
     @DataPermission({
         @DataColumn(key = "deptName", value = "dept_id"),
@@ -81,6 +107,12 @@
     })
     int update(@Param(Constants.ENTITY) SysUser user, @Param(Constants.WRAPPER) Wrapper<SysUser> updateWrapper);
 
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏇存柊鐢ㄦ埛鏁版嵁
+     *
+     * @param user 瑕佹洿鏂扮殑鐢ㄦ埛瀹炰綋
+     * @return 鏇存柊鎿嶄綔褰卞搷鐨勮鏁�
+     */
     @Override
     @DataPermission({
         @DataColumn(key = "deptName", value = "dept_id"),
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java
index e2f706c..8340348 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java
@@ -12,6 +12,12 @@
  */
 public interface SysUserRoleMapper extends BaseMapperPlus<SysUserRole, SysUserRole> {
 
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鍏宠仈鐨勭敤鎴稩D鍒楄〃
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 鍏宠仈鍒版寚瀹氳鑹茬殑鐢ㄦ埛ID鍒楄〃
+     */
     List<Long> selectUserIdsByRoleId(Long roleId);
 
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java
index d0f8a3c..546c3f3 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java
@@ -50,7 +50,7 @@
     /**
      * 淇敼鐘舵��
      */
-    int updateUserStatus(String clientId, String status);
+    int updateClientStatus(String clientId, String status);
 
     /**
      * 鏍¢獙骞舵壒閲忓垹闄ゅ鎴风绠$悊淇℃伅
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
index 3751b23..a760d49 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
@@ -26,6 +26,14 @@
     List<SysPostVo> selectPostList(SysPostBo post);
 
     /**
+     * 鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 宀椾綅ID
+     */
+    List<SysPostVo> selectPostsByUserId(Long userId);
+
+    /**
      * 鏌ヨ鎵�鏈夊矖浣�
      *
      * @return 宀椾綅鍒楄〃
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java
index 64740ae..cec4bf7 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java
@@ -197,4 +197,6 @@
 
     void cleanOnlineUserByRole(Long roleId);
 
+    void cleanOnlineUser(List<Long> userIds);
+
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java
index d12ed95..f697829 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java
@@ -79,4 +79,9 @@
      * 鍚屾绉熸埛濂楅
      */
     Boolean syncTenantPackage(String tenantId, Long packageId);
+
+    /**
+     * 鍚屾绉熸埛瀛楀吀
+     */
+    void syncTenantDict();
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
index 1c69243..4f6e676 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
@@ -123,7 +123,7 @@
      */
     @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId")
     @Override
-    public int updateUserStatus(String clientId, String status) {
+    public int updateClientStatus(String clientId, String status) {
         return baseMapper.update(null,
             new LambdaUpdateWrapper<SysClient>()
                 .set(SysClient::getStatus, status)
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java
index 46526bd..d92647c 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java
@@ -7,10 +7,11 @@
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.dromara.common.core.constant.CacheNames;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.service.ConfigService;
 import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.ObjectUtils;
 import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
@@ -72,10 +73,7 @@
     public String selectConfigByKey(String configKey) {
         SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
             .eq(SysConfig::getConfigKey, configKey));
-        if (ObjectUtil.isNotNull(retConfig)) {
-            return retConfig.getConfigValue();
-        }
-        return StringUtils.EMPTY;
+        return ObjectUtils.notNullGetter(retConfig, SysConfig::getConfigValue, StringUtils.EMPTY);
     }
 
     /**
@@ -173,7 +171,7 @@
     public void deleteConfigByIds(Long[] configIds) {
         for (Long configId : configIds) {
             SysConfig config = baseMapper.selectById(configId);
-            if (StringUtils.equals(UserConstants.YES, config.getConfigType())) {
+            if (StringUtils.equals(SystemConstants.YES, config.getConfigType())) {
                 throw new ServiceException(String.format("鍐呯疆鍙傛暟銆�%1$s銆戜笉鑳藉垹闄� ", config.getConfigKey()));
             }
             CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey());
@@ -197,7 +195,7 @@
      */
     @Override
     public boolean checkConfigKeyUnique(SysConfigBo config) {
-        long configId = ObjectUtil.isNull(config.getConfigId()) ? -1L : config.getConfigId();
+        long configId = ObjectUtils.notNull(config.getConfigId(), -1L);
         SysConfig info = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, config.getConfigKey()));
         if (ObjectUtil.isNotNull(info) && info.getConfigId() != configId) {
             return false;
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
index 018f9a0..12a5072 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
@@ -5,13 +5,14 @@
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.utils.StreamUtils;
-import org.dromara.common.mybatis.helper.DataBaseHelper;
 import org.dromara.system.domain.SysDept;
 import org.dromara.system.domain.SysRoleDept;
 import org.dromara.system.mapper.SysDeptMapper;
 import org.dromara.system.mapper.SysRoleDeptMapper;
 import org.dromara.system.service.ISysDataScopeService;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -37,6 +38,7 @@
      * @param roleId 瑙掕壊Id
      * @return 閮ㄩ棬Id缁�
      */
+    @Cacheable(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId", condition = "#roleId != null")
     @Override
     public String getRoleCustom(Long roleId) {
         if (ObjectUtil.isNull(roleId)) {
@@ -58,14 +60,13 @@
      * @param deptId 閮ㄩ棬Id
      * @return 閮ㄩ棬Id缁�
      */
+    @Cacheable(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId", condition = "#deptId != null")
     @Override
     public String getDeptAndChild(Long deptId) {
         if (ObjectUtil.isNull(deptId)) {
             return "-1";
         }
-        List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
-            .select(SysDept::getDeptId)
-            .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
+        List<SysDept> deptList = deptMapper.selectListByParentId(deptId);
         List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
         ids.add(deptId);
         if (CollUtil.isNotEmpty(ids)) {
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
index 160238d..ca062be 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
@@ -1,5 +1,6 @@
 package org.dromara.system.service.impl;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.lang.tree.Tree;
@@ -9,13 +10,11 @@
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.constant.CacheNames;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
+import org.dromara.common.core.domain.dto.DeptDTO;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.service.DeptService;
-import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.core.utils.SpringUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.core.utils.TreeBuildUtils;
+import org.dromara.common.core.utils.*;
 import org.dromara.common.mybatis.helper.DataBaseHelper;
 import org.dromara.common.redis.utils.CacheUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
@@ -30,7 +29,9 @@
 import org.dromara.system.service.ISysDeptService;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
+import org.springframework.cache.annotation.Caching;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -69,8 +70,6 @@
      */
     @Override
     public List<Tree<Long>> selectDeptTreeList(SysDeptBo bo) {
-        // 鍙煡璇㈡湭绂佺敤閮ㄩ棬
-        bo.setStatus(UserConstants.DEPT_NORMAL);
         LambdaQueryWrapper<SysDept> lqw = buildQueryWrapper(bo);
         List<SysDeptVo> depts = baseMapper.selectDeptList(lqw);
         return buildDeptTreeSelect(depts);
@@ -78,7 +77,7 @@
 
     private LambdaQueryWrapper<SysDept> buildQueryWrapper(SysDeptBo bo) {
         LambdaQueryWrapper<SysDept> lqw = Wrappers.lambdaQuery();
-        lqw.eq(SysDept::getDelFlag, UserConstants.DEL_FLAG_NORMAL);
+        lqw.eq(SysDept::getDelFlag, SystemConstants.NORMAL);
         lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId());
         lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId());
         lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
@@ -102,11 +101,23 @@
         if (CollUtil.isEmpty(depts)) {
             return CollUtil.newArrayList();
         }
-        return TreeBuildUtils.build(depts, (dept, tree) ->
-            tree.setId(dept.getDeptId())
-                .setParentId(dept.getParentId())
-                .setName(dept.getDeptName())
-                .setWeight(dept.getOrderNum()));
+        // 鑾峰彇褰撳墠鍒楄〃涓瘡涓�涓妭鐐圭殑parentId锛岀劧鍚庡湪鍒楄〃涓煡鎵炬槸鍚︽湁id涓庡叾parentId瀵瑰簲锛岃嫢鏃犲搴旓紝鍒欒〃鏄庢鏃惰妭鐐瑰垪琛ㄤ腑锛岃鑺傜偣鍦ㄥ綋鍓嶅垪琛ㄤ腑灞炰簬椤剁骇鑺傜偣
+        List<Tree<Long>> treeList = CollUtil.newArrayList();
+        for (SysDeptVo d : depts) {
+            Long parentId = d.getParentId();
+            SysDeptVo sysDeptVo = StreamUtils.findFirst(depts, it -> it.getDeptId().longValue() == parentId);
+            if (ObjectUtil.isNull(sysDeptVo)) {
+                List<Tree<Long>> trees = TreeBuildUtils.build(depts, parentId, (dept, tree) ->
+                    tree.setId(dept.getDeptId())
+                        .setParentId(dept.getParentId())
+                        .setName(dept.getDeptName())
+                        .setWeight(dept.getOrderNum())
+                        .putExtra("disabled", SystemConstants.DISABLE.equals(dept.getStatus())));
+                Tree<Long> tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId());
+                treeList.add(tree);
+            }
+        }
+        return treeList;
     }
 
     /**
@@ -136,7 +147,7 @@
         }
         SysDeptVo parentDept = baseMapper.selectVoOne(new LambdaQueryWrapper<SysDept>()
             .select(SysDept::getDeptName).eq(SysDept::getDeptId, dept.getParentId()));
-        dept.setParentName(ObjectUtil.isNotNull(parentDept) ? parentDept.getDeptName() : null);
+        dept.setParentName(ObjectUtils.notNullGetter(parentDept, SysDeptVo::getDeptName));
         return dept;
     }
 
@@ -144,7 +155,7 @@
     public List<SysDeptVo> selectDeptByIds(List<Long> deptIds) {
         return baseMapper.selectDeptList(new LambdaQueryWrapper<SysDept>()
             .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getLeader)
-            .eq(SysDept::getStatus, UserConstants.DEPT_NORMAL)
+            .eq(SysDept::getStatus, SystemConstants.NORMAL)
             .in(CollUtil.isNotEmpty(deptIds), SysDept::getDeptId, deptIds));
     }
 
@@ -167,6 +178,31 @@
     }
 
     /**
+     * 鏍规嵁閮ㄩ棬ID鏌ヨ閮ㄩ棬璐熻矗浜�
+     *
+     * @param deptId 閮ㄩ棬ID锛岀敤浜庢寚瀹氶渶瑕佹煡璇㈢殑閮ㄩ棬
+     * @return 杩斿洖璇ラ儴闂ㄧ殑璐熻矗浜篒D
+     */
+    @Override
+    public Long selectDeptLeaderById(Long deptId) {
+        SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(deptId);
+        return vo.getLeader();
+    }
+
+    /**
+     * 鏌ヨ閮ㄩ棬
+     *
+     * @return 閮ㄩ棬鍒楄〃
+     */
+    @Override
+    public List<DeptDTO> selectDeptsByList() {
+        List<SysDeptVo> list = baseMapper.selectDeptList(new LambdaQueryWrapper<SysDept>()
+            .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getParentId)
+            .eq(SysDept::getStatus, SystemConstants.NORMAL));
+        return BeanUtil.copyToList(list, DeptDTO.class);
+    }
+
+    /**
      * 鏍规嵁ID鏌ヨ鎵�鏈夊瓙閮ㄩ棬鏁帮紙姝e父鐘舵�侊級
      *
      * @param deptId 閮ㄩ棬ID
@@ -175,7 +211,7 @@
     @Override
     public long selectNormalChildrenDeptById(Long deptId) {
         return baseMapper.selectCount(new LambdaQueryWrapper<SysDept>()
-            .eq(SysDept::getStatus, UserConstants.DEPT_NORMAL)
+            .eq(SysDept::getStatus, SystemConstants.NORMAL)
             .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
     }
 
@@ -242,11 +278,12 @@
      * @param bo 閮ㄩ棬淇℃伅
      * @return 缁撴灉
      */
+    @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true)
     @Override
     public int insertDept(SysDeptBo bo) {
         SysDept info = baseMapper.selectById(bo.getParentId());
         // 濡傛灉鐖惰妭鐐逛笉涓烘甯哥姸鎬�,鍒欎笉鍏佽鏂板瀛愯妭鐐�
-        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) {
+        if (!SystemConstants.NORMAL.equals(info.getStatus())) {
             throw new ServiceException("閮ㄩ棬鍋滅敤锛屼笉鍏佽鏂板");
         }
         SysDept dept = MapstructUtils.convert(bo, SysDept.class);
@@ -260,25 +297,34 @@
      * @param bo 閮ㄩ棬淇℃伅
      * @return 缁撴灉
      */
-    @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#bo.deptId")
+    @Caching(evict = {
+        @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#bo.deptId"),
+        @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true)
+    })
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public int updateDept(SysDeptBo bo) {
         SysDept dept = MapstructUtils.convert(bo, SysDept.class);
         SysDept oldDept = baseMapper.selectById(dept.getDeptId());
+        if (ObjectUtil.isNull(oldDept)) {
+            throw new ServiceException("閮ㄩ棬涓嶅瓨鍦紝鏃犳硶淇敼");
+        }
         if (!oldDept.getParentId().equals(dept.getParentId())) {
             // 濡傛灉鏄柊鐖堕儴闂� 鍒欐牎楠屾槸鍚﹀叿鏈夋柊鐖堕儴闂ㄦ潈闄� 閬垮厤瓒婃潈
             this.checkDeptDataScope(dept.getParentId());
             SysDept newParentDept = baseMapper.selectById(dept.getParentId());
-            if (ObjectUtil.isNotNull(newParentDept) && ObjectUtil.isNotNull(oldDept)) {
+            if (ObjectUtil.isNotNull(newParentDept)) {
                 String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId();
                 String oldAncestors = oldDept.getAncestors();
                 dept.setAncestors(newAncestors);
                 updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
             }
+        } else {
+            dept.setAncestors(oldDept.getAncestors());
         }
         int result = baseMapper.updateById(dept);
-        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
-            && !StringUtils.equals(UserConstants.DEPT_NORMAL, dept.getAncestors())) {
+        if (SystemConstants.NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
+            && !StringUtils.equals(SystemConstants.NORMAL, dept.getAncestors())) {
             // 濡傛灉璇ラ儴闂ㄦ槸鍚敤鐘舵�侊紝鍒欏惎鐢ㄨ閮ㄩ棬鐨勬墍鏈変笂绾ч儴闂�
             updateParentDeptStatusNormal(dept);
         }
@@ -294,7 +340,7 @@
         String ancestors = dept.getAncestors();
         Long[] deptIds = Convert.toLongArray(ancestors);
         baseMapper.update(null, new LambdaUpdateWrapper<SysDept>()
-            .set(SysDept::getStatus, UserConstants.DEPT_NORMAL)
+            .set(SysDept::getStatus, SystemConstants.NORMAL)
             .in(SysDept::getDeptId, Arrays.asList(deptIds)));
     }
 
@@ -328,7 +374,10 @@
      * @param deptId 閮ㄩ棬ID
      * @return 缁撴灉
      */
-    @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#deptId")
+    @Caching(evict = {
+        @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#deptId"),
+        @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId")
+    })
     @Override
     public int deleteDeptById(Long deptId) {
         return baseMapper.deleteById(deptId);
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java
index 1ab0faf..e44fdbc 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java
@@ -6,6 +6,7 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.ObjectUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.system.domain.SysDictData;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -144,7 +145,7 @@
      */
     @Override
     public boolean checkDictDataUnique(SysDictDataBo dict) {
-        Long dictCode = ObjectUtil.isNull(dict.getDictCode()) ? -1L : dict.getDictCode();
+        Long dictCode = ObjectUtils.notNull(dict.getDictCode(), -1L);
         SysDictData entity = baseMapper.selectOne(new LambdaQueryWrapper<SysDictData>()
             .eq(SysDictData::getDictType, dict.getDictType()).eq(SysDictData::getDictValue, dict.getDictValue()));
         if (ObjectUtil.isNotNull(entity) && !dictCode.equals(entity.getDictCode())) {
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
index b95baf4..72b497e 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
@@ -118,8 +118,7 @@
             .between(params.get("beginTime") != null && params.get("endTime") != null,
                 SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime"));
         if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
-            pageQuery.setOrderByColumn("info_id");
-            pageQuery.setIsAsc("desc");
+            lqw.orderByDesc(SysLogininfor::getInfoId);
         }
         Page<SysLogininforVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
         return TableDataInfo.build(page);
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
index af844c9..40643e1 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
@@ -8,7 +8,7 @@
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -196,7 +196,7 @@
             router.setQuery(menu.getQueryParam());
             router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
             List<SysMenu> cMenus = menu.getChildren();
-            if (CollUtil.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
+            if (CollUtil.isNotEmpty(cMenus) && SystemConstants.TYPE_DIR.equals(menu.getMenuType())) {
                 router.setAlwaysShow(true);
                 router.setRedirect("noRedirect");
                 router.setChildren(buildMenus(cMenus));
@@ -220,7 +220,7 @@
                 String routerPath = SysMenu.innerLinkReplaceEach(menu.getPath());
                 String innerLinkName = StringUtils.capitalize(routerPath) + menu.getMenuId();
                 children.setPath(routerPath);
-                children.setComponent(UserConstants.INNER_LINK);
+                children.setComponent(SystemConstants.INNER_LINK);
                 children.setName(innerLinkName);
                 children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
                 childrenList.add(children);
@@ -242,11 +242,14 @@
         if (CollUtil.isEmpty(menus)) {
             return CollUtil.newArrayList();
         }
-        return TreeBuildUtils.build(menus, (menu, tree) ->
-            tree.setId(menu.getMenuId())
+        return TreeBuildUtils.build(menus, (menu, tree) -> {
+            Tree<Long> menuTree = tree.setId(menu.getMenuId())
                 .setParentId(menu.getParentId())
                 .setName(menu.getMenuName())
-                .setWeight(menu.getOrderNum()));
+                .setWeight(menu.getOrderNum());
+            menuTree.put("menuType", menu.getMenuType());
+            menuTree.put("icon", menu.getIcon());
+        });
     }
 
     /**
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java
index db63e61..19a3ff5 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java
@@ -1,10 +1,10 @@
 package org.dromara.system.service.impl;
 
-import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.ObjectUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -70,7 +70,7 @@
         lqw.eq(StringUtils.isNotBlank(bo.getNoticeType()), SysNotice::getNoticeType, bo.getNoticeType());
         if (StringUtils.isNotBlank(bo.getCreateByName())) {
             SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, bo.getCreateByName()));
-            lqw.eq(SysNotice::getCreateBy, ObjectUtil.isNotNull(sysUser) ? sysUser.getUserId() : null);
+            lqw.eq(SysNotice::getCreateBy, ObjectUtils.notNullGetter(sysUser, SysUserVo::getUserId));
         }
         lqw.orderByAsc(SysNotice::getNoticeId);
         return lqw;
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
index b78b9dc..27c2f32 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
@@ -3,18 +3,18 @@
 import cn.hutool.core.util.ArrayUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.core.utils.ip.AddressUtils;
 import org.dromara.common.log.event.OperLogEvent;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.system.domain.SysOperLog;
 import org.dromara.system.domain.bo.SysOperLogBo;
 import org.dromara.system.domain.vo.SysOperLogVo;
 import org.dromara.system.mapper.SysOperLogMapper;
 import org.dromara.system.service.ISysOperLogService;
-import lombok.RequiredArgsConstructor;
 import org.springframework.context.event.EventListener;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
@@ -51,8 +51,17 @@
 
     @Override
     public TableDataInfo<SysOperLogVo> selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysOperLog> lqw = buildQueryWrapper(operLog);
+        if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
+            lqw.orderByDesc(SysOperLog::getOperId);
+        }
+        Page<SysOperLogVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(page);
+    }
+
+    private LambdaQueryWrapper<SysOperLog> buildQueryWrapper(SysOperLogBo operLog) {
         Map<String, Object> params = operLog.getParams();
-        LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>()
+        return new LambdaQueryWrapper<SysOperLog>()
             .like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
             .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
             .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
@@ -67,12 +76,6 @@
             .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
             .between(params.get("beginTime") != null && params.get("endTime") != null,
                 SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"));
-        if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
-            pageQuery.setOrderByColumn("oper_id");
-            pageQuery.setIsAsc("desc");
-        }
-        Page<SysOperLogVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
-        return TableDataInfo.build(page);
     }
 
     /**
@@ -95,23 +98,8 @@
      */
     @Override
     public List<SysOperLogVo> selectOperLogList(SysOperLogBo operLog) {
-        Map<String, Object> params = operLog.getParams();
-        return baseMapper.selectVoList(new LambdaQueryWrapper<SysOperLog>()
-            .like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
-            .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
-            .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
-                SysOperLog::getBusinessType, operLog.getBusinessType())
-            .func(f -> {
-                if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
-                    f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
-                }
-            })
-            .eq(operLog.getStatus() != null && operLog.getStatus() > 0,
-                SysOperLog::getStatus, operLog.getStatus())
-            .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
-            .between(params.get("beginTime") != null && params.get("endTime") != null,
-                SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"))
-            .orderByDesc(SysOperLog::getOperId));
+        LambdaQueryWrapper<SysOperLog> lqw = buildQueryWrapper(operLog);
+        return baseMapper.selectVoList(lqw.orderByDesc(SysOperLog::getOperId));
     }
 
     /**
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java
index a1eefce..a67b04e 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java
@@ -11,6 +11,7 @@
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.ObjectUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
@@ -147,7 +148,7 @@
      * 鍒ゆ柇configKey鏄惁鍞竴
      */
     private boolean checkConfigKeyUnique(SysOssConfig sysOssConfig) {
-        long ossConfigId = ObjectUtil.isNull(sysOssConfig.getOssConfigId()) ? -1L : sysOssConfig.getOssConfigId();
+        long ossConfigId = ObjectUtils.notNull(sysOssConfig.getOssConfigId(), -1L);
         SysOssConfig info = baseMapper.selectOne(new LambdaQueryWrapper<SysOssConfig>()
             .select(SysOssConfig::getOssConfigId, SysOssConfig::getConfigKey)
             .eq(SysOssConfig::getConfigKey, sysOssConfig.getConfigKey()));
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
index 1866531..c2eb08c 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
@@ -36,6 +36,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -177,8 +178,7 @@
         FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
         response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
         OssClient storage = OssFactory.instance(sysOss.getService());
-        long contentLength = storage.download(sysOss.getFileName(), response.getOutputStream());
-        response.setContentLengthLong(contentLength);
+        storage.download(sysOss.getFileName(), response.getOutputStream(), response::setContentLengthLong);
     }
 
     /**
@@ -195,7 +195,7 @@
         OssClient storage = OssFactory.instance();
         UploadResult uploadResult;
         try {
-            uploadResult = storage.uploadSuffix(file.getBytes(), suffix);
+            uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
         } catch (IOException e) {
             throw new ServiceException(e.getMessage());
         }
@@ -244,7 +244,7 @@
         if (isValid) {
             // 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
         }
-        List<SysOss> list = baseMapper.selectBatchIds(ids);
+        List<SysOss> list = baseMapper.selectByIds(ids);
         for (SysOss sysOss : list) {
             OssClient storage = OssFactory.instance(sysOss.getService());
             storage.delete(sysOss.getUrl());
@@ -262,7 +262,7 @@
         OssClient storage = OssFactory.instance(oss.getService());
         // 浠呬慨鏀规《绫诲瀷涓� private 鐨刄RL锛屼复鏃禪RL鏃堕暱涓�120s
         if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
-            oss.setUrl(storage.getPrivateUrl(oss.getFileName(), 120));
+            oss.setUrl(storage.getPrivateUrl(oss.getFileName(), Duration.ofSeconds(120)));
         }
         return oss;
     }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
index 2c38129..5888985 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
@@ -6,14 +6,14 @@
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.PostService;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.mybatis.helper.DataBaseHelper;
 import org.dromara.system.domain.SysDept;
 import org.dromara.system.domain.SysPost;
 import org.dromara.system.domain.SysUserPost;
@@ -27,7 +27,6 @@
 
 import java.util.Arrays;
 import java.util.List;
-import java.util.stream.Collectors;
 
 /**
  * 宀椾綅淇℃伅 鏈嶅姟灞傚鐞�
@@ -36,7 +35,7 @@
  */
 @RequiredArgsConstructor
 @Service
-public class SysPostServiceImpl implements ISysPostService {
+public class SysPostServiceImpl implements ISysPostService, PostService {
 
     private final SysPostMapper baseMapper;
     private final SysDeptMapper deptMapper;
@@ -60,6 +59,17 @@
     }
 
     /**
+     * 鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 宀椾綅ID
+     */
+    @Override
+    public List<SysPostVo> selectPostsByUserId(Long userId) {
+        return baseMapper.selectPostsByUserId(userId);
+    }
+
+    /**
      * 鏍规嵁鏌ヨ鏉′欢鏋勫缓鏌ヨ鍖呰鍣�
      *
      * @param bo 鏌ヨ鏉′欢瀵硅薄
@@ -78,12 +88,8 @@
         } else if (ObjectUtil.isNotNull(bo.getBelongDeptId())) {
             //閮ㄩ棬鏍戞悳绱�
             wrapper.and(x -> {
-                List<Long> deptIds = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
-                        .select(SysDept::getDeptId)
-                        .apply(DataBaseHelper.findInSet(bo.getBelongDeptId(), "ancestors")))
-                    .stream()
-                    .map(SysDept::getDeptId)
-                    .collect(Collectors.toList());
+                List<SysDept> deptList = deptMapper.selectListByParentId(bo.getBelongDeptId());
+                List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
                 deptIds.add(bo.getBelongDeptId());
                 x.in(SysPost::getDeptId, deptIds);
             });
@@ -134,7 +140,7 @@
     public List<SysPostVo> selectPostByIds(List<Long> postIds) {
         return baseMapper.selectVoList(new LambdaQueryWrapper<SysPost>()
             .select(SysPost::getPostId, SysPost::getPostName, SysPost::getPostCode)
-            .eq(SysPost::getStatus, UserConstants.POST_NORMAL)
+            .eq(SysPost::getStatus, SystemConstants.NORMAL)
             .in(CollUtil.isNotEmpty(postIds), SysPost::getPostId, postIds));
     }
 
@@ -239,4 +245,5 @@
         SysPost post = MapstructUtils.convert(bo, SysPost.class);
         return baseMapper.updateById(post);
     }
+
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
index 9b8b0ec..0a2e485 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
@@ -12,10 +12,12 @@
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.constant.TenantConstants;
-import org.dromara.common.core.constant.UserConstants;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.RoleService;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -33,6 +35,7 @@
 import org.dromara.system.mapper.SysRoleMenuMapper;
 import org.dromara.system.mapper.SysUserRoleMapper;
 import org.dromara.system.service.ISysRoleService;
+import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -45,7 +48,7 @@
  */
 @RequiredArgsConstructor
 @Service
-public class SysRoleServiceImpl implements ISysRoleService {
+public class SysRoleServiceImpl implements ISysRoleService, RoleService {
 
     private final SysRoleMapper baseMapper;
     private final SysRoleMenuMapper roleMenuMapper;
@@ -72,7 +75,7 @@
     private Wrapper<SysRole> buildQueryWrapper(SysRoleBo bo) {
         Map<String, Object> params = bo.getParams();
         QueryWrapper<SysRole> wrapper = Wrappers.query();
-        wrapper.eq("r.del_flag", UserConstants.ROLE_NORMAL)
+        wrapper.eq("r.del_flag", SystemConstants.NORMAL)
             .eq(ObjectUtil.isNotNull(bo.getRoleId()), "r.role_id", bo.getRoleId())
             .like(StringUtils.isNotBlank(bo.getRoleName()), "r.role_name", bo.getRoleName())
             .eq(StringUtils.isNotBlank(bo.getStatus()), "r.status", bo.getStatus())
@@ -174,7 +177,7 @@
     @Override
     public List<SysRoleVo> selectRoleByIds(List<Long> roleIds) {
         return baseMapper.selectRoleList(new QueryWrapper<SysRole>()
-            .eq("r.status", UserConstants.ROLE_NORMAL)
+            .eq("r.status", SystemConstants.NORMAL)
             .in(CollUtil.isNotEmpty(roleIds), "r.role_id", roleIds));
     }
 
@@ -294,7 +297,7 @@
     public int updateRole(SysRoleBo bo) {
         SysRole role = MapstructUtils.convert(bo, SysRole.class);
 
-        if (UserConstants.ROLE_DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) {
+        if (SystemConstants.DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) {
             throw new ServiceException("瑙掕壊宸插垎閰嶏紝涓嶈兘绂佺敤!");
         }
         // 淇敼瑙掕壊淇℃伅
@@ -313,7 +316,7 @@
      */
     @Override
     public int updateRoleStatus(Long roleId, String status) {
-        if (UserConstants.ROLE_DISABLE.equals(status) && this.countUserRoleByRoleId(roleId) > 0) {
+        if (SystemConstants.DISABLE.equals(status) && this.countUserRoleByRoleId(roleId) > 0) {
             throw new ServiceException("瑙掕壊宸插垎閰嶏紝涓嶈兘绂佺敤!");
         }
         return baseMapper.update(null,
@@ -328,6 +331,7 @@
      * @param bo 瑙掕壊淇℃伅
      * @return 缁撴灉
      */
+    @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#bo.roleId")
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int authDataScope(SysRoleBo bo) {
@@ -348,7 +352,7 @@
     private int insertRoleMenu(SysRoleBo role) {
         int rows = 1;
         // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
-        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
+        List<SysRoleMenu> list = new ArrayList<>();
         for (Long menuId : role.getMenuIds()) {
             SysRoleMenu rm = new SysRoleMenu();
             rm.setRoleId(role.getRoleId());
@@ -369,7 +373,7 @@
     private int insertRoleDept(SysRoleBo role) {
         int rows = 1;
         // 鏂板瑙掕壊涓庨儴闂紙鏁版嵁鏉冮檺锛夌鐞�
-        List<SysRoleDept> list = new ArrayList<SysRoleDept>();
+        List<SysRoleDept> list = new ArrayList<>();
         for (Long deptId : role.getDeptIds()) {
             SysRoleDept rd = new SysRoleDept();
             rd.setRoleId(role.getRoleId());
@@ -388,6 +392,7 @@
      * @param roleId 瑙掕壊ID
      * @return 缁撴灉
      */
+    @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId")
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int deleteRoleById(Long roleId) {
@@ -404,6 +409,7 @@
      * @param roleIds 闇�瑕佸垹闄ょ殑瑙掕壊ID
      * @return 缁撴灉
      */
+    @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, allEntries = true)
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int deleteRoleByIds(Long[] roleIds) {
@@ -435,7 +441,7 @@
             .eq(SysUserRole::getRoleId, userRole.getRoleId())
             .eq(SysUserRole::getUserId, userRole.getUserId()));
         if (rows > 0) {
-            cleanOnlineUserByRole(userRole.getRoleId());
+            cleanOnlineUser(List.of(userRole.getUserId()));
         }
         return rows;
     }
@@ -449,11 +455,12 @@
      */
     @Override
     public int deleteAuthUsers(Long roleId, Long[] userIds) {
+        List<Long> ids = List.of(userIds);
         int rows = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
             .eq(SysUserRole::getRoleId, roleId)
-            .in(SysUserRole::getUserId, Arrays.asList(userIds)));
+            .in(SysUserRole::getUserId, ids));
         if (rows > 0) {
-            cleanOnlineUserByRole(roleId);
+            cleanOnlineUser(ids);
         }
         return rows;
     }
@@ -469,7 +476,8 @@
     public int insertAuthUsers(Long roleId, Long[] userIds) {
         // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
         int rows = 1;
-        List<SysUserRole> list = StreamUtils.toList(List.of(userIds), userId -> {
+        List<Long> ids = List.of(userIds);
+        List<SysUserRole> list = StreamUtils.toList(ids, userId -> {
             SysUserRole ur = new SysUserRole();
             ur.setUserId(userId);
             ur.setRoleId(roleId);
@@ -479,7 +487,7 @@
             rows = userRoleMapper.insertBatch(list) ? list.size() : 0;
         }
         if (rows > 0) {
-            cleanOnlineUserByRole(roleId);
+            cleanOnlineUser(ids);
         }
         return rows;
     }
@@ -503,6 +511,9 @@
                 return;
             }
             LoginUser loginUser = LoginHelper.getLoginUser(token);
+            if (ObjectUtil.isNull(loginUser) || CollUtil.isEmpty(loginUser.getRoles())) {
+                return;
+            }
             if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) {
                 try {
                     StpUtil.logoutByTokenValue(token);
@@ -511,4 +522,31 @@
             }
         });
     }
+
+    @Override
+    public void cleanOnlineUser(List<Long> userIds) {
+        List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
+        if (CollUtil.isEmpty(keys)) {
+            return;
+        }
+        // 瑙掕壊鍏宠仈鐨勫湪绾跨敤鎴烽噺杩囧ぇ浼氬鑷磖edis闃诲鍗¢】 璋ㄦ厧鎿嶄綔
+        keys.parallelStream().forEach(key -> {
+            String token = StringUtils.substringAfterLast(key, ":");
+            // 濡傛灉宸茬粡杩囨湡鍒欒烦杩�
+            if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) {
+                return;
+            }
+            LoginUser loginUser = LoginHelper.getLoginUser(token);
+            if (ObjectUtil.isNull(loginUser)) {
+                return;
+            }
+            if (userIds.contains(loginUser.getUserId())) {
+                try {
+                    StpUtil.logoutByTokenValue(token);
+                } catch (NotLoginException ignored) {
+                }
+            }
+        });
+    }
+
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java
index 5f4d121..8a0d45e 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java
@@ -1,7 +1,7 @@
 package org.dromara.system.service.impl;
 
 import cn.dev33.satoken.stp.StpUtil;
-import org.dromara.common.core.utils.StringUtils;
+import cn.hutool.core.util.ArrayUtil;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.sensitive.core.SensitiveService;
 import org.dromara.common.tenant.helper.TenantHelper;
@@ -22,19 +22,19 @@
      * 鏄惁鑴辨晱
      */
     @Override
-    public boolean isSensitive(String roleKey, String perms) {
+    public boolean isSensitive(String[] roleKey, String[] perms) {
         if (!LoginHelper.isLogin()) {
             return true;
         }
-        boolean roleExist = StringUtils.isNotBlank(roleKey);
-        boolean permsExist = StringUtils.isNotBlank(perms);
+        boolean roleExist = ArrayUtil.isNotEmpty(roleKey);
+        boolean permsExist = ArrayUtil.isNotEmpty(perms);
         if (roleExist && permsExist) {
-            if (StpUtil.hasRole(roleKey) && StpUtil.hasPermission(perms)) {
+            if (StpUtil.hasRoleOr(roleKey) && StpUtil.hasPermissionOr(perms)) {
                 return false;
             }
-        } else if (roleExist && StpUtil.hasRole(roleKey)) {
+        } else if (roleExist && StpUtil.hasRoleOr(roleKey)) {
             return false;
-        } else if (permsExist && StpUtil.hasPermission(perms)) {
+        } else if (permsExist && StpUtil.hasPermissionOr(perms)) {
             return false;
         }
 
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java
new file mode 100644
index 0000000..23dd052
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java
@@ -0,0 +1,168 @@
+package org.dromara.system.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.SystemConstants;
+import org.dromara.common.core.domain.dto.TaskAssigneeDTO;
+import org.dromara.common.core.domain.model.TaskAssigneeBody;
+import org.dromara.common.core.service.TaskAssigneeService;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.system.domain.SysDept;
+import org.dromara.system.domain.SysPost;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.dromara.system.domain.vo.SysPostVo;
+import org.dromara.system.domain.vo.SysRoleVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysDeptMapper;
+import org.dromara.system.mapper.SysPostMapper;
+import org.dromara.system.mapper.SysRoleMapper;
+import org.dromara.system.mapper.SysUserMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 宸ヤ綔娴佽璁″櫒鑾峰彇浠诲姟鎵ц浜�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysTaskAssigneeServiceImpl implements TaskAssigneeService {
+
+    private final SysPostMapper postMapper;
+    private final SysDeptMapper deptMapper;
+    private final SysUserMapper userMapper;
+    private final SysRoleMapper roleMapper;
+
+    /**
+     * 鏌ヨ瑙掕壊骞惰繑鍥炰换鍔℃寚娲剧殑鍒楄〃锛屾敮鎸佸垎椤�
+     *
+     * @param taskQuery 鏌ヨ鏉′欢
+     * @return 鍔炵悊浜�
+     */
+    @Override
+    public TaskAssigneeDTO selectRolesByTaskAssigneeList(TaskAssigneeBody taskQuery) {
+        PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
+        QueryWrapper<SysRole> wrapper = Wrappers.query();
+        wrapper.eq("r.del_flag", SystemConstants.NORMAL)
+            .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "r.role_name", taskQuery.getHandlerCode())
+            .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "r.role_key", taskQuery.getHandlerName())
+            .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()),
+                "r.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime())
+            .orderByAsc("r.role_sort").orderByAsc("r.create_time");
+        Page<SysRoleVo> page = roleMapper.selectPageRoleList(pageQuery.build(), wrapper);
+        // 浣跨敤灏佽鐨勫瓧娈垫槧灏勬柟娉曡繘琛岃浆鎹�
+        List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
+            SysRoleVo::getRoleId, SysRoleVo::getRoleKey, SysRoleVo::getRoleName, null, SysRoleVo::getCreateTime);
+        return new TaskAssigneeDTO(page.getTotal(), handlers);
+    }
+
+    /**
+     * 鏌ヨ宀椾綅骞惰繑鍥炰换鍔℃寚娲剧殑鍒楄〃锛屾敮鎸佸垎椤�
+     *
+     * @param taskQuery 鏌ヨ鏉′欢
+     * @return 鍔炵悊浜�
+     */
+    @Override
+    public TaskAssigneeDTO selectPostsByTaskAssigneeList(TaskAssigneeBody taskQuery) {
+        PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
+        LambdaQueryWrapper<SysPost> wrapper = Wrappers.<SysPost>lambdaQuery()
+            .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysPost::getPostCategory, taskQuery.getHandlerCode())
+            .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysPost::getPostName, taskQuery.getHandlerName())
+            .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()),
+                SysPost::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime());
+        if (StringUtils.isNotBlank(taskQuery.getGroupId())) {
+            Long belongDeptId = Long.valueOf(taskQuery.getGroupId());
+            wrapper.and(x -> {
+                List<SysDept> deptList = deptMapper.selectListByParentId(belongDeptId);
+                List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
+                deptIds.add(belongDeptId);
+                x.in(SysPost::getDeptId, deptIds);
+            });
+        }
+        Page<SysPostVo> page = postMapper.selectPagePostList(pageQuery.build(), wrapper);
+        // 浣跨敤灏佽鐨勫瓧娈垫槧灏勬柟娉曡繘琛岃浆鎹�
+        List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
+            SysPostVo::getPostId, SysPostVo::getPostCategory, SysPostVo::getPostName, SysPostVo::getDeptId, SysPostVo::getCreateTime);
+        return new TaskAssigneeDTO(page.getTotal(), handlers);
+    }
+
+    /**
+     * 鏌ヨ閮ㄩ棬骞惰繑鍥炰换鍔℃寚娲剧殑鍒楄〃锛屾敮鎸佸垎椤�
+     *
+     * @param taskQuery 鏌ヨ鏉′欢
+     * @return 鍔炵悊浜�
+     */
+    @Override
+    public TaskAssigneeDTO selectDeptsByTaskAssigneeList(TaskAssigneeBody taskQuery) {
+        PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
+        LambdaQueryWrapper<SysDept> wrapper = Wrappers.<SysDept>lambdaQuery()
+            .eq(SysDept::getDelFlag, SystemConstants.NORMAL)
+            .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysDept::getDeptCategory, taskQuery.getHandlerCode())
+            .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysDept::getDeptName, taskQuery.getHandlerName())
+            .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()),
+                SysDept::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime())
+            .orderByAsc(SysDept::getAncestors)
+            .orderByAsc(SysDept::getParentId)
+            .orderByAsc(SysDept::getOrderNum)
+            .orderByAsc(SysDept::getDeptId);
+        if (StringUtils.isNotBlank(taskQuery.getGroupId())) {
+            //閮ㄩ棬鏍戞悳绱�
+            wrapper.and(x -> {
+                Long parentId = Long.valueOf(taskQuery.getGroupId());
+                List<SysDept> deptList = deptMapper.selectListByParentId(parentId);
+                List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
+                deptIds.add(parentId);
+                x.in(SysDept::getDeptId, deptIds);
+            });
+        }
+        Page<SysDeptVo> page = deptMapper.selectPageDeptList(pageQuery.build(), wrapper);
+        // 浣跨敤灏佽鐨勫瓧娈垫槧灏勬柟娉曡繘琛岃浆鎹�
+        List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
+            SysDeptVo::getDeptId, SysDeptVo::getDeptCategory, SysDeptVo::getDeptName, SysDeptVo::getParentId, SysDeptVo::getCreateTime);
+        return new TaskAssigneeDTO(page.getTotal(), handlers);
+    }
+
+
+    /**
+     * 鏌ヨ鐢ㄦ埛骞惰繑鍥炰换鍔℃寚娲剧殑鍒楄〃锛屾敮鎸佸垎椤�
+     *
+     * @param taskQuery 鏌ヨ鏉′欢
+     * @return 鍔炵悊浜�
+     */
+    @Override
+    public TaskAssigneeDTO selectUsersByTaskAssigneeList(TaskAssigneeBody taskQuery) {
+        PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
+        QueryWrapper<SysUser> wrapper = Wrappers.query();
+        wrapper.eq("u.del_flag", SystemConstants.NORMAL)
+            .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "u.user_name", taskQuery.getHandlerCode())
+            .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "u.nick_name", taskQuery.getHandlerName())
+            .between(taskQuery.getBeginTime() != null && taskQuery.getEndTime() != null,
+                "u.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime())
+            .orderByAsc("u.user_id");
+        if (StringUtils.isNotBlank(taskQuery.getGroupId())) {
+            //閮ㄩ棬鏍戞悳绱�
+            wrapper.and(x -> {
+                Long parentId = Long.valueOf(taskQuery.getGroupId());
+                List<SysDept> deptList = deptMapper.selectListByParentId(parentId);
+                List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
+                deptIds.add(parentId);
+                x.in("u.dept_id", deptIds);
+            });
+        }
+        Page<SysUserVo> page = userMapper.selectPageUserList(pageQuery.build(), wrapper);
+        // 浣跨敤灏佽鐨勫瓧娈垫槧灏勬柟娉曡繘琛岃浆鎹�
+        List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
+            SysUserVo::getUserId, SysUserVo::getUserName, SysUserVo::getNickName, SysUserVo::getDeptId, SysUserVo::getCreateTime);
+        return new TaskAssigneeDTO(page.getTotal(), handlers);
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
index d2a72f6..8d69e96 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
@@ -6,7 +6,7 @@
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -59,7 +59,7 @@
     @Override
     public List<SysTenantPackageVo> selectList() {
         return baseMapper.selectVoList(new LambdaQueryWrapper<SysTenantPackage>()
-                .eq(SysTenantPackage::getStatus, TenantConstants.NORMAL));
+                .eq(SysTenantPackage::getStatus, SystemConstants.NORMAL));
     }
 
     /**
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
index d30750d..f31bd30 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
@@ -1,6 +1,8 @@
 package org.dromara.system.service.impl;
 
 import cn.dev33.satoken.secure.BCrypt;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.RandomUtil;
@@ -10,13 +12,19 @@
 import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.constant.TenantConstants;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.WorkflowService;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.common.tenant.core.TenantEntity;
+import org.dromara.common.tenant.helper.TenantHelper;
 import org.dromara.system.domain.*;
 import org.dromara.system.domain.bo.SysTenantBo;
 import org.dromara.system.domain.vo.SysTenantVo;
@@ -27,10 +35,7 @@
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 
 /**
  * 绉熸埛Service涓氬姟灞傚鐞�
@@ -117,7 +122,9 @@
 
         // 鑾峰彇鎵�鏈夌鎴风紪鍙�
         List<String> tenantIds = baseMapper.selectObjs(
-            new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId), x -> {return Convert.toStr(x);});
+            new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId), x -> {
+                return Convert.toStr(x);
+            });
         String tenantId = generateTenantId(tenantIds);
         add.setTenantId(tenantId);
         boolean flag = baseMapper.insert(add) > 0;
@@ -187,6 +194,13 @@
             config.setTenantId(tenantId);
         }
         configMapper.insertBatch(sysConfigList);
+
+        // 鏈紑鍚伐浣滄祦涓嶆墽琛屼笅鏂规搷浣�
+        if (SpringUtils.getProperty("warm-flow.enabled", Boolean.class, false)) {
+            WorkflowService workflowService = SpringUtils.getBean(WorkflowService.class);
+            // 鏂板绉熸埛娴佺▼瀹氫箟
+            workflowService.syncDef(tenantId);
+        }
         return true;
     }
 
@@ -201,7 +215,7 @@
         String numbers = RandomUtil.randomNumbers(6);
         // 鍒ゆ柇鏄惁瀛樺湪锛屽鏋滃瓨鍦ㄥ垯閲嶆柊鐢熸垚
         if (tenantIds.contains(numbers)) {
-            generateTenantId(tenantIds);
+            return generateTenantId(tenantIds);
         }
         return numbers;
     }
@@ -228,7 +242,7 @@
         role.setRoleName(TenantConstants.TENANT_ADMIN_ROLE_NAME);
         role.setRoleKey(TenantConstants.TENANT_ADMIN_ROLE_KEY);
         role.setRoleSort(1);
-        role.setStatus(TenantConstants.NORMAL);
+        role.setStatus(SystemConstants.NORMAL);
         roleMapper.insert(role);
         Long roleId = role.getRoleId();
 
@@ -266,7 +280,9 @@
     @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
     @Override
     public int updateTenantStatus(SysTenantBo bo) {
-        SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class);
+        SysTenant tenant = new SysTenant();
+        tenant.setId(bo.getId());
+        tenant.setStatus(bo.getStatus());
         return baseMapper.updateById(tenant);
     }
 
@@ -369,4 +385,93 @@
         }
         return true;
     }
+
+    /**
+     * 鍚屾绉熸埛瀛楀吀
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void syncTenantDict() {
+        // 鏌ヨ瓒呯 鎵�鏈夊瓧鍏告暟鎹�
+        List<SysDictType> dictTypeList = new ArrayList<>();
+        List<SysDictData> dictDataList = new ArrayList<>();
+        TenantHelper.ignore(() -> {
+            dictTypeList.addAll(dictTypeMapper.selectList());
+            dictDataList.addAll(dictDataMapper.selectList());
+        });
+        Map<String, List<SysDictType>> typeMap = StreamUtils.groupByKey(dictTypeList, TenantEntity::getTenantId);
+        Map<String, Map<String, List<SysDictData>>> typeDataMap = StreamUtils.groupBy2Key(
+            dictDataList, TenantEntity::getTenantId, SysDictData::getDictType);
+        // 绠$悊绉熸埛瀛楀吀鏁版嵁
+        List<SysDictType> defaultTypeMap = typeMap.get(TenantConstants.DEFAULT_TENANT_ID);
+        Map<String, List<SysDictData>> defaultTypeDataMap = typeDataMap.get(TenantConstants.DEFAULT_TENANT_ID);
+
+        // 鑾峰彇鎵�鏈夌鎴风紪鍙�
+        List<String> tenantIds = baseMapper.selectObjs(
+            new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId)
+                .eq(SysTenant::getStatus, SystemConstants.NORMAL), x -> {
+                return Convert.toStr(x);
+            });
+        List<SysDictType> saveTypeList = new ArrayList<>();
+        List<SysDictData> saveDataList = new ArrayList<>();
+        Set<String> set = new HashSet<>();
+        for (String tenantId : tenantIds) {
+            if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
+                continue;
+            }
+            for (SysDictType dictType : defaultTypeMap) {
+                List<String> typeList = StreamUtils.toList(typeMap.get(tenantId), SysDictType::getDictType);
+                List<SysDictData> dataList = defaultTypeDataMap.get(dictType.getDictType());
+                if (typeList.contains(dictType.getDictType())) {
+                    List<SysDictData> dataListTenant = typeDataMap.get(tenantId).get(dictType.getDictType());
+                    Map<String, SysDictData> map = StreamUtils.toIdentityMap(dataListTenant, SysDictData::getDictValue);
+                    for (SysDictData dictData : dataList) {
+                        if (!map.containsKey(dictData.getDictValue())) {
+                            SysDictData data = BeanUtil.toBean(dictData, SysDictData.class);
+                            // 璁剧疆瀛楀吀缂栫爜涓� null
+                            data.setDictCode(null);
+                            data.setTenantId(tenantId);
+                            data.setCreateTime(null);
+                            data.setUpdateTime(null);
+                            set.add(tenantId);
+                            saveDataList.add(data);
+                        }
+                    }
+                } else {
+                    SysDictType type = BeanUtil.toBean(dictType, SysDictType.class);
+                    type.setDictId(null);
+                    type.setTenantId(tenantId);
+                    type.setCreateTime(null);
+                    type.setUpdateTime(null);
+                    set.add(tenantId);
+                    saveTypeList.add(type);
+                    if (CollUtil.isNotEmpty(dataList)) {
+                        // 绛涢�夊嚭 dictType 瀵瑰簲鐨� data
+                        for (SysDictData dictData : dataList) {
+                            SysDictData data = BeanUtil.toBean(dictData, SysDictData.class);
+                            // 璁剧疆瀛楀吀缂栫爜涓� null
+                            data.setDictCode(null);
+                            data.setTenantId(tenantId);
+                            data.setCreateTime(null);
+                            data.setUpdateTime(null);
+                            set.add(tenantId);
+                            saveDataList.add(data);
+                        }
+                    }
+                }
+            }
+        }
+        TenantHelper.ignore(() -> {
+            if (CollUtil.isNotEmpty(saveTypeList)) {
+                dictTypeMapper.insertBatch(saveTypeList);
+            }
+            if (CollUtil.isNotEmpty(saveDataList)) {
+                dictDataMapper.insertBatch(saveDataList);
+            }
+        });
+        for (String tenantId : set) {
+            TenantHelper.dynamic(tenantId, () -> CacheUtils.clear(CacheNames.SYS_DICT));
+        }
+    }
+
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
index 2540606..4081170 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
@@ -14,17 +14,13 @@
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.constant.CacheNames;
-import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.dto.UserDTO;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.service.UserService;
-import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.core.utils.SpringUtils;
-import org.dromara.common.core.utils.StreamUtils;
-import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.*;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.mybatis.helper.DataBaseHelper;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.system.domain.*;
 import org.dromara.system.domain.bo.SysUserBo;
@@ -42,6 +38,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * 鐢ㄦ埛 涓氬姟灞傚鐞�
@@ -80,7 +77,7 @@
     private Wrapper<SysUser> buildQueryWrapper(SysUserBo user) {
         Map<String, Object> params = user.getParams();
         QueryWrapper<SysUser> wrapper = Wrappers.query();
-        wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
+        wrapper.eq("u.del_flag", SystemConstants.NORMAL)
             .eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId())
             .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
             .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
@@ -88,9 +85,7 @@
             .between(params.get("beginTime") != null && params.get("endTime") != null,
                 "u.create_time", params.get("beginTime"), params.get("endTime"))
             .and(ObjectUtil.isNotNull(user.getDeptId()), w -> {
-                List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
-                    .select(SysDept::getDeptId)
-                    .apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors")));
+                List<SysDept> deptList = deptMapper.selectListByParentId(user.getDeptId());
                 List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
                 ids.add(user.getDeptId());
                 w.in("u.dept_id", ids);
@@ -110,7 +105,7 @@
     @Override
     public TableDataInfo<SysUserVo> selectAllocatedList(SysUserBo user, PageQuery pageQuery) {
         QueryWrapper<SysUser> wrapper = Wrappers.query();
-        wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
+        wrapper.eq("u.del_flag", SystemConstants.NORMAL)
             .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId())
             .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
             .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
@@ -130,7 +125,7 @@
     public TableDataInfo<SysUserVo> selectUnallocatedList(SysUserBo user, PageQuery pageQuery) {
         List<Long> userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId());
         QueryWrapper<SysUser> wrapper = Wrappers.query();
-        wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
+        wrapper.eq("u.del_flag", SystemConstants.NORMAL)
             .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id"))
             .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds)
             .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
@@ -189,7 +184,7 @@
     public List<SysUserVo> selectUserByIds(List<Long> userIds, Long deptId) {
         return baseMapper.selectUserList(new LambdaQueryWrapper<SysUser>()
             .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName)
-            .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
+            .eq(SysUser::getStatus, SystemConstants.NORMAL)
             .eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId)
             .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
     }
@@ -472,7 +467,7 @@
         if (ArrayUtil.isNotEmpty(roleIds)) {
             List<Long> roleList = new ArrayList<>(List.of(roleIds));
             if (!LoginHelper.isSuperAdmin(userId)) {
-                roleList.remove(UserConstants.SUPER_ADMIN_ID);
+                roleList.remove(SystemConstants.SUPER_ADMIN_ID);
             }
             // 鍒ゆ柇鏄惁鍏锋湁姝よ鑹茬殑鎿嶄綔鏉冮檺
             List<SysRoleVo> roles = roleMapper.selectRoleList(
@@ -567,7 +562,7 @@
     public String selectUserNameById(Long userId) {
         SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
             .select(SysUser::getUserName).eq(SysUser::getUserId, userId));
-        return ObjectUtil.isNull(sysUser) ? null : sysUser.getUserName();
+        return ObjectUtils.notNullGetter(sysUser, SysUser::getUserName);
     }
 
     /**
@@ -581,7 +576,7 @@
     public String selectNicknameById(Long userId) {
         SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
             .select(SysUser::getNickName).eq(SysUser::getUserId, userId));
-        return ObjectUtil.isNull(sysUser) ? null : sysUser.getNickName();
+        return ObjectUtils.notNullGetter(sysUser, SysUser::getNickName);
     }
 
     /**
@@ -612,7 +607,7 @@
     public String selectPhonenumberById(Long userId) {
         SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
             .select(SysUser::getPhonenumber).eq(SysUser::getUserId, userId));
-        return ObjectUtil.isNull(sysUser) ? null : sysUser.getPhonenumber();
+        return ObjectUtils.notNullGetter(sysUser, SysUser::getPhonenumber);
     }
 
     /**
@@ -625,9 +620,15 @@
     public String selectEmailById(Long userId) {
         SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
             .select(SysUser::getEmail).eq(SysUser::getUserId, userId));
-        return ObjectUtil.isNull(sysUser) ? null : sysUser.getEmail();
+        return ObjectUtils.notNullGetter(sysUser, SysUser::getEmail);
     }
 
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鍒楄〃
+     *
+     * @param userIds 鐢ㄦ埛ids
+     * @return 鐢ㄦ埛鍒楄〃
+     */
     @Override
     public List<UserDTO> selectListByIds(List<Long> userIds) {
         if (CollUtil.isEmpty(userIds)) {
@@ -635,29 +636,55 @@
         }
         List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
             .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
-            .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
-            .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
+            .eq(SysUser::getStatus, SystemConstants.NORMAL)
+            .in(SysUser::getUserId, userIds));
         return BeanUtil.copyToList(list, UserDTO.class);
     }
 
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ鐢ㄦ埛ID
+     *
+     * @param roleIds 瑙掕壊ids
+     * @return 鐢ㄦ埛ids
+     */
     @Override
     public List<Long> selectUserIdsByRoleIds(List<Long> roleIds) {
-        List<SysUserRole> userRoles = userRoleMapper.selectList(
-            new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
-        return StreamUtils.toList(userRoles, SysUserRole::getUserId);
-    }
-
-    @Override
-    public List<UserDTO> selectUsersByRoleIds(List<Long> roleIds) {
         if (CollUtil.isEmpty(roleIds)) {
             return List.of();
         }
         List<SysUserRole> userRoles = userRoleMapper.selectList(
             new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
-        List<Long> userIds = StreamUtils.toList(userRoles, SysUserRole::getUserId);
-        return selectListByIds(userIds);
+        return StreamUtils.toList(userRoles, SysUserRole::getUserId);
     }
 
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ鐢ㄦ埛
+     *
+     * @param roleIds 瑙掕壊ids
+     * @return 鐢ㄦ埛
+     */
+    @Override
+    public List<UserDTO> selectUsersByRoleIds(List<Long> roleIds) {
+        if (CollUtil.isEmpty(roleIds)) {
+            return List.of();
+        }
+
+        // 閫氳繃瑙掕壊ID鑾峰彇鐢ㄦ埛瑙掕壊淇℃伅
+        List<SysUserRole> userRoles = userRoleMapper.selectList(
+            new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
+
+        // 鑾峰彇鐢ㄦ埛ID鍒楄〃
+        Set<Long> userIds = StreamUtils.toSet(userRoles, SysUserRole::getUserId);
+
+        return selectListByIds(new ArrayList<>(userIds));
+    }
+
+    /**
+     * 閫氳繃閮ㄩ棬ID鏌ヨ鐢ㄦ埛
+     *
+     * @param deptIds 閮ㄩ棬ids
+     * @return 鐢ㄦ埛
+     */
     @Override
     public List<UserDTO> selectUsersByDeptIds(List<Long> deptIds) {
         if (CollUtil.isEmpty(deptIds)) {
@@ -665,8 +692,31 @@
         }
         List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
             .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
-            .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
-            .in(CollUtil.isNotEmpty(deptIds), SysUser::getDeptId, deptIds));
+            .eq(SysUser::getStatus, SystemConstants.NORMAL)
+            .in(SysUser::getDeptId, deptIds));
         return BeanUtil.copyToList(list, UserDTO.class);
     }
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ鐢ㄦ埛
+     *
+     * @param postIds 宀椾綅ids
+     * @return 鐢ㄦ埛
+     */
+    @Override
+    public List<UserDTO> selectUsersByPostIds(List<Long> postIds) {
+        if (CollUtil.isEmpty(postIds)) {
+            return List.of();
+        }
+
+        // 閫氳繃宀椾綅ID鑾峰彇鐢ㄦ埛宀椾綅淇℃伅
+        List<SysUserPost> userPosts = userPostMapper.selectList(
+            new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getPostId, postIds));
+
+        // 鑾峰彇鐢ㄦ埛ID鍒楄〃
+        Set<Long> userIds = StreamUtils.toSet(userPosts, SysUserPost::getUserId);
+
+        return selectListByIds(new ArrayList<>(userIds));
+    }
+
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
index 6ad866f..9057a0e 100644
--- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -18,6 +18,17 @@
         from sys_dept ${ew.getCustomSqlSegment}
     </select>
 
+    <select id="selectPageDeptList" resultMap="SysDeptResult">
+        select
+        <if test="ew.getSqlSelect != null">
+            ${ew.getSqlSelect}
+        </if>
+        <if test="ew.getSqlSelect == null">
+            *
+        </if>
+        from sys_dept ${ew.getCustomSqlSegment}
+    </select>
+
     <select id="countDeptById" resultType="Long">
         select count(*) from sys_dept where del_flag = '0' and dept_id = #{deptId}
     </select>
diff --git a/ruoyi-modules/ruoyi-workflow/pom.xml b/ruoyi-modules/ruoyi-workflow/pom.xml
index e55839e..d195faf 100644
--- a/ruoyi-modules/ruoyi-workflow/pom.xml
+++ b/ruoyi-modules/ruoyi-workflow/pom.xml
@@ -18,57 +18,14 @@
 
     <dependencies>
 
-        <!--寮曞叆flowable渚濊禆-->
         <dependency>
-            <groupId>org.flowable</groupId>
-            <artifactId>flowable-spring-boot-autoconfigure</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.flowable</groupId>
-                    <artifactId>flowable-spring-security</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <dependency>
-            <groupId>org.flowable</groupId>
-            <artifactId>flowable-spring-configurator</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.flowable</groupId>
-            <artifactId>flowable-spring-boot-starter-actuator</artifactId>
-        </dependency>
-
-        <!-- 缁樺埗flowable娴佺▼鍥� -->
-        <dependency>
-            <groupId>org.flowable</groupId>
-            <artifactId>flowable-image-generator</artifactId>
-        </dependency>
-
-        <!-- flowable json 杞崲 -->
-        <dependency>
-            <groupId>org.flowable</groupId>
-            <artifactId>flowable-json-converter</artifactId>
-            <version>6.8.0</version>
-        </dependency>
-
-        <!-- svg杞琾ng鍥剧墖宸ュ叿-->
-        <dependency>
-            <groupId>org.apache.xmlgraphics</groupId>
-            <artifactId>batik-all</artifactId>
-            <version>1.17</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>xalan</groupId>
-                    <artifactId>xalan</artifactId>
-                </exclusion>
-            </exclusions>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sse</artifactId>
         </dependency>
 
         <dependency>
             <groupId>org.dromara</groupId>
-            <artifactId>ruoyi-common-websocket</artifactId>
+            <artifactId>ruoyi-common-doc</artifactId>
         </dependency>
 
         <dependency>
@@ -113,6 +70,14 @@
             <groupId>org.dromara</groupId>
             <artifactId>ruoyi-common-security</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.dromara.warm</groupId>
+            <artifactId>warm-flow-mybatis-plus-sb3-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara.warm</groupId>
+            <artifactId>warm-flow-plugin-ui-sb-web</artifactId>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java
new file mode 100644
index 0000000..5d24b35
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java
@@ -0,0 +1,14 @@
+package org.dromara.workflow.common;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@ConditionalOnProperty(value = "warm-flow.enabled", havingValue = "true")
+public @interface ConditionalOnEnable {
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java
index c3fcafa..1b10eb8 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java
@@ -8,83 +8,6 @@
  */
 public interface FlowConstant {
 
-    String MESSAGE_CURRENT_TASK_IS_NULL = "褰撳墠浠诲姟涓嶅瓨鍦ㄦ垨浣犱笉鏄换鍔″姙鐞嗕汉锛�";
-
-    String MESSAGE_SUSPENDED = "褰撳墠浠诲姟宸叉寕璧蜂笉鍙鎵癸紒";
-
-    /**
-     * 杩炵嚎
-     */
-    String SEQUENCE_FLOW = "sequenceFlow";
-
-    /**
-     * 骞惰缃戝叧
-     */
-    String PARALLEL_GATEWAY = "parallelGateway";
-
-    /**
-     * 鎺掑畠缃戝叧
-     */
-    String EXCLUSIVE_GATEWAY = "exclusiveGateway";
-
-    /**
-     * 鍖呭惈缃戝叧
-     */
-    String INCLUSIVE_GATEWAY = "inclusiveGateway";
-
-    /**
-     * 缁撴潫鑺傜偣
-     */
-    String END_EVENT = "endEvent";
-
-
-    /**
-     * 娴佺▼濮旀淳鏍囪瘑
-     */
-    String PENDING = "PENDING";
-
-    /**
-     * 鍊欓�変汉鏍囪瘑
-     */
-    String CANDIDATE = "candidate";
-
-    /**
-     * 浼氱浠诲姟鎬绘暟
-     */
-    String NUMBER_OF_INSTANCES = "nrOfInstances";
-
-    /**
-     * 姝e湪鎵ц鐨勪細绛炬�绘暟
-     */
-    String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances";
-
-    /**
-     * 宸插畬鎴愮殑浼氱浠诲姟鎬绘暟
-     */
-    String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances";
-
-    /**
-     * 寰幆鐨勭储寮曞�硷紝鍙互浣跨敤elementIndexVariable灞炴�т慨鏀筶oopCounter鐨勫彉閲忓悕
-     */
-    String LOOP_COUNTER = "loopCounter";
-
-    String ZIP = "ZIP";
-
-    /**
-     * 涓氬姟涓庢祦绋嬪疄渚嬪叧鑱斿璞�
-     */
-    String BUSINESS_INSTANCE_DTO = "businessInstanceDTO";
-
-    /**
-     * 娴佺▼瀹氫箟閰嶇疆
-     */
-    String WF_DEFINITION_CONFIG_VO = "wfDefinitionConfigVo";
-
-    /**
-     * 鑺傜偣閰嶇疆
-     */
-    String WF_NODE_CONFIG_VO = "wfNodeConfigVo";
-
     /**
      * 娴佺▼鍙戣捣浜�
      */
@@ -98,40 +21,46 @@
     /**
      * 涓氬姟id
      */
-    String BUSINESS_KEY = "businessKey";
+    String BUSINESS_ID = "businessId";
 
     /**
-     * 娴佺▼瀹氫箟id
+     * 浠诲姟id
      */
-    String PROCESS_DEFINITION_ID = "processDefinitionId";
+    String TASK_ID = "taskId";
 
     /**
-     * 寮�鍚烦杩囪〃杈惧紡鍙橀噺
+     * 濮旀墭
      */
-    String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED";
+    String DELEGATE_TASK = "delegateTask";
 
     /**
-     * 妯″瀷鏍囪瘑key鍛藉悕瑙勮寖姝e垯琛ㄨ揪寮�
+     * 杞姙
      */
-    String MODEL_KEY_PATTERN = "^[a-zA-Z][a-zA-Z0-9_]{0,254}$";
+    String TRANSFER_TASK = "transferTask";
 
     /**
-     * 鐢ㄦ埛浠诲姟
+     * 鍔犵
      */
-    String USER_TASK = "userTask";
+    String ADD_SIGNATURE = "addSignature";
 
     /**
-     * 浼氱
+     * 鍑忕
      */
-    String MULTI_INSTANCE = "multiInstance";
+    String REDUCTION_SIGNATURE = "reductionSignature";
 
     /**
-     * 鏄�
+     * 娴佺▼鍒嗙被Id杞悕绉�
      */
-    String TRUE = "0";
+    String CATEGORY_ID_TO_NAME = "category_id_to_name";
 
     /**
-     * 鍚�
+     * 娴佺▼鍒嗙被鍚嶇О
      */
-    String FALSE = "1";
+    String FLOW_CATEGORY_NAME = "flow_category_name#30d";
+
+    /**
+     * 榛樿绉熸埛OA鐢宠鍒嗙被id
+     */
+    Long FLOW_CATEGORY_ID = 100L;
+
 }
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java
deleted file mode 100644
index 083ab7b..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.dromara.workflow.common.enums;
-
-import cn.hutool.core.util.StrUtil;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.Arrays;
-
-/**
- * 浠诲姟鐘舵�佹灇涓�
- *
- * @author may
- */
-@Getter
-@AllArgsConstructor
-public enum FormTypeEnum {
-    /**
-     * 鑷畾涔夎〃鍗�
-     */
-    STATIC("static", "鑷畾涔夎〃鍗�"),
-    /**
-     * 鍔ㄦ�佽〃鍗�
-     */
-    DYNAMIC("dynamic", "鍔ㄦ�佽〃鍗�");
-
-    /**
-     * 绫诲瀷
-     */
-    private final String type;
-
-    /**
-     * 鎻忚堪
-     */
-    private final String desc;
-
-    /**
-     * 琛ㄥ崟绫诲瀷
-     *
-     * @param formType 琛ㄥ崟绫诲瀷
-     */
-    public static String findByType(String formType) {
-        if (StringUtils.isBlank(formType)) {
-            return StrUtil.EMPTY;
-        }
-
-        return Arrays.stream(FormTypeEnum.values())
-            .filter(statusEnum -> statusEnum.getType().equals(formType))
-            .findFirst()
-            .map(FormTypeEnum::getDesc)
-            .orElse(StrUtil.EMPTY);
-    }
-}
-
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java
index a282958..0fe5cfe 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java
@@ -3,8 +3,10 @@
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
+import java.util.Arrays;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * 娑堟伅绫诲瀷鏋氫妇
@@ -14,14 +16,17 @@
 @Getter
 @AllArgsConstructor
 public enum MessageTypeEnum {
+
     /**
      * 绔欏唴淇�
      */
     SYSTEM_MESSAGE("1", "绔欏唴淇�"),
+
     /**
      * 閭
      */
     EMAIL_MESSAGE("2", "閭"),
+
     /**
      * 鐭俊
      */
@@ -31,21 +36,18 @@
 
     private final String desc;
 
-    private final static Map<String, MessageTypeEnum> MESSAGE_TYPE_ENUM_MAP = new ConcurrentHashMap<>(MessageTypeEnum.values().length);
-
-    static {
-        for (MessageTypeEnum messageType : MessageTypeEnum.values()) {
-            MESSAGE_TYPE_ENUM_MAP.put(messageType.code, messageType);
-        }
-    }
+    private static final Map<String, MessageTypeEnum> MESSAGE_TYPE_ENUM_MAP = Arrays.stream(values())
+        .collect(Collectors.toConcurrentMap(MessageTypeEnum::getCode, Function.identity()));
 
     /**
      * 鏍规嵁娑堟伅绫诲瀷 code 鑾峰彇 MessageTypeEnum
+     *
      * @param code 娑堟伅绫诲瀷code
      * @return MessageTypeEnum
      */
     public static MessageTypeEnum getByCode(String code) {
-        return MESSAGE_TYPE_ENUM_MAP.get(code);
+        return MESSAGE_TYPE_ENUM_MAP.getOrDefault(code, null);
     }
+
 }
 
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java
new file mode 100644
index 0000000..60be92f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java
@@ -0,0 +1,109 @@
+package org.dromara.workflow.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.dromara.common.core.exception.ServiceException;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 浠诲姟鍒嗛厤浜烘灇涓�
+ *
+ * @author AprilWind
+ */
+@Getter
+@AllArgsConstructor
+public enum TaskAssigneeEnum {
+
+    /**
+     * 鐢ㄦ埛
+     */
+    USER("鐢ㄦ埛", ""),
+
+    /**
+     * 瑙掕壊
+     */
+    ROLE("瑙掕壊", "role:"),
+
+    /**
+     * 閮ㄩ棬
+     */
+    DEPT("閮ㄩ棬", "dept:"),
+
+    /**
+     * 宀椾綅
+     */
+    POST("宀椾綅", "post:");
+
+    private final String desc;
+    private final String code;
+
+    /**
+     * 鏍规嵁鎻忚堪鑾峰彇瀵瑰簲鐨勬灇涓剧被鍨�
+     * <p>
+     * 閫氳繃浼犲叆鎻忚堪锛屾煡鎵惧苟杩斿洖鍖归厤鐨勬灇涓鹃」銆傚鏋滄湭鎵惧埌鍖归厤椤癸紝浼氭姏鍑� {@link ServiceException}銆�
+     * </p>
+     *
+     * @param desc 鎻忚堪锛岀敤浜庡尮閰嶅搴旂殑鏋氫妇椤�
+     * @return TaskAssigneeEnum 杩斿洖瀵瑰簲鐨勬灇涓剧被鍨�
+     * @throws ServiceException 濡傛灉鏈壘鍒板尮閰嶇殑鏋氫妇椤�
+     */
+    public static TaskAssigneeEnum fromDesc(String desc) {
+        for (TaskAssigneeEnum type : values()) {
+            if (type.getDesc().equals(desc)) {
+                return type;
+            }
+        }
+        throw new ServiceException("鏈煡鐨勫姙鐞嗕汉绫诲瀷: " + desc);
+    }
+
+    /**
+     * 鏍规嵁浠g爜鑾峰彇瀵瑰簲鐨勬灇涓剧被鍨�
+     * <p>
+     * 閫氳繃浼犲叆浠g爜锛屾煡鎵惧苟杩斿洖鍖归厤鐨勬灇涓鹃」銆傚鏋滄湭鎵惧埌鍖归厤椤癸紝浼氭姏鍑� {@link ServiceException}銆�
+     * </p>
+     *
+     * @param code 浠g爜锛岀敤浜庡尮閰嶅搴旂殑鏋氫妇椤�
+     * @return TaskAssigneeEnum 杩斿洖瀵瑰簲鐨勬灇涓剧被鍨�
+     * @throws IllegalArgumentException 濡傛灉鏈壘鍒板尮閰嶇殑鏋氫妇椤�
+     */
+    public static TaskAssigneeEnum fromCode(String code) {
+        for (TaskAssigneeEnum type : values()) {
+            if (type.getCode().equals(code)) {
+                return type;
+            }
+        }
+        throw new ServiceException("鏈煡鐨勫姙鐞嗕汉绫诲瀷浠g爜: " + code);
+    }
+
+    /**
+     * 鑾峰彇鎵�鏈夊姙鐞嗕汉绫诲瀷鐨勬弿杩板垪琛�
+     * <p>
+     * 鑾峰彇褰撳墠鏋氫妇绫绘墍鏈夐」鐨勬弿杩板瓧娈靛垪琛紝閫氬父鐢ㄤ簬灞曠ず閫夋嫨椤广��
+     * </p>
+     *
+     * @return List<String> 杩斿洖鎵�鏈夊姙鐞嗕汉绫诲瀷鐨勬弿杩板垪琛�
+     */
+    public static List<String> getAssigneeTypeList() {
+        return Arrays.stream(values())
+            .map(TaskAssigneeEnum::getDesc)
+            .collect(Collectors.toList());
+    }
+
+    /**
+     * 鑾峰彇鎵�鏈夊姙鐞嗕汉绫诲瀷鐨勪唬鐮佸垪琛�
+     * <p>
+     * 鑾峰彇褰撳墠鏋氫妇绫绘墍鏈夐」鐨勪唬鐮佸瓧娈靛垪琛紝閫氬父鐢ㄤ簬绋嬪簭鍐呴儴閫昏緫鐨勫垽鏂��
+     * </p>
+     *
+     * @return List<String> 杩斿洖鎵�鏈夊姙鐞嗕汉绫诲瀷鐨勪唬鐮佸垪琛�
+     */
+    public static List<String> getAssigneeCodeList() {
+        return Arrays.stream(values())
+            .map(TaskAssigneeEnum::getCode)
+            .collect(Collectors.toList());
+    }
+}
+
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java
new file mode 100644
index 0000000..eed1b91
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java
@@ -0,0 +1,49 @@
+package org.dromara.workflow.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 浜哄憳绫诲瀷
+ *
+ * @author AprilWind
+ */
+@Getter
+@AllArgsConstructor
+public enum TaskAssigneeType {
+
+    /**
+     * 寰呭姙浠诲姟鐨勫鎵逛汉鏉冮檺
+     * <p>璇ユ潈闄愯〃绀虹敤鎴锋槸寰呭姙浠诲姟鐨勫鎵逛汉锛岃礋璐e鏍镐换鍔$殑鎵ц鎯呭喌銆�</p>
+     */
+    APPROVER("1", "寰呭姙浠诲姟鐨勫鎵逛汉鏉冮檺"),
+
+    /**
+     * 寰呭姙浠诲姟鐨勮浆鍔炰汉鏉冮檺
+     * <p>璇ユ潈闄愯〃绀虹敤鎴锋槸寰呭姙浠诲姟鐨勮浆鍔炰汉锛岃礋璐e皢浠诲姟鍒嗛厤缁欏叾浠栦汉鍛樸��</p>
+     */
+    TRANSFER("2", "寰呭姙浠诲姟鐨勮浆鍔炰汉鏉冮檺"),
+
+    /**
+     * 寰呭姙浠诲姟鐨勫鎵樹汉鏉冮檺
+     * <p>璇ユ潈闄愯〃绀虹敤鎴锋槸寰呭姙浠诲姟鐨勫鎵樹汉锛岃兘澶熷鎵樺叾浠栦汉浠d负澶勭悊浠诲姟銆�</p>
+     */
+    DELEGATE("3", "寰呭姙浠诲姟鐨勫鎵樹汉鏉冮檺"),
+
+    /**
+     * 寰呭姙浠诲姟鐨勬妱閫佷汉鏉冮檺
+     * <p>璇ユ潈闄愯〃绀虹敤鎴锋槸寰呭姙浠诲姟鐨勬妱閫佷汉锛屼粎鎺ユ敹浠诲姟淇℃伅鐨勯�氱煡锛屼笉鍙備笌浠诲姟鐨勫鎵规垨澶勭悊銆�</p>
+     */
+    COPY("4", "寰呭姙浠诲姟鐨勬妱閫佷汉鏉冮檺");
+
+    /**
+     * 绫诲瀷
+     */
+    private final String code;
+
+    /**
+     * 鎻忚堪
+     */
+    private final String description;
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java
index 7b2f55c..d18ebb0 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java
@@ -3,9 +3,10 @@
 import cn.hutool.core.util.StrUtil;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
-import org.apache.commons.lang3.StringUtils;
 
 import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * 浠诲姟鐘舵�佹灇涓�
@@ -15,50 +16,62 @@
 @Getter
 @AllArgsConstructor
 public enum TaskStatusEnum {
+
     /**
      * 鎾ら攢
      */
     CANCEL("cancel", "鎾ら攢"),
+
     /**
      * 閫氳繃
      */
     PASS("pass", "閫氳繃"),
+
     /**
      * 寰呭鏍�
      */
     WAITING("waiting", "寰呭鏍�"),
+
     /**
      * 浣滃簾
      */
     INVALID("invalid", "浣滃簾"),
+
     /**
      * 閫�鍥�
      */
     BACK("back", "閫�鍥�"),
+
     /**
      * 缁堟
      */
     TERMINATION("termination", "缁堟"),
+
     /**
      * 杞姙
      */
     TRANSFER("transfer", "杞姙"),
+
     /**
      * 濮旀墭
      */
-    PENDING("pending", "濮旀墭"),
+    DEPUTE("depute", "濮旀墭"),
+
     /**
      * 鎶勯��
      */
     COPY("copy", "鎶勯��"),
+
     /**
      * 鍔犵
      */
     SIGN("sign", "鍔犵"),
+
     /**
      * 鍑忕
      */
     SIGN_OFF("sign_off", "鍑忕"),
+
     /**
      * 瓒呮椂
      */
@@ -74,21 +87,18 @@
      */
     private final String desc;
 
+    private static final Map<String, String> STATUS_DESC_MAP = Arrays.stream(values())
+        .collect(Collectors.toConcurrentMap(TaskStatusEnum::getStatus, TaskStatusEnum::getDesc));
+
     /**
      * 浠诲姟涓氬姟鐘舵��
      *
      * @param status 鐘舵��
      */
     public static String findByStatus(String status) {
-        if (StringUtils.isBlank(status)) {
-            return StrUtil.EMPTY;
-        }
-
-        return Arrays.stream(TaskStatusEnum.values())
-            .filter(statusEnum -> statusEnum.getStatus().equals(status))
-            .findFirst()
-            .map(TaskStatusEnum::getDesc)
-            .orElse(StrUtil.EMPTY);
+        // 浠庣紦瀛樹腑鐩存帴鑾峰彇鎻忚堪
+        return STATUS_DESC_MAP.getOrDefault(status, StrUtil.EMPTY);
     }
+
 }
 
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java
new file mode 100644
index 0000000..08f1808
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java
@@ -0,0 +1,16 @@
+package org.dromara.workflow.config;
+
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * warmFlow閰嶇疆
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Configuration
+public class WarmFlowConfig {
+
+}
+
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
deleted file mode 100644
index 842d3d6..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package org.dromara.workflow.controller;
-
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotEmpty;
-import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.domain.R;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.log.enums.BusinessType;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.workflow.domain.bo.ModelBo;
-import org.dromara.workflow.domain.vo.ModelVo;
-import org.dromara.workflow.service.IActModelService;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.repository.Model;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * 妯″瀷绠$悊 鎺у埗灞�
- *
- * @author may
- */
-@Validated
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/workflow/model")
-public class ActModelController extends BaseController {
-
-    @Autowired(required = false)
-    private RepositoryService repositoryService;
-    private final IActModelService actModelService;
-
-
-    /**
-     * 鍒嗛〉鏌ヨ妯″瀷
-     *
-     * @param modelBo 妯″瀷鍙傛暟
-     */
-    @GetMapping("/list")
-    public TableDataInfo<Model> page(ModelBo modelBo, PageQuery pageQuery) {
-        return actModelService.page(modelBo, pageQuery);
-    }
-
-    /**
-     * 鏂板妯″瀷
-     *
-     * @param modelBo 妯″瀷璇锋眰瀵硅薄
-     */
-    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/save")
-    public R<Void> saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) {
-        return toAjax(actModelService.saveNewModel(modelBo));
-    }
-
-    /**
-     * 鏌ヨ妯″瀷
-     *
-     * @param id 妯″瀷id
-     */
-    @GetMapping("/getInfo/{id}")
-    public R<ModelVo> getInfo(@NotBlank(message = "妯″瀷id涓嶈兘涓虹┖") @PathVariable String id) {
-        return R.ok(actModelService.getInfo(id));
-    }
-
-    /**
-     * 淇敼妯″瀷淇℃伅
-     *
-     * @param modelBo 妯″瀷鏁版嵁
-     */
-    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.UPDATE)
-    @RepeatSubmit()
-    @PutMapping(value = "/update")
-    public R<Void> update(@RequestBody ModelBo modelBo) {
-        return toAjax(actModelService.update(modelBo));
-    }
-
-    /**
-     * 缂栬緫XMl妯″瀷
-     *
-     * @param modelBo 妯″瀷鏁版嵁
-     */
-    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.UPDATE)
-    @RepeatSubmit()
-    @PutMapping(value = "/editModelXml")
-    public R<Void> editModel(@Validated(EditGroup.class) @RequestBody ModelBo modelBo) {
-        return toAjax(actModelService.editModelXml(modelBo));
-    }
-
-    /**
-     * 鍒犻櫎娴佺▼妯″瀷
-     *
-     * @param ids 妯″瀷id
-     */
-    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.DELETE)
-    @RepeatSubmit()
-    @DeleteMapping("/{ids}")
-    @Transactional(rollbackFor = Exception.class)
-    public R<Void> delete(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖") @PathVariable String[] ids) {
-        Arrays.stream(ids).parallel().forEachOrdered(repositoryService::deleteModel);
-        return R.ok();
-    }
-
-    /**
-     * 妯″瀷閮ㄧ讲
-     *
-     * @param id 妯″瀷id
-     */
-    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/modelDeploy/{id}")
-    public R<Void> deploy(@NotBlank(message = "妯″瀷id涓嶈兘涓虹┖") @PathVariable("id") String id) {
-        return toAjax(actModelService.modelDeploy(id));
-    }
-
-    /**
-     * 瀵煎嚭妯″瀷zip鍘嬬缉鍖�
-     *
-     * @param modelIds 妯″瀷id
-     * @param response 鐩稿簲
-     */
-    @GetMapping("/export/zip/{modelIds}")
-    public void exportZip(@NotEmpty(message = "妯″瀷id涓嶈兘涓虹┖") @PathVariable List<String> modelIds,
-                          HttpServletResponse response) {
-        actModelService.exportZip(modelIds, response);
-    }
-
-    /**
-     * 澶嶅埗妯″瀷
-     *
-     * @param modelBo 妯″瀷鏁版嵁
-     */
-    @PostMapping("/copyModel")
-    public R<Void> copyModel(@RequestBody ModelBo modelBo) {
-        return toAjax(actModelService.copyModel(modelBo));
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java
deleted file mode 100644
index 5198bd1..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package org.dromara.workflow.controller;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
-import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.domain.R;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.log.enums.BusinessType;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.workflow.domain.bo.ProcessDefinitionBo;
-import org.dromara.workflow.domain.vo.ProcessDefinitionVo;
-import org.dromara.workflow.service.IActProcessDefinitionService;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-
-/**
- * 娴佺▼瀹氫箟绠$悊 鎺у埗灞�
- *
- * @author may
- */
-@Validated
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/workflow/processDefinition")
-public class ActProcessDefinitionController extends BaseController {
-
-    private final IActProcessDefinitionService actProcessDefinitionService;
-
-    /**
-     * 鍒嗛〉鏌ヨ
-     *
-     * @param bo 鍙傛暟
-     */
-    @GetMapping("/list")
-    public TableDataInfo<ProcessDefinitionVo> page(ProcessDefinitionBo bo, PageQuery pageQuery) {
-        return actProcessDefinitionService.page(bo, pageQuery);
-    }
-
-    /**
-     * 鏌ヨ鍘嗗彶娴佺▼瀹氫箟鍒楄〃
-     *
-     * @param key 娴佺▼瀹氫箟key
-     */
-    @GetMapping("/getListByKey/{key}")
-    public R<List<ProcessDefinitionVo>> getListByKey(@NotEmpty(message = "娴佺▼瀹氫箟key涓嶈兘涓虹┖") @PathVariable String key) {
-        return R.ok("鎿嶄綔鎴愬姛", actProcessDefinitionService.getListByKey(key));
-    }
-
-    /**
-     * 鏌ョ湅娴佺▼瀹氫箟鍥剧墖
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    @GetMapping("/definitionImage/{processDefinitionId}")
-    public R<String> definitionImage(@PathVariable String processDefinitionId) {
-        return R.ok("鎿嶄綔鎴愬姛", actProcessDefinitionService.definitionImage(processDefinitionId));
-    }
-
-    /**
-     * 鏌ョ湅娴佺▼瀹氫箟xml鏂囦欢
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    @GetMapping("/definitionXml/{processDefinitionId}")
-    public R<Map<String, Object>> definitionXml(@NotBlank(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖") @PathVariable String processDefinitionId) {
-        Map<String, Object> map = new HashMap<>();
-        String xmlStr = actProcessDefinitionService.definitionXml(processDefinitionId);
-        map.put("xml", Arrays.asList(xmlStr.split("\n")));
-        map.put("xmlStr", xmlStr);
-        return R.ok(map);
-    }
-
-    /**
-     * 鍒犻櫎娴佺▼瀹氫箟
-     *
-     * @param deploymentIds        閮ㄧ讲id
-     * @param processDefinitionIds 娴佺▼瀹氫箟id
-     */
-    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{deploymentIds}/{processDefinitionIds}")
-    public R<Void> deleteDeployment(@NotNull(message = "娴佺▼閮ㄧ讲id涓嶈兘涓虹┖") @PathVariable List<String> deploymentIds,
-                                    @NotNull(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖") @PathVariable List<String> processDefinitionIds) {
-        return toAjax(actProcessDefinitionService.deleteDeployment(deploymentIds, processDefinitionIds));
-    }
-
-    /**
-     * 婵�娲绘垨鑰呮寕璧锋祦绋嬪畾涔�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.UPDATE)
-    @RepeatSubmit()
-    @PutMapping("/updateDefinitionState/{processDefinitionId}")
-    public R<Void> updateDefinitionState(@NotBlank(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖") @PathVariable String processDefinitionId) {
-        return toAjax(actProcessDefinitionService.updateDefinitionState(processDefinitionId));
-    }
-
-    /**
-     * 杩佺Щ娴佺▼瀹氫箟
-     *
-     * @param currentProcessDefinitionId 褰撳墠娴佺▼瀹氫箟id
-     * @param fromProcessDefinitionId    闇�瑕佽縼绉诲埌鐨勬祦绋嬪畾涔塱d
-     */
-    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.UPDATE)
-    @RepeatSubmit()
-    @PutMapping("/migrationDefinition/{currentProcessDefinitionId}/{fromProcessDefinitionId}")
-    public R<Void> migrationDefinition(@NotBlank(message = "褰撳墠娴佺▼瀹氫箟id") @PathVariable String currentProcessDefinitionId,
-                                       @NotBlank(message = "闇�瑕佽縼绉诲埌鐨勬祦绋嬪畾涔塱d") @PathVariable String fromProcessDefinitionId) {
-        return toAjax(actProcessDefinitionService.migrationDefinition(currentProcessDefinitionId, fromProcessDefinitionId));
-    }
-
-    /**
-     * 娴佺▼瀹氫箟杞崲涓烘ā鍨�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.UPDATE)
-    @RepeatSubmit()
-    @PutMapping("/convertToModel/{processDefinitionId}")
-    public R<Void> convertToModel(@NotEmpty(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖") @PathVariable String processDefinitionId) {
-        return toAjax(actProcessDefinitionService.convertToModel(processDefinitionId));
-    }
-
-    /**
-     * 閫氳繃zip鎴杧ml閮ㄧ讲娴佺▼瀹氫箟
-     *
-     * @param file         鏂囦欢
-     * @param categoryCode 鍒嗙被
-     */
-    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.INSERT)
-    @PostMapping("/deployByFile")
-    public void deployByFile(@RequestParam("file") MultipartFile file, @RequestParam("categoryCode") String categoryCode) {
-        actProcessDefinitionService.deployByFile(file, categoryCode);
-    }
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java
deleted file mode 100644
index 931b9f5..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.dromara.workflow.controller;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.domain.R;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.log.enums.BusinessType;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.workflow.domain.bo.ProcessInstanceBo;
-import org.dromara.workflow.domain.bo.ProcessInvalidBo;
-import org.dromara.workflow.domain.bo.TaskUrgingBo;
-import org.dromara.workflow.domain.vo.ActHistoryInfoVo;
-import org.dromara.workflow.domain.vo.ProcessInstanceVo;
-import org.dromara.workflow.service.IActProcessInstanceService;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 娴佺▼瀹炰緥绠$悊 鎺у埗灞�
- *
- * @author may
- */
-@Validated
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/workflow/processInstance")
-public class ActProcessInstanceController extends BaseController {
-
-    private final IActProcessInstanceService actProcessInstanceService;
-
-    /**
-     * 鍒嗛〉鏌ヨ姝e湪杩愯鐨勬祦绋嬪疄渚�
-     *
-     * @param bo 鍙傛暟
-     */
-    @GetMapping("/getPageByRunning")
-    public TableDataInfo<ProcessInstanceVo> getPageByRunning(ProcessInstanceBo bo, PageQuery pageQuery) {
-        return actProcessInstanceService.getPageByRunning(bo, pageQuery);
-    }
-
-    /**
-     * 鍒嗛〉鏌ヨ宸茬粨鏉熺殑娴佺▼瀹炰緥
-     *
-     * @param bo 鍙傛暟
-     */
-    @GetMapping("/getPageByFinish")
-    public TableDataInfo<ProcessInstanceVo> getPageByFinish(ProcessInstanceBo bo, PageQuery pageQuery) {
-        return actProcessInstanceService.getPageByFinish(bo, pageQuery);
-    }
-
-    /**
-     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥�
-     *
-     * @param businessKey 涓氬姟id
-     */
-    @GetMapping("/getHistoryImage/{businessKey}")
-    public R<String> getHistoryImage(@NotBlank(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String businessKey) {
-        return R.ok("鎿嶄綔鎴愬姛", actProcessInstanceService.getHistoryImage(businessKey));
-    }
-
-    /**
-     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥捐繍琛屼腑锛屽巻鍙茬瓑鑺傜偣
-     *
-     * @param businessKey 涓氬姟id
-     */
-    @GetMapping("/getHistoryList/{businessKey}")
-    public R<Map<String, Object>> getHistoryList(@NotBlank(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String businessKey) {
-        return R.ok("鎿嶄綔鎴愬姛", actProcessInstanceService.getHistoryList(businessKey));
-    }
-
-    /**
-     * 鑾峰彇瀹℃壒璁板綍
-     *
-     * @param businessKey 涓氬姟id
-     */
-    @GetMapping("/getHistoryRecord/{businessKey}")
-    public R<List<ActHistoryInfoVo>> getHistoryRecord(@NotBlank(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String businessKey) {
-        return R.ok(actProcessInstanceService.getHistoryRecord(businessKey));
-    }
-
-    /**
-     * 浣滃簾娴佺▼瀹炰緥锛屼笉浼氬垹闄ゅ巻鍙茶褰�(鍒犻櫎杩愯涓殑瀹炰緥)
-     *
-     * @param processInvalidBo 鍙傛暟
-     */
-    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.DELETE)
-    @RepeatSubmit()
-    @PostMapping("/deleteRunInstance")
-    public R<Void> deleteRunInstance(@Validated(AddGroup.class) @RequestBody ProcessInvalidBo processInvalidBo) {
-        return toAjax(actProcessInstanceService.deleteRunInstance(processInvalidBo));
-    }
-
-    /**
-     * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
-     *
-     * @param businessKeys 涓氬姟id
-     */
-    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.DELETE)
-    @RepeatSubmit()
-    @DeleteMapping("/deleteRunAndHisInstance/{businessKeys}")
-    public R<Void> deleteRunAndHisInstance(@NotNull(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String[] businessKeys) {
-        return toAjax(actProcessInstanceService.deleteRunAndHisInstance(Arrays.asList(businessKeys)));
-    }
-
-    /**
-     * 宸插畬鎴愮殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
-     *
-     * @param businessKeys 涓氬姟id
-     */
-    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.DELETE)
-    @RepeatSubmit()
-    @DeleteMapping("/deleteFinishAndHisInstance/{businessKeys}")
-    public R<Void> deleteFinishAndHisInstance(@NotNull(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String[] businessKeys) {
-        return toAjax(actProcessInstanceService.deleteFinishAndHisInstance(Arrays.asList(businessKeys)));
-    }
-
-    /**
-     * 鎾ら攢娴佺▼鐢宠
-     *
-     * @param businessKey 涓氬姟id
-     */
-    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/cancelProcessApply/{businessKey}")
-    public R<Void> cancelProcessApply(@NotBlank(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String businessKey) {
-        return toAjax(actProcessInstanceService.cancelProcessApply(businessKey));
-    }
-
-    /**
-     * 鍒嗛〉鏌ヨ褰撳墠鐧诲綍浜哄崟鎹�
-     *
-     * @param bo 鍙傛暟
-     */
-    @GetMapping("/getPageByCurrent")
-    public TableDataInfo<ProcessInstanceVo> getPageByCurrent(ProcessInstanceBo bo, PageQuery pageQuery) {
-        return actProcessInstanceService.getPageByCurrent(bo, pageQuery);
-    }
-
-    /**
-     * 浠诲姟鍌姙(缁欏綋鍓嶄换鍔″姙鐞嗕汉鍙戦�佺珯鍐呬俊锛岄偖浠讹紝鐭俊绛�)
-     *
-     * @param taskUrgingBo 浠诲姟鍌姙
-     */
-    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/taskUrging")
-    public R<Void> taskUrging(@RequestBody TaskUrgingBo taskUrgingBo) {
-        return toAjax(actProcessInstanceService.taskUrging(taskUrgingBo));
-    }
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java
deleted file mode 100644
index 25724b6..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java
+++ /dev/null
@@ -1,295 +0,0 @@
-package org.dromara.workflow.controller;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.convert.Convert;
-import jakarta.validation.constraints.NotBlank;
-import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.domain.R;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.log.enums.BusinessType;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.satoken.utils.LoginHelper;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.workflow.domain.WfTaskBackNode;
-import org.dromara.workflow.domain.bo.*;
-import org.dromara.workflow.domain.vo.TaskVo;
-import org.dromara.workflow.domain.vo.VariableVo;
-import org.dromara.workflow.service.IActTaskService;
-import org.dromara.workflow.service.IWfTaskBackNodeService;
-import org.dromara.workflow.utils.QueryUtils;
-import org.flowable.engine.TaskService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * 浠诲姟绠$悊 鎺у埗灞�
- *
- * @author may
- */
-@Validated
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/workflow/task")
-public class ActTaskController extends BaseController {
-
-    @Autowired(required = false)
-    private TaskService taskService;
-    private final IActTaskService actTaskService;
-    private final IWfTaskBackNodeService wfTaskBackNodeService;
-
-
-    /**
-     * 鍚姩浠诲姟
-     *
-     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/startWorkFlow")
-    public R<Map<String, Object>> startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) {
-        Map<String, Object> map = actTaskService.startWorkFlow(startProcessBo);
-        return R.ok("鎻愪氦鎴愬姛", map);
-    }
-
-    /**
-     * 鍔炵悊浠诲姟
-     *
-     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/completeTask")
-    public R<Void> completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) {
-        return toAjax(actTaskService.completeTask(completeTaskBo));
-    }
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @GetMapping("/getPageByTaskWait")
-    public TableDataInfo<TaskVo> getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) {
-        return actTaskService.getPageByTaskWait(taskBo, pageQuery);
-    }
-
-    /**
-     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊緟鍔炰换鍔�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @GetMapping("/getPageByAllTaskWait")
-    public TableDataInfo<TaskVo> getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) {
-        return actTaskService.getPageByAllTaskWait(taskBo, pageQuery);
-    }
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @GetMapping("/getPageByTaskFinish")
-    public TableDataInfo<TaskVo> getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
-        return actTaskService.getPageByTaskFinish(taskBo, pageQuery);
-    }
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @GetMapping("/getPageByTaskCopy")
-    public TableDataInfo<TaskVo> getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) {
-        return actTaskService.getPageByTaskCopy(taskBo, pageQuery);
-    }
-
-    /**
-     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊凡鍔炰换鍔�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @GetMapping("/getPageByAllTaskFinish")
-    public TableDataInfo<TaskVo> getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
-        return actTaskService.getPageByAllTaskFinish(taskBo, pageQuery);
-    }
-
-    /**
-     * 绛炬敹锛堟嬀鍙栵級浠诲姟
-     *
-     * @param taskId 浠诲姟id
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/claim/{taskId}")
-    public R<Void> claimTask(@NotBlank(message = "浠诲姟id涓嶈兘涓虹┖") @PathVariable String taskId) {
-        try {
-            taskService.claim(taskId, Convert.toStr(LoginHelper.getUserId()));
-            return R.ok();
-        } catch (Exception e) {
-            e.printStackTrace();
-            return R.fail("绛炬敹浠诲姟澶辫触锛�" + e.getMessage());
-        }
-    }
-
-    /**
-     * 褰掕繕锛堟嬀鍙栫殑锛変换鍔�
-     *
-     * @param taskId 浠诲姟id
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/returnTask/{taskId}")
-    public R<Void> returnTask(@NotBlank(message = "浠诲姟id涓嶈兘涓虹┖") @PathVariable String taskId) {
-        try {
-            taskService.setAssignee(taskId, null);
-            return R.ok();
-        } catch (Exception e) {
-            e.printStackTrace();
-            return R.fail("褰掕繕浠诲姟澶辫触锛�" + e.getMessage());
-        }
-    }
-
-    /**
-     * 濮旀淳浠诲姟
-     *
-     * @param delegateBo 鍙傛暟
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/delegateTask")
-    public R<Void> delegateTask(@Validated({AddGroup.class}) @RequestBody DelegateBo delegateBo) {
-        return toAjax(actTaskService.delegateTask(delegateBo));
-    }
-
-    /**
-     * 缁堟浠诲姟
-     *
-     * @param terminationBo 鍙傛暟
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.DELETE)
-    @RepeatSubmit()
-    @PostMapping("/terminationTask")
-    public R<Void> terminationTask(@RequestBody TerminationBo terminationBo) {
-        return toAjax(actTaskService.terminationTask(terminationBo));
-    }
-
-    /**
-     * 杞姙浠诲姟
-     *
-     * @param transmitBo 鍙傛暟
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/transferTask")
-    public R<Void> transferTask(@Validated({AddGroup.class}) @RequestBody TransmitBo transmitBo) {
-        return toAjax(actTaskService.transferTask(transmitBo));
-    }
-
-    /**
-     * 浼氱浠诲姟鍔犵
-     *
-     * @param addMultiBo 鍙傛暟
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/addMultiInstanceExecution")
-    public R<Void> addMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody AddMultiBo addMultiBo) {
-        return toAjax(actTaskService.addMultiInstanceExecution(addMultiBo));
-    }
-
-    /**
-     * 浼氱浠诲姟鍑忕
-     *
-     * @param deleteMultiBo 鍙傛暟
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/deleteMultiInstanceExecution")
-    public R<Void> deleteMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody DeleteMultiBo deleteMultiBo) {
-        return toAjax(actTaskService.deleteMultiInstanceExecution(deleteMultiBo));
-    }
-
-    /**
-     * 椹冲洖瀹℃壒
-     *
-     * @param backProcessBo 鍙傛暟
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/backProcess")
-    public R<String> backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo backProcessBo) {
-        return R.ok("鎿嶄綔鎴愬姛", actTaskService.backProcess(backProcessBo));
-    }
-
-    /**
-     * 鑾峰彇褰撳墠浠诲姟
-     *
-     * @param taskId 浠诲姟id
-     */
-    @GetMapping("/getTaskById/{taskId}")
-    public R<TaskVo> getTaskById(@PathVariable String taskId) {
-        return R.ok(QueryUtils.getTask(taskId));
-    }
-
-
-    /**
-     * 淇敼浠诲姟鍔炵悊浜�
-     *
-     * @param taskIds 浠诲姟id
-     * @param userId  鍔炵悊浜篿d
-     */
-    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.UPDATE)
-    @RepeatSubmit()
-    @PutMapping("/updateAssignee/{taskIds}/{userId}")
-    public R<Void> updateAssignee(@PathVariable String[] taskIds, @PathVariable String userId) {
-        return toAjax(actTaskService.updateAssignee(taskIds, userId));
-    }
-
-    /**
-     * 鏌ヨ娴佺▼鍙橀噺
-     *
-     * @param taskId 浠诲姟id
-     */
-    @GetMapping("/getInstanceVariable/{taskId}")
-    public R<List<VariableVo>> getProcessInstVariable(@PathVariable String taskId) {
-        return R.ok(actTaskService.getInstanceVariable(taskId));
-    }
-
-    /**
-     * 鑾峰彇鍙┏鍥炲緱浠诲姟鑺傜偣
-     *
-     * @param processInstanceId 娴佺▼瀹炰緥id
-     */
-    @GetMapping("/getTaskNodeList/{processInstanceId}")
-    public R<List<WfTaskBackNode>> getNodeList(@PathVariable String processInstanceId) {
-        return R.ok(CollUtil.reverse(wfTaskBackNodeService.getListByInstanceId(processInstanceId)));
-    }
-
-    /**
-     * 鏌ヨ宸ヤ綔娴佷换鍔$敤鎴烽�夋嫨鍔犵浜哄憳
-     *
-     * @param taskId 浠诲姟id
-     */
-    @GetMapping("/getTaskUserIdsByAddMultiInstance/{taskId}")
-    public R<String> getTaskUserIdsByAddMultiInstance(@PathVariable String taskId) {
-        return R.ok("鎿嶄綔鎴愬姛", actTaskService.getTaskUserIdsByAddMultiInstance(taskId));
-    }
-
-    /**
-     * 鏌ヨ宸ヤ綔娴侀�夋嫨鍑忕浜哄憳
-     *
-     * @param taskId 浠诲姟id
-     */
-    @GetMapping("/getListByDeleteMultiInstance/{taskId}")
-    public R<List<TaskVo>> getListByDeleteMultiInstance(@PathVariable String taskId) {
-        return R.ok(actTaskService.getListByDeleteMultiInstance(taskId));
-    }
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java
new file mode 100644
index 0000000..37d414f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java
@@ -0,0 +1,132 @@
+package org.dromara.workflow.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.lang.tree.Tree;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.domain.bo.FlowCategoryBo;
+import org.dromara.workflow.domain.vo.FlowCategoryVo;
+import org.dromara.workflow.service.IFlwCategoryService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 娴佺▼鍒嗙被
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/category")
+public class FlwCategoryController extends BaseController {
+
+    private final IFlwCategoryService flwCategoryService;
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被鍒楄〃
+     */
+    @SaCheckPermission("workflow:category:list")
+    @GetMapping("/list")
+    public R<List<FlowCategoryVo>> list(FlowCategoryBo bo) {
+        List<FlowCategoryVo> list = flwCategoryService.queryList(bo);
+        return R.ok(list);
+    }
+
+    /**
+     * 瀵煎嚭娴佺▼鍒嗙被鍒楄〃
+     */
+    @SaCheckPermission("workflow:category:export")
+    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(FlowCategoryBo bo, HttpServletResponse response) {
+        List<FlowCategoryVo> list = flwCategoryService.queryList(bo);
+        ExcelUtil.exportExcel(list, "娴佺▼鍒嗙被", FlowCategoryVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍒嗙被璇︾粏淇℃伅
+     *
+     * @param categoryId 涓婚敭
+     */
+    @SaCheckPermission("workflow:category:query")
+    @GetMapping("/{categoryId}")
+    public R<FlowCategoryVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖") @PathVariable Long categoryId) {
+        flwCategoryService.checkCategoryDataScope(categoryId);
+        return R.ok(flwCategoryService.queryById(categoryId));
+    }
+
+    /**
+     * 鏂板娴佺▼鍒嗙被
+     */
+    @SaCheckPermission("workflow:category:add")
+    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody FlowCategoryBo category) {
+        if (!flwCategoryService.checkCategoryNameUnique(category)) {
+            return R.fail("鏂板娴佺▼鍒嗙被'" + category.getCategoryName() + "'澶辫触锛屾祦绋嬪垎绫诲悕绉板凡瀛樺湪");
+        }
+        return toAjax(flwCategoryService.insertByBo(category));
+    }
+
+    /**
+     * 淇敼娴佺▼鍒嗙被
+     */
+    @SaCheckPermission("workflow:category:edit")
+    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody FlowCategoryBo category) {
+        Long categoryId = category.getCategoryId();
+        flwCategoryService.checkCategoryDataScope(categoryId);
+        if (!flwCategoryService.checkCategoryNameUnique(category)) {
+            return R.fail("淇敼娴佺▼鍒嗙被'" + category.getCategoryName() + "'澶辫触锛屾祦绋嬪垎绫诲悕绉板凡瀛樺湪");
+        } else if (category.getParentId().equals(categoryId)) {
+            return R.fail("淇敼娴佺▼鍒嗙被'" + category.getCategoryName() + "'澶辫触锛屼笂绾ф祦绋嬪垎绫讳笉鑳芥槸鑷繁");
+        }
+        return toAjax(flwCategoryService.updateByBo(category));
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼鍒嗙被
+     *
+     * @param categoryId 涓婚敭
+     */
+    @SaCheckPermission("workflow:category:remove")
+    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{categoryId}")
+    public R<Void> remove(@PathVariable Long categoryId) {
+        if (flwCategoryService.hasChildByCategoryId(categoryId)) {
+            return R.warn("瀛樺湪涓嬬骇娴佺▼鍒嗙被,涓嶅厑璁稿垹闄�");
+        }
+        if (flwCategoryService.checkCategoryExistDefinition(categoryId)) {
+            return R.warn("娴佺▼鍒嗙被瀛樺湪娴佺▼瀹氫箟,涓嶅厑璁稿垹闄�");
+        }
+        return toAjax(flwCategoryService.deleteWithValidById(categoryId));
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍒嗙被鏍戝垪琛�
+     *
+     * @param categoryBo 娴佺▼鍒嗙被
+     */
+    @GetMapping("/categoryTree")
+    public R<List<Tree<String>>> categoryTree(FlowCategoryBo categoryBo) {
+        return R.ok(flwCategoryService.selectCategoryTreeList(categoryBo));
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java
new file mode 100644
index 0000000..10d9de8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java
@@ -0,0 +1,194 @@
+package org.dromara.workflow.controller;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.warm.flow.core.entity.Definition;
+import org.dromara.warm.flow.core.service.DefService;
+import org.dromara.warm.flow.orm.entity.FlowDefinition;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.domain.vo.FlowDefinitionVo;
+import org.dromara.workflow.service.IFlwDefinitionService;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 娴佺▼瀹氫箟绠$悊 鎺у埗灞�
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/definition")
+public class FlwDefinitionController extends BaseController {
+
+    private final DefService defService;
+    private final IFlwDefinitionService flwDefinitionService;
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param flowDefinition 鍙傛暟
+     * @param pageQuery      鍒嗛〉
+     */
+    @GetMapping("/list")
+    public TableDataInfo<FlowDefinitionVo> list(FlowDefinition flowDefinition, PageQuery pageQuery) {
+        return flwDefinitionService.queryList(flowDefinition, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ鏈彂甯冪殑娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param flowDefinition 鍙傛暟
+     * @param pageQuery      鍒嗛〉
+     */
+    @GetMapping("/unPublishList")
+    public TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) {
+        return flwDefinitionService.unPublishList(flowDefinition, pageQuery);
+    }
+
+    /**
+     * 鑾峰彇娴佺▼瀹氫箟璇︾粏淇℃伅
+     *
+     * @param id 娴佺▼瀹氫箟id
+     */
+    @GetMapping(value = "/{id}")
+    public R<Definition> getInfo(@PathVariable Long id) {
+        return R.ok(defService.getById(id));
+    }
+
+    /**
+     * 鏂板娴佺▼瀹氫箟
+     *
+     * @param flowDefinition 鍙傛暟
+     */
+    @Log(title = "娴佺▼瀹氫箟", businessType = BusinessType.INSERT)
+    @PostMapping
+    @RepeatSubmit()
+    @Transactional(rollbackFor = Exception.class)
+    public R<Boolean> add(@RequestBody FlowDefinition flowDefinition) {
+        return R.ok(defService.checkAndSave(flowDefinition));
+    }
+
+    /**
+     * 淇敼娴佺▼瀹氫箟
+     *
+     * @param flowDefinition 鍙傛暟
+     */
+    @Log(title = "娴佺▼瀹氫箟", businessType = BusinessType.UPDATE)
+    @PutMapping
+    @RepeatSubmit()
+    @Transactional(rollbackFor = Exception.class)
+    public R<Boolean> edit(@RequestBody FlowDefinition flowDefinition) {
+        return R.ok(defService.updateById(flowDefinition));
+    }
+
+    /**
+     * 鍙戝竷娴佺▼瀹氫箟
+     *
+     * @param id 娴佺▼瀹氫箟id
+     */
+    @Log(title = "娴佺▼瀹氫箟", businessType = BusinessType.INSERT)
+    @PutMapping("/publish/{id}")
+    @RepeatSubmit()
+    public R<Boolean> publish(@PathVariable Long id) {
+        return R.ok(flwDefinitionService.publish(id));
+    }
+
+    /**
+     * 鍙栨秷鍙戝竷娴佺▼瀹氫箟
+     *
+     * @param id 娴佺▼瀹氫箟id
+     */
+    @Log(title = "娴佺▼瀹氫箟", businessType = BusinessType.INSERT)
+    @PutMapping("/unPublish/{id}")
+    @RepeatSubmit()
+    @Transactional(rollbackFor = Exception.class)
+    public R<Boolean> unPublish(@PathVariable Long id) {
+        return R.ok(defService.unPublish(id));
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼瀹氫箟
+     */
+    @Log(title = "娴佺▼瀹氫箟", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@PathVariable List<Long> ids) {
+        return toAjax(flwDefinitionService.removeDef(ids));
+    }
+
+    /**
+     * 澶嶅埗娴佺▼瀹氫箟
+     *
+     * @param id 娴佺▼瀹氫箟id
+     */
+    @Log(title = "娴佺▼瀹氫箟", businessType = BusinessType.INSERT)
+    @PostMapping("/copy/{id}")
+    @RepeatSubmit()
+    @Transactional(rollbackFor = Exception.class)
+    public R<Boolean> copy(@PathVariable Long id) {
+        return R.ok(defService.copyDef(id));
+    }
+
+    /**
+     * 瀵煎叆娴佺▼瀹氫箟
+     *
+     * @param file     鏂囦欢
+     * @param category 鍒嗙被
+     */
+    @Log(title = "娴佺▼瀹氫箟", businessType = BusinessType.IMPORT)
+    @PostMapping("/importDef")
+    public R<Boolean> importDef(MultipartFile file, String category) {
+        return R.ok(flwDefinitionService.importJson(file, category));
+    }
+
+    /**
+     * 瀵煎嚭娴佺▼瀹氫箟
+     *
+     * @param id       娴佺▼瀹氫箟id
+     * @param response 鍝嶅簲
+     * @throws IOException 寮傚父
+     */
+    @Log(title = "娴佺▼瀹氫箟", businessType = BusinessType.EXPORT)
+    @PostMapping("/exportDef/{id}")
+    public void exportDef(@PathVariable Long id, HttpServletResponse response) throws IOException {
+        flwDefinitionService.exportDef(id, response);
+    }
+
+    /**
+     * 鑾峰彇娴佺▼瀹氫箟JSON瀛楃涓�
+     *
+     * @param id 娴佺▼瀹氫箟id
+     */
+    @GetMapping("/xmlString/{id}")
+    public R<String> xmlString(@PathVariable Long id) {
+        return R.ok("鎿嶄綔鎴愬姛", defService.exportJson(id));
+    }
+
+    /**
+     * 婵�娲�/鎸傝捣娴佺▼瀹氫箟
+     *
+     * @param id     娴佺▼瀹氫箟id
+     * @param active 婵�娲�/鎸傝捣
+     */
+    @RepeatSubmit()
+    @PutMapping("/active/{id}")
+    @Transactional(rollbackFor = Exception.class)
+    public R<Boolean> active(@PathVariable Long id, @RequestParam boolean active) {
+        return R.ok(active ? defService.active(id) : defService.unActive(id));
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java
new file mode 100644
index 0000000..ae99c16
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java
@@ -0,0 +1,157 @@
+package org.dromara.workflow.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.warm.flow.core.service.InsService;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.domain.bo.FlowCancelBo;
+import org.dromara.workflow.domain.bo.FlowInstanceBo;
+import org.dromara.workflow.domain.bo.FlowInvalidBo;
+import org.dromara.workflow.domain.vo.FlowInstanceVo;
+import org.dromara.workflow.service.IFlwInstanceService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 娴佺▼瀹炰緥绠$悊 鎺у埗灞�
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/instance")
+public class FlwInstanceController extends BaseController {
+
+    private final InsService insService;
+    private final IFlwInstanceService flwInstanceService;
+
+    /**
+     * 鏌ヨ姝e湪杩愯鐨勬祦绋嬪疄渚嬪垪琛�
+     *
+     * @param flowInstanceBo 娴佺▼瀹炰緥
+     * @param pageQuery      鍒嗛〉
+     */
+    @GetMapping("/pageByRunning")
+    public TableDataInfo<FlowInstanceVo> selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
+        return flwInstanceService.selectRunningInstanceList(flowInstanceBo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ宸茬粨鏉熺殑娴佺▼瀹炰緥鍒楄〃
+     *
+     * @param flowInstanceBo 娴佺▼瀹炰緥
+     * @param pageQuery      鍒嗛〉
+     */
+    @GetMapping("/pageByFinish")
+    public TableDataInfo<FlowInstanceVo> selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
+        return flwInstanceService.selectFinishInstanceList(flowInstanceBo, pageQuery);
+    }
+
+    /**
+     * 鏍规嵁涓氬姟id鏌ヨ娴佺▼瀹炰緥璇︾粏淇℃伅
+     *
+     * @param businessId 涓氬姟id
+     */
+    @GetMapping("/getInfo/{businessId}")
+    public R<FlowInstanceVo> getInfo(@PathVariable Long businessId) {
+        return R.ok(flwInstanceService.queryByBusinessId(businessId));
+    }
+
+    /**
+     * 鎸夌収涓氬姟id鍒犻櫎娴佺▼瀹炰緥
+     *
+     * @param businessIds 涓氬姟id
+     */
+    @DeleteMapping("/deleteByBusinessIds/{businessIds}")
+    public R<Void> deleteByBusinessIds(@PathVariable List<Long> businessIds) {
+        return toAjax(flwInstanceService.deleteByBusinessIds(businessIds));
+    }
+
+    /**
+     * 鎸夌収瀹炰緥id鍒犻櫎娴佺▼瀹炰緥
+     *
+     * @param instanceIds 瀹炰緥id
+     */
+    @DeleteMapping("/deleteByInstanceIds/{instanceIds}")
+    public R<Void> deleteByInstanceIds(@PathVariable List<Long> instanceIds) {
+        return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds));
+    }
+
+    /**
+     * 鎾ら攢娴佺▼
+     *
+     * @param bo 鍙傛暟
+     */
+    @RepeatSubmit()
+    @PutMapping("/cancelProcessApply")
+    public R<Void> cancelProcessApply(@RequestBody FlowCancelBo bo) {
+        return toAjax(flwInstanceService.cancelProcessApply(bo));
+    }
+
+    /**
+     * 婵�娲�/鎸傝捣娴佺▼瀹炰緥
+     *
+     * @param id     娴佺▼瀹炰緥id
+     * @param active 婵�娲�/鎸傝捣
+     */
+    @RepeatSubmit()
+    @PutMapping("/active/{id}")
+    public R<Boolean> active(@PathVariable Long id, @RequestParam boolean active) {
+        return R.ok(active ? insService.active(id) : insService.unActive(id));
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐧婚檰浜哄彂璧风殑娴佺▼瀹炰緥
+     *
+     * @param flowInstanceBo 鍙傛暟
+     * @param pageQuery      鍒嗛〉
+     */
+    @GetMapping("/pageByCurrent")
+    public TableDataInfo<FlowInstanceVo> selectCurrentInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
+        return flwInstanceService.selectCurrentInstanceList(flowInstanceBo, pageQuery);
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍥撅紝娴佺▼璁板綍
+     *
+     * @param businessId 涓氬姟id
+     */
+    @GetMapping("/flowImage/{businessId}")
+    public R<Map<String, Object>> flowImage(@PathVariable String businessId) {
+        return R.ok(flwInstanceService.flowImage(businessId));
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍙橀噺
+     *
+     * @param instanceId 娴佺▼瀹炰緥id
+     */
+    @GetMapping("/instanceVariable/{instanceId}")
+    public R<Map<String, Object>> instanceVariable(@PathVariable Long instanceId) {
+        return R.ok(flwInstanceService.instanceVariable(instanceId));
+    }
+
+    /**
+     * 浣滃簾娴佺▼
+     *
+     * @param bo 鍙傛暟
+     */
+    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/invalid")
+    public R<Boolean> invalid(@Validated @RequestBody FlowInvalidBo bo) {
+        return R.ok(flwInstanceService.processInvalid(bo));
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java
new file mode 100644
index 0000000..463916b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java
@@ -0,0 +1,201 @@
+package org.dromara.workflow.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.domain.dto.StartProcessReturnDTO;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.warm.flow.core.entity.Node;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.domain.bo.*;
+import org.dromara.workflow.domain.vo.FlowHisTaskVo;
+import org.dromara.workflow.domain.vo.FlowTaskVo;
+import org.dromara.workflow.service.IFlwTaskService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 浠诲姟绠$悊 鎺у埗灞�
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/task")
+public class FlwTaskController extends BaseController {
+
+    private final IFlwTaskService flwTaskService;
+
+    /**
+     * 鍚姩浠诲姟
+     *
+     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/startWorkFlow")
+    public R<StartProcessReturnDTO> startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) {
+        StartProcessReturnDTO startProcessReturn = flwTaskService.startWorkFlow(startProcessBo);
+        return R.ok("鎻愪氦鎴愬姛", startProcessReturn);
+    }
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/completeTask")
+    public R<Void> completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) {
+        return toAjax(flwTaskService.completeTask(completeTaskBo));
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @GetMapping("/pageByTaskWait")
+    public TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        return flwTaskService.pageByTaskWait(flowTaskBo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+
+    @GetMapping("/pageByTaskFinish")
+    public TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        return flwTaskService.pageByTaskFinish(flowTaskBo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ寰呭姙浠诲姟
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @GetMapping("/pageByAllTaskWait")
+    public TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        return flwTaskService.pageByAllTaskWait(flowTaskBo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ宸插姙浠诲姟
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @GetMapping("/pageByAllTaskFinish")
+    public TableDataInfo<FlowHisTaskVo> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        return flwTaskService.pageByAllTaskFinish(flowTaskBo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @GetMapping("/pageByTaskCopy")
+    public TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        return flwTaskService.pageByTaskCopy(flowTaskBo, pageQuery);
+    }
+
+    /**
+     * 鏍规嵁taskId鏌ヨ浠h〃浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     */
+    @GetMapping("/getTask/{taskId}")
+    public R<FlowTaskVo> getTask(@PathVariable Long taskId) {
+        return R.ok(flwTaskService.selectById(taskId));
+    }
+
+    /**
+     * 缁堟浠诲姟
+     *
+     * @param bo 鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/terminationTask")
+    public R<Boolean> terminationTask(@RequestBody FlowTerminationBo bo) {
+        return R.ok(flwTaskService.terminationTask(bo));
+    }
+
+    /**
+     * 浠诲姟鎿嶄綔
+     *
+     * @param bo            鍙傛暟
+     * @param taskOperation 鎿嶄綔绫诲瀷锛屽娲� delegateTask銆佽浆鍔� transferTask銆佸姞绛� addSignature銆佸噺绛� reductionSignature
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @PostMapping("/taskOperation/{taskOperation}")
+    public R<Void> taskOperation(@Validated @RequestBody TaskOperationBo bo, @PathVariable String taskOperation) {
+        return toAjax(flwTaskService.taskOperation(bo, taskOperation));
+    }
+
+    /**
+     * 淇敼浠诲姟鍔炵悊浜�
+     *
+     * @param taskIdList 浠诲姟id
+     * @param userId     鍔炵悊浜篿d
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("/updateAssignee/{userId}")
+    public R<Void> updateAssignee(@RequestBody List<Long> taskIdList, @PathVariable String userId) {
+        return toAjax(flwTaskService.updateAssignee(taskIdList, userId));
+    }
+
+    /**
+     * 椹冲洖瀹℃壒
+     *
+     * @param bo 鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/backProcess")
+    public R<Void> backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo bo) {
+        return toAjax(flwTaskService.backProcess(bo));
+    }
+
+    /**
+     * 鑾峰彇鍙┏鍥炵殑鍓嶇疆鑺傜偣
+     *
+     * @param definitionId 娴佺▼瀹氫箟id
+     * @param nowNodeCode  褰撳墠鑺傜偣
+     */
+    @GetMapping("/getBackTaskNode/{definitionId}/{nowNodeCode}")
+    public R<List<Node>> getBackTaskNode(@PathVariable Long definitionId, @PathVariable String nowNodeCode) {
+        return R.ok(flwTaskService.getBackTaskNode(definitionId, nowNodeCode));
+    }
+
+    /**
+     * 鑾峰彇褰撳墠浠诲姟鐨勬墍鏈夊姙鐞嗕汉
+     *
+     * @param taskId 浠诲姟id
+     */
+    @GetMapping("/currentTaskAllUser/{taskId}")
+    public R<List<UserDTO>> currentTaskAllUser(@PathVariable Long taskId) {
+        return R.ok(flwTaskService.currentTaskAllUser(taskId));
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java
index e1c246f..98825d9 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java
@@ -15,6 +15,7 @@
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.web.core.BaseController;
+import org.dromara.workflow.common.ConditionalOnEnable;
 import org.dromara.workflow.domain.bo.TestLeaveBo;
 import org.dromara.workflow.domain.vo.TestLeaveVo;
 import org.dromara.workflow.service.ITestLeaveService;
@@ -29,6 +30,7 @@
  * @author may
  * @date 2023-07-21
  */
+@ConditionalOnEnable
 @Validated
 @RequiredArgsConstructor
 @RestController
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java
deleted file mode 100644
index 8dced89..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package org.dromara.workflow.controller;
-
-import cn.dev33.satoken.annotation.SaCheckPermission;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
-import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.domain.R;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.log.enums.BusinessType;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.workflow.domain.bo.WfCategoryBo;
-import org.dromara.workflow.domain.vo.WfCategoryVo;
-import org.dromara.workflow.service.IWfCategoryService;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * 娴佺▼鍒嗙被
- *
- * @author may
- * @date 2023-06-28
- */
-@Validated
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/workflow/category")
-public class WfCategoryController extends BaseController {
-
-    private final IWfCategoryService wfCategoryService;
-
-    /**
-     * 鏌ヨ娴佺▼鍒嗙被鍒楄〃
-     */
-    @SaCheckPermission("workflow:category:list")
-    @GetMapping("/list")
-    public R<List<WfCategoryVo>> list(WfCategoryBo bo) {
-        List<WfCategoryVo> list = wfCategoryService.queryList(bo);
-        return R.ok(list);
-
-    }
-
-    /**
-     * 瀵煎嚭娴佺▼鍒嗙被鍒楄〃
-     */
-    @SaCheckPermission("workflow:category:export")
-    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(WfCategoryBo bo, HttpServletResponse response) {
-        List<WfCategoryVo> list = wfCategoryService.queryList(bo);
-        ExcelUtil.exportExcel(list, "娴佺▼鍒嗙被", WfCategoryVo.class, response);
-    }
-
-    /**
-     * 鑾峰彇娴佺▼鍒嗙被璇︾粏淇℃伅
-     *
-     * @param id 涓婚敭
-     */
-    @SaCheckPermission("workflow:category:query")
-    @GetMapping("/{id}")
-    public R<WfCategoryVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
-                                   @PathVariable Long id) {
-        return R.ok(wfCategoryService.queryById(id));
-    }
-
-    /**
-     * 鏂板娴佺▼鍒嗙被
-     */
-    @SaCheckPermission("workflow:category:add")
-    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping()
-    public R<Void> add(@Validated(AddGroup.class) @RequestBody WfCategoryBo bo) {
-        return toAjax(wfCategoryService.insertByBo(bo));
-    }
-
-    /**
-     * 淇敼娴佺▼鍒嗙被
-     */
-    @SaCheckPermission("workflow:category:edit")
-    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.UPDATE)
-    @RepeatSubmit()
-    @PutMapping()
-    public R<Void> edit(@Validated(EditGroup.class) @RequestBody WfCategoryBo bo) {
-        return toAjax(wfCategoryService.updateByBo(bo));
-    }
-
-    /**
-     * 鍒犻櫎娴佺▼鍒嗙被
-     *
-     * @param ids 涓婚敭涓�
-     */
-    @SaCheckPermission("workflow:category:remove")
-    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{ids}")
-    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
-                          @PathVariable Long[] ids) {
-        return toAjax(wfCategoryService.deleteWithValidByIds(List.of(ids), true));
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java
deleted file mode 100644
index 176aba2..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.dromara.workflow.controller;
-
-import java.util.List;
-
-import lombok.RequiredArgsConstructor;
-import jakarta.validation.constraints.*;
-import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.core.domain.R;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.log.enums.BusinessType;
-import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
-import org.dromara.workflow.service.IWfDefinitionConfigService;
-
-/**
- * 娴佺▼瀹氫箟閰嶇疆
- *
- * @author may
- * @date 2024-03-18
- */
-@Validated
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/workflow/definitionConfig")
-public class WfDefinitionConfigController extends BaseController {
-
-    private final IWfDefinitionConfigService wfDefinitionConfigService;
-
-
-    /**
-     * 鑾峰彇娴佺▼瀹氫箟閰嶇疆璇︾粏淇℃伅
-     *
-     * @param definitionId 涓婚敭
-     */
-    @GetMapping("/getByDefId/{definitionId}")
-    public R<WfDefinitionConfigVo> getByDefId(@NotBlank(message = "娴佺▼瀹氫箟ID涓嶈兘涓虹┖")
-                                              @PathVariable String definitionId) {
-        return R.ok(wfDefinitionConfigService.getByDefId(definitionId));
-    }
-
-    /**
-     * 鏂板娴佺▼瀹氫箟閰嶇疆
-     */
-    @Log(title = "娴佺▼瀹氫箟閰嶇疆", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping("/saveOrUpdate")
-    public R<Void> saveOrUpdate(@Validated(AddGroup.class) @RequestBody WfDefinitionConfigBo bo) {
-        return toAjax(wfDefinitionConfigService.saveOrUpdate(bo));
-    }
-
-    /**
-     * 鍒犻櫎娴佺▼瀹氫箟閰嶇疆
-     *
-     * @param ids 涓婚敭涓�
-     */
-    @Log(title = "娴佺▼瀹氫箟閰嶇疆", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{ids}")
-    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
-                          @PathVariable Long[] ids) {
-        return toAjax(wfDefinitionConfigService.deleteByIds(List.of(ids)));
-    }
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鎺掗櫎褰撳墠鏌ヨ鐨勬祦绋嬪畾涔�
-     *
-     * @param tableName    琛ㄥ悕
-     * @param definitionId 娴佺▼瀹氫箟id
-     */
-    @GetMapping("/getByTableNameNotDefId/{tableName}/{definitionId}")
-    public R<List<WfDefinitionConfigVo>> getByTableNameNotDefId(@NotBlank(message = "琛ㄥ悕涓嶈兘涓虹┖") @PathVariable String tableName,
-                                                                @NotBlank(message = "娴佺▼瀹氫箟ID涓嶈兘涓虹┖") @PathVariable String definitionId) {
-        return R.ok(wfDefinitionConfigService.getByTableNameNotDefId(tableName, definitionId));
-    }
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java
deleted file mode 100644
index 198e233..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package org.dromara.workflow.controller;
-
-import java.util.List;
-
-import lombok.RequiredArgsConstructor;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.*;
-import cn.dev33.satoken.annotation.SaCheckPermission;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.core.domain.R;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.log.enums.BusinessType;
-import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.workflow.domain.vo.WfFormManageVo;
-import org.dromara.workflow.domain.bo.WfFormManageBo;
-import org.dromara.workflow.service.IWfFormManageService;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-
-/**
- * 琛ㄥ崟绠$悊
- *
- * @author may
- * @date 2024-03-29
- */
-@Validated
-@RequiredArgsConstructor
-@RestController
-@RequestMapping("/workflow/formManage")
-public class WfFormManageController extends BaseController {
-
-    private final IWfFormManageService wfFormManageService;
-
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
-     */
-    @SaCheckPermission("workflow:formManage:list")
-    @GetMapping("/list")
-    public TableDataInfo<WfFormManageVo> list(WfFormManageBo bo, PageQuery pageQuery) {
-        return wfFormManageService.queryPageList(bo, pageQuery);
-    }
-
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
-     */
-    @SaCheckPermission("workflow:formManage:list")
-    @GetMapping("/list/selectList")
-    public R<List<WfFormManageVo>> selectList() {
-        return R.ok(wfFormManageService.selectList());
-    }
-
-    /**
-     * 瀵煎嚭琛ㄥ崟绠$悊鍒楄〃
-     */
-    @SaCheckPermission("workflow:formManage:export")
-    @Log(title = "琛ㄥ崟绠$悊", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(WfFormManageBo bo, HttpServletResponse response) {
-        List<WfFormManageVo> list = wfFormManageService.queryList(bo);
-        ExcelUtil.exportExcel(list, "琛ㄥ崟绠$悊", WfFormManageVo.class, response);
-    }
-
-    /**
-     * 鑾峰彇琛ㄥ崟绠$悊璇︾粏淇℃伅
-     *
-     * @param id 涓婚敭
-     */
-    @SaCheckPermission("workflow:formManage:query")
-    @GetMapping("/{id}")
-    public R<WfFormManageVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
-                                     @PathVariable Long id) {
-        return R.ok(wfFormManageService.queryById(id));
-    }
-
-    /**
-     * 鏂板琛ㄥ崟绠$悊
-     */
-    @SaCheckPermission("workflow:formManage:add")
-    @Log(title = "琛ㄥ崟绠$悊", businessType = BusinessType.INSERT)
-    @RepeatSubmit()
-    @PostMapping()
-    public R<Void> add(@Validated(AddGroup.class) @RequestBody WfFormManageBo bo) {
-        return toAjax(wfFormManageService.insertByBo(bo));
-    }
-
-    /**
-     * 淇敼琛ㄥ崟绠$悊
-     */
-    @SaCheckPermission("workflow:formManage:edit")
-    @Log(title = "琛ㄥ崟绠$悊", businessType = BusinessType.UPDATE)
-    @RepeatSubmit()
-    @PutMapping()
-    public R<Void> edit(@Validated(EditGroup.class) @RequestBody WfFormManageBo bo) {
-        return toAjax(wfFormManageService.updateByBo(bo));
-    }
-
-    /**
-     * 鍒犻櫎琛ㄥ崟绠$悊
-     *
-     * @param ids 涓婚敭涓�
-     */
-    @SaCheckPermission("workflow:formManage:remove")
-    @Log(title = "琛ㄥ崟绠$悊", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{ids}")
-    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
-                          @PathVariable Long[] ids) {
-        return toAjax(wfFormManageService.deleteByIds(List.of(ids)));
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java
deleted file mode 100644
index e87fb92..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java
+++ /dev/null
@@ -1,152 +0,0 @@
-package org.dromara.workflow.domain;
-
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * 娴佺▼瀹炰緥瀵硅薄 act_hi_procinst
- *
- * @author may
- * @date 2023-07-22
- */
-@Data
-@TableName("act_hi_procinst")
-public class ActHiProcinst implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     *
-     */
-    @TableId(value = "ID_")
-    private String id;
-
-    /**
-     *
-     */
-    @TableField(value = "REV_")
-    private Long rev;
-
-    /**
-     *
-     */
-    @TableField(value = "PROC_INST_ID_")
-    private String procInstId;
-
-    /**
-     *
-     */
-    @TableField(value = "BUSINESS_KEY_")
-    private String businessKey;
-
-    /**
-     *
-     */
-    @TableField(value = "PROC_DEF_ID_")
-    private String procDefId;
-
-    /**
-     *
-     */
-    @TableField(value = "START_TIME_")
-    private Date startTime;
-
-    /**
-     *
-     */
-    @TableField(value = "END_TIME_")
-    private Date endTime;
-
-    /**
-     *
-     */
-    @TableField(value = "DURATION_")
-    private Long duration;
-
-    /**
-     *
-     */
-    @TableField(value = "START_USER_ID_")
-    private String startUserId;
-
-    /**
-     *
-     */
-    @TableField(value = "START_ACT_ID_")
-    private String startActId;
-
-    /**
-     *
-     */
-    @TableField(value = "END_ACT_ID_")
-    private String endActId;
-
-    /**
-     *
-     */
-    @TableField(value = "SUPER_PROCESS_INSTANCE_ID_")
-    private String superProcessInstanceId;
-
-    /**
-     *
-     */
-    @TableField(value = "DELETE_REASON_")
-    private String deleteReason;
-
-    /**
-     *
-     */
-    @TableField(value = "TENANT_ID_")
-    private String tenantId;
-
-    /**
-     *
-     */
-    @TableField(value = "NAME_")
-    private String name;
-
-    /**
-     *
-     */
-    @TableField(value = "CALLBACK_ID_")
-    private String callbackId;
-
-    /**
-     *
-     */
-    @TableField(value = "CALLBACK_TYPE_")
-    private String callbackType;
-
-    /**
-     *
-     */
-    @TableField(value = "REFERENCE_ID_")
-    private String referenceId;
-
-    /**
-     *
-     */
-    @TableField(value = "REFERENCE_TYPE_")
-    private String referenceType;
-
-    /**
-     *
-     */
-    @TableField(value = "PROPAGATED_STAGE_INST_ID_")
-    private String propagatedStageInstId;
-
-    /**
-     *
-     */
-    @TableField(value = "BUSINESS_STATUS_")
-    private String businessStatus;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java
deleted file mode 100644
index abc17b5..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java
+++ /dev/null
@@ -1,193 +0,0 @@
-package org.dromara.workflow.domain;
-
-import com.baomidou.mybatisplus.annotation.*;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.util.Date;
-
-import java.io.Serial;
-
-/**
- * 娴佺▼鍘嗗彶浠诲姟瀵硅薄 act_hi_taskinst
- *
- * @author may
- * @date 2024-03-02
- */
-@Data
-@TableName("act_hi_taskinst")
-public class ActHiTaskinst implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     *
-     */
-    @TableId(value = "ID_")
-    private String id;
-
-    /**
-     * 鐗堟湰
-     */
-    @TableField(value = "REV_")
-    private Long rev;
-
-    /**
-     * 娴佺▼瀹氫箟id
-     */
-    @TableField(value = "PROC_DEF_ID_")
-    private String procDefId;
-
-    /**
-     *
-     */
-    @TableField(value = "TASK_DEF_ID_")
-    private String taskDefId;
-
-    /**
-     * 浠诲姟鑺傜偣id
-     */
-    @TableField(value = "TASK_DEF_KEY_")
-    private String taskDefKey;
-
-    /**
-     * 娴佺▼瀹炰緥id
-     */
-    @TableField(value = "PROC_INST_ID_")
-    private String procInstId;
-
-    /**
-     * 娴佺▼鎵цid
-     */
-    @TableField(value = "EXECUTION_ID")
-    private String executionId;
-
-    /**
-     *
-     */
-    @TableField(value = "SCOPE_ID_")
-    private String scopeId;
-
-    /**
-     *
-     */
-    @TableField(value = "SUB_SCOPE_ID_")
-    private String subScopeId;
-
-    /**
-     * 鍏堢敤褰撳墠瀛楁鏍囪瘑鎶勯�佺被鍨�
-     */
-    @TableField(value = "SCOPE_TYPE_")
-    private String scopeType;
-
-    /**
-     *
-     */
-    @TableField(value = "SCOPE_DEFINITION_ID_")
-    private String scopeDefinitionId;
-
-    /**
-     *
-     */
-    @TableField(value = "PROPAGATED_STAGE_INST_ID_")
-    private String propagatedStageInstId;
-
-    /**
-     * 浠诲姟鍚嶇О
-     */
-    @TableField(value = "NAME_")
-    private String name;
-
-    /**
-     * 鐖剁骇id
-     */
-    @TableField(value = "PARENT_TASK_ID_")
-    private String parentTaskId;
-
-    /**
-     * 鎻忚堪
-     */
-    @TableField(value = "DESCRIPTION_")
-    private String description;
-
-    /**
-     * 鍔炵悊浜�
-     */
-    @TableField(value = "OWNER_")
-    private String owner;
-
-    /**
-     * 鍔炵悊浜�
-     */
-    @TableField(value = "ASSIGNEE_")
-    private String assignee;
-
-    /**
-     * 寮�濮嬩簨浠�
-     */
-    @TableField(value = "START_TIME_")
-    private Date startTime;
-
-    /**
-     * 璁ら鏃堕棿
-     */
-    @TableField(value = "CLAIM_TIME_")
-    private Date claimTime;
-
-    /**
-     * 缁撴潫鏃堕棿
-     */
-    @TableField(value = "END_TIME_")
-    private Date endTime;
-
-    /**
-     * 鎸佺画鏃堕棿
-     */
-    @TableField(value = "DURATION_")
-    private Long duration;
-
-    /**
-     * 鍒犻櫎鍘熷洜
-     */
-    @TableField(value = "DELETE_REASON_")
-    private String deleteReason;
-
-    /**
-     * 浼樺厛绾�
-     */
-    @TableField(value = "PRIORITY_")
-    private Long priority;
-
-    /**
-     * 鍒版湡鏃堕棿
-     */
-    @TableField(value = "DUE_DATE_")
-    private Date dueDate;
-
-    /**
-     *
-     */
-    @TableField(value = "FORM_KEY_")
-    private String formKey;
-
-    /**
-     * 鍒嗙被
-     */
-    @TableField(value = "CATEGORY_")
-    private String category;
-
-    /**
-     * 鏈�鍚庝慨鏀规椂闂�
-     */
-    @TableField(value = "LAST_UPDATED_TIME_")
-    private Date lastUpdatedTime;
-
-    /**
-     * 绉熸埛id
-     */
-    @TableField(value = "TENANT_ID_")
-    private String tenantId;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java
new file mode 100644
index 0000000..86ac1ac
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java
@@ -0,0 +1,58 @@
+package org.dromara.workflow.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 娴佺▼鍒嗙被瀵硅薄 wf_category
+ *
+ * @author may
+ * @date 2023-06-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("flow_category")
+public class FlowCategory extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼鍒嗙被ID
+     */
+    @TableId(value = "category_id")
+    private Long categoryId;
+
+    /**
+     * 鐖舵祦绋嬪垎绫籭d
+     */
+    private Long parentId;
+
+    /**
+     * 绁栫骇鍒楄〃
+     */
+    private String ancestors;
+
+    /**
+     * 娴佺▼鍒嗙被鍚嶇О
+     */
+    private String categoryName;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Long orderNum;
+
+    /**
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�
+     */
+    @TableLogic
+    private String delFlag;
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java
deleted file mode 100644
index 94a7cf5..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.dromara.workflow.domain;
-
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import org.dromara.common.tenant.core.TenantEntity;
-
-import java.io.Serial;
-
-/**
- * 娴佺▼鍒嗙被瀵硅薄 wf_category
- *
- * @author may
- * @date 2023-06-27
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@TableName("wf_category")
-public class WfCategory extends TenantEntity {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭
-     */
-    @TableId(value = "id")
-    private Long id;
-
-    /**
-     * 鍒嗙被鍚嶇О
-     */
-    private String categoryName;
-
-    /**
-     * 鍒嗙被缂栫爜
-     */
-    private String categoryCode;
-
-    /**
-     * 鐖剁骇id
-     */
-    private Long parentId;
-
-    /**
-     * 鎺掑簭
-     */
-    private Long sortNum;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java
deleted file mode 100644
index 11dcaa0..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.dromara.workflow.domain;
-
-import org.dromara.common.mybatis.core.domain.BaseEntity;
-import com.baomidou.mybatisplus.annotation.*;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.io.Serial;
-
-/**
- * 娴佺▼瀹氫箟閰嶇疆瀵硅薄 wf_definition_config
- *
- * @author may
- * @date 2024-03-18
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@TableName("wf_definition_config")
-public class WfDefinitionConfig extends BaseEntity {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭
-     */
-    @TableId(value = "id")
-    private Long id;
-
-    /**
-     * 琛ㄥ悕
-     */
-    private String tableName;
-
-    /**
-     * 娴佺▼瀹氫箟ID
-     */
-    private String definitionId;
-
-    /**
-     * 娴佺▼KEY
-     */
-    private String processKey;
-
-    /**
-     * 娴佺▼鐗堟湰
-     */
-    private Integer version;
-
-    /**
-     * 澶囨敞
-     */
-    private String remark;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java
deleted file mode 100644
index 47f0d7a..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.dromara.workflow.domain;
-
-import org.dromara.common.tenant.core.TenantEntity;
-import com.baomidou.mybatisplus.annotation.*;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.io.Serial;
-
-/**
- * 琛ㄥ崟绠$悊瀵硅薄 wf_form_manage
- *
- * @author may
- * @date 2024-03-29
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@TableName("wf_form_manage")
-public class WfFormManage extends TenantEntity {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭
-     */
-    @TableId(value = "id")
-    private Long id;
-
-    /**
-     * 琛ㄥ崟鍚嶇О
-     */
-    private String formName;
-
-    /**
-     * 琛ㄥ崟绫诲瀷
-     */
-    private String formType;
-
-    /**
-     * 璺敱鍦板潃/琛ㄥ崟ID
-     */
-    private String router;
-
-    /**
-     * 澶囨敞
-     */
-    private String remark;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java
deleted file mode 100644
index 999425f..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.dromara.workflow.domain;
-
-import org.dromara.common.tenant.core.TenantEntity;
-import com.baomidou.mybatisplus.annotation.*;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.io.Serial;
-
-/**
- * 鑺傜偣閰嶇疆瀵硅薄 wf_node_config
- *
- * @author may
- * @date 2024-03-30
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@TableName("wf_node_config")
-public class WfNodeConfig extends TenantEntity {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭
-     */
-    @TableId(value = "id")
-    private Long id;
-
-    /**
-     * 琛ㄥ崟id
-     */
-    private Long formId;
-
-    /**
-     * 琛ㄥ崟绫诲瀷
-     */
-    private String formType;
-
-    /**
-     * 鑺傜偣鍚嶇О
-     */
-    private String nodeName;
-
-    /**
-     * 鑺傜偣id
-     */
-    private String nodeId;
-
-    /**
-     * 娴佺▼瀹氫箟id
-     */
-    private String definitionId;
-
-    /**
-     * 鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級
-     */
-    private String applyUserTask;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java
deleted file mode 100644
index 6f59727..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.dromara.workflow.domain;
-
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import org.dromara.common.tenant.core.TenantEntity;
-
-import java.io.Serial;
-
-/**
- * 鑺傜偣椹冲洖璁板綍 wf_task_back_node
- *
- * @author may
- * @date 2024-03-13
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@TableName("wf_task_back_node")
-public class WfTaskBackNode extends TenantEntity {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭
-     */
-    @TableId(value = "id")
-    private Long id;
-
-    /**
-     * 瀹炰緥id
-     */
-    private String instanceId;
-
-    /**
-     * 鑺傜偣id
-     */
-    private String nodeId;
-
-    /**
-     * 鑺傜偣鍚嶇О
-     */
-    private String nodeName;
-
-    /**
-     * 鎺掑簭
-     */
-    private Integer orderNo;
-
-    /**
-     * 鑺傜偣绫诲瀷
-     */
-    private String taskType;
-
-    /**
-     * 鍔炵悊浜�
-     */
-    private String assignee;
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java
deleted file mode 100644
index 320ec64..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotEmpty;
-import lombok.Data;
-import org.dromara.common.core.validate.AddGroup;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * 鍔犵鍙傛暟璇锋眰
- *
- * @author may
- */
-@Data
-public class AddMultiBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 浠诲姟ID
-     */
-    @NotBlank(message = "浠诲姟ID涓嶈兘涓虹┖", groups = AddGroup.class)
-    private String taskId;
-
-    /**
-     * 鍔犵浜哄憳id
-     */
-    @NotEmpty(message = "鍔犵浜哄憳涓嶈兘涓虹┖", groups = AddGroup.class)
-    private List<Long> assignees;
-
-    /**
-     * 鍔犵浜哄憳鍚嶇О
-     */
-    @NotEmpty(message = "鍔犵浜哄憳涓嶈兘涓虹┖", groups = AddGroup.class)
-    private List<String> assigneeNames;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java
index d0f4369..3117a33 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java
@@ -1,12 +1,16 @@
 package org.dromara.workflow.domain.bo;
 
 import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 import org.dromara.common.core.validate.AddGroup;
 
 import java.io.Serial;
 import java.io.Serializable;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 
 /**
@@ -23,8 +27,13 @@
     /**
      * 浠诲姟ID
      */
-    @NotBlank(message = "浠诲姟ID涓嶈兘涓虹┖", groups = AddGroup.class)
-    private String taskId;
+    @NotNull(message = "浠诲姟ID涓嶈兘涓虹┖", groups = AddGroup.class)
+    private Long taskId;
+
+    /**
+     * 闄勪欢id
+     */
+    private String fileId;
 
     /**
      * 娑堟伅绫诲瀷
@@ -35,10 +44,28 @@
      * 椹冲洖鐨勮妭鐐筰d(鐩墠鏈娇鐢紝鐩存帴椹冲洖鍒扮敵璇蜂汉)
      */
     @NotBlank(message = "椹冲洖鐨勮妭鐐逛笉鑳戒负绌�", groups = AddGroup.class)
-    private String targetActivityId;
+    private String nodeCode;
 
     /**
      * 鍔炵悊鎰忚
      */
     private String message;
+
+    /**
+     * 閫氱煡
+     */
+    private String notice;
+
+    /**
+     * 娴佺▼鍙橀噺
+     */
+    private Map<String, Object> variables;
+
+    public Map<String, Object> getVariables() {
+        if (variables == null) {
+            return new HashMap<>(16);
+        }
+        variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
+        return variables;
+    }
 }
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java
index 0623905..9fdf484 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java
@@ -1,9 +1,8 @@
 package org.dromara.workflow.domain.bo;
 
-import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 import org.dromara.common.core.validate.AddGroup;
-import org.dromara.workflow.domain.vo.WfCopy;
 
 import java.io.Serial;
 import java.io.Serializable;
@@ -26,8 +25,8 @@
     /**
      * 浠诲姟id
      */
-    @NotBlank(message = "浠诲姟id涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String taskId;
+    @NotNull(message = "浠诲姟id涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private Long taskId;
 
     /**
      * 闄勪欢id
@@ -37,7 +36,7 @@
     /**
      * 鎶勯�佷汉鍛�
      */
-    private List<WfCopy> wfCopyList;
+    private List<FlowCopyBo> flowCopyList;
 
     /**
      * 娑堟伅绫诲瀷
@@ -50,10 +49,21 @@
     private String message;
 
     /**
+     * 娑堟伅閫氱煡
+     */
+    private String notice;
+
+    /**
      * 娴佺▼鍙橀噺
      */
     private Map<String, Object> variables;
 
+    /**
+     * 鎵╁睍鍙橀噺(姝ゅ涓洪�楀彿鍒嗛殧鐨刼ssId)
+     * @return
+     */
+    private String ext;
+
     public Map<String, Object> getVariables() {
         if (variables == null) {
             return new HashMap<>(16);
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java
deleted file mode 100644
index a6846a6..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import jakarta.validation.constraints.NotBlank;
-import lombok.Data;
-import org.dromara.common.core.validate.AddGroup;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 濮旀淳浠诲姟璇锋眰瀵硅薄
- *
- * @author may
- */
-@Data
-public class DelegateBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 濮旀淳浜篿d
-     */
-    @NotBlank(message = "濮旀淳浜篿d涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String userId;
-
-    /**
-     * 濮旀淳浜哄悕绉�
-     */
-    @NotBlank(message = "濮旀淳浜哄悕绉颁笉鑳戒负绌�", groups = {AddGroup.class})
-    private String nickName;
-
-    /**
-     * 浠诲姟id
-     */
-    @NotBlank(message = "浠诲姟id涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String taskId;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java
deleted file mode 100644
index e533167..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotEmpty;
-import lombok.Data;
-import org.dromara.common.core.validate.AddGroup;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * 鍑忕鍙傛暟璇锋眰
- *
- * @author may
- */
-@Data
-public class DeleteMultiBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 浠诲姟ID
-     */
-    @NotBlank(message = "浠诲姟ID涓嶈兘涓虹┖", groups = AddGroup.class)
-    private String taskId;
-
-    /**
-     * 鍑忕浜哄憳
-     */
-    @NotEmpty(message = "鍑忕浜哄憳涓嶈兘涓虹┖", groups = AddGroup.class)
-    private List<String> taskIds;
-
-    /**
-     * 鎵цid
-     */
-    @NotEmpty(message = "鎵цid涓嶈兘涓虹┖", groups = AddGroup.class)
-    private List<String> executionIds;
-
-    /**
-     * 浜哄憳id
-     */
-    @NotEmpty(message = "鍑忕浜哄憳id涓嶈兘涓虹┖", groups = AddGroup.class)
-    private List<Long> assigneeIds;
-
-    /**
-     * 浜哄憳鍚嶇О
-     */
-    @NotEmpty(message = "鍑忕浜哄憳涓嶈兘涓虹┖", groups = AddGroup.class)
-    private List<String> assigneeNames;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java
new file mode 100644
index 0000000..31742ea
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java
@@ -0,0 +1,31 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鎾ら攢浠诲姟璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class FlowCancelBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟ID
+     */
+    @NotBlank(message = "涓氬姟ID涓嶈兘涓虹┖", groups = AddGroup.class)
+    private String businessId;
+
+    /**
+     * 鍔炵悊鎰忚
+     */
+    private String message;
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java
new file mode 100644
index 0000000..fd626eb
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java
@@ -0,0 +1,47 @@
+package org.dromara.workflow.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.workflow.domain.FlowCategory;
+
+/**
+ * 娴佺▼鍒嗙被涓氬姟瀵硅薄 wf_category
+ *
+ * @author may
+ * @date 2023-06-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = FlowCategory.class, reverseConvertGenerate = false)
+public class FlowCategoryBo extends BaseEntity {
+
+    /**
+     * 娴佺▼鍒嗙被ID
+     */
+    @NotNull(message = "娴佺▼鍒嗙被ID涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long categoryId;
+
+    /**
+     * 鐖舵祦绋嬪垎绫籭d
+     */
+    @NotNull(message = "鐖舵祦绋嬪垎绫籭d涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private Long parentId;
+
+    /**
+     * 娴佺▼鍒嗙被鍚嶇О
+     */
+    @NotBlank(message = "娴佺▼鍒嗙被鍚嶇О涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private String categoryName;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Long orderNum;
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java
similarity index 76%
rename from ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java
rename to ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java
index 88a5a21..a45e521 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java
@@ -1,9 +1,10 @@
-package org.dromara.workflow.domain.vo;
+package org.dromara.workflow.domain.bo;
 
 import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
+
 
 /**
  * 鎶勯��
@@ -11,7 +12,7 @@
  * @author may
  */
 @Data
-public class WfCopy implements Serializable {
+public class FlowCopyBo implements Serializable {
 
     @Serial
     private static final long serialVersionUID = 1L;
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java
new file mode 100644
index 0000000..fb1fe61
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java
@@ -0,0 +1,55 @@
+package org.dromara.workflow.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 娴佺▼瀹炰緥璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class FlowInstanceBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String flowName;
+
+    /**
+     * 娴佺▼瀹氫箟缂栫爜
+     */
+    private String flowCode;
+
+    /**
+     * 浠诲姟鍙戣捣浜�
+     */
+    private String startUserId;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessId;
+
+    /**
+     * 娴佺▼鍒嗙被id
+     */
+    private String category;
+
+    /**
+     * 浠诲姟鍚嶇О
+     */
+    private String nodeName;
+
+    /**
+     * 鐢宠浜篒ds
+     */
+    private List<Long> createByIds;
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java
new file mode 100644
index 0000000..297bd00
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java
@@ -0,0 +1,31 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 浣滃簾璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class FlowInvalidBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼瀹炰緥id
+     */
+    @NotNull(message = "娴佺▼瀹炰緥id涓虹┖", groups = AddGroup.class)
+    private Long id;
+
+    /**
+     * 瀹℃壒鎰忚
+     */
+    private String comment;
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java
new file mode 100644
index 0000000..64dd082
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java
@@ -0,0 +1,55 @@
+package org.dromara.workflow.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 浠诲姟璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class FlowTaskBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟鍚嶇О
+     */
+    private String nodeName;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String flowName;
+
+    /**
+     * 娴佺▼瀹氫箟缂栫爜
+     */
+    private String flowCode;
+
+    /**
+     * 娴佺▼鍒嗙被id
+     */
+    private String category;
+
+    /**
+     * 娴佺▼瀹炰緥id
+     */
+    private Long instanceId;
+
+    /**
+     * 鏉冮檺鍒楄〃
+     */
+    private List<String> permissionList;
+
+    /**
+     * 鐢宠浜篒ds
+     */
+    private List<Long> createByIds;
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java
similarity index 66%
rename from ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java
rename to ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java
index 8f2206e..897fc21 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java
@@ -1,6 +1,6 @@
 package org.dromara.workflow.domain.bo;
 
-import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 import org.dromara.common.core.validate.AddGroup;
 
@@ -13,7 +13,7 @@
  * @author may
  */
 @Data
-public class TerminationBo implements Serializable {
+public class FlowTerminationBo implements Serializable {
 
     @Serial
     private static final long serialVersionUID = 1L;
@@ -21,8 +21,8 @@
     /**
      * 浠诲姟id
      */
-    @NotBlank(message = "浠诲姟id涓虹┖", groups = AddGroup.class)
-    private String taskId;
+    @NotNull(message = "浠诲姟id涓虹┖", groups = AddGroup.class)
+    private Long taskId;
 
     /**
      * 瀹℃壒鎰忚
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java
deleted file mode 100644
index efe9acd..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Pattern;
-import lombok.Data;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
-import org.dromara.workflow.common.constant.FlowConstant;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 妯″瀷璇锋眰瀵硅薄
- *
- * @author may
- */
-@Data
-public class ModelBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 妯″瀷id
-     */
-    @NotBlank(message = "妯″瀷ID涓嶈兘涓虹┖", groups = {EditGroup.class})
-    private String id;
-
-    /**
-     * 妯″瀷鍚嶇О
-     */
-    @NotBlank(message = "妯″瀷鍚嶇О涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String name;
-
-    /**
-     * 妯″瀷鏍囪瘑key
-     */
-    @NotBlank(message = "妯″瀷鏍囪瘑key涓嶈兘涓虹┖", groups = {AddGroup.class})
-    @Pattern(regexp = FlowConstant.MODEL_KEY_PATTERN, message = "妯″瀷鏍囪瘑key鍙兘瀛楃鎴栬�呬笅鍒掔嚎寮�澶�", groups = {AddGroup.class})
-    private String key;
-
-    /**
-     * 妯″瀷鍒嗙被
-     */
-    @NotBlank(message = "妯″瀷鍒嗙被涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String categoryCode;
-
-    /**
-     * 妯″瀷XML
-     */
-    @NotBlank(message = "妯″瀷XML涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String xml;
-
-    /**
-     * 妯″瀷SVG鍥剧墖
-     */
-    @NotBlank(message = "妯″瀷SVG涓嶈兘涓虹┖", groups = {EditGroup.class})
-    private String svg;
-
-    /**
-     * 澶囨敞
-     */
-    private String description;
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java
deleted file mode 100644
index 2025932..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 娴佺▼瀹氫箟璇锋眰瀵硅薄
- *
- * @author may
- */
-@Data
-public class ProcessDefinitionBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 娴佺▼瀹氫箟鍚嶇Оkey
-     */
-    private String key;
-
-    /**
-     * 娴佺▼瀹氫箟鍚嶇О
-     */
-    private String name;
-
-    /**
-     * 妯″瀷鍒嗙被
-     */
-    private String categoryCode;
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java
deleted file mode 100644
index 2833b3e..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 娴佺▼瀹炰緥璇锋眰瀵硅薄
- *
- * @author may
- */
-@Data
-public class ProcessInstanceBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 娴佺▼鍚嶇О
-     */
-    private String name;
-
-    /**
-     * 娴佺▼key
-     */
-    private String key;
-
-    /**
-     * 浠诲姟鍙戣捣浜�
-     */
-    private String startUserId;
-
-    /**
-     * 涓氬姟id
-     */
-    private String businessKey;
-
-    /**
-     * 妯″瀷鍒嗙被
-     */
-    private String categoryCode;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java
deleted file mode 100644
index 41e51c2..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import jakarta.validation.constraints.NotBlank;
-import lombok.Data;
-import org.dromara.common.core.validate.AddGroup;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 娴佺▼瀹炰緥浣滃簾璇锋眰瀵硅薄
- *
- * @author may
- */
-@Data
-public class ProcessInvalidBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓氬姟id
-     */
-    @NotBlank(message = "涓氬姟id涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String businessKey;
-
-    /**
-     * 浣滃簾鍘熷洜
-     */
-    private String deleteReason;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java
index 7af7935..ea21a81 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java
@@ -26,13 +26,13 @@
      * 涓氬姟鍞竴鍊糹d
      */
     @NotBlank(message = "涓氬姟ID涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String businessKey;
+    private String businessId;
 
     /**
-     * 琛ㄥ悕
+     * 娴佺▼瀹氫箟缂栫爜
      */
-    @NotBlank(message = "琛ㄥ悕涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String tableName;
+    @NotBlank(message = "娴佺▼瀹氫箟缂栫爜涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String flowCode;
 
     /**
      * 娴佺▼鍙橀噺锛屽墠绔細鎻愪氦涓�涓厓绱爗'entity': {涓氬姟璇︽儏鏁版嵁瀵硅薄}}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java
deleted file mode 100644
index e4d99e4..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-
-/**
- * 鐢ㄦ埛鍔犵鏌ヨ
- *
- * @author may
- */
-@Data
-public class SysUserMultiBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 浜哄憳鍚嶇О
-     */
-    private String userName;
-
-    /**
-     * 浜哄憳鍚嶇О
-     */
-    private String nickName;
-
-    /**
-     * 閮ㄩ棬id
-     */
-    private String deptId;
-
-    /**
-     * 浠诲姟id
-     */
-    private String taskId;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java
deleted file mode 100644
index 3037479..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 浠诲姟璇锋眰瀵硅薄
- *
- * @author may
- */
-@Data
-public class TaskBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 浠诲姟鍚嶇О
-     */
-    private String name;
-
-    /**
-     * 娴佺▼瀹氫箟鍚嶇О
-     */
-    private String processDefinitionName;
-
-    /**
-     * 娴佺▼瀹氫箟key
-     */
-    private String processDefinitionKey;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java
new file mode 100644
index 0000000..4348e31
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java
@@ -0,0 +1,48 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+
+/**
+ * 浠诲姟鎿嶄綔涓氬姟瀵硅薄锛岀敤浜庢弿杩颁换鍔″娲俱�佽浆鍔炪�佸姞绛剧瓑鎿嶄綔鐨勫繀瑕佸弬鏁�
+ * 鍖呭惈浜嗙敤鎴稩D銆佷换鍔D銆佷换鍔$浉鍏崇殑娑堟伅銆佷互鍙婂姞绛�/鍑忕鐨勭敤鎴稩D
+ *
+ * @author AprilWind
+ */
+@Data
+public class TaskOperationBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 濮旀淳/杞姙浜虹殑鐢ㄦ埛ID锛堝繀濉紝鍑嗗濮旀淳/杞姙浜烘搷浣滐級
+     */
+    @NotNull(message = "濮旀淳/杞姙浜篿d涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String userId;
+
+    /**
+     * 鍔犵/鍑忕浜虹殑鐢ㄦ埛ID鍒楄〃锛堝繀濉紝閽堝鍔犵/鍑忕鎿嶄綔锛�
+     */
+    @NotNull(message = "鍔犵/鍑忕id涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private List<String> userIds;
+
+    /**
+     * 浠诲姟ID锛堝繀濉級
+     */
+    @NotNull(message = "浠诲姟id涓嶈兘涓虹┖")
+    private Long taskId;
+
+    /**
+     * 鎰忚鎴栧娉ㄤ俊鎭紙鍙�夛級
+     */
+    private String message;
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java
deleted file mode 100644
index 20856ef..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * 浠诲姟鍌姙
- *
- * @author may
- */
-@Data
-public class TaskUrgingBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 娴佺▼瀹炰緥id
-     */
-    private String processInstanceId;
-
-    /**
-     * 娑堟伅绫诲瀷
-     */
-    private List<String> messageType;
-
-    /**
-     * 鍌姙鍐呭锛堜负绌洪粯璁ょ郴缁熷唴缃俊鎭級
-     */
-    private String message;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java
index 877e981..a1a4b59 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java
@@ -53,7 +53,6 @@
     /**
      * 璇峰亣澶╂暟
      */
-    @NotNull(message = "璇峰亣澶╂暟涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
     private Integer leaveDays;
 
     /**
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java
deleted file mode 100644
index 3eb6609..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import jakarta.validation.constraints.NotBlank;
-import lombok.Data;
-import org.dromara.common.core.validate.AddGroup;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 缁堣浆鍔炲姟璇锋眰瀵硅薄
- *
- * @author may
- */
-@Data
-public class TransmitBo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 浠诲姟id
-     */
-    @NotBlank(message = "浠诲姟id涓虹┖", groups = AddGroup.class)
-    private String taskId;
-
-    /**
-     * 杞姙浜篿d
-     */
-    @NotBlank(message = "杞姙浜轰笉鑳戒负绌�", groups = AddGroup.class)
-    private String userId;
-
-    /**
-     * 瀹℃壒鎰忚
-     */
-    private String comment;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java
deleted file mode 100644
index 69608fd..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import io.github.linpeilie.annotations.AutoMapper;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.mybatis.core.domain.BaseEntity;
-import org.dromara.workflow.domain.WfCategory;
-
-/**
- * 娴佺▼鍒嗙被涓氬姟瀵硅薄 wf_category
- *
- * @author may
- * @date 2023-06-27
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@AutoMapper(target = WfCategory.class, reverseConvertGenerate = false)
-public class WfCategoryBo extends BaseEntity {
-
-    /**
-     * 涓婚敭
-     */
-    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
-    private Long id;
-
-    /**
-     * 鍒嗙被鍚嶇О
-     */
-    @NotBlank(message = "鍒嗙被鍚嶇О涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
-    private String categoryName;
-
-    /**
-     * 鍒嗙被缂栫爜
-     */
-    @NotBlank(message = "鍒嗙被缂栫爜涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
-    private String categoryCode;
-
-    /**
-     * 鐖剁骇id
-     */
-    @NotNull(message = "鐖剁骇id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
-    private Long parentId;
-
-    /**
-     * 鎺掑簭
-     */
-    private Long sortNum;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java
deleted file mode 100644
index fac1770..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import org.dromara.workflow.domain.WfDefinitionConfig;
-import org.dromara.common.mybatis.core.domain.BaseEntity;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
-import io.github.linpeilie.annotations.AutoMapper;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import jakarta.validation.constraints.*;
-
-/**
- * 娴佺▼瀹氫箟閰嶇疆涓氬姟瀵硅薄 wf_form_definition
- *
- * @author may
- * @date 2024-03-18
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@AutoMapper(target = WfDefinitionConfig.class, reverseConvertGenerate = false)
-public class WfDefinitionConfigBo extends BaseEntity {
-
-    /**
-     * 涓婚敭
-     */
-    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
-    private Long id;
-
-    /**
-     * 琛ㄥ悕
-     */
-    @NotBlank(message = "琛ㄥ悕涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String tableName;
-
-    /**
-     * 娴佺▼瀹氫箟ID
-     */
-    @NotBlank(message = "娴佺▼瀹氫箟ID涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String definitionId;
-
-    /**
-     * 娴佺▼KEY
-     */
-    @NotBlank(message = "娴佺▼KEY涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private String processKey;
-
-    /**
-     * 娴佺▼鐗堟湰
-     */
-    @NotNull(message = "娴佺▼鐗堟湰涓嶈兘涓虹┖", groups = {AddGroup.class})
-    private Integer version;
-
-    /**
-     * 澶囨敞
-     */
-    private String remark;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java
deleted file mode 100644
index 8afc286..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import org.dromara.workflow.domain.WfFormManage;
-import org.dromara.common.mybatis.core.domain.BaseEntity;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
-import io.github.linpeilie.annotations.AutoMapper;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import jakarta.validation.constraints.*;
-
-/**
- * 琛ㄥ崟绠$悊涓氬姟瀵硅薄 wf_form_manage
- *
- * @author may
- * @date 2024-03-29
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@AutoMapper(target = WfFormManage.class, reverseConvertGenerate = false)
-public class WfFormManageBo extends BaseEntity {
-
-    /**
-     * 涓婚敭
-     */
-    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = { EditGroup.class })
-    private Long id;
-
-    /**
-     * 琛ㄥ崟鍚嶇О
-     */
-    @NotBlank(message = "琛ㄥ崟鍚嶇О涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
-    private String formName;
-
-    /**
-     * 琛ㄥ崟绫诲瀷
-     */
-    @NotBlank(message = "琛ㄥ崟绫诲瀷涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
-    private String formType;
-    /**
-     * 璺敱鍦板潃/琛ㄥ崟ID
-     */
-    @NotBlank(message = "璺敱鍦板潃/琛ㄥ崟ID涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
-    private String router;
-
-
-    /**
-     * 澶囨敞
-     */
-    private String remark;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java
deleted file mode 100644
index de518d3..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.dromara.workflow.domain.bo;
-
-import org.dromara.workflow.domain.WfNodeConfig;
-import org.dromara.common.mybatis.core.domain.BaseEntity;
-import org.dromara.common.core.validate.AddGroup;
-import org.dromara.common.core.validate.EditGroup;
-import io.github.linpeilie.annotations.AutoMapper;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import jakarta.validation.constraints.*;
-
-/**
- * 鑺傜偣閰嶇疆涓氬姟瀵硅薄 wf_node_config
- *
- * @author may
- * @date 2024-03-30
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@AutoMapper(target = WfNodeConfig.class, reverseConvertGenerate = false)
-public class WfNodeConfigBo extends BaseEntity {
-
-    /**
-     * 涓婚敭
-     */
-    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
-    private Long id;
-
-    /**
-     * 琛ㄥ崟id
-     */
-    private Long formId;
-
-    /**
-     * 琛ㄥ崟绫诲瀷
-     */
-    private String formType;
-
-    /**
-     * 鑺傜偣鍚嶇О
-     */
-    @NotBlank(message = "鑺傜偣鍚嶇О涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
-    private String nodeName;
-
-    /**
-     * 鑺傜偣id
-     */
-    @NotBlank(message = "鑺傜偣id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
-    private String nodeId;
-
-    /**
-     * 娴佺▼瀹氫箟id
-     */
-    @NotBlank(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
-    private String definitionId;
-
-    /**
-     * 鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級
-     */
-    @NotBlank(message = "鏄惁涓虹敵璇蜂汉鑺傜偣涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
-    private String applyUserTask;
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java
deleted file mode 100644
index e4c1142..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import lombok.Data;
-import org.dromara.common.translation.annotation.Translation;
-import org.dromara.common.translation.constant.TransConstant;
-import org.flowable.engine.task.Attachment;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.util.Date;
-import java.util.List;
-
-/**
- * 娴佺▼瀹℃壒璁板綍瑙嗗浘
- *
- * @author may
- */
-@Data
-public class ActHistoryInfoVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-    /**
-     * 浠诲姟id
-     */
-    private String id;
-    /**
-     * 鑺傜偣id
-     */
-    private String taskDefinitionKey;
-    /**
-     * 浠诲姟鍚嶇О
-     */
-    private String name;
-    /**
-     * 娴佺▼瀹炰緥id
-     */
-    private String processInstanceId;
-    /**
-     * 鐗堟湰
-     */
-    private Integer version;
-    /**
-     * 寮�濮嬫椂闂�
-     */
-    private Date startTime;
-    /**
-     * 缁撴潫鏃堕棿
-     */
-    private Date endTime;
-    /**
-     * 杩愯鏃堕暱
-     */
-    private String runDuration;
-    /**
-     * 鐘舵��
-     */
-    private String status;
-    /**
-     * 鐘舵��
-     */
-    private String statusName;
-    /**
-     * 鍔炵悊浜篿d
-     */
-    private String assignee;
-
-    /**
-     * 鍔炵悊浜哄悕绉�
-     */
-    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assignee")
-    private String nickName;
-
-    /**
-     * 鍔炵悊浜篿d
-     */
-    private String owner;
-
-    /**
-     * 瀹℃壒淇℃伅id
-     */
-    private String commentId;
-
-    /**
-     * 瀹℃壒淇℃伅
-     */
-    private String comment;
-
-    /**
-     * 瀹℃壒闄勪欢
-     */
-    private List<Attachment> attachmentList;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java
new file mode 100644
index 0000000..c5d2785
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java
@@ -0,0 +1,67 @@
+package org.dromara.workflow.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.workflow.domain.FlowCategory;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 娴佺▼鍒嗙被瑙嗗浘瀵硅薄 wf_category
+ *
+ * @author may
+ * @date 2023-06-27
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = FlowCategory.class)
+public class FlowCategoryVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼鍒嗙被ID
+     */
+    @ExcelProperty(value = "娴佺▼鍒嗙被ID")
+    private Long categoryId;
+
+    /**
+     * 鐖剁骇id
+     */
+    private Long parentId;
+
+    /**
+     * 鐖剁被鍒悕绉�
+     */
+    private String parentName;
+
+    /**
+     * 绁栫骇鍒楄〃
+     */
+    private String ancestors;
+
+    /**
+     * 娴佺▼鍒嗙被鍚嶇О
+     */
+    @ExcelProperty(value = "娴佺▼鍒嗙被鍚嶇О")
+    private String categoryName;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @ExcelProperty(value = "鏄剧ず椤哄簭")
+    private Long orderNum;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java
new file mode 100644
index 0000000..aef7573
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java
@@ -0,0 +1,104 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.workflow.common.constant.FlowConstant;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 娴佺▼瀹氫箟瑙嗗浘
+ *
+ * @author may
+ */
+@Data
+public class FlowDefinitionVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    private Date updateTime;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 鍒犻櫎鏍囪
+     */
+    private String delFlag;
+
+    /**
+     * 娴佺▼瀹氫箟缂栫爜
+     */
+    private String flowCode;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String flowName;
+
+    /**
+     * 娴佺▼鍒嗙被id
+     */
+    private String category;
+
+    /**
+     * 娴佺▼鍒嗙被鍚嶇О
+     */
+    @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
+    private String categoryName;
+
+    /**
+     * 娴佺▼鐗堟湰
+     */
+    private String version;
+
+    /**
+     * 鏄惁鍙戝竷锛�0鏈彂甯� 1宸插彂甯� 9澶辨晥锛�
+     */
+    private Integer isPublish;
+
+    /**
+     * 瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級
+     */
+    private String formCustom;
+
+    /**
+     * 瀹℃壒琛ㄥ崟璺緞
+     */
+    private String formPath;
+
+    /**
+     * 娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級
+     */
+    private Integer activityStatus;
+
+    /**
+     * 鐩戝惉鍣ㄧ被鍨�
+     */
+    private String listenerType;
+
+    /**
+     * 鐩戝惉鍣ㄨ矾寰�
+     */
+    private String listenerPath;
+
+    /**
+     * 鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤
+     */
+    private String ext;
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java
new file mode 100644
index 0000000..8776a76
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java
@@ -0,0 +1,244 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+import org.dromara.common.core.utils.DateUtils;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.warm.flow.core.enums.CooperateType;
+import org.dromara.workflow.common.constant.FlowConstant;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 鍘嗗彶浠诲姟瑙嗗浘
+ *
+ * @author may
+ */
+@Data
+public class FlowHisTaskVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    private Date updateTime;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 鍒犻櫎鏍囪
+     */
+    private String delFlag;
+
+    /**
+     * 瀵瑰簲flow_definition琛ㄧ殑id
+     */
+    private Long definitionId;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String flowName;
+
+    /**
+     * 娴佺▼瀹炰緥琛╥d
+     */
+    private Long instanceId;
+
+    /**
+     * 浠诲姟琛╥d
+     */
+    private Long taskId;
+
+    /**
+     * 鍗忎綔鏂瑰紡(1瀹℃壒 2杞姙 3濮旀淳 4浼氱 5绁ㄧ 6鍔犵 7鍑忕)
+     */
+    private Integer cooperateType;
+
+    /**
+     * 鍗忎綔鏂瑰紡(1瀹℃壒 2杞姙 3濮旀淳 4浼氱 5绁ㄧ 6鍔犵 7鍑忕)
+     */
+    private String cooperateTypeName;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessId;
+
+    /**
+     * 寮�濮嬭妭鐐圭紪鐮�
+     */
+    private String nodeCode;
+
+    /**
+     * 寮�濮嬭妭鐐瑰悕绉�
+     */
+    private String nodeName;
+
+    /**
+     * 寮�濮嬭妭鐐圭被鍨嬶紙0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�
+     */
+    private Integer nodeType;
+
+    /**
+     * 鐩爣鑺傜偣缂栫爜
+     */
+    private String targetNodeCode;
+
+    /**
+     * 缁撴潫鑺傜偣鍚嶇О
+     */
+    private String targetNodeName;
+
+    /**
+     * 瀹℃壒鑰�
+     */
+    private String approver;
+
+    /**
+     * 瀹℃壒鑰�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "approver")
+    private String approveName;
+
+    /**
+     * 鍗忎綔浜�(鍙湁杞姙銆佷細绛俱�佺エ绛俱�佸娲�)
+     */
+    private String collaborator;
+
+    /**
+     * 鏉冮檺鏍囪瘑 permissionFlag鐨刲ist褰㈠紡
+     */
+    private List<String> permissionList;
+
+    /**
+     * 璺宠浆绫诲瀷锛圥ASS閫氳繃 REJECT閫�鍥� NONE鏃犲姩浣滐級
+     */
+    private String skipType;
+
+    /**
+     * 娴佺▼鐘舵��
+     */
+    private String flowStatus;
+
+    /**
+     * 浠诲姟鐘舵��
+     */
+    private String flowTaskStatus;
+
+    /**
+     * 娴佺▼鐘舵��
+     */
+    private String flowStatusName;
+
+    /**
+     * 瀹℃壒鎰忚
+     */
+    private String message;
+
+    /**
+     * 涓氬姟璇︽儏 瀛樹笟鍔$被鐨刯son
+     */
+    private String ext;
+
+    /**
+     * 鍒涘缓鑰�
+     */
+    private String createBy;
+
+    /**
+     * 鐢宠浜�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy")
+    private String createByName;
+
+    /**
+     * 娴佺▼鍒嗙被id
+     */
+    private String category;
+
+    /**
+     * 娴佺▼鍒嗙被鍚嶇О
+     */
+    @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
+    private String categoryName;
+
+    /**
+     * 瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級
+     */
+    private String formCustom;
+
+    /**
+     * 瀹℃壒琛ㄥ崟璺緞
+     */
+    private String formPath;
+
+    /**
+     * 娴佺▼瀹氫箟缂栫爜
+     */
+    private String flowCode;
+
+    /**
+     * 娴佺▼鐗堟湰鍙�
+     */
+    private String version;
+
+    /**
+     * 杩愯鏃堕暱
+     */
+    private String runDuration;
+
+    /**
+     * 璁剧疆鍒涘缓鏃堕棿骞惰绠椾换鍔¤繍琛屾椂闀�
+     *
+     * @param createTime 鍒涘缓鏃堕棿
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+        updateRunDuration();
+    }
+
+    /**
+     * 璁剧疆鏇存柊鏃堕棿骞惰绠椾换鍔¤繍琛屾椂闀�
+     *
+     * @param updateTime 鏇存柊鏃堕棿
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+        updateRunDuration();
+    }
+
+    /**
+     * 鏇存柊杩愯鏃堕暱
+     */
+    private void updateRunDuration() {
+        // 濡傛灉鍒涘缓鏃堕棿鍜屾洿鏂版椂闂村潎涓嶄负绌猴紝璁$畻瀹冧滑涔嬮棿鐨勬椂闀�
+        if (this.updateTime != null && this.createTime != null) {
+            this.runDuration = DateUtils.getTimeDifference(this.updateTime, this.createTime);
+        }
+    }
+
+    /**
+     * 璁剧疆鍗忎綔鏂瑰紡锛屽苟閫氳繃鍗忎綔鏂瑰紡鑾峰彇鍚嶇О
+     */
+    public void setCooperateType(Integer cooperateType) {
+        this.cooperateType = cooperateType;
+        this.cooperateTypeName = CooperateType.getValueByKey(cooperateType);
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java
new file mode 100644
index 0000000..75543f4
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java
@@ -0,0 +1,137 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.workflow.common.constant.FlowConstant;
+
+import java.util.Date;
+
+/**
+ * 娴佺▼瀹炰緥瑙嗗浘
+ *
+ * @author may
+ */
+@Data
+public class FlowInstanceVo {
+
+    private Long id;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    private Date updateTime;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 鍒犻櫎鏍囪
+     */
+    private String delFlag;
+
+    /**
+     * 瀵瑰簲flow_definition琛ㄧ殑id
+     */
+    private Long definitionId;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String flowName;
+
+    /**
+     * 娴佺▼瀹氫箟缂栫爜
+     */
+    private String flowCode;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessId;
+
+    /**
+     * 鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�
+     */
+    private Integer nodeType;
+
+    /**
+     * 娴佺▼鑺傜偣缂栫爜   姣忎釜娴佺▼鐨刵odeCode鏄敮涓�鐨�,鍗砫efinitionId+nodeCode鍞竴,鍦ㄦ暟鎹簱灞傞潰鍋氫簡鎺у埗
+     */
+    private String nodeCode;
+
+    /**
+     * 娴佺▼鑺傜偣鍚嶇О
+     */
+    private String nodeName;
+
+    /**
+     * 娴佺▼鍙橀噺
+     */
+    private String variable;
+
+    /**
+     * 娴佺▼鐘舵�侊紙0寰呮彁浜� 1瀹℃壒涓� 2 瀹℃壒閫氳繃 3鑷姩閫氳繃 8宸插畬鎴� 9宸查��鍥� 10澶辨晥锛�
+     */
+    private String flowStatus;
+
+    /**
+     * 娴佺▼鐘舵��
+     */
+    private String flowStatusName;
+
+    /**
+     * 娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級
+     */
+    private Integer activityStatus;
+
+    /**
+     * 瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級
+     */
+    private String formCustom;
+
+    /**
+     * 瀹℃壒琛ㄥ崟璺緞
+     */
+    private String formPath;
+
+    /**
+     * 鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤
+     */
+    private String ext;
+
+    /**
+     * 娴佺▼瀹氫箟鐗堟湰
+     */
+    private String version;
+
+    /**
+     * 鍒涘缓鑰�
+     */
+    private String createBy;
+
+    /**
+     * 鐢宠浜�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy")
+    private String createByName;
+
+    /**
+     * 娴佺▼鍒嗙被id
+     */
+    private String category;
+
+    /**
+     * 娴佺▼鍒嗙被鍚嶇О
+     */
+    @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
+    private String categoryName;
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java
new file mode 100644
index 0000000..3fb08d9
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java
@@ -0,0 +1,176 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.warm.flow.core.entity.User;
+import org.dromara.workflow.common.constant.FlowConstant;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 浠诲姟瑙嗗浘
+ *
+ * @author may
+ */
+@Data
+public class FlowTaskVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    private Date updateTime;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 鍒犻櫎鏍囪
+     */
+    private String delFlag;
+
+    /**
+     * 瀵瑰簲flow_definition琛ㄧ殑id
+     */
+    private Long definitionId;
+
+    /**
+     * 娴佺▼瀹炰緥琛╥d
+     */
+    private Long instanceId;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String flowName;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessId;
+
+    /**
+     * 鑺傜偣缂栫爜
+     */
+    private String nodeCode;
+
+    /**
+     * 鑺傜偣鍚嶇О
+     */
+    private String nodeName;
+
+    /**
+     * 鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�
+     */
+    private Integer nodeType;
+
+    /**
+     * 鏉冮檺鏍囪瘑 permissionFlag鐨刲ist褰㈠紡
+     */
+    private List<String> permissionList;
+
+    /**
+     * 娴佺▼鐢ㄦ埛鍒楄〃
+     */
+    private List<User> userList;
+
+    /**
+     * 瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級
+     */
+    private String formCustom;
+
+    /**
+     * 瀹℃壒琛ㄥ崟
+     */
+    private String formPath;
+
+    /**
+     * 娴佺▼瀹氫箟缂栫爜
+     */
+    private String flowCode;
+
+    /**
+     * 娴佺▼鐗堟湰鍙�
+     */
+    private String version;
+
+    /**
+     * 娴佺▼鐘舵��
+     */
+    private String flowStatus;
+
+    /**
+     * 娴佺▼鍒嗙被id
+     */
+    private String category;
+
+    /**
+     * 娴佺▼鍒嗙被鍚嶇О
+     */
+    @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
+    private String categoryName;
+
+    /**
+     * 娴佺▼鐘舵��
+     */
+    @Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "flowStatus", other = "wf_business_status")
+    private String flowStatusName;
+
+    /**
+     * 鍔炵悊浜虹被鍨�
+     */
+    private String type;
+
+    /**
+     * 鍔炵悊浜篿ds
+     */
+    private String assigneeIds;
+
+    /**
+     * 鍔炵悊浜哄悕绉�
+     */
+    private String assigneeNames;
+
+    /**
+     * 鎶勯�佷汉id
+     */
+    private String processedBy;
+
+    /**
+     * 鎶勯�佷汉鍚嶇О
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "processedBy")
+    private String processedByName;
+
+    /**
+     * 娴佺▼绛剧讲姣斾緥鍊� 澶т簬0涓虹エ绛撅紝浼氱
+     */
+    private BigDecimal nodeRatio;
+
+    /**
+     * 鐢宠浜篿d
+     */
+    private String createBy;
+
+    /**
+     * 鐢宠浜哄悕绉�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy")
+    private String createByName;
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java
similarity index 86%
rename from ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java
rename to ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java
index 6a26c82..b4de76e 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java
@@ -11,7 +11,7 @@
  * @author may
  */
 @Data
-public class VariableVo implements Serializable {
+public class FlowVariableVo implements Serializable {
 
     @Serial
     private static final long serialVersionUID = 1L;
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java
deleted file mode 100644
index 7636131..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 鑺傜偣鍥惧舰淇℃伅
- *
- * @author may
- */
-@Data
-public class GraphicInfoVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-    /**
-     * x鍧愭爣
-     */
-    private double x;
-
-    /**
-     * y鍧愭爣
-     */
-    private double y;
-
-    /**
-     * 鑺傜偣楂樺害
-     */
-    private double height;
-
-    /**
-     * 鑺傜偣瀹藉害
-     */
-    private double width;
-
-    /**
-     * 鑺傜偣id
-     */
-    private String nodeId;
-
-    /**
-     * 鑺傜偣鍚嶇О
-     */
-    private String nodeName;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java
deleted file mode 100644
index b2ce811..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 妯″瀷瑙嗗浘瀵硅薄
- *
- * @author may
- */
-@Data
-public class ModelVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 妯″瀷id
-     */
-    private String id;
-
-    /**
-     * 妯″瀷鍚嶇О
-     */
-    private String name;
-
-    /**
-     * 妯″瀷鏍囪瘑key
-     */
-    private String key;
-
-    /**
-     * 妯″瀷鍒嗙被
-     */
-    private String categoryCode;
-
-    /**
-     * 妯″瀷XML
-     */
-    private String xml;
-
-    /**
-     * 澶囨敞
-     */
-    private String description;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java
deleted file mode 100644
index b998396..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-/**
- * 澶氬疄渚嬩俊鎭�
- *
- * @author may
- */
-@Data
-public class MultiInstanceVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 浼氱绫诲瀷锛堜覆琛岋紝骞惰锛�
-     */
-    private Object type;
-
-    /**
-     * 浼氱浜哄憳KEY
-     */
-    private String assignee;
-
-    /**
-     * 浼氱浜哄憳闆嗗悎KEY
-     */
-    private String assigneeList;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java
deleted file mode 100644
index c5876f6..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * 鍙備笌鑰�
- *
- * @author may
- */
-@Data
-public class ParticipantVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 缁刬d锛堣鑹瞚d锛�
-     */
-    private List<Long> groupIds;
-
-    /**
-     * 鍊欓�変汉id锛堢敤鎴穒d锛� 褰撶粍id涓嶄负绌烘椂锛屽皢缁勫唴浜哄憳鏌ュ嚭鏀惧叆candidate
-     */
-    private List<Long> candidate;
-
-    /**
-     * 鍊欓�変汉鍚嶇О锛堢敤鎴峰悕绉帮級 褰撶粍id涓嶄负绌烘椂锛屽皢缁勫唴浜哄憳鏌ュ嚭鏀惧叆candidateName
-     */
-    private List<String> candidateName;
-
-    /**
-     * 鏄惁璁ら鏍囪瘑
-     * 褰撲负绌烘椂榛樿褰撳墠浠诲姟涓嶉渶瑕佽棰�
-     * 褰撲负true鏃跺綋鍓嶄换鍔¤鏄庝负鍊欓�夋ā寮忓苟涓旀湁浜哄凡缁忚棰嗕簡浠诲姟鍙互褰掕繕锛�
-     * 褰撲负false鏃跺綋鍓嶄换鍔¤鏄庝负鍊欓�夋ā寮忚浠诲姟鏈棰嗭紝
-     */
-    private Boolean claim;
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java
deleted file mode 100644
index 034adbb..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * 娴佺▼瀹氫箟瑙嗗浘
- *
- * @author may
- */
-@Data
-public class ProcessDefinitionVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 娴佺▼瀹氫箟id
-     */
-    private String id;
-
-    /**
-     * 娴佺▼瀹氫箟鍚嶇О
-     */
-    private String name;
-
-    /**
-     * 娴佺▼瀹氫箟鏍囪瘑key
-     */
-    private String key;
-
-    /**
-     * 娴佺▼瀹氫箟鐗堟湰
-     */
-    private int version;
-
-    /**
-     * 娴佺▼瀹氫箟鎸傝捣鎴栨縺娲� 1婵�娲� 2鎸傝捣
-     */
-    private int suspensionState;
-
-    /**
-     * 娴佺▼xml鍚嶇О
-     */
-    private String resourceName;
-
-    /**
-     * 娴佺▼鍥剧墖鍚嶇О
-     */
-    private String diagramResourceName;
-
-    /**
-     * 娴佺▼閮ㄧ讲id
-     */
-    private String deploymentId;
-
-    /**
-     * 娴佺▼閮ㄧ讲鏃堕棿
-     */
-    private Date deploymentTime;
-
-    /**
-     * 娴佺▼瀹氫箟閰嶇疆
-     */
-    private WfDefinitionConfigVo wfDefinitionConfigVo;
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java
deleted file mode 100644
index ab3e7a1..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.util.Date;
-import java.util.List;
-
-/**
- * 娴佺▼瀹炰緥瑙嗗浘
- *
- * @author may
- */
-@Data
-public class ProcessInstanceVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 娴佺▼瀹炰緥id
-     */
-    private String id;
-
-    /**
-     * 娴佺▼瀹氫箟id
-     */
-    private String processDefinitionId;
-
-    /**
-     * 娴佺▼瀹氫箟鍚嶇О
-     */
-    private String processDefinitionName;
-
-    /**
-     * 娴佺▼瀹氫箟key
-     */
-    private String processDefinitionKey;
-
-    /**
-     * 娴佺▼瀹氫箟鐗堟湰
-     */
-    private Integer processDefinitionVersion;
-
-    /**
-     * 閮ㄧ讲id
-     */
-    private String deploymentId;
-
-    /**
-     * 涓氬姟id
-     */
-    private String businessKey;
-
-    /**
-     * 鏄惁鎸傝捣
-     */
-    private Boolean isSuspended;
-
-    /**
-     * 绉熸埛id
-     */
-    private String tenantId;
-
-    /**
-     * 鍚姩鏃堕棿
-     */
-    private Date startTime;
-
-    /**
-     * 缁撴潫鏃堕棿
-     */
-    private Date endTime;
-
-    /**
-     * 鍚姩浜篿d
-     */
-    private String startUserId;
-
-    /**
-     * 娴佺▼鐘舵��
-     */
-    private String businessStatus;
-
-    /**
-     * 娴佺▼鐘舵��
-     */
-    private String businessStatusName;
-
-    /**
-     * 寰呭姙浠诲姟闆嗗悎
-     */
-    private List<TaskVo> taskVoList;
-
-    /**
-     * 鑺傜偣閰嶇疆
-     */
-    private WfNodeConfigVo wfNodeConfigVo;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java
deleted file mode 100644
index 466e776..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import lombok.Data;
-import org.dromara.common.translation.annotation.Translation;
-import org.dromara.common.translation.constant.TransConstant;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * 浠诲姟瑙嗗浘
- *
- * @author may
- */
-@Data
-public class TaskVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 浠诲姟id
-     */
-    private String id;
-
-    /**
-     * 浠诲姟鍚嶇О
-     */
-    private String name;
-
-    /**
-     * 鎻忚堪
-     */
-    private String description;
-
-    /**
-     * 浼樺厛绾�
-     */
-    private Integer priority;
-
-    /**
-     * 璐熻矗姝や换鍔$殑浜哄憳鐨勭敤鎴穒d
-     */
-    private String owner;
-
-    /**
-     * 鍔炵悊浜篿d
-     */
-    private Long assignee;
-
-    /**
-     * 鍔炵悊浜�
-     */
-    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assignee")
-    private String assigneeName;
-
-
-    /**
-     * 娴佺▼瀹炰緥id
-     */
-    private String processInstanceId;
-
-    /**
-     * 鎵цid
-     */
-    private String executionId;
-
-    /**
-     * 鏃犵敤
-     */
-    private String taskDefinitionId;
-
-    /**
-     * 娴佺▼瀹氫箟id
-     */
-    private String processDefinitionId;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    private Date createTime;
-
-    /**
-     * 宸插姙浠诲姟-鍒涘缓鏃堕棿
-     */
-    private Date startTime;
-
-    /**
-     * 缁撴潫鏃堕棿
-     */
-    private Date endTime;
-
-    /**
-     * 鑺傜偣id
-     */
-    private String taskDefinitionKey;
-
-    /**
-     * 浠诲姟鎴鏃ユ湡
-     */
-    private Date dueDate;
-
-    /**
-     * 娴佺▼绫诲埆
-     */
-    private String category;
-
-    /**
-     * 鐖剁骇浠诲姟id
-     */
-    private String parentTaskId;
-
-    /**
-     * 绉熸埛id
-     */
-    private String tenantId;
-
-    /**
-     * 璁ら鏃堕棿
-     */
-    private Date claimTime;
-
-    /**
-     * 娴佺▼鐘舵��
-     */
-    private String businessStatus;
-
-    /**
-     * 娴佺▼鐘舵��
-     */
-    private String businessStatusName;
-
-    /**
-     * 娴佺▼瀹氫箟鍚嶇О
-     */
-    private String processDefinitionName;
-
-    /**
-     * 娴佺▼瀹氫箟key
-     */
-    private String processDefinitionKey;
-
-    /**
-     * 娴佺▼瀹氫箟鐗堟湰
-     */
-    private Integer processDefinitionVersion;
-
-    /**
-     * 鍙備笌鑰�
-     */
-    private ParticipantVo participantVo;
-
-    /**
-     * 鏄惁浼氱
-     */
-    private Boolean multiInstance;
-
-    /**
-     * 涓氬姟id
-     */
-    private String businessKey;
-
-    /**
-     * 娴佺▼瀹氫箟閰嶇疆
-     */
-    private WfDefinitionConfigVo wfDefinitionConfigVo;
-
-    /**
-     * 鑺傜偣閰嶇疆
-     */
-    private WfNodeConfigVo wfNodeConfigVo;
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java
deleted file mode 100644
index 362f646..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
-import com.alibaba.excel.annotation.ExcelProperty;
-import io.github.linpeilie.annotations.AutoMapper;
-import lombok.Data;
-import org.dromara.workflow.domain.WfCategory;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-
-/**
- * 娴佺▼鍒嗙被瑙嗗浘瀵硅薄 wf_category
- *
- * @author may
- * @date 2023-06-27
- */
-@Data
-@ExcelIgnoreUnannotated
-@AutoMapper(target = WfCategory.class)
-public class WfCategoryVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭
-     */
-    @ExcelProperty(value = "涓婚敭")
-    private Long id;
-
-    /**
-     * 鍒嗙被鍚嶇О
-     */
-    @ExcelProperty(value = "鍒嗙被鍚嶇О")
-    private String categoryName;
-
-    /**
-     * 鍒嗙被缂栫爜
-     */
-    @ExcelProperty(value = "鍒嗙被缂栫爜")
-    private String categoryCode;
-
-    /**
-     * 鐖剁骇id
-     */
-    @ExcelProperty(value = "鐖剁骇id")
-    private Long parentId;
-
-    /**
-     * 鎺掑簭
-     */
-    @ExcelProperty(value = "鎺掑簭")
-    private Long sortNum;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java
deleted file mode 100644
index 9c7b0d7..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import org.dromara.workflow.domain.WfDefinitionConfig;
-import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
-import com.alibaba.excel.annotation.ExcelProperty;
-import io.github.linpeilie.annotations.AutoMapper;
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-
-/**
- * 娴佺▼瀹氫箟閰嶇疆瑙嗗浘瀵硅薄 wf_definition_config
- *
- * @author may
- * @date 2024-03-18
- */
-@Data
-@ExcelIgnoreUnannotated
-@AutoMapper(target = WfDefinitionConfig.class)
-public class WfDefinitionConfigVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭
-     */
-    @ExcelProperty(value = "涓婚敭")
-    private Long id;
-
-    /**
-     * 琛ㄥ悕
-     */
-    @ExcelProperty(value = "琛ㄥ悕")
-    private String tableName;
-
-    /**
-     * 娴佺▼瀹氫箟ID
-     */
-    @ExcelProperty(value = "娴佺▼瀹氫箟ID")
-    private String definitionId;
-
-    /**
-     * 娴佺▼KEY
-     */
-    @ExcelProperty(value = "娴佺▼KEY")
-    private String processKey;
-
-
-    /**
-     * 娴佺▼鐗堟湰
-     */
-    @ExcelProperty(value = "娴佺▼鐗堟湰")
-    private Integer version;
-
-    /**
-     * 澶囨敞
-     */
-    @ExcelProperty(value = "澶囨敞")
-    private String remark;
-
-    /**
-     * 琛ㄥ崟绠$悊
-     */
-    private WfFormManageVo wfFormManageVo;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java
deleted file mode 100644
index 302df23..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import org.dromara.workflow.domain.WfFormManage;
-import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
-import com.alibaba.excel.annotation.ExcelProperty;
-import io.github.linpeilie.annotations.AutoMapper;
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-
-/**
- * 琛ㄥ崟绠$悊瑙嗗浘瀵硅薄 wf_form_manage
- *
- * @author may
- * @date 2024-03-29
- */
-@Data
-@ExcelIgnoreUnannotated
-@AutoMapper(target = WfFormManage.class)
-public class WfFormManageVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭
-     */
-    @ExcelProperty(value = "涓婚敭")
-    private Long id;
-
-    /**
-     * 琛ㄥ崟鍚嶇О
-     */
-    @ExcelProperty(value = "琛ㄥ崟鍚嶇О")
-    private String formName;
-
-    /**
-     * 琛ㄥ崟绫诲瀷
-     */
-    @ExcelProperty(value = "琛ㄥ崟绫诲瀷")
-    private String formType;
-
-    /**
-     * 琛ㄥ崟绫诲瀷鍚嶇О
-     */
-    private String formTypeName;
-
-    /**
-     * 璺敱鍦板潃/琛ㄥ崟ID
-     */
-    @ExcelProperty(value = "璺敱鍦板潃/琛ㄥ崟ID")
-    private String router;
-
-    /**
-     * 澶囨敞
-     */
-    @ExcelProperty(value = "澶囨敞")
-    private String remark;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java
deleted file mode 100644
index 89e9d9b..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.dromara.workflow.domain.vo;
-
-import org.dromara.workflow.domain.WfNodeConfig;
-import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
-import com.alibaba.excel.annotation.ExcelProperty;
-import io.github.linpeilie.annotations.AutoMapper;
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-
-/**
- * 鑺傜偣閰嶇疆瑙嗗浘瀵硅薄 wf_node_config
- *
- * @author may
- * @date 2024-03-30
- */
-@Data
-@ExcelIgnoreUnannotated
-@AutoMapper(target = WfNodeConfig.class)
-public class WfNodeConfigVo implements Serializable {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 涓婚敭
-     */
-    @ExcelProperty(value = "涓婚敭")
-    private Long id;
-
-    /**
-     * 琛ㄥ崟id
-     */
-    @ExcelProperty(value = "琛ㄥ崟id")
-    private Long formId;
-
-    /**
-     * 琛ㄥ崟绫诲瀷
-     */
-    @ExcelProperty(value = "琛ㄥ崟绫诲瀷")
-    private String formType;
-
-    /**
-     * 鑺傜偣鍚嶇О
-     */
-    @ExcelProperty(value = "鑺傜偣鍚嶇О")
-    private String nodeName;
-
-    /**
-     * 鑺傜偣id
-     */
-    @ExcelProperty(value = "鑺傜偣id")
-    private String nodeId;
-
-    /**
-     * 娴佺▼瀹氫箟id
-     */
-    @ExcelProperty(value = "娴佺▼瀹氫箟id")
-    private String definitionId;
-
-    /**
-     * 鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級
-     */
-    @ExcelProperty(value = "鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級")
-    private String applyUserTask;
-
-    /**
-     * 琛ㄥ崟绠$悊
-     */
-    private WfFormManageVo wfFormManageVo;
-
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java
deleted file mode 100644
index 39fd9d3..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.dromara.workflow.flowable;
-
-import org.flowable.bpmn.model.AssociationDirection;
-import org.flowable.image.impl.DefaultProcessDiagramCanvas;
-
-import java.awt.*;
-import java.awt.geom.Line2D;
-import java.awt.geom.RoundRectangle2D;
-
-public class CustomDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
-    //璁剧疆楂樹寒绾跨殑棰滆壊  杩欓噷鎴戣缃垚缁胯壊
-    protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN;
-
-    public CustomDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
-        super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
-    }
-
-    /**
-     * 鐢荤嚎棰滆壊璁剧疆
-     */
-    public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType,
-                               AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {
-
-        Paint originalPaint = g.getPaint();
-        Stroke originalStroke = g.getStroke();
-
-        g.setPaint(CONNECTION_COLOR);
-        if (connectionType.equals("association")) {
-            g.setStroke(ASSOCIATION_STROKE);
-        } else if (highLighted) {
-            //璁剧疆绾跨殑棰滆壊
-            g.setPaint(HIGHLIGHT_SEQUENCEFLOW_COLOR);
-            g.setStroke(HIGHLIGHT_FLOW_STROKE);
-        }
-
-        for (int i = 1; i < xPoints.length; i++) {
-            Integer sourceX = xPoints[i - 1];
-            Integer sourceY = yPoints[i - 1];
-            Integer targetX = xPoints[i];
-            Integer targetY = yPoints[i];
-            Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
-            g.draw(line);
-        }
-
-        if (isDefault) {
-            Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
-            drawDefaultSequenceFlowIndicator(line, scaleFactor);
-        }
-
-        if (conditional) {
-            Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
-            drawConditionalSequenceFlowIndicator(line, scaleFactor);
-        }
-
-        if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) {
-            Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
-            drawArrowHead(line, scaleFactor);
-        }
-        if (associationDirection == AssociationDirection.BOTH) {
-            Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
-            drawArrowHead(line, scaleFactor);
-        }
-        g.setPaint(originalPaint);
-        g.setStroke(originalStroke);
-    }
-
-    /**
-     * 楂樹寒鑺傜偣璁剧疆
-     */
-    public void drawHighLight(int x, int y, int width, int height) {
-        Paint originalPaint = g.getPaint();
-        Stroke originalStroke = g.getStroke();
-        //璁剧疆楂樹寒鑺傜偣鐨勯鑹�
-        g.setPaint(HIGHLIGHT_COLOR);
-        g.setStroke(THICK_TASK_BORDER_STROKE);
-
-        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
-        g.draw(rect);
-
-        g.setPaint(originalPaint);
-        g.setStroke(originalStroke);
-    }
-
-    /**
-     * @description: 楂樹寒鑺傜偣绾㈣壊
-     * @param: x
-     * @param: y
-     * @param: width
-     * @param: height
-     * @return: void
-     * @author: gssong
-     * @date: 2022/4/12
-     */
-    public void drawHighLightRed(int x, int y, int width, int height) {
-        Paint originalPaint = g.getPaint();
-        Stroke originalStroke = g.getStroke();
-        //璁剧疆楂樹寒鑺傜偣鐨勯鑹�
-        g.setPaint(Color.green);
-        g.setStroke(THICK_TASK_BORDER_STROKE);
-
-        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
-        g.draw(rect);
-
-        g.setPaint(originalPaint);
-        g.setStroke(originalStroke);
-    }
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java
deleted file mode 100644
index e4793a2..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java
+++ /dev/null
@@ -1,1120 +0,0 @@
-/* Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.dromara.workflow.flowable;
-
-import org.flowable.bpmn.model.Event;
-import org.flowable.bpmn.model.Process;
-import org.flowable.bpmn.model.*;
-import org.flowable.image.ProcessDiagramGenerator;
-
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.io.InputStream;
-import java.util.List;
-import java.util.*;
-
-/**
- * Class to generate an image based the diagram interchange information in a BPMN 2.0 process.
- *
- * @author Joram Barrez
- * @author Tijs Rademakers
- * @author Zheng Ji
- */
-public class CustomDefaultProcessDiagramGenerator implements ProcessDiagramGenerator {
-
-    protected Map<Class<? extends BaseElement>, ActivityDrawInstruction> activityDrawInstructions = new HashMap<>();
-    protected Map<Class<? extends BaseElement>, ArtifactDrawInstruction> artifactDrawInstructions = new HashMap<>();
-
-    public CustomDefaultProcessDiagramGenerator() {
-        this(1.0);
-    }
-
-    // The instructions on how to draw a certain construct is
-    // created statically and stored in a map for performance.
-    public CustomDefaultProcessDiagramGenerator(final double scaleFactor) {
-        // start event
-        activityDrawInstructions.put(StartEvent.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                StartEvent startEvent = (StartEvent) flowNode;
-                if (startEvent.getEventDefinitions() != null && !startEvent.getEventDefinitions().isEmpty()) {
-                    EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0);
-                    if (eventDefinition instanceof TimerEventDefinition) {
-                        processDiagramCanvas.drawTimerStartEvent(graphicInfo, scaleFactor);
-                    } else if (eventDefinition instanceof ErrorEventDefinition) {
-                        processDiagramCanvas.drawErrorStartEvent(graphicInfo, scaleFactor);
-                    } else if (eventDefinition instanceof EscalationEventDefinition) {
-                        processDiagramCanvas.drawEscalationStartEvent(graphicInfo, scaleFactor);
-                    } else if (eventDefinition instanceof ConditionalEventDefinition) {
-                        processDiagramCanvas.drawConditionalStartEvent(graphicInfo, scaleFactor);
-                    } else if (eventDefinition instanceof SignalEventDefinition) {
-                        processDiagramCanvas.drawSignalStartEvent(graphicInfo, scaleFactor);
-                    } else if (eventDefinition instanceof MessageEventDefinition) {
-                        processDiagramCanvas.drawMessageStartEvent(graphicInfo, scaleFactor);
-                    } else {
-                        processDiagramCanvas.drawNoneStartEvent(graphicInfo);
-                    }
-                } else {
-                    List<ExtensionElement> eventTypeElements = startEvent.getExtensionElements().get("eventType");
-                    if (eventTypeElements != null && eventTypeElements.size() > 0) {
-                        processDiagramCanvas.drawEventRegistryStartEvent(graphicInfo, scaleFactor);
-
-                    } else {
-                        processDiagramCanvas.drawNoneStartEvent(graphicInfo);
-                    }
-                }
-            }
-        });
-
-        // signal catch
-        activityDrawInstructions.put(IntermediateCatchEvent.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent) flowNode;
-                if (intermediateCatchEvent.getEventDefinitions() != null && !intermediateCatchEvent.getEventDefinitions().isEmpty()) {
-
-                    if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
-                        processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
-                    } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) {
-                        processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
-                    } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) {
-                        processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
-                    } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof ConditionalEventDefinition) {
-                        processDiagramCanvas.drawCatchingConditionalEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
-                    }
-                }
-            }
-        });
-
-        // signal throw
-        activityDrawInstructions.put(ThrowEvent.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                ThrowEvent throwEvent = (ThrowEvent) flowNode;
-                if (throwEvent.getEventDefinitions() != null && !throwEvent.getEventDefinitions().isEmpty()) {
-                    if (throwEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
-                        processDiagramCanvas.drawThrowingSignalEvent(graphicInfo, scaleFactor);
-                    } else if (throwEvent.getEventDefinitions().get(0) instanceof EscalationEventDefinition) {
-                        processDiagramCanvas.drawThrowingEscalationEvent(graphicInfo, scaleFactor);
-                    } else if (throwEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) {
-                        processDiagramCanvas.drawThrowingCompensateEvent(graphicInfo, scaleFactor);
-                    } else {
-                        processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor);
-                    }
-                } else {
-                    processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor);
-                }
-            }
-        });
-
-        // end event
-        activityDrawInstructions.put(EndEvent.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                EndEvent endEvent = (EndEvent) flowNode;
-                if (endEvent.getEventDefinitions() != null && !endEvent.getEventDefinitions().isEmpty()) {
-                    if (endEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) {
-                        processDiagramCanvas.drawErrorEndEvent(flowNode.getName(), graphicInfo, scaleFactor);
-                    } else if (endEvent.getEventDefinitions().get(0) instanceof EscalationEventDefinition) {
-                        processDiagramCanvas.drawEscalationEndEvent(flowNode.getName(), graphicInfo, scaleFactor);
-                    } else {
-                        processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor);
-                    }
-                } else {
-                    processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor);
-                }
-            }
-        });
-
-        // task
-        activityDrawInstructions.put(Task.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // user task
-        activityDrawInstructions.put(UserTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawUserTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // script task
-        activityDrawInstructions.put(ScriptTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawScriptTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // service task
-        activityDrawInstructions.put(ServiceTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                ServiceTask serviceTask = (ServiceTask) flowNode;
-                if ("camel".equalsIgnoreCase(serviceTask.getType())) {
-                    processDiagramCanvas.drawCamelTask(serviceTask.getName(), graphicInfo, scaleFactor);
-                }else if (ServiceTask.HTTP_TASK.equalsIgnoreCase(serviceTask.getType())) {
-                    processDiagramCanvas.drawHttpTask(serviceTask.getName(), graphicInfo, scaleFactor);
-                } else if (ServiceTask.DMN_TASK.equalsIgnoreCase(serviceTask.getType())) {
-                    processDiagramCanvas.drawDMNTask(serviceTask.getName(), graphicInfo, scaleFactor);
-                } else if (ServiceTask.SHELL_TASK.equalsIgnoreCase(serviceTask.getType())) {
-                    processDiagramCanvas.drawShellTask(serviceTask.getName(), graphicInfo, scaleFactor);
-                } else {
-                    processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor);
-                }
-            }
-        });
-
-        // http service task
-        activityDrawInstructions.put(HttpServiceTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawHttpTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // receive task
-        activityDrawInstructions.put(ReceiveTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawReceiveTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // send task
-        activityDrawInstructions.put(SendTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawSendTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // manual task
-        activityDrawInstructions.put(ManualTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawManualTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // send event service task
-        activityDrawInstructions.put(SendEventServiceTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawSendEventServiceTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // external worker service task
-        activityDrawInstructions.put(ExternalWorkerServiceTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                ServiceTask serviceTask = (ServiceTask) flowNode;
-                processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // case service task
-        activityDrawInstructions.put(CaseServiceTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawCaseServiceTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // businessRuleTask task
-        activityDrawInstructions.put(BusinessRuleTask.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawBusinessRuleTask(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // exclusive gateway
-        activityDrawInstructions.put(ExclusiveGateway.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawExclusiveGateway(graphicInfo, scaleFactor);
-            }
-        });
-
-        // inclusive gateway
-        activityDrawInstructions.put(InclusiveGateway.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawInclusiveGateway(graphicInfo, scaleFactor);
-            }
-        });
-
-        // parallel gateway
-        activityDrawInstructions.put(ParallelGateway.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawParallelGateway(graphicInfo, scaleFactor);
-            }
-        });
-
-        // event based gateway
-        activityDrawInstructions.put(EventGateway.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawEventBasedGateway(graphicInfo, scaleFactor);
-            }
-        });
-
-        // Boundary timer
-        activityDrawInstructions.put(BoundaryEvent.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                BoundaryEvent boundaryEvent = (BoundaryEvent) flowNode;
-                if (boundaryEvent.getEventDefinitions() != null && !boundaryEvent.getEventDefinitions().isEmpty()) {
-                    EventDefinition eventDefinition = boundaryEvent.getEventDefinitions().get(0);
-                    if (eventDefinition instanceof TimerEventDefinition) {
-                        processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
-
-                    } else if (eventDefinition instanceof ConditionalEventDefinition) {
-                        processDiagramCanvas.drawCatchingConditionalEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
-
-                    } else if (eventDefinition instanceof ErrorEventDefinition) {
-                        processDiagramCanvas.drawCatchingErrorEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
-
-                    } else if (eventDefinition instanceof EscalationEventDefinition) {
-                        processDiagramCanvas.drawCatchingEscalationEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
-
-                    } else if (eventDefinition instanceof SignalEventDefinition) {
-                        processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
-
-                    } else if (eventDefinition instanceof MessageEventDefinition) {
-                        processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
-
-                    } else if (eventDefinition instanceof CompensateEventDefinition) {
-                        processDiagramCanvas.drawCatchingCompensateEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
-                    }
-
-                } else {
-                    List<ExtensionElement> eventTypeElements = boundaryEvent.getExtensionElements().get("eventType");
-                    if (eventTypeElements != null && eventTypeElements.size() > 0) {
-                        processDiagramCanvas.drawCatchingEventRegistryEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
-                    }
-                }
-            }
-        });
-
-        // subprocess
-        activityDrawInstructions.put(SubProcess.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
-                    processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
-                } else {
-                    processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
-                }
-            }
-        });
-
-        // transaction
-        activityDrawInstructions.put(Transaction.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
-                    processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
-                } else {
-                    processDiagramCanvas.drawExpandedTransaction(flowNode.getName(), graphicInfo, scaleFactor);
-                }
-            }
-        });
-
-        // Event subprocess
-        activityDrawInstructions.put(EventSubProcess.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
-                    processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor);
-                } else {
-                    processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor);
-                }
-            }
-        });
-
-        // Adhoc subprocess
-        activityDrawInstructions.put(AdhocSubProcess.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
-                    processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
-                } else {
-                    processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
-                }
-            }
-        });
-
-        // call activity
-        activityDrawInstructions.put(CallActivity.class, new ActivityDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-                processDiagramCanvas.drawCollapsedCallActivity(flowNode.getName(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // text annotation
-        artifactDrawInstructions.put(TextAnnotation.class, new ArtifactDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
-                TextAnnotation textAnnotation = (TextAnnotation) artifact;
-                processDiagramCanvas.drawTextAnnotation(textAnnotation.getText(), graphicInfo, scaleFactor);
-            }
-        });
-
-        // association
-        artifactDrawInstructions.put(Association.class, new ArtifactDrawInstruction() {
-
-            @Override
-            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
-                Association association = (Association) artifact;
-                String sourceRef = association.getSourceRef();
-                String targetRef = association.getTargetRef();
-
-                // source and target can be instance of FlowElement or Artifact
-                BaseElement sourceElement = bpmnModel.getFlowElement(sourceRef);
-                BaseElement targetElement = bpmnModel.getFlowElement(targetRef);
-                if (sourceElement == null) {
-                    sourceElement = bpmnModel.getArtifact(sourceRef);
-                }
-                if (targetElement == null) {
-                    targetElement = bpmnModel.getArtifact(targetRef);
-                }
-                List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
-                graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
-                int[] xPoints = new int[graphicInfoList.size()];
-                int[] yPoints = new int[graphicInfoList.size()];
-                for (int i = 1; i < graphicInfoList.size(); i++) {
-                    GraphicInfo graphicInfo = graphicInfoList.get(i);
-                    GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
-
-                    if (i == 1) {
-                        xPoints[0] = (int) previousGraphicInfo.getX();
-                        yPoints[0] = (int) previousGraphicInfo.getY();
-                    }
-                    xPoints[i] = (int) graphicInfo.getX();
-                    yPoints[i] = (int) graphicInfo.getY();
-                }
-
-                AssociationDirection associationDirection = association.getAssociationDirection();
-                processDiagramCanvas.drawAssociation(xPoints, yPoints, associationDirection, false, scaleFactor);
-            }
-        });
-    }
-
-    @Override
-    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
-                                       String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
-
-        return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
-            activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI).generateImage(imageType);
-    }
-
-    @Override
-    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows, boolean drawSequenceFlowNameWithNoLabelDI) {
-        return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, 1.0, drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    @Override
-    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType,
-                                       List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
-        return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    @Override
-    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, boolean drawSequenceFlowNameWithNoLabelDI) {
-        return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.emptyList(), drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    @Override
-    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
-        return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.emptyList(), scaleFactor, drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    @Override
-    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName,
-                                       String labelFontName, String annotationFontName, ClassLoader customClassLoader, boolean drawSequenceFlowNameWithNoLabelDI) {
-
-        return generateDiagram(bpmnModel, imageType, Collections.emptyList(), Collections.emptyList(),
-            activityFontName, labelFontName, annotationFontName, customClassLoader, 1.0, drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    @Override
-    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName,
-                                       String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
-
-        return generateDiagram(bpmnModel, imageType, Collections.emptyList(), Collections.emptyList(),
-            activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    @Override
-    public InputStream generatePngDiagram(BpmnModel bpmnModel, boolean drawSequenceFlowNameWithNoLabelDI) {
-        return generatePngDiagram(bpmnModel, 1.0, drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    @Override
-    public InputStream generatePngDiagram(BpmnModel bpmnModel, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
-        return generateDiagram(bpmnModel, "png", Collections.emptyList(), Collections.emptyList(), scaleFactor, drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    @Override
-    public InputStream generateJpgDiagram(BpmnModel bpmnModel) {
-        return generateJpgDiagram(bpmnModel, 1.0, false);
-    }
-
-    @Override
-    public InputStream generateJpgDiagram(BpmnModel bpmnModel, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
-        return generateDiagram(bpmnModel, "jpg", Collections.emptyList(), Collections.emptyList(), drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
-                                       String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
-
-        return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
-            activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI).generateBufferedImage(imageType);
-    }
-
-    public BufferedImage generateImage(BpmnModel bpmnModel, String imageType,
-                                       List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
-
-        return generateImage(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
-    }
-
-    @Override
-    public BufferedImage generatePngImage(BpmnModel bpmnModel, double scaleFactor) {
-        return generateImage(bpmnModel, "png", Collections.emptyList(), Collections.emptyList(), scaleFactor, false);
-    }
-
-    protected CustomDefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType,
-                                                                       List<String> highLightedActivities, List<String> highLightedFlows,
-                                                                       String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
-
-        prepareBpmnModel(bpmnModel);
-
-        CustomDefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
-
-        // Draw pool shape, if process is participant in collaboration
-        for (Pool pool : bpmnModel.getPools()) {
-            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
-            processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo, scaleFactor);
-        }
-
-        // Draw lanes
-        for (Process process : bpmnModel.getProcesses()) {
-            for (Lane lane : process.getLanes()) {
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId());
-                processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo, scaleFactor);
-            }
-        }
-
-        // Draw activities and their sequence-flows
-        for (Process process : bpmnModel.getProcesses()) {
-            for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) {
-                if (!isPartOfCollapsedSubProcess(flowNode, bpmnModel)) {
-                    drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
-                }
-            }
-        }
-
-        // Draw artifacts
-        for (Process process : bpmnModel.getProcesses()) {
-
-            for (Artifact artifact : process.getArtifacts()) {
-                drawArtifact(processDiagramCanvas, bpmnModel, artifact);
-            }
-
-            List<SubProcess> subProcesses = process.findFlowElementsOfType(SubProcess.class, true);
-            if (subProcesses != null) {
-                for (SubProcess subProcess : subProcesses) {
-
-                    GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(subProcess.getId());
-                    if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
-                        continue;
-                    }
-
-                    if (!isPartOfCollapsedSubProcess(subProcess, bpmnModel)) {
-                        for (Artifact subProcessArtifact : subProcess.getArtifacts()) {
-                            drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact);
-                        }
-                    }
-                }
-            }
-        }
-
-        return processDiagramCanvas;
-    }
-
-    protected void prepareBpmnModel(BpmnModel bpmnModel) {
-
-        // Need to make sure all elements have positive x and y.
-        // Check all graphicInfo and update the elements accordingly
-
-        List<GraphicInfo> allGraphicInfos = new ArrayList<>();
-        if (bpmnModel.getLocationMap() != null) {
-            allGraphicInfos.addAll(bpmnModel.getLocationMap().values());
-        }
-        if (bpmnModel.getLabelLocationMap() != null) {
-            allGraphicInfos.addAll(bpmnModel.getLabelLocationMap().values());
-        }
-        if (bpmnModel.getFlowLocationMap() != null) {
-            for (List<GraphicInfo> flowGraphicInfos : bpmnModel.getFlowLocationMap().values()) {
-                allGraphicInfos.addAll(flowGraphicInfos);
-            }
-        }
-
-        if (allGraphicInfos.size() > 0) {
-
-            boolean needsTranslationX = false;
-            boolean needsTranslationY = false;
-
-            double lowestX = 0.0;
-            double lowestY = 0.0;
-
-            // Collect lowest x and y
-            for (GraphicInfo graphicInfo : allGraphicInfos) {
-
-                double x = graphicInfo.getX();
-                double y = graphicInfo.getY();
-
-                if (x < lowestX) {
-                    needsTranslationX = true;
-                    lowestX = x;
-                }
-                if (y < lowestY) {
-                    needsTranslationY = true;
-                    lowestY = y;
-                }
-
-            }
-
-            // Update all graphicInfo objects
-            if (needsTranslationX || needsTranslationY) {
-
-                double translationX = Math.abs(lowestX);
-                double translationY = Math.abs(lowestY);
-
-                for (GraphicInfo graphicInfo : allGraphicInfos) {
-                    if (needsTranslationX) {
-                        graphicInfo.setX(graphicInfo.getX() + translationX);
-                    }
-                    if (needsTranslationY) {
-                        graphicInfo.setY(graphicInfo.getY() + translationY);
-                    }
-                }
-            }
-
-        }
-
-    }
-
-    protected void drawActivity(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel,
-                                FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, Boolean drawSequenceFlowNameWithNoLabelDI) {
-
-        ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
-        if (drawInstruction != null) {
-
-            drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);
-
-            // Gather info on the multi instance marker
-            boolean multiInstanceSequential = false;
-            boolean multiInstanceParallel = false;
-            boolean collapsed = false;
-            if (flowNode instanceof Activity) {
-                Activity activity = (Activity) flowNode;
-                MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics();
-                if (multiInstanceLoopCharacteristics != null) {
-                    multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential();
-                    multiInstanceParallel = !multiInstanceSequential;
-                }
-            }
-
-            // Gather info on the collapsed marker
-            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-            if (flowNode instanceof SubProcess) {
-                collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
-            } else if (flowNode instanceof CallActivity) {
-                collapsed = true;
-            }
-
-            if (scaleFactor == 1.0) {
-                // Actually draw the markers
-                processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(),
-                    multiInstanceSequential, multiInstanceParallel, collapsed);
-            }
-
-            // Draw highlighted activities
-            if (highLightedActivities.contains(flowNode.getId())) {
-                drawHighLightRed(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
-            } else if (highLightedActivities.contains(Color.RED.toString() + flowNode.getId())) {
-                drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
-            }
-
-        } else if (flowNode instanceof Task) {
-            activityDrawInstructions.get(Task.class).draw(processDiagramCanvas, bpmnModel, flowNode);
-
-            if (highLightedActivities.contains(flowNode.getId())) {
-                drawHighLightRed(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
-            } else if (highLightedActivities.contains(Color.RED.toString() + flowNode.getId())) {
-                drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
-            }
-        }
-
-        // Outgoing transitions of activity
-        for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
-            boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId()));
-            String defaultFlow = null;
-            if (flowNode instanceof Activity) {
-                defaultFlow = ((Activity) flowNode).getDefaultFlow();
-            } else if (flowNode instanceof Gateway) {
-                defaultFlow = ((Gateway) flowNode).getDefaultFlow();
-            }
-
-            boolean isDefault = false;
-            if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) {
-                isDefault = true;
-            }
-            boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && sequenceFlow.getConditionExpression().trim().length() > 0 && !(flowNode instanceof Gateway);
-
-            String sourceRef = sequenceFlow.getSourceRef();
-            String targetRef = sequenceFlow.getTargetRef();
-            FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
-            FlowElement targetElement = bpmnModel.getFlowElement(targetRef);
-            List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
-            if (graphicInfoList != null && graphicInfoList.size() > 0) {
-                graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
-                int[] xPoints = new int[graphicInfoList.size()];
-                int[] yPoints = new int[graphicInfoList.size()];
-
-                for (int i = 1; i < graphicInfoList.size(); i++) {
-                    GraphicInfo graphicInfo = graphicInfoList.get(i);
-                    GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
-
-                    if (i == 1) {
-                        xPoints[0] = (int) previousGraphicInfo.getX();
-                        yPoints[0] = (int) previousGraphicInfo.getY();
-                    }
-                    xPoints[i] = (int) graphicInfo.getX();
-                    yPoints[i] = (int) graphicInfo.getY();
-
-                }
-
-                processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, scaleFactor);
-
-                // Draw sequenceflow label
-                GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
-                if (labelGraphicInfo != null) {
-                    processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
-                } else {
-                    if (drawSequenceFlowNameWithNoLabelDI) {
-                        GraphicInfo lineCenter = getLineCenter(graphicInfoList);
-                        processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false);
-                    }
-
-                }
-            }
-        }
-
-        // Nested elements
-        if (flowNode instanceof FlowElementsContainer) {
-            for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
-                if (nestedFlowElement instanceof FlowNode && !isPartOfCollapsedSubProcess(nestedFlowElement, bpmnModel)) {
-                    drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement,
-                        highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
-                }
-            }
-        }
-    }
-
-    /**
-     * This method makes coordinates of connection flow better.
-     *
-     * @param processDiagramCanvas
-     * @param bpmnModel
-     * @param sourceElement
-     * @param targetElement
-     * @param graphicInfoList
-     * @return
-     */
-    protected static List<GraphicInfo> connectionPerfectionizer(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, BaseElement sourceElement, BaseElement targetElement, List<GraphicInfo> graphicInfoList) {
-        GraphicInfo sourceGraphicInfo = bpmnModel.getGraphicInfo(sourceElement.getId());
-        GraphicInfo targetGraphicInfo = bpmnModel.getGraphicInfo(targetElement.getId());
-
-        CustomDefaultProcessDiagramCanvas.SHAPE_TYPE sourceShapeType = getShapeType(sourceElement);
-        CustomDefaultProcessDiagramCanvas.SHAPE_TYPE targetShapeType = getShapeType(targetElement);
-
-        return processDiagramCanvas.connectionPerfectionizer(sourceShapeType, targetShapeType, sourceGraphicInfo, targetGraphicInfo, graphicInfoList);
-    }
-
-    /**
-     * This method returns shape type of base element.<br>
-     * Each element can be presented as rectangle, rhombus, or ellipse.
-     *
-     * @param baseElement
-     * @return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE
-     */
-    protected static CustomDefaultProcessDiagramCanvas.SHAPE_TYPE getShapeType(BaseElement baseElement) {
-        if (baseElement instanceof Task || baseElement instanceof Activity || baseElement instanceof TextAnnotation) {
-            return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Rectangle;
-        } else if (baseElement instanceof Gateway) {
-            return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Rhombus;
-        } else if (baseElement instanceof Event) {
-            return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Ellipse;
-        } else {
-            // unknown source element, just do not correct coordinates
-        }
-        return null;
-    }
-
-    protected static GraphicInfo getLineCenter(List<GraphicInfo> graphicInfoList) {
-        GraphicInfo gi = new GraphicInfo();
-
-        int[] xPoints = new int[graphicInfoList.size()];
-        int[] yPoints = new int[graphicInfoList.size()];
-
-        double length = 0;
-        double[] lengths = new double[graphicInfoList.size()];
-        lengths[0] = 0;
-        double m;
-        for (int i = 1; i < graphicInfoList.size(); i++) {
-            GraphicInfo graphicInfo = graphicInfoList.get(i);
-            GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
-
-            if (i == 1) {
-                xPoints[0] = (int) previousGraphicInfo.getX();
-                yPoints[0] = (int) previousGraphicInfo.getY();
-            }
-            xPoints[i] = (int) graphicInfo.getX();
-            yPoints[i] = (int) graphicInfo.getY();
-
-            length += Math.sqrt(
-                Math.pow((int) graphicInfo.getX() - (int) previousGraphicInfo.getX(), 2) +
-                    Math.pow((int) graphicInfo.getY() - (int) previousGraphicInfo.getY(), 2));
-            lengths[i] = length;
-        }
-        m = length / 2;
-        int p1 = 0;
-        int p2 = 1;
-        for (int i = 1; i < lengths.length; i++) {
-            double len = lengths[i];
-            p1 = i - 1;
-            p2 = i;
-            if (len > m) {
-                break;
-            }
-        }
-
-        GraphicInfo graphicInfo1 = graphicInfoList.get(p1);
-        GraphicInfo graphicInfo2 = graphicInfoList.get(p2);
-
-        double AB = (int) graphicInfo2.getX() - (int) graphicInfo1.getX();
-        double OA = (int) graphicInfo2.getY() - (int) graphicInfo1.getY();
-        double OB = lengths[p2] - lengths[p1];
-        double ob = m - lengths[p1];
-        double ab = AB * ob / OB;
-        double oa = OA * ob / OB;
-
-        double mx = graphicInfo1.getX() + ab;
-        double my = graphicInfo1.getY() + oa;
-
-        gi.setX(mx);
-        gi.setY(my);
-        return gi;
-    }
-
-    protected void drawArtifact(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
-
-        ArtifactDrawInstruction drawInstruction = artifactDrawInstructions.get(artifact.getClass());
-        if (drawInstruction != null) {
-            drawInstruction.draw(processDiagramCanvas, bpmnModel, artifact);
-        }
-    }
-
-    private static void drawHighLight(CustomDefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
-        processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
-
-    }
-
-    private static void drawHighLightRed(CustomDefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
-        processDiagramCanvas.drawHighLightRed((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
-
-    }
-
-    protected static CustomDefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType,
-                                                                                String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
-
-        // We need to calculate maximum values to know how big the image will be in its entirety
-        double minX = Double.MAX_VALUE;
-        double maxX = 0;
-        double minY = Double.MAX_VALUE;
-        double maxY = 0;
-
-        for (Pool pool : bpmnModel.getPools()) {
-            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
-            minX = graphicInfo.getX();
-            maxX = graphicInfo.getX() + graphicInfo.getWidth();
-            minY = graphicInfo.getY();
-            maxY = graphicInfo.getY() + graphicInfo.getHeight();
-        }
-
-        List<FlowNode> flowNodes = gatherAllFlowNodes(bpmnModel);
-        for (FlowNode flowNode : flowNodes) {
-
-            GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
-
-            // width
-            if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) {
-                maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth();
-            }
-            if (flowNodeGraphicInfo.getX() < minX) {
-                minX = flowNodeGraphicInfo.getX();
-            }
-            // height
-            if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) {
-                maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight();
-            }
-            if (flowNodeGraphicInfo.getY() < minY) {
-                minY = flowNodeGraphicInfo.getY();
-            }
-
-            for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
-                List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
-                if (graphicInfoList != null) {
-                    for (GraphicInfo graphicInfo : graphicInfoList) {
-                        // width
-                        if (graphicInfo.getX() > maxX) {
-                            maxX = graphicInfo.getX();
-                        }
-                        if (graphicInfo.getX() < minX) {
-                            minX = graphicInfo.getX();
-                        }
-                        // height
-                        if (graphicInfo.getY() > maxY) {
-                            maxY = graphicInfo.getY();
-                        }
-                        if (graphicInfo.getY() < minY) {
-                            minY = graphicInfo.getY();
-                        }
-                    }
-                }
-            }
-        }
-
-        List<Artifact> artifacts = gatherAllArtifacts(bpmnModel);
-        for (Artifact artifact : artifacts) {
-
-            GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
-
-            if (artifactGraphicInfo != null) {
-                // width
-                if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) {
-                    maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth();
-                }
-                if (artifactGraphicInfo.getX() < minX) {
-                    minX = artifactGraphicInfo.getX();
-                }
-                // height
-                if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) {
-                    maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight();
-                }
-                if (artifactGraphicInfo.getY() < minY) {
-                    minY = artifactGraphicInfo.getY();
-                }
-            }
-
-            List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
-            if (graphicInfoList != null) {
-                for (GraphicInfo graphicInfo : graphicInfoList) {
-                    // width
-                    if (graphicInfo.getX() > maxX) {
-                        maxX = graphicInfo.getX();
-                    }
-                    if (graphicInfo.getX() < minX) {
-                        minX = graphicInfo.getX();
-                    }
-                    // height
-                    if (graphicInfo.getY() > maxY) {
-                        maxY = graphicInfo.getY();
-                    }
-                    if (graphicInfo.getY() < minY) {
-                        minY = graphicInfo.getY();
-                    }
-                }
-            }
-        }
-
-        int nrOfLanes = 0;
-        for (Process process : bpmnModel.getProcesses()) {
-            for (Lane l : process.getLanes()) {
-
-                nrOfLanes++;
-
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());
-                // // width
-                if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) {
-                    maxX = graphicInfo.getX() + graphicInfo.getWidth();
-                }
-                if (graphicInfo.getX() < minX) {
-                    minX = graphicInfo.getX();
-                }
-                // height
-                if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) {
-                    maxY = graphicInfo.getY() + graphicInfo.getHeight();
-                }
-                if (graphicInfo.getY() < minY) {
-                    minY = graphicInfo.getY();
-                }
-            }
-        }
-
-        // Special case, see https://activiti.atlassian.net/browse/ACT-1431
-        if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) {
-            // Nothing to show
-            minX = 0;
-            minY = 0;
-        }
-
-        return new CustomDefaultProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY,
-            imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
-    }
-
-    protected static List<Artifact> gatherAllArtifacts(BpmnModel bpmnModel) {
-        List<Artifact> artifacts = new ArrayList<>();
-        for (Process process : bpmnModel.getProcesses()) {
-            artifacts.addAll(process.getArtifacts());
-        }
-        return artifacts;
-    }
-
-    protected static List<FlowNode> gatherAllFlowNodes(BpmnModel bpmnModel) {
-        List<FlowNode> flowNodes = new ArrayList<>();
-        for (Process process : bpmnModel.getProcesses()) {
-            flowNodes.addAll(gatherAllFlowNodes(process));
-        }
-        return flowNodes;
-    }
-
-    protected static List<FlowNode> gatherAllFlowNodes(FlowElementsContainer flowElementsContainer) {
-        List<FlowNode> flowNodes = new ArrayList<>();
-        for (FlowElement flowElement : flowElementsContainer.getFlowElements()) {
-            if (flowElement instanceof FlowNode) {
-                flowNodes.add((FlowNode) flowElement);
-            }
-            if (flowElement instanceof FlowElementsContainer) {
-                flowNodes.addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement));
-            }
-        }
-        return flowNodes;
-    }
-
-    protected boolean isPartOfCollapsedSubProcess(FlowElement flowElement, BpmnModel model) {
-        SubProcess subProcess = flowElement.getSubProcess();
-        if (subProcess != null) {
-            GraphicInfo graphicInfo = model.getGraphicInfo(subProcess.getId());
-            if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
-                return true;
-            }
-
-            return isPartOfCollapsedSubProcess(subProcess, model);
-        }
-
-        return false;
-    }
-
-    public Map<Class<? extends BaseElement>, ActivityDrawInstruction> getActivityDrawInstructions() {
-        return activityDrawInstructions;
-    }
-
-    public void setActivityDrawInstructions(
-        Map<Class<? extends BaseElement>, ActivityDrawInstruction> activityDrawInstructions) {
-        this.activityDrawInstructions = activityDrawInstructions;
-    }
-
-    public Map<Class<? extends BaseElement>, ArtifactDrawInstruction> getArtifactDrawInstructions() {
-        return artifactDrawInstructions;
-    }
-
-    public void setArtifactDrawInstructions(
-        Map<Class<? extends BaseElement>, ArtifactDrawInstruction> artifactDrawInstructions) {
-        this.artifactDrawInstructions = artifactDrawInstructions;
-    }
-
-    protected interface ActivityDrawInstruction {
-        void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode);
-    }
-
-    protected interface ArtifactDrawInstruction {
-        void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact);
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java
deleted file mode 100644
index 3cdfcf4..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.dromara.workflow.flowable.cmd;
-
-import cn.hutool.core.collection.CollUtil;
-import org.flowable.common.engine.impl.interceptor.Command;
-import org.flowable.common.engine.impl.interceptor.CommandContext;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
-import org.flowable.engine.impl.util.CommandContextUtil;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES;
-
-/**
- * 涓茶鍔犵
- *
- * @author may
- */
-public class AddSequenceMultiInstanceCmd implements Command<Void> {
-
-    /**
-     * 鎵цid
-     */
-    private final String executionId;
-
-    /**
-     * 浼氱浜哄憳闆嗗悎KEY
-     */
-    private final String assigneeList;
-
-    /**
-     * 鍔犵浜哄憳
-     */
-    private final List<Long> assignees;
-
-    public AddSequenceMultiInstanceCmd(String executionId, String assigneeList, List<Long> assignees) {
-        this.executionId = executionId;
-        this.assigneeList = assigneeList;
-        this.assignees = assignees;
-    }
-
-    @Override
-    public Void execute(CommandContext commandContext) {
-        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
-        ExecutionEntity entity = executionEntityManager.findById(executionId);
-        // 澶氬疄渚嬩换鍔℃�绘暟鍔� assignees.size()
-        if (entity.getVariable(NUMBER_OF_INSTANCES) instanceof Integer nrOfInstances) {
-            entity.setVariable(NUMBER_OF_INSTANCES, nrOfInstances + assignees.size());
-        }
-        // 璁剧疆娴佺▼鍙橀噺
-        if (entity.getVariable(assigneeList) instanceof List<?> userIds) {
-            CollUtil.addAll(userIds, assignees);
-            Map<String, Object> variables = new HashMap<>(16);
-            variables.put(assigneeList, userIds);
-            entity.setVariables(variables);
-        }
-        return null;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java
deleted file mode 100644
index 20a0a5f..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.dromara.workflow.flowable.cmd;
-
-import cn.hutool.core.collection.CollUtil;
-import org.dromara.common.core.domain.dto.OssDTO;
-import org.dromara.common.core.service.OssService;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.satoken.utils.LoginHelper;
-import org.flowable.common.engine.impl.interceptor.Command;
-import org.flowable.common.engine.impl.interceptor.CommandContext;
-import org.flowable.engine.impl.persistence.entity.AttachmentEntity;
-import org.flowable.engine.impl.persistence.entity.AttachmentEntityManager;
-import org.flowable.engine.impl.util.CommandContextUtil;
-
-import java.util.Date;
-import java.util.List;
-
-/**
- * 闄勪欢涓婁紶
- *
- * @author may
- */
-public class AttachmentCmd implements Command<Boolean> {
-
-    private final String fileId;
-
-    private final String taskId;
-
-    private final String processInstanceId;
-
-    private final OssService ossService;
-
-    public AttachmentCmd(String fileId, String taskId, String processInstanceId, OssService ossService) {
-        this.fileId = fileId;
-        this.taskId = taskId;
-        this.processInstanceId = processInstanceId;
-        this.ossService = ossService;
-    }
-
-    @Override
-    public Boolean execute(CommandContext commandContext) {
-        try {
-            if (StringUtils.isNotBlank(fileId)) {
-                List<OssDTO> ossList = ossService.selectByIds(fileId);
-                if (CollUtil.isNotEmpty(ossList)) {
-                    for (OssDTO oss : ossList) {
-                        AttachmentEntityManager attachmentEntityManager = CommandContextUtil.getAttachmentEntityManager();
-                        AttachmentEntity attachmentEntity = attachmentEntityManager.create();
-                        attachmentEntity.setRevision(1);
-                        attachmentEntity.setUserId(LoginHelper.getUserId().toString());
-                        attachmentEntity.setName(oss.getOriginalName());
-                        attachmentEntity.setDescription(oss.getOriginalName());
-                        attachmentEntity.setType(oss.getFileSuffix());
-                        attachmentEntity.setTaskId(taskId);
-                        attachmentEntity.setProcessInstanceId(processInstanceId);
-                        attachmentEntity.setContentId(oss.getOssId().toString());
-                        attachmentEntity.setTime(new Date());
-                        attachmentEntityManager.insert(attachmentEntity);
-                    }
-                }
-            }
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-        return true;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java
deleted file mode 100644
index 215d310..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.dromara.workflow.flowable.cmd;
-
-import org.flowable.common.engine.impl.interceptor.Command;
-import org.flowable.common.engine.impl.interceptor.CommandContext;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
-import org.flowable.engine.impl.util.CommandContextUtil;
-
-import java.io.Serializable;
-
-/**
- * 鍒犻櫎鎵ц鏁版嵁
- *
- * @author may
- */
-public class DeleteExecutionCmd implements Command<Void>, Serializable {
-
-    /**
-     * 鎵цid
-     */
-    private final String executionId;
-
-    public DeleteExecutionCmd(String executionId) {
-        this.executionId = executionId;
-    }
-
-    @Override
-    public Void execute(CommandContext commandContext) {
-        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
-        ExecutionEntity entity = executionEntityManager.findById(executionId);
-        if (entity != null) {
-            executionEntityManager.deleteExecutionAndRelatedData(entity, "", false, false);
-        }
-        return null;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java
deleted file mode 100644
index a61daeb..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package org.dromara.workflow.flowable.cmd;
-
-import cn.hutool.core.util.ObjectUtil;
-import lombok.AllArgsConstructor;
-import org.dromara.common.core.utils.StreamUtils;
-import org.flowable.common.engine.impl.interceptor.Command;
-import org.flowable.common.engine.impl.interceptor.CommandContext;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
-import org.flowable.engine.impl.util.CommandContextUtil;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.dromara.workflow.common.constant.FlowConstant.LOOP_COUNTER;
-import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES;
-
-
-/**
- * 涓茶鍑忕
- *
- * @author may
- */
-@AllArgsConstructor
-public class DeleteSequenceMultiInstanceCmd implements Command<Void> {
-
-    /**
-     * 褰撳墠鑺傜偣瀹℃壒浜哄憳id
-     */
-    private final String currentUserId;
-
-    /**
-     * 鎵цid
-     */
-    private final String executionId;
-
-    /**
-     * 浼氱浜哄憳闆嗗悎KEY
-     */
-    private final String assigneeList;
-
-    /**
-     * 鍑忕浜哄憳
-     */
-    private final List<Long> assignees;
-
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public Void execute(CommandContext commandContext) {
-        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
-        ExecutionEntity entity = executionEntityManager.findById(executionId);
-        // 璁剧疆娴佺▼鍙橀噺
-        List<Long> userIds = new ArrayList<>();
-        List<Object> variable = (List<Object>) entity.getVariable(assigneeList);
-        for (Object o : variable) {
-            userIds.add(Long.valueOf(o.toString()));
-        }
-        List<Long> userIdList = new ArrayList<>();
-        userIds.forEach(e -> {
-            Long userId = StreamUtils.findFirst(assignees, id -> ObjectUtil.equals(id, e));
-            if (userId == null) {
-                userIdList.add(e);
-            }
-        });
-        // 褰撳墠浠诲姟鎵ц浣嶇疆
-        int loopCounterIndex = -1;
-        for (int i = 0; i < userIdList.size(); i++) {
-            Long userId = userIdList.get(i);
-            if (currentUserId.equals(userId.toString())) {
-                loopCounterIndex = i;
-            }
-        }
-        Map<String, Object> variables = new HashMap<>(16);
-        variables.put(NUMBER_OF_INSTANCES, userIdList.size());
-        variables.put(assigneeList, userIdList);
-        variables.put(LOOP_COUNTER, loopCounterIndex);
-        entity.setVariables(variables);
-        return null;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java
deleted file mode 100644
index 1f3088b..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.dromara.workflow.flowable.cmd;
-
-import org.dromara.common.core.utils.StreamUtils;
-import org.flowable.common.engine.impl.interceptor.Command;
-import org.flowable.common.engine.impl.interceptor.CommandContext;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
-import org.flowable.engine.impl.util.CommandContextUtil;
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * 鑾峰彇骞惰缃戝叧鎵ц鍚庝繚鐣欑殑鎵ц瀹炰緥鏁版嵁
- *
- * @author may
- */
-public class ExecutionChildByExecutionIdCmd implements Command<List<ExecutionEntity>>, Serializable {
-
-    /**
-     * 褰撳墠浠诲姟鎵ц瀹炰緥id
-     */
-    private final String executionId;
-
-    public ExecutionChildByExecutionIdCmd(String executionId) {
-        this.executionId = executionId;
-    }
-
-    @Override
-    public List<ExecutionEntity> execute(CommandContext commandContext) {
-        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
-        // 鑾峰彇褰撳墠鎵ц鏁版嵁
-        ExecutionEntity executionEntity = executionEntityManager.findById(executionId);
-        // 閫氳繃褰撳墠鎵ц鏁版嵁鐨勭埗鎵ц锛屾煡璇㈡墍鏈夊瓙鎵ц鏁版嵁
-        List<ExecutionEntity> allChildrenExecution =
-            executionEntityManager.collectChildren(executionEntity.getParent());
-        return StreamUtils.filter(allChildrenExecution, e -> !e.isActive());
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java
deleted file mode 100644
index 3ba120a..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.dromara.workflow.flowable.cmd;
-
-import org.dromara.common.core.exception.ServiceException;
-import org.flowable.common.engine.impl.interceptor.Command;
-import org.flowable.common.engine.impl.interceptor.CommandContext;
-import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
-import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityManager;
-import org.flowable.engine.impl.util.CommandContextUtil;
-
-/**
- * 淇敼娴佺▼鐘舵��
- *
- * @author may
- */
-public class UpdateBusinessStatusCmd implements Command<Boolean> {
-
-    private final String processInstanceId;
-    private final String status;
-
-    public UpdateBusinessStatusCmd(String processInstanceId, String status) {
-        this.processInstanceId = processInstanceId;
-        this.status = status;
-    }
-
-    @Override
-    public Boolean execute(CommandContext commandContext) {
-        try {
-            HistoricProcessInstanceEntityManager manager = CommandContextUtil.getHistoricProcessInstanceEntityManager();
-            HistoricProcessInstanceEntity processInstance = manager.findById(processInstanceId);
-            processInstance.setBusinessStatus(status);
-            manager.update(processInstance);
-            return true;
-        } catch (Exception e) {
-            throw new ServiceException(e.getMessage());
-        }
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java
deleted file mode 100644
index 42f6d1c..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.dromara.workflow.flowable.cmd;
-
-import org.dromara.common.core.exception.ServiceException;
-import org.flowable.common.engine.impl.interceptor.Command;
-import org.flowable.common.engine.impl.interceptor.CommandContext;
-import org.flowable.engine.impl.util.CommandContextUtil;
-import org.flowable.task.service.HistoricTaskService;
-import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
-
-import java.util.Date;
-import java.util.List;
-
-
-/**
- * 淇敼娴佺▼鍘嗗彶
- *
- * @author may
- */
-public class UpdateHiTaskInstCmd implements Command<Boolean> {
-
-    private final List<String> taskIds;
-
-    private final String processDefinitionId;
-
-    private final String processInstanceId;
-
-    public UpdateHiTaskInstCmd(List<String> taskIds, String processDefinitionId, String processInstanceId) {
-        this.taskIds = taskIds;
-        this.processDefinitionId = processDefinitionId;
-        this.processInstanceId = processInstanceId;
-    }
-
-    @Override
-    public Boolean execute(CommandContext commandContext) {
-        try {
-            HistoricTaskService historicTaskService = CommandContextUtil.getHistoricTaskService();
-            for (String taskId : taskIds) {
-                HistoricTaskInstanceEntity historicTask = historicTaskService.getHistoricTask(taskId);
-                if (historicTask != null) {
-                    historicTask.setProcessDefinitionId(processDefinitionId);
-                    historicTask.setProcessInstanceId(processInstanceId);
-                    historicTask.setCreateTime(new Date());
-                    CommandContextUtil.getHistoricTaskService().updateHistoricTask(historicTask, true);
-                }
-            }
-            return true;
-        } catch (Exception e) {
-            throw new ServiceException(e.getMessage());
-        }
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java
deleted file mode 100644
index 1494bf3..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.dromara.workflow.flowable.config;
-
-import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
-import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler;
-import org.flowable.spring.SpringProcessEngineConfiguration;
-import org.flowable.spring.boot.EngineConfigurationConfigurer;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Configuration;
-
-import java.util.Collections;
-
-
-/**
- * flowable閰嶇疆
- *
- * @author may
- */
-@Configuration
-public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
-
-    @Autowired
-    private GlobalFlowableListener globalFlowableListener;
-    @Autowired
-    private IdentifierGenerator identifierGenerator;
-
-    @Override
-    public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
-        processEngineConfiguration.setIdGenerator(() -> identifierGenerator.nextId(null).toString());
-        processEngineConfiguration.setEventListeners(Collections.singletonList(globalFlowableListener));
-        processEngineConfiguration.addCustomJobHandler(new TaskTimeoutJobHandler());
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java
deleted file mode 100644
index 9bb971a..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package org.dromara.workflow.flowable.config;
-
-import cn.hutool.core.collection.CollUtil;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.workflow.common.enums.TaskStatusEnum;
-import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler;
-import org.dromara.workflow.utils.QueryUtils;
-import org.flowable.bpmn.model.BoundaryEvent;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.bpmn.model.FlowElement;
-import org.flowable.common.engine.api.delegate.event.*;
-import org.flowable.common.engine.impl.cfg.TransactionState;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.impl.util.CommandContextUtil;
-import org.flowable.engine.runtime.Execution;
-import org.flowable.engine.task.Comment;
-import org.flowable.job.service.TimerJobService;
-import org.flowable.job.service.impl.persistence.entity.JobEntity;
-import org.flowable.job.service.impl.persistence.entity.TimerJobEntity;
-import org.flowable.task.api.Task;
-import org.flowable.task.service.impl.persistence.entity.TaskEntity;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.stereotype.Component;
-
-import java.util.Date;
-import java.util.List;
-
-
-/**
- * 寮曟搸璋冨害鐩戝惉
- *
- * @author may
- */
-@Component
-public class GlobalFlowableListener implements FlowableEventListener {
-
-    @Autowired
-    @Lazy
-    private TaskService taskService;
-
-    @Autowired
-    @Lazy
-    private RuntimeService runtimeService;
-
-    @Autowired
-    @Lazy
-    private RepositoryService repositoryService;
-
-    @Value("${flowable.async-executor-activate}")
-    private boolean asyncExecutorActivate;
-
-    @Override
-    public void onEvent(FlowableEvent flowableEvent) {
-        if (flowableEvent instanceof FlowableEngineEvent flowableEngineEvent) {
-            FlowableEngineEventType engineEventType = (FlowableEngineEventType) flowableEvent.getType();
-            switch (engineEventType) {
-                case JOB_EXECUTION_SUCCESS -> jobExecutionSuccess((FlowableEngineEntityEvent) flowableEngineEvent);
-                case TASK_DUEDATE_CHANGED, TASK_CREATED -> {
-                    FlowableEntityEvent flowableEntityEvent = (FlowableEntityEvent) flowableEngineEvent;
-                    Object entityObject = flowableEntityEvent.getEntity();
-                    TaskEntity task = (TaskEntity) entityObject;
-                    if (asyncExecutorActivate && task.getDueDate() != null && task.getDueDate().after(new Date())) {
-                        //鍒犻櫎涔嬪墠宸茬粡瀛樺湪鐨勫畾鏃朵换鍔�
-                        TimerJobService timerJobService = CommandContextUtil.getTimerJobService();
-                        List<TimerJobEntity> timerJobEntityList = timerJobService.findTimerJobsByProcessInstanceId(task.getProcessInstanceId());
-                        if (!CollUtil.isEmpty(timerJobEntityList)) {
-                            for (TimerJobEntity timerJobEntity : timerJobEntityList) {
-                                String taskId = timerJobEntity.getJobHandlerConfiguration();
-                                if (task.getId().equals(taskId)) {
-                                    timerJobService.deleteTimerJob(timerJobEntity);
-                                }
-                            }
-                        }
-                        //鍒涘缓job瀵硅薄
-                        TimerJobEntity timer = timerJobService.createTimerJob();
-                        timer.setTenantId(TenantHelper.getTenantId());
-                        //璁剧疆job绫诲瀷
-                        timer.setJobType(JobEntity.JOB_TYPE_TIMER);
-                        timer.setJobHandlerType(TaskTimeoutJobHandler.TYPE);
-                        timer.setDuedate(task.getDueDate());
-                        timer.setProcessInstanceId(task.getProcessInstanceId());
-                        //璁剧疆浠诲姟id
-                        timer.setJobHandlerConfiguration(task.getId());
-                        //淇濆瓨骞惰Е鍙戜簨浠�
-                        timerJobService.scheduleTimerJob(timer);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public boolean isFailOnException() {
-        return true;
-    }
-
-    @Override
-    public boolean isFireOnTransactionLifecycleEvent() {
-        return false;
-    }
-
-    @Override
-    public String getOnTransaction() {
-        return TransactionState.COMMITTED.name();
-    }
-
-    /**
-     * 澶勭悊杈圭晫瀹氭椂浜嬩欢鑷姩瀹℃壒璁板綍
-     *
-     * @param event 浜嬩欢
-     */
-    protected void jobExecutionSuccess(FlowableEngineEntityEvent event) {
-        if (event != null && StringUtils.isNotBlank(event.getExecutionId())) {
-            Execution execution = runtimeService.createExecutionQuery().executionId(event.getExecutionId()).singleResult();
-            if (execution != null) {
-                BpmnModel bpmnModel = repositoryService.getBpmnModel(event.getProcessDefinitionId());
-                FlowElement flowElement = bpmnModel.getFlowElement(execution.getActivityId());
-                if (flowElement instanceof BoundaryEvent) {
-                    String attachedToRefId = ((BoundaryEvent) flowElement).getAttachedToRefId();
-                    List<Execution> list = runtimeService.createExecutionQuery().activityId(attachedToRefId).list();
-                    for (Execution ex : list) {
-                        Task task = QueryUtils.taskQuery().executionId(ex.getId()).singleResult();
-                        if (task != null) {
-                            List<Comment> taskComments = taskService.getTaskComments(task.getId());
-                            if (CollUtil.isEmpty(taskComments)) {
-                                taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), "瓒呮椂鑷姩瀹℃壒!");
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java
deleted file mode 100644
index 69ae70a..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.dromara.workflow.flowable.handler;
-
-import org.dromara.common.core.domain.event.ProcessEvent;
-import org.dromara.common.core.domain.event.ProcessTaskEvent;
-import org.dromara.common.core.utils.SpringUtils;
-import org.springframework.stereotype.Component;
-
-/**
- * 娴佺▼鐩戝惉鏈嶅姟
- *
- * @author may
- * @date 2024-06-02
- */
-@Component
-public class FlowProcessEventHandler {
-
-    /**
-     * 鎬讳綋娴佺▼鐩戝惉(渚嬪: 鎻愪氦 閫�鍥� 鎾ら攢 缁堟 浣滃簾绛�)
-     *
-     * @param key         娴佺▼key
-     * @param businessKey 涓氬姟id
-     * @param status      鐘舵��
-     * @param submit      褰撲负true鏃朵负鐢宠浜鸿妭鐐瑰姙鐞�
-     */
-    public void processHandler(String key, String businessKey, String status, boolean submit) {
-        ProcessEvent processEvent = new ProcessEvent();
-        processEvent.setKey(key);
-        processEvent.setBusinessKey(businessKey);
-        processEvent.setStatus(status);
-        processEvent.setSubmit(submit);
-        SpringUtils.context().publishEvent(processEvent);
-    }
-
-    /**
-     * 鎵ц鍔炵悊浠诲姟鐩戝惉
-     *
-     * @param key               娴佺▼key
-     * @param taskDefinitionKey 瀹℃壒鑺傜偣key
-     * @param taskId            浠诲姟id
-     * @param businessKey       涓氬姟id
-     */
-    public void processTaskHandler(String key, String taskDefinitionKey, String taskId, String businessKey) {
-        ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
-        processTaskEvent.setKey(key);
-        processTaskEvent.setTaskDefinitionKey(taskDefinitionKey);
-        processTaskEvent.setTaskId(taskId);
-        processTaskEvent.setBusinessKey(businessKey);
-        SpringUtils.context().publishEvent(processTaskEvent);
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java
deleted file mode 100644
index 61c9388..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.dromara.workflow.flowable.handler;
-
-import org.dromara.workflow.common.enums.TaskStatusEnum;
-import org.flowable.common.engine.impl.interceptor.CommandContext;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.impl.jobexecutor.TimerEventHandler;
-import org.flowable.engine.impl.util.CommandContextUtil;
-import org.flowable.job.service.JobHandler;
-import org.flowable.job.service.impl.persistence.entity.JobEntity;
-import org.flowable.task.api.Task;
-import org.flowable.variable.api.delegate.VariableScope;
-
-/**
- * 鍔炵悊瓒呮椂(杩囨湡)浠诲姟
- *
- * @author may
- */
-public class TaskTimeoutJobHandler extends TimerEventHandler implements JobHandler {
-
-    public static final String TYPE = "taskTimeout";
-
-    @Override
-    public String getType() {
-        return TYPE;
-    }
-
-    @Override
-    public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
-        TaskService taskService = CommandContextUtil.getProcessEngineConfiguration(commandContext)
-            .getTaskService();
-        Task task = taskService.createTaskQuery().taskId(configuration).singleResult();
-        if (task != null) {
-            taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TIMEOUT.getStatus(), "瓒呮椂鑷姩瀹℃壒!");
-            taskService.complete(configuration);
-        }
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java
new file mode 100644
index 0000000..4b215ef
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java
@@ -0,0 +1,82 @@
+package org.dromara.workflow.handler;
+
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.event.ProcessDeleteEvent;
+import org.dromara.common.core.domain.event.ProcessEvent;
+import org.dromara.common.core.domain.event.ProcessTaskEvent;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 娴佺▼鐩戝惉鏈嶅姟
+ *
+ * @author may
+ * @date 2024-06-02
+ */
+@ConditionalOnEnable
+@Slf4j
+@Component
+public class FlowProcessEventHandler {
+
+    /**
+     * 鎬讳綋娴佺▼鐩戝惉(渚嬪: 鑽夌锛屾挙閿�锛岄��鍥烇紝浣滃簾锛岀粓姝紝宸插畬鎴愮瓑)
+     *
+     * @param flowCode   娴佺▼瀹氫箟缂栫爜
+     * @param businessId 涓氬姟id
+     * @param status     鐘舵��
+     * @param submit     褰撲负true鏃朵负鐢宠浜鸿妭鐐瑰姙鐞�
+     */
+    public void processHandler(String flowCode, String businessId, String status, Map<String, Object> params, boolean submit) {
+        String tenantId = TenantHelper.getTenantId();
+        log.info("鍙戝竷娴佺▼浜嬩欢锛岀鎴稩D: {}, 娴佺▼鐘舵��: {}, 娴佺▼缂栫爜: {}, 涓氬姟ID: {}, 鏄惁鐢宠浜鸿妭鐐瑰姙鐞�: {}", tenantId, status, flowCode, businessId, submit);
+        ProcessEvent processEvent = new ProcessEvent();
+        processEvent.setTenantId(tenantId);
+        processEvent.setFlowCode(flowCode);
+        processEvent.setBusinessId(businessId);
+        processEvent.setStatus(status);
+        processEvent.setParams(params);
+        processEvent.setSubmit(submit);
+        SpringUtils.context().publishEvent(processEvent);
+    }
+
+    /**
+     * 鎵ц鍔炵悊浠诲姟鐩戝惉
+     *
+     * @param flowCode   娴佺▼瀹氫箟缂栫爜
+     * @param nodeCode   瀹℃壒鑺傜偣缂栫爜
+     * @param taskId     浠诲姟id
+     * @param businessId 涓氬姟id
+     */
+    public void processTaskHandler(String flowCode, String nodeCode, Long taskId, String businessId) {
+        String tenantId = TenantHelper.getTenantId();
+        log.info("鍙戝竷娴佺▼浠诲姟浜嬩欢, 绉熸埛ID: {}, 娴佺▼缂栫爜: {}, 鑺傜偣缂栫爜: {}, 浠诲姟ID: {}, 涓氬姟ID: {}", tenantId, flowCode, nodeCode, taskId, businessId);
+        ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
+        processTaskEvent.setTenantId(tenantId);
+        processTaskEvent.setFlowCode(flowCode);
+        processTaskEvent.setNodeCode(nodeCode);
+        processTaskEvent.setTaskId(taskId);
+        processTaskEvent.setBusinessId(businessId);
+        SpringUtils.context().publishEvent(processTaskEvent);
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼鐩戝惉
+     *
+     * @param flowCode    娴佺▼瀹氫箟缂栫爜
+     * @param businessId  涓氬姟ID
+     */
+    public void processDeleteHandler(String flowCode, String businessId) {
+        String tenantId = TenantHelper.getTenantId();
+        log.info("鍙戝竷鍒犻櫎娴佺▼浜嬩欢, 绉熸埛ID: {}, 娴佺▼缂栫爜: {}, 涓氬姟ID: {}", tenantId, flowCode, businessId);
+        ProcessDeleteEvent processDeleteEvent = new ProcessDeleteEvent();
+        processDeleteEvent.setTenantId(tenantId);
+        processDeleteEvent.setFlowCode(flowCode);
+        processDeleteEvent.setBusinessId(businessId);
+        SpringUtils.context().publishEvent(processDeleteEvent);
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java
new file mode 100644
index 0000000..c18e4ed
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java
@@ -0,0 +1,73 @@
+package org.dromara.workflow.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.common.enums.TaskAssigneeEnum;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.warm.flow.core.dto.FlowParams;
+import org.dromara.warm.flow.core.handler.PermissionHandler;
+import org.dromara.warm.flow.core.service.impl.TaskServiceImpl;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * 鍔炵悊浜烘潈闄愬鐞嗗櫒
+ *
+ * @author AprilWind
+ */
+@ConditionalOnEnable
+@RequiredArgsConstructor
+@Component
+@Slf4j
+public class WorkflowPermissionHandler implements PermissionHandler {
+
+    /**
+     * 瀹℃壒鍓嶈幏鍙栧綋鍓嶅姙鐞嗕汉锛屽姙鐞嗘椂浼氭牎楠岀殑璇ユ潈闄愰泦鍚�
+     * 鍚庣画鍦▄@link TaskServiceImpl#checkAuth(Task, FlowParams)} 涓皟鐢�
+     * 杩斿洖褰撳墠鐢ㄦ埛鏉冮檺闆嗗悎
+     */
+    @Override
+    public List<String> permissions() {
+        LoginUser loginUser = LoginHelper.getLoginUser();
+        if (ObjectUtil.isNull(loginUser)) {
+            return new ArrayList<>();
+        }
+        // 浣跨敤涓�涓祦鏉ユ瀯寤烘潈闄愬垪琛�
+        return Stream.of(
+                // 瑙掕壊鏉冮檺鍓嶇紑
+                loginUser.getRoles().stream()
+                    .map(role -> TaskAssigneeEnum.ROLE.getCode() + role.getRoleId()),
+
+                // 宀椾綅鏉冮檺鍓嶇紑
+                Stream.ofNullable(loginUser.getPosts())
+                    .flatMap(Collection::stream)
+                    .map(post -> TaskAssigneeEnum.POST.getCode() + post.getPostId()),
+
+                // 鐢ㄦ埛鍜岄儴闂ㄦ潈闄�
+                Stream.of(String.valueOf(loginUser.getUserId()),
+                    TaskAssigneeEnum.DEPT.getCode() + loginUser.getDeptId()
+                )
+            )
+            .flatMap(stream -> stream)
+            .collect(Collectors.toList());
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鍔炵悊浜�
+     *
+     * @return 褰撳墠鍔炵悊浜�
+     */
+    @Override
+    public String getHandler() {
+        return LoginHelper.getUserIdStr();
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java
new file mode 100644
index 0000000..b187854
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java
@@ -0,0 +1,130 @@
+package org.dromara.workflow.listener;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.enums.BusinessStatusEnum;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.warm.flow.core.dto.FlowParams;
+import org.dromara.warm.flow.core.entity.Definition;
+import org.dromara.warm.flow.core.entity.Instance;
+import org.dromara.warm.flow.core.entity.Task;
+import org.dromara.warm.flow.core.listener.GlobalListener;
+import org.dromara.warm.flow.core.listener.ListenerVariable;
+import org.dromara.warm.flow.orm.entity.FlowTask;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.handler.FlowProcessEventHandler;
+import org.dromara.workflow.service.IFlwInstanceService;
+import org.dromara.workflow.service.IFlwTaskService;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鍏ㄥ眬浠诲姟鍔炵悊鐩戝惉
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class WorkflowGlobalListener implements GlobalListener {
+
+    private final IFlwTaskService taskService;
+    private final IFlwInstanceService instanceService;
+    private final FlowProcessEventHandler flowProcessEventHandler;
+
+    /**
+     * 鍒涘缓鐩戝惉鍣紝浠诲姟鍒涘缓鏃舵墽琛�
+     *
+     * @param listenerVariable 鐩戝惉鍣ㄥ彉閲�
+     */
+    @Override
+    public void create(ListenerVariable listenerVariable) {
+        Instance instance = listenerVariable.getInstance();
+        Definition definition = listenerVariable.getDefinition();
+        String businessId = instance.getBusinessId();
+        String flowStatus = instance.getFlowStatus();
+        Task task = listenerVariable.getTask();
+        if (task != null && BusinessStatusEnum.WAITING.getStatus().equals(flowStatus)) {
+            // 鍒ゆ柇娴佺▼鐘舵�侊紙鍙戝竷瀹℃壒涓簨浠讹級
+            flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), task.getNodeCode(), task.getId(), businessId);
+        }
+    }
+
+    /**
+     * 寮�濮嬬洃鍚櫒锛屼换鍔″紑濮嬪姙鐞嗘椂鎵ц
+     *
+     * @param listenerVariable 鐩戝惉鍣ㄥ彉閲�
+     */
+    @Override
+    public void start(ListenerVariable listenerVariable) {
+    }
+
+    /**
+     * 鍒嗘淳鐩戝惉鍣紝鍔ㄦ�佷慨鏀逛唬鍔炰换鍔′俊鎭�
+     *
+     * @param listenerVariable 鐩戝惉鍣ㄥ彉閲�
+     */
+    @Override
+    public void assignment(ListenerVariable listenerVariable) {
+    }
+
+    /**
+     * 瀹屾垚鐩戝惉鍣紝褰撳墠浠诲姟瀹屾垚鍚庢墽琛�
+     *
+     * @param listenerVariable 鐩戝惉鍣ㄥ彉閲�
+     */
+    @Override
+    public void finish(ListenerVariable listenerVariable) {
+        Instance instance = listenerVariable.getInstance();
+        Definition definition = listenerVariable.getDefinition();
+        String businessId = instance.getBusinessId();
+        String flowStatus = instance.getFlowStatus();
+        Map<String, Object> params = new HashMap<>();
+        FlowParams flowParams = listenerVariable.getFlowParams();
+        if (ObjectUtil.isNotNull(flowParams)) {
+            // 鍘嗗彶浠诲姟鎵╁睍(閫氬父涓洪檮浠�)
+            params.put("hisTaskExt", flowParams.getHisTaskExt());
+            // 鍔炵悊浜�
+            params.put("handler", flowParams.getHandler());
+            // 鍔炵悊鎰忚
+            params.put("message", flowParams.getMessage());
+        }
+        // 鍒ゆ柇娴佺▼鐘舵�侊紙鍙戝竷锛氭挙閿�锛岄��鍥烇紝浣滃簾锛岀粓姝紝宸插畬鎴愪簨浠讹級
+        String status = determineFlowStatus(instance, flowStatus);
+        if (StringUtils.isNotBlank(status)) {
+            flowProcessEventHandler.processHandler(definition.getFlowCode(), businessId, status, params, false);
+        }
+    }
+
+    /**
+     * 鏍规嵁娴佺▼瀹炰緥鍜屽綋鍓嶆祦绋嬬姸鎬佺‘瀹氭渶缁堢姸鎬�
+     *
+     * @param instance   娴佺▼瀹炰緥
+     * @param flowStatus 娴佺▼瀹炰緥褰撳墠鐘舵��
+     * @return 娴佺▼鏈�缁堢姸鎬�
+     */
+    private String determineFlowStatus(Instance instance, String flowStatus) {
+        if (StringUtils.isNotBlank(flowStatus) && BusinessStatusEnum.initialState(flowStatus)) {
+            log.info("娴佺▼瀹炰緥褰撳墠鐘舵��: {}", flowStatus);
+            return flowStatus;
+        } else {
+            Long instanceId = instance.getId();
+            List<FlowTask> flowTasks = taskService.selectByInstId(instanceId);
+            if (CollUtil.isEmpty(flowTasks)) {
+                String status = BusinessStatusEnum.FINISH.getStatus();
+                // 鏇存柊娴佺▼鐘舵�佷负宸插畬鎴�
+                instanceService.updateStatus(instanceId, status);
+                log.info("娴佺▼宸茬粨鏉燂紝鐘舵�佹洿鏂颁负: {}", status);
+                return status;
+            }
+            return null;
+        }
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java
deleted file mode 100644
index a3a41c9..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.dromara.workflow.mapper;
-
-import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-import org.dromara.workflow.domain.ActHiProcinst;
-
-/**
- * 娴佺▼瀹炰緥Mapper鎺ュ彛
- *
- * @author may
- * @date 2023-07-22
- */
-@InterceptorIgnore(tenantLine = "true")
-public interface ActHiProcinstMapper extends BaseMapperPlus<ActHiProcinst, ActHiProcinst> {
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java
deleted file mode 100644
index 63b394b..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.dromara.workflow.mapper;
-
-import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
-import org.dromara.workflow.domain.ActHiTaskinst;
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-
-/**
- * 娴佺▼鍘嗗彶浠诲姟Mapper鎺ュ彛
- *
- * @author may
- * @date 2024-03-02
- */
-@InterceptorIgnore(tenantLine = "true")
-public interface ActHiTaskinstMapper extends BaseMapperPlus<ActHiTaskinst, ActHiTaskinst> {
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java
deleted file mode 100644
index 63c5ecb..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.dromara.workflow.mapper;
-
-import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
-import com.baomidou.mybatisplus.core.conditions.Wrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.Constants;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.apache.ibatis.annotations.Param;
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-import org.dromara.workflow.domain.vo.TaskVo;
-
-
-/**
- * 浠诲姟淇℃伅Mapper鎺ュ彛
- *
- * @author may
- * @date 2024-03-02
- */
-@InterceptorIgnore(tenantLine = "true")
-public interface ActTaskMapper extends BaseMapperPlus<TaskVo, TaskVo> {
-    /**
-     * 鑾峰彇寰呭姙淇℃伅
-     *
-     * @param page         鍒嗛〉
-     * @param queryWrapper 鏉′欢
-     * @return 缁撴灉
-     */
-    Page<TaskVo> getTaskWaitByPage(@Param("page") Page<TaskVo> page, @Param(Constants.WRAPPER) Wrapper<TaskVo> queryWrapper);
-
-    /**
-     * 鑾峰彇宸插姙
-     *
-     * @param page         鍒嗛〉
-     * @param queryWrapper 鏉′欢
-     * @return 缁撴灉
-     */
-    Page<TaskVo> getTaskFinishByPage(@Param("page") Page<TaskVo> page, @Param(Constants.WRAPPER) Wrapper<TaskVo> queryWrapper);
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
-     *
-     * @param page         鍒嗛〉
-     * @param queryWrapper 鏉′欢
-     * @return 缁撴灉
-     */
-    Page<TaskVo> getTaskCopyByPage(@Param("page") Page<TaskVo> page, @Param(Constants.WRAPPER) QueryWrapper<TaskVo> queryWrapper);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java
new file mode 100644
index 0000000..d2c0b3a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java
@@ -0,0 +1,60 @@
+package org.dromara.workflow.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.workflow.domain.FlowCategory;
+import org.dromara.workflow.domain.vo.FlowCategoryVo;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * 娴佺▼鍒嗙被Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2023-06-27
+ */
+public interface FlwCategoryMapper extends BaseMapperPlus<FlowCategory, FlowCategoryVo> {
+
+    /**
+     * 缁熻鎸囧畾娴佺▼鍒嗙被ID鐨勫垎绫绘暟閲�
+     *
+     * @param categoryId 娴佺▼鍒嗙被ID
+     * @return 璇ユ祦绋嬪垎绫籌D鐨勫垎绫绘暟閲�
+     */
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "createDept")
+    })
+    long countCategoryById(Long categoryId);
+
+    /**
+     * 鏍规嵁鐖舵祦绋嬪垎绫籌D鏌ヨ鍏舵墍鏈夊瓙娴佺▼鍒嗙被鐨勫垪琛�
+     *
+     * @param parentId 鐖舵祦绋嬪垎绫籌D
+     * @return 鍖呭惈瀛愭祦绋嬪垎绫荤殑鍒楄〃
+     */
+    default List<FlowCategory> selectListByParentId(Long parentId) {
+        return this.selectList(new LambdaQueryWrapper<FlowCategory>()
+            .select(FlowCategory::getCategoryId)
+            .apply(DataBaseHelper.findInSet(parentId, "ancestors")));
+    }
+
+    /**
+     * 鏍规嵁鐖舵祦绋嬪垎绫籌D鏌ヨ鍖呮嫭鐖禝D鍙婂叾鎵�鏈夊瓙娴佺▼鍒嗙被ID鐨勫垪琛�
+     *
+     * @param parentId 鐖舵祦绋嬪垎绫籌D
+     * @return 鍖呭惈鐖禝D鍜屽瓙娴佺▼鍒嗙被ID鐨勫垪琛�
+     */
+    default List<Long> selectCategoryIdsByParentId(Long parentId) {
+        return Stream.concat(
+            this.selectListByParentId(parentId).stream()
+                .map(FlowCategory::getCategoryId),
+            Stream.of(parentId)
+        ).collect(Collectors.toList());
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java
new file mode 100644
index 0000000..92809c8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java
@@ -0,0 +1,27 @@
+package org.dromara.workflow.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.workflow.domain.bo.FlowInstanceBo;
+import org.dromara.workflow.domain.vo.FlowInstanceVo;
+
+/**
+ * 瀹炰緥淇℃伅Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-02
+ */
+public interface FlwInstanceMapper {
+
+    /**
+     * 娴佺▼瀹炰緥淇℃伅
+     *
+     * @param page         鍒嗛〉
+     * @param queryWrapper 鏉′欢
+     * @return 缁撴灉
+     */
+    Page<FlowInstanceVo> selectInstanceList(@Param("page") Page<FlowInstanceVo> page, @Param(Constants.WRAPPER) Wrapper<FlowInstanceBo> queryWrapper);
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java
new file mode 100644
index 0000000..fd86c82
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java
@@ -0,0 +1,57 @@
+package org.dromara.workflow.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.workflow.domain.bo.FlowTaskBo;
+import org.dromara.workflow.domain.vo.FlowHisTaskVo;
+import org.dromara.workflow.domain.vo.FlowTaskVo;
+
+import java.util.List;
+
+
+/**
+ * 浠诲姟淇℃伅Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-02
+ */
+public interface FlwTaskMapper {
+
+    /**
+     * 鑾峰彇寰呭姙淇℃伅
+     *
+     * @param page         鍒嗛〉
+     * @param queryWrapper 鏉′欢
+     * @return 缁撴灉
+     */
+    Page<FlowTaskVo> getListRunTask(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
+
+    /**
+     * 鑾峰彇寰呭姙淇℃伅
+     *
+     * @param queryWrapper 鏉′欢
+     * @return 缁撴灉
+     */
+    List<FlowTaskVo> getListRunTask(@Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
+
+    /**
+     * 鑾峰彇宸插姙
+     *
+     * @param page         鍒嗛〉
+     * @param queryWrapper 鏉′欢
+     * @return 缁撴灉
+     */
+    Page<FlowHisTaskVo> getListFinishTask(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param page         鍒嗛〉
+     * @param queryWrapper 鏉′欢
+     * @return 缁撴灉
+     */
+    Page<FlowTaskVo> getTaskCopyByPage(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) QueryWrapper<FlowTaskBo> queryWrapper);
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java
deleted file mode 100644
index 98aea02..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.dromara.workflow.mapper;
-
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-import org.dromara.workflow.domain.WfCategory;
-import org.dromara.workflow.domain.vo.WfCategoryVo;
-
-/**
- * 娴佺▼鍒嗙被Mapper鎺ュ彛
- *
- * @author may
- * @date 2023-06-27
- */
-public interface WfCategoryMapper extends BaseMapperPlus<WfCategory, WfCategoryVo> {
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java
deleted file mode 100644
index ee20882..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.dromara.workflow.mapper;
-
-import org.dromara.workflow.domain.WfDefinitionConfig;
-import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-
-/**
- * 娴佺▼瀹氫箟閰嶇疆Mapper鎺ュ彛
- *
- * @author may
- * @date 2024-03-18
- */
-public interface WfDefinitionConfigMapper extends BaseMapperPlus<WfDefinitionConfig, WfDefinitionConfigVo> {
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java
deleted file mode 100644
index acf8111..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.dromara.workflow.mapper;
-
-import org.dromara.workflow.domain.WfFormManage;
-import org.dromara.workflow.domain.vo.WfFormManageVo;
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-
-/**
- * 琛ㄥ崟绠$悊Mapper鎺ュ彛
- *
- * @author may
- * @date 2024-03-29
- */
-public interface WfFormManageMapper extends BaseMapperPlus<WfFormManage, WfFormManageVo> {
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java
deleted file mode 100644
index d2aecac..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.dromara.workflow.mapper;
-
-import org.dromara.workflow.domain.WfNodeConfig;
-import org.dromara.workflow.domain.vo.WfNodeConfigVo;
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-
-/**
- * 鑺傜偣閰嶇疆Mapper鎺ュ彛
- *
- * @author may
- * @date 2024-03-30
- */
-public interface WfNodeConfigMapper extends BaseMapperPlus<WfNodeConfig, WfNodeConfigVo> {
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java
deleted file mode 100644
index 9b291fe..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.dromara.workflow.mapper;
-
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-import org.dromara.workflow.domain.WfTaskBackNode;
-
-/**
- * 鑺傜偣椹冲洖璁板綍Mapper鎺ュ彛
- *
- * @author may
- * @date 2024-03-13
- */
-public interface WfTaskBackNodeMapper extends BaseMapperPlus<WfTaskBackNode, WfTaskBackNode> {
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java
deleted file mode 100644
index e802c69..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.dromara.workflow.service;
-
-
-import org.dromara.workflow.domain.ActHiProcinst;
-
-import java.util.List;
-
-/**
- * 娴佺▼瀹炰緥Service鎺ュ彛
- *
- * @author may
- * @date 2023-07-22
- */
-public interface IActHiProcinstService {
-
-    /**
-     * 鎸夌収涓氬姟id鏌ヨ
-     *
-     * @param businessKeys 涓氬姟id
-     * @return 缁撴灉
-     */
-    List<ActHiProcinst> selectByBusinessKeyIn(List<String> businessKeys);
-
-    /**
-     * 鎸夌収涓氬姟id鏌ヨ
-     *
-     * @param businessKey 涓氬姟id
-     * @return 缁撴灉
-     */
-    ActHiProcinst selectByBusinessKey(String businessKey);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java
deleted file mode 100644
index ad286e2..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.dromara.workflow.service;
-
-
-/**
- * 娴佺▼鍘嗗彶浠诲姟Service鎺ュ彛
- *
- * @author may
- * @date 2024-03-02
- */
-public interface IActHiTaskinstService {
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java
deleted file mode 100644
index 4a6d170..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package org.dromara.workflow.service;
-
-import jakarta.servlet.http.HttpServletResponse;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.workflow.domain.bo.ModelBo;
-import org.dromara.workflow.domain.vo.ModelVo;
-import org.flowable.engine.repository.Model;
-
-import java.util.List;
-
-
-/**
- * 妯″瀷绠$悊 鏈嶅姟灞�
- *
- * @author may
- */
-public interface IActModelService {
-    /**
-     * 鍒嗛〉鏌ヨ妯″瀷
-     *
-     * @param modelBo   妯″瀷鍙傛暟
-     * @param pageQuery 鍙傛暟
-     * @return 杩斿洖鍒嗛〉鍒楄〃
-     */
-    TableDataInfo<Model> page(ModelBo modelBo, PageQuery pageQuery);
-
-    /**
-     * 鏂板妯″瀷
-     *
-     * @param modelBo 妯″瀷璇锋眰瀵硅薄
-     * @return 缁撴灉
-     */
-    boolean saveNewModel(ModelBo modelBo);
-
-    /**
-     * 鏌ヨ妯″瀷
-     *
-     * @param modelId 妯″瀷id
-     * @return 妯″瀷鏁版嵁
-     */
-    ModelVo getInfo(String modelId);
-
-    /**
-     * 淇敼妯″瀷淇℃伅
-     *
-     * @param modelBo 妯″瀷鏁版嵁
-     * @return 缁撴灉
-     */
-    boolean update(ModelBo modelBo);
-
-    /**
-     * 缂栬緫妯″瀷XML
-     *
-     * @param modelBo 妯″瀷鏁版嵁
-     * @return 缁撴灉
-     */
-    boolean editModelXml(ModelBo modelBo);
-
-    /**
-     * 妯″瀷閮ㄧ讲
-     *
-     * @param id 妯″瀷id
-     * @return 缁撴灉
-     */
-    boolean modelDeploy(String id);
-
-    /**
-     * 瀵煎嚭妯″瀷zip鍘嬬缉鍖�
-     *
-     * @param modelIds 妯″瀷id
-     * @param response 鍝嶅簲
-     */
-    void exportZip(List<String> modelIds, HttpServletResponse response);
-
-    /**
-     * 澶嶅埗妯″瀷
-     *
-     * @param modelBo 妯″瀷鏁版嵁
-     * @return 缁撴灉
-     */
-    boolean copyModel(ModelBo modelBo);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java
deleted file mode 100644
index 5d00e41..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.dromara.workflow.service;
-
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.workflow.domain.bo.ProcessDefinitionBo;
-import org.dromara.workflow.domain.vo.ProcessDefinitionVo;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.util.List;
-
-/**
- * 娴佺▼瀹氫箟 鏈嶅姟灞�
- *
- * @author may
- */
-public interface IActProcessDefinitionService {
-    /**
-     * 鍒嗛〉鏌ヨ
-     *
-     * @param processDefinitionBo 鍙傛暟
-     * @param pageQuery           鍒嗛〉
-     * @return 杩斿洖鍒嗛〉鍒楄〃
-     */
-    TableDataInfo<ProcessDefinitionVo> page(ProcessDefinitionBo processDefinitionBo, PageQuery pageQuery);
-
-    /**
-     * 鏌ヨ鍘嗗彶娴佺▼瀹氫箟鍒楄〃
-     *
-     * @param key 娴佺▼瀹氫箟key
-     * @return 缁撴灉
-     */
-    List<ProcessDefinitionVo> getListByKey(String key);
-
-    /**
-     * 鏌ョ湅娴佺▼瀹氫箟鍥剧墖
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    String definitionImage(String processDefinitionId);
-
-    /**
-     * 鏌ョ湅娴佺▼瀹氫箟xml鏂囦欢
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    String definitionXml(String processDefinitionId);
-
-    /**
-     * 鍒犻櫎娴佺▼瀹氫箟
-     *
-     * @param deploymentIds        閮ㄧ讲id
-     * @param processDefinitionIds 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    boolean deleteDeployment(List<String> deploymentIds, List<String> processDefinitionIds);
-
-    /**
-     * 婵�娲绘垨鑰呮寕璧锋祦绋嬪畾涔�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    boolean updateDefinitionState(String processDefinitionId);
-
-    /**
-     * 杩佺Щ娴佺▼瀹氫箟
-     *
-     * @param currentProcessDefinitionId 褰撳墠娴佺▼瀹氫箟id
-     * @param fromProcessDefinitionId    闇�瑕佽縼绉诲埌鐨勬祦绋嬪畾涔塱d
-     * @return 缁撴灉
-     */
-    boolean migrationDefinition(String currentProcessDefinitionId, String fromProcessDefinitionId);
-
-    /**
-     * 娴佺▼瀹氫箟杞崲涓烘ā鍨�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    boolean convertToModel(String processDefinitionId);
-
-    /**
-     * 閫氳繃zip鎴杧ml閮ㄧ讲娴佺▼瀹氫箟
-     *
-     * @param file         鏂囦欢
-     * @param categoryCode 鍒嗙被
-     */
-    void deployByFile(MultipartFile file, String categoryCode);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java
deleted file mode 100644
index ca3b6fb..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package org.dromara.workflow.service;
-
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.workflow.domain.bo.ProcessInstanceBo;
-import org.dromara.workflow.domain.bo.ProcessInvalidBo;
-import org.dromara.workflow.domain.bo.TaskUrgingBo;
-import org.dromara.workflow.domain.vo.ActHistoryInfoVo;
-import org.dromara.workflow.domain.vo.ProcessInstanceVo;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * 娴佺▼瀹炰緥 鏈嶅姟灞�
- *
- * @author may
- */
-public interface IActProcessInstanceService {
-    /**
-     * 閫氳繃娴佺▼瀹炰緥id鑾峰彇鍘嗗彶娴佺▼鍥�
-     *
-     * @param businessKey 娴佺▼瀹炰緥id
-     * @return 缁撴灉
-     */
-    String getHistoryImage(String businessKey);
-
-    /**
-     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥捐繍琛屼腑锛屽巻鍙茬瓑鑺傜偣
-     *
-     * @param businessKey 涓氬姟id
-     * @return 缁撴灉
-     */
-    Map<String, Object> getHistoryList(String businessKey);
-
-    /**
-     * 鍒嗛〉鏌ヨ姝e湪杩愯鐨勬祦绋嬪疄渚�
-     *
-     * @param processInstanceBo 鍙傛暟
-     * @param pageQuery         鍒嗛〉
-     * @return 缁撴灉
-     */
-    TableDataInfo<ProcessInstanceVo> getPageByRunning(ProcessInstanceBo processInstanceBo, PageQuery pageQuery);
-
-    /**
-     * 鍒嗛〉鏌ヨ宸茬粨鏉熺殑娴佺▼瀹炰緥
-     *
-     * @param processInstanceBo 鍙傛暟
-     * @param pageQuery         鍒嗛〉
-     * @return 缁撴灉
-     */
-    TableDataInfo<ProcessInstanceVo> getPageByFinish(ProcessInstanceBo processInstanceBo, PageQuery pageQuery);
-
-    /**
-     * 鑾峰彇瀹℃壒璁板綍
-     *
-     * @param businessKey 涓氬姟id
-     * @return 缁撴灉
-     */
-    List<ActHistoryInfoVo> getHistoryRecord(String businessKey);
-
-    /**
-     * 浣滃簾娴佺▼瀹炰緥锛屼笉浼氬垹闄ゅ巻鍙茶褰�(鍒犻櫎杩愯涓殑瀹炰緥)
-     *
-     * @param processInvalidBo 鍙傛暟
-     * @return 缁撴灉
-     */
-    boolean deleteRunInstance(ProcessInvalidBo processInvalidBo);
-
-    /**
-     * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
-     *
-     * @param businessKeys 涓氬姟id
-     * @return 缁撴灉
-     */
-    boolean deleteRunAndHisInstance(List<String> businessKeys);
-
-    /**
-     * 宸插畬鎴愮殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
-     *
-     * @param businessKeys 涓氬姟id
-     * @return 缁撴灉
-     */
-    boolean deleteFinishAndHisInstance(List<String> businessKeys);
-
-    /**
-     * 鎾ら攢娴佺▼鐢宠
-     *
-     * @param businessKey 涓氬姟id
-     * @return 缁撴灉
-     */
-    boolean cancelProcessApply(String businessKey);
-
-    /**
-     * 鍒嗛〉鏌ヨ褰撳墠鐧诲綍浜哄崟鎹�
-     *
-     * @param processInstanceBo 鍙傛暟
-     * @param pageQuery         鍒嗛〉
-     * @return 缁撴灉
-     */
-    TableDataInfo<ProcessInstanceVo> getPageByCurrent(ProcessInstanceBo processInstanceBo, PageQuery pageQuery);
-
-    /**
-     * 浠诲姟鍌姙(缁欏綋鍓嶄换鍔″姙鐞嗕汉鍙戦�佺珯鍐呬俊锛岄偖浠讹紝鐭俊绛�)
-     *
-     * @param taskUrgingBo 浠诲姟鍌姙
-     * @return 缁撴灉
-     */
-    boolean taskUrging(TaskUrgingBo taskUrgingBo);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java
deleted file mode 100644
index 8e9f763..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package org.dromara.workflow.service;
-
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.workflow.domain.bo.*;
-import org.dromara.workflow.domain.vo.TaskVo;
-import org.dromara.workflow.domain.vo.VariableVo;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * 浠诲姟 鏈嶅姟灞�
- *
- * @author may
- */
-public interface IActTaskService {
-    /**
-     * 鍚姩浠诲姟
-     *
-     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
-     * @return 缁撴灉
-     */
-    Map<String, Object> startWorkFlow(StartProcessBo startProcessBo);
-
-
-    /**
-     * 鍔炵悊浠诲姟
-     *
-     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
-     * @return 缁撴灉
-     */
-    boolean completeTask(CompleteTaskBo completeTaskBo);
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
-     *
-     * @param taskBo    鍙傛暟
-     * @param pageQuery 鍒嗛〉
-     * @return 缁撴灉
-     */
-    TableDataInfo<TaskVo> getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery);
-
-    /**
-     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊緟鍔炰换鍔�
-     *
-     * @param taskBo    鍙傛暟
-     * @param pageQuery 鍒嗛〉
-     * @return 缁撴灉
-     */
-    TableDataInfo<TaskVo> getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery);
-
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
-     *
-     * @param taskBo    鍙傛暟
-     * @param pageQuery 鍙傛暟
-     * @return 缁撴灉
-     */
-    TableDataInfo<TaskVo> getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery);
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
-     *
-     * @param taskBo    鍙傛暟
-     * @param pageQuery 鍙傛暟
-     * @return 缁撴灉
-     */
-    TableDataInfo<TaskVo> getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery);
-
-    /**
-     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊凡鍔炰换鍔�
-     *
-     * @param taskBo    鍙傛暟
-     * @param pageQuery 鍙傛暟
-     * @return 缁撴灉
-     */
-    TableDataInfo<TaskVo> getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery);
-
-    /**
-     * 濮旀淳浠诲姟
-     *
-     * @param delegateBo 鍙傛暟
-     * @return 缁撴灉
-     */
-    boolean delegateTask(DelegateBo delegateBo);
-
-    /**
-     * 缁堟浠诲姟
-     *
-     * @param terminationBo 鍙傛暟
-     * @return 缁撴灉
-     */
-    boolean terminationTask(TerminationBo terminationBo);
-
-    /**
-     * 杞姙浠诲姟
-     *
-     * @param transmitBo 鍙傛暟
-     * @return 缁撴灉
-     */
-    boolean transferTask(TransmitBo transmitBo);
-
-    /**
-     * 浼氱浠诲姟鍔犵
-     *
-     * @param addMultiBo 鍙傛暟
-     * @return 缁撴灉
-     */
-    boolean addMultiInstanceExecution(AddMultiBo addMultiBo);
-
-    /**
-     * 浼氱浠诲姟鍑忕
-     *
-     * @param deleteMultiBo 鍙傛暟
-     * @return 缁撴灉
-     */
-    boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo);
-
-    /**
-     * 椹冲洖瀹℃壒
-     *
-     * @param backProcessBo 鍙傛暟
-     * @return 娴佺▼瀹炰緥id
-     */
-    String backProcess(BackProcessBo backProcessBo);
-
-    /**
-     * 淇敼浠诲姟鍔炵悊浜�
-     *
-     * @param taskIds 浠诲姟id
-     * @param userId  鍔炵悊浜篿d
-     * @return 缁撴灉
-     */
-    boolean updateAssignee(String[] taskIds, String userId);
-
-    /**
-     * 鏌ヨ娴佺▼鍙橀噺
-     *
-     * @param taskId 浠诲姟id
-     * @return 缁撴灉
-     */
-    List<VariableVo> getInstanceVariable(String taskId);
-
-    /**
-     * 鏌ヨ宸ヤ綔娴佷换鍔$敤鎴烽�夋嫨鍔犵浜哄憳
-     *
-     * @param taskId 浠诲姟id
-     * @return 缁撴灉
-     */
-    String getTaskUserIdsByAddMultiInstance(String taskId);
-
-    /**
-     * 鏌ヨ宸ヤ綔娴侀�夋嫨鍑忕浜哄憳
-     *
-     * @param taskId 浠诲姟id
-     * @return 缁撴灉
-     */
-    List<TaskVo> getListByDeleteMultiInstance(String taskId);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java
new file mode 100644
index 0000000..91f173d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java
@@ -0,0 +1,102 @@
+package org.dromara.workflow.service;
+
+import cn.hutool.core.lang.tree.Tree;
+import org.dromara.workflow.domain.bo.FlowCategoryBo;
+import org.dromara.workflow.domain.vo.FlowCategoryVo;
+
+import java.util.List;
+
+/**
+ * 娴佺▼鍒嗙被Service鎺ュ彛
+ *
+ * @author may
+ */
+public interface IFlwCategoryService {
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被
+     *
+     * @param categoryId 涓婚敭
+     * @return 娴佺▼鍒嗙被
+     */
+    FlowCategoryVo queryById(Long categoryId);
+
+    /**
+     * 鏍规嵁娴佺▼鍒嗙被ID鏌ヨ娴佺▼鍒嗙被鍚嶇О
+     *
+     * @param categoryId 娴佺▼鍒嗙被ID
+     * @return 娴佺▼鍒嗙被鍚嶇О
+     */
+    String selectCategoryNameById(Long categoryId);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勬祦绋嬪垎绫诲垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 娴佺▼鍒嗙被鍒楄〃
+     */
+    List<FlowCategoryVo> queryList(FlowCategoryBo bo);
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被鏍戠粨鏋勪俊鎭�
+     *
+     * @param category 娴佺▼鍒嗙被淇℃伅
+     * @return 娴佺▼鍒嗙被鏍戜俊鎭泦鍚�
+     */
+    List<Tree<String>> selectCategoryTreeList(FlowCategoryBo category);
+
+    /**
+     * 鏍¢獙娴佺▼鍒嗙被鏄惁鏈夋暟鎹潈闄�
+     *
+     * @param categoryId 娴佺▼鍒嗙被ID
+     */
+    void checkCategoryDataScope(Long categoryId);
+
+    /**
+     * 鏍¢獙娴佺▼鍒嗙被鍚嶇О鏄惁鍞竴
+     *
+     * @param category 娴佺▼鍒嗙被淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkCategoryNameUnique(FlowCategoryBo category);
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被鏄惁瀛樺湪娴佺▼瀹氫箟
+     *
+     * @param categoryId 娴佺▼鍒嗙被ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    boolean checkCategoryExistDefinition(Long categoryId);
+
+    /**
+     * 鏄惁瀛樺湪娴佺▼鍒嗙被瀛愯妭鐐�
+     *
+     * @param categoryId 娴佺▼鍒嗙被ID
+     * @return 缁撴灉
+     */
+    boolean hasChildByCategoryId(Long categoryId);
+
+    /**
+     * 鏂板娴佺▼鍒嗙被
+     *
+     * @param bo 娴佺▼鍒嗙被
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    int insertByBo(FlowCategoryBo bo);
+
+    /**
+     * 淇敼娴佺▼鍒嗙被
+     *
+     * @param bo 娴佺▼鍒嗙被
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    int updateByBo(FlowCategoryBo bo);
+
+    /**
+     * 鍒犻櫎娴佺▼鍒嗙被淇℃伅
+     *
+     * @param categoryId 涓婚敭
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    int deleteWithValidById(Long categoryId);
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java
new file mode 100644
index 0000000..1a2d29f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java
@@ -0,0 +1,79 @@
+package org.dromara.workflow.service;
+
+import jakarta.servlet.http.HttpServletResponse;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.warm.flow.orm.entity.FlowDefinition;
+import org.dromara.workflow.domain.vo.FlowDefinitionVo;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 娴佺▼瀹氫箟 鏈嶅姟灞�
+ *
+ * @author may
+ */
+public interface IFlwDefinitionService {
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param flowDefinition 鍙傛暟
+     * @param pageQuery      鍒嗛〉
+     * @return 杩斿洖鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<FlowDefinitionVo> queryList(FlowDefinition flowDefinition, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ鏈彂甯冪殑娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param flowDefinition 鍙傛暟
+     * @param pageQuery      鍒嗛〉
+     * @return 杩斿洖鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery);
+
+
+    /**
+     * 鍙戝竷娴佺▼瀹氫箟
+     *
+     * @param id 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    boolean publish(Long id);
+
+    /**
+     * 瀵煎嚭娴佺▼瀹氫箟
+     *
+     * @param id       娴佺▼瀹氫箟id
+     * @param response 鍝嶅簲
+     * @throws IOException 寮傚父
+     */
+    void exportDef(Long id, HttpServletResponse response) throws IOException;
+
+    /**
+     * 瀵煎叆娴佺▼瀹氫箟
+     *
+     * @param file     鏂囦欢
+     * @param category 鍒嗙被
+     * @return 缁撴灉
+     */
+    boolean importJson(MultipartFile file, String category);
+
+    /**
+     * 鍒犻櫎娴佺▼瀹氫箟
+     *
+     * @param ids 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    boolean removeDef(List<Long> ids);
+
+    /**
+     * 鏂板绉熸埛娴佺▼瀹氫箟
+     *
+     * @param tenantId 绉熸埛id
+     */
+    void syncDef(String tenantId);
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java
new file mode 100644
index 0000000..99729c2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java
@@ -0,0 +1,159 @@
+package org.dromara.workflow.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.warm.flow.orm.entity.FlowInstance;
+import org.dromara.workflow.domain.bo.FlowCancelBo;
+import org.dromara.workflow.domain.bo.FlowInstanceBo;
+import org.dromara.workflow.domain.bo.FlowInvalidBo;
+import org.dromara.workflow.domain.vo.FlowInstanceVo;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 娴佺▼瀹炰緥 鏈嶅姟灞�
+ *
+ * @author may
+ */
+public interface IFlwInstanceService {
+
+    /**
+     * 鍒嗛〉鏌ヨ姝e湪杩愯鐨勬祦绋嬪疄渚�
+     *
+     * @param flowInstanceBo 娴佺▼瀹炰緥
+     * @param pageQuery      鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<FlowInstanceVo> selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery);
+
+    /**
+     * 鍒嗛〉鏌ヨ宸茬粨鏉熺殑娴佺▼瀹炰緥
+     *
+     * @param flowInstanceBo 娴佺▼瀹炰緥
+     * @param pageQuery      鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<FlowInstanceVo> selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery);
+
+    /**
+     * 鏍规嵁涓氬姟id鏌ヨ娴佺▼瀹炰緥璇︾粏淇℃伅
+     *
+     * @param businessId 涓氬姟id
+     * @return 缁撴灉
+     */
+    FlowInstanceVo queryByBusinessId(Long businessId);
+
+    /**
+     * 鎸夌収涓氬姟id鏌ヨ娴佺▼瀹炰緥
+     *
+     * @param businessId 涓氬姟id
+     * @return 缁撴灉
+     */
+    FlowInstance selectInstByBusinessId(String businessId);
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ娴佺▼瀹炰緥
+     *
+     * @param instanceId 瀹炰緥id
+     * @return 缁撴灉
+     */
+    FlowInstance selectInstById(Long instanceId);
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ娴佺▼瀹炰緥
+     *
+     * @param instanceIds 瀹炰緥id
+     * @return 缁撴灉
+     */
+    List<FlowInstance> selectInstListByIdList(List<Long> instanceIds);
+
+    /**
+     * 鎸夌収涓氬姟id鍒犻櫎娴佺▼瀹炰緥
+     *
+     * @param businessIds 涓氬姟id
+     * @return 缁撴灉
+     */
+    boolean deleteByBusinessIds(List<Long> businessIds);
+
+    /**
+     * 鎸夌収瀹炰緥id鍒犻櫎娴佺▼瀹炰緥
+     *
+     * @param instanceIds 瀹炰緥id
+     * @return 缁撴灉
+     */
+    boolean deleteByInstanceIds(List<Long> instanceIds);
+
+    /**
+     * 鎾ら攢娴佺▼
+     *
+     * @param bo 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean cancelProcessApply(FlowCancelBo bo);
+
+    /**
+     * 鑾峰彇褰撳墠鐧婚檰浜哄彂璧风殑娴佺▼瀹炰緥
+     *
+     * @param instanceBo 娴佺▼瀹炰緥
+     * @param pageQuery  鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<FlowInstanceVo> selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery);
+
+    /**
+     * 鑾峰彇娴佺▼鍥�,娴佺▼璁板綍
+     *
+     * @param businessId 涓氬姟id
+     * @return 缁撴灉
+     */
+    Map<String, Object> flowImage(String businessId);
+
+    /**
+     * 鎸夌収瀹炰緥id鏇存柊鐘舵��
+     *
+     * @param instanceId 瀹炰緥id
+     * @param status     鐘舵��
+     */
+    void updateStatus(Long instanceId, String status);
+
+    /**
+     * 鑾峰彇娴佺▼鍙橀噺
+     *
+     * @param instanceId 瀹炰緥id
+     * @return 缁撴灉
+     */
+    Map<String, Object> instanceVariable(Long instanceId);
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺
+     *
+     * @param instanceId 瀹炰緥id
+     * @param variable   娴佺▼鍙橀噺
+     */
+    void setVariable(Long instanceId, Map<String, Object> variable);
+
+    /**
+     * 鎸変换鍔d鏌ヨ瀹炰緥
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    FlowInstance selectByTaskId(Long taskId);
+
+    /**
+     * 鎸変换鍔d鏌ヨ瀹炰緥
+     *
+     * @param taskIdList 浠诲姟id
+     * @return 缁撴灉
+     */
+    List<FlowInstance> selectByTaskIdList(List<Long> taskIdList);
+
+    /**
+     * 浣滃簾娴佺▼
+     *
+     * @param bo 娴佺▼瀹炰緥
+     * @return 缁撴灉
+     */
+    boolean processInvalid(FlowInvalidBo bo);
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java
new file mode 100644
index 0000000..116cb74
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java
@@ -0,0 +1,22 @@
+package org.dromara.workflow.service;
+
+import org.dromara.common.core.domain.dto.UserDTO;
+
+import java.util.List;
+
+/**
+ * 娴佺▼璁捐鍣�-鑾峰彇鍔炵悊浜�
+ *
+ * @author AprilWind
+ */
+public interface IFlwTaskAssigneeService {
+
+    /**
+     * 鏍规嵁瀛樺偍鏍囪瘑绗︼紙storageId锛夎В鏋愬垎閰嶇被鍨嬪拰ID锛屽苟鑾峰彇瀵瑰簲鐨勭敤鎴峰垪琛�
+     *
+     * @param storageId 鍖呭惈鍒嗛厤绫诲瀷鍜孖D鐨勫瓧绗︿覆锛堜緥濡� "user:123" 鎴� "role:456"锛�
+     * @return 涓庡垎閰嶇被鍨嬪拰ID鍖归厤鐨勭敤鎴峰垪琛紝濡傛灉鏍煎紡鏃犳晥鍒欒繑鍥炵┖鍒楄〃
+     */
+    List<UserDTO> fetchUsersByStorageId(String storageId);
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java
new file mode 100644
index 0000000..11034e7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java
@@ -0,0 +1,191 @@
+package org.dromara.workflow.service;
+
+import org.dromara.common.core.domain.dto.StartProcessReturnDTO;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.warm.flow.core.entity.Node;
+import org.dromara.warm.flow.orm.entity.FlowHisTask;
+import org.dromara.warm.flow.orm.entity.FlowTask;
+import org.dromara.workflow.domain.bo.*;
+import org.dromara.workflow.domain.vo.FlowHisTaskVo;
+import org.dromara.workflow.domain.vo.FlowTaskVo;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 浠诲姟 鏈嶅姟灞�
+ *
+ * @author may
+ */
+public interface IFlwTaskService {
+
+    /**
+     * 鍚姩浠诲姟
+     *
+     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
+     * @return 缁撴灉
+     */
+    StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo);
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean completeTask(CompleteTaskBo completeTaskBo);
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊緟鍔炰换鍔�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ寰呭姙浠诲姟
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ宸插姙浠诲姟
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<FlowHisTaskVo> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery);
+
+    /**
+     * 淇敼浠诲姟鍔炵悊浜�
+     *
+     * @param taskIdList 浠诲姟id
+     * @param userId     鐢ㄦ埛id
+     * @return 缁撴灉
+     */
+    boolean updateAssignee(List<Long> taskIdList, String userId);
+
+    /**
+     * 椹冲洖瀹℃壒
+     *
+     * @param bo 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean backProcess(BackProcessBo bo);
+
+    /**
+     * 鑾峰彇鍙┏鍥炵殑鍓嶇疆鑺傜偣
+     *
+     * @param definitionId 娴佺▼瀹氫箟id
+     * @param nowNodeCode  褰撳墠鑺傜偣
+     * @return 缁撴灉
+     */
+    List<Node> getBackTaskNode(Long definitionId, String nowNodeCode);
+
+    /**
+     * 缁堟浠诲姟
+     *
+     * @param bo 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean terminationTask(FlowTerminationBo bo);
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskIdList 浠诲姟id
+     * @return 缁撴灉
+     */
+    List<FlowTask> selectByIdList(List<Long> taskIdList);
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    FlowTaskVo selectById(Long taskId);
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskIdList 浠诲姟id
+     * @return 缁撴灉
+     */
+    List<FlowHisTask> selectHisTaskByIdList(List<Long> taskIdList);
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    FlowHisTask selectHisTaskById(Long taskId);
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ浠诲姟
+     *
+     * @param instanceIdList 娴佺▼瀹炰緥id
+     * @return 缁撴灉
+     */
+    List<FlowTask> selectByInstIdList(List<Long> instanceIdList);
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ浠诲姟
+     *
+     * @param instanceId 娴佺▼瀹炰緥id
+     * @return 缁撴灉
+     */
+    List<FlowTask> selectByInstId(Long instanceId);
+
+    /**
+     * 浠诲姟鎿嶄綔
+     *
+     * @param bo            鍙傛暟
+     * @param taskOperation 鎿嶄綔绫诲瀷锛屽娲� delegateTask銆佽浆鍔� transferTask銆佸姞绛� addSignature銆佸噺绛� reductionSignature
+     * @return 缁撴灉
+     */
+    boolean taskOperation(TaskOperationBo bo, String taskOperation);
+
+    /**
+     * 鑾峰彇浠诲姟鎵�鏈夊姙鐞嗕汉
+     *
+     * @param taskIdList 浠诲姟id
+     * @return 缁撴灉
+     */
+    Map<Long, List<UserDTO>> currentTaskAllUser(List<Long> taskIdList);
+
+    /**
+     * 鑾峰彇褰撳墠浠诲姟鐨勬墍鏈夊姙鐞嗕汉
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    List<UserDTO> currentTaskAllUser(Long taskId);
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java
index 943c919..67b50ba 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java
@@ -5,7 +5,6 @@
 import org.dromara.workflow.domain.bo.TestLeaveBo;
 import org.dromara.workflow.domain.vo.TestLeaveVo;
 
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -44,5 +43,5 @@
     /**
      * 鏍¢獙骞舵壒閲忓垹闄よ鍋囦俊鎭�
      */
-    Boolean deleteWithValidByIds(Collection<Long> ids);
+    Boolean deleteWithValidByIds(List<Long> ids);
 }
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java
deleted file mode 100644
index acf0aa2..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.dromara.workflow.service;
-
-import org.dromara.workflow.domain.WfCategory;
-import org.dromara.workflow.domain.bo.WfCategoryBo;
-import org.dromara.workflow.domain.vo.WfCategoryVo;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * 娴佺▼鍒嗙被Service鎺ュ彛
- *
- * @author may
- * @date 2023-06-28
- */
-public interface IWfCategoryService {
-
-    /**
-     * 鏌ヨ娴佺▼鍒嗙被
-     */
-    WfCategoryVo queryById(Long id);
-
-
-    /**
-     * 鏌ヨ娴佺▼鍒嗙被鍒楄〃
-     */
-    List<WfCategoryVo> queryList(WfCategoryBo bo);
-
-    /**
-     * 鏂板娴佺▼鍒嗙被
-     */
-    Boolean insertByBo(WfCategoryBo bo);
-
-    /**
-     * 淇敼娴佺▼鍒嗙被
-     */
-    Boolean updateByBo(WfCategoryBo bo);
-
-    /**
-     * 鏍¢獙骞舵壒閲忓垹闄ゆ祦绋嬪垎绫讳俊鎭�
-     */
-    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
-
-    /**
-     * 鎸夌収绫诲埆缂栫爜鏌ヨ
-     *
-     * @param categoryCode 鍒嗙被姣斿悧
-     * @return 缁撴灉
-     */
-    WfCategory queryByCategoryCode(String categoryCode);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java
deleted file mode 100644
index fe5cf7a..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package org.dromara.workflow.service;
-
-import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
-import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * 娴佺▼瀹氫箟閰嶇疆Service鎺ュ彛
- *
- * @author may
- * @date 2024-03-18
- */
-public interface IWfDefinitionConfigService {
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
-     *
-     * @param definitionId 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    WfDefinitionConfigVo getByDefId(String definitionId);
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
-     *
-     * @param tableName 琛ㄥ悕
-     * @return 缁撴灉
-     */
-    WfDefinitionConfigVo getByTableNameLastVersion(String tableName);
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
-     *
-     * @param definitionId 娴佺▼瀹氫箟id
-     * @param tableName    琛ㄥ悕
-     * @return 缁撴灉
-     */
-    WfDefinitionConfigVo getByDefIdAndTableName(String definitionId, String tableName);
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鎺掗櫎褰撳墠鏌ヨ鐨勬祦绋嬪畾涔�
-     *
-     * @param definitionId 娴佺▼瀹氫箟id
-     * @param tableName    琛ㄥ悕
-     * @return 缁撴灉
-     */
-    List<WfDefinitionConfigVo> getByTableNameNotDefId(String tableName, String definitionId);
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鍒楄〃
-     *
-     * @param definitionIds 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    List<WfDefinitionConfigVo> queryList(List<String> definitionIds);
-
-
-    /**
-     * 鏂板娴佺▼瀹氫箟閰嶇疆
-     *
-     * @param bo 鍙傛暟
-     * @return 缁撴灉
-     */
-    Boolean saveOrUpdate(WfDefinitionConfigBo bo);
-
-    /**
-     * 鍒犻櫎
-     *
-     * @param ids id
-     * @return 缁撴灉
-     */
-    Boolean deleteByIds(Collection<Long> ids);
-
-    /**
-     * 鎸夌収娴佺▼瀹氫箟id鍒犻櫎
-     *
-     * @param ids 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    Boolean deleteByDefIds(Collection<String> ids);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java
deleted file mode 100644
index 2ca2264..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.dromara.workflow.service;
-
-import org.dromara.workflow.domain.vo.WfFormManageVo;
-import org.dromara.workflow.domain.bo.WfFormManageBo;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.mybatis.core.page.PageQuery;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * 琛ㄥ崟绠$悊Service鎺ュ彛
- *
- * @author may
- * @date 2024-03-29
- */
-public interface IWfFormManageService {
-
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊
-     *
-     * @param id 涓婚敭
-     * @return 缁撴灉
-     */
-    WfFormManageVo queryById(Long id);
-
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊
-     *
-     * @param ids 涓婚敭
-     * @return 缁撴灉
-     */
-    List<WfFormManageVo> queryByIds(List<Long> ids);
-
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
-     *
-     * @param bo        鍙傛暟
-     * @param pageQuery 鍒嗛〉
-     * @return 缁撴灉
-     */
-    TableDataInfo<WfFormManageVo> queryPageList(WfFormManageBo bo, PageQuery pageQuery);
-
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
-     *
-     * @return 缁撴灉
-     */
-    List<WfFormManageVo> selectList();
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
-     *
-     * @param bo 鍙傛暟
-     * @return 缁撴灉
-     */
-    List<WfFormManageVo> queryList(WfFormManageBo bo);
-
-    /**
-     * 鏂板琛ㄥ崟绠$悊
-     *
-     * @param bo 鍙傛暟
-     * @return 缁撴灉
-     */
-    Boolean insertByBo(WfFormManageBo bo);
-
-    /**
-     * 淇敼琛ㄥ崟绠$悊
-     *
-     * @param bo 鍙傛暟
-     * @return 缁撴灉
-     */
-    Boolean updateByBo(WfFormManageBo bo);
-
-    /**
-     * 鎵归噺鍒犻櫎琛ㄥ崟绠$悊淇℃伅
-     *
-     * @param ids 涓婚敭
-     * @return 缁撴灉
-     */
-    Boolean deleteByIds(Collection<Long> ids);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java
deleted file mode 100644
index 5e64d64..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.dromara.workflow.service;
-
-import org.dromara.workflow.domain.WfNodeConfig;
-import org.dromara.workflow.domain.vo.WfNodeConfigVo;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * 鑺傜偣閰嶇疆Service鎺ュ彛
- *
- * @author may
- * @date 2024-03-30
- */
-public interface IWfNodeConfigService {
-
-    /**
-     * 鏌ヨ鑺傜偣閰嶇疆
-     *
-     * @param id 涓婚敭
-     * @return 缁撴灉
-     */
-    WfNodeConfigVo queryById(Long id);
-
-    /**
-     * 淇濆瓨鑺傜偣閰嶇疆
-     *
-     * @param list 鍙傛暟
-     * @return 缁撴灉
-     */
-    Boolean saveOrUpdate(List<WfNodeConfig> list);
-
-    /**
-     * 鎵归噺鍒犻櫎鑺傜偣閰嶇疆淇℃伅
-     *
-     * @param ids 涓婚敭
-     * @return 缁撴灉
-     */
-    Boolean deleteByIds(Collection<Long> ids);
-
-    /**
-     * 鎸夌収娴佺▼瀹氫箟id鍒犻櫎
-     *
-     * @param ids 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    Boolean deleteByDefIds(Collection<String> ids);
-
-    /**
-     * 鎸夌収娴佺▼瀹氫箟id鏌ヨ
-     *
-     * @param ids 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    List<WfNodeConfigVo> selectByDefIds(Collection<String> ids);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java
deleted file mode 100644
index 97f9406..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.dromara.workflow.service;
-
-
-import org.dromara.workflow.domain.WfTaskBackNode;
-import org.flowable.task.api.Task;
-
-import java.util.List;
-
-/**
- * 鑺傜偣椹冲洖璁板綍Service鎺ュ彛
- *
- * @author may
- * @date 2024-03-13
- */
-public interface IWfTaskBackNodeService {
-
-    /**
-     * 璁板綍瀹℃壒鑺傜偣
-     *
-     * @param task 浠诲姟
-     */
-    void recordExecuteNode(Task task);
-
-    /**
-     * 鎸夋祦绋嬪疄渚媔d鏌ヨ
-     *
-     * @param processInstanceId 娴佺▼瀹炰緥id
-     * @return 缁撴灉
-     */
-    List<WfTaskBackNode> getListByInstanceId(String processInstanceId);
-
-    /**
-     * 鎸夌収娴佺▼瀹炰緥id锛岃妭鐐筰d鏌ヨ
-     *
-     * @param processInstanceId 娴佺▼瀹炰緥id
-     * @param nodeId            鑺傜偣id
-     * @return 缁撴灉
-     */
-    WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId);
-
-    /**
-     * 鍒犻櫎椹冲洖鍚庣殑鑺傜偣
-     *
-     * @param processInstanceId 娴佺▼瀹炰緥id
-     * @param targetActivityId  鑺傜偣id
-     * @return 缁撴灉
-     */
-    boolean deleteBackTaskNode(String processInstanceId, String targetActivityId);
-
-    /**
-     * 鎸夋祦绋嬪疄渚媔d鍒犻櫎
-     *
-     * @param processInstanceId 娴佺▼瀹炰緥id
-     * @return 缁撴灉
-     */
-    boolean deleteByInstanceId(String processInstanceId);
-
-    /**
-     * 鎸夋祦绋嬪疄渚媔d鍒犻櫎
-     *
-     * @param processInstanceIds 娴佺▼瀹炰緥id
-     * @return 缁撴灉
-     */
-    boolean deleteByInstanceIds(List<String> processInstanceIds);
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java
deleted file mode 100644
index 06d607b..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import lombok.RequiredArgsConstructor;
-import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.workflow.domain.ActHiProcinst;
-import org.dromara.workflow.mapper.ActHiProcinstMapper;
-import org.dromara.workflow.service.IActHiProcinstService;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-
-/**
- * 娴佺▼瀹炰緥Service涓氬姟灞傚鐞�
- *
- * @author may
- * @date 2023-07-22
- */
-@RequiredArgsConstructor
-@Service
-public class ActHiProcinstServiceImpl implements IActHiProcinstService {
-
-    private final ActHiProcinstMapper baseMapper;
-
-    /**
-     * 鎸夌収涓氬姟id鏌ヨ
-     *
-     * @param businessKeys 涓氬姟id
-     */
-    @Override
-    public List<ActHiProcinst> selectByBusinessKeyIn(List<String> businessKeys) {
-        return baseMapper.selectList(new LambdaQueryWrapper<ActHiProcinst>()
-            .in(ActHiProcinst::getBusinessKey, businessKeys)
-            .eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId()));
-    }
-
-    /**
-     * 鎸夌収涓氬姟id鏌ヨ
-     *
-     * @param businessKey 涓氬姟id
-     */
-    @Override
-    public ActHiProcinst selectByBusinessKey(String businessKey) {
-        return baseMapper.selectOne(new LambdaQueryWrapper<ActHiProcinst>()
-            .eq(ActHiProcinst::getBusinessKey, businessKey)
-            .eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId()));
-
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java
deleted file mode 100644
index 5548f22..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.dromara.workflow.service.IActHiTaskinstService;
-
-
-/**
- * 娴佺▼鍘嗗彶浠诲姟Service涓氬姟灞傚鐞�
- *
- * @author may
- * @date 2024-03-02
- */
-@RequiredArgsConstructor
-@Service
-public class ActHiTaskinstServiceImpl implements IActHiTaskinstService {
-
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java
deleted file mode 100644
index 217538e..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java
+++ /dev/null
@@ -1,431 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.ZipUtil;
-import cn.hutool.json.JSONUtil;
-import com.alibaba.excel.util.StringUtils;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.batik.transcoder.TranscoderInput;
-import org.apache.batik.transcoder.TranscoderOutput;
-import org.apache.batik.transcoder.image.PNGTranscoder;
-import org.dromara.common.core.exception.ServiceException;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.workflow.common.constant.FlowConstant;
-import org.dromara.workflow.domain.WfNodeConfig;
-import org.dromara.workflow.domain.bo.ModelBo;
-import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
-import org.dromara.workflow.domain.vo.ModelVo;
-import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
-import org.dromara.workflow.service.IActModelService;
-import org.dromara.workflow.service.IWfDefinitionConfigService;
-import org.dromara.workflow.service.IWfNodeConfigService;
-import org.dromara.workflow.utils.ModelUtils;
-import org.dromara.workflow.utils.QueryUtils;
-import org.flowable.bpmn.converter.BpmnXMLConverter;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.bpmn.model.Process;
-import org.flowable.bpmn.model.UserTask;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.repository.Deployment;
-import org.flowable.engine.repository.Model;
-import org.flowable.engine.repository.ModelQuery;
-import org.flowable.engine.repository.ProcessDefinition;
-import org.flowable.validation.ValidationError;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-
-/**
- * 妯″瀷绠$悊 鏈嶅姟灞傚疄鐜�
- *
- * @author may
- */
-@Slf4j
-@RequiredArgsConstructor
-@Service
-public class ActModelServiceImpl implements IActModelService {
-
-    @Autowired(required = false)
-    private RepositoryService repositoryService;
-    private final IWfNodeConfigService wfNodeConfigService;
-    private final IWfDefinitionConfigService wfDefinitionConfigService;
-
-    /**
-     * 鍒嗛〉鏌ヨ妯″瀷
-     *
-     * @param modelBo 妯″瀷鍙傛暟
-     * @return 杩斿洖鍒嗛〉鍒楄〃
-     */
-    @Override
-    public TableDataInfo<Model> page(ModelBo modelBo, PageQuery pageQuery) {
-        ModelQuery query = QueryUtils.modelQuery();
-        if (StringUtils.isNotBlank(modelBo.getName())) {
-            query.modelNameLike("%" + modelBo.getName() + "%");
-        }
-        if (StringUtils.isNotBlank(modelBo.getKey())) {
-            query.modelKey(modelBo.getKey());
-        }
-        if (StringUtils.isNotBlank(modelBo.getCategoryCode())) {
-            query.modelCategory(modelBo.getCategoryCode());
-        }
-        query.orderByLastUpdateTime().desc();
-        // 鍒涘缓鏃堕棿闄嶅簭鎺掑垪
-        query.orderByCreateTime().desc();
-        // 鍒嗛〉鏌ヨ
-        List<Model> modelList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
-        // 鎬昏褰曟暟
-        long total = query.count();
-        TableDataInfo<Model> build = TableDataInfo.build();
-        build.setRows(modelList);
-        build.setTotal(total);
-        return build;
-    }
-
-    /**
-     * 鏂板妯″瀷
-     *
-     * @param modelBo 妯″瀷璇锋眰瀵硅薄
-     * @return 缁撴灉
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean saveNewModel(ModelBo modelBo) {
-        try {
-            int version = 0;
-            String key = modelBo.getKey();
-            String name = modelBo.getName();
-            String description = modelBo.getDescription();
-            String categoryCode = modelBo.getCategoryCode();
-            String xml = modelBo.getXml();
-            Model checkModel = QueryUtils.modelQuery().modelKey(key).singleResult();
-            if (ObjectUtil.isNotNull(checkModel)) {
-                throw new ServiceException("妯″瀷key宸插瓨鍦紒");
-            }
-            //鍒濆绌虹殑妯″瀷
-            Model model = repositoryService.newModel();
-            model.setKey(key);
-            model.setName(name);
-            model.setVersion(version);
-            model.setCategory(categoryCode);
-            model.setMetaInfo(description);
-            model.setTenantId(TenantHelper.getTenantId());
-            //淇濆瓨鍒濆鍖栫殑妯″瀷鍩烘湰淇℃伅鏁版嵁
-            repositoryService.saveModel(model);
-            repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml));
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 鏌ヨ妯″瀷
-     *
-     * @param id 妯″瀷id
-     * @return 妯″瀷鏁版嵁
-     */
-    @Override
-    public ModelVo getInfo(String id) {
-        ModelVo modelVo = new ModelVo();
-        Model model = repositoryService.getModel(id);
-        if (model != null) {
-            try {
-                byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
-                modelVo.setXml(StrUtil.utf8Str(modelEditorSource));
-                modelVo.setId(model.getId());
-                modelVo.setKey(model.getKey());
-                modelVo.setName(model.getName());
-                modelVo.setCategoryCode(model.getCategory());
-                modelVo.setDescription(model.getMetaInfo());
-                return modelVo;
-            } catch (Exception e) {
-                log.error(e.getMessage(), e);
-                throw new ServiceException(e.getMessage());
-            }
-        }
-        return modelVo;
-    }
-
-    /**
-     * 淇敼妯″瀷淇℃伅
-     *
-     * @param modelBo 妯″瀷鏁版嵁
-     * @return 缁撴灉
-     */
-    @Override
-    public boolean update(ModelBo modelBo) {
-        try {
-            Model model = repositoryService.getModel(modelBo.getId());
-            List<Model> list = QueryUtils.modelQuery().modelKey(modelBo.getKey()).list();
-            list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> {
-                throw new ServiceException("妯″瀷KEY宸插瓨鍦紒");
-            });
-            model.setCategory(modelBo.getCategoryCode());
-            model.setMetaInfo(modelBo.getDescription());
-            repositoryService.saveModel(model);
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-        return true;
-    }
-
-    /**
-     * 缂栬緫妯″瀷XML
-     *
-     * @param modelBo 妯″瀷鏁版嵁
-     * @return 缁撴灉
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean editModelXml(ModelBo modelBo) {
-        try {
-            String xml = modelBo.getXml();
-            String svg = modelBo.getSvg();
-            String modelId = modelBo.getId();
-            String key = modelBo.getKey();
-            String name = modelBo.getName();
-            BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xml);
-            ModelUtils.checkBpmnModel(bpmnModel);
-            Model model = repositoryService.getModel(modelId);
-            List<Model> list = QueryUtils.modelQuery().modelKey(key).list();
-            list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> {
-                throw new ServiceException("妯″瀷KEY宸插瓨鍦紒");
-            });
-            // 鏍¢獙key鍛藉悕瑙勮寖
-            if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) {
-                throw new ServiceException("妯″瀷鏍囪瘑KEY鍙兘瀛楃鎴栬�呬笅鍒掔嚎寮�澶达紒");
-            }
-            model.setKey(key);
-            model.setName(name);
-            model.setVersion(model.getVersion() + 1);
-            repositoryService.saveModel(model);
-            repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml));
-            // 杞崲鍥剧墖
-            InputStream svgStream = new ByteArrayInputStream(StrUtil.utf8Bytes(svg));
-            TranscoderInput input = new TranscoderInput(svgStream);
-
-            PNGTranscoder transcoder = new PNGTranscoder();
-            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
-            TranscoderOutput output = new TranscoderOutput(outStream);
-
-            transcoder.transcode(input, output);
-            final byte[] result = outStream.toByteArray();
-            repositoryService.addModelEditorSourceExtra(model.getId(), result);
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 妯″瀷閮ㄧ讲
-     *
-     * @param id 妯″瀷id
-     * @return 缁撴灉
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean modelDeploy(String id) {
-        try {
-            // 鏌ヨ娴佺▼瀹氫箟妯″瀷xml
-            byte[] xmlBytes = repositoryService.getModelEditorSource(id);
-            if (ArrayUtil.isEmpty(xmlBytes)) {
-                throw new ServiceException("妯″瀷鏁版嵁涓虹┖锛岃鍏堣璁℃祦绋嬪畾涔夋ā鍨嬶紝鍐嶈繘琛岄儴缃诧紒");
-            }
-            if (JSONUtil.isTypeJSON(new String(xmlBytes, StandardCharsets.UTF_8))) {
-                byte[] bytes = ModelUtils.bpmnJsonToXmlBytes(xmlBytes);
-                if (ArrayUtil.isEmpty(bytes)) {
-                    throw new ServiceException("妯″瀷涓嶈兘涓虹┖锛岃鑷冲皯璁捐涓�鏉′富绾挎祦绋嬶紒");
-                }
-            }
-            BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xmlBytes);
-            // 鏍¢獙妯″瀷
-            ModelUtils.checkBpmnModel(bpmnModel);
-            List<ValidationError> validationErrors = repositoryService.validateProcess(bpmnModel);
-            if (CollUtil.isNotEmpty(validationErrors)) {
-                String errorMsg = validationErrors.stream().map(ValidationError::getProblem).distinct().collect(Collectors.joining(","));
-                throw new ServiceException(errorMsg);
-            }
-            // 鏌ヨ妯″瀷鐨勫熀鏈俊鎭�
-            Model model = repositoryService.getModel(id);
-            ProcessDefinition processDefinition = QueryUtils.definitionQuery().processDefinitionKey(model.getKey()).latestVersion().singleResult();
-            // xml璧勬簮鐨勫悕绉� 锛屽搴攁ct_ge_bytearray琛ㄤ腑鐨刵ame_瀛楁
-            String processName = model.getName() + ".bpmn20.xml";
-            // 璋冪敤閮ㄧ讲鐩稿叧鐨刟pi鏂规硶杩涜閮ㄧ讲娴佺▼瀹氫箟
-            Deployment deployment = repositoryService.createDeployment()
-                // 閮ㄧ讲鍚嶇О
-                .name(model.getName())
-                // 閮ㄧ讲鏍囪瘑key
-                .key(model.getKey())
-                // 閮ㄧ讲娴佺▼鍒嗙被
-                .category(model.getCategory())
-                // bpmn20.xml璧勬簮
-                .addBytes(processName, xmlBytes)
-                // 绉熸埛id
-                .tenantId(TenantHelper.getTenantId())
-                .deploy();
-
-            // 鏇存柊 閮ㄧ讲id 鍒版祦绋嬪畾涔夋ā鍨嬫暟鎹〃涓�
-            model.setDeploymentId(deployment.getId());
-            repositoryService.saveModel(model);
-            // 鏇存柊鍒嗙被
-            ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult();
-            repositoryService.setProcessDefinitionCategory(definition.getId(), model.getCategory());
-            //鏇存柊娴佺▼瀹氫箟閰嶇疆
-            if (processDefinition != null) {
-                WfDefinitionConfigVo definitionVo = wfDefinitionConfigService.getByDefId(processDefinition.getId());
-                if (definitionVo != null) {
-                    wfDefinitionConfigService.deleteByDefIds(Collections.singletonList(processDefinition.getId()));
-                    WfDefinitionConfigBo wfFormDefinition = new WfDefinitionConfigBo();
-                    wfFormDefinition.setDefinitionId(definition.getId());
-                    wfFormDefinition.setProcessKey(definition.getKey());
-                    wfFormDefinition.setTableName(definitionVo.getTableName());
-                    wfFormDefinition.setVersion(definition.getVersion());
-                    wfFormDefinition.setRemark(definitionVo.getRemark());
-                    wfDefinitionConfigService.saveOrUpdate(wfFormDefinition);
-                }
-            }
-            //鏇存柊娴佺▼鑺傜偣閰嶇疆琛ㄥ崟
-            List<UserTask> userTasks = ModelUtils.getUserTaskFlowElements(definition.getId());
-            UserTask applyUserTask = ModelUtils.getApplyUserTask(definition.getId());
-            List<WfNodeConfig> wfNodeConfigList = new ArrayList<>();
-            for (UserTask userTask : userTasks) {
-                if (StringUtils.isNotBlank(userTask.getFormKey()) && userTask.getFormKey().contains(StrUtil.COLON)) {
-                    WfNodeConfig wfNodeConfig = new WfNodeConfig();
-                    wfNodeConfig.setNodeId(userTask.getId());
-                    wfNodeConfig.setNodeName(userTask.getName());
-                    wfNodeConfig.setDefinitionId(definition.getId());
-                    String[] split = userTask.getFormKey().split(StrUtil.COLON);
-                    wfNodeConfig.setFormType(split[0]);
-                    wfNodeConfig.setFormId(Long.valueOf(split[1]));
-                    wfNodeConfig.setApplyUserTask(applyUserTask.getId().equals(userTask.getId()) ? FlowConstant.TRUE : FlowConstant.FALSE);
-                    wfNodeConfigList.add(wfNodeConfig);
-                }
-            }
-            if (CollUtil.isNotEmpty(wfNodeConfigList)) {
-                wfNodeConfigService.saveOrUpdate(wfNodeConfigList);
-            }
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 瀵煎嚭妯″瀷zip鍘嬬缉鍖�
-     *
-     * @param modelIds 妯″瀷id
-     * @param response 鐩稿簲
-     */
-    @Override
-    public void exportZip(List<String> modelIds, HttpServletResponse response) {
-        try (ZipOutputStream zos = ZipUtil.getZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8)) {
-            // 鍘嬬缉鍖呮枃浠跺悕
-            String zipName = "妯″瀷涓嶅瓨鍦�";
-            // 鏌ヨ妯″瀷鍩烘湰淇℃伅
-            for (String modelId : modelIds) {
-                Model model = repositoryService.getModel(modelId);
-                byte[] xmlBytes = repositoryService.getModelEditorSource(modelId);
-                if (ObjectUtil.isNotNull(model)) {
-                    if (JSONUtil.isTypeJSON(new String(xmlBytes, StandardCharsets.UTF_8)) && ArrayUtil.isEmpty(ModelUtils.bpmnJsonToXmlBytes(xmlBytes))) {
-                        zipName = "妯″瀷涓嶈兘涓虹┖锛岃鑷冲皯璁捐涓�鏉′富绾挎祦绋嬶紒";
-                        zos.putNextEntry(new ZipEntry(zipName + ".txt"));
-                        zos.write(zipName.getBytes(StandardCharsets.UTF_8));
-                    } else if (ArrayUtil.isEmpty(xmlBytes)) {
-                        zipName = "妯″瀷鏁版嵁涓虹┖锛岃鍏堣璁℃祦绋嬪畾涔夋ā鍨嬶紝鍐嶈繘琛岄儴缃诧紒";
-                        zos.putNextEntry(new ZipEntry(zipName + ".txt"));
-                        zos.write(zipName.getBytes(StandardCharsets.UTF_8));
-                    } else {
-                        String fileName = model.getName() + "-" + model.getKey();
-                        // 鍘嬬缉鍖呮枃浠跺悕
-                        zipName = fileName + ".zip";
-                        // 灏唜ml娣诲姞鍒板帇缂╁寘涓�(鎸囧畾xml鏂囦欢鍚嶏細璇峰亣娴佺▼.bpmn20.xml
-                        zos.putNextEntry(new ZipEntry(fileName + ".bpmn20.xml"));
-                        zos.write(xmlBytes);
-                    }
-                }
-            }
-            response.setHeader("Content-Disposition",
-                "attachment; filename=" + URLEncoder.encode(zipName, StandardCharsets.UTF_8) + ".zip");
-            response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
-            // 鍒峰嚭鍝嶅簲娴�
-            response.flushBuffer();
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        }
-    }
-
-    /**
-     * 澶嶅埗妯″瀷
-     *
-     * @param modelBo 妯″瀷鏁版嵁
-     * @return 缁撴灉
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean copyModel(ModelBo modelBo) {
-        try {
-            String key = modelBo.getKey();
-            if (StringUtils.isNotBlank(key)) {
-                // 鏌ヨ妯″瀷
-                Model model = repositoryService.createModelQuery().modelId(modelBo.getId()).singleResult();
-                if (ObjectUtil.isNotNull(model)) {
-                    byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
-                    List<Model> list = QueryUtils.modelQuery().modelKey(key).list();
-                    if (CollUtil.isNotEmpty(list)) {
-                        throw new ServiceException("妯″瀷KEY宸插瓨鍦紒");
-                    }
-                    // 鏍¢獙key鍛藉悕瑙勮寖
-                    if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) {
-                        throw new ServiceException("妯″瀷鏍囪瘑KEY鍙兘瀛楃鎴栬�呬笅鍒掔嚎寮�澶达紒");
-                    }
-                    // 澶嶅埗妯″瀷鏁版嵁
-                    Model newModel = repositoryService.newModel();
-                    newModel.setKey(modelBo.getKey());
-                    newModel.setName(modelBo.getName());
-                    newModel.setCategory(modelBo.getCategoryCode());
-                    newModel.setVersion(1);
-                    newModel.setMetaInfo(modelBo.getDescription());
-                    newModel.setTenantId(TenantHelper.getTenantId());
-                    String xml = StrUtil.utf8Str(modelEditorSource);
-                    BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xml);
-                    Process mainProcess = bpmnModel.getMainProcess();
-                    mainProcess.setId(modelBo.getKey());
-                    mainProcess.setName(modelBo.getName());
-                    byte[] xmlBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
-                    repositoryService.saveModel(newModel);
-                    repositoryService.addModelEditorSource(newModel.getId(), xmlBytes);
-                }
-            }
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-        return true;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
deleted file mode 100644
index 77fb257..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
+++ /dev/null
@@ -1,444 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.codec.Base64;
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.dromara.common.core.exception.ServiceException;
-import org.dromara.common.core.utils.StreamUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.workflow.common.constant.FlowConstant;
-import org.dromara.workflow.domain.WfCategory;
-import org.dromara.workflow.domain.WfDefinitionConfig;
-import org.dromara.workflow.domain.WfNodeConfig;
-import org.dromara.workflow.domain.bo.ProcessDefinitionBo;
-import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
-import org.dromara.workflow.domain.vo.ProcessDefinitionVo;
-import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
-import org.dromara.workflow.mapper.WfDefinitionConfigMapper;
-import org.dromara.workflow.service.IActProcessDefinitionService;
-import org.dromara.workflow.service.IWfCategoryService;
-import org.dromara.workflow.service.IWfDefinitionConfigService;
-import org.dromara.workflow.service.IWfNodeConfigService;
-import org.dromara.workflow.utils.ModelUtils;
-import org.dromara.workflow.utils.QueryUtils;
-import org.flowable.bpmn.model.UserTask;
-import org.flowable.engine.ProcessMigrationService;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.history.HistoricProcessInstance;
-import org.flowable.engine.impl.bpmn.deployer.ResourceNameUtil;
-import org.flowable.engine.repository.*;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-/**
- * 娴佺▼瀹氫箟 鏈嶅姟灞傚疄鐜�
- *
- * @author may
- */
-@Slf4j
-@RequiredArgsConstructor
-@Service
-public class ActProcessDefinitionServiceImpl implements IActProcessDefinitionService {
-
-    @Autowired(required = false)
-    private RepositoryService repositoryService;
-    @Autowired(required = false)
-    private ProcessMigrationService processMigrationService;
-    private final IWfCategoryService wfCategoryService;
-    private final IWfDefinitionConfigService wfDefinitionConfigService;
-    private final WfDefinitionConfigMapper wfDefinitionConfigMapper;
-    private final IWfNodeConfigService wfNodeConfigService;
-
-    /**
-     * 鍒嗛〉鏌ヨ
-     *
-     * @param bo 鍙傛暟
-     * @return 杩斿洖鍒嗛〉鍒楄〃
-     */
-    @Override
-    public TableDataInfo<ProcessDefinitionVo> page(ProcessDefinitionBo bo, PageQuery pageQuery) {
-        ProcessDefinitionQuery query = QueryUtils.definitionQuery();
-        if (StringUtils.isNotEmpty(bo.getKey())) {
-            query.processDefinitionKey(bo.getKey());
-        }
-        if (StringUtils.isNotEmpty(bo.getCategoryCode())) {
-            query.processDefinitionCategory(bo.getCategoryCode());
-        }
-        if (StringUtils.isNotEmpty(bo.getName())) {
-            query.processDefinitionNameLike("%" + bo.getName() + "%");
-        }
-        query.orderByDeploymentId().desc();
-        // 鍒嗛〉鏌ヨ
-        List<ProcessDefinitionVo> processDefinitionVoList = new ArrayList<>();
-        List<ProcessDefinition> definitionList = query.latestVersion().listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
-        List<Deployment> deploymentList = null;
-        if (CollUtil.isNotEmpty(definitionList)) {
-            List<String> deploymentIds = StreamUtils.toList(definitionList, ProcessDefinition::getDeploymentId);
-            deploymentList = QueryUtils.deploymentQuery(deploymentIds).list();
-        }
-        if (CollUtil.isNotEmpty(definitionList)) {
-            List<String> ids = StreamUtils.toList(definitionList, ProcessDefinition::getId);
-            List<WfDefinitionConfigVo> wfDefinitionConfigVos = wfDefinitionConfigService.queryList(ids);
-            for (ProcessDefinition processDefinition : definitionList) {
-                ProcessDefinitionVo processDefinitionVo = BeanUtil.toBean(processDefinition, ProcessDefinitionVo.class);
-                if (CollUtil.isNotEmpty(deploymentList)) {
-                    // 閮ㄧ讲鏃堕棿
-                    deploymentList.stream().filter(e -> e.getId().equals(processDefinition.getDeploymentId())).findFirst().ifPresent(e -> {
-                        processDefinitionVo.setDeploymentTime(e.getDeploymentTime());
-                    });
-                }
-                if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) {
-                    wfDefinitionConfigVos.stream().filter(e -> e.getDefinitionId().equals(processDefinition.getId())).findFirst().ifPresent(processDefinitionVo::setWfDefinitionConfigVo);
-                }
-                processDefinitionVoList.add(processDefinitionVo);
-            }
-        }
-        // 鎬昏褰曟暟
-        long total = query.count();
-        TableDataInfo<ProcessDefinitionVo> build = TableDataInfo.build();
-        build.setRows(processDefinitionVoList);
-        build.setTotal(total);
-        return build;
-    }
-
-    /**
-     * 鏌ヨ鍘嗗彶娴佺▼瀹氫箟鍒楄〃
-     *
-     * @param key 娴佺▼瀹氫箟key
-     */
-    @Override
-    public List<ProcessDefinitionVo> getListByKey(String key) {
-        List<ProcessDefinitionVo> processDefinitionVoList = new ArrayList<>();
-        ProcessDefinitionQuery query = QueryUtils.definitionQuery();
-        List<ProcessDefinition> definitionList = query.processDefinitionKey(key).list();
-        List<Deployment> deploymentList = null;
-        if (CollUtil.isNotEmpty(definitionList)) {
-            List<String> deploymentIds = StreamUtils.toList(definitionList, ProcessDefinition::getDeploymentId);
-            deploymentList = QueryUtils.deploymentQuery(deploymentIds).list();
-        }
-        if (CollUtil.isNotEmpty(definitionList)) {
-            List<String> ids = StreamUtils.toList(definitionList, ProcessDefinition::getId);
-            List<WfDefinitionConfigVo> wfDefinitionConfigVos = wfDefinitionConfigService.queryList(ids);
-            for (ProcessDefinition processDefinition : definitionList) {
-                ProcessDefinitionVo processDefinitionVo = BeanUtil.toBean(processDefinition, ProcessDefinitionVo.class);
-                if (CollUtil.isNotEmpty(deploymentList)) {
-                    // 閮ㄧ讲鏃堕棿
-                    deploymentList.stream().filter(e -> e.getId().equals(processDefinition.getDeploymentId())).findFirst().ifPresent(e -> {
-                        processDefinitionVo.setDeploymentTime(e.getDeploymentTime());
-                    });
-                    if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) {
-                        wfDefinitionConfigVos.stream().filter(e -> e.getDefinitionId().equals(processDefinition.getId())).findFirst().ifPresent(processDefinitionVo::setWfDefinitionConfigVo);
-                    }
-                }
-                processDefinitionVoList.add(processDefinitionVo);
-            }
-        }
-        return CollUtil.reverse(processDefinitionVoList);
-    }
-
-    /**
-     * 鏌ョ湅娴佺▼瀹氫箟鍥剧墖
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    @SneakyThrows
-    @Override
-    public String definitionImage(String processDefinitionId) {
-        InputStream inputStream = repositoryService.getProcessDiagram(processDefinitionId);
-        return Base64.encode(IoUtil.readBytes(inputStream));
-    }
-
-    /**
-     * 鏌ョ湅娴佺▼瀹氫箟xml鏂囦欢
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    @Override
-    public String definitionXml(String processDefinitionId) {
-        StringBuilder xml = new StringBuilder();
-        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);
-        InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
-        xml.append(IoUtil.read(inputStream, StandardCharsets.UTF_8));
-        return xml.toString();
-    }
-
-    /**
-     * 鍒犻櫎娴佺▼瀹氫箟
-     *
-     * @param deploymentIds        閮ㄧ讲id
-     * @param processDefinitionIds 娴佺▼瀹氫箟id
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean deleteDeployment(List<String> deploymentIds, List<String> processDefinitionIds) {
-        try {
-            List<HistoricProcessInstance> historicProcessInstances = QueryUtils.hisInstanceQuery().deploymentIdIn(deploymentIds).list();
-            if (CollUtil.isNotEmpty(historicProcessInstances)) {
-                Set<String> defIds = StreamUtils.toSet(historicProcessInstances, HistoricProcessInstance::getProcessDefinitionId);
-                List<ProcessDefinition> processDefinitions = QueryUtils.definitionQuery().processDefinitionIds(defIds).list();
-                if (CollUtil.isNotEmpty(processDefinitions)) {
-                    Set<String> keys = StreamUtils.toSet(processDefinitions, ProcessDefinition::getKey);
-                    throw new ServiceException("褰撳墠銆�" + String.join(",", keys) + "銆戞祦绋嬪畾涔夊凡琚娇鐢ㄤ笉鍙垹闄わ紒");
-                }
-            }
-            //鍒犻櫎娴佺▼瀹氫箟
-            for (String deploymentId : deploymentIds) {
-                repositoryService.deleteDeployment(deploymentId);
-            }
-            //鍒犻櫎娴佺▼瀹氫箟閰嶇疆
-            wfDefinitionConfigService.deleteByDefIds(processDefinitionIds);
-            //鍒犻櫎鑺傜偣閰嶇疆
-            wfNodeConfigService.deleteByDefIds(processDefinitionIds);
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 婵�娲绘垨鑰呮寕璧锋祦绋嬪畾涔�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    @Override
-    public boolean updateDefinitionState(String processDefinitionId) {
-        try {
-            ProcessDefinition processDefinition = QueryUtils.definitionQuery()
-                .processDefinitionId(processDefinitionId).singleResult();
-            //灏嗗綋鍓嶄负鎸傝捣鐘舵�佹洿鏂颁负婵�娲荤姸鎬�
-            //鍙傛暟璇存槑锛氬弬鏁�1锛氭祦绋嬪畾涔塱d,鍙傛暟2锛氭槸鍚︽縺娲伙紙true鏄惁绾ц仈瀵瑰簲娴佺▼瀹炰緥锛屾縺娲讳簡鍒欏搴旀祦绋嬪疄渚嬮兘鍙互瀹℃壒锛夛紝
-            //鍙傛暟3锛氫粈涔堟椂鍊欐縺娲伙紝濡傛灉涓簄ull鍒欑珛鍗虫縺娲伙紝濡傛灉涓哄叿浣撴椂闂村垯鍒拌揪姝ゆ椂闂村悗婵�娲�
-            if (processDefinition.isSuspended()) {
-                repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
-            } else {
-                repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
-            }
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException("鎿嶄綔澶辫触:" + e.getMessage());
-        }
-    }
-
-    /**
-     * 杩佺Щ娴佺▼瀹氫箟
-     *
-     * @param currentProcessDefinitionId 褰撳墠娴佺▼瀹氫箟id
-     * @param fromProcessDefinitionId    闇�瑕佽縼绉诲埌鐨勬祦绋嬪畾涔塱d
-     */
-
-    @Override
-    public boolean migrationDefinition(String currentProcessDefinitionId, String fromProcessDefinitionId) {
-        try {
-            // 杩佺Щ楠岃瘉
-            boolean migrationValid = processMigrationService.createProcessInstanceMigrationBuilder()
-                .migrateToProcessDefinition(currentProcessDefinitionId)
-                .validateMigrationOfProcessInstances(fromProcessDefinitionId)
-                .isMigrationValid();
-            if (!migrationValid) {
-                throw new ServiceException("娴佺▼瀹氫箟宸紓杩囧ぇ鏃犳硶杩佺Щ锛岃淇敼娴佺▼鍥�");
-            }
-            // 宸茬粨鏉熺殑娴佺▼瀹炰緥涓嶄細杩佺Щ
-            processMigrationService.createProcessInstanceMigrationBuilder()
-                .migrateToProcessDefinition(currentProcessDefinitionId)
-                .migrateProcessInstances(fromProcessDefinitionId);
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 娴佺▼瀹氫箟杞崲涓烘ā鍨�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    @Override
-    public boolean convertToModel(String processDefinitionId) {
-        ProcessDefinition pd = QueryUtils.definitionQuery()
-            .processDefinitionId(processDefinitionId).singleResult();
-        InputStream inputStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), pd.getResourceName());
-        ModelQuery query = QueryUtils.modelQuery();
-        Model model = query.modelKey(pd.getKey()).singleResult();
-        try {
-            if (ObjectUtil.isNotNull(model)) {
-                repositoryService.addModelEditorSource(model.getId(), IoUtil.readBytes(inputStream));
-            } else {
-                Model modelData = repositoryService.newModel();
-                modelData.setKey(pd.getKey());
-                modelData.setName(pd.getName());
-                modelData.setCategory(pd.getCategory());
-                modelData.setTenantId(pd.getTenantId());
-                repositoryService.saveModel(modelData);
-                repositoryService.addModelEditorSource(modelData.getId(), IoUtil.readBytes(inputStream));
-            }
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 閫氳繃zip鎴杧ml閮ㄧ讲娴佺▼瀹氫箟
-     *
-     * @param file         鏂囦欢
-     * @param categoryCode 鍒嗙被
-     */
-    @SneakyThrows
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void deployByFile(MultipartFile file, String categoryCode) {
-
-        WfCategory wfCategory = wfCategoryService.queryByCategoryCode(categoryCode);
-        if (wfCategory == null) {
-            throw new ServiceException("娴佺▼鍒嗙被涓嶅瓨鍦�");
-        }
-        // 鏂囦欢鍚庣紑鍚�
-        String suffix = FileUtil.extName(file.getOriginalFilename());
-        InputStream inputStream = file.getInputStream();
-        if (FlowConstant.ZIP.equalsIgnoreCase(suffix)) {
-            ZipInputStream zipInputStream = null;
-            try {
-                zipInputStream = new ZipInputStream(inputStream);
-                ZipEntry zipEntry;
-                while ((zipEntry = zipInputStream.getNextEntry()) != null) {
-                    String filename = zipEntry.getName();
-                    String[] splitFilename = filename.substring(0, filename.lastIndexOf(".")).split("-");
-                    //娴佺▼鍚嶇О
-                    String processName = splitFilename[0];
-                    //娴佺▼key
-                    String processKey = splitFilename[1];
-                    ProcessDefinition oldProcessDefinition = QueryUtils.definitionQuery().processDefinitionKey(processKey).latestVersion().singleResult();
-                    DeploymentBuilder builder = repositoryService.createDeployment();
-                    Deployment deployment = builder.addInputStream(filename, zipInputStream)
-                        .tenantId(TenantHelper.getTenantId())
-                        .name(processName).key(processKey).category(categoryCode).deploy();
-                    ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult();
-                    repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode);
-                    setWfConfig(oldProcessDefinition, definition);
-                    zipInputStream.closeEntry();
-                }
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            } finally {
-                if (zipInputStream != null) {
-                    zipInputStream.close();
-                }
-            }
-            //鍒濆鍖栭厤缃暟鎹紙demo浣跨敤锛屼笉鐢ㄥ彲鍒犻櫎锛�
-            initWfDefConfig();
-        } else {
-            String originalFilename = file.getOriginalFilename();
-            if (StringUtils.containsAny(originalFilename, ResourceNameUtil.BPMN_RESOURCE_SUFFIXES)) {
-                // 鏂囦欢鍚� = 娴佺▼鍚嶇О-娴佺▼key
-                String[] splitFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")).split("-");
-                if (splitFilename.length < 2) {
-                    throw new ServiceException("鏂囦欢鍚� = 娴佺▼鍚嶇О-娴佺▼KEY");
-                }
-                //娴佺▼鍚嶇О
-                String processName = splitFilename[0];
-                //娴佺▼key
-                String processKey = splitFilename[1];
-                ProcessDefinition oldProcessDefinition = QueryUtils.definitionQuery().processDefinitionKey(processKey).latestVersion().singleResult();
-                DeploymentBuilder builder = repositoryService.createDeployment();
-                Deployment deployment = builder.addInputStream(originalFilename, inputStream)
-                    .tenantId(TenantHelper.getTenantId())
-                    .name(processName).key(processKey).category(categoryCode).deploy();
-                // 鏇存柊鍒嗙被
-                ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult();
-                repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode);
-                setWfConfig(oldProcessDefinition, definition);
-            } else {
-                throw new ServiceException("鏂囦欢绫诲瀷涓婁紶閿欒锛�");
-            }
-        }
-
-    }
-
-    /**
-     * 鍒濆鍖栭厤缃暟鎹紙demo浣跨敤锛屼笉鐢ㄥ彲鍒犻櫎锛�
-     */
-    private void initWfDefConfig() {
-        List<WfDefinitionConfig> wfDefinitionConfigs = wfDefinitionConfigMapper.selectList();
-        if (CollUtil.isEmpty(wfDefinitionConfigs)) {
-            ProcessDefinition processDefinition = QueryUtils.definitionQuery().processDefinitionKey("leave1").latestVersion().singleResult();
-            if (processDefinition != null) {
-                WfDefinitionConfigBo wfDefinitionConfigBo = new WfDefinitionConfigBo();
-                wfDefinitionConfigBo.setDefinitionId(processDefinition.getId());
-                wfDefinitionConfigBo.setProcessKey(processDefinition.getKey());
-                wfDefinitionConfigBo.setTableName("test_leave");
-                wfDefinitionConfigBo.setVersion(processDefinition.getVersion());
-                wfDefinitionConfigService.saveOrUpdate(wfDefinitionConfigBo);
-            }
-        }
-
-    }
-
-    /**
-     * 璁剧疆琛ㄥ崟鍐呭
-     *
-     * @param oldProcessDefinition 閮ㄧ讲鍓嶆渶鏂版祦绋嬪畾涔�
-     * @param definition           閮ㄧ讲鍚庢渶鏂版祦绋嬪畾涔�
-     */
-    private void setWfConfig(ProcessDefinition oldProcessDefinition, ProcessDefinition definition) {
-        //鏇存柊娴佺▼瀹氫箟琛ㄥ崟
-        if (oldProcessDefinition != null) {
-            WfDefinitionConfigVo definitionVo = wfDefinitionConfigService.getByDefId(oldProcessDefinition.getId());
-            if (definitionVo != null) {
-                wfDefinitionConfigService.deleteByDefIds(Collections.singletonList(oldProcessDefinition.getId()));
-                WfDefinitionConfigBo wfDefinitionConfigBo = new WfDefinitionConfigBo();
-                wfDefinitionConfigBo.setDefinitionId(definition.getId());
-                wfDefinitionConfigBo.setProcessKey(definition.getKey());
-                wfDefinitionConfigBo.setTableName(definitionVo.getTableName());
-                wfDefinitionConfigBo.setVersion(definition.getVersion());
-                wfDefinitionConfigBo.setRemark(definitionVo.getRemark());
-                wfDefinitionConfigService.saveOrUpdate(wfDefinitionConfigBo);
-            }
-        }
-        //鏇存柊娴佺▼鑺傜偣閰嶇疆琛ㄥ崟
-        List<UserTask> userTasks = ModelUtils.getUserTaskFlowElements(definition.getId());
-        UserTask applyUserTask = ModelUtils.getApplyUserTask(definition.getId());
-        List<WfNodeConfig> wfNodeConfigList = new ArrayList<>();
-        for (UserTask userTask : userTasks) {
-            if (StringUtils.isNotBlank(userTask.getFormKey()) && userTask.getFormKey().contains(StrUtil.COLON)) {
-                WfNodeConfig wfNodeConfig = new WfNodeConfig();
-                wfNodeConfig.setNodeId(userTask.getId());
-                wfNodeConfig.setNodeName(userTask.getName());
-                wfNodeConfig.setDefinitionId(definition.getId());
-                String[] split = userTask.getFormKey().split(StrUtil.COLON);
-                wfNodeConfig.setFormType(split[0]);
-                wfNodeConfig.setFormId(Long.valueOf(split[1]));
-                wfNodeConfig.setApplyUserTask(applyUserTask.getId().equals(userTask.getId()) ? FlowConstant.TRUE : FlowConstant.FALSE);
-                wfNodeConfigList.add(wfNodeConfig);
-            }
-        }
-        if (CollUtil.isNotEmpty(wfNodeConfigList)) {
-            wfNodeConfigService.saveOrUpdate(wfNodeConfigList);
-        }
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
deleted file mode 100644
index 8b9b113..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
+++ /dev/null
@@ -1,691 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.codec.Base64;
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.ObjectUtil;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.dromara.common.core.enums.BusinessStatusEnum;
-import org.dromara.common.core.exception.ServiceException;
-import org.dromara.common.core.service.UserService;
-import org.dromara.common.core.utils.StreamUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.satoken.utils.LoginHelper;
-import org.dromara.workflow.common.constant.FlowConstant;
-import org.dromara.workflow.common.enums.TaskStatusEnum;
-import org.dromara.workflow.domain.ActHiProcinst;
-import org.dromara.workflow.domain.bo.ProcessInstanceBo;
-import org.dromara.workflow.domain.bo.ProcessInvalidBo;
-import org.dromara.workflow.domain.bo.TaskUrgingBo;
-import org.dromara.workflow.domain.vo.*;
-import org.dromara.workflow.flowable.CustomDefaultProcessDiagramGenerator;
-import org.dromara.workflow.flowable.cmd.DeleteExecutionCmd;
-import org.dromara.workflow.flowable.cmd.ExecutionChildByExecutionIdCmd;
-import org.dromara.workflow.flowable.handler.FlowProcessEventHandler;
-import org.dromara.workflow.service.IActHiProcinstService;
-import org.dromara.workflow.service.IActProcessInstanceService;
-import org.dromara.workflow.service.IWfNodeConfigService;
-import org.dromara.workflow.service.IWfTaskBackNodeService;
-import org.dromara.workflow.utils.QueryUtils;
-import org.dromara.workflow.utils.WorkflowUtils;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.engine.*;
-import org.flowable.engine.history.HistoricActivityInstance;
-import org.flowable.engine.history.HistoricProcessInstance;
-import org.flowable.engine.history.HistoricProcessInstanceQuery;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
-import org.flowable.engine.repository.ProcessDefinition;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.engine.runtime.ProcessInstanceQuery;
-import org.flowable.engine.task.Attachment;
-import org.flowable.engine.task.Comment;
-import org.flowable.task.api.Task;
-import org.flowable.task.api.history.HistoricTaskInstance;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.awt.*;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.*;
-
-/**
- * 娴佺▼瀹炰緥 鏈嶅姟灞傚疄鐜�
- *
- * @author may
- */
-@Slf4j
-@RequiredArgsConstructor
-@Service
-public class ActProcessInstanceServiceImpl implements IActProcessInstanceService {
-
-    @Autowired(required = false)
-    private RepositoryService repositoryService;
-    @Autowired(required = false)
-    private RuntimeService runtimeService;
-    @Autowired(required = false)
-    private HistoryService historyService;
-    @Autowired(required = false)
-    private TaskService taskService;
-    @Autowired(required = false)
-    private ManagementService managementService;
-    private final IActHiProcinstService actHiProcinstService;
-    private final IWfTaskBackNodeService wfTaskBackNodeService;
-    private final IWfNodeConfigService wfNodeConfigService;
-    private final FlowProcessEventHandler flowProcessEventHandler;
-    private final UserService userService;
-
-    @Value("${flowable.activity-font-name}")
-    private String activityFontName;
-
-    @Value("${flowable.label-font-name}")
-    private String labelFontName;
-
-    @Value("${flowable.annotation-font-name}")
-    private String annotationFontName;
-
-    /**
-     * 鍒嗛〉鏌ヨ姝e湪杩愯鐨勬祦绋嬪疄渚�
-     *
-     * @param bo 鍙傛暟
-     */
-    @Override
-    public TableDataInfo<ProcessInstanceVo> getPageByRunning(ProcessInstanceBo bo, PageQuery pageQuery) {
-        List<ProcessInstanceVo> list = new ArrayList<>();
-        ProcessInstanceQuery query = QueryUtils.instanceQuery();
-        if (StringUtils.isNotBlank(bo.getName())) {
-            query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%");
-        }
-        if (StringUtils.isNotBlank(bo.getKey())) {
-            query.processDefinitionKey(bo.getKey());
-        }
-        if (StringUtils.isNotBlank(bo.getStartUserId())) {
-            query.startedBy(bo.getStartUserId());
-        }
-        if (StringUtils.isNotBlank(bo.getBusinessKey())) {
-            query.processInstanceBusinessKey(bo.getBusinessKey());
-        }
-        if (StringUtils.isNotBlank(bo.getCategoryCode())) {
-            query.processDefinitionCategory(bo.getCategoryCode());
-        }
-        query.orderByStartTime().desc();
-        List<ProcessInstance> processInstances = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
-        for (ProcessInstance processInstance : processInstances) {
-            ProcessInstanceVo processInstanceVo = BeanUtil.toBean(processInstance, ProcessInstanceVo.class);
-            processInstanceVo.setIsSuspended(processInstance.isSuspended());
-            processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstance.getBusinessStatus()));
-            list.add(processInstanceVo);
-        }
-        if (CollUtil.isNotEmpty(list)) {
-            List<String> processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId);
-            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
-            for (ProcessInstanceVo processInstanceVo : list) {
-                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo);
-                }
-            }
-        }
-        long count = query.count();
-        TableDataInfo<ProcessInstanceVo> build = TableDataInfo.build();
-        build.setRows(list);
-        build.setTotal(count);
-        return build;
-    }
-
-    /**
-     * 鍒嗛〉鏌ヨ宸茬粨鏉熺殑娴佺▼瀹炰緥
-     *
-     * @param bo 鍙傛暟
-     */
-    @Override
-    public TableDataInfo<ProcessInstanceVo> getPageByFinish(ProcessInstanceBo bo, PageQuery pageQuery) {
-        List<ProcessInstanceVo> list = new ArrayList<>();
-        HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery()
-            .finished().orderByProcessInstanceEndTime().desc();
-        if (StringUtils.isNotEmpty(bo.getName())) {
-            query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%");
-        }
-        if (StringUtils.isNotBlank(bo.getKey())) {
-            query.processDefinitionKey(bo.getKey());
-        }
-        if (StringUtils.isNotEmpty(bo.getStartUserId())) {
-            query.startedBy(bo.getStartUserId());
-        }
-        if (StringUtils.isNotBlank(bo.getBusinessKey())) {
-            query.processInstanceBusinessKey(bo.getBusinessKey());
-        }
-        if (StringUtils.isNotBlank(bo.getCategoryCode())) {
-            query.processDefinitionCategory(bo.getCategoryCode());
-        }
-        List<HistoricProcessInstance> historicProcessInstances = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
-        for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
-            ProcessInstanceVo processInstanceVo = BeanUtil.toBean(historicProcessInstance, ProcessInstanceVo.class);
-            processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(historicProcessInstance.getBusinessStatus()));
-            list.add(processInstanceVo);
-        }
-        if (CollUtil.isNotEmpty(list)) {
-            List<String> processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId);
-            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
-            for (ProcessInstanceVo processInstanceVo : list) {
-                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo);
-                }
-            }
-        }
-        long count = query.count();
-        TableDataInfo<ProcessInstanceVo> build = TableDataInfo.build();
-        build.setRows(list);
-        build.setTotal(count);
-        return build;
-    }
-
-    /**
-     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥�
-     *
-     * @param businessKey 涓氬姟id
-     */
-    @SneakyThrows
-    @Override
-    public String getHistoryImage(String businessKey) {
-        String processDefinitionId;
-        // 鑾峰彇褰撳墠鐨勬祦绋嬪疄渚�
-        ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey).singleResult();
-        // 濡傛灉娴佺▼宸茬粡缁撴潫锛屽垯寰楀埌缁撴潫鑺傜偣
-        if (Objects.isNull(processInstance)) {
-            HistoricProcessInstance pi = QueryUtils.hisInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
-            processDefinitionId = pi.getProcessDefinitionId();
-        } else {
-            // 鏍规嵁娴佺▼瀹炰緥ID鑾峰緱褰撳墠澶勪簬娲诲姩鐘舵�佺殑ActivityId鍚堥泦
-            ProcessInstance pi = QueryUtils.instanceQuery(processInstance.getProcessInstanceId()).singleResult();
-            processDefinitionId = pi.getProcessDefinitionId();
-        }
-
-        // 鑾峰緱娲诲姩鐨勮妭鐐�
-        List<HistoricActivityInstance> highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstance.getProcessInstanceId()).orderByHistoricActivityInstanceStartTime().asc().list();
-
-        List<String> highLightedFlows = new ArrayList<>();
-        List<String> highLightedNodes = new ArrayList<>();
-        //楂樹寒
-        for (HistoricActivityInstance tempActivity : highLightedFlowList) {
-            if (FlowConstant.SEQUENCE_FLOW.equals(tempActivity.getActivityType())) {
-                //楂樹寒绾�
-                highLightedFlows.add(tempActivity.getActivityId());
-            } else {
-                //楂樹寒鑺傜偣
-                if (tempActivity.getEndTime() == null) {
-                    highLightedNodes.add(Color.RED.toString() + tempActivity.getActivityId());
-                } else {
-                    highLightedNodes.add(tempActivity.getActivityId());
-                }
-            }
-        }
-        List<String> highLightedNodeList = new ArrayList<>();
-        //杩愯涓殑鑺傜偣
-        List<String> redNodeCollect = StreamUtils.filter(highLightedNodes, e -> e.contains(Color.RED.toString()));
-        //鎺掗櫎涓庤繍琛屼腑鐩稿悓鐨勮妭鐐�
-        for (String nodeId : highLightedNodes) {
-            if (!nodeId.contains(Color.RED.toString()) && !redNodeCollect.contains(Color.RED + nodeId)) {
-                highLightedNodeList.add(nodeId);
-            }
-        }
-        highLightedNodeList.addAll(redNodeCollect);
-        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
-        CustomDefaultProcessDiagramGenerator diagramGenerator = new CustomDefaultProcessDiagramGenerator();
-        InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodeList, highLightedFlows, activityFontName, labelFontName, annotationFontName, null, 1.0, true);
-        return Base64.encode(IoUtil.readBytes(inputStream));
-    }
-
-    /**
-     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥捐繍琛屼腑锛屽巻鍙茬瓑鑺傜偣
-     *
-     * @param businessKey 涓氬姟id
-     */
-    @Override
-    public Map<String, Object> getHistoryList(String businessKey) {
-        Map<String, Object> map = new HashMap<>();
-        List<Map<String, Object>> taskList = new ArrayList<>();
-        HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
-        String processInstanceId = historicProcessInstance.getId();
-        StringBuilder xml = new StringBuilder();
-        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
-        // 鑾峰彇鑺傜偣
-        List<HistoricActivityInstance> highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
-        for (HistoricActivityInstance tempActivity : highLightedFlowList) {
-            Map<String, Object> task = new HashMap<>();
-            switch (tempActivity.getActivityType()) {
-                case FlowConstant.SEQUENCE_FLOW, FlowConstant.PARALLEL_GATEWAY,
-                     FlowConstant.EXCLUSIVE_GATEWAY, FlowConstant.INCLUSIVE_GATEWAY -> {}
-                default -> {
-                    task.put("key", tempActivity.getActivityId());
-                    task.put("completed", tempActivity.getEndTime() != null);
-                    task.put("activityType", tempActivity.getActivityType());
-                    taskList.add(task);
-                }
-            }
-        }
-        ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId).singleResult();
-        if (processInstance != null) {
-            taskList = StreamUtils.filter(taskList, e -> !e.get("activityType").equals(FlowConstant.END_EVENT));
-        }
-        //鏌ヨ鍑鸿繍琛屼腑鑺傜偣
-        List<Map<String, Object>> runtimeNodeList = StreamUtils.filter(taskList, e -> !(Boolean) e.get("completed"));
-        if (CollUtil.isNotEmpty(runtimeNodeList)) {
-            Iterator<Map<String, Object>> iterator = taskList.iterator();
-            while (iterator.hasNext()) {
-                Map<String, Object> next = iterator.next();
-                runtimeNodeList.stream().filter(t -> t.get("key").equals(next.get("key")) && (Boolean) next.get("completed")).findFirst().ifPresent(t -> iterator.remove());
-            }
-        }
-        map.put("taskList", taskList);
-        List<ActHistoryInfoVo> historyTaskList = getHistoryTaskList(processInstanceId, processDefinition.getVersion());
-        map.put("historyList", historyTaskList);
-        InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
-        xml.append(IoUtil.read(inputStream, StandardCharsets.UTF_8));
-        map.put("xml", xml.toString());
-        return map;
-    }
-
-    /**
-     * 鑾峰彇鍘嗗彶浠诲姟鑺傜偣淇℃伅
-     *
-     * @param processInstanceId 娴佺▼瀹炰緥id
-     * @param version           鐗堟湰
-     */
-    private List<ActHistoryInfoVo> getHistoryTaskList(String processInstanceId, Integer version) {
-        //鏌ヨ浠诲姟鍔炵悊璁板綍
-        List<HistoricTaskInstance> list = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list();
-        list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed());
-        List<ActHistoryInfoVo> actHistoryInfoVoList = new ArrayList<>();
-        for (HistoricTaskInstance historicTaskInstance : list) {
-            ActHistoryInfoVo actHistoryInfoVo = new ActHistoryInfoVo();
-            BeanUtils.copyProperties(historicTaskInstance, actHistoryInfoVo);
-            actHistoryInfoVo.setStatus(actHistoryInfoVo.getEndTime() == null ? "寰呭鐞�" : "宸插鐞�");
-            if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) {
-                actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis()));
-            }
-            actHistoryInfoVo.setVersion(version);
-            actHistoryInfoVoList.add(actHistoryInfoVo);
-        }
-        List<ActHistoryInfoVo> historyInfoVoList = new ArrayList<>();
-        Map<String, List<ActHistoryInfoVo>> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey);
-        for (Map.Entry<String, List<ActHistoryInfoVo>> entry : groupByKey.entrySet()) {
-            ActHistoryInfoVo historyInfoVo = new ActHistoryInfoVo();
-            if (entry.getValue().size() > 1) {
-                List<ActHistoryInfoVo> historyInfoVos = StreamUtils.filter(entry.getValue(), e -> StringUtils.isNotBlank(e.getAssignee()));
-                if (CollUtil.isNotEmpty(historyInfoVos)) {
-                    ActHistoryInfoVo infoVo = historyInfoVos.get(0);
-                    BeanUtils.copyProperties(infoVo, historyInfoVo);
-                    historyInfoVo.setStatus(infoVo.getEndTime() == null ? "寰呭鐞�" : "宸插鐞�");
-                    historyInfoVo.setStartTime(infoVo.getStartTime());
-                    historyInfoVo.setEndTime(infoVo.getEndTime() == null ? null : infoVo.getEndTime());
-                    historyInfoVo.setRunDuration(infoVo.getEndTime() == null ? null : infoVo.getRunDuration());
-                    if (ObjectUtil.isEmpty(infoVo.getAssignee())) {
-                        ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(infoVo.getId(), userService);
-                        if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
-                            historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
-                        }
-                    }
-                }
-            } else {
-                actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey())).findFirst()
-                    .ifPresent(e -> {
-                        BeanUtils.copyProperties(e, historyInfoVo);
-                        historyInfoVo.setStatus(e.getEndTime() == null ? "寰呭鐞�" : "宸插鐞�");
-                        historyInfoVo.setStartTime(e.getStartTime());
-                        historyInfoVo.setEndTime(e.getEndTime() == null ? null : e.getEndTime());
-                        historyInfoVo.setRunDuration(e.getEndTime() == null ? null : e.getRunDuration());
-                        if (ObjectUtil.isEmpty(e.getAssignee())) {
-                            ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(e.getId(), userService);
-                            if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
-                                historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
-                            }
-                        }
-                    });
-
-            }
-            historyInfoVoList.add(historyInfoVo);
-
-        }
-        return historyInfoVoList;
-    }
-
-    /**
-     * 鑾峰彇瀹℃壒璁板綍
-     *
-     * @param businessKey 涓氬姟id
-     */
-    @Override
-    public List<ActHistoryInfoVo> getHistoryRecord(String businessKey) {
-        // 鏌ヨ浠诲姟鍔炵悊璁板綍
-        List<HistoricTaskInstance> list = QueryUtils.hisTaskBusinessKeyQuery(businessKey).orderByHistoricTaskInstanceEndTime().desc().list();
-        list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed());
-        HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
-        String processInstanceId = historicProcessInstance.getId();
-        List<ActHistoryInfoVo> actHistoryInfoVoList = new ArrayList<>();
-        List<Comment> processInstanceComments = taskService.getProcessInstanceComments(processInstanceId);
-        //闄勪欢
-        List<Attachment> attachmentList = taskService.getProcessInstanceAttachments(processInstanceId);
-        for (HistoricTaskInstance historicTaskInstance : list) {
-            ActHistoryInfoVo actHistoryInfoVo = new ActHistoryInfoVo();
-            BeanUtils.copyProperties(historicTaskInstance, actHistoryInfoVo);
-            if (actHistoryInfoVo.getEndTime() == null) {
-                actHistoryInfoVo.setStatus(TaskStatusEnum.WAITING.getStatus());
-                actHistoryInfoVo.setStatusName(TaskStatusEnum.WAITING.getDesc());
-            }
-            if (CollUtil.isNotEmpty(processInstanceComments)) {
-                processInstanceComments.stream().filter(e -> e.getTaskId().equals(historicTaskInstance.getId())).findFirst().ifPresent(e -> {
-                    actHistoryInfoVo.setComment(e.getFullMessage());
-                    actHistoryInfoVo.setStatus(e.getType());
-                    actHistoryInfoVo.setStatusName(TaskStatusEnum.findByStatus(e.getType()));
-                });
-            }
-            if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) {
-                actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis()));
-            }
-            //闄勪欢
-            if (CollUtil.isNotEmpty(attachmentList)) {
-                List<Attachment> attachments = StreamUtils.filter(attachmentList, e -> e.getTaskId().equals(historicTaskInstance.getId()));
-                if (CollUtil.isNotEmpty(attachments)) {
-                    actHistoryInfoVo.setAttachmentList(attachments);
-                }
-            }
-            //璁剧疆浜哄憳id
-            if (ObjectUtil.isEmpty(historicTaskInstance.getAssignee())) {
-                ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(historicTaskInstance.getId(), userService);
-                if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
-                    actHistoryInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
-                }
-            }
-            actHistoryInfoVoList.add(actHistoryInfoVo);
-        }
-        // 瀹℃壒璁板綍
-        Map<String, List<ActHistoryInfoVo>> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey);
-        for (Map.Entry<String, List<ActHistoryInfoVo>> entry : groupByKey.entrySet()) {
-            ActHistoryInfoVo actHistoryInfoVo = BeanUtil.toBean(entry.getValue().get(0), ActHistoryInfoVo.class);
-            actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() != null).findFirst()
-                .ifPresent(e -> {
-                    actHistoryInfoVo.setStatus("宸插鐞�");
-                    actHistoryInfoVo.setStartTime(e.getStartTime());
-                });
-            actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() == null).findFirst()
-                .ifPresent(e -> {
-                    actHistoryInfoVo.setStatus("寰呭鐞�");
-                    actHistoryInfoVo.setStartTime(e.getStartTime());
-                    actHistoryInfoVo.setEndTime(null);
-                    actHistoryInfoVo.setRunDuration(null);
-                });
-        }
-        List<ActHistoryInfoVo> recordList = new ArrayList<>();
-        // 寰呭姙鐞�
-        recordList.addAll(StreamUtils.filter(actHistoryInfoVoList, e -> e.getEndTime() == null));
-        // 宸插姙鐞�
-        recordList.addAll(StreamUtils.filter(actHistoryInfoVoList, e -> e.getEndTime() != null));
-
-        return recordList;
-    }
-
-    /**
-     * 浠诲姟瀹屾垚鏃堕棿澶勭悊
-     *
-     * @param time 鏃堕棿
-     */
-    private String getDuration(long time) {
-
-        long day = time / (24 * 60 * 60 * 1000);
-        long hour = (time / (60 * 60 * 1000) - day * 24);
-        long minute = ((time / (60 * 1000)) - day * 24 * 60 - hour * 60);
-        long second = (time / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60);
-
-        if (day > 0) {
-            return day + "澶�" + hour + "灏忔椂" + minute + "鍒嗛挓";
-        }
-        if (hour > 0) {
-            return hour + "灏忔椂" + minute + "鍒嗛挓";
-        }
-        if (minute > 0) {
-            return minute + "鍒嗛挓";
-        }
-        if (second > 0) {
-            return second + "绉�";
-        } else {
-            return 0 + "绉�";
-        }
-    }
-
-    /**
-     * 浣滃簾娴佺▼瀹炰緥锛屼笉浼氬垹闄ゅ巻鍙茶褰�(鍒犻櫎杩愯涓殑瀹炰緥)
-     *
-     * @param processInvalidBo 鍙傛暟
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean deleteRunInstance(ProcessInvalidBo processInvalidBo) {
-        try {
-            List<Task> list = QueryUtils.taskQuery().processInstanceBusinessKey(processInvalidBo.getBusinessKey()).list();
-            String processInstanceId = list.get(0).getProcessInstanceId();
-            List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
-            if (CollUtil.isNotEmpty(subTasks)) {
-                subTasks.forEach(e -> taskService.deleteTask(e.getId()));
-            }
-            String deleteReason = LoginHelper.getLoginUser().getNickname() + "浣滃簾浜嗗綋鍓嶇敵璇凤紒";
-            if (StringUtils.isNotBlank(processInvalidBo.getDeleteReason())) {
-                deleteReason = LoginHelper.getLoginUser().getNickname() + "浣滃簾鐞嗙敱:" + processInvalidBo.getDeleteReason();
-            }
-            for (Task task : StreamUtils.filter(list, e -> StringUtils.isBlank(e.getParentTaskId()))) {
-                taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.INVALID.getStatus(), deleteReason);
-            }
-            HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
-            BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus());
-            runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.INVALID.getStatus());
-            runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
-            //娴佺▼浣滃簾鐩戝惉
-            flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(),
-                historicProcessInstance.getBusinessKey(), BusinessStatusEnum.INVALID.getStatus(), false);
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
-     *
-     * @param businessKeys 涓氬姟id
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean deleteRunAndHisInstance(List<String> businessKeys) {
-        try {
-            // 1.鍒犻櫎杩愯涓祦绋嬪疄渚�
-            List<ActHiProcinst> actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys);
-            if (CollUtil.isEmpty(actHiProcinsts)) {
-                log.warn("褰撳墠涓氬姟ID:{}鏌ヨ鍒版祦绋嬪疄渚嬩负绌猴紒", businessKeys);
-                return false;
-            }
-            List<String> processInstanceIds = StreamUtils.toList(actHiProcinsts, ActHiProcinst::getId);
-            List<Task> list = QueryUtils.taskQuery(processInstanceIds).list();
-            List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
-            if (CollUtil.isNotEmpty(subTasks)) {
-                subTasks.forEach(e -> taskService.deleteTask(e.getId()));
-            }
-            runtimeService.bulkDeleteProcessInstances(processInstanceIds, LoginHelper.getUserId() + "鍒犻櫎浜嗗綋鍓嶆祦绋嬬敵璇�");
-            // 2.鍒犻櫎鍘嗗彶璁板綍
-            List<HistoricProcessInstance> historicProcessInstanceList = QueryUtils.hisInstanceQuery(new HashSet<>(processInstanceIds)).list();
-            if (ObjectUtil.isNotEmpty(historicProcessInstanceList)) {
-                historyService.bulkDeleteHistoricProcessInstances(processInstanceIds);
-            }
-            wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds);
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 宸插畬鎴愮殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
-     *
-     * @param businessKeys 涓氬姟id
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean deleteFinishAndHisInstance(List<String> businessKeys) {
-        try {
-            List<ActHiProcinst> actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys);
-            if (CollUtil.isEmpty(actHiProcinsts)) {
-                log.warn("褰撳墠涓氬姟ID:{}鏌ヨ鍒版祦绋嬪疄渚嬩负绌猴紒", businessKeys);
-                return false;
-            }
-            List<String> processInstanceIds = StreamUtils.toList(actHiProcinsts, ActHiProcinst::getId);
-            historyService.bulkDeleteHistoricProcessInstances(processInstanceIds);
-            wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds);
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 鎾ら攢娴佺▼鐢宠
-     *
-     * @param businessKey 涓氬姟id
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean cancelProcessApply(String businessKey) {
-        try {
-            ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey)
-                .startedBy(String.valueOf(LoginHelper.getUserId())).singleResult();
-            if (ObjectUtil.isNull(processInstance)) {
-                throw new ServiceException("鎮ㄤ笉鏄祦绋嬪彂璧蜂汉,鎾ら攢澶辫触!");
-            }
-            if (processInstance.isSuspended()) {
-                throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
-            }
-            String processInstanceId = processInstance.getId();
-            BusinessStatusEnum.checkCancelStatus(processInstance.getBusinessStatus());
-            List<Task> taskList = QueryUtils.taskQuery(processInstanceId).list();
-            for (Task task : taskList) {
-                taskService.setAssignee(task.getId(), null);
-                taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.CANCEL.getStatus(), LoginHelper.getLoginUser().getNickname() + "锛氭挙閿�鐢宠");
-            }
-            HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().asc().list().get(0);
-            List<String> nodeIds = StreamUtils.toList(taskList, Task::getTaskDefinitionKey);
-            runtimeService.createChangeActivityStateBuilder()
-                .processInstanceId(processInstanceId)
-                .moveActivityIdsToSingleActivityId(nodeIds, historicTaskInstance.getTaskDefinitionKey()).changeState();
-            Task task = QueryUtils.taskQuery(processInstanceId).list().get(0);
-            taskService.setAssignee(task.getId(), historicTaskInstance.getAssignee());
-            //鑾峰彇骞惰缃戝叧鎵ц鍚庝繚鐣欑殑鎵ц瀹炰緥鏁版嵁
-            ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId());
-            List<ExecutionEntity> executionEntities = managementService.executeCommand(childByExecutionIdCmd);
-            //鍒犻櫎娴佺▼瀹炰緥鍨冨溇鏁版嵁
-            for (ExecutionEntity executionEntity : executionEntities) {
-                DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId());
-                managementService.executeCommand(deleteExecutionCmd);
-            }
-            runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.CANCEL.getStatus());
-            //娴佺▼浣滃簾鐩戝惉
-            flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(),
-                processInstance.getBusinessKey(), BusinessStatusEnum.CANCEL.getStatus(), false);
-            return true;
-        } catch (Exception e) {
-            log.error("鎾ら攢澶辫触:" + e.getMessage(), e);
-            throw new ServiceException("鎾ら攢澶辫触:" + e.getMessage());
-        }
-    }
-
-    /**
-     * 鍒嗛〉鏌ヨ褰撳墠鐧诲綍浜哄崟鎹�
-     *
-     * @param bo 鍙傛暟
-     */
-    @Override
-    public TableDataInfo<ProcessInstanceVo> getPageByCurrent(ProcessInstanceBo bo, PageQuery pageQuery) {
-        List<ProcessInstanceVo> list = new ArrayList<>();
-        HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery();
-        query.startedBy(String.valueOf(LoginHelper.getUserId()));
-        if (StringUtils.isNotBlank(bo.getName())) {
-            query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%");
-        }
-        if (StringUtils.isNotBlank(bo.getKey())) {
-            query.processDefinitionKey(bo.getKey());
-        }
-        if (StringUtils.isNotBlank(bo.getBusinessKey())) {
-            query.processInstanceBusinessKey(bo.getBusinessKey());
-        }
-        if (StringUtils.isNotBlank(bo.getCategoryCode())) {
-            query.processDefinitionCategory(bo.getCategoryCode());
-        }
-        query.orderByProcessInstanceStartTime().desc();
-        List<HistoricProcessInstance> historicProcessInstanceList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
-        List<TaskVo> taskVoList = new ArrayList<>();
-        if (CollUtil.isNotEmpty(historicProcessInstanceList)) {
-            List<String> processInstanceIds = StreamUtils.toList(historicProcessInstanceList, HistoricProcessInstance::getId);
-            List<Task> taskList = QueryUtils.taskQuery(processInstanceIds).list();
-            for (Task task : taskList) {
-                taskVoList.add(BeanUtil.toBean(task, TaskVo.class));
-            }
-        }
-        for (HistoricProcessInstance processInstance : historicProcessInstanceList) {
-            ProcessInstanceVo processInstanceVo = BeanUtil.toBean(processInstance, ProcessInstanceVo.class);
-            processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstance.getBusinessStatus()));
-            if (CollUtil.isNotEmpty(taskVoList)) {
-                List<TaskVo> collect = StreamUtils.filter(taskVoList, e -> e.getProcessInstanceId().equals(processInstance.getId()));
-                processInstanceVo.setTaskVoList(CollUtil.isNotEmpty(collect) ? collect : Collections.emptyList());
-            }
-            list.add(processInstanceVo);
-        }
-        if (CollUtil.isNotEmpty(list)) {
-            List<String> processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId);
-            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
-            for (ProcessInstanceVo processInstanceVo : list) {
-                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo);
-                }
-            }
-        }
-        long count = query.count();
-        TableDataInfo<ProcessInstanceVo> build = TableDataInfo.build();
-        build.setRows(list);
-        build.setTotal(count);
-        return build;
-    }
-
-    /**
-     * 浠诲姟鍌姙(缁欏綋鍓嶄换鍔″姙鐞嗕汉鍙戦�佺珯鍐呬俊锛岄偖浠讹紝鐭俊绛�)
-     *
-     * @param taskUrgingBo 浠诲姟鍌姙
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean taskUrging(TaskUrgingBo taskUrgingBo) {
-        try {
-            ProcessInstance processInstance = QueryUtils.instanceQuery(taskUrgingBo.getProcessInstanceId()).singleResult();
-            if (processInstance == null) {
-                throw new ServiceException("浠诲姟宸茬粨鏉燂紒");
-            }
-            String message = taskUrgingBo.getMessage();
-            if (StringUtils.isBlank(message)) {
-                message = "鎮ㄧ殑銆�" + processInstance.getName() + "銆戝崟鎹繕鏈鎵癸紝璇锋偍鍙婃椂澶勭悊銆�";
-            }
-            List<Task> list = QueryUtils.taskQuery(taskUrgingBo.getProcessInstanceId()).list();
-            WorkflowUtils.sendMessage(list, processInstance.getName(), taskUrgingBo.getMessageType(), message, userService);
-        } catch (ServiceException e) {
-            throw new ServiceException(e.getMessage());
-        }
-        return true;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
deleted file mode 100644
index 5235d12..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
+++ /dev/null
@@ -1,858 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.dromara.common.core.domain.dto.RoleDTO;
-import org.dromara.common.core.domain.dto.UserDTO;
-import org.dromara.common.core.exception.ServiceException;
-import org.dromara.common.core.service.OssService;
-import org.dromara.common.core.service.UserService;
-import org.dromara.common.core.utils.StreamUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.satoken.utils.LoginHelper;
-import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.workflow.common.constant.FlowConstant;
-import org.dromara.common.core.enums.BusinessStatusEnum;
-import org.dromara.workflow.common.enums.TaskStatusEnum;
-import org.dromara.workflow.domain.ActHiTaskinst;
-import org.dromara.workflow.domain.WfTaskBackNode;
-import org.dromara.workflow.domain.bo.*;
-import org.dromara.workflow.domain.vo.*;
-import org.dromara.workflow.flowable.cmd.*;
-import org.dromara.workflow.flowable.handler.FlowProcessEventHandler;
-import org.dromara.workflow.mapper.ActHiTaskinstMapper;
-import org.dromara.workflow.mapper.ActTaskMapper;
-import org.dromara.workflow.service.IActTaskService;
-import org.dromara.workflow.service.IWfDefinitionConfigService;
-import org.dromara.workflow.service.IWfNodeConfigService;
-import org.dromara.workflow.service.IWfTaskBackNodeService;
-import org.dromara.workflow.utils.ModelUtils;
-import org.dromara.workflow.utils.QueryUtils;
-import org.dromara.workflow.utils.WorkflowUtils;
-import org.flowable.common.engine.api.FlowableObjectNotFoundException;
-import org.flowable.common.engine.impl.identity.Authentication;
-import org.flowable.engine.*;
-import org.flowable.engine.history.HistoricProcessInstance;
-import org.flowable.engine.history.HistoricProcessInstanceQuery;
-import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
-import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.identitylink.api.history.HistoricIdentityLink;
-import org.flowable.task.api.Task;
-import org.flowable.task.api.TaskQuery;
-import org.flowable.task.api.history.HistoricTaskInstance;
-import org.flowable.task.service.impl.persistence.entity.TaskEntity;
-import org.flowable.variable.api.persistence.entity.VariableInstance;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-import static org.dromara.workflow.common.constant.FlowConstant.*;
-
-/**
- * 浠诲姟 鏈嶅姟灞傚疄鐜�
- *
- * @author may
- */
-@Slf4j
-@RequiredArgsConstructor
-@Service
-public class ActTaskServiceImpl implements IActTaskService {
-
-    @Autowired(required = false)
-    private RuntimeService runtimeService;
-    @Autowired(required = false)
-    private TaskService taskService;
-    @Autowired(required = false)
-    private HistoryService historyService;
-    @Autowired(required = false)
-    private IdentityService identityService;
-    @Autowired(required = false)
-    private ManagementService managementService;
-    private final ActTaskMapper actTaskMapper;
-    private final IWfTaskBackNodeService wfTaskBackNodeService;
-    private final ActHiTaskinstMapper actHiTaskinstMapper;
-    private final IWfNodeConfigService wfNodeConfigService;
-    private final IWfDefinitionConfigService wfDefinitionConfigService;
-    private final FlowProcessEventHandler flowProcessEventHandler;
-    private final UserService userService;
-    private final OssService ossService;
-
-    /**
-     * 鍚姩浠诲姟
-     *
-     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Map<String, Object> startWorkFlow(StartProcessBo startProcessBo) {
-        Map<String, Object> map = new HashMap<>();
-        if (StringUtils.isBlank(startProcessBo.getBusinessKey())) {
-            throw new ServiceException("鍚姩宸ヤ綔娴佹椂蹇呴』鍖呭惈涓氬姟ID");
-        }
-        // 鍒ゆ柇褰撳墠涓氬姟鏄惁鍚姩杩囨祦绋�
-        HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery();
-        HistoricProcessInstance historicProcessInstance = query.processInstanceBusinessKey(startProcessBo.getBusinessKey()).singleResult();
-        if (ObjectUtil.isNotEmpty(historicProcessInstance)) {
-            BusinessStatusEnum.checkStartStatus(historicProcessInstance.getBusinessStatus());
-        }
-        List<Task> taskResult = QueryUtils.taskQuery().processInstanceBusinessKey(startProcessBo.getBusinessKey()).list();
-        if (CollUtil.isNotEmpty(taskResult)) {
-            if (CollUtil.isNotEmpty(startProcessBo.getVariables())) {
-                taskService.setVariables(taskResult.get(0).getId(), startProcessBo.getVariables());
-            }
-            map.put(PROCESS_INSTANCE_ID, taskResult.get(0).getProcessInstanceId());
-            map.put("taskId", taskResult.get(0).getId());
-            return map;
-        }
-        WfDefinitionConfigVo wfDefinitionConfigVo = wfDefinitionConfigService.getByTableNameLastVersion(startProcessBo.getTableName());
-        if (wfDefinitionConfigVo == null) {
-            throw new ServiceException("璇峰埌娴佺▼瀹氫箟缁戝畾涓氬姟琛ㄥ悕涓庢祦绋婯EY锛�");
-        }
-        // 璁剧疆鍚姩浜�
-        identityService.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId()));
-        Authentication.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId()));
-        // 鍚姩娴佺▼瀹炰緥锛堟彁浜ょ敵璇凤級
-        Map<String, Object> variables = startProcessBo.getVariables();
-        // 鍚姩璺宠繃琛ㄨ揪寮�
-        variables.put(FLOWABLE_SKIP_EXPRESSION_ENABLED, true);
-        // 娴佺▼鍙戣捣浜�
-        variables.put(INITIATOR, (String.valueOf(LoginHelper.getUserId())));
-        ProcessInstance pi;
-        try {
-            if (TenantHelper.isEnable()) {
-                pi = runtimeService.startProcessInstanceByKeyAndTenantId(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables, TenantHelper.getTenantId());
-            } else {
-                pi = runtimeService.startProcessInstanceByKey(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables);
-            }
-        } catch (FlowableObjectNotFoundException e) {
-            throw new ServiceException("鎵句笉鍒板綋鍓嶃��" + wfDefinitionConfigVo.getProcessKey() + "銆戞祦绋嬪畾涔夛紒");
-        }
-        // 灏嗘祦绋嬪畾涔夊悕绉� 浣滀负 娴佺▼瀹炰緥鍚嶇О
-        runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName());
-        // 鐢宠浜烘墽琛屾祦绋�
-        List<Task> taskList = QueryUtils.taskQuery(pi.getId()).list();
-        if (taskList.size() > 1) {
-            throw new ServiceException("璇锋鏌ユ祦绋嬬涓�涓幆鑺傛槸鍚︿负鐢宠浜猴紒");
-        }
-
-        runtimeService.updateBusinessStatus(pi.getProcessInstanceId(), BusinessStatusEnum.DRAFT.getStatus());
-        taskService.setAssignee(taskList.get(0).getId(), LoginHelper.getUserId().toString());
-        taskService.setVariable(taskList.get(0).getId(), PROCESS_INSTANCE_ID, pi.getProcessInstanceId());
-        taskService.setVariable(taskList.get(0).getId(), BUSINESS_KEY, pi.getBusinessKey());
-        map.put("processInstanceId", pi.getProcessInstanceId());
-        map.put("taskId", taskList.get(0).getId());
-        return map;
-    }
-
-    /**
-     * 鍔炵悊浠诲姟
-     *
-     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean completeTask(CompleteTaskBo completeTaskBo) {
-        try {
-            String userId = String.valueOf(LoginHelper.getUserId());
-            Task task = WorkflowUtils.getTaskByCurrentUser(completeTaskBo.getTaskId());
-            if (task == null) {
-                throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
-            }
-            if (task.isSuspended()) {
-                throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
-            }
-            ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
-            //鍔炵悊濮旀墭浠诲姟
-            if (ObjectUtil.isNotEmpty(task.getDelegationState()) && FlowConstant.PENDING.equals(task.getDelegationState().name())) {
-                taskService.resolveTask(completeTaskBo.getTaskId());
-                TaskEntity newTask = WorkflowUtils.createNewTask(task);
-                taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isNotBlank(completeTaskBo.getMessage()) ? completeTaskBo.getMessage() : StrUtil.EMPTY);
-                taskService.complete(newTask.getId());
-                return true;
-            }
-            //闄勪欢涓婁紶
-            AttachmentCmd attachmentCmd = new AttachmentCmd(completeTaskBo.getFileId(), task.getId(), task.getProcessInstanceId(), ossService);
-            managementService.executeCommand(attachmentCmd);
-            String businessStatus = WorkflowUtils.getBusinessStatus(processInstance.getBusinessKey());
-            //娴佺▼鎻愪氦鐩戝惉
-            if (BusinessStatusEnum.DRAFT.getStatus().equals(businessStatus) || BusinessStatusEnum.BACK.getStatus().equals(businessStatus) || BusinessStatusEnum.CANCEL.getStatus().equals(businessStatus)) {
-                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(), businessStatus, true);
-            }
-            runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.WAITING.getStatus());
-            //鍔炵悊鐩戝惉
-            flowProcessEventHandler.processTaskHandler(processInstance.getProcessDefinitionKey(), task.getTaskDefinitionKey(),
-                task.getId(), processInstance.getBusinessKey());
-            //鍔炵悊鎰忚
-            taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "鍚屾剰" : completeTaskBo.getMessage());
-            //鍔炵悊浠诲姟
-            taskService.setAssignee(task.getId(), userId);
-            if (CollUtil.isNotEmpty(completeTaskBo.getVariables())) {
-                taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables());
-            } else {
-                taskService.complete(completeTaskBo.getTaskId());
-            }
-            //璁板綍鎵ц杩囩殑娴佺▼浠诲姟鑺傜偣
-            wfTaskBackNodeService.recordExecuteNode(task);
-            ProcessInstance pi = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
-            if (pi == null) {
-                UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus());
-                managementService.executeCommand(updateBusinessStatusCmd);
-                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(),
-                    BusinessStatusEnum.FINISH.getStatus(), false);
-            } else {
-                List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
-                for (Task t : list) {
-                    if (ModelUtils.isUserTask(t.getProcessDefinitionId(), t.getTaskDefinitionKey())) {
-                        List<HistoricIdentityLink> links = historyService.getHistoricIdentityLinksForTask(t.getId());
-                        if (CollUtil.isEmpty(links) && StringUtils.isBlank(t.getAssignee())) {
-                            throw new ServiceException("涓嬩竴鑺傜偣銆�" + t.getName() + "銆戞病鏈夊姙鐞嗕汉!");
-                        }
-                    }
-                }
-
-                if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(completeTaskBo.getWfCopyList())) {
-                    TaskEntity newTask = WorkflowUtils.createNewTask(task);
-                    taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), LoginHelper.getLoginUser().getNickname() + "銆愭妱閫併�戠粰" + String.join(",", StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserName)));
-                    taskService.complete(newTask.getId());
-                    List<Task> taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
-                    WorkflowUtils.createCopyTask(taskList, StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserId));
-                }
-                sendMessage(list, processInstance.getName(), completeTaskBo.getMessageType(), null);
-            }
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 鍙戦�佹秷鎭�
-     *
-     * @param list        浠诲姟
-     * @param name        娴佺▼鍚嶇О
-     * @param messageType 娑堟伅绫诲瀷
-     * @param message     娑堟伅鍐呭锛屼负绌哄垯鍙戦�侀粯璁ら厤缃殑娑堟伅鍐呭
-     */
-    @Async
-    public void sendMessage(List<Task> list, String name, List<String> messageType, String message) {
-        WorkflowUtils.sendMessage(list, name, messageType, message, userService);
-    }
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @Override
-    public TableDataInfo<TaskVo> getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) {
-        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
-        List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
-        List<String> roleIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
-        String userId = String.valueOf(LoginHelper.getUserId());
-        queryWrapper.eq("t.business_status_", BusinessStatusEnum.WAITING.getStatus());
-        queryWrapper.eq(TenantHelper.isEnable(), "t.tenant_id_", TenantHelper.getTenantId());
-        String ids = StreamUtils.join(roleIds, x -> "'" + x + "'");
-        queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN (" + ids + ") ) ))", userId)));
-        if (StringUtils.isNotBlank(taskBo.getName())) {
-            queryWrapper.like("t.name_", taskBo.getName());
-        }
-        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
-            queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName());
-        }
-        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
-            queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey());
-        }
-        Page<TaskVo> page = actTaskMapper.getTaskWaitByPage(pageQuery.build(), queryWrapper);
-
-        List<TaskVo> taskList = page.getRecords();
-        if (CollUtil.isNotEmpty(taskList)) {
-            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
-            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
-            for (TaskVo task : taskList) {
-                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
-                task.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId(), userService));
-                task.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
-                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
-                }
-            }
-        }
-        return TableDataInfo.build(page);
-    }
-
-    /**
-     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊緟鍔炰换鍔�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @Override
-    public TableDataInfo<TaskVo> getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) {
-        TaskQuery query = QueryUtils.taskQuery();
-        if (StringUtils.isNotBlank(taskBo.getName())) {
-            query.taskNameLike("%" + taskBo.getName() + "%");
-        }
-        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
-            query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%");
-        }
-        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
-            query.processDefinitionKey(taskBo.getProcessDefinitionKey());
-        }
-        query.orderByTaskCreateTime().desc();
-        List<Task> taskList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
-        List<ProcessInstance> processInstanceList = null;
-        if (CollUtil.isNotEmpty(taskList)) {
-            Set<String> processInstanceIds = StreamUtils.toSet(taskList, Task::getProcessInstanceId);
-            processInstanceList = QueryUtils.instanceQuery(processInstanceIds).list();
-        }
-        List<TaskVo> list = new ArrayList<>();
-        if (CollUtil.isNotEmpty(taskList)) {
-            List<String> processDefinitionIds = StreamUtils.toList(taskList, Task::getProcessDefinitionId);
-            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
-            for (Task task : taskList) {
-                TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class);
-                if (CollUtil.isNotEmpty(processInstanceList)) {
-                    processInstanceList.stream().filter(e -> e.getId().equals(task.getProcessInstanceId())).findFirst().ifPresent(e -> {
-                        taskVo.setBusinessStatus(e.getBusinessStatus());
-                        taskVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(taskVo.getBusinessStatus()));
-                        taskVo.setProcessDefinitionKey(e.getProcessDefinitionKey());
-                        taskVo.setProcessDefinitionName(e.getProcessDefinitionName());
-                        taskVo.setProcessDefinitionVersion(e.getProcessDefinitionVersion());
-                        taskVo.setBusinessKey(e.getBusinessKey());
-                    });
-                }
-                taskVo.setAssignee(StringUtils.isNotBlank(task.getAssignee()) ? Long.valueOf(task.getAssignee()) : null);
-                taskVo.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId(), userService));
-                taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
-                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo);
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo);
-                }
-                list.add(taskVo);
-            }
-        }
-        long count = query.count();
-        TableDataInfo<TaskVo> build = TableDataInfo.build();
-        build.setRows(list);
-        build.setTotal(count);
-        return build;
-    }
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @Override
-    public TableDataInfo<TaskVo> getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
-        String userId = String.valueOf(LoginHelper.getUserId());
-        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
-        queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName());
-        queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName());
-        queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey());
-        queryWrapper.eq("t.assignee_", userId);
-        Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper);
-
-        List<TaskVo> taskList = page.getRecords();
-        if (CollUtil.isNotEmpty(taskList)) {
-            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
-            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
-            for (TaskVo task : taskList) {
-                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
-                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
-                }
-            }
-        }
-        return TableDataInfo.build(page);
-    }
-
-    /**
-     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @Override
-    public TableDataInfo<TaskVo> getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) {
-        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
-        String userId = String.valueOf(LoginHelper.getUserId());
-        if (StringUtils.isNotBlank(taskBo.getName())) {
-            queryWrapper.like("t.name_", taskBo.getName());
-        }
-        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
-            queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName());
-        }
-        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
-            queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey());
-        }
-        queryWrapper.eq("t.assignee_", userId);
-        Page<TaskVo> page = actTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper);
-
-        List<TaskVo> taskList = page.getRecords();
-        if (CollUtil.isNotEmpty(taskList)) {
-            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
-            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
-            for (TaskVo task : taskList) {
-                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
-                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
-                }
-            }
-        }
-        return TableDataInfo.build(page);
-    }
-
-    /**
-     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊凡鍔炰换鍔�
-     *
-     * @param taskBo 鍙傛暟
-     */
-    @Override
-    public TableDataInfo<TaskVo> getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
-        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
-        queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName());
-        queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName());
-        queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey());
-        Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper);
-
-        List<TaskVo> taskList = page.getRecords();
-        if (CollUtil.isNotEmpty(taskList)) {
-            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
-            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
-            for (TaskVo task : taskList) {
-                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
-                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
-                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
-                }
-            }
-        }
-        return TableDataInfo.build(page);
-    }
-
-    /**
-     * 濮旀淳浠诲姟
-     *
-     * @param delegateBo 鍙傛暟
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean delegateTask(DelegateBo delegateBo) {
-        Task task = WorkflowUtils.getTaskByCurrentUser(delegateBo.getTaskId());
-
-        if (ObjectUtil.isEmpty(task)) {
-            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
-        }
-        if (task.isSuspended()) {
-            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
-        }
-        try {
-            TaskEntity newTask = WorkflowUtils.createNewTask(task);
-            taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PENDING.getStatus(), "銆�" + LoginHelper.getLoginUser().getNickname() + "銆戝娲剧粰銆�" + delegateBo.getNickName() + "銆�");
-            //濮旀墭浠诲姟
-            taskService.delegateTask(delegateBo.getTaskId(), delegateBo.getUserId());
-            //鍔炵悊鐢熸垚鐨勪换鍔¤褰�
-            taskService.complete(newTask.getId());
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 缁堟浠诲姟
-     *
-     * @param terminationBo 鍙傛暟
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean terminationTask(TerminationBo terminationBo) {
-        TaskQuery query = QueryUtils.taskQuery();
-        Task task = query.taskId(terminationBo.getTaskId()).singleResult();
-
-        if (ObjectUtil.isEmpty(task)) {
-            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
-        }
-        if (task.isSuspended()) {
-            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
-        }
-        HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
-        BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus());
-        try {
-            if (StringUtils.isBlank(terminationBo.getComment())) {
-                terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "缁堟浜嗙敵璇�");
-            } else {
-                terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "缁堟浜嗙敵璇凤細" + terminationBo.getComment());
-            }
-            taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TERMINATION.getStatus(), terminationBo.getComment());
-            List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
-            if (CollUtil.isNotEmpty(list)) {
-                List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
-                if (CollUtil.isNotEmpty(subTasks)) {
-                    subTasks.forEach(e -> taskService.deleteTask(e.getId()));
-                }
-                runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.TERMINATION.getStatus());
-                runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY);
-            }
-            //娴佺▼缁堟鐩戝惉
-            flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(),
-                historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false);
-            return true;
-        } catch (Exception e) {
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 杞姙浠诲姟
-     *
-     * @param transmitBo 鍙傛暟
-     */
-    @Override
-    public boolean transferTask(TransmitBo transmitBo) {
-        Task task = WorkflowUtils.getTaskByCurrentUser(transmitBo.getTaskId());
-        if (ObjectUtil.isEmpty(task)) {
-            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
-        }
-        if (task.isSuspended()) {
-            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
-        }
-        try {
-            TaskEntity newTask = WorkflowUtils.createNewTask(task);
-            taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.TRANSFER.getStatus(), StringUtils.isNotBlank(transmitBo.getComment()) ? transmitBo.getComment() : LoginHelper.getUsername() + "杞姙浜嗕换鍔�");
-            taskService.complete(newTask.getId());
-            taskService.setAssignee(task.getId(), transmitBo.getUserId());
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 浼氱浠诲姟鍔犵
-     *
-     * @param addMultiBo 鍙傛暟
-     */
-    @Override
-    public boolean addMultiInstanceExecution(AddMultiBo addMultiBo) {
-        TaskQuery taskQuery = QueryUtils.taskQuery();
-        taskQuery.taskId(addMultiBo.getTaskId());
-        if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) {
-            taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
-        }
-        Task task = taskQuery.singleResult();
-        if (ObjectUtil.isEmpty(task)) {
-            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
-        }
-        if (task.isSuspended()) {
-            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
-        }
-        String taskDefinitionKey = task.getTaskDefinitionKey();
-        String processInstanceId = task.getProcessInstanceId();
-        String processDefinitionId = task.getProcessDefinitionId();
-
-        try {
-            MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
-            if (multiInstanceVo == null) {
-                throw new ServiceException("褰撳墠鐜妭涓嶆槸浼氱鑺傜偣");
-            }
-            if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
-                for (Long assignee : addMultiBo.getAssignees()) {
-                    runtimeService.addMultiInstanceExecution(taskDefinitionKey, processInstanceId, Collections.singletonMap(multiInstanceVo.getAssignee(), assignee));
-                }
-            } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
-                AddSequenceMultiInstanceCmd addSequenceMultiInstanceCmd = new AddSequenceMultiInstanceCmd(task.getExecutionId(), multiInstanceVo.getAssigneeList(), addMultiBo.getAssignees());
-                managementService.executeCommand(addSequenceMultiInstanceCmd);
-            }
-            List<String> assigneeNames = addMultiBo.getAssigneeNames();
-            String username = LoginHelper.getUsername();
-            TaskEntity newTask = WorkflowUtils.createNewTask(task);
-            taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN.getStatus(), username + "鍔犵銆�" + String.join(StringUtils.SEPARATOR, assigneeNames) + "銆�");
-            taskService.complete(newTask.getId());
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 浼氱浠诲姟鍑忕
-     *
-     * @param deleteMultiBo 鍙傛暟
-     */
-    @Override
-    public boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo) {
-        TaskQuery taskQuery = QueryUtils.taskQuery();
-        taskQuery.taskId(deleteMultiBo.getTaskId());
-        if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) {
-            taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
-        }
-        Task task = taskQuery.singleResult();
-        if (ObjectUtil.isEmpty(task)) {
-            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
-        }
-        if (task.isSuspended()) {
-            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
-        }
-        String taskDefinitionKey = task.getTaskDefinitionKey();
-        String processInstanceId = task.getProcessInstanceId();
-        String processDefinitionId = task.getProcessDefinitionId();
-        try {
-            MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
-            if (multiInstanceVo == null) {
-                throw new ServiceException("褰撳墠鐜妭涓嶆槸浼氱鑺傜偣");
-            }
-            if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
-                for (String executionId : deleteMultiBo.getExecutionIds()) {
-                    runtimeService.deleteMultiInstanceExecution(executionId, false);
-                }
-                for (String taskId : deleteMultiBo.getTaskIds()) {
-                    historyService.deleteHistoricTaskInstance(taskId);
-                }
-            } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
-                DeleteSequenceMultiInstanceCmd deleteSequenceMultiInstanceCmd = new DeleteSequenceMultiInstanceCmd(task.getAssignee(), task.getExecutionId(), multiInstanceVo.getAssigneeList(), deleteMultiBo.getAssigneeIds());
-                managementService.executeCommand(deleteSequenceMultiInstanceCmd);
-            }
-            List<String> assigneeNames = deleteMultiBo.getAssigneeNames();
-            String username = LoginHelper.getUsername();
-            TaskEntity newTask = WorkflowUtils.createNewTask(task);
-            taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN_OFF.getStatus(), username + "鍑忕銆�" + String.join(StringUtils.SEPARATOR, assigneeNames) + "銆�");
-            taskService.complete(newTask.getId());
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-    }
-
-    /**
-     * 椹冲洖瀹℃壒
-     *
-     * @param backProcessBo 鍙傛暟
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public String backProcess(BackProcessBo backProcessBo) {
-        String userId = String.valueOf(LoginHelper.getUserId());
-        Task task = WorkflowUtils.getTaskByCurrentUser(backProcessBo.getTaskId());
-
-        if (ObjectUtil.isEmpty(task)) {
-            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
-        }
-        if (task.isSuspended()) {
-            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
-        }
-        try {
-            String processInstanceId = task.getProcessInstanceId();
-            ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
-            //鑾峰彇骞惰缃戝叧鎵ц鍚庝繚鐣欑殑鎵ц瀹炰緥鏁版嵁
-            ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId());
-            List<ExecutionEntity> executionEntities = managementService.executeCommand(childByExecutionIdCmd);
-            //鏍¢獙鍗曟嵁
-            BusinessStatusEnum.checkBackStatus(processInstance.getBusinessStatus());
-            //鍒ゆ柇鏄惁鏈夊涓换鍔�
-            List<Task> taskList = QueryUtils.taskQuery(processInstanceId).list();
-            String backTaskDefinitionKey = backProcessBo.getTargetActivityId();
-            taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.BACK.getStatus(), StringUtils.isNotBlank(backProcessBo.getMessage()) ? backProcessBo.getMessage() : "閫�鍥�");
-            if (taskList.size() > 1) {
-                //褰撳墠澶氫釜浠诲姟椹冲洖鍒板崟涓妭鐐�
-                runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdsToSingleActivityId(taskList.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList()), backTaskDefinitionKey).changeState();
-                ActHiTaskinst actHiTaskinst = new ActHiTaskinst();
-                actHiTaskinst.setAssignee(userId);
-                actHiTaskinst.setId(task.getId());
-                actHiTaskinstMapper.updateById(actHiTaskinst);
-            } else {
-                //褰撳墠鍗曚釜鑺傜偣椹冲洖鍗曚釜鑺傜偣
-                runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdTo(task.getTaskDefinitionKey(), backTaskDefinitionKey).changeState();
-            }
-            //鍒犻櫎骞惰鐜妭鏈姙鐞嗚褰�
-            MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
-            if (multiInstance == null && taskList.size() > 1) {
-                List<Task> tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
-                if (CollUtil.isNotEmpty(tasks)) {
-                    actHiTaskinstMapper.deleteByIds(StreamUtils.toList(tasks, Task::getId));
-                }
-            }
-
-
-            List<HistoricTaskInstance> instanceList = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().desc().list();
-            List<Task> list = QueryUtils.taskQuery(processInstanceId).list();
-            for (Task t : list) {
-                instanceList.stream().filter(e -> e.getTaskDefinitionKey().equals(t.getTaskDefinitionKey())).findFirst().ifPresent(e -> {
-                    taskService.setAssignee(t.getId(), e.getAssignee());
-                });
-            }
-            //鍙戦�佹秷鎭�
-            String message = "鎮ㄧ殑銆�" + processInstance.getName() + "銆戝崟鎹凡缁忚椹冲洖锛岃鎮ㄦ敞鎰忔煡鏀躲��";
-            sendMessage(list, processInstance.getName(), backProcessBo.getMessageType(), message);
-            //鍒犻櫎娴佺▼瀹炰緥鍨冨溇鏁版嵁
-            for (ExecutionEntity executionEntity : executionEntities) {
-                DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId());
-                managementService.executeCommand(deleteExecutionCmd);
-            }
-
-            WfTaskBackNode wfTaskBackNode = wfTaskBackNodeService.getListByInstanceIdAndNodeId(task.getProcessInstanceId(), backProcessBo.getTargetActivityId());
-            if (ObjectUtil.isNotNull(wfTaskBackNode) && wfTaskBackNode.getOrderNo() == 0) {
-                runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus());
-                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(),
-                    processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false);
-            }
-            //鍒犻櫎椹冲洖鍚庣殑娴佺▼鑺傜偣
-            wfTaskBackNodeService.deleteBackTaskNode(processInstanceId, backProcessBo.getTargetActivityId());
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException(e.getMessage());
-        }
-        return task.getProcessInstanceId();
-    }
-
-    /**
-     * 淇敼浠诲姟鍔炵悊浜�
-     *
-     * @param taskIds 浠诲姟id
-     * @param userId  鍔炵悊浜篿d
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean updateAssignee(String[] taskIds, String userId) {
-        try {
-            List<Task> list = QueryUtils.taskQuery().taskIds(Arrays.asList(taskIds)).list();
-            for (Task task : list) {
-                taskService.setAssignee(task.getId(), userId);
-            }
-        } catch (Exception e) {
-            log.error("淇敼澶辫触锛�" + e.getMessage(), e);
-            throw new ServiceException("淇敼澶辫触锛�" + e.getMessage());
-        }
-        return true;
-    }
-
-    /**
-     * 鏌ヨ娴佺▼鍙橀噺
-     *
-     * @param taskId 浠诲姟id
-     */
-    @Override
-    public List<VariableVo> getInstanceVariable(String taskId) {
-        List<VariableVo> variableVoList = new ArrayList<>();
-        Map<String, VariableInstance> variableInstances = taskService.getVariableInstances(taskId);
-        if (CollUtil.isNotEmpty(variableInstances)) {
-            for (Map.Entry<String, VariableInstance> entry : variableInstances.entrySet()) {
-                VariableVo variableVo = new VariableVo();
-                variableVo.setKey(entry.getKey());
-                variableVo.setValue(entry.getValue().getValue().toString());
-                variableVoList.add(variableVo);
-            }
-        }
-        return variableVoList;
-    }
-
-    /**
-     * 鏌ヨ宸ヤ綔娴佷换鍔$敤鎴烽�夋嫨鍔犵浜哄憳
-     *
-     * @param taskId 浠诲姟id
-     * @return
-     */
-    @Override
-    @SuppressWarnings("unchecked")
-    public String getTaskUserIdsByAddMultiInstance(String taskId) {
-        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
-        if (task == null) {
-            throw new ServiceException("浠诲姟涓嶅瓨鍦�");
-        }
-        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
-        if (multiInstance == null) {
-            return "";
-        }
-        List<Long> userIds;
-        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
-            userIds = (List<Long>) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList());
-        } else {
-            List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
-            userIds = StreamUtils.toList(list, e -> Long.valueOf(e.getAssignee()));
-        }
-        return StringUtils.join(userIds, StringUtils.SEPARATOR);
-    }
-
-    /**
-     * 鏌ヨ宸ヤ綔娴侀�夋嫨鍑忕浜哄憳
-     *
-     * @param taskId 浠诲姟id 浠诲姟id
-     */
-    @Override
-    @SuppressWarnings("unchecked")
-    public List<TaskVo> getListByDeleteMultiInstance(String taskId) {
-        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
-        List<Task> taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
-        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
-        List<TaskVo> taskListVo = new ArrayList<>();
-        if (multiInstance == null) {
-            return List.of();
-        }
-        List<Long> assigneeList = new ArrayList<>();
-        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
-            List<Object> variable = (List<Object>) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList());
-            for (Object o : variable) {
-                assigneeList.add(Long.valueOf(o.toString()));
-            }
-        }
-
-        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
-            List<Long> userIds = StreamUtils.filter(assigneeList, e -> !String.valueOf(e).equals(task.getAssignee()));
-            List<UserDTO> userList = userService.selectListByIds(userIds);
-            for (Long userId : userIds) {
-                TaskVo taskVo = new TaskVo();
-                taskVo.setId("涓茶浼氱");
-                taskVo.setExecutionId("涓茶浼氱");
-                taskVo.setProcessInstanceId(task.getProcessInstanceId());
-                taskVo.setName(task.getName());
-                taskVo.setAssignee(userId);
-                if (CollUtil.isNotEmpty(userList)) {
-                    userList.stream().filter(u -> u.getUserId().toString().equals(userId.toString())).findFirst().ifPresent(u -> taskVo.setAssigneeName(u.getNickName()));
-                }
-                taskListVo.add(taskVo);
-            }
-            return taskListVo;
-        } else if (multiInstance.getType() instanceof ParallelMultiInstanceBehavior) {
-            List<Task> tasks = StreamUtils.filter(taskList, e -> StringUtils.isBlank(e.getParentTaskId()) && !e.getExecutionId().equals(task.getExecutionId()) && e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
-            if (CollUtil.isNotEmpty(tasks)) {
-                List<Long> userIds = StreamUtils.toList(tasks, e -> Long.valueOf(e.getAssignee()));
-                List<UserDTO> userList = userService.selectListByIds(userIds);
-                for (Task t : tasks) {
-                    TaskVo taskVo = new TaskVo();
-                    taskVo.setId(t.getId());
-                    taskVo.setExecutionId(t.getExecutionId());
-                    taskVo.setProcessInstanceId(t.getProcessInstanceId());
-                    taskVo.setName(t.getName());
-                    taskVo.setAssignee(Long.valueOf(t.getAssignee()));
-                    if (CollUtil.isNotEmpty(userList)) {
-                        userList.stream().filter(u -> u.getUserId().toString().equals(t.getAssignee())).findFirst().ifPresent(e -> taskVo.setAssigneeName(e.getNickName()));
-                    }
-                    taskListVo.add(taskVo);
-                }
-                return taskListVo;
-            }
-        }
-        return List.of();
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java
new file mode 100644
index 0000000..8c73b59
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java
@@ -0,0 +1,37 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.convert.Convert;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.core.TranslationInterface;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.workflow.service.IFlwCategoryService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 娴佺▼鍒嗙被鍚嶇О缈昏瘧瀹炵幇
+ *
+ * @author AprilWind
+ */
+@ConditionalOnEnable
+@Slf4j
+@RequiredArgsConstructor
+@Service
+@TranslationType(type = FlowConstant.CATEGORY_ID_TO_NAME)
+public class CategoryNameTranslationImpl implements TranslationInterface<String> {
+
+    private final IFlwCategoryService flwCategoryService;
+
+    @Override
+    public String translation(Object key, String other) {
+        Long id = null;
+        if (key instanceof String categoryId) {
+            id = Convert.toLong(categoryId);
+        } else if (key instanceof Long categoryId) {
+            id = categoryId;
+        }
+        return flwCategoryService.selectCategoryNameById(id);
+    }
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java
new file mode 100644
index 0000000..db1b7b7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java
@@ -0,0 +1,269 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.SystemConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.*;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.warm.flow.core.service.DefService;
+import org.dromara.warm.flow.orm.entity.FlowDefinition;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.workflow.domain.FlowCategory;
+import org.dromara.workflow.domain.bo.FlowCategoryBo;
+import org.dromara.workflow.domain.vo.FlowCategoryVo;
+import org.dromara.workflow.mapper.FlwCategoryMapper;
+import org.dromara.workflow.service.IFlwCategoryService;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 娴佺▼鍒嗙被Service涓氬姟灞傚鐞�
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@RequiredArgsConstructor
+@Service
+public class FlwCategoryServiceImpl implements IFlwCategoryService {
+
+    private final DefService defService;
+    private final FlwCategoryMapper baseMapper;
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被
+     *
+     * @param categoryId 涓婚敭
+     * @return 娴佺▼鍒嗙被
+     */
+    @Override
+    public FlowCategoryVo queryById(Long categoryId) {
+        FlowCategoryVo category = baseMapper.selectVoById(categoryId);
+        if (ObjectUtil.isNull(category)) {
+            return null;
+        }
+        FlowCategoryVo parentCategory = baseMapper.selectVoOne(new LambdaQueryWrapper<FlowCategory>()
+            .select(FlowCategory::getCategoryName).eq(FlowCategory::getCategoryId, category.getParentId()));
+        category.setParentName(ObjectUtils.notNullGetter(parentCategory, FlowCategoryVo::getCategoryName));
+        return category;
+    }
+
+    /**
+     * 鏍规嵁娴佺▼鍒嗙被ID鏌ヨ娴佺▼鍒嗙被鍚嶇О
+     *
+     * @param categoryId 娴佺▼鍒嗙被ID
+     * @return 娴佺▼鍒嗙被鍚嶇О
+     */
+    @Cacheable(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId")
+    @Override
+    public String selectCategoryNameById(Long categoryId) {
+        if (ObjectUtil.isNull(categoryId)) {
+            return null;
+        }
+        FlowCategory category = baseMapper.selectOne(new LambdaQueryWrapper<FlowCategory>()
+            .select(FlowCategory::getCategoryName).eq(FlowCategory::getCategoryId, categoryId));
+        return ObjectUtils.notNullGetter(category, FlowCategory::getCategoryName);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勬祦绋嬪垎绫诲垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 娴佺▼鍒嗙被鍒楄〃
+     */
+    @Override
+    public List<FlowCategoryVo> queryList(FlowCategoryBo bo) {
+        LambdaQueryWrapper<FlowCategory> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被鏍戠粨鏋勪俊鎭�
+     *
+     * @param category 娴佺▼鍒嗙被淇℃伅
+     * @return 娴佺▼鍒嗙被鏍戜俊鎭泦鍚�
+     */
+    @Override
+    public List<Tree<String>> selectCategoryTreeList(FlowCategoryBo category) {
+        LambdaQueryWrapper<FlowCategory> lqw = buildQueryWrapper(category);
+        List<FlowCategoryVo> categorys = baseMapper.selectVoList(lqw);
+        if (CollUtil.isEmpty(categorys)) {
+            return CollUtil.newArrayList();
+        }
+        // 鑾峰彇褰撳墠鍒楄〃涓瘡涓�涓妭鐐圭殑parentId锛岀劧鍚庡湪鍒楄〃涓煡鎵炬槸鍚︽湁id涓庡叾parentId瀵瑰簲锛岃嫢鏃犲搴旓紝鍒欒〃鏄庢鏃惰妭鐐瑰垪琛ㄤ腑锛岃鑺傜偣鍦ㄥ綋鍓嶅垪琛ㄤ腑灞炰簬椤剁骇鑺傜偣
+        List<Tree<String>> treeList = CollUtil.newArrayList();
+        for (FlowCategoryVo d : categorys) {
+            String parentId = d.getParentId().toString();
+            FlowCategoryVo categoryVo = StreamUtils.findFirst(categorys, it -> it.getCategoryId().toString().equals(parentId));
+            if (ObjectUtil.isNull(categoryVo)) {
+                List<Tree<String>> trees = TreeBuildUtils.build(categorys, parentId, (dept, tree) ->
+                    tree.setId(dept.getCategoryId().toString())
+                        .setParentId(dept.getParentId().toString())
+                        .setName(dept.getCategoryName())
+                        .setWeight(dept.getOrderNum()));
+                Tree<String> tree = StreamUtils.findFirst(trees, it -> it.getId().equals(d.getCategoryId().toString()));
+                treeList.add(tree);
+            }
+        }
+        return treeList;
+    }
+
+    /**
+     * 鏍¢獙娴佺▼鍒嗙被鏄惁鏈夋暟鎹潈闄�
+     *
+     * @param categoryId 娴佺▼鍒嗙被ID
+     */
+    @Override
+    public void checkCategoryDataScope(Long categoryId) {
+        if (ObjectUtil.isNull(categoryId)) {
+            return;
+        }
+        if (LoginHelper.isSuperAdmin()) {
+            return;
+        }
+        if (baseMapper.countCategoryById(categoryId) == 0) {
+            throw new ServiceException("娌℃湁鏉冮檺璁块棶娴佺▼鍒嗙被鏁版嵁锛�");
+        }
+    }
+
+    /**
+     * 鏍¢獙娴佺▼鍒嗙被鍚嶇О鏄惁鍞竴
+     *
+     * @param category 娴佺▼鍒嗙被淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkCategoryNameUnique(FlowCategoryBo category) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<FlowCategory>()
+            .eq(FlowCategory::getCategoryName, category.getCategoryName())
+            .eq(FlowCategory::getParentId, category.getParentId())
+            .ne(ObjectUtil.isNotNull(category.getCategoryId()), FlowCategory::getCategoryId, category.getCategoryId()));
+        return !exist;
+    }
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被鏄惁瀛樺湪娴佺▼瀹氫箟
+     *
+     * @param categoryId 娴佺▼鍒嗙被ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    @Override
+    public boolean checkCategoryExistDefinition(Long categoryId) {
+        FlowDefinition definition = new FlowDefinition();
+        definition.setCategory(categoryId.toString());
+        return defService.exists(definition);
+    }
+
+    /**
+     * 鏄惁瀛樺湪娴佺▼鍒嗙被瀛愯妭鐐�
+     *
+     * @param categoryId 娴佺▼鍒嗙被ID
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean hasChildByCategoryId(Long categoryId) {
+        return baseMapper.exists(new LambdaQueryWrapper<FlowCategory>()
+            .eq(FlowCategory::getParentId, categoryId));
+    }
+
+    private LambdaQueryWrapper<FlowCategory> buildQueryWrapper(FlowCategoryBo bo) {
+        LambdaQueryWrapper<FlowCategory> lqw = Wrappers.lambdaQuery();
+        lqw.eq(FlowCategory::getDelFlag, SystemConstants.NORMAL);
+        lqw.eq(ObjectUtil.isNotNull(bo.getCategoryId()), FlowCategory::getCategoryId, bo.getCategoryId());
+        lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), FlowCategory::getParentId, bo.getParentId());
+        lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), FlowCategory::getCategoryName, bo.getCategoryName());
+        lqw.orderByAsc(FlowCategory::getAncestors);
+        lqw.orderByAsc(FlowCategory::getParentId);
+        lqw.orderByAsc(FlowCategory::getOrderNum);
+        lqw.orderByAsc(FlowCategory::getCategoryId);
+        return lqw;
+    }
+
+    /**
+     * 鏂板娴佺▼鍒嗙被
+     *
+     * @param bo 娴佺▼鍒嗙被
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public int insertByBo(FlowCategoryBo bo) {
+        FlowCategory info = baseMapper.selectById(bo.getParentId());
+        FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
+        category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId());
+        return baseMapper.insert(category);
+    }
+
+    /**
+     * 淇敼娴佺▼鍒嗙被
+     *
+     * @param bo 娴佺▼鍒嗙被
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#bo.categoryId")
+    @Override
+    public int updateByBo(FlowCategoryBo bo) {
+        FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
+        FlowCategory oldCategory = baseMapper.selectById(category.getCategoryId());
+        if (ObjectUtil.isNull(oldCategory)) {
+            throw new ServiceException("娴佺▼鍒嗙被涓嶅瓨鍦紝鏃犳硶淇敼");
+        }
+        if (!oldCategory.getParentId().equals(category.getParentId())) {
+            // 濡傛灉鏄柊鐖舵祦绋嬪垎绫� 鍒欐牎楠屾槸鍚﹀叿鏈夋柊鐖舵祦绋嬪垎绫绘潈闄� 閬垮厤瓒婃潈
+            this.checkCategoryDataScope(category.getParentId());
+            FlowCategory newParentCategory = baseMapper.selectById(category.getParentId());
+            if (ObjectUtil.isNotNull(newParentCategory)) {
+                String newAncestors = newParentCategory.getAncestors() + StringUtils.SEPARATOR + newParentCategory.getCategoryId();
+                String oldAncestors = oldCategory.getAncestors();
+                category.setAncestors(newAncestors);
+                updateCategoryChildren(category.getCategoryId(), newAncestors, oldAncestors);
+            }
+        } else {
+            category.setAncestors(oldCategory.getAncestors());
+        }
+        return baseMapper.updateById(category);
+    }
+
+    /**
+     * 淇敼瀛愬厓绱犲叧绯�
+     *
+     * @param categoryId   琚慨鏀圭殑娴佺▼鍒嗙被ID
+     * @param newAncestors 鏂扮殑鐖禝D闆嗗悎
+     * @param oldAncestors 鏃х殑鐖禝D闆嗗悎
+     */
+    private void updateCategoryChildren(Long categoryId, String newAncestors, String oldAncestors) {
+        List<FlowCategory> children = baseMapper.selectList(new LambdaQueryWrapper<FlowCategory>()
+            .apply(DataBaseHelper.findInSet(categoryId, "ancestors")));
+        List<FlowCategory> list = new ArrayList<>();
+        for (FlowCategory child : children) {
+            FlowCategory category = new FlowCategory();
+            category.setCategoryId(child.getCategoryId());
+            category.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
+            list.add(category);
+        }
+        if (CollUtil.isNotEmpty(list)) {
+            baseMapper.updateBatchById(list);
+        }
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼鍒嗙被淇℃伅
+     *
+     * @param categoryId 涓婚敭
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId")
+    @Override
+    public int deleteWithValidById(Long categoryId) {
+        return baseMapper.deleteById(categoryId);
+    }
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java
new file mode 100644
index 0000000..591339b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java
@@ -0,0 +1,266 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.IoUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.warm.flow.core.dto.DefJson;
+import org.dromara.warm.flow.core.enums.NodeType;
+import org.dromara.warm.flow.core.enums.PublishStatus;
+import org.dromara.warm.flow.core.service.DefService;
+import org.dromara.warm.flow.orm.entity.FlowDefinition;
+import org.dromara.warm.flow.orm.entity.FlowHisTask;
+import org.dromara.warm.flow.orm.entity.FlowNode;
+import org.dromara.warm.flow.orm.entity.FlowSkip;
+import org.dromara.warm.flow.orm.mapper.FlowDefinitionMapper;
+import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
+import org.dromara.warm.flow.orm.mapper.FlowNodeMapper;
+import org.dromara.warm.flow.orm.mapper.FlowSkipMapper;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.workflow.domain.FlowCategory;
+import org.dromara.workflow.domain.vo.FlowDefinitionVo;
+import org.dromara.workflow.mapper.FlwCategoryMapper;
+import org.dromara.workflow.service.IFlwDefinitionService;
+import org.dromara.workflow.utils.WorkflowUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.dromara.common.core.constant.TenantConstants.DEFAULT_TENANT_ID;
+
+/**
+ * 娴佺▼瀹氫箟 鏈嶅姟灞傚疄鐜�
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
+
+    private final DefService defService;
+    private final FlowDefinitionMapper flowDefinitionMapper;
+    private final FlowHisTaskMapper flowHisTaskMapper;
+    private final FlowNodeMapper flowNodeMapper;
+    private final FlowSkipMapper flowSkipMapper;
+    private final FlwCategoryMapper flwCategoryMapper;
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param flowDefinition 娴佺▼瀹氫箟淇℃伅
+     * @param pageQuery      鍒嗛〉
+     * @return 杩斿洖鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<FlowDefinitionVo> queryList(FlowDefinition flowDefinition, PageQuery pageQuery) {
+        LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinition);
+        wrapper.eq(FlowDefinition::getIsPublish, PublishStatus.PUBLISHED.getKey());
+        Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper);
+        TableDataInfo<FlowDefinitionVo> build = TableDataInfo.build();
+        build.setRows(BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class));
+        build.setTotal(page.getTotal());
+        return build;
+    }
+
+    /**
+     * 鏌ヨ鏈彂甯冪殑娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param flowDefinition 娴佺▼瀹氫箟淇℃伅
+     * @param pageQuery      鍒嗛〉
+     * @return 杩斿洖鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) {
+        LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinition);
+        wrapper.in(FlowDefinition::getIsPublish, Arrays.asList(PublishStatus.UNPUBLISHED.getKey(), PublishStatus.EXPIRED.getKey()));
+        Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper);
+        TableDataInfo<FlowDefinitionVo> build = TableDataInfo.build();
+        build.setRows(BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class));
+        build.setTotal(page.getTotal());
+        return build;
+    }
+
+    private LambdaQueryWrapper<FlowDefinition> buildQueryWrapper(FlowDefinition flowDefinition) {
+        LambdaQueryWrapper<FlowDefinition> wrapper = Wrappers.lambdaQuery();
+        wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowCode()), FlowDefinition::getFlowCode, flowDefinition.getFlowCode());
+        wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowName()), FlowDefinition::getFlowName, flowDefinition.getFlowName());
+        if (StringUtils.isNotBlank(flowDefinition.getCategory())) {
+            List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowDefinition.getCategory()));
+            wrapper.in(FlowDefinition::getCategory, StreamUtils.toList(categoryIds, Convert::toStr));
+        }
+        wrapper.orderByDesc(FlowDefinition::getCreateTime);
+        return wrapper;
+    }
+
+    /**
+     * 鍙戝竷娴佺▼瀹氫箟
+     *
+     * @param id 娴佺▼瀹氫箟id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean publish(Long id) {
+        List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().eq(FlowNode::getDefinitionId, id));
+        List<String> errorMsg = new ArrayList<>();
+        if (CollUtil.isNotEmpty(flowNodes)) {
+            for (FlowNode flowNode : flowNodes) {
+                String applyNodeCode = WorkflowUtils.applyNodeCode(id);
+                if (StringUtils.isBlank(flowNode.getPermissionFlag()) && !applyNodeCode.equals(flowNode.getNodeCode()) && NodeType.BETWEEN.getKey().equals(flowNode.getNodeType())) {
+                    errorMsg.add(flowNode.getNodeName());
+                }
+            }
+            if (CollUtil.isNotEmpty(errorMsg)) {
+                throw new ServiceException("鑺傜偣銆�" + StringUtils.join(errorMsg, ",") + "銆戞湭閰嶇疆鍔炵悊浜�!");
+            }
+        }
+        return defService.publish(id);
+    }
+
+    /**
+     * 瀵煎叆娴佺▼瀹氫箟
+     *
+     * @param file 鏂囦欢
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean importJson(MultipartFile file, String category) {
+        try {
+            DefJson defJson = JsonUtils.parseObject(file.getBytes(), DefJson.class);
+            defJson.setCategory(category);
+            defService.importDef(defJson);
+        } catch (IOException e) {
+            log.error("璇诲彇鏂囦欢娴侀敊璇�: {}", e.getMessage(), e);
+            throw new IllegalStateException("鏂囦欢璇诲彇澶辫触锛岃妫�鏌ユ枃浠跺唴瀹�", e);
+        }
+        return true;
+    }
+
+    /**
+     * 瀵煎嚭娴佺▼瀹氫箟
+     *
+     * @param id       娴佺▼瀹氫箟id
+     * @param response 鍝嶅簲
+     * @throws IOException 寮傚父
+     */
+    @Override
+    public void exportDef(Long id, HttpServletResponse response) throws IOException {
+        byte[] data = defService.exportJson(id).getBytes(StandardCharsets.UTF_8);
+        // 璁剧疆鍝嶅簲澶村拰鍐呭绫诲瀷
+        response.reset();
+        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
+        response.setContentType("application/text");
+        response.setHeader("Content-Disposition", "attachment;");
+        response.addHeader("Content-Length", "" + data.length);
+        IoUtil.write(response.getOutputStream(), false, data);
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼瀹氫箟
+     *
+     * @param ids 娴佺▼瀹氫箟id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean removeDef(List<Long> ids) {
+        LambdaQueryWrapper<FlowHisTask> wrapper = Wrappers.lambdaQuery();
+        wrapper.in(FlowHisTask::getDefinitionId, ids);
+        List<FlowHisTask> flowHisTasks = flowHisTaskMapper.selectList(wrapper);
+        if (CollUtil.isNotEmpty(flowHisTasks)) {
+            List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectByIds(StreamUtils.toList(flowHisTasks, FlowHisTask::getDefinitionId));
+            if (CollUtil.isNotEmpty(flowDefinitions)) {
+                String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode);
+                log.error("娴佺▼瀹氫箟銆恵}銆戝凡琚娇鐢ㄤ笉鍙鍒犻櫎锛�", join);
+                throw new ServiceException("娴佺▼瀹氫箟銆�" + join + "銆戝凡琚娇鐢ㄤ笉鍙鍒犻櫎锛�");
+            }
+        }
+        try {
+            defService.removeDef(ids);
+        } catch (Exception e) {
+            log.error("Error removing flow definitions: {}", e.getMessage(), e);
+            throw new RuntimeException("Failed to remove flow definitions", e);
+        }
+        return true;
+    }
+
+    /**
+     * 鏂板绉熸埛娴佺▼瀹氫箟
+     *
+     * @param tenantId 绉熸埛id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void syncDef(String tenantId) {
+        List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID));
+        if (CollUtil.isEmpty(flowDefinitions)) {
+            return;
+        }
+        FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper<FlowCategory>()
+            .eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID).eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID));
+        flowCategory.setCategoryId(null);
+        flowCategory.setTenantId(tenantId);
+        flwCategoryMapper.insert(flowCategory);
+        List<Long> defIds = StreamUtils.toList(flowDefinitions, FlowDefinition::getId);
+        List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().in(FlowNode::getDefinitionId, defIds));
+        List<FlowSkip> flowSkips = flowSkipMapper.selectList(new LambdaQueryWrapper<FlowSkip>().in(FlowSkip::getDefinitionId, defIds));
+        for (FlowDefinition definition : flowDefinitions) {
+            FlowDefinition flowDefinition = BeanUtil.toBean(definition, FlowDefinition.class);
+            flowDefinition.setId(null);
+            flowDefinition.setTenantId(tenantId);
+            flowDefinition.setIsPublish(0);
+            flowDefinition.setCategory(String.valueOf(flowCategory.getCategoryId()));
+            int insert = flowDefinitionMapper.insert(flowDefinition);
+            if (insert <= 0) {
+                log.info("鍚屾娴佺▼瀹氫箟銆恵}銆戝け璐ワ紒", definition.getFlowCode());
+                continue;
+            }
+            log.info("鍚屾娴佺▼瀹氫箟銆恵}銆戞垚鍔燂紒", definition.getFlowCode());
+            Long definitionId = flowDefinition.getId();
+            if (CollUtil.isNotEmpty(flowNodes)) {
+                List<FlowNode> nodes = StreamUtils.filter(flowNodes, node -> node.getDefinitionId().equals(definition.getId()));
+                if (CollUtil.isNotEmpty(nodes)) {
+                    List<FlowNode> flowNodeList = BeanUtil.copyToList(nodes, FlowNode.class);
+                    flowNodeList.forEach(e -> {
+                        e.setId(null);
+                        e.setDefinitionId(definitionId);
+                        e.setTenantId(tenantId);
+                        e.setPermissionFlag(null);
+                    });
+                    flowNodeMapper.insertOrUpdate(flowNodeList);
+                }
+            }
+            if (CollUtil.isNotEmpty(flowSkips)) {
+                List<FlowSkip> skips = StreamUtils.filter(flowSkips, skip -> skip.getDefinitionId().equals(definition.getId()));
+                if (CollUtil.isNotEmpty(skips)) {
+                    List<FlowSkip> flowSkipList = BeanUtil.copyToList(skips, FlowSkip.class);
+                    flowSkipList.forEach(e -> {
+                        e.setId(null);
+                        e.setDefinitionId(definitionId);
+                        e.setTenantId(tenantId);
+                    });
+                    flowSkipMapper.insertOrUpdate(flowSkipList);
+                }
+            }
+        }
+    }
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java
new file mode 100644
index 0000000..db8ab71
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java
@@ -0,0 +1,451 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.enums.BusinessStatusEnum;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.warm.flow.core.FlowEngine;
+import org.dromara.warm.flow.core.constant.ExceptionCons;
+import org.dromara.warm.flow.core.dto.FlowParams;
+import org.dromara.warm.flow.core.entity.Definition;
+import org.dromara.warm.flow.core.entity.Instance;
+import org.dromara.warm.flow.core.entity.Task;
+import org.dromara.warm.flow.core.enums.NodeType;
+import org.dromara.warm.flow.core.service.ChartService;
+import org.dromara.warm.flow.core.service.DefService;
+import org.dromara.warm.flow.core.service.InsService;
+import org.dromara.warm.flow.core.service.TaskService;
+import org.dromara.warm.flow.orm.entity.FlowHisTask;
+import org.dromara.warm.flow.orm.entity.FlowInstance;
+import org.dromara.warm.flow.orm.entity.FlowTask;
+import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
+import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.common.enums.TaskStatusEnum;
+import org.dromara.workflow.domain.bo.FlowCancelBo;
+import org.dromara.workflow.domain.bo.FlowInstanceBo;
+import org.dromara.workflow.domain.bo.FlowInvalidBo;
+import org.dromara.workflow.domain.vo.FlowHisTaskVo;
+import org.dromara.workflow.domain.vo.FlowInstanceVo;
+import org.dromara.workflow.domain.vo.FlowVariableVo;
+import org.dromara.workflow.handler.FlowProcessEventHandler;
+import org.dromara.workflow.mapper.FlwCategoryMapper;
+import org.dromara.workflow.mapper.FlwInstanceMapper;
+import org.dromara.workflow.service.IFlwInstanceService;
+import org.dromara.workflow.service.IFlwTaskService;
+import org.dromara.workflow.utils.WorkflowUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 娴佺▼瀹炰緥 鏈嶅姟灞傚疄鐜�
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class FlwInstanceServiceImpl implements IFlwInstanceService {
+
+    private final InsService insService;
+    private final DefService defService;
+    private final ChartService chartService;
+    private final TaskService taskService;
+    private final FlowHisTaskMapper flowHisTaskMapper;
+    private final FlowInstanceMapper flowInstanceMapper;
+    private final FlowProcessEventHandler flowProcessEventHandler;
+    private final IFlwTaskService flwTaskService;
+    private final FlwInstanceMapper flwInstanceMapper;
+    private final FlwCategoryMapper flwCategoryMapper;
+
+    /**
+     * 鍒嗛〉鏌ヨ姝e湪杩愯鐨勬祦绋嬪疄渚�
+     *
+     * @param flowInstanceBo 娴佺▼瀹炰緥
+     * @param pageQuery      鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowInstanceVo> selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
+        QueryWrapper<FlowInstanceBo> queryWrapper = buildQueryWrapper(flowInstanceBo);
+        queryWrapper.in("fi.flow_status", BusinessStatusEnum.runningStatus());
+        Page<FlowInstanceVo> page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ宸茬粨鏉熺殑娴佺▼瀹炰緥
+     *
+     * @param flowInstanceBo 娴佺▼瀹炰緥
+     * @param pageQuery      鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowInstanceVo> selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) {
+        QueryWrapper<FlowInstanceBo> queryWrapper = buildQueryWrapper(flowInstanceBo);
+        queryWrapper.in("fi.flow_status", BusinessStatusEnum.finishStatus());
+        Page<FlowInstanceVo> page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏍规嵁涓氬姟id鏌ヨ娴佺▼瀹炰緥璇︾粏淇℃伅
+     *
+     * @param businessId 涓氬姟id
+     * @return 缁撴灉
+     */
+    @Override
+    public FlowInstanceVo queryByBusinessId(Long businessId) {
+        FlowInstance instance = this.selectInstByBusinessId(String.valueOf(businessId));
+        FlowInstanceVo instanceVo = BeanUtil.toBean(instance, FlowInstanceVo.class);
+        Definition definition = defService.getById(instanceVo.getDefinitionId());
+        instanceVo.setFlowName(definition.getFlowName());
+        instanceVo.setFlowCode(definition.getFlowCode());
+        instanceVo.setVersion(definition.getVersion());
+        instanceVo.setFormCustom(definition.getFormCustom());
+        instanceVo.setFormPath(definition.getFormPath());
+        instanceVo.setCategory(definition.getCategory());
+        return instanceVo;
+    }
+
+    /**
+     * 閫氱敤鏌ヨ鏉′欢
+     *
+     * @param flowInstanceBo 鏌ヨ鏉′欢
+     * @return 鏌ヨ鏉′欢鏋勯�犳柟娉�
+     */
+    private QueryWrapper<FlowInstanceBo> buildQueryWrapper(FlowInstanceBo flowInstanceBo) {
+        QueryWrapper<FlowInstanceBo> queryWrapper = Wrappers.query();
+        queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getNodeName()), "fi.node_name", flowInstanceBo.getNodeName());
+        queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getFlowName()), "fd.flow_name", flowInstanceBo.getFlowName());
+        queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getFlowCode()), "fd.flow_code", flowInstanceBo.getFlowCode());
+        if (StringUtils.isNotBlank(flowInstanceBo.getCategory())) {
+            List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowInstanceBo.getCategory()));
+            queryWrapper.in("fd.category", StreamUtils.toList(categoryIds, Convert::toStr));
+        }
+        queryWrapper.eq(StringUtils.isNotBlank(flowInstanceBo.getBusinessId()), "fi.business_id", flowInstanceBo.getBusinessId());
+        queryWrapper.in(CollUtil.isNotEmpty(flowInstanceBo.getCreateByIds()), "fi.create_by", flowInstanceBo.getCreateByIds());
+        queryWrapper.eq("fi.del_flag", "0");
+        queryWrapper.orderByDesc("fi.create_time");
+        return queryWrapper;
+    }
+
+    /**
+     * 鏍规嵁涓氬姟id鏌ヨ娴佺▼瀹炰緥
+     *
+     * @param businessId 涓氬姟id
+     */
+    @Override
+    public FlowInstance selectInstByBusinessId(String businessId) {
+        return flowInstanceMapper.selectOne(new LambdaQueryWrapper<FlowInstance>().eq(FlowInstance::getBusinessId, businessId));
+    }
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ娴佺▼瀹炰緥
+     *
+     * @param instanceId 瀹炰緥id
+     */
+    @Override
+    public FlowInstance selectInstById(Long instanceId) {
+        return flowInstanceMapper.selectById(instanceId);
+    }
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ娴佺▼瀹炰緥
+     *
+     * @param instanceIds 瀹炰緥id
+     */
+    @Override
+    public List<FlowInstance> selectInstListByIdList(List<Long> instanceIds) {
+        return flowInstanceMapper.selectByIds(instanceIds);
+    }
+
+    /**
+     * 鎸夌収涓氬姟id鍒犻櫎娴佺▼瀹炰緥
+     *
+     * @param businessIds 涓氬姟id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteByBusinessIds(List<Long> businessIds) {
+        List<FlowInstance> flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper<FlowInstance>().in(FlowInstance::getBusinessId, businessIds));
+        if (CollUtil.isEmpty(flowInstances)) {
+            log.warn("鏈壘鍒板搴旂殑娴佺▼瀹炰緥淇℃伅锛屾棤娉曟墽琛屽垹闄ゆ搷浣溿��");
+            return false;
+        }
+        return insService.remove(StreamUtils.toList(flowInstances, FlowInstance::getId));
+    }
+
+    /**
+     * 鎸夌収瀹炰緥id鍒犻櫎娴佺▼瀹炰緥
+     *
+     * @param instanceIds 瀹炰緥id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteByInstanceIds(List<Long> instanceIds) {
+        // 鑾峰彇瀹炰緥淇℃伅
+        List<Instance> instances = insService.getByIds(instanceIds);
+        if (CollUtil.isEmpty(instances)) {
+            log.warn("鏈壘鍒板搴旂殑娴佺▼瀹炰緥淇℃伅锛屾棤娉曟墽琛屽垹闄ゆ搷浣溿��");
+            return false;
+        }
+        // 鑾峰彇瀹氫箟淇℃伅
+        Map<Long, Definition> definitionMap = defService.getByIds(
+            StreamUtils.toList(instances, Instance::getDefinitionId)
+        ).stream().collect(Collectors.toMap(Definition::getId, definition -> definition));
+
+        // 閫愪竴瑙﹀彂鍒犻櫎浜嬩欢
+        instances.forEach(instance -> {
+            Definition definition = definitionMap.get(instance.getDefinitionId());
+            if (ObjectUtil.isNull(definition)) {
+                log.warn("瀹炰緥 ID: {} 瀵瑰簲鐨勬祦绋嬪畾涔変俊鎭湭鎵惧埌锛岃烦杩囧垹闄や簨浠惰Е鍙戙��", instance.getId());
+                return;
+            }
+            flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
+        });
+
+        // 鍒犻櫎瀹炰緥
+        return insService.remove(instanceIds);
+    }
+
+    /**
+     * 鎾ら攢娴佺▼
+     *
+     * @param bo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean cancelProcessApply(FlowCancelBo bo) {
+        try {
+            Instance instance = selectInstByBusinessId(bo.getBusinessId());
+            if (instance == null) {
+                throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE);
+            }
+            Definition definition = defService.getById(instance.getDefinitionId());
+            if (definition == null) {
+                throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF);
+            }
+            String message = bo.getMessage();
+            BusinessStatusEnum.checkCancelStatus(instance.getFlowStatus());
+            String applyNodeCode = WorkflowUtils.applyNodeCode(definition.getId());
+            //鎾ら攢
+            WorkflowUtils.backTask(message, instance.getId(), applyNodeCode, BusinessStatusEnum.CANCEL.getStatus(), BusinessStatusEnum.CANCEL.getStatus());
+            //鍒ゆ柇鎴栫鑺傜偣鏄惁鏈夊涓紝鍙繚鐣欎竴涓�
+            List<Task> currentTaskList = taskService.list(FlowEngine.newTask().setInstanceId(instance.getId()));
+            if (CollUtil.isNotEmpty(currentTaskList)) {
+                if (currentTaskList.size() > 1) {
+                    currentTaskList.remove(0);
+                    WorkflowUtils.deleteRunTask(StreamUtils.toList(currentTaskList, Task::getId));
+                }
+            }
+
+        } catch (Exception e) {
+            log.error("鎾ら攢澶辫触: {}", e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐧婚檰浜哄彂璧风殑娴佺▼瀹炰緥
+     *
+     * @param instanceBo 娴佺▼瀹炰緥
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowInstanceVo> selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery) {
+        QueryWrapper<FlowInstanceBo> queryWrapper = buildQueryWrapper(instanceBo);
+        queryWrapper.eq("fi.create_by", LoginHelper.getUserIdStr());
+        Page<FlowInstanceVo> page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍥�,娴佺▼璁板綍
+     *
+     * @param businessId 涓氬姟id
+     */
+    @Override
+    public Map<String, Object> flowImage(String businessId) {
+        FlowInstance flowInstance = this.selectInstByBusinessId(businessId);
+        if (ObjectUtil.isNull(flowInstance)) {
+            throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE);
+        }
+        Long instanceId = flowInstance.getId();
+        //杩愯涓殑浠诲姟
+        List<FlowHisTaskVo> list = new ArrayList<>();
+        List<FlowTask> flowTaskList = flwTaskService.selectByInstId(instanceId);
+        if (CollUtil.isNotEmpty(flowTaskList)) {
+            List<FlowHisTaskVo> flowHisTaskVos = BeanUtil.copyToList(flowTaskList, FlowHisTaskVo.class);
+            for (FlowHisTaskVo flowHisTaskVo : flowHisTaskVos) {
+                flowHisTaskVo.setFlowStatus(TaskStatusEnum.WAITING.getStatus());
+                flowHisTaskVo.setUpdateTime(null);
+                flowHisTaskVo.setRunDuration(null);
+                List<UserDTO> allUser = flwTaskService.currentTaskAllUser(flowHisTaskVo.getId());
+                if (CollUtil.isNotEmpty(allUser)) {
+                    String join = StreamUtils.join(allUser, e -> String.valueOf(e.getUserId()));
+                    flowHisTaskVo.setApprover(join);
+                }
+                if (BusinessStatusEnum.isDraftOrCancelOrBack(flowInstance.getFlowStatus())) {
+                    flowHisTaskVo.setApprover(LoginHelper.getUserIdStr());
+                    flowHisTaskVo.setApproveName(LoginHelper.getLoginUser().getNickname());
+                }
+            }
+            list.addAll(flowHisTaskVos);
+        }
+        //鍘嗗彶浠诲姟
+        LambdaQueryWrapper<FlowHisTask> wrapper = Wrappers.lambdaQuery();
+        wrapper.eq(FlowHisTask::getInstanceId, instanceId);
+        wrapper.eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey());
+        wrapper.orderByDesc(FlowHisTask::getCreateTime).orderByDesc(FlowHisTask::getUpdateTime);
+        List<FlowHisTask> flowHisTasks = flowHisTaskMapper.selectList(wrapper);
+        if (CollUtil.isNotEmpty(flowHisTasks)) {
+            list.addAll(BeanUtil.copyToList(flowHisTasks, FlowHisTaskVo.class));
+        }
+        String flowChart = chartService.chartIns(instanceId);
+        return Map.of("list", list, "image", flowChart);
+    }
+
+    /**
+     * 鎸夌収瀹炰緥id鏇存柊鐘舵��
+     *
+     * @param instanceId 瀹炰緥id
+     * @param status     鐘舵��
+     */
+    @Override
+    public void updateStatus(Long instanceId, String status) {
+        LambdaUpdateWrapper<FlowInstance> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.set(FlowInstance::getFlowStatus, status);
+        wrapper.eq(FlowInstance::getId, instanceId);
+        flowInstanceMapper.update(wrapper);
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍙橀噺
+     *
+     * @param instanceId 瀹炰緥id
+     */
+    @Override
+    public Map<String, Object> instanceVariable(Long instanceId) {
+        Map<String, Object> map = new HashMap<>();
+        FlowInstance flowInstance = flowInstanceMapper.selectById(instanceId);
+        Map<String, Object> variableMap = flowInstance.getVariableMap();
+        List<FlowVariableVo> list = new ArrayList<>();
+        if (CollUtil.isNotEmpty(variableMap)) {
+            for (Map.Entry<String, Object> entry : variableMap.entrySet()) {
+                FlowVariableVo flowVariableVo = new FlowVariableVo();
+                flowVariableVo.setKey(entry.getKey());
+                flowVariableVo.setValue(entry.getValue().toString());
+                list.add(flowVariableVo);
+            }
+        }
+        map.put("variableList", list);
+        map.put("variable", flowInstance.getVariable());
+        return map;
+    }
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺
+     *
+     * @param instanceId 瀹炰緥id
+     * @param variable   娴佺▼鍙橀噺
+     */
+    @Override
+    public void setVariable(Long instanceId, Map<String, Object> variable) {
+        Instance instance = insService.getById(instanceId);
+        if (instance != null) {
+            taskService.mergeVariable(instance, variable);
+        }
+    }
+
+    /**
+     * 鎸変换鍔d鏌ヨ瀹炰緥
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Override
+    public FlowInstance selectByTaskId(Long taskId) {
+        Task task = taskService.getById(taskId);
+        if (task == null) {
+            FlowHisTask flowHisTask = flwTaskService.selectHisTaskById(taskId);
+            if (flowHisTask != null) {
+                return this.selectInstById(flowHisTask.getInstanceId());
+            }
+        } else {
+            return this.selectInstById(task.getInstanceId());
+        }
+        return null;
+    }
+
+    /**
+     * 鎸変换鍔d鏌ヨ瀹炰緥
+     *
+     * @param taskIdList 浠诲姟id
+     */
+    @Override
+    public List<FlowInstance> selectByTaskIdList(List<Long> taskIdList) {
+        if (CollUtil.isEmpty(taskIdList)) {
+            return Collections.emptyList();
+        }
+        Set<Long> instanceIds = new HashSet<>();
+        List<FlowTask> flowTaskList = flwTaskService.selectByIdList(taskIdList);
+        for (FlowTask flowTask : flowTaskList) {
+            instanceIds.add(flowTask.getInstanceId());
+        }
+        List<FlowHisTask> flowHisTaskList = flwTaskService.selectHisTaskByIdList(taskIdList);
+        for (FlowHisTask flowHisTask : flowHisTaskList) {
+            instanceIds.add(flowHisTask.getInstanceId());
+        }
+        if (!instanceIds.isEmpty()) {
+            return this.selectInstListByIdList(new ArrayList<>(instanceIds));
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * 浣滃簾娴佺▼
+     *
+     * @param bo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean processInvalid(FlowInvalidBo bo) {
+        try {
+            Instance instance = insService.getById(bo.getId());
+            if (instance != null) {
+                BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus());
+            }
+            List<FlowTask> flowTaskList = flwTaskService.selectByInstId(bo.getId());
+            for (FlowTask flowTask : flowTaskList) {
+                FlowParams flowParams = new FlowParams();
+                flowParams.message(bo.getComment());
+                flowParams.flowStatus(BusinessStatusEnum.INVALID.getStatus())
+                    .hisStatus(TaskStatusEnum.INVALID.getStatus());
+                flowParams.ignore(true);
+                taskService.termination(flowTask.getId(), flowParams);
+            }
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java
new file mode 100644
index 0000000..5877bb5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java
@@ -0,0 +1,165 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.dto.DeptDTO;
+import org.dromara.common.core.domain.dto.TaskAssigneeDTO;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.domain.model.TaskAssigneeBody;
+import org.dromara.common.core.enums.FormatsType;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.DeptService;
+import org.dromara.common.core.service.TaskAssigneeService;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.DateUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.warm.flow.ui.dto.HandlerFunDto;
+import org.dromara.warm.flow.ui.dto.HandlerQuery;
+import org.dromara.warm.flow.ui.dto.TreeFunDto;
+import org.dromara.warm.flow.ui.service.HandlerSelectService;
+import org.dromara.warm.flow.ui.vo.HandlerSelectVo;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.common.enums.TaskAssigneeEnum;
+import org.dromara.workflow.service.IFlwTaskAssigneeService;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 娴佺▼璁捐鍣�-鑾峰彇鍔炵悊浜烘潈闄愯缃垪琛�
+ *
+ * @author AprilWind
+ */
+@ConditionalOnEnable
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, HandlerSelectService {
+
+    private static final String DEFAULT_GROUP_NAME = "榛樿鍒嗙粍";
+    private final TaskAssigneeService taskAssigneeService;
+    private final UserService userService;
+    private final DeptService deptService;
+
+    /**
+     * 鑾峰彇鍔炵悊浜烘潈闄愯缃垪琛╰abs椤电
+     *
+     * @return tabs椤电
+     */
+    @Override
+    public List<String> getHandlerType() {
+        return TaskAssigneeEnum.getAssigneeTypeList();
+    }
+
+    /**
+     * 鑾峰彇鍔炵悊鍒楄〃, 鍚屾椂鏋勫缓宸︿晶閮ㄩ棬鏍戠姸缁撴瀯
+     *
+     * @param query 鏌ヨ鏉′欢
+     * @return HandlerSelectVo
+     */
+    @Override
+    public HandlerSelectVo getHandlerSelect(HandlerQuery query) {
+        // 鑾峰彇浠诲姟鍔炵悊绫诲瀷
+        TaskAssigneeEnum type = TaskAssigneeEnum.fromDesc(query.getHandlerType());
+        // 杞崲鏌ヨ鏉′欢涓� TaskAssigneeBody
+        TaskAssigneeBody taskQuery = BeanUtil.toBean(query, TaskAssigneeBody.class);
+
+        // 缁熶竴鏌ヨ骞舵瀯寤轰笟鍔℃暟鎹�
+        TaskAssigneeDTO dto = fetchTaskAssigneeData(type, taskQuery);
+        List<DeptDTO> depts = fetchDeptData(type);
+
+        return getHandlerSelectVo(buildHandlerData(dto, type), buildDeptTree(depts));
+    }
+
+    /**
+     * 鏍规嵁浠诲姟鍔炵悊绫诲瀷鏌ヨ瀵瑰簲鐨勬暟鎹�
+     */
+    private TaskAssigneeDTO fetchTaskAssigneeData(TaskAssigneeEnum type, TaskAssigneeBody taskQuery) {
+        return switch (type) {
+            case USER -> taskAssigneeService.selectUsersByTaskAssigneeList(taskQuery);
+            case ROLE -> taskAssigneeService.selectRolesByTaskAssigneeList(taskQuery);
+            case DEPT -> taskAssigneeService.selectDeptsByTaskAssigneeList(taskQuery);
+            case POST -> taskAssigneeService.selectPostsByTaskAssigneeList(taskQuery);
+            default -> throw new ServiceException("Unsupported handler type");
+        };
+    }
+
+    /**
+     * 鏍规嵁浠诲姟鍔炵悊绫诲瀷鑾峰彇閮ㄩ棬鏁版嵁
+     */
+    private List<DeptDTO> fetchDeptData(TaskAssigneeEnum type) {
+        if (type == TaskAssigneeEnum.USER || type == TaskAssigneeEnum.DEPT || type == TaskAssigneeEnum.POST) {
+            return deptService.selectDeptsByList();
+        }
+        return new ArrayList<>();
+    }
+
+    /**
+     * 鏋勫缓閮ㄩ棬鏍戠姸缁撴瀯
+     */
+    private TreeFunDto<DeptDTO> buildDeptTree(List<DeptDTO> depts) {
+        return new TreeFunDto<>(depts)
+            .setId(dept -> String.valueOf(dept.getDeptId()))
+            .setName(DeptDTO::getDeptName)
+            .setParentId(dept -> String.valueOf(dept.getParentId()));
+    }
+
+    /**
+     * 鏋勫缓浠诲姟鍔炵悊浜烘暟鎹�
+     */
+    private HandlerFunDto<TaskAssigneeDTO.TaskHandler> buildHandlerData(TaskAssigneeDTO dto, TaskAssigneeEnum type) {
+        return new HandlerFunDto<>(dto.getList(), dto.getTotal())
+            .setStorageId(assignee -> type.getCode() + assignee.getStorageId())
+            .setHandlerCode(assignee -> StringUtils.blankToDefault(assignee.getHandlerCode(), "鏃�"))
+            .setHandlerName(assignee -> StringUtils.blankToDefault(assignee.getHandlerName(), "鏃�"))
+            .setGroupName(assignee -> StringUtils.defaultIfBlank(
+                Optional.ofNullable(assignee.getGroupName())
+                    .map(deptService::selectDeptNameByIds)
+                    .orElse(DEFAULT_GROUP_NAME), DEFAULT_GROUP_NAME))
+            .setCreateTime(assignee -> DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, assignee.getCreateTime()));
+    }
+
+    /**
+     * 鏍规嵁瀛樺偍鏍囪瘑绗︼紙storageId锛夎В鏋愬垎閰嶇被鍨嬪拰ID锛屽苟鑾峰彇瀵瑰簲鐨勭敤鎴峰垪琛�
+     *
+     * @param storageId 鍖呭惈鍒嗛厤绫诲瀷鍜孖D鐨勫瓧绗︿覆锛堜緥濡� "user:123" 鎴� "role:456"锛�
+     * @return 涓庡垎閰嶇被鍨嬪拰ID鍖归厤鐨勭敤鎴峰垪琛紝濡傛灉鏍煎紡鏃犳晥鍒欒繑鍥炵┖鍒楄〃
+     */
+    @Override
+    public List<UserDTO> fetchUsersByStorageId(String storageId) {
+        List<UserDTO> list = new ArrayList<>();
+        for (String str : storageId.split(StrUtil.COMMA)) {
+            String[] parts = str.split(StrUtil.COLON, 2);
+            if (parts.length < 2) {
+                list.addAll(getUsersByType(TaskAssigneeEnum.USER, List.of(Long.valueOf(parts[0]))));
+            } else {
+                list.addAll(getUsersByType(TaskAssigneeEnum.fromCode(parts[0] + StrUtil.COLON), List.of(Long.valueOf(parts[1]))));
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 鏍规嵁鎸囧畾鐨勪换鍔″垎閰嶇被鍨嬶紙TaskAssigneeEnum锛夊拰 ID 鍒楄〃锛岃幏鍙栧搴旂殑鐢ㄦ埛淇℃伅鍒楄〃
+     *
+     * @param type 浠诲姟鍒嗛厤绫诲瀷锛岃〃绀虹敤鎴枫�佽鑹层�侀儴闂ㄦ垨鍏朵粬锛圱askAssigneeEnum 鏋氫妇鍊硷級
+     * @param ids  涓庢寚瀹氬垎閰嶇被鍨嬪叧鑱旂殑 ID 鍒楄〃锛堜緥濡傜敤鎴稩D銆佽鑹睮D銆侀儴闂↖D绛夛級
+     * @return 杩斿洖鍖呭惈鐢ㄦ埛淇℃伅鐨勫垪琛ㄣ�傚鏋滅被鍨嬩负鐢ㄦ埛锛圲SER锛夛紝鍒欓�氳繃鐢ㄦ埛ID鍒楄〃鏌ヨ锛�
+     * 濡傛灉绫诲瀷涓鸿鑹诧紙ROLE锛夛紝鍒欓�氳繃瑙掕壊ID鍒楄〃鏌ヨ锛�
+     * 濡傛灉绫诲瀷涓洪儴闂紙DEPT锛夛紝鍒欓�氳繃閮ㄩ棬ID鍒楄〃鏌ヨ锛�
+     * 濡傛灉绫诲瀷涓哄矖浣嶏紙POST锛夋垨鏃犳硶璇嗗埆鐨勭被鍨嬶紝鍒欒繑鍥炵┖鍒楄〃
+     */
+    private List<UserDTO> getUsersByType(TaskAssigneeEnum type, List<Long> ids) {
+        return switch (type) {
+            case USER -> userService.selectListByIds(ids);
+            case ROLE -> userService.selectUsersByRoleIds(ids);
+            case DEPT -> userService.selectUsersByDeptIds(ids);
+            case POST -> userService.selectUsersByPostIds(ids);
+        };
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java
new file mode 100644
index 0000000..21a54d7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java
@@ -0,0 +1,687 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.dto.StartProcessReturnDTO;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.enums.BusinessStatusEnum;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.warm.flow.core.dto.FlowParams;
+import org.dromara.warm.flow.core.entity.*;
+import org.dromara.warm.flow.core.enums.NodeType;
+import org.dromara.warm.flow.core.enums.SkipType;
+import org.dromara.warm.flow.core.service.*;
+import org.dromara.warm.flow.orm.entity.*;
+import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
+import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper;
+import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.common.enums.TaskAssigneeType;
+import org.dromara.workflow.common.enums.TaskStatusEnum;
+import org.dromara.workflow.domain.bo.*;
+import org.dromara.workflow.domain.vo.FlowHisTaskVo;
+import org.dromara.workflow.domain.vo.FlowTaskVo;
+import org.dromara.workflow.handler.FlowProcessEventHandler;
+import org.dromara.workflow.handler.WorkflowPermissionHandler;
+import org.dromara.workflow.mapper.FlwCategoryMapper;
+import org.dromara.workflow.mapper.FlwTaskMapper;
+import org.dromara.workflow.service.IFlwTaskService;
+import org.dromara.workflow.utils.WorkflowUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static org.dromara.workflow.common.constant.FlowConstant.*;
+
+/**
+ * 浠诲姟 鏈嶅姟灞傚疄鐜�
+ *
+ * @author may
+ */
+@ConditionalOnEnable
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class FlwTaskServiceImpl implements IFlwTaskService {
+
+    private final TaskService taskService;
+    private final InsService insService;
+    private final DefService defService;
+    private final HisTaskService hisTaskService;
+    private final NodeService nodeService;
+    private final FlowInstanceMapper flowInstanceMapper;
+    private final FlowTaskMapper flowTaskMapper;
+    private final FlowHisTaskMapper flowHisTaskMapper;
+    private final IdentifierGenerator identifierGenerator;
+    private final FlowProcessEventHandler flowProcessEventHandler;
+    private final UserService userService;
+    private final FlwTaskMapper flwTaskMapper;
+    private final FlwCategoryMapper flwCategoryMapper;
+
+    /**
+     * 鍚姩浠诲姟
+     *
+     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo) {
+        String businessId = startProcessBo.getBusinessId();
+        if (StringUtils.isBlank(businessId)) {
+            throw new ServiceException("鍚姩宸ヤ綔娴佹椂蹇呴』鍖呭惈涓氬姟ID");
+        }
+        // 鍚姩娴佺▼瀹炰緥锛堟彁浜ょ敵璇凤級
+        Map<String, Object> variables = startProcessBo.getVariables();
+        // 娴佺▼鍙戣捣浜�
+        variables.put(INITIATOR, LoginHelper.getUserIdStr());
+        // 涓氬姟id
+        variables.put(BUSINESS_ID, businessId);
+        FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class)
+            .eq(FlowInstance::getBusinessId, businessId));
+        if (ObjectUtil.isNotNull(flowInstance)) {
+            BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus());
+            List<Task> taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId()));
+            StartProcessReturnDTO dto = new StartProcessReturnDTO();
+            dto.setProcessInstanceId(taskList.get(0).getInstanceId());
+            dto.setTaskId(taskList.get(0).getId());
+            return dto;
+        }
+        FlowParams flowParams = new FlowParams();
+        flowParams.flowCode(startProcessBo.getFlowCode());
+        flowParams.variable(startProcessBo.getVariables());
+        flowParams.flowStatus(BusinessStatusEnum.DRAFT.getStatus());
+        Instance instance;
+        try {
+            instance = insService.start(businessId, flowParams);
+        } catch (Exception e) {
+            throw new ServiceException(e.getMessage());
+        }
+        // 鐢宠浜烘墽琛屾祦绋�
+        List<Task> taskList = taskService.list(new FlowTask().setInstanceId(instance.getId()));
+        if (taskList.size() > 1) {
+            throw new ServiceException("璇锋鏌ユ祦绋嬬涓�涓幆鑺傛槸鍚︿负鐢宠浜猴紒");
+        }
+        StartProcessReturnDTO dto = new StartProcessReturnDTO();
+        dto.setProcessInstanceId(instance.getId());
+        dto.setTaskId(taskList.get(0).getId());
+        return dto;
+    }
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean completeTask(CompleteTaskBo completeTaskBo) {
+        try {
+            // 鑾峰彇浠诲姟ID骞舵煡璇㈠搴旂殑娴佺▼浠诲姟鍜屽疄渚嬩俊鎭�
+            Long taskId = completeTaskBo.getTaskId();
+            List<String> messageType = completeTaskBo.getMessageType();
+            String notice = completeTaskBo.getNotice();
+            // 鑾峰彇鎶勯�佷汉
+            List<FlowCopyBo> flowCopyList = completeTaskBo.getFlowCopyList();
+            FlowTask flowTask = flowTaskMapper.selectById(taskId);
+            if (ObjectUtil.isNull(flowTask)) {
+                throw new ServiceException("娴佺▼浠诲姟涓嶅瓨鍦ㄦ垨浠诲姟宸插鎵癸紒");
+            }
+            Instance ins = insService.getById(flowTask.getInstanceId());
+            // 鑾峰彇娴佺▼瀹氫箟淇℃伅
+            Definition definition = defService.getById(flowTask.getDefinitionId());
+            // 妫�鏌ユ祦绋嬬姸鎬佹槸鍚︿负鑽夌銆佸凡鎾ら攢鎴栧凡閫�鍥炵姸鎬侊紝鑻ユ槸鍒欐墽琛屾祦绋嬫彁浜ょ洃鍚�
+            if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) {
+                flowProcessEventHandler.processHandler(definition.getFlowCode(), ins.getBusinessId(), ins.getFlowStatus(), null, true);
+            }
+            // 鏋勫缓娴佺▼鍙傛暟锛屽寘鎷彉閲忋�佽烦杞被鍨嬨�佹秷鎭�佸鐞嗕汉銆佹潈闄愮瓑淇℃伅
+            FlowParams flowParams = new FlowParams();
+            flowParams.variable(completeTaskBo.getVariables());
+            flowParams.skipType(SkipType.PASS.getKey());
+            flowParams.message(completeTaskBo.getMessage());
+            flowParams.flowStatus(BusinessStatusEnum.WAITING.getStatus()).hisStatus(TaskStatusEnum.PASS.getStatus());
+
+            flowParams.hisTaskExt(completeTaskBo.getFileId());
+            // 鎵ц浠诲姟璺宠浆锛屽苟鏍规嵁杩斿洖鐨勫鐞嗕汉璁剧疆涓嬩竴姝ュ鐞嗕汉
+            Instance instance = taskService.skip(taskId, flowParams);
+            this.setHandler(instance, flowTask, flowCopyList);
+            // 娑堟伅閫氱煡
+            WorkflowUtils.sendMessage(definition.getFlowName(), ins.getId(), messageType, notice);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 璁剧疆鍔炵悊浜�
+     *
+     * @param instance     瀹炰緥
+     * @param task         (褰撳墠浠诲姟)鏈姙鐞嗙殑浠诲姟
+     * @param flowCopyList 鎶勯�佷汉
+     */
+    private void setHandler(Instance instance, FlowTask task, List<FlowCopyBo> flowCopyList) {
+        if (ObjectUtil.isNull(instance)) {
+            return;
+        }
+        // 娣诲姞鎶勯�佷汉
+        this.setCopy(task, flowCopyList);
+        // 鏍规嵁娴佺▼瀹炰緥ID鏌ヨ鎵�鏈夊叧鑱旂殑浠诲姟
+        List<FlowTask> flowTasks = this.selectByInstId(instance.getId());
+        if (CollUtil.isEmpty(flowTasks)) {
+            return;
+        }
+        List<Long> taskIdList = StreamUtils.toList(flowTasks, FlowTask::getId);
+        // 鑾峰彇涓庡綋鍓嶄换鍔″叧鑱旂殑鐢ㄦ埛鍒楄〃
+        List<User> associatedUsers = WorkflowUtils.getFlowUserService().getByAssociateds(taskIdList);
+        if (CollUtil.isEmpty(associatedUsers)) {
+            return;
+        }
+        List<User> userList = new ArrayList<>();
+        // 閬嶅巻浠诲姟鍒楄〃锛屽鐞嗘瘡涓换鍔$殑鍔炵悊浜�
+        for (FlowTask flowTask : flowTasks) {
+            List<User> users = StreamUtils.filter(associatedUsers, user -> Objects.equals(user.getAssociated(), flowTask.getId()));
+            if (CollUtil.isNotEmpty(users)) {
+                userList.addAll(WorkflowUtils.buildUser(users, flowTask.getId()));
+            }
+        }
+        // 鎵归噺鍒犻櫎鐜版湁浠诲姟鐨勫姙鐞嗕汉璁板綍
+        WorkflowUtils.getFlowUserService().deleteByTaskIds(taskIdList);
+        // 纭繚瑕佷繚瀛樼殑 userList 涓嶄负绌�
+        if (CollUtil.isEmpty(userList)) {
+            return;
+        }
+        WorkflowUtils.getFlowUserService().saveBatch(userList);
+    }
+
+    /**
+     * 娣诲姞鎶勯�佷汉
+     *
+     * @param task         浠诲姟淇℃伅
+     * @param flowCopyList 鎶勯�佷汉
+     */
+    public void setCopy(FlowTask task, List<FlowCopyBo> flowCopyList) {
+        if (CollUtil.isEmpty(flowCopyList)) {
+            return;
+        }
+        // 娣诲姞鎶勯�佷汉璁板綍
+        FlowHisTask flowHisTask = flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId())).get(0);
+        FlowNode flowNode = new FlowNode();
+        flowNode.setNodeCode(flowHisTask.getTargetNodeCode());
+        flowNode.setNodeName(flowHisTask.getTargetNodeName());
+        //鐢熸垚鏂扮殑浠诲姟id
+        long taskId = identifierGenerator.nextId(null).longValue();
+        task.setId(taskId);
+        task.setNodeName("銆愭妱閫併��" + task.getNodeName());
+        Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000);
+        FlowParams flowParams = FlowParams.build();
+        flowParams.skipType(SkipType.NONE.getKey());
+        flowParams.hisStatus(TaskStatusEnum.COPY.getStatus());
+        flowParams.message("銆愭妱閫佺粰銆�" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName));
+        HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams);
+        hisTask.setCreateTime(updateTime);
+        hisTask.setUpdateTime(updateTime);
+        hisTaskService.save(hisTask);
+        List<User> userList = flowCopyList.stream()
+            .map(flowCopy -> {
+                FlowUser flowUser = new FlowUser();
+                flowUser.setType(TaskAssigneeType.COPY.getCode());
+                flowUser.setProcessedBy(String.valueOf(flowCopy.getUserId()));
+                flowUser.setAssociated(taskId);
+                return flowUser;
+            }).collect(Collectors.toList());
+        // 鎵归噺淇濆瓨鎶勯�佷汉鍛�
+        WorkflowUtils.getFlowUserService().saveBatch(userList);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
+        queryWrapper.in("t.processed_by", SpringUtils.getBean(WorkflowPermissionHandler.class).permissions());
+        queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus());
+        Page<FlowTaskVo> page = this.getFlowTaskVoPage(pageQuery, queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
+        queryWrapper.in("t.approver", LoginHelper.getUserIdStr());
+        queryWrapper.orderByDesc("t.create_time").orderByDesc("t.update_time");
+        Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ寰呭姙浠诲姟
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
+        Page<FlowTaskVo> page = getFlowTaskVoPage(pageQuery, queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    private Page<FlowTaskVo> getFlowTaskVoPage(PageQuery pageQuery, QueryWrapper<FlowTaskBo> queryWrapper) {
+        Page<FlowTaskVo> page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper);
+        List<FlowTaskVo> records = page.getRecords();
+        if (CollUtil.isNotEmpty(records)) {
+            List<Long> taskIds = StreamUtils.toList(records, FlowTaskVo::getId);
+            Map<Long, List<UserDTO>> listMap = currentTaskAllUser(taskIds);
+            records.forEach(t -> {
+                List<UserDTO> userList = listMap.getOrDefault(t.getId(), Collections.emptyList());
+                if (CollUtil.isNotEmpty(userList)) {
+                    t.setAssigneeIds(StreamUtils.join(userList, e -> String.valueOf(e.getUserId())));
+                    t.setAssigneeNames(StreamUtils.join(userList, UserDTO::getNickName));
+                }
+            });
+        }
+        return page;
+    }
+
+    /**
+     * 鏌ヨ宸插姙浠诲姟
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowHisTaskVo> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param flowTaskBo 鍙傛暟
+     * @param pageQuery  鍒嗛〉
+     */
+    @Override
+    public TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
+        QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
+        queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
+        Page<FlowTaskVo> page = flwTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper);
+        return TableDataInfo.build(page);
+    }
+
+    private QueryWrapper<FlowTaskBo> buildQueryWrapper(FlowTaskBo flowTaskBo) {
+        QueryWrapper<FlowTaskBo> wrapper = Wrappers.query();
+        wrapper.like(StringUtils.isNotBlank(flowTaskBo.getNodeName()), "t.node_name", flowTaskBo.getNodeName());
+        wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowName()), "t.flow_name", flowTaskBo.getFlowName());
+        wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowCode()), "t.flow_code", flowTaskBo.getFlowCode());
+        wrapper.in(CollUtil.isNotEmpty(flowTaskBo.getCreateByIds()), "t.create_by", flowTaskBo.getCreateByIds());
+        if (StringUtils.isNotBlank(flowTaskBo.getCategory())) {
+            List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory()));
+            wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr));
+        }
+        wrapper.orderByDesc("t.create_time");
+        return wrapper;
+    }
+
+    /**
+     * 椹冲洖浠诲姟
+     *
+     * @param bo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean backProcess(BackProcessBo bo) {
+        try {
+            Long taskId = bo.getTaskId();
+            String notice = bo.getNotice();
+            List<String> messageType = bo.getMessageType();
+            String message = bo.getMessage();
+            FlowTask task = flowTaskMapper.selectById(taskId);
+            if (ObjectUtil.isNull(task)) {
+                throw new ServiceException("浠诲姟涓嶅瓨鍦紒");
+            }
+            Instance inst = insService.getById(task.getInstanceId());
+            BusinessStatusEnum.checkBackStatus(inst.getFlowStatus());
+            Long definitionId = task.getDefinitionId();
+            Definition definition = defService.getById(definitionId);
+            String applyNodeCode = WorkflowUtils.applyNodeCode(definitionId);
+            FlowParams flowParams = FlowParams.build();
+            flowParams.nodeCode(bo.getNodeCode());
+            flowParams.message(message);
+            flowParams.skipType(SkipType.REJECT.getKey());
+            flowParams.flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus())
+                .hisStatus(TaskStatusEnum.BACK.getStatus());
+            flowParams.hisTaskExt(bo.getFileId());
+            taskService.skip(task.getId(), flowParams);
+
+            Instance instance = insService.getById(inst.getId());
+            this.setHandler(instance, task, null);
+            // 娑堟伅閫氱煡
+            WorkflowUtils.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 鑾峰彇鍙┏鍥炵殑鍓嶇疆鑺傜偣
+     *
+     * @param definitionId 娴佺▼瀹氫箟id
+     * @param nowNodeCode  褰撳墠鑺傜偣
+     */
+    @Override
+    public List<Node> getBackTaskNode(Long definitionId, String nowNodeCode) {
+        List<Node> nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), definitionId);
+        if (!CollUtil.isNotEmpty(nodeCodes)) {
+            return nodeCodes;
+        }
+        //鍒ゆ柇鏄惁閰嶇疆浜嗗浐瀹氶┏鍥炶妭鐐�
+        Node node = nodeCodes.get(0);
+        if (StringUtils.isNotBlank(node.getAnyNodeSkip())) {
+            return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), definitionId);
+        }
+        //鑾峰彇鍙┏鍥炵殑鍓嶇疆鑺傜偣
+        List<Node> nodes = nodeService.previousNodeList(definitionId, nowNodeCode);
+        if (CollUtil.isNotEmpty(nodes)) {
+            return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
+        }
+        return nodes;
+    }
+
+    /**
+     * 缁堟浠诲姟
+     *
+     * @param bo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean terminationTask(FlowTerminationBo bo) {
+        try {
+            Long taskId = bo.getTaskId();
+            Task task = taskService.getById(taskId);
+            if (task == null) {
+                throw new ServiceException("浠诲姟涓嶅瓨鍦紒");
+            }
+            Instance instance = insService.getById(task.getInstanceId());
+            if (ObjectUtil.isNotNull(instance)) {
+                BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus());
+            }
+            FlowParams flowParams = new FlowParams();
+            flowParams.message(bo.getComment());
+            flowParams.flowStatus(BusinessStatusEnum.TERMINATION.getStatus())
+                .hisStatus(TaskStatusEnum.TERMINATION.getStatus());
+            taskService.termination(taskId, flowParams);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskIdList 浠诲姟id
+     */
+    @Override
+    public List<FlowTask> selectByIdList(List<Long> taskIdList) {
+        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
+            .in(FlowTask::getId, taskIdList));
+    }
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Override
+    public FlowTaskVo selectById(Long taskId) {
+        Task task = taskService.getById(taskId);
+        if (ObjectUtil.isNull(task)) {
+            return null;
+        }
+        FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class);
+        Instance instance = insService.getById(task.getInstanceId());
+        Definition definition = defService.getById(task.getDefinitionId());
+        flowTaskVo.setFlowStatus(instance.getFlowStatus());
+        flowTaskVo.setVersion(definition.getVersion());
+        flowTaskVo.setFlowCode(definition.getFlowCode());
+        flowTaskVo.setFlowName(definition.getFlowName());
+        flowTaskVo.setBusinessId(instance.getBusinessId());
+        List<Node> nodeList = nodeService.getByNodeCodes(Collections.singletonList(flowTaskVo.getNodeCode()), instance.getDefinitionId());
+        if (CollUtil.isNotEmpty(nodeList)) {
+            Node node = nodeList.get(0);
+            flowTaskVo.setNodeRatio(node.getNodeRatio());
+        }
+        return flowTaskVo;
+    }
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskIdList 浠诲姟id
+     * @return 缁撴灉
+     */
+    @Override
+    public List<FlowHisTask> selectHisTaskByIdList(List<Long> taskIdList) {
+        return flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class)
+            .in(FlowHisTask::getId, taskIdList));
+    }
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    @Override
+    public FlowHisTask selectHisTaskById(Long taskId) {
+        return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class)
+            .eq(FlowHisTask::getId, taskId));
+    }
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ浠诲姟
+     *
+     * @param instanceIdList 娴佺▼瀹炰緥id
+     */
+    @Override
+    public List<FlowTask> selectByInstIdList(List<Long> instanceIdList) {
+        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
+            .in(FlowTask::getInstanceId, instanceIdList));
+    }
+
+    /**
+     * 鎸夌収瀹炰緥id鏌ヨ浠诲姟
+     *
+     * @param instanceId 娴佺▼瀹炰緥id
+     */
+    @Override
+    public List<FlowTask> selectByInstId(Long instanceId) {
+        return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
+            .eq(FlowTask::getInstanceId, instanceId));
+    }
+
+    /**
+     * 浠诲姟鎿嶄綔
+     *
+     * @param bo            鍙傛暟
+     * @param taskOperation 鎿嶄綔绫诲瀷锛屽娲� delegateTask銆佽浆鍔� transferTask銆佸姞绛� addSignature銆佸噺绛� reductionSignature
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean taskOperation(TaskOperationBo bo, String taskOperation) {
+        FlowParams flowParams = new FlowParams();
+        flowParams.message(bo.getMessage());
+        if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
+            flowParams.ignore(true);
+        }
+
+        // 鏍规嵁鎿嶄綔绫诲瀷鏋勫缓 FlowParams
+        switch (taskOperation) {
+            case DELEGATE_TASK, TRANSFER_TASK -> {
+                ValidatorUtils.validate(bo, AddGroup.class);
+                flowParams.addHandlers(Collections.singletonList(bo.getUserId()));
+            }
+            case ADD_SIGNATURE -> {
+                ValidatorUtils.validate(bo, EditGroup.class);
+                flowParams.addHandlers(bo.getUserIds());
+            }
+            case REDUCTION_SIGNATURE -> {
+                ValidatorUtils.validate(bo, EditGroup.class);
+                flowParams.reductionHandlers(bo.getUserIds());
+            }
+            default -> {
+                log.error("Invalid operation type:{} ", taskOperation);
+                throw new ServiceException("Invalid operation type " + taskOperation);
+            }
+        }
+
+        Long taskId = bo.getTaskId();
+        FlowTaskVo flowTaskVo = selectById(taskId);
+        if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) {
+            if (flowTaskVo.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) {
+                throw new ServiceException(flowTaskVo.getNodeName() + "涓嶆槸浼氱鑺傜偣锛�");
+            }
+        }
+        // 璁剧疆浠诲姟鐘舵�佸苟鎵ц瀵瑰簲鐨勪换鍔℃搷浣�
+        switch (taskOperation) {
+            //濮旀淳浠诲姟
+            case DELEGATE_TASK -> {
+                flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus());
+                return taskService.depute(taskId, flowParams);
+            }
+            //杞姙浠诲姟
+            case TRANSFER_TASK -> {
+                flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus());
+                return taskService.transfer(taskId, flowParams);
+            }
+            //鍔犵锛屽鍔犲姙鐞嗕汉
+            case ADD_SIGNATURE -> {
+                flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus());
+                return taskService.addSignature(taskId, flowParams);
+            }
+            //鍑忕锛屽噺灏戝姙鐞嗕汉
+            case REDUCTION_SIGNATURE -> {
+                flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus());
+                return taskService.reductionSignature(taskId, flowParams);
+            }
+            default -> {
+                log.error("Invalid operation type:{} ", taskOperation);
+                throw new ServiceException("Invalid operation type " + taskOperation);
+            }
+        }
+    }
+
+    /**
+     * 淇敼浠诲姟鍔炵悊浜猴紙姝ゆ柟娉曞皢浼氭壒閲忎慨鏀规墍鏈変换鍔$殑鍔炵悊浜猴級
+     *
+     * @param taskIdList 浠诲姟id
+     * @param userId     鐢ㄦ埛id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean updateAssignee(List<Long> taskIdList, String userId) {
+        if (CollUtil.isEmpty(taskIdList)) {
+            return false;
+        }
+        try {
+            List<FlowTask> flowTasks = this.selectByIdList(taskIdList);
+            // 鎵归噺鍒犻櫎鐜版湁浠诲姟鐨勫姙鐞嗕汉璁板綍
+            if (CollUtil.isNotEmpty(flowTasks)) {
+                WorkflowUtils.getFlowUserService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId));
+                List<User> userList = flowTasks.stream()
+                    .map(flowTask -> {
+                        FlowUser flowUser = new FlowUser();
+                        flowUser.setType(TaskAssigneeType.APPROVER.getCode());
+                        flowUser.setProcessedBy(userId);
+                        flowUser.setAssociated(flowTask.getId());
+                        return flowUser;
+                    })
+                    .collect(Collectors.toList());
+                if (CollUtil.isNotEmpty(userList)) {
+                    WorkflowUtils.getFlowUserService().saveBatch(userList);
+                }
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * 鑾峰彇浠诲姟鎵�鏈夊姙鐞嗕汉
+     *
+     * @param taskIdList 浠诲姟id
+     */
+    @Override
+    public Map<Long, List<UserDTO>> currentTaskAllUser(List<Long> taskIdList) {
+        Map<Long, List<UserDTO>> map = new HashMap<>();
+        // 鑾峰彇涓庡綋鍓嶄换鍔″叧鑱旂殑鐢ㄦ埛鍒楄〃
+        List<User> associatedUsers = WorkflowUtils.getFlowUserService().getByAssociateds(taskIdList);
+        Map<Long, List<User>> listMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated);
+        for (Map.Entry<Long, List<User>> entry : listMap.entrySet()) {
+            List<User> value = entry.getValue();
+            if (CollUtil.isNotEmpty(value)) {
+                List<UserDTO> userDTOS = userService.selectListByIds(StreamUtils.toList(value, e -> Long.valueOf(e.getProcessedBy())));
+                map.put(entry.getKey(), userDTOS);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 鑾峰彇褰撳墠浠诲姟鐨勬墍鏈夊姙鐞嗕汉
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Override
+    public List<UserDTO> currentTaskAllUser(Long taskId) {
+        // 鑾峰彇涓庡綋鍓嶄换鍔″叧鑱旂殑鐢ㄦ埛鍒楄〃
+        List<User> userList = WorkflowUtils.getFlowUserService().getByAssociateds(Collections.singletonList(taskId));
+        if (CollUtil.isEmpty(userList)) {
+            return Collections.emptyList();
+        }
+        return userService.selectListByIds(StreamUtils.toList(userList, e -> Long.valueOf(e.getProcessedBy())));
+    }
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java
index a62ce5f..2c43173 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java
@@ -1,20 +1,25 @@
 package org.dromara.workflow.service.impl;
 
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.event.ProcessDeleteEvent;
 import org.dromara.common.core.domain.event.ProcessEvent;
 import org.dromara.common.core.domain.event.ProcessTaskEvent;
 import org.dromara.common.core.enums.BusinessStatusEnum;
 import org.dromara.common.core.service.WorkflowService;
 import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.domain.BaseEntity;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.workflow.common.ConditionalOnEnable;
 import org.dromara.workflow.domain.TestLeave;
 import org.dromara.workflow.domain.bo.TestLeaveBo;
 import org.dromara.workflow.domain.vo.TestLeaveVo;
@@ -24,8 +29,8 @@
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 璇峰亣Service涓氬姟灞傚鐞�
@@ -33,6 +38,7 @@
  * @author may
  * @date 2023-07-21
  */
+@ConditionalOnEnable
 @RequiredArgsConstructor
 @Service
 @Slf4j
@@ -82,6 +88,9 @@
      */
     @Override
     public TestLeaveVo insertByBo(TestLeaveBo bo) {
+        long day = DateUtil.betweenDay(bo.getStartDate(), bo.getEndDate(), true);
+        // 鎴鏃ユ湡涔熺畻涓�澶�
+        bo.setLeaveDays((int) day + 1);
         TestLeave add = MapstructUtils.convert(bo, TestLeave.class);
         if (StringUtils.isBlank(add.getStatus())) {
             add.setStatus(BusinessStatusEnum.DRAFT.getStatus());
@@ -108,24 +117,33 @@
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public Boolean deleteWithValidByIds(Collection<Long> ids) {
-        List<String> idList = StreamUtils.toList(ids, String::valueOf);
-        workflowService.deleteRunAndHisInstance(idList);
+    public Boolean deleteWithValidByIds(List<Long> ids) {
+        workflowService.deleteInstance(ids);
         return baseMapper.deleteByIds(ids) > 0;
     }
 
     /**
-     * 鎬讳綋娴佺▼鐩戝惉(渚嬪: 鎻愪氦 閫�鍥� 鎾ら攢 缁堟 浣滃簾绛�)
-     * 姝e父浣跨敤鍙渶#processEvent.key=='leave1'
+     * 鎬讳綋娴佺▼鐩戝惉(渚嬪: 鑽夌锛屾挙閿�锛岄��鍥烇紝浣滃簾锛岀粓姝紝宸插畬鎴愮瓑)
+     * 姝e父浣跨敤鍙渶#processEvent.flowCode=='leave1'
      * 绀轰緥涓轰簡鏂逛究鍒欎娇鐢╯tartsWith鍖归厤浜嗗叏閮ㄧず渚媖ey
      *
      * @param processEvent 鍙傛暟
      */
-    @EventListener(condition = "#processEvent.key.startsWith('leave')")
+    @EventListener(condition = "#processEvent.flowCode.startsWith('leave')")
     public void processHandler(ProcessEvent processEvent) {
         log.info("褰撳墠浠诲姟鎵ц浜唟}", processEvent.toString());
-        TestLeave testLeave = baseMapper.selectById(Long.valueOf(processEvent.getBusinessKey()));
+        TestLeave testLeave = baseMapper.selectById(Long.valueOf(processEvent.getBusinessId()));
         testLeave.setStatus(processEvent.getStatus());
+        // 鐢ㄤ簬渚嬪瀹℃壒闄勪欢 瀹℃壒鎰忚绛� 瀛樺偍鍒颁笟鍔¤〃鍐� 鑷鏍规嵁涓氬姟瀹炵幇瀛樺偍娴佺▼
+        Map<String, Object> params = processEvent.getParams();
+        if (MapUtil.isNotEmpty(params)) {
+            // 鍘嗗彶浠诲姟鎵╁睍(閫氬父涓洪檮浠�)
+            String hisTaskExt = Convert.toStr(params.get("hisTaskExt"));
+            // 鍔炵悊浜�
+            String handler = Convert.toStr(params.get("handler"));
+            // 鍔炵悊鎰忚
+            String message = Convert.toStr(params.get("message"));
+        }
         if (processEvent.isSubmit()) {
             testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
         }
@@ -134,19 +152,37 @@
 
     /**
      * 鎵ц鍔炵悊浠诲姟鐩戝惉
-     * 绀轰緥锛氫篃鍙�氳繃  @EventListener(condition = "#processTaskEvent.key=='leave1'")杩涜鍒ゆ柇
+     * 绀轰緥锛氫篃鍙�氳繃  @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")杩涜鍒ゆ柇
      * 鍦ㄦ柟娉曚腑鍒ゆ柇娴佺▼鑺傜偣key
-     * if ("xxx".equals(processTaskEvent.getTaskDefinitionKey())) {
+     * if ("xxx".equals(processTaskEvent.getNodeCode())) {
      * //鎵ц涓氬姟閫昏緫
      * }
      *
      * @param processTaskEvent 鍙傛暟
      */
-    @EventListener(condition = "#processTaskEvent.key=='leave1' && #processTaskEvent.taskDefinitionKey=='Activity_14633hx'")
+    @EventListener(condition = "#processTaskEvent.flowCode.startsWith('leave')")
     public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
         log.info("褰撳墠浠诲姟鎵ц浜唟}", processTaskEvent.toString());
-        TestLeave testLeave = baseMapper.selectById(Long.valueOf(processTaskEvent.getBusinessKey()));
+        TestLeave testLeave = baseMapper.selectById(Long.valueOf(processTaskEvent.getBusinessId()));
         testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
         baseMapper.updateById(testLeave);
     }
+
+    /**
+     * 鐩戝惉鍒犻櫎娴佺▼浜嬩欢
+     * 姝e父浣跨敤鍙渶#processDeleteEvent.flowCode=='leave1'
+     * 绀轰緥涓轰簡鏂逛究鍒欎娇鐢╯tartsWith鍖归厤浜嗗叏閮ㄧず渚媖ey
+     *
+     * @param processDeleteEvent 鍙傛暟
+     */
+    @EventListener(condition = "#processDeleteEvent.flowCode.startsWith('leave')")
+    public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) {
+        log.info("鐩戝惉鍒犻櫎娴佺▼浜嬩欢锛屽綋鍓嶄换鍔℃墽琛屼簡{}", processDeleteEvent.toString());
+        TestLeave testLeave = baseMapper.selectById(Long.valueOf(processDeleteEvent.getBusinessId()));
+        if (ObjectUtil.isNull(testLeave)) {
+            return;
+        }
+        baseMapper.deleteById(testLeave.getId());
+    }
+
 }
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java
deleted file mode 100644
index e562823..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.workflow.domain.WfCategory;
-import org.dromara.workflow.domain.bo.WfCategoryBo;
-import org.dromara.workflow.domain.vo.WfCategoryVo;
-import org.dromara.workflow.mapper.WfCategoryMapper;
-import org.dromara.workflow.service.IWfCategoryService;
-import org.dromara.workflow.utils.QueryUtils;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.repository.Deployment;
-import org.flowable.engine.repository.Model;
-import org.flowable.engine.repository.ProcessDefinition;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * 娴佺▼鍒嗙被Service涓氬姟灞傚鐞�
- *
- * @author may
- * @date 2023-06-28
- */
-@RequiredArgsConstructor
-@Service
-public class WfCategoryServiceImpl implements IWfCategoryService {
-
-    private final WfCategoryMapper baseMapper;
-    @Autowired(required = false)
-    private RepositoryService repositoryService;
-
-    /**
-     * 鏌ヨ娴佺▼鍒嗙被
-     */
-    @Override
-    public WfCategoryVo queryById(Long id) {
-        return baseMapper.selectVoById(id);
-    }
-
-
-    /**
-     * 鏌ヨ娴佺▼鍒嗙被鍒楄〃
-     */
-    @Override
-    public List<WfCategoryVo> queryList(WfCategoryBo bo) {
-        LambdaQueryWrapper<WfCategory> lqw = buildQueryWrapper(bo);
-        return baseMapper.selectVoList(lqw);
-    }
-
-    private LambdaQueryWrapper<WfCategory> buildQueryWrapper(WfCategoryBo bo) {
-        LambdaQueryWrapper<WfCategory> lqw = Wrappers.lambdaQuery();
-        lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), WfCategory::getCategoryName, bo.getCategoryName());
-        lqw.eq(StringUtils.isNotBlank(bo.getCategoryCode()), WfCategory::getCategoryCode, bo.getCategoryCode());
-        return lqw;
-    }
-
-    /**
-     * 鏂板娴佺▼鍒嗙被
-     */
-    @Override
-    public Boolean insertByBo(WfCategoryBo bo) {
-        WfCategory add = MapstructUtils.convert(bo, WfCategory.class);
-        validEntityBeforeSave(add);
-        boolean flag = baseMapper.insert(add) > 0;
-        if (flag) {
-            bo.setId(add.getId());
-        }
-        return flag;
-    }
-
-    /**
-     * 淇敼娴佺▼鍒嗙被
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean updateByBo(WfCategoryBo bo) {
-        WfCategory update = MapstructUtils.convert(bo, WfCategory.class);
-        validEntityBeforeSave(update);
-        WfCategoryVo wfCategoryVo = baseMapper.selectVoById(bo.getId());
-        List<ProcessDefinition> processDefinitionList = QueryUtils.definitionQuery().processDefinitionCategory(wfCategoryVo.getCategoryCode()).list();
-        for (ProcessDefinition processDefinition : processDefinitionList) {
-            repositoryService.setProcessDefinitionCategory(processDefinition.getId(), bo.getCategoryCode());
-        }
-        List<Deployment> deploymentList = QueryUtils.deploymentQuery().deploymentCategory(wfCategoryVo.getCategoryCode()).list();
-        for (Deployment deployment : deploymentList) {
-            repositoryService.setDeploymentCategory(deployment.getId(), bo.getCategoryCode());
-        }
-        List<Model> modelList = QueryUtils.modelQuery().modelCategory(wfCategoryVo.getCategoryCode()).list();
-        for (Model model : modelList) {
-            model.setCategory(bo.getCategoryCode());
-            repositoryService.saveModel(model);
-        }
-        return baseMapper.updateById(update) > 0;
-    }
-
-    /**
-     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
-     */
-    private void validEntityBeforeSave(WfCategory entity) {
-        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
-    }
-
-    /**
-     * 鎵归噺鍒犻櫎娴佺▼鍒嗙被
-     */
-    @Override
-    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
-        if (isValid) {
-            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
-        }
-        return baseMapper.deleteByIds(ids) > 0;
-    }
-
-    /**
-     * 鎸夌収绫诲埆缂栫爜鏌ヨ
-     *
-     * @param categoryCode 鍒嗙被姣斿悧
-     */
-    @Override
-    public WfCategory queryByCategoryCode(String categoryCode) {
-        return baseMapper.selectOne(new LambdaQueryWrapper<WfCategory>().eq(WfCategory::getCategoryCode, categoryCode));
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java
deleted file mode 100644
index ab55ff8..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import org.dromara.common.core.utils.MapstructUtils;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import lombok.RequiredArgsConstructor;
-import org.dromara.workflow.domain.WfDefinitionConfig;
-import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
-import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
-import org.dromara.workflow.service.IWfDefinitionConfigService;
-import org.springframework.stereotype.Service;
-import org.dromara.workflow.mapper.WfDefinitionConfigMapper;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-import java.util.Collection;
-
-/**
- * 娴佺▼瀹氫箟閰嶇疆Service涓氬姟灞傚鐞�
- *
- * @author may
- * @date 2024-03-18
- */
-@RequiredArgsConstructor
-@Service
-public class WfDefinitionConfigServiceImpl implements IWfDefinitionConfigService {
-
-    private final WfDefinitionConfigMapper baseMapper;
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
-     */
-    @Override
-    public WfDefinitionConfigVo getByDefId(String definitionId) {
-        return baseMapper.selectVoOne(new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getDefinitionId, definitionId));
-    }
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
-     *
-     * @param tableName 琛ㄥ悕
-     * @return 缁撴灉
-     */
-    @Override
-    public WfDefinitionConfigVo getByTableNameLastVersion(String tableName) {
-        List<WfDefinitionConfigVo> wfDefinitionConfigVos = baseMapper.selectVoList(
-            new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getTableName, tableName).orderByDesc(WfDefinitionConfig::getVersion));
-        if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) {
-            return wfDefinitionConfigVos.get(0);
-        }
-        return null;
-    }
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
-     *
-     * @param definitionId 娴佺▼瀹氫箟id
-     * @param tableName    琛ㄥ悕
-     * @return 缁撴灉
-     */
-    @Override
-    public WfDefinitionConfigVo getByDefIdAndTableName(String definitionId, String tableName) {
-        return baseMapper.selectVoOne(new LambdaQueryWrapper<WfDefinitionConfig>()
-            .eq(WfDefinitionConfig::getDefinitionId, definitionId)
-            .eq(WfDefinitionConfig::getTableName, tableName));
-    }
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鎺掗櫎褰撳墠鏌ヨ鐨勬祦绋嬪畾涔�
-     *
-     * @param tableName    琛ㄥ悕
-     * @param definitionId 娴佺▼瀹氫箟id
-     */
-    @Override
-    public List<WfDefinitionConfigVo> getByTableNameNotDefId(String tableName, String definitionId) {
-        return baseMapper.selectVoList(new LambdaQueryWrapper<WfDefinitionConfig>()
-            .eq(WfDefinitionConfig::getTableName, tableName)
-            .ne(WfDefinitionConfig::getDefinitionId, definitionId));
-    }
-
-    /**
-     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鍒楄〃
-     */
-    @Override
-    public List<WfDefinitionConfigVo> queryList(List<String> definitionIds) {
-        return baseMapper.selectVoList(new LambdaQueryWrapper<WfDefinitionConfig>().in(WfDefinitionConfig::getDefinitionId, definitionIds));
-    }
-
-    /**
-     * 鏂板娴佺▼瀹氫箟閰嶇疆
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Boolean saveOrUpdate(WfDefinitionConfigBo bo) {
-        WfDefinitionConfig add = MapstructUtils.convert(bo, WfDefinitionConfig.class);
-        baseMapper.delete(new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getTableName, bo.getTableName()));
-        add.setTableName(add.getTableName().toLowerCase());
-        boolean flag = baseMapper.insertOrUpdate(add);
-        if (baseMapper.insertOrUpdate(add)) {
-            bo.setId(add.getId());
-        }
-        return flag;
-    }
-
-    /**
-     * 鎵归噺鍒犻櫎娴佺▼瀹氫箟閰嶇疆
-     */
-    @Override
-    public Boolean deleteByIds(Collection<Long> ids) {
-        return baseMapper.deleteByIds(ids) > 0;
-    }
-
-    @Override
-    public Boolean deleteByDefIds(Collection<String> ids) {
-        return baseMapper.delete(new LambdaQueryWrapper<WfDefinitionConfig>().in(WfDefinitionConfig::getDefinitionId, ids)) > 0;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java
deleted file mode 100644
index da2e777..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import lombok.RequiredArgsConstructor;
-import org.dromara.workflow.common.enums.FormTypeEnum;
-import org.springframework.stereotype.Service;
-import org.dromara.workflow.domain.bo.WfFormManageBo;
-import org.dromara.workflow.domain.vo.WfFormManageVo;
-import org.dromara.workflow.domain.WfFormManage;
-import org.dromara.workflow.mapper.WfFormManageMapper;
-import org.dromara.workflow.service.IWfFormManageService;
-
-import java.util.List;
-import java.util.Collection;
-
-/**
- * 琛ㄥ崟绠$悊Service涓氬姟灞傚鐞�
- *
- * @author may
- * @date 2024-03-29
- */
-@RequiredArgsConstructor
-@Service
-public class WfFormManageServiceImpl implements IWfFormManageService {
-
-    private final WfFormManageMapper baseMapper;
-
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊
-     */
-    @Override
-    public WfFormManageVo queryById(Long id) {
-        return baseMapper.selectVoById(id);
-    }
-
-    @Override
-    public List<WfFormManageVo> queryByIds(List<Long> ids) {
-        return baseMapper.selectVoBatchIds(ids);
-    }
-
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
-     */
-    @Override
-    public TableDataInfo<WfFormManageVo> queryPageList(WfFormManageBo bo, PageQuery pageQuery) {
-        LambdaQueryWrapper<WfFormManage> lqw = buildQueryWrapper(bo);
-        Page<WfFormManageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
-        return TableDataInfo.build(result);
-    }
-
-    @Override
-    public List<WfFormManageVo> selectList() {
-        List<WfFormManageVo> wfFormManageVos = baseMapper.selectVoList(new LambdaQueryWrapper<WfFormManage>().orderByDesc(WfFormManage::getUpdateTime));
-        for (WfFormManageVo wfFormManageVo : wfFormManageVos) {
-            wfFormManageVo.setFormTypeName(FormTypeEnum.findByType(wfFormManageVo.getFormType()));
-        }
-        return wfFormManageVos;
-    }
-
-    /**
-     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
-     */
-    @Override
-    public List<WfFormManageVo> queryList(WfFormManageBo bo) {
-        LambdaQueryWrapper<WfFormManage> lqw = buildQueryWrapper(bo);
-        return baseMapper.selectVoList(lqw);
-    }
-
-    private LambdaQueryWrapper<WfFormManage> buildQueryWrapper(WfFormManageBo bo) {
-        LambdaQueryWrapper<WfFormManage> lqw = Wrappers.lambdaQuery();
-        lqw.like(StringUtils.isNotBlank(bo.getFormName()), WfFormManage::getFormName, bo.getFormName());
-        lqw.eq(StringUtils.isNotBlank(bo.getFormType()), WfFormManage::getFormType, bo.getFormType());
-        return lqw;
-    }
-
-    /**
-     * 鏂板琛ㄥ崟绠$悊
-     */
-    @Override
-    public Boolean insertByBo(WfFormManageBo bo) {
-        WfFormManage add = MapstructUtils.convert(bo, WfFormManage.class);
-        boolean flag = baseMapper.insert(add) > 0;
-        if (flag) {
-            bo.setId(add.getId());
-        }
-        return flag;
-    }
-
-    /**
-     * 淇敼琛ㄥ崟绠$悊
-     */
-    @Override
-    public Boolean updateByBo(WfFormManageBo bo) {
-        WfFormManage update = MapstructUtils.convert(bo, WfFormManage.class);
-        return baseMapper.updateById(update) > 0;
-    }
-
-    /**
-     * 鎵归噺鍒犻櫎琛ㄥ崟绠$悊
-     */
-    @Override
-    public Boolean deleteByIds(Collection<Long> ids) {
-        return baseMapper.deleteByIds(ids) > 0;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java
deleted file mode 100644
index 2f71482..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import lombok.RequiredArgsConstructor;
-import org.dromara.common.core.utils.StreamUtils;
-import org.dromara.workflow.domain.vo.WfFormManageVo;
-import org.dromara.workflow.service.IWfFormManageService;
-import org.springframework.stereotype.Service;
-import org.dromara.workflow.domain.vo.WfNodeConfigVo;
-import org.dromara.workflow.domain.WfNodeConfig;
-import org.dromara.workflow.mapper.WfNodeConfigMapper;
-import org.dromara.workflow.service.IWfNodeConfigService;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * 鑺傜偣閰嶇疆Service涓氬姟灞傚鐞�
- *
- * @author may
- * @date 2024-03-30
- */
-@RequiredArgsConstructor
-@Service
-public class WfNodeConfigServiceImpl implements IWfNodeConfigService {
-
-    private final WfNodeConfigMapper baseMapper;
-    private final IWfFormManageService wfFormManageService;
-
-    /**
-     * 鏌ヨ鑺傜偣閰嶇疆
-     */
-    @Override
-    public WfNodeConfigVo queryById(Long id) {
-        return baseMapper.selectVoById(id);
-    }
-
-    /**
-     * 淇濆瓨鑺傜偣閰嶇疆
-     */
-    @Override
-    public Boolean saveOrUpdate(List<WfNodeConfig> list) {
-        return baseMapper.insertOrUpdateBatch(list);
-    }
-
-    /**
-     * 鎵归噺鍒犻櫎鑺傜偣閰嶇疆
-     */
-    @Override
-    public Boolean deleteByIds(Collection<Long> ids) {
-        return baseMapper.deleteByIds(ids) > 0;
-    }
-
-
-
-    @Override
-    public Boolean deleteByDefIds(Collection<String> ids) {
-        return baseMapper.delete(new LambdaQueryWrapper<WfNodeConfig>().in(WfNodeConfig::getDefinitionId, ids)) > 0;
-    }
-
-    @Override
-    public List<WfNodeConfigVo> selectByDefIds(Collection<String> ids) {
-        List<WfNodeConfigVo> wfNodeConfigVos = baseMapper.selectVoList(new LambdaQueryWrapper<WfNodeConfig>().in(WfNodeConfig::getDefinitionId, ids));
-        if (CollUtil.isNotEmpty(wfNodeConfigVos)) {
-            List<Long> formIds = StreamUtils.toList(wfNodeConfigVos, WfNodeConfigVo::getFormId);
-            List<WfFormManageVo> wfFormManageVos = wfFormManageService.queryByIds(formIds);
-            for (WfNodeConfigVo wfNodeConfigVo : wfNodeConfigVos) {
-                wfFormManageVos.stream().filter(e -> ObjectUtil.equals(e.getId(), wfNodeConfigVo.getFormId())).findFirst().ifPresent(wfNodeConfigVo::setWfFormManageVo);
-            }
-        }
-        return wfNodeConfigVos;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java
deleted file mode 100644
index 6c255d3..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package org.dromara.workflow.service.impl;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.dromara.common.core.exception.ServiceException;
-import org.dromara.common.core.utils.StreamUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.satoken.utils.LoginHelper;
-import org.dromara.workflow.domain.WfTaskBackNode;
-import org.dromara.workflow.domain.vo.MultiInstanceVo;
-import org.dromara.workflow.mapper.WfTaskBackNodeMapper;
-import org.dromara.workflow.service.IWfTaskBackNodeService;
-import org.dromara.workflow.utils.WorkflowUtils;
-import org.flowable.task.api.Task;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.dromara.workflow.common.constant.FlowConstant.MULTI_INSTANCE;
-import static org.dromara.workflow.common.constant.FlowConstant.USER_TASK;
-
-
-/**
- * 鑺傜偣椹冲洖璁板綍Service涓氬姟灞傚鐞�
- *
- * @author may
- * @date 2024-03-13
- */
-@Slf4j
-@RequiredArgsConstructor
-@Service
-public class WfTaskBackNodeServiceImpl implements IWfTaskBackNodeService {
-
-    private final WfTaskBackNodeMapper wfTaskBackNodeMapper;
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void recordExecuteNode(Task task) {
-        List<WfTaskBackNode> list = getListByInstanceId(task.getProcessInstanceId());
-        WfTaskBackNode wfTaskBackNode = new WfTaskBackNode();
-        wfTaskBackNode.setNodeId(task.getTaskDefinitionKey());
-        wfTaskBackNode.setNodeName(task.getName());
-        wfTaskBackNode.setInstanceId(task.getProcessInstanceId());
-        wfTaskBackNode.setAssignee(String.valueOf(LoginHelper.getUserId()));
-        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
-        if (ObjectUtil.isNotEmpty(multiInstance)) {
-            wfTaskBackNode.setTaskType(MULTI_INSTANCE);
-        } else {
-            wfTaskBackNode.setTaskType(USER_TASK);
-        }
-        if (CollUtil.isEmpty(list)) {
-            wfTaskBackNode.setOrderNo(0);
-            wfTaskBackNodeMapper.insert(wfTaskBackNode);
-        } else {
-            WfTaskBackNode taskNode = StreamUtils.findFirst(list, e -> e.getNodeId().equals(wfTaskBackNode.getNodeId()) && e.getOrderNo() == 0);
-            if (ObjectUtil.isEmpty(taskNode)) {
-                wfTaskBackNode.setOrderNo(list.get(0).getOrderNo() + 1);
-                WfTaskBackNode node = getListByInstanceIdAndNodeId(wfTaskBackNode.getInstanceId(), wfTaskBackNode.getNodeId());
-                if (ObjectUtil.isNotEmpty(node)) {
-                    node.setAssignee(node.getAssignee() + StringUtils.SEPARATOR + LoginHelper.getUserId());
-                    wfTaskBackNodeMapper.updateById(node);
-                } else {
-                    wfTaskBackNodeMapper.insert(wfTaskBackNode);
-                }
-            }
-        }
-    }
-
-    @Override
-    public List<WfTaskBackNode> getListByInstanceId(String processInstanceId) {
-        LambdaQueryWrapper<WfTaskBackNode> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId);
-        wrapper.orderByDesc(WfTaskBackNode::getOrderNo);
-        return wfTaskBackNodeMapper.selectList(wrapper);
-    }
-
-    @Override
-    public WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId) {
-        LambdaQueryWrapper<WfTaskBackNode> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId);
-        queryWrapper.eq(WfTaskBackNode::getNodeId, nodeId);
-        return wfTaskBackNodeMapper.selectOne(queryWrapper);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean deleteBackTaskNode(String processInstanceId, String targetActivityId) {
-        try {
-            LambdaQueryWrapper<WfTaskBackNode> queryWrapper = new LambdaQueryWrapper<>();
-            queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId);
-            queryWrapper.eq(WfTaskBackNode::getNodeId, targetActivityId);
-            WfTaskBackNode actTaskNode = wfTaskBackNodeMapper.selectOne(queryWrapper);
-            if (ObjectUtil.isNotNull(actTaskNode)) {
-                Integer orderNo = actTaskNode.getOrderNo();
-                List<WfTaskBackNode> taskNodeList = getListByInstanceId(processInstanceId);
-                List<Long> ids = new ArrayList<>();
-                if (CollUtil.isNotEmpty(taskNodeList)) {
-                    for (WfTaskBackNode taskNode : taskNodeList) {
-                        if (taskNode.getOrderNo() >= orderNo) {
-                            ids.add(taskNode.getId());
-                        }
-                    }
-                }
-                if (CollUtil.isNotEmpty(ids)) {
-                    wfTaskBackNodeMapper.deleteByIds(ids);
-                }
-            }
-            return true;
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-            throw new ServiceException("鍒犻櫎澶辫触");
-        }
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean deleteByInstanceId(String processInstanceId) {
-        LambdaQueryWrapper<WfTaskBackNode> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId);
-        List<WfTaskBackNode> list = wfTaskBackNodeMapper.selectList(wrapper);
-        int delete = wfTaskBackNodeMapper.delete(wrapper);
-        if (list.size() != delete) {
-            throw new ServiceException("鍒犻櫎澶辫触");
-        }
-        return true;
-    }
-
-    @Override
-    public boolean deleteByInstanceIds(List<String> processInstanceIds) {
-        LambdaQueryWrapper<WfTaskBackNode> wrapper = new LambdaQueryWrapper<>();
-        wrapper.in(WfTaskBackNode::getInstanceId, processInstanceIds);
-        List<WfTaskBackNode> list = wfTaskBackNodeMapper.selectList(wrapper);
-        int delete = wfTaskBackNodeMapper.delete(wrapper);
-        if (list.size() != delete) {
-            throw new ServiceException("鍒犻櫎澶辫触");
-        }
-        return true;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
index f75a188..f8a20b5 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
@@ -1,14 +1,20 @@
 package org.dromara.workflow.service.impl;
 
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
 import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.dto.CompleteTaskDTO;
+import org.dromara.common.core.domain.dto.StartProcessDTO;
+import org.dromara.common.core.domain.dto.StartProcessReturnDTO;
 import org.dromara.common.core.service.WorkflowService;
-import org.dromara.workflow.domain.ActHiProcinst;
-import org.dromara.workflow.service.IActHiProcinstService;
-import org.dromara.workflow.service.IActProcessInstanceService;
-import org.dromara.workflow.utils.WorkflowUtils;
-import org.flowable.engine.RuntimeService;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.warm.flow.orm.entity.FlowInstance;
+import org.dromara.workflow.common.ConditionalOnEnable;
+import org.dromara.workflow.domain.bo.CompleteTaskBo;
+import org.dromara.workflow.domain.bo.StartProcessBo;
+import org.dromara.workflow.service.IFlwDefinitionService;
+import org.dromara.workflow.service.IFlwInstanceService;
+import org.dromara.workflow.service.IFlwTaskService;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -19,23 +25,24 @@
  *
  * @author may
  */
+@ConditionalOnEnable
 @RequiredArgsConstructor
 @Service
 public class WorkflowServiceImpl implements WorkflowService {
 
-    @Autowired(required = false)
-    private RuntimeService runtimeService;
-    private final IActProcessInstanceService iActProcessInstanceService;
-    private final IActHiProcinstService iActHiProcinstService;
+    private final IFlwInstanceService flwInstanceService;
+    private final IFlwDefinitionService flwDefinitionService;
+    private final IFlwTaskService flwTaskService;
+
     /**
-     * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
+     * 鍒犻櫎娴佺▼瀹炰緥
      *
-     * @param businessKeys 涓氬姟id
+     * @param businessIds 涓氬姟id
      * @return 缁撴灉
      */
     @Override
-    public boolean deleteRunAndHisInstance(List<String> businessKeys) {
-        return iActProcessInstanceService.deleteRunAndHisInstance(businessKeys);
+    public boolean deleteInstance(List<Long> businessIds) {
+        return flwInstanceService.deleteByBusinessIds(businessIds);
     }
 
     /**
@@ -44,78 +51,82 @@
      * @param taskId 浠诲姟id
      */
     @Override
-    public String getBusinessStatusByTaskId(String taskId) {
-        return WorkflowUtils.getBusinessStatusByTaskId(taskId);
+    public String getBusinessStatusByTaskId(Long taskId) {
+        FlowInstance flowInstance = flwInstanceService.selectByTaskId(taskId);
+        return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY;
     }
 
     /**
      * 鑾峰彇褰撳墠娴佺▼鐘舵��
      *
-     * @param businessKey 涓氬姟id
+     * @param businessId 涓氬姟id
      */
     @Override
-    public String getBusinessStatus(String businessKey) {
-        return WorkflowUtils.getBusinessStatus(businessKey);
+    public String getBusinessStatus(String businessId) {
+        FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId);
+        return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY;
     }
 
     /**
-     * 璁剧疆娴佺▼鍙橀噺(鍏ㄥ眬鍙橀噺)
+     * 璁剧疆娴佺▼鍙橀噺
      *
-     * @param taskId       浠诲姟id
-     * @param variableName 鍙橀噺鍚嶇О
-     * @param value        鍙橀噺鍊�
+     * @param instanceId 娴佺▼瀹炰緥id
+     * @param variables  娴佺▼鍙橀噺
      */
     @Override
-    public void setVariable(String taskId, String variableName, Object value) {
-        runtimeService.setVariable(taskId, variableName, value);
+    public void setVariable(Long instanceId, Map<String, Object> variables) {
+        flwInstanceService.setVariable(instanceId, variables);
     }
 
     /**
-     * 璁剧疆娴佺▼鍙橀噺(鍏ㄥ眬鍙橀噺)
+     * 鑾峰彇娴佺▼鍙橀噺
      *
-     * @param taskId    浠诲姟id
-     * @param variables 娴佺▼鍙橀噺
+     * @param instanceId 娴佺▼瀹炰緥id
      */
     @Override
-    public void setVariables(String taskId, Map<String, Object> variables) {
-        runtimeService.setVariables(taskId, variables);
-    }
-
-    /**
-     * 璁剧疆娴佺▼鍙橀噺(鏈湴鍙橀噺,闈炲叏灞�鍙橀噺)
-     *
-     * @param taskId       浠诲姟id
-     * @param variableName 鍙橀噺鍚嶇О
-     * @param value        鍙橀噺鍊�
-     */
-    @Override
-    public void setVariableLocal(String taskId, String variableName, Object value) {
-        runtimeService.setVariableLocal(taskId, variableName, value);
-    }
-
-    /**
-     * 璁剧疆娴佺▼鍙橀噺(鏈湴鍙橀噺,闈炲叏灞�鍙橀噺)
-     *
-     * @param taskId    浠诲姟id
-     * @param variables 娴佺▼鍙橀噺
-     */
-    @Override
-    public void setVariablesLocal(String taskId, Map<String, Object> variables) {
-        runtimeService.setVariablesLocal(taskId, variables);
+    public Map<String, Object> instanceVariable(Long instanceId) {
+        return flwInstanceService.instanceVariable(instanceId);
     }
 
     /**
      * 鎸夌収涓氬姟id鏌ヨ娴佺▼瀹炰緥id
      *
-     * @param businessKey 涓氬姟id
+     * @param businessId 涓氬姟id
      * @return 缁撴灉
      */
     @Override
-    public String getInstanceIdByBusinessKey(String businessKey) {
-        ActHiProcinst actHiProcinst = iActHiProcinstService.selectByBusinessKey(businessKey);
-        if (actHiProcinst == null) {
-            return StrUtil.EMPTY;
-        }
-        return actHiProcinst.getId();
+    public Long getInstanceIdByBusinessId(String businessId) {
+        FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId);
+        return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getId() : null;
+    }
+
+    /**
+     * 鏂板绉熸埛娴佺▼瀹氫箟
+     *
+     * @param tenantId 绉熸埛id
+     */
+    @Override
+    public void syncDef(String tenantId) {
+        flwDefinitionService.syncDef(tenantId);
+    }
+
+    /**
+     * 鍚姩娴佺▼
+     *
+     * @param startProcess 鍙傛暟
+     */
+    @Override
+    public StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess) {
+        return flwTaskService.startWorkFlow(BeanUtil.toBean(startProcess, StartProcessBo.class));
+    }
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTask 鍙傛暟
+     */
+    @Override
+    public boolean completeTask(CompleteTaskDTO completeTask) {
+        return flwTaskService.completeTask(BeanUtil.toBean(completeTask, CompleteTaskBo.class));
     }
 }
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java
deleted file mode 100644
index 7c5377e..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java
+++ /dev/null
@@ -1,289 +0,0 @@
-package org.dromara.workflow.utils;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
-import org.dromara.common.core.utils.SpringUtils;
-import org.dromara.common.core.utils.StreamUtils;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.json.utils.JsonUtils;
-import org.dromara.workflow.domain.vo.MultiInstanceVo;
-import org.flowable.bpmn.converter.BpmnXMLConverter;
-import org.flowable.bpmn.model.*;
-import org.flowable.bpmn.model.Process;
-import org.flowable.editor.language.json.converter.BpmnJsonConverter;
-import org.flowable.engine.ProcessEngine;
-
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.rmi.ServerException;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * 妯″瀷宸ュ叿
- *
- * @author may
- */
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public class ModelUtils {
-
-    private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);
-
-    public static BpmnModel xmlToBpmnModel(String xml) throws IOException {
-        if (xml == null) {
-            throw new ServerException("xml涓嶈兘涓虹┖");
-        }
-        try {
-            InputStream inputStream = new ByteArrayInputStream(StrUtil.utf8Bytes(xml));
-            XMLInputFactory factory = XMLInputFactory.newInstance();
-            XMLStreamReader reader = factory.createXMLStreamReader(inputStream);
-            return new BpmnXMLConverter().convertToBpmnModel(reader);
-        } catch (XMLStreamException e) {
-            throw new ServerException(e.getMessage());
-        }
-    }
-
-    /**
-     * bpmnModel杞负xml
-     *
-     * @param jsonBytes json
-     */
-    public static byte[] bpmnJsonToXmlBytes(byte[] jsonBytes) throws IOException {
-        if (jsonBytes == null) {
-            return new byte[0];
-        }
-        // 1. json瀛楄妭鐮佽浆鎴� BpmnModel 瀵硅薄
-        ObjectMapper objectMapper = JsonUtils.getObjectMapper();
-        JsonNode jsonNode = objectMapper.readTree(jsonBytes);
-        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
-
-        if (bpmnModel.getProcesses().isEmpty()) {
-            return new byte[0];
-        }
-        // 2.灏哹pmnModel杞负xml
-        return new BpmnXMLConverter().convertToXML(bpmnModel);
-    }
-
-    /**
-     * xml杞负bpmnModel
-     *
-     * @param xmlBytes xml
-     */
-    public static BpmnModel xmlToBpmnModel(byte[] xmlBytes) throws XMLStreamException {
-        ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(xmlBytes);
-        XMLInputFactory xif = XMLInputFactory.newInstance();
-        XMLStreamReader xtr = xif.createXMLStreamReader(byteArrayInputStream);
-        return new BpmnXMLConverter().convertToBpmnModel(xtr);
-    }
-
-    /**
-     * 鏍¢獙妯″瀷
-     *
-     * @param bpmnModel bpmn妯″瀷
-     */
-    public static void checkBpmnModel(BpmnModel bpmnModel) throws ServerException {
-        Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
-
-        checkBpmnNode(flowElements, false);
-
-        List<SubProcess> subProcessList = flowElements.stream().filter(SubProcess.class::isInstance).map(SubProcess.class::cast).collect(Collectors.toList());
-        if (!CollUtil.isEmpty(subProcessList)) {
-            for (SubProcess subProcess : subProcessList) {
-                Collection<FlowElement> subProcessFlowElements = subProcess.getFlowElements();
-                checkBpmnNode(subProcessFlowElements, true);
-            }
-        }
-        List<MultiInstanceVo> multiInstanceVoList = new ArrayList<>();
-        for (FlowElement flowElement : flowElements) {
-            if (flowElement instanceof UserTask && ObjectUtil.isNotEmpty(((UserTask) flowElement).getLoopCharacteristics()) && StringUtils.isNotBlank(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem())) {
-                MultiInstanceVo multiInstanceVo = new MultiInstanceVo();
-                multiInstanceVo.setAssigneeList(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem());
-                multiInstanceVoList.add(multiInstanceVo);
-            }
-        }
-
-        if (CollectionUtil.isNotEmpty(multiInstanceVoList) && multiInstanceVoList.size() > 1) {
-            Map<String, List<MultiInstanceVo>> assigneeListGroup = StreamUtils.groupByKey(multiInstanceVoList, MultiInstanceVo::getAssigneeList);
-            for (Map.Entry<String, List<MultiInstanceVo>> entry : assigneeListGroup.entrySet()) {
-                List<MultiInstanceVo> value = entry.getValue();
-                if (CollectionUtil.isNotEmpty(value) && value.size() > 1) {
-                    String key = entry.getKey();
-                    throw new ServerException("浼氱浜哄憳闆嗗悎銆�" + key + "銆戦噸澶�,璇烽噸鏂拌缃泦鍚圞EY");
-                }
-            }
-        }
-    }
-
-    /**
-     * 鏍¢獙bpmn鑺傜偣鏄惁鍚堟硶
-     *
-     * @param flowElements 鑺傜偣闆嗗悎
-     * @param subtask      鏄惁瀛愭祦绋�
-     */
-    private static void checkBpmnNode(Collection<FlowElement> flowElements, boolean subtask) throws ServerException {
-
-        if (CollUtil.isEmpty(flowElements)) {
-            throw new ServerException(subtask ? "瀛愭祦绋嬪繀椤诲瓨鍦ㄨ妭鐐�" : "蹇呴』瀛樺湪鑺傜偣锛�");
-        }
-
-        List<StartEvent> startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList());
-        if (CollUtil.isEmpty(startEventList)) {
-            throw new ServerException(subtask ? "瀛愭祦绋嬪繀椤诲瓨鍦ㄥ紑濮嬭妭鐐�" : "蹇呴』瀛樺湪寮�濮嬭妭鐐癸紒");
-        }
-
-        if (startEventList.size() > 1) {
-            throw new ServerException(subtask ? "瀛愭祦绋嬪彧鑳藉瓨鍦ㄤ竴涓紑濮嬭妭鐐�" : "鍙兘瀛樺湪涓�涓紑濮嬭妭鐐癸紒");
-        }
-
-        StartEvent startEvent = startEventList.get(0);
-        List<SequenceFlow> outgoingFlows = startEvent.getOutgoingFlows();
-        if (CollUtil.isEmpty(outgoingFlows)) {
-            throw new ServerException(subtask ? "瀛愭祦绋嬫祦绋嬭妭鐐逛负绌猴紝璇疯嚦灏戣璁′竴鏉′富绾挎祦绋嬶紒" : "娴佺▼鑺傜偣涓虹┖锛岃鑷冲皯璁捐涓�鏉′富绾挎祦绋嬶紒");
-        }
-
-        FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement();
-        if (!(targetFlowElement instanceof UserTask) && !subtask) {
-            throw new ServerException("寮�濮嬭妭鐐瑰悗绗竴涓妭鐐瑰繀椤绘槸鐢ㄦ埛浠诲姟锛�");
-        }
-        //寮�濮嬭妭鐐瑰悗绗竴涓妭鐐圭敵璇蜂汉鑺傜偣
-        if ((targetFlowElement instanceof UserTask) && !subtask) {
-            UserTask userTask = (UserTask) targetFlowElement;
-            if (StringUtils.isBlank(userTask.getFormKey())) {
-                throw new ServerException("鐢宠浜鸿妭鐐瑰繀椤婚�夋嫨琛ㄥ崟锛�");
-            }
-        }
-        List<EndEvent> endEventList = flowElements.stream().filter(EndEvent.class::isInstance).map(EndEvent.class::cast).collect(Collectors.toList());
-        if (CollUtil.isEmpty(endEventList)) {
-            throw new ServerException(subtask ? "瀛愭祦绋嬪繀椤诲瓨鍦ㄧ粨鏉熻妭鐐癸紒" : "蹇呴』瀛樺湪缁撴潫鑺傜偣锛�");
-        }
-    }
-
-    /**
-     * 鑾峰彇娴佺▼鍏ㄩ儴鐢ㄦ埛鑺傜偣
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    public static List<UserTask> getUserTaskFlowElements(String processDefinitionId) {
-        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
-        List<UserTask> list = new ArrayList<>();
-        List<Process> processes = bpmnModel.getProcesses();
-        Collection<FlowElement> flowElements = processes.get(0).getFlowElements();
-        buildUserTaskFlowElements(flowElements, list);
-        return list;
-    }
-
-    /**
-     * 閫掑綊鑾峰彇鎵�鏈夎妭鐐�
-     *
-     * @param flowElements 鑺傜偣淇℃伅
-     * @param list         闆嗗悎
-     */
-    private static void buildUserTaskFlowElements(Collection<FlowElement> flowElements, List<UserTask> list) {
-        for (FlowElement flowElement : flowElements) {
-            if (flowElement instanceof SubProcess) {
-                Collection<FlowElement> subFlowElements = ((SubProcess) flowElement).getFlowElements();
-                buildUserTaskFlowElements(subFlowElements, list);
-            } else if (flowElement instanceof UserTask) {
-                list.add((UserTask) flowElement);
-            }
-        }
-    }
-
-    /**
-     * 鑾峰彇娴佺▼鍏ㄩ儴鑺傜偣
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    public static List<FlowElement> getFlowElements(String processDefinitionId) {
-        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
-        List<FlowElement> list = new ArrayList<>();
-        List<Process> processes = bpmnModel.getProcesses();
-        Collection<FlowElement> flowElements = processes.get(0).getFlowElements();
-        buildFlowElements(flowElements, list);
-        return list;
-    }
-
-    /**
-     * 閫掑綊鑾峰彇鎵�鏈夎妭鐐�
-     *
-     * @param flowElements 鑺傜偣淇℃伅
-     * @param list         闆嗗悎
-     */
-    private static void buildFlowElements(Collection<FlowElement> flowElements, List<FlowElement> list) {
-        for (FlowElement flowElement : flowElements) {
-            list.add(flowElement);
-            if (flowElement instanceof SubProcess) {
-                Collection<FlowElement> subFlowElements = ((SubProcess) flowElement).getFlowElements();
-                buildFlowElements(subFlowElements, list);
-            }
-        }
-    }
-
-    /**
-     * 鑾峰彇鍏ㄩ儴鎵╁睍淇℃伅
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     */
-    public static Map<String, List<ExtensionElement>> getExtensionElements(String processDefinitionId) {
-        Map<String, List<ExtensionElement>> map = new HashMap<>();
-        List<FlowElement> flowElements = getFlowElements(processDefinitionId);
-        for (FlowElement flowElement : flowElements) {
-            if (flowElement instanceof UserTask && CollUtil.isNotEmpty(flowElement.getExtensionElements())) {
-                map.putAll(flowElement.getExtensionElements());
-            }
-        }
-        return map;
-    }
-
-    /**
-     * 鑾峰彇鏌愪釜鑺傜偣鐨勬墿灞曚俊鎭�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     * @param flowElementId       鑺傜偣id
-     */
-    public static Map<String, List<ExtensionElement>> getExtensionElement(String processDefinitionId, String flowElementId) {
-        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
-        Process process = bpmnModel.getMainProcess();
-        FlowElement flowElement = process.getFlowElement(flowElementId);
-        return flowElement.getExtensionElements();
-    }
-
-    /**
-     * 鍒ゆ柇褰撳墠鑺傜偣鏄惁涓虹敤鎴蜂换鍔�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     * @param taskDefinitionKey   娴佺▼瀹氫箟id
-     */
-    public static boolean isUserTask(String processDefinitionId, String taskDefinitionKey) {
-        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
-        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey);
-        return flowNode instanceof UserTask;
-    }
-
-    /**
-     * 鑾峰彇鐢宠浜鸿妭鐐�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     * @return 缁撴灉
-     */
-    public static UserTask getApplyUserTask(String processDefinitionId) {
-        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
-        Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
-        List<StartEvent> startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList());
-        StartEvent startEvent = startEventList.get(0);
-        List<SequenceFlow> outgoingFlows = startEvent.getOutgoingFlows();
-        FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement();
-        return (UserTask) targetFlowElement;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java
deleted file mode 100644
index df928dc..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package org.dromara.workflow.utils;
-
-import cn.hutool.core.bean.BeanUtil;
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
-import org.dromara.common.core.utils.SpringUtils;
-import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.workflow.domain.vo.TaskVo;
-import org.flowable.engine.ProcessEngine;
-import org.flowable.engine.history.HistoricActivityInstanceQuery;
-import org.flowable.engine.history.HistoricProcessInstanceQuery;
-import org.flowable.engine.repository.DeploymentQuery;
-import org.flowable.engine.repository.ModelQuery;
-import org.flowable.engine.repository.ProcessDefinitionQuery;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.engine.runtime.ProcessInstanceQuery;
-import org.flowable.task.api.Task;
-import org.flowable.task.api.TaskQuery;
-import org.flowable.task.api.history.HistoricTaskInstanceQuery;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-/**
- * 鏌ヨ宸ュ叿
- *
- * @author Lion Li
- */
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public class QueryUtils {
-
-    private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);
-
-    public static ModelQuery modelQuery() {
-        ModelQuery query = PROCESS_ENGINE.getRepositoryService().createModelQuery();
-        if (TenantHelper.isEnable()) {
-            query.modelTenantId(TenantHelper.getTenantId());
-        }
-        return query;
-    }
-
-    public static ProcessDefinitionQuery definitionQuery() {
-        ProcessDefinitionQuery query = PROCESS_ENGINE.getRepositoryService().createProcessDefinitionQuery();
-        if (TenantHelper.isEnable()) {
-            query.processDefinitionTenantId(TenantHelper.getTenantId());
-        }
-        return query;
-    }
-
-    public static DeploymentQuery deploymentQuery() {
-        DeploymentQuery query = PROCESS_ENGINE.getRepositoryService().createDeploymentQuery();
-        if (TenantHelper.isEnable()) {
-            query.deploymentTenantId(TenantHelper.getTenantId());
-        }
-        return query;
-    }
-
-    public static DeploymentQuery deploymentQuery(String deploymentId) {
-        return deploymentQuery().deploymentId(deploymentId);
-    }
-
-    public static DeploymentQuery deploymentQuery(List<String> deploymentIds) {
-        return deploymentQuery().deploymentIds(deploymentIds);
-    }
-
-    public static HistoricTaskInstanceQuery hisTaskInstanceQuery() {
-        HistoricTaskInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricTaskInstanceQuery();
-        if (TenantHelper.isEnable()) {
-            query.taskTenantId(TenantHelper.getTenantId());
-        }
-        return query;
-    }
-
-    public static HistoricTaskInstanceQuery hisTaskInstanceQuery(String processInstanceId) {
-        return hisTaskInstanceQuery().processInstanceId(processInstanceId);
-    }
-
-    public static HistoricTaskInstanceQuery hisTaskBusinessKeyQuery(String businessKey) {
-        return hisTaskInstanceQuery().processInstanceBusinessKey(businessKey);
-    }
-
-    public static ProcessInstanceQuery instanceQuery() {
-        ProcessInstanceQuery query = PROCESS_ENGINE.getRuntimeService().createProcessInstanceQuery();
-        if (TenantHelper.isEnable()) {
-            query.processInstanceTenantId(TenantHelper.getTenantId());
-        }
-        return query;
-    }
-
-    public static ProcessInstanceQuery instanceQuery(String processInstanceId) {
-        return instanceQuery().processInstanceId(processInstanceId);
-    }
-
-    public static ProcessInstanceQuery businessKeyQuery(String businessKey) {
-        return instanceQuery().processInstanceBusinessKey(businessKey);
-    }
-
-    public static ProcessInstanceQuery instanceQuery(Set<String> processInstanceIds) {
-        return instanceQuery().processInstanceIds(processInstanceIds);
-    }
-
-    public static HistoricProcessInstanceQuery hisInstanceQuery() {
-        HistoricProcessInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricProcessInstanceQuery();
-        if (TenantHelper.isEnable()) {
-            query.processInstanceTenantId(TenantHelper.getTenantId());
-        }
-        return query;
-    }
-
-    public static HistoricProcessInstanceQuery hisInstanceQuery(String processInstanceId) {
-        return hisInstanceQuery().processInstanceId(processInstanceId);
-    }
-
-    public static HistoricProcessInstanceQuery hisBusinessKeyQuery(String businessKey) {
-        return hisInstanceQuery().processInstanceBusinessKey(businessKey);
-    }
-
-    public static HistoricProcessInstanceQuery hisInstanceQuery(Set<String> processInstanceIds) {
-        return hisInstanceQuery().processInstanceIds(processInstanceIds);
-    }
-
-    public static HistoricActivityInstanceQuery hisActivityInstanceQuery() {
-        HistoricActivityInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricActivityInstanceQuery();
-        if (TenantHelper.isEnable()) {
-            query.activityTenantId(TenantHelper.getTenantId());
-        }
-        return query;
-    }
-
-    public static HistoricActivityInstanceQuery hisActivityInstanceQuery(String processInstanceId) {
-        return hisActivityInstanceQuery().processInstanceId(processInstanceId);
-    }
-
-    public static TaskQuery taskQuery() {
-        TaskQuery query = PROCESS_ENGINE.getTaskService().createTaskQuery();
-        if (TenantHelper.isEnable()) {
-            query.taskTenantId(TenantHelper.getTenantId());
-        }
-        return query;
-    }
-
-    public static TaskQuery taskQuery(String processInstanceId) {
-        return taskQuery().processInstanceId(processInstanceId);
-    }
-
-    public static TaskQuery taskQuery(Collection<String> processInstanceIds) {
-        return taskQuery().processInstanceIdIn(processInstanceIds);
-    }
-
-    /**
-     * 鎸夌収浠诲姟id鏌ヨ褰撳墠浠诲姟
-     *
-     * @param taskId 浠诲姟id
-     */
-    public static TaskVo getTask(String taskId) {
-        Task task = PROCESS_ENGINE.getTaskService().createTaskQuery().taskId(taskId).singleResult();
-        if (task == null) {
-            return null;
-        }
-        ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
-        TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class);
-        taskVo.setBusinessKey(processInstance.getBusinessKey());
-        taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
-        String businessStatus = WorkflowUtils.getBusinessStatus(taskVo.getBusinessKey());
-        taskVo.setBusinessStatus(businessStatus);
-        return taskVo;
-    }
-}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java
index d7c4472..e48ffc8 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java
@@ -2,43 +2,42 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.dromara.common.core.domain.dto.RoleDTO;
 import org.dromara.common.core.domain.dto.UserDTO;
-import org.dromara.common.core.service.UserService;
 import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mail.utils.MailUtils;
-import org.dromara.common.satoken.utils.LoginHelper;
-import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.common.websocket.dto.WebSocketMessageDto;
-import org.dromara.common.websocket.utils.WebSocketUtils;
-import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.common.sse.dto.SseMessageDto;
+import org.dromara.common.sse.utils.SseMessageUtils;
+import org.dromara.warm.flow.core.constant.ExceptionCons;
+import org.dromara.warm.flow.core.dto.FlowParams;
+import org.dromara.warm.flow.core.entity.Node;
+import org.dromara.warm.flow.core.entity.Task;
+import org.dromara.warm.flow.core.entity.User;
+import org.dromara.warm.flow.core.enums.NodeType;
+import org.dromara.warm.flow.core.enums.SkipType;
+import org.dromara.warm.flow.core.service.NodeService;
+import org.dromara.warm.flow.core.service.TaskService;
+import org.dromara.warm.flow.core.service.UserService;
+import org.dromara.warm.flow.core.utils.AssertUtil;
+import org.dromara.warm.flow.orm.entity.FlowNode;
+import org.dromara.warm.flow.orm.entity.FlowTask;
+import org.dromara.warm.flow.orm.entity.FlowUser;
+import org.dromara.warm.flow.orm.mapper.FlowNodeMapper;
+import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
 import org.dromara.workflow.common.enums.MessageTypeEnum;
-import org.dromara.workflow.common.enums.TaskStatusEnum;
-import org.dromara.workflow.domain.ActHiTaskinst;
-import org.dromara.workflow.domain.vo.MultiInstanceVo;
-import org.dromara.workflow.domain.vo.ParticipantVo;
-import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd;
-import org.dromara.workflow.mapper.ActHiTaskinstMapper;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.bpmn.model.FlowNode;
-import org.flowable.common.engine.api.delegate.Expression;
-import org.flowable.engine.ProcessEngine;
-import org.flowable.engine.history.HistoricProcessInstance;
-import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
-import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
-import org.flowable.identitylink.api.history.HistoricIdentityLink;
-import org.flowable.task.api.Task;
-import org.flowable.task.api.TaskQuery;
-import org.flowable.task.api.history.HistoricTaskInstance;
-import org.flowable.task.service.impl.persistence.entity.TaskEntity;
+import org.dromara.workflow.service.IFlwTaskAssigneeService;
+import org.dromara.workflow.service.IFlwTaskService;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 
 /**
  * 宸ヤ綔娴佸伐鍏�
@@ -48,220 +47,84 @@
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class WorkflowUtils {
 
-    private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);
-    private static final ActHiTaskinstMapper ACT_HI_TASKINST_MAPPER = SpringUtils.getBean(ActHiTaskinstMapper.class);
+    private static final IFlwTaskAssigneeService TASK_ASSIGNEE_SERVICE = SpringUtils.getBean(IFlwTaskAssigneeService.class);
+    private static final IFlwTaskService FLW_TASK_SERVICE = SpringUtils.getBean(IFlwTaskService.class);
+    private static final FlowNodeMapper FLOW_NODE_MAPPER = SpringUtils.getBean(FlowNodeMapper.class);
+    private static final FlowTaskMapper FLOW_TASK_MAPPER = SpringUtils.getBean(FlowTaskMapper.class);
+    private static final UserService USER_SERVICE = SpringUtils.getBean(UserService.class);
+    private static final TaskService TASK_SERVICE = SpringUtils.getBean(TaskService.class);
+    private static final NodeService NODE_SERVICE = SpringUtils.getBean(NodeService.class);
 
     /**
-     * 鍒涘缓涓�涓柊浠诲姟
-     *
-     * @param currentTask 鍙傛暟
+     * 鑾峰彇宸ヤ綔娴佺敤鎴穝ervice
      */
-    public static TaskEntity createNewTask(Task currentTask) {
-        TaskEntity task = null;
-        if (ObjectUtil.isNotEmpty(currentTask)) {
-            task = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask();
-            task.setCategory(currentTask.getCategory());
-            task.setDescription(currentTask.getDescription());
-            task.setAssignee(currentTask.getAssignee());
-            task.setName(currentTask.getName());
-            task.setProcessDefinitionId(currentTask.getProcessDefinitionId());
-            task.setProcessInstanceId(currentTask.getProcessInstanceId());
-            task.setTaskDefinitionKey(currentTask.getTaskDefinitionKey());
-            task.setPriority(currentTask.getPriority());
-            task.setCreateTime(new Date());
-            task.setTenantId(TenantHelper.getTenantId());
-            PROCESS_ENGINE.getTaskService().saveTask(task);
-        }
-        if (ObjectUtil.isNotNull(task)) {
-            UpdateHiTaskInstCmd updateHiTaskInstCmd = new UpdateHiTaskInstCmd(Collections.singletonList(task.getId()), task.getProcessDefinitionId(), task.getProcessInstanceId());
-            PROCESS_ENGINE.getManagementService().executeCommand(updateHiTaskInstCmd);
-        }
-        return task;
+    public static UserService getFlowUserService() {
+        return USER_SERVICE;
     }
 
     /**
-     * 鎶勯�佷换鍔�
+     * 鏋勫缓宸ヤ綔娴佺敤鎴�
      *
-     * @param parentTaskList 鐖剁骇浠诲姟
-     * @param userIds        浜哄憳id
+     * @param userList 鍔炵悊鐢ㄦ埛
+     * @param taskId   浠诲姟ID
+     * @return 鐢ㄦ埛
      */
-    public static void createCopyTask(List<Task> parentTaskList, List<Long> userIds) {
-        List<Task> list = new ArrayList<>();
-        String tenantId = TenantHelper.getTenantId();
-        for (Task parentTask : parentTaskList) {
-            for (Long userId : userIds) {
-                TaskEntity newTask = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask();
-                newTask.setParentTaskId(parentTask.getId());
-                newTask.setAssignee(userId.toString());
-                newTask.setName("銆愭妱閫併��-" + parentTask.getName());
-                newTask.setProcessDefinitionId(parentTask.getProcessDefinitionId());
-                newTask.setProcessInstanceId(parentTask.getProcessInstanceId());
-                newTask.setTaskDefinitionKey(parentTask.getTaskDefinitionKey());
-                newTask.setTenantId(tenantId);
-                list.add(newTask);
+    public static Set<User> buildUser(List<User> userList, Long taskId) {
+        if (CollUtil.isEmpty(userList)) {
+            return Set.of();
+        }
+        Set<User> list = new HashSet<>();
+        Set<String> processedBySet = new HashSet<>();
+        for (User user : userList) {
+            // 鏍规嵁 processedBy 鍓嶇紑鍒ゆ柇澶勭悊浜虹被鍨嬶紝鍒嗗埆鑾峰彇鐢ㄦ埛鍒楄〃
+            List<UserDTO> users = TASK_ASSIGNEE_SERVICE.fetchUsersByStorageId(user.getProcessedBy());
+            // 杞崲涓� FlowUser 骞舵坊鍔犲埌缁撴灉闆嗗悎
+            if (CollUtil.isNotEmpty(users)) {
+                users.forEach(dto -> {
+                    String processedBy = String.valueOf(dto.getUserId());
+                    if (!processedBySet.contains(processedBy)) {
+                        FlowUser flowUser = new FlowUser();
+                        flowUser.setType(user.getType());
+                        flowUser.setProcessedBy(processedBy);
+                        flowUser.setAssociated(taskId);
+                        list.add(flowUser);
+                        processedBySet.add(processedBy);
+                    }
+                });
             }
         }
-        PROCESS_ENGINE.getTaskService().bulkSaveTasks(list);
-        if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(parentTaskList)) {
-            String processInstanceId = parentTaskList.get(0).getProcessInstanceId();
-            String processDefinitionId = parentTaskList.get(0).getProcessDefinitionId();
-            List<String> taskIds = StreamUtils.toList(list, Task::getId);
-            ActHiTaskinst actHiTaskinst = new ActHiTaskinst();
-            actHiTaskinst.setProcDefId(processDefinitionId);
-            actHiTaskinst.setProcInstId(processInstanceId);
-            actHiTaskinst.setScopeType(TaskStatusEnum.COPY.getStatus());
-            actHiTaskinst.setTenantId(tenantId);
-            LambdaUpdateWrapper<ActHiTaskinst> updateWrapper = new LambdaUpdateWrapper<>();
-            updateWrapper.in(ActHiTaskinst::getId, taskIds);
-            ACT_HI_TASKINST_MAPPER.update(actHiTaskinst, updateWrapper);
-            for (Task task : list) {
-                PROCESS_ENGINE.getTaskService().addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), StrUtil.EMPTY);
-            }
-        }
-    }
-
-    /**
-     * 鑾峰彇褰撳墠浠诲姟鍙備笌鑰�
-     *
-     * @param taskId 浠诲姟id
-     */
-    public static ParticipantVo getCurrentTaskParticipant(String taskId, UserService userService) {
-        ParticipantVo participantVo = new ParticipantVo();
-        List<HistoricIdentityLink> linksForTask = PROCESS_ENGINE.getHistoryService().getHistoricIdentityLinksForTask(taskId);
-        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
-        if (task != null && CollUtil.isNotEmpty(linksForTask)) {
-            List<HistoricIdentityLink> groupList = StreamUtils.filter(linksForTask, e -> StringUtils.isNotBlank(e.getGroupId()));
-            if (CollUtil.isNotEmpty(groupList)) {
-                List<Long> groupIds = StreamUtils.toList(groupList, e -> Long.valueOf(e.getGroupId()));
-                List<Long> userIds = userService.selectUserIdsByRoleIds(groupIds);
-                if (CollUtil.isNotEmpty(userIds)) {
-                    participantVo.setGroupIds(groupIds);
-                    List<UserDTO> userList = userService.selectListByIds(userIds);
-                    if (CollUtil.isNotEmpty(userList)) {
-                        List<Long> userIdList = StreamUtils.toList(userList, UserDTO::getUserId);
-                        List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName);
-                        participantVo.setCandidate(userIdList);
-                        participantVo.setCandidateName(nickNames);
-                        participantVo.setClaim(!StringUtils.isBlank(task.getAssignee()));
-                    }
-                }
-            } else {
-                List<HistoricIdentityLink> candidateList = StreamUtils.filter(linksForTask, e -> FlowConstant.CANDIDATE.equals(e.getType()));
-                List<Long> userIdList = new ArrayList<>();
-                for (HistoricIdentityLink historicIdentityLink : linksForTask) {
-                    try {
-                        userIdList.add(Long.valueOf(historicIdentityLink.getUserId()));
-                    } catch (NumberFormatException ignored) {
-
-                    }
-                }
-                List<UserDTO> userList = userService.selectListByIds(userIdList);
-                if (CollUtil.isNotEmpty(userList)) {
-                    List<Long> userIds = StreamUtils.toList(userList, UserDTO::getUserId);
-                    List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName);
-                    participantVo.setCandidate(userIds);
-                    participantVo.setCandidateName(nickNames);
-                    // 鍒ゆ柇褰撳墠浠诲姟鏄惁鍏锋湁澶氫釜鍔炵悊浜�
-                    if (CollUtil.isNotEmpty(candidateList) && candidateList.size() > 1) {
-                        // 濡傛灉 assignee 瀛樺湪锛屽垯璁剧疆褰撳墠浠诲姟宸茬粡琚棰�
-                        participantVo.setClaim(StringUtils.isNotBlank(task.getAssignee()));
-                    }
-                }
-            }
-        }
-        return participantVo;
-    }
-
-    /**
-     * 鍒ゆ柇褰撳墠鑺傜偣鏄惁涓轰細绛捐妭鐐�
-     *
-     * @param processDefinitionId 娴佺▼瀹氫箟id
-     * @param taskDefinitionKey   娴佺▼瀹氫箟id
-     */
-    public static MultiInstanceVo isMultiInstance(String processDefinitionId, String taskDefinitionKey) {
-        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
-        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey);
-        MultiInstanceVo multiInstanceVo = new MultiInstanceVo();
-        //鍒ゆ柇鏄惁涓哄苟琛屼細绛捐妭鐐�
-        if (flowNode.getBehavior() instanceof ParallelMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) {
-            Expression collectionExpression = behavior.getCollectionExpression();
-            String assigneeList = collectionExpression.getExpressionText();
-            String assignee = behavior.getCollectionElementVariable();
-            multiInstanceVo.setType(behavior);
-            multiInstanceVo.setAssignee(assignee);
-            multiInstanceVo.setAssigneeList(assigneeList);
-            return multiInstanceVo;
-            //鍒ゆ柇鏄惁涓轰覆琛屼細绛捐妭鐐�
-        } else if (flowNode.getBehavior() instanceof SequentialMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) {
-            Expression collectionExpression = behavior.getCollectionExpression();
-            String assigneeList = collectionExpression.getExpressionText();
-            String assignee = behavior.getCollectionElementVariable();
-            multiInstanceVo.setType(behavior);
-            multiInstanceVo.setAssignee(assignee);
-            multiInstanceVo.setAssigneeList(assigneeList);
-            return multiInstanceVo;
-        }
-        return null;
-    }
-
-    /**
-     * 鑾峰彇褰撳墠娴佺▼鐘舵��
-     *
-     * @param taskId 浠诲姟id
-     */
-    public static String getBusinessStatusByTaskId(String taskId) {
-        HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery().taskId(taskId).singleResult();
-        HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(historicTaskInstance.getProcessInstanceId()).singleResult();
-        return historicProcessInstance.getBusinessStatus();
-    }
-
-    /**
-     * 鑾峰彇褰撳墠娴佺▼鐘舵��
-     *
-     * @param businessKey 涓氬姟id
-     */
-    public static String getBusinessStatus(String businessKey) {
-        HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
-        return historicProcessInstance.getBusinessStatus();
+        return list;
     }
 
     /**
      * 鍙戦�佹秷鎭�
      *
-     * @param list        浠诲姟
-     * @param name        娴佺▼鍚嶇О
+     * @param flowName    娴佺▼瀹氫箟鍚嶇О
      * @param messageType 娑堟伅绫诲瀷
      * @param message     娑堟伅鍐呭锛屼负绌哄垯鍙戦�侀粯璁ら厤缃殑娑堟伅鍐呭
      */
-    public static void sendMessage(List<Task> list, String name, List<String> messageType, String message, UserService userService) {
-        Set<Long> userIds = new HashSet<>();
+    public static void sendMessage(String flowName, Long instId, List<String> messageType, String message) {
+        List<UserDTO> userList = new ArrayList<>();
+        List<FlowTask> list = FLW_TASK_SERVICE.selectByInstId(instId);
         if (StringUtils.isBlank(message)) {
-            message = "鏈夋柊鐨勩��" + name + "銆戝崟鎹凡缁忔彁浜よ嚦鎮ㄧ殑寰呭姙锛岃鎮ㄥ強鏃跺鐞嗐��";
+            message = "鏈夋柊鐨勩��" + flowName + "銆戝崟鎹凡缁忔彁浜よ嚦鎮紝璇锋偍鍙婃椂澶勭悊銆�";
         }
-        for (Task t : list) {
-            ParticipantVo taskParticipant = WorkflowUtils.getCurrentTaskParticipant(t.getId(), userService);
-            if (CollUtil.isNotEmpty(taskParticipant.getGroupIds())) {
-                List<Long> userIdList = userService.selectUserIdsByRoleIds(taskParticipant.getGroupIds());
-                if (CollUtil.isNotEmpty(userIdList)) {
-                    userIds.addAll(userIdList);
-                }
-            }
-            List<Long> candidate = taskParticipant.getCandidate();
-            if (CollUtil.isNotEmpty(candidate)) {
-                userIds.addAll(candidate);
+        for (Task task : list) {
+            List<UserDTO> users = FLW_TASK_SERVICE.currentTaskAllUser(task.getId());
+            if (CollUtil.isNotEmpty(users)) {
+                userList.addAll(users);
             }
         }
-        if (CollUtil.isNotEmpty(userIds)) {
-            List<UserDTO> userList = userService.selectListByIds(new ArrayList<>(userIds));
+        if (CollUtil.isNotEmpty(userList)) {
             for (String code : messageType) {
                 MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code);
                 if (ObjectUtil.isNotEmpty(messageTypeEnum)) {
                     switch (messageTypeEnum) {
                         case SYSTEM_MESSAGE:
-                            WebSocketMessageDto dto = new WebSocketMessageDto();
-                            dto.setSessionKeys(new ArrayList<>(userIds));
+                            SseMessageDto dto = new SseMessageDto();
+                            dto.setUserIds(StreamUtils.toList(userList, UserDTO::getUserId).stream().distinct().collect(Collectors.toList()));
                             dto.setMessage(message);
-                            WebSocketUtils.publishMessage(dto);
+                            SseMessageUtils.publishMessage(dto);
                             break;
                         case EMAIL_MESSAGE:
                             MailUtils.sendText(StreamUtils.join(userList, UserDTO::getEmail), "鍗曟嵁瀹℃壒鎻愰啋", message);
@@ -269,6 +132,8 @@
                         case SMS_MESSAGE:
                             //todo 鐭俊鍙戦��
                             break;
+                        default:
+                            throw new IllegalStateException("Unexpected value: " + messageTypeEnum);
                     }
                 }
             }
@@ -276,20 +141,66 @@
     }
 
     /**
-     * 鏍规嵁浠诲姟id鏌ヨ 褰撳墠鐢ㄦ埛鐨勪换鍔★紝妫�鏌� 褰撳墠浜哄憳 鏄惁鏄 taskId 鐨勫姙鐞嗕汉
+     * 椹冲洖
      *
-     * @param taskId 浠诲姟id
-     * @return 缁撴灉
+     * @param message        瀹℃壒鎰忚
+     * @param instanceId     娴佺▼瀹炰緥id
+     * @param targetNodeCode 鐩爣鑺傜偣
+     * @param flowStatus     娴佺▼鐘舵��
+     * @param flowHisStatus  鑺傜偣鎿嶄綔鐘舵��
      */
-    public static Task getTaskByCurrentUser(String taskId) {
-        TaskQuery taskQuery = QueryUtils.taskQuery();
-        taskQuery.taskId(taskId).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
-
-        List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
-        if (CollUtil.isNotEmpty(roles)) {
-            List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
-            taskQuery.taskCandidateGroupIn(groupIds);
+    public static void backTask(String message, Long instanceId, String targetNodeCode, String flowStatus, String flowHisStatus) {
+        List<FlowTask> list = FLW_TASK_SERVICE.selectByInstId(instanceId);
+        if (CollUtil.isNotEmpty(list)) {
+            List<FlowTask> tasks = StreamUtils.filter(list, e -> e.getNodeCode().equals(targetNodeCode));
+            if (list.size() == tasks.size()) {
+                return;
+            }
         }
-        return taskQuery.singleResult();
+        for (FlowTask task : list) {
+            List<UserDTO> userList = FLW_TASK_SERVICE.currentTaskAllUser(task.getId());
+            FlowParams flowParams = FlowParams.build();
+            flowParams.nodeCode(targetNodeCode);
+            flowParams.message(message);
+            flowParams.skipType(SkipType.PASS.getKey());
+            flowParams.flowStatus(flowStatus).hisStatus(flowHisStatus);
+            flowParams.ignore(true);
+            //瑙e喅浼氱娌℃潈闄愰棶棰�
+            if (CollUtil.isNotEmpty(userList)) {
+                flowParams.handler(userList.get(0).getUserId().toString());
+            }
+            TASK_SERVICE.skip(task.getId(), flowParams);
+        }
+        //瑙e喅浼氱澶氫汉瀹℃壒闂
+        backTask(message, instanceId, targetNodeCode, flowStatus, flowHisStatus);
+    }
+
+    /**
+     * 鐢宠浜鸿妭鐐圭紪鐮�
+     *
+     * @param definitionId 娴佺▼瀹氫箟id
+     * @return 鐢宠浜鸿妭鐐圭紪鐮�
+     */
+    public static String applyNodeCode(Long definitionId) {
+        //鑾峰彇宸插彂甯冪殑娴佺▼鑺傜偣
+        List<FlowNode> flowNodes = FLOW_NODE_MAPPER.selectList(new LambdaQueryWrapper<FlowNode>().eq(FlowNode::getDefinitionId, definitionId));
+        AssertUtil.isTrue(CollUtil.isEmpty(flowNodes), ExceptionCons.NOT_PUBLISH_NODE);
+        Node startNode = flowNodes.stream().filter(t -> NodeType.isStart(t.getNodeType())).findFirst().orElse(null);
+        AssertUtil.isNull(startNode, ExceptionCons.LOST_START_NODE);
+        Node nextNode = NODE_SERVICE.getNextNode(definitionId, startNode.getNodeCode(), null, SkipType.PASS.getKey());
+        return nextNode.getNodeCode();
+    }
+
+    /**
+     * 鍒犻櫎杩愯涓殑浠诲姟
+     *
+     * @param taskIds 浠诲姟id
+     */
+    public static void deleteRunTask(List<Long> taskIds) {
+        if (CollUtil.isEmpty(taskIds)) {
+            return;
+        }
+        USER_SERVICE.deleteByTaskIds(taskIds);
+        FLOW_TASK_MAPPER.deleteByIds(taskIds);
     }
 }
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml
deleted file mode 100644
index dd05785..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.workflow.mapper.ActHiProcinstMapper">
-
-</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml
deleted file mode 100644
index 7e73b60..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.workflow.mapper.ActHiTaskinstMapper">
-
-</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml
deleted file mode 100644
index d1508ab..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.workflow.mapper.ActTaskMapper">
-    <resultMap type="org.dromara.workflow.domain.vo.TaskVo" id="TaskVoResult">
-        <result property="id" column="ID_"/>
-        <result property="name" column="NAME_"/>
-        <result property="description" column="DESCRIPTION_"/>
-        <result property="priority" column="PRIORITY_"/>
-        <result property="owner" column="OWNER_"/>
-        <result property="assignee" column="ASSIGNEE_"/>
-        <result property="processInstanceId" column="PROC_INST_ID_"/>
-        <result property="executionId" column="EXECUTION_ID_"/>
-        <result property="taskDefinitionId" column="TASK_DEF_ID_"/>
-        <result property="processDefinitionId" column="PROC_DEF_ID_"/>
-        <result property="createTime" column="CREATE_TIME_"/>
-        <result property="startTime" column="START_TIME_"/>
-        <result property="endTime" column="END_TIME_"/>
-        <result property="taskDefinitionKey" column="TASK_DEF_KEY_"/>
-        <result property="dueDate" column="DUE_DATE_"/>
-        <result property="category" column="CATEGORY_"/>
-        <result property="parentTaskId" column="PARENT_TASK_ID_"/>
-        <result property="tenantId" column="TENANT_ID_"/>
-        <result property="claimTime" column="CLAIM_TIME"/>
-        <result property="businessStatus" column="BUSINESS_STATUS_"/>
-        <result property="processDefinitionName" column="processDefinitionName"/>
-        <result property="processDefinitionKey" column="processDefinitionKey"/>
-        <result property="processDefinitionVersion" column="processDefinitionVersion"/>
-        <result property="businessKey" column="BUSINESS_KEY_"/>
-
-    </resultMap>
-    <select id="getTaskWaitByPage" resultMap="TaskVoResult">
-        select *
-        from (SELECT RES.*,
-                     AHP.BUSINESS_STATUS_,
-                     AHP.BUSINESS_KEY_,
-                     ARP.NAME_ AS processDefinitionName,
-                     ARP.KEY_  AS processDefinitionKey,
-                     ARP.VERSION_  AS processDefinitionVersion
-              FROM ACT_RU_TASK RES
-                       INNER JOIN ACT_HI_PROCINST AHP ON RES.PROC_INST_ID_ = AHP.PROC_INST_ID_
-                       INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = RES.PROC_DEF_ID_
-              WHERE RES.PARENT_TASK_ID_ IS NULL
-              ORDER BY RES.CREATE_TIME_ DESC) t ${ew.getCustomSqlSegment}
-    </select>
-
-    <select id="getTaskFinishByPage" resultMap="TaskVoResult">
-        select *
-        from (SELECT HTI.*,
-                     AHP.BUSINESS_STATUS_,
-                     AHP.BUSINESS_KEY_,
-                     ARP.NAME_ AS processDefinitionName,
-                     ARP.KEY_  AS processDefinitionKey,
-                     ARP.VERSION_  AS processDefinitionVersion
-              FROM ACT_HI_TASKINST HTI
-                       INNER JOIN ACT_HI_PROCINST AHP ON HTI.PROC_INST_ID_ = AHP.PROC_INST_ID_
-                       INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = HTI.PROC_DEF_ID_
-              WHERE HTI.PARENT_TASK_ID_ IS NULL AND HTI.END_TIME_ IS NOT NULL
-              ORDER BY HTI.START_TIME_ DESC) t ${ew.getCustomSqlSegment}
-    </select>
-
-    <select id="getTaskCopyByPage" resultMap="TaskVoResult">
-        select *
-        from (SELECT AHT.*,
-                     AHP.BUSINESS_STATUS_,
-                     AHP.BUSINESS_KEY_,
-                     ARP.NAME_ as processDefinitionName,
-                     ARP.KEY_  as processDefinitionKey,
-                     ARP.VERSION_  AS processDefinitionVersion
-              FROM ACT_HI_TASKINST AHT
-                       INNER JOIN ACT_HI_PROCINST AHP ON AHT.PROC_INST_ID_ = AHP.PROC_INST_ID_
-                       INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = AHT.PROC_DEF_ID_
-              WHERE AHT.PARENT_TASK_ID_ IS NOT NULL
-                and AHT.scope_type_ = 'copy'
-              ORDER BY AHT.START_TIME_ DESC) t ${ew.getCustomSqlSegment}
-    </select>
-</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml
new file mode 100644
index 0000000..e9918f1
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.FlwCategoryMapper">
+
+    <select id="countCategoryById" resultType="Long">
+        select count(*) from flow_category where del_flag = '0' and category_id = #{categoryId}
+    </select>
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml
new file mode 100644
index 0000000..30e2267
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.FlwInstanceMapper">
+    <resultMap type="org.dromara.workflow.domain.vo.FlowInstanceVo" id="FlowInstanceResult">
+    </resultMap>
+
+    <select id="selectInstanceList" resultMap="FlowInstanceResult">
+        select fi.id,
+               fi.create_time,
+               fi.update_time,
+               fi.tenant_id,
+               fi.del_flag,
+               fi.definition_id,
+               fi.business_id,
+               fi.node_type,
+               fi.node_code,
+               fi.node_name,
+               fi.variable,
+               fi.flow_status,
+               fi.activity_status,
+               fi.create_by,
+               fi.ext,
+               fd.flow_name,
+               fd.flow_code,
+               fd.version,
+               fd.form_custom,
+               fd.form_path,
+               fd.category
+        from flow_instance fi
+                 left join flow_definition fd on fi.definition_id = fd.id
+                ${ew.getCustomSqlSegment}
+    </select>
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml
new file mode 100644
index 0000000..73e4ec7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.FlwTaskMapper">
+    <resultMap type="org.dromara.workflow.domain.vo.FlowTaskVo" id="FlowTaskResult">
+    </resultMap>
+    <resultMap type="org.dromara.workflow.domain.vo.FlowHisTaskVo" id="FlowHisTaskResult">
+    </resultMap>
+
+    <select id="getListRunTask" resultMap="FlowTaskResult">
+        select * from (
+            select distinct
+                t.id,
+                t.node_code,
+                t.node_name,
+                t.node_type,
+                t.definition_id,
+                t.instance_id,
+                t.create_time,
+                t.update_time,
+                t.tenant_id,
+                i.business_id,
+                i.flow_status,
+                i.create_by,
+                d.flow_name,
+                d.flow_code,
+                d.form_custom,
+                d.category,
+                COALESCE(t.form_path, d.form_path) as form_path,
+                d.version,
+                uu.processed_by,
+                uu.type
+            from flow_task as t
+                    left join flow_user uu on uu.associated = t.id
+                    left join flow_definition d on t.definition_id = d.id
+                    left join flow_instance i on t.instance_id = i.id
+            where t.node_type = 1
+              and t.del_flag = '0'
+              and uu.del_flag = '0'
+              and uu.type in ('1','2','3')
+         ) t
+         ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="getListFinishTask" resultMap="FlowHisTaskResult">
+        select * from (
+            select
+                a.id,
+                a.node_code,
+                a.node_name,
+                a.cooperate_type,
+                a.approver,
+                a.collaborator,
+                a.node_type,
+                a.target_node_code,
+                a.target_node_name,
+                a.definition_id,
+                a.instance_id,
+                a.flow_status flow_task_status,
+                a.message,
+                a.ext,
+                a.create_time,
+                a.update_time,
+                a.tenant_id,
+                a.form_custom,
+                a.form_path,
+                b.flow_status,
+                b.business_id,
+                b.create_by,
+                c.flow_name,
+                c.flow_code,
+                c.category,
+                c.version
+            from flow_his_task a
+                    left join flow_instance b on a.instance_id = b.id
+                    left join flow_definition c on a.definition_id = c.id
+            where a.del_flag ='0'
+              and b.del_flag = '0'
+              and c.del_flag = '0'
+              and a.node_type in ('1','3','4')
+        ) t
+        ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="getTaskCopyByPage" resultMap="FlowTaskResult">
+       select * from (
+            select
+                b.id,
+                b.update_time,
+                c.business_id,
+                c.flow_status,
+                c.create_by,
+                a.processed_by,
+                a.create_time,
+                b.form_custom,
+                b.form_path,
+                b.node_name,
+                b.node_code,
+                d.flow_name,
+                d.flow_code,
+                d.category,
+                d.version
+            from flow_user a
+                left join flow_his_task b on a.associated = b.task_id
+                left join flow_instance c on b.instance_id = c.id
+                left join flow_definition d on c.definition_id=d.id
+            where a.type = '4'
+               and a.del_flag = '0'
+               and b.del_flag = '0'
+               and d.del_flag = '0'
+            ) t
+        ${ew.getCustomSqlSegment}
+    </select>
+</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml
deleted file mode 100644
index 4375cb2..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.workflow.mapper.WfCategoryMapper">
-
-</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml
deleted file mode 100644
index 8d579f7..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.workflow.mapper.WfDefinitionConfigMapper">
-
-</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml
deleted file mode 100644
index 59221f8..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.workflow.mapper.WfFormManageMapper">
-
-</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml
deleted file mode 100644
index b65194f..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.workflow.mapper.WfNodeConfigMapper">
-
-</mapper>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml
deleted file mode 100644
index 4a9179b..0000000
--- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.workflow.mapper.WfTaskBackNodeMapper">
-
-</mapper>
diff --git "a/script/bpmn/\346\250\241\345\236\213.zip" "b/script/bpmn/\346\250\241\345\236\213.zip"
deleted file mode 100644
index 6f30952..0000000
--- "a/script/bpmn/\346\250\241\345\236\213.zip"
+++ /dev/null
Binary files differ
diff --git a/script/docker/database.yml b/script/docker/database.yml
index 0368fd2..6034b39 100644
--- a/script/docker/database.yml
+++ b/script/docker/database.yml
@@ -1,5 +1,3 @@
-version: '3'
-
 services:
   # 姝ら暅鍍忎粎鐢ㄤ簬娴嬭瘯 姝e紡鐜闇�鑷瀹夎鏁版嵁搴�
   # SID: XE user: system password: oracle
diff --git a/script/docker/docker-compose.yml b/script/docker/docker-compose.yml
index 91d97ae..885c236 100644
--- a/script/docker/docker-compose.yml
+++ b/script/docker/docker-compose.yml
@@ -1,5 +1,3 @@
-version: '3'
-
 services:
   mysql:
     image: mysql:8.0.33
@@ -100,7 +98,7 @@
     network_mode: "host"
 
   ruoyi-server1:
-    image: ruoyi/ruoyi-server:5.2.2
+    image: ruoyi/ruoyi-server:5.3.0
     container_name: ruoyi-server1
     environment:
       # 鏃跺尯涓婃捣
@@ -115,7 +113,7 @@
     network_mode: "host"
 
   ruoyi-server2:
-    image: ruoyi/ruoyi-server:5.2.2
+    image: ruoyi/ruoyi-server:5.3.0
     container_name: ruoyi-server2
     environment:
       # 鏃跺尯涓婃捣
@@ -130,7 +128,7 @@
     network_mode: "host"
 
   ruoyi-monitor-admin:
-    image: ruoyi/ruoyi-monitor-admin:5.2.2
+    image: ruoyi/ruoyi-monitor-admin:5.3.0
     container_name: ruoyi-monitor-admin
     environment:
       # 鏃跺尯涓婃捣
@@ -142,7 +140,7 @@
     network_mode: "host"
 
   ruoyi-snailjob-server:
-    image: ruoyi/ruoyi-snailjob-server:5.2.2
+    image: ruoyi/ruoyi-snailjob-server:5.3.0
     container_name: ruoyi-snailjob-server
     environment:
       # 鏃跺尯涓婃捣
diff --git a/script/leave/leave1.json b/script/leave/leave1.json
new file mode 100644
index 0000000..0cf67bc
--- /dev/null
+++ b/script/leave/leave1.json
@@ -0,0 +1,75 @@
+{
+  "flowCode" : "leave1",
+  "flowName" : "璇峰亣鐢宠-鏅��",
+  "category" : "1",
+  "version" : "1",
+  "formCustom" : "N",
+  "formPath" : "/workflow/leaveEdit/index",
+  "nodeList" : [ {
+    "nodeType" : 0,
+    "nodeCode" : "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
+    "nodeName" : "寮�濮�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "200,200|200,200",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
+      "nextNodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42",
+      "skipType" : "PASS",
+      "coordinate" : "220,200;310,200"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42",
+    "nodeName" : "鐢宠浜�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "360,200|360,200",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42",
+      "nextNodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf",
+      "skipType" : "PASS",
+      "coordinate" : "410,200;490,200"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf",
+    "nodeName" : "缁勯暱",
+    "permissionFlag" : "role:1",
+    "nodeRatio" : 0.000,
+    "coordinate" : "540,200|540,200",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf",
+      "nextNodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe",
+      "skipType" : "PASS",
+      "coordinate" : "590,200;670,200"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe",
+    "nodeName" : "閮ㄩ棬涓荤",
+    "permissionFlag" : "role:3,role:4",
+    "nodeRatio" : 0.000,
+    "coordinate" : "720,200|720,200",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe",
+      "nextNodeCode" : "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
+      "skipType" : "PASS",
+      "coordinate" : "770,200;880,200"
+    } ]
+  }, {
+    "nodeType" : 2,
+    "nodeCode" : "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
+    "nodeName" : "缁撴潫",
+    "nodeRatio" : 0.000,
+    "coordinate" : "900,200|900,200",
+    "skipAnyNode" : "N",
+    "formCustom" : "N"
+  } ]
+}
\ No newline at end of file
diff --git a/script/leave/leave2.json b/script/leave/leave2.json
new file mode 100644
index 0000000..9fce8ff
--- /dev/null
+++ b/script/leave/leave2.json
@@ -0,0 +1,111 @@
+{
+  "flowCode" : "leave2",
+  "flowName" : "璇峰亣鐢宠-鎺掍粬缃戝叧",
+  "category" : "1",
+  "version" : "1",
+  "formCustom" : "N",
+  "formPath" : "/workflow/leaveEdit/index",
+  "nodeList" : [ {
+    "nodeType" : 0,
+    "nodeCode" : "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
+    "nodeName" : "寮�濮�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "300,240|300,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
+      "nextNodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd",
+      "skipType" : "PASS",
+      "coordinate" : "320,240;390,240"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd",
+    "nodeName" : "鐢宠浜�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "440,240|440,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd",
+      "nextNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
+      "skipType" : "PASS",
+      "coordinate" : "490,240;535,240"
+    } ]
+  }, {
+    "nodeType" : 3,
+    "nodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
+    "nodeRatio" : 0.000,
+    "coordinate" : "560,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
+      "nextNodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86",
+      "skipType" : "PASS",
+      "skipCondition" : "le@@leaveDays|2",
+      "coordinate" : "560,265;560,320;670,320"
+    }, {
+      "nowNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
+      "nextNodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605",
+      "skipName" : "澶т簬涓ゅぉ",
+      "skipType" : "PASS",
+      "skipCondition" : "gt@@leaveDays|2",
+      "coordinate" : "560,215;560,160;670,160|560,187"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86",
+    "nodeName" : "缁勯暱",
+    "permissionFlag" : "3,4",
+    "nodeRatio" : 0.000,
+    "coordinate" : "720,320|720,320",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86",
+      "nextNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
+      "skipType" : "PASS",
+      "coordinate" : "770,320;860,320;860,280"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
+    "nodeName" : "鎬荤粡鐞�",
+    "permissionFlag" : "role:1",
+    "nodeRatio" : 0.000,
+    "coordinate" : "860,240|860,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
+      "nextNodeCode" : "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
+      "skipType" : "PASS",
+      "coordinate" : "910,240;980,240"
+    } ]
+  }, {
+    "nodeType" : 2,
+    "nodeCode" : "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
+    "nodeName" : "缁撴潫",
+    "nodeRatio" : 0.000,
+    "coordinate" : "1000,240|1000,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N"
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605",
+    "nodeName" : "閮ㄩ棬棰嗗",
+    "permissionFlag" : "role:1",
+    "nodeRatio" : 0.000,
+    "coordinate" : "720,160|720,160",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605",
+      "nextNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
+      "skipType" : "PASS",
+      "coordinate" : "770,160;860,160;860,200"
+    } ]
+  } ]
+}
diff --git a/script/leave/leave3.json b/script/leave/leave3.json
new file mode 100644
index 0000000..08daae4
--- /dev/null
+++ b/script/leave/leave3.json
@@ -0,0 +1,121 @@
+{
+  "flowCode" : "leave3",
+  "flowName" : "璇峰亣鐢宠-骞惰缃戝叧",
+  "category" : "1",
+  "version" : "1",
+  "formCustom" : "N",
+  "formPath" : "/workflow/leaveEdit/index",
+  "nodeList" : [ {
+    "nodeType" : 0,
+    "nodeCode" : "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
+    "nodeName" : "寮�濮�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "380,220|380,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
+      "nextNodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99",
+      "skipType" : "PASS",
+      "coordinate" : "400,220;470,220"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99",
+    "nodeName" : "鐢宠浜�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "520,220|520,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99",
+      "nextNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
+      "skipType" : "PASS",
+      "coordinate" : "570,220;655,220"
+    } ]
+  }, {
+    "nodeType" : 4,
+    "nodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
+    "nodeRatio" : 0.000,
+    "coordinate" : "680,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
+      "nextNodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe",
+      "skipType" : "PASS",
+      "coordinate" : "680,195;680,140;750,140"
+    }, {
+      "nowNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
+      "nextNodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394",
+      "skipType" : "PASS",
+      "coordinate" : "680,245;680,300;750,300"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe",
+    "nodeName" : "甯傚満閮�",
+    "permissionFlag" : "role:1",
+    "nodeRatio" : 0.000,
+    "coordinate" : "800,140|800,140",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe",
+      "nextNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
+      "skipType" : "PASS",
+      "coordinate" : "850,140;920,140;920,195"
+    } ]
+  }, {
+    "nodeType" : 4,
+    "nodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
+    "nodeRatio" : 0.000,
+    "coordinate" : "920,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
+      "nextNodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6",
+      "skipType" : "PASS",
+      "coordinate" : "945,220;975,220;975,220;960,220;960,220;990,220"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6",
+    "nodeName" : "CEO",
+    "permissionFlag" : "1",
+    "nodeRatio" : 0.000,
+    "coordinate" : "1040,220|1040,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6",
+      "nextNodeCode" : "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
+      "skipType" : "PASS",
+      "coordinate" : "1090,220;1140,220"
+    } ]
+  }, {
+    "nodeType" : 2,
+    "nodeCode" : "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
+    "nodeName" : "缁撴潫",
+    "nodeRatio" : 0.000,
+    "coordinate" : "1160,220|1160,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N"
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394",
+    "nodeName" : "缁煎悎閮�",
+    "permissionFlag" : "role:3,role:4",
+    "nodeRatio" : 0.000,
+    "coordinate" : "800,300|800,300",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394",
+      "nextNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
+      "skipType" : "PASS",
+      "coordinate" : "850,300;920,300;920,245"
+    } ]
+  } ]
+}
\ No newline at end of file
diff --git a/script/leave/leave4.json b/script/leave/leave4.json
new file mode 100644
index 0000000..f8f4408
--- /dev/null
+++ b/script/leave/leave4.json
@@ -0,0 +1,90 @@
+{
+  "flowCode" : "leave4",
+  "flowName" : "璇峰亣鐢宠-浼氱",
+  "category" : "1",
+  "version" : "1",
+  "formCustom" : "N",
+  "formPath" : "/workflow/leaveEdit/index",
+  "nodeList" : [ {
+    "nodeType" : 0,
+    "nodeCode" : "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
+    "nodeName" : "寮�濮�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "320,240|320,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
+      "nextNodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f",
+      "skipType" : "PASS",
+      "coordinate" : "340,240;410,240"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f",
+    "nodeName" : "鐢宠浜�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "460,240|460,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f",
+      "nextNodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045",
+      "skipType" : "PASS",
+      "coordinate" : "510,240;590,240"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045",
+    "nodeName" : "鐧惧垎涔�60閫氳繃",
+    "permissionFlag" : "${userList}",
+    "nodeRatio" : 60.000,
+    "coordinate" : "640,240|640,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045",
+      "nextNodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
+      "skipType" : "PASS",
+      "coordinate" : "690,240;770,240"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
+    "nodeName" : "鍏ㄩ儴瀹℃壒閫氳繃",
+    "permissionFlag" : "role:1,role:3",
+    "nodeRatio" : 100.000,
+    "coordinate" : "820,240|820,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
+      "nextNodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
+      "skipType" : "PASS",
+      "coordinate" : "870,240;950,240"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
+    "nodeName" : "CEO",
+    "permissionFlag" : "1",
+    "nodeRatio" : 0.000,
+    "coordinate" : "1000,240|1000,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
+      "nextNodeCode" : "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
+      "skipType" : "PASS",
+      "coordinate" : "1050,240;1080,240;1080,240;1070,240;1070,240;1100,240"
+    } ]
+  }, {
+    "nodeType" : 2,
+    "nodeCode" : "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
+    "nodeName" : "缁撴潫",
+    "nodeRatio" : 0.000,
+    "coordinate" : "1120,240|1120,240",
+    "skipAnyNode" : "N",
+    "formCustom" : "N"
+  } ]
+}
\ No newline at end of file
diff --git a/script/leave/leave5.json b/script/leave/leave5.json
new file mode 100644
index 0000000..dc99494
--- /dev/null
+++ b/script/leave/leave5.json
@@ -0,0 +1,121 @@
+{
+  "flowCode" : "leave5",
+  "flowName" : "璇峰亣鐢宠-骞惰浼氱缃戝叧",
+  "category" : "1",
+  "version" : "1",
+  "formCustom" : "N",
+  "formPath" : "/workflow/leaveEdit/index",
+  "nodeList" : [ {
+    "nodeType" : 0,
+    "nodeCode" : "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
+    "nodeName" : "寮�濮�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "300,220|300,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
+      "nextNodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374",
+      "skipType" : "PASS",
+      "coordinate" : "320,220;350,220;350,220;340,220;340,220;370,220"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374",
+    "nodeName" : "鐢宠浜�",
+    "nodeRatio" : 0.000,
+    "coordinate" : "420,220|420,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374",
+      "nextNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
+      "skipType" : "PASS",
+      "coordinate" : "470,220;535,220"
+    } ]
+  }, {
+    "nodeType" : 4,
+    "nodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
+    "nodeRatio" : 0.000,
+    "coordinate" : "560,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
+      "nextNodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
+      "skipType" : "PASS",
+      "coordinate" : "560,245;560,320;650,320"
+    }, {
+      "nowNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
+      "nextNodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
+      "skipType" : "PASS",
+      "coordinate" : "560,195;560,120;650,120"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
+    "nodeName" : "浼氱",
+    "permissionFlag" : "role:1,role:3",
+    "nodeRatio" : 100.000,
+    "coordinate" : "700,320|700,320",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
+      "nextNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b",
+      "skipType" : "PASS",
+      "coordinate" : "750,320;860,320;860,245"
+    } ]
+  }, {
+    "nodeType" : 4,
+    "nodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b",
+    "nodeRatio" : 0.000,
+    "coordinate" : "860,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b",
+      "nextNodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9",
+      "skipType" : "PASS",
+      "coordinate" : "885,220;950,220"
+    } ]
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9",
+    "nodeName" : "CEO",
+    "permissionFlag" : "1",
+    "nodeRatio" : 0.000,
+    "coordinate" : "1000,220|1000,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9",
+      "nextNodeCode" : "03c4d2bc-58b5-4408-a2e4-65afb046f169",
+      "skipType" : "PASS",
+      "coordinate" : "1050,220;1120,220"
+    } ]
+  }, {
+    "nodeType" : 2,
+    "nodeCode" : "03c4d2bc-58b5-4408-a2e4-65afb046f169",
+    "nodeName" : "缁撴潫",
+    "nodeRatio" : 0.000,
+    "coordinate" : "1140,220|1140,220",
+    "skipAnyNode" : "N",
+    "formCustom" : "N"
+  }, {
+    "nodeType" : 1,
+    "nodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
+    "nodeName" : "鐧惧垎涔�60绁ㄧ",
+    "permissionFlag" : "${userList}",
+    "nodeRatio" : 60.000,
+    "coordinate" : "700,120|700,120",
+    "skipAnyNode" : "N",
+    "formCustom" : "N",
+    "skipList" : [ {
+      "nowNodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
+      "nextNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b",
+      "skipType" : "PASS",
+      "coordinate" : "750,120;860,120;860,195"
+    } ]
+  } ]
+}
\ No newline at end of file
diff --git a/script/sql/flowable.sql b/script/sql/flowable.sql
deleted file mode 100644
index e8dc798..0000000
--- a/script/sql/flowable.sql
+++ /dev/null
@@ -1,176 +0,0 @@
-insert into sys_menu values('11616', '宸ヤ綔娴�'  , '0',    '6', 'workflow',          '',                                 '', '1', '0', 'M', '0', '0', '',                       'workflow', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11617', '妯″瀷绠$悊', '11616', '2', 'model',             'workflow/model/index',             '', '1', '1', 'C', '0', '0', 'workflow:model:list',    'model', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11618', '鎴戠殑浠诲姟', '0', '7', 'task',              '',                                 '', '1', '0', 'M', '0', '0', '',                       'my-task', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting',       'workflow/task/taskWaiting',              '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish',       'workflow/task/taskFinish',              '', '1', '1', 'C', '0', '0', '',                       'finish', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList',       'workflow/task/taskCopyList',              '', '1', '1', 'C', '0', '0', '',                       'my-copy', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '',                       'process-definition', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance',   'workflow/processInstance/index',   '', '1', '1', 'C', '0', '0', '',                       'tree-table', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11622', '娴佺▼鍒嗙被', '11616', '1', 'category',          'workflow/category/index',          '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument',        'workflow/task/myDocument',         '', '1', '1', 'C', '0', '0', '',                       'guide', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor',           '',                                 '', '1', '0', 'M', '0', '0', '',                       'monitor', 103, 1, sysdate(), NULL, NULL, '');
-insert into sys_menu values('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting',    'workflow/task/allTaskWaiting',     '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, sysdate(), NULL, NULL, '');
-
-
--- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
-insert into sys_menu values ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, sysdate(), null, null, '');
-insert into sys_menu values ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add',   '#', 103, 1, sysdate(), null, null, '');
-insert into sys_menu values ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit',  '#', 103, 1, sysdate(), null, null, '');
-insert into sys_menu values ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, sysdate(), null, null, '');
-insert into sys_menu values ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, sysdate(), null, null, '');
--- 璇峰亣鍗曚俊鎭�
-create table test_leave
-(
-    id          bigint                       not null comment '涓婚敭',
-    leave_type  varchar(255)                 not null comment '璇峰亣绫诲瀷',
-    start_date   datetime                     not null comment '寮�濮嬫椂闂�',
-    end_date     datetime                     not null comment '缁撴潫鏃堕棿',
-    leave_days  int(10)                      not null comment '璇峰亣澶╂暟',
-    remark      varchar(255)                 null comment '璇峰亣鍘熷洜',
-    status      varchar(255)                 null comment '鐘舵��',
-    create_dept bigint                       null comment '鍒涘缓閮ㄩ棬',
-    create_by   bigint                       null comment '鍒涘缓鑰�',
-    create_time datetime                     null comment '鍒涘缓鏃堕棿',
-    update_by   bigint                       null comment '鏇存柊鑰�',
-    update_time datetime                     null comment '鏇存柊鏃堕棿',
-    tenant_id   varchar(20)                  null comment '绉熸埛缂栧彿',
-    PRIMARY KEY (id) USING BTREE
-) ENGINE = InnoDB COMMENT = '璇峰亣鐢宠琛�';
-
--- 娴佺▼鍒嗙被淇℃伅琛�
-create table wf_category
-(
-    id            bigint                       not null comment '涓婚敭'
-        primary key,
-    category_name varchar(255)                 null comment '鍒嗙被鍚嶇О',
-    category_code varchar(255)                 null comment '鍒嗙被缂栫爜',
-    parent_id     bigint                       null comment '鐖剁骇id',
-    sort_num      int(19)                      null comment '鎺掑簭',
-    tenant_id     varchar(20)                  null comment '绉熸埛缂栧彿',
-    create_dept   bigint                       null comment '鍒涘缓閮ㄩ棬',
-    create_by     bigint                       null comment '鍒涘缓鑰�',
-    create_time   datetime                     null comment '鍒涘缓鏃堕棿',
-    update_by     bigint                       null comment '鏇存柊鑰�',
-    update_time   datetime                     null comment '鏇存柊鏃堕棿',
-    constraint uni_category_code
-        unique (category_code)
-) engine=innodb comment= '娴佺▼鍒嗙被';
-INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, sysdate(), 1, sysdate());
-
-create table wf_task_back_node
-(
-    id          bigint                       not null
-        primary key,
-    node_id     varchar(255)                 not null comment '鑺傜偣id',
-    node_name   varchar(255)                 not null comment '鑺傜偣鍚嶇О',
-    order_no    int                          not null comment '鎺掑簭',
-    instance_id varchar(255)                 null comment '娴佺▼瀹炰緥id',
-    task_type   varchar(255)                 not null comment '鑺傜偣绫诲瀷',
-    assignee    varchar(2000)                not null comment '瀹℃壒浜�',
-    tenant_id   varchar(20)                  null comment '绉熸埛缂栧彿',
-    create_dept bigint                       null comment '鍒涘缓閮ㄩ棬',
-    create_by   bigint                       null comment '鍒涘缓鑰�',
-    create_time datetime                     null comment '鍒涘缓鏃堕棿',
-    update_by   bigint                       null comment '鏇存柊鑰�',
-    update_time datetime                     null comment '鏇存柊鏃堕棿'
-)
-    comment '鑺傜偣瀹℃壒璁板綍';
-
-create table wf_definition_config
-(
-    id            bigint                        not null comment '涓婚敭'
-        primary key,
-    table_name    varchar(255)                  not null comment '琛ㄥ悕',
-    definition_id varchar(255)                  not null comment '娴佺▼瀹氫箟ID',
-    process_key   varchar(255)                  not null comment '娴佺▼KEY',
-    version       int(10)                       not null comment '娴佺▼鐗堟湰',
-    create_dept   bigint                        null comment '鍒涘缓閮ㄩ棬',
-    create_by     bigint                        null comment '鍒涘缓鑰�',
-    create_time   datetime                      null comment '鍒涘缓鏃堕棿',
-    update_by     bigint                        null comment '鏇存柊鑰�',
-    update_time   datetime                      null comment '鏇存柊鏃堕棿',
-    remark        varchar(500) default ''       null comment '澶囨敞',
-    tenant_id     varchar(20)                   null comment '绉熸埛缂栧彿',
-    constraint uni_definition_id
-        unique (definition_id)
-)
-    comment '娴佺▼瀹氫箟閰嶇疆';
-
-create table wf_form_manage
-(
-    id          bigint       not null comment '涓婚敭'
-        primary key,
-    form_name   varchar(255) not null comment '琛ㄥ崟鍚嶇О',
-    form_type   varchar(255) not null comment '琛ㄥ崟绫诲瀷',
-    router      varchar(255) not null comment '璺敱鍦板潃/琛ㄥ崟ID',
-    remark      varchar(500) null comment '澶囨敞',
-    tenant_id   varchar(20)  null comment '绉熸埛缂栧彿',
-    create_dept bigint       null comment '鍒涘缓閮ㄩ棬',
-    create_by   bigint       null comment '鍒涘缓鑰�',
-    create_time datetime     null comment '鍒涘缓鏃堕棿',
-    update_by   bigint       null comment '鏇存柊鑰�',
-    update_time datetime     null comment '鏇存柊鏃堕棿'
-)
-    comment '琛ㄥ崟绠$悊';
-
-insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '璇峰亣鐢宠', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, sysdate(), 1, sysdate());
-
-create table wf_node_config
-(
-    id               bigint       not null comment '涓婚敭'
-        primary key,
-    form_id          bigint       null comment '琛ㄥ崟id',
-    form_type        varchar(255) null comment '琛ㄥ崟绫诲瀷',
-    node_name        varchar(255) not null comment '鑺傜偣鍚嶇О',
-    node_id          varchar(255) not null comment '鑺傜偣id',
-    definition_id    varchar(255) not null comment '娴佺▼瀹氫箟id',
-    apply_user_task  char(1)      default '0'     comment '鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級',
-    create_dept      bigint       null comment '鍒涘缓閮ㄩ棬',
-    create_by        bigint       null comment '鍒涘缓鑰�',
-    create_time      datetime     null comment '鍒涘缓鏃堕棿',
-    update_by        bigint       null comment '鏇存柊鑰�',
-    update_time      datetime     null comment '鏇存柊鏃堕棿',
-    tenant_id        varchar(20)  null comment '绉熸埛缂栧彿'
-)
-    comment '鑺傜偣閰嶇疆';
-
-
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '璇峰亣鐢宠', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '璇峰亣鐢宠鑿滃崟');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '璇峰亣鐢宠鏂板', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '璇峰亣鐢宠淇敼', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '璇峰亣鐢宠鍒犻櫎', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '璇峰亣鐢宠瀵煎嚭', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate(), NULL, NULL, '');
-
-INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, sysdate(), NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
-INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, sysdate(), NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
-
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '宸叉挙閿�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, sysdate(), NULL, NULL, '鑽夌');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,sysdate(), NULL, NULL, '寰呭鏍�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '宸插畬鎴�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '宸蹭綔搴�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '宸查��鍥�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,sysdate(), NULL, NULL, '宸茬粓姝�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '鑷畾涔夎〃鍗�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '鍔ㄦ�佽〃鍗�');
-
--- 琛ㄥ崟绠$悊 SQL
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11628, '琛ㄥ崟绠$悊', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, sysdate(), null, null, '琛ㄥ崟绠$悊鑿滃崟');
-
--- 琛ㄥ崟绠$悊鎸夐挳 SQL
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11644, '琛ㄥ崟绠$悊鏌ヨ', 11628, '1',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query',        '', 103, 1, sysdate(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11645, '琛ㄥ崟绠$悊鏂板', 11628, '2',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add',          '', 103, 1, sysdate(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11646, '琛ㄥ崟绠$悊淇敼', 11628, '3',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit',         '', 103, 1, sysdate(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11647, '琛ㄥ崟绠$悊鍒犻櫎', 11628, '4',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove',       '', 103, 1, sysdate(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11648, '琛ㄥ崟绠$悊瀵煎嚭', 11628, '5',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export',       'tree-table', 103, 1, sysdate(), null, null, '');
diff --git a/script/sql/oracle/flowable.sql b/script/sql/oracle/flowable.sql
deleted file mode 100644
index 65474f4..0000000
--- a/script/sql/oracle/flowable.sql
+++ /dev/null
@@ -1,261 +0,0 @@
-insert into sys_menu values('11616', '宸ヤ綔娴�'  , '0',    '6', 'workflow',          '',                                 '', '1', '0', 'M', '0', '0', '',                       'workflow', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11617', '妯″瀷绠$悊', '11616', '2', 'model',             'workflow/model/index',             '', '1', '1', 'C', '0', '0', 'workflow:model:list',    'model', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11618', '鎴戠殑浠诲姟', '0', '7', 'task',              '',                                 '', '1', '0', 'M', '0', '0', '',                       'my-task', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting',       'workflow/task/taskWaiting',              '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish',       'workflow/task/taskFinish',              '', '1', '1', 'C', '0', '0', '',                       'finish', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList',       'workflow/task/taskCopyList',              '', '1', '1', 'C', '0', '0', '',                       'my-copy', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '',                       'process-definition', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance',   'workflow/processInstance/index',   '', '1', '1', 'C', '0', '0', '',                       'tree-table', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11622', '娴佺▼鍒嗙被', '11616', '1', 'category',          'workflow/category/index',          '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument',        'workflow/task/myDocument',         '', '1', '1', 'C', '0', '0', '',                       'guide', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor',           '',                                 '', '1', '0', 'M', '0', '0', '',                       'monitor', 103, 1, sysdate, NULL, NULL, '');
-insert into sys_menu values('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting',    'workflow/task/allTaskWaiting',     '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, sysdate, NULL, NULL, '');
-
-
--- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
-insert into sys_menu values ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, sysdate, null, null, '');
-insert into sys_menu values ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add',   '#', 103, 1, sysdate, null, null, '');
-insert into sys_menu values ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit',  '#', 103, 1, sysdate, null, null, '');
-insert into sys_menu values ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, sysdate, null, null, '');
-insert into sys_menu values ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, sysdate, null, null, '');
-
--- 璇峰亣鍗曚俊鎭�
-create table TEST_LEAVE
-(
-    ID          NUMBER(20) not null
-        constraint PK_TEST_LEAVE
-        primary key,
-    LEAVE_TYPE  VARCHAR2(255),
-    START_DATE  DATE,
-    END_DATE    DATE,
-    LEAVE_DAYS  NUMBER(10),
-    REMARK      VARCHAR2(255),
-    STATUS      VARCHAR2(255),
-    CREATE_DEPT NUMBER(20),
-    CREATE_BY   NUMBER(20),
-    CREATE_TIME DATE,
-    UPDATE_BY   NUMBER(20),
-    UPDATE_TIME DATE,
-    TENANT_ID   VARCHAR2(20)
-);
-
-comment on table TEST_LEAVE is '璇峰亣鐢宠琛�';
-comment on column TEST_LEAVE.ID is '涓婚敭';
-comment on column TEST_LEAVE.LEAVE_TYPE is '璇峰亣绫诲瀷';
-comment on column TEST_LEAVE.START_DATE is '寮�濮嬫椂闂�';
-comment on column TEST_LEAVE.END_DATE is '缁撴潫鏃堕棿';
-comment on column TEST_LEAVE.LEAVE_DAYS is '璇峰亣澶╂暟';
-comment on column TEST_LEAVE.REMARK is '璇峰亣鍘熷洜';
-comment on column TEST_LEAVE.STATUS is '鐘舵��';
-comment on column TEST_LEAVE.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
-comment on column TEST_LEAVE.CREATE_BY is '鍒涘缓鑰�';
-comment on column TEST_LEAVE.CREATE_TIME is '鍒涘缓鏃堕棿';
-comment on column TEST_LEAVE.UPDATE_BY is '鏇存柊鑰�';
-comment on column TEST_LEAVE.UPDATE_TIME is '鏇存柊鏃堕棿';
-comment on column TEST_LEAVE.TENANT_ID is '绉熸埛缂栧彿';
-
--- 娴佺▼鍒嗙被淇℃伅琛�
-create table WF_CATEGORY
-(
-    ID            NUMBER(20) not null
-        constraint PK_WF_CATEGORY
-        primary key,
-    CATEGORY_NAME VARCHAR2(255),
-    CATEGORY_CODE VARCHAR2(255)
-        constraint UNI_CATEGORY_CODE
-        unique,
-    PARENT_ID     NUMBER(20),
-    SORT_NUM      NUMBER(10),
-    TENANT_ID     VARCHAR2(20),
-    CREATE_DEPT   NUMBER(20),
-    CREATE_BY     NUMBER(20),
-    CREATE_TIME   DATE,
-    UPDATE_BY     NUMBER(20),
-    UPDATE_TIME   DATE
-);
-
-comment on table WF_CATEGORY is '娴佺▼鍒嗙被';
-comment on column WF_CATEGORY.ID is '涓婚敭';
-comment on column WF_CATEGORY.CATEGORY_NAME is '鍒嗙被鍚嶇О';
-comment on column WF_CATEGORY.CATEGORY_CODE is '鍒嗙被缂栫爜';
-comment on column WF_CATEGORY.PARENT_ID is '鐖剁骇id';
-comment on column WF_CATEGORY.SORT_NUM is '鎺掑簭';
-comment on column WF_CATEGORY.TENANT_ID is '绉熸埛缂栧彿';
-comment on column WF_CATEGORY.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
-comment on column WF_CATEGORY.CREATE_BY is '鍒涘缓鑰�';
-comment on column WF_CATEGORY.CREATE_TIME is '鍒涘缓鏃堕棿';
-comment on column WF_CATEGORY.UPDATE_BY is '鏇存柊鑰�';
-comment on column WF_CATEGORY.UPDATE_TIME is '鏇存柊鏃堕棿';
-INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, sysdate, 1, sysdate);
-
-create table WF_TASK_BACK_NODE
-(
-    ID            NUMBER(20) not null
-        constraint PK_WF_TASK_BACK_NODE
-        primary key,
-    NODE_ID       VARCHAR2(255) not null,
-    NODE_NAME     VARCHAR2(255) not null,
-    ORDER_NO      NUMBER(20) not null,
-    INSTANCE_ID   VARCHAR2(255) not null,
-    TASK_TYPE     VARCHAR2(255) not null,
-    ASSIGNEE      VARCHAR2(2000) not null,
-    TENANT_ID     VARCHAR2(20),
-    CREATE_DEPT   NUMBER(20),
-    CREATE_BY     NUMBER(20),
-    CREATE_TIME   DATE,
-    UPDATE_BY     NUMBER(20),
-    UPDATE_TIME   DATE
-);
-comment on table WF_TASK_BACK_NODE is '鑺傜偣瀹℃壒璁板綍';
-comment on column WF_TASK_BACK_NODE.ID is '涓婚敭';
-comment on column WF_TASK_BACK_NODE.NODE_ID is '鑺傜偣id';
-comment on column WF_TASK_BACK_NODE.NODE_NAME is '鑺傜偣鍚嶇О';
-comment on column WF_TASK_BACK_NODE.ORDER_NO is '鎺掑簭';
-comment on column WF_TASK_BACK_NODE.INSTANCE_ID is '娴佺▼瀹炰緥id';
-comment on column WF_TASK_BACK_NODE.TASK_TYPE is '鑺傜偣绫诲瀷';
-comment on column WF_TASK_BACK_NODE.ASSIGNEE is '瀹℃壒浜�';
-comment on column WF_TASK_BACK_NODE.TENANT_ID is '绉熸埛缂栧彿';
-comment on column WF_TASK_BACK_NODE.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
-comment on column WF_TASK_BACK_NODE.CREATE_BY is '鍒涘缓鑰�';
-comment on column WF_TASK_BACK_NODE.CREATE_TIME is '鍒涘缓鏃堕棿';
-comment on column WF_TASK_BACK_NODE.UPDATE_BY is '鏇存柊鑰�';
-comment on column WF_TASK_BACK_NODE.UPDATE_TIME is '鏇存柊鏃堕棿';
-
-create table WF_DEFINITION_CONFIG
-(
-    ID            NUMBER(20) NOT NULL
-        CONSTRAINT PK_WF_DEFINITION_CONFIG
-        PRIMARY KEY,
-    TABLE_NAME    VARCHAR2(255) NOT NULL,
-    DEFINITION_ID VARCHAR2(255) NOT NULL,
-    PROCESS_KEY   VARCHAR2(255) NOT NULL,
-    VERSION       NUMBER(10)    NOT NULL,
-    REMARK        VARCHAR2(500),
-    TENANT_ID     VARCHAR2(20),
-    CREATE_DEPT   NUMBER(20),
-    CREATE_BY     NUMBER(20),
-    CREATE_TIME   DATE,
-    UPDATE_BY     NUMBER(20),
-    UPDATE_TIME   DATE,
-    constraint uni_definition_id
-        unique (definition_id)
-);
-comment on table WF_DEFINITION_CONFIG is '娴佺▼瀹氫箟閰嶇疆';
-comment on column WF_DEFINITION_CONFIG.ID is '涓婚敭';
-comment on column WF_DEFINITION_CONFIG.TABLE_NAME is '琛ㄥ悕';
-comment on column WF_DEFINITION_CONFIG.DEFINITION_ID is '娴佺▼瀹氫箟ID';
-comment on column WF_DEFINITION_CONFIG.PROCESS_KEY is '娴佺▼KEY';
-comment on column WF_DEFINITION_CONFIG.VERSION is '娴佺▼鐗堟湰';
-comment on column WF_DEFINITION_CONFIG.TENANT_ID is '绉熸埛缂栧彿';
-comment on column WF_DEFINITION_CONFIG.REMARK is '澶囨敞';
-comment on column WF_DEFINITION_CONFIG.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
-comment on column WF_DEFINITION_CONFIG.CREATE_BY is '鍒涘缓鑰�';
-comment on column WF_DEFINITION_CONFIG.CREATE_TIME is '鍒涘缓鏃堕棿';
-comment on column WF_DEFINITION_CONFIG.UPDATE_BY is '鏇存柊鑰�';
-comment on column WF_DEFINITION_CONFIG.UPDATE_TIME is '鏇存柊鏃堕棿';
-
-create table WF_FORM_MANAGE
-(
-    ID            NUMBER(20) NOT NULL
-        CONSTRAINT PK_WF_FORM_MANAGE
-        PRIMARY KEY,
-    FORM_NAME     VARCHAR2(255) NOT NULL,
-    FORM_TYPE     VARCHAR2(255) NOT NULL,
-    ROUTER        VARCHAR2(255) NOT NULL,
-    REMARK        VARCHAR2(500),
-    TENANT_ID     VARCHAR2(20),
-    CREATE_DEPT   NUMBER(20),
-    CREATE_BY     NUMBER(20),
-    CREATE_TIME   DATE,
-    UPDATE_BY     NUMBER(20),
-    UPDATE_TIME   DATE
-);
-
-comment on table WF_FORM_MANAGE is '琛ㄥ崟绠$悊';
-comment on column WF_FORM_MANAGE.ID is '涓婚敭';
-comment on column WF_FORM_MANAGE.FORM_NAME is '琛ㄥ崟鍚嶇О';
-comment on column WF_FORM_MANAGE.FORM_TYPE is '琛ㄥ崟绫诲瀷';
-comment on column WF_FORM_MANAGE.ROUTER is '璺敱鍦板潃/琛ㄥ崟ID';
-comment on column WF_FORM_MANAGE.REMARK is '澶囨敞';
-comment on column WF_FORM_MANAGE.TENANT_ID is '绉熸埛缂栧彿';
-comment on column WF_FORM_MANAGE.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
-comment on column WF_FORM_MANAGE.CREATE_BY is '鍒涘缓鑰�';
-comment on column WF_FORM_MANAGE.CREATE_TIME is '鍒涘缓鏃堕棿';
-comment on column WF_FORM_MANAGE.UPDATE_BY is '鏇存柊鑰�';
-comment on column WF_FORM_MANAGE.UPDATE_TIME is '鏇存柊鏃堕棿';
-
-insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '璇峰亣鐢宠', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, sysdate, 1, sysdate);
-
-create table WF_NODE_CONFIG
-(
-    ID               NUMBER(20) NOT NULL
-        CONSTRAINT PK_WF_NODE_CONFIG
-        PRIMARY KEY,
-    FORM_ID          NUMBER(20),
-    FORM_TYPE        VARCHAR2(255),
-    NODE_NAME        VARCHAR2(255) NOT NULL,
-    NODE_ID          VARCHAR2(255) NOT NULL,
-    DEFINITION_ID    VARCHAR2(255) NOT NULL,
-    APPLY_USER_TASK  CHAR(1) DEFAULT '0',
-    TENANT_ID        VARCHAR2(20),
-    CREATE_DEPT      NUMBER(20),
-    CREATE_BY        NUMBER(20),
-    CREATE_TIME      DATE,
-    UPDATE_BY        NUMBER(20),
-    UPDATE_TIME      DATE
-);
-
-comment on table WF_NODE_CONFIG is '鑺傜偣閰嶇疆';
-comment on column WF_NODE_CONFIG.ID is '涓婚敭';
-comment on column WF_NODE_CONFIG.FORM_ID is '琛ㄥ崟id';
-comment on column WF_NODE_CONFIG.FORM_TYPE is '琛ㄥ崟绫诲瀷';
-comment on column WF_NODE_CONFIG.NODE_ID is '鑺傜偣id';
-comment on column WF_NODE_CONFIG.NODE_NAME is '鑺傜偣鍚嶇О';
-comment on column WF_NODE_CONFIG.DEFINITION_ID is '娴佺▼瀹氫箟id';
-comment on column WF_NODE_CONFIG.APPLY_USER_TASK is '鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級';
-comment on column WF_NODE_CONFIG.TENANT_ID is '绉熸埛缂栧彿';
-comment on column WF_NODE_CONFIG.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
-comment on column WF_NODE_CONFIG.CREATE_BY is '鍒涘缓鑰�';
-comment on column WF_NODE_CONFIG.CREATE_TIME is '鍒涘缓鏃堕棿';
-comment on column WF_NODE_CONFIG.UPDATE_BY is '鏇存柊鑰�';
-comment on column WF_NODE_CONFIG.UPDATE_TIME is '鏇存柊鏃堕棿';
-
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '璇峰亣鐢宠', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate, NULL, NULL, '璇峰亣鐢宠鑿滃崟');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate, NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '璇峰亣鐢宠鏂板', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate, NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '璇峰亣鐢宠淇敼', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate, NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '璇峰亣鐢宠鍒犻櫎', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate, NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '璇峰亣鐢宠瀵煎嚭', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate, NULL, NULL, '');
-
-INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, sysdate, NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
-INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, sysdate, NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
-
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate, NULL, NULL, '宸叉挙閿�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, sysdate, NULL, NULL, '鑽夌');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,sysdate, NULL, NULL, '寰呭鏍�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, sysdate, NULL, NULL, '宸插畬鎴�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate, NULL, NULL, '宸蹭綔搴�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate, NULL, NULL, '宸查��鍥�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,sysdate, NULL, NULL, '宸茬粓姝�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, sysdate, NULL, NULL, '鑷畾涔夎〃鍗�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, sysdate, NULL, NULL, '鍔ㄦ�佽〃鍗�');
-
--- 琛ㄥ崟绠$悊 SQL
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11628, '琛ㄥ崟绠$悊', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, sysdate, null, null, '琛ㄥ崟绠$悊鑿滃崟');
-
--- 琛ㄥ崟绠$悊鎸夐挳 SQL
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11644, '琛ㄥ崟绠$悊鏌ヨ', 11628, '1',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query',        '', 103, 1, sysdate, null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11645, '琛ㄥ崟绠$悊鏂板', 11628, '2',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add',          '', 103, 1, sysdate, null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11646, '琛ㄥ崟绠$悊淇敼', 11628, '3',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit',         '', 103, 1, sysdate, null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11647, '琛ㄥ崟绠$悊鍒犻櫎', 11628, '4',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove',       '', 103, 1, sysdate, null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11648, '琛ㄥ崟绠$悊瀵煎嚭', 11628, '5',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export',       'tree-table', 103, 1, sysdate, null, null, '');
diff --git a/script/sql/oracle/snail_job_oracle.sql b/script/sql/oracle/oracle_ry_job.sql
similarity index 97%
rename from script/sql/oracle/snail_job_oracle.sql
rename to script/sql/oracle/oracle_ry_job.sql
index d2e17c1..c2dbbfa 100644
--- a/script/sql/oracle/snail_job_oracle.sql
+++ b/script/sql/oracle/oracle_ry_job.sql
@@ -2,7 +2,7 @@
  SnailJob Database Transfer Tool
  Source Server Type    : MySQL
  Target Server Type    : Oracle
- Date: 2024-07-06 12:49:36
+ Date: 2024-12-27 22:22:15
 */
 
 
@@ -74,6 +74,7 @@
 COMMENT ON TABLE sj_group_config IS '缁勯厤缃�';
 
 INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate);
+INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES ('prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate);
 
 -- sj_notify_config
 CREATE TABLE sj_notify_config
@@ -81,7 +82,7 @@
     id                     number GENERATED ALWAYS AS IDENTITY,
     namespace_id           varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
     group_name             varchar2(64)                                             NULL,
-    business_id            varchar2(64)                                             NULL,
+    notify_name            varchar2(64)  DEFAULT ''                                 NULL,
     system_task_type       smallint      DEFAULT 3                                  NOT NULL,
     notify_status          smallint      DEFAULT 0                                  NOT NULL,
     recipient_ids          varchar2(128)                                            NULL,
@@ -97,12 +98,12 @@
 ALTER TABLE sj_notify_config
     ADD CONSTRAINT pk_sj_notify_config PRIMARY KEY (id);
 
-CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name, business_id);
+CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name);
 
 COMMENT ON COLUMN sj_notify_config.id IS '涓婚敭';
 COMMENT ON COLUMN sj_notify_config.namespace_id IS '鍛藉悕绌洪棿id';
 COMMENT ON COLUMN sj_notify_config.group_name IS '缁勫悕绉�';
-COMMENT ON COLUMN sj_notify_config.business_id IS '涓氬姟id  ( job_id鎴杦orkflow_id鎴杝cene_name ) ';
+COMMENT ON COLUMN sj_notify_config.notify_name IS '閫氱煡鍚嶇О';
 COMMENT ON COLUMN sj_notify_config.system_task_type IS '浠诲姟绫诲瀷 1. 閲嶈瘯浠诲姟 2. 閲嶈瘯鍥炶皟 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟';
 COMMENT ON COLUMN sj_notify_config.notify_status IS '閫氱煡鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�';
 COMMENT ON COLUMN sj_notify_config.recipient_ids IS '鎺ユ敹浜篿d鍒楄〃';
@@ -320,6 +321,7 @@
     max_retry_count  number        DEFAULT 5                                  NOT NULL,
     back_off         smallint      DEFAULT 1                                  NOT NULL,
     trigger_interval varchar2(16)  DEFAULT ''                                 NULL,
+    notify_ids       varchar2(128) DEFAULT ''                                 NULL,
     deadline_request number        DEFAULT 60000                              NOT NULL,
     executor_timeout number        DEFAULT 5                                  NOT NULL,
     route_key        smallint      DEFAULT 4                                  NOT NULL,
@@ -341,6 +343,7 @@
 COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '鏈�澶ч噸璇曟鏁�';
 COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1銆侀粯璁ょ瓑绾� 2銆佸浐瀹氶棿闅旀椂闂� 3銆丆RON 琛ㄨ揪寮�';
 COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '闂撮殧鏃堕暱';
+COMMENT ON COLUMN sj_retry_scene_config.notify_ids IS '閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃';
 COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 璋冪敤閾捐秴鏃� 鍗曚綅姣';
 COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
 COMMENT ON COLUMN sj_retry_scene_config.route_key IS '璺敱绛栫暐';
@@ -505,6 +508,8 @@
     retry_interval   number        DEFAULT 0                                  NOT NULL,
     bucket_index     number        DEFAULT 0                                  NOT NULL,
     resident         smallint      DEFAULT 0                                  NOT NULL,
+    notify_ids       varchar2(128) DEFAULT ''                                 NULL,
+    owner_id         number                                                   NULL,
     description      varchar2(256) DEFAULT ''                                 NULL,
     ext_attrs        varchar2(256) DEFAULT ''                                 NULL,
     deleted          smallint      DEFAULT 0                                  NOT NULL,
@@ -540,6 +545,8 @@
 COMMENT ON COLUMN sj_job.retry_interval IS '閲嶈瘯闂撮殧 ( s ) ';
 COMMENT ON COLUMN sj_job.bucket_index IS 'bucket';
 COMMENT ON COLUMN sj_job.resident IS '鏄惁鏄父椹讳换鍔�';
+COMMENT ON COLUMN sj_job.notify_ids IS '閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃';
+COMMENT ON COLUMN sj_job.owner_id IS '璐熻矗浜篿d';
 COMMENT ON COLUMN sj_job.description IS '鎻忚堪';
 COMMENT ON COLUMN sj_job.ext_attrs IS '鎵╁睍瀛楁';
 COMMENT ON COLUMN sj_job.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
@@ -547,7 +554,7 @@
 COMMENT ON COLUMN sj_job.update_dt IS '淇敼鏃堕棿';
 COMMENT ON TABLE sj_job IS '浠诲姟淇℃伅';
 
-INSERT INTO sj_job(namespace_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, description, ext_attrs, deleted, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', 'demo-job', NULL, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', '', 0, sysdate, sysdate);
+INSERT INTO sj_job(namespace_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, notify_ids, owner_id, description, ext_attrs, deleted, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', 'demo-job', NULL, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1,'', '', 0, sysdate, sysdate);
 
 -- sj_job_log_message
 CREATE TABLE sj_job_log_message
@@ -780,6 +787,7 @@
     description      varchar2(256) DEFAULT ''                                 NULL,
     flow_info        clob          DEFAULT NULL                               NULL,
     wf_context       clob          DEFAULT NULL                               NULL,
+    notify_ids       varchar2(128) DEFAULT ''                                 NULL,
     bucket_index     number        DEFAULT 0                                  NOT NULL,
     version          number                                                   NOT NULL,
     ext_attrs        varchar2(256) DEFAULT ''                                 NULL,
@@ -807,6 +815,7 @@
 COMMENT ON COLUMN sj_workflow.description IS '鎻忚堪';
 COMMENT ON COLUMN sj_workflow.flow_info IS '娴佺▼淇℃伅';
 COMMENT ON COLUMN sj_workflow.wf_context IS '涓婁笅鏂�';
+COMMENT ON COLUMN sj_workflow.notify_ids IS '閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃';
 COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket';
 COMMENT ON COLUMN sj_workflow.version IS '鐗堟湰鍙�';
 COMMENT ON COLUMN sj_workflow.ext_attrs IS '鎵╁睍瀛楁';
diff --git a/script/sql/oracle/oracle_ry_vue_5.X.sql b/script/sql/oracle/oracle_ry_vue_5.X.sql
index 0aed89d..94024c9 100644
--- a/script/sql/oracle/oracle_ry_vue_5.X.sql
+++ b/script/sql/oracle/oracle_ry_vue_5.X.sql
@@ -5,7 +5,7 @@
 (
     id                 number(20)        not null,
     user_id            number(20)        not null,
-    tenant_id          varchar2(20)      default null,
+    tenant_id          varchar2(20)      default '000000',
     auth_id            varchar2(255)     not null,
     source             varchar2(255)     not null,
     open_id            varchar2(255)     default null,
@@ -65,7 +65,7 @@
 comment on column  sys_social.create_time       is '鍒涘缓鏃堕棿';
 comment on column  sys_social.update_by         is '鏇存柊鑰�';
 comment on column  sys_social.update_time       is '鏇存柊鏃堕棿';
-comment on column  sys_social.del_flag          is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_social.del_flag          is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 
 -- ----------------------------
 -- 绉熸埛琛�
@@ -108,7 +108,7 @@
 comment on column  sys_tenant.expire_time        is '杩囨湡鏃堕棿';
 comment on column  sys_tenant.account_count      is '鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級';
 comment on column  sys_tenant.status             is '绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column  sys_tenant.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_tenant.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column  sys_tenant.create_dept        is '鍒涘缓閮ㄩ棬';
 comment on column  sys_tenant.create_by          is '鍒涘缓鑰�';
 comment on column  sys_tenant.create_time        is '鍒涘缓鏃堕棿';
@@ -148,7 +148,7 @@
 comment on column  sys_tenant_package.menu_ids           is '鍏宠仈鑿滃崟id';
 comment on column  sys_tenant_package.remark             is '澶囨敞';
 comment on column  sys_tenant_package.status             is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column  sys_tenant_package.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_tenant_package.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column  sys_tenant_package.create_dept        is '鍒涘缓閮ㄩ棬';
 comment on column  sys_tenant_package.create_by          is '鍒涘缓鑰�';
 comment on column  sys_tenant_package.create_time        is '鍒涘缓鏃堕棿';
@@ -193,7 +193,7 @@
 comment on column sys_dept.phone        is '鑱旂郴鐢佃瘽';
 comment on column sys_dept.email        is '閭';
 comment on column sys_dept.status       is '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column sys_dept.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_dept.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column sys_dept.create_dept  is '鍒涘缓閮ㄩ棬';
 comment on column sys_dept.create_by    is '鍒涘缓鑰�';
 comment on column sys_dept.create_time  is '鍒涘缓鏃堕棿';
@@ -258,7 +258,7 @@
 comment on column sys_user.avatar       is '澶村儚璺緞';
 comment on column sys_user.password     is '瀵嗙爜';
 comment on column sys_user.status       is '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column sys_user.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_user.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column sys_user.login_ip     is '鏈�鍚庣櫥褰旾P';
 comment on column sys_user.login_date   is '鏈�鍚庣櫥褰曟椂闂�';
 comment on column sys_user.create_dept  is '鍒涘缓閮ㄩ棬';
@@ -356,7 +356,7 @@
 comment on column sys_role.menu_check_strictly   is '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
 comment on column sys_role.dept_check_strictly   is '閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
 comment on column sys_role.status                is '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column sys_role.del_flag              is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_role.del_flag              is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column sys_role.create_dept           is '鍒涘缓閮ㄩ棬';
 comment on column sys_role.create_by             is '鍒涘缓鑰�';
 comment on column sys_role.create_time           is '鍒涘缓鏃堕棿';
@@ -615,6 +615,8 @@
 insert into sys_role_menu values ('3', '106');
 insert into sys_role_menu values ('3', '107');
 insert into sys_role_menu values ('3', '108');
+insert into sys_role_menu values ('3', '118');
+insert into sys_role_menu values ('3', '123');
 insert into sys_role_menu values ('3', '500');
 insert into sys_role_menu values ('3', '501');
 insert into sys_role_menu values ('3', '1001');
@@ -662,6 +664,12 @@
 insert into sys_role_menu values ('3', '1043');
 insert into sys_role_menu values ('3', '1044');
 insert into sys_role_menu values ('3', '1045');
+insert into sys_role_menu values ('3', '1050');
+insert into sys_role_menu values ('3', '1061');
+insert into sys_role_menu values ('3', '1062');
+insert into sys_role_menu values ('3', '1063');
+insert into sys_role_menu values ('3', '1064');
+insert into sys_role_menu values ('3', '1065');
 insert into sys_role_menu values ('3', '1500');
 insert into sys_role_menu values ('3', '1501');
 insert into sys_role_menu values ('3', '1502');
@@ -674,6 +682,25 @@
 insert into sys_role_menu values ('3', '1509');
 insert into sys_role_menu values ('3', '1510');
 insert into sys_role_menu values ('3', '1511');
+insert into sys_role_menu values ('3', '1600');
+insert into sys_role_menu values ('3', '1601');
+insert into sys_role_menu values ('3', '1602');
+insert into sys_role_menu values ('3', '1603');
+insert into sys_role_menu values ('3', '1620');
+insert into sys_role_menu values ('3', '1621');
+insert into sys_role_menu values ('3', '1622');
+insert into sys_role_menu values ('3', '1623');
+insert into sys_role_menu values ('3', '11618');
+insert into sys_role_menu values ('3', '11619');
+insert into sys_role_menu values ('3', '11629');
+insert into sys_role_menu values ('3', '11632');
+insert into sys_role_menu values ('3', '11633');
+insert into sys_role_menu values ('3', '11638');
+insert into sys_role_menu values ('3', '11639');
+insert into sys_role_menu values ('3', '11640');
+insert into sys_role_menu values ('3', '11641');
+insert into sys_role_menu values ('3', '11642');
+insert into sys_role_menu values ('3', '11643');
 insert into sys_role_menu values ('4', '5');
 insert into sys_role_menu values ('4', '1500');
 insert into sys_role_menu values ('4', '1501');
@@ -738,10 +765,10 @@
   oper_url          varchar2(255)   default '',
   oper_ip           varchar2(128)   default '',
   oper_location     varchar2(255)   default '',
-  oper_param        varchar2(2100)  default '',
-  json_result       varchar2(2100)  default '',
+  oper_param        varchar2(4000)  default '',
+  json_result       varchar2(4000)  default '',
   status            number(1)       default 0,
-  error_msg         varchar2(2100)  default '',
+  error_msg         varchar2(4000)  default '',
   oper_time         date,
   cost_time         number(20)      default 0
 );
@@ -1245,7 +1272,7 @@
 comment on column sys_client.active_timeout         is 'token娲昏穬瓒呮椂鏃堕棿';
 comment on column sys_client.timeout                is 'token鍥哄畾瓒呮椂';
 comment on column sys_client.status                 is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column sys_client.del_flag               is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_client.del_flag               is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column sys_client.create_dept            is '鍒涘缓閮ㄩ棬';
 comment on column sys_client.create_by              is '鍒涘缓鑰�';
 comment on column sys_client.create_time            is '鍒涘缓鏃堕棿';
diff --git a/script/sql/oracle/oracle_ry_workflow.sql b/script/sql/oracle/oracle_ry_workflow.sql
new file mode 100644
index 0000000..b515b78
--- /dev/null
+++ b/script/sql/oracle/oracle_ry_workflow.sql
@@ -0,0 +1,414 @@
+create table FLOW_DEFINITION
+(
+    ID              NUMBER(20)            not null,
+    FLOW_CODE       VARCHAR2(40)          not null,
+    FLOW_NAME       VARCHAR2(100)         not null,
+    CATEGORY        VARCHAR2(100),
+    VERSION         VARCHAR2(20)          not null,
+    IS_PUBLISH      NUMBER(1)   default 0 not null,
+    FORM_CUSTOM     VARCHAR2(1) default 'N',
+    FORM_PATH       VARCHAR2(100),
+    ACTIVITY_STATUS NUMBER(1)   default 1,
+    LISTENER_TYPE   VARCHAR2(100),
+    LISTENER_PATH   VARCHAR2(500),
+    EXT             VARCHAR2(500),
+    CREATE_TIME     DATE,
+    UPDATE_TIME     DATE,
+    DEL_FLAG        VARCHAR2(1) default '0',
+    TENANT_ID       VARCHAR2(40)
+);
+
+alter table FLOW_DEFINITION add constraint PK_FLOW_DEFINITION primary key (ID);
+
+comment on table FLOW_DEFINITION is '娴佺▼瀹氫箟琛�';
+comment on column FLOW_DEFINITION.ID is '涓婚敭id';
+comment on column FLOW_DEFINITION.FLOW_CODE is '娴佺▼缂栫爜';
+comment on column FLOW_DEFINITION.FLOW_NAME is '娴佺▼鍚嶇О';
+comment on column FLOW_DEFINITION.CATEGORY is '娴佺▼绫诲埆';
+comment on column FLOW_DEFINITION.VERSION is '娴佺▼鐗堟湰';
+comment on column FLOW_DEFINITION.IS_PUBLISH is '鏄惁鍙戝竷 (0鏈彂甯� 1宸插彂甯� 9澶辨晥)';
+comment on column FLOW_DEFINITION.FORM_CUSTOM is '瀹℃壒琛ㄥ崟鏄惁鑷畾涔� (Y鏄� N鍚�)';
+comment on column FLOW_DEFINITION.FORM_PATH is '瀹℃壒琛ㄥ崟璺緞';
+comment on column FLOW_DEFINITION.ACTIVITY_STATUS is '娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級';
+comment on column FLOW_DEFINITION.LISTENER_TYPE is '鐩戝惉鍣ㄧ被鍨�';
+comment on column FLOW_DEFINITION.LISTENER_PATH is '鐩戝惉鍣ㄨ矾寰�';
+comment on column FLOW_DEFINITION.EXT is '鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤';
+comment on column FLOW_DEFINITION.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column FLOW_DEFINITION.UPDATE_TIME is '鏇存柊鏃堕棿';
+comment on column FLOW_DEFINITION.DEL_FLAG is '鍒犻櫎鏍囧織';
+comment on column FLOW_DEFINITION.TENANT_ID is '绉熸埛id';
+
+create table FLOW_NODE
+(
+    ID              NUMBER(20)    not null,
+    NODE_TYPE       NUMBER(1)     not null,
+    DEFINITION_ID   NUMBER(20)    not null,
+    NODE_CODE       VARCHAR2(100) not null,
+    NODE_NAME       VARCHAR2(100),
+    NODE_RATIO      NUMBER(6, 3),
+    COORDINATE      VARCHAR2(100),
+    SKIP_ANY_NODE   VARCHAR2(100) default 'N',
+    ANY_NODE_SKIP   VARCHAR2(100),
+    LISTENER_TYPE   VARCHAR2(100),
+    LISTENER_PATH   VARCHAR2(500),
+    HANDLER_TYPE    VARCHAR2(100),
+    HANDLER_PATH    VARCHAR2(400),
+    FORM_CUSTOM     VARCHAR2(1)   default 'N',
+    FORM_PATH       VARCHAR2(100),
+    VERSION         VARCHAR2(20),
+    CREATE_TIME     DATE,
+    UPDATE_TIME     DATE,
+    DEL_FLAG        VARCHAR2(1)   default '0',
+    TENANT_ID       VARCHAR2(40),
+    PERMISSION_FLAG VARCHAR2(200)
+);
+
+alter table FLOW_NODE add constraint PK_FLOW_NODE primary key (ID);
+
+comment on table FLOW_NODE is '娴佺▼鑺傜偣琛�';
+comment on column FLOW_NODE.ID is '涓婚敭id';
+comment on column FLOW_NODE.NODE_TYPE is '鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�';
+comment on column FLOW_NODE.DEFINITION_ID is '瀵瑰簲flow_definition琛ㄧ殑id';
+comment on column FLOW_NODE.NODE_CODE is '娴佺▼鑺傜偣缂栫爜';
+comment on column FLOW_NODE.NODE_NAME is '娴佺▼鑺傜偣鍚嶇О';
+comment on column FLOW_NODE.NODE_RATIO is '娴佺▼绛剧讲姣斾緥鍊�';
+comment on column FLOW_NODE.COORDINATE is '鍧愭爣';
+comment on column FLOW_NODE.SKIP_ANY_NODE is '鏄惁鍙互閫�鍥炰换鎰忚妭鐐癸紙Y鏄� N鍚︼級鍗冲皢鍒犻櫎';
+comment on column FLOW_NODE.ANY_NODE_SKIP is '浠绘剰缁撶偣璺宠浆';
+comment on column FLOW_NODE.LISTENER_TYPE is '鐩戝惉鍣ㄧ被鍨�';
+comment on column FLOW_NODE.LISTENER_PATH is '鐩戝惉鍣ㄨ矾寰�';
+comment on column FLOW_NODE.HANDLER_TYPE is '澶勭悊鍣ㄧ被鍨�';
+comment on column FLOW_NODE.HANDLER_PATH is '澶勭悊鍣ㄨ矾寰�';
+comment on column FLOW_NODE.FORM_CUSTOM is '瀹℃壒琛ㄥ崟鏄惁鑷畾涔� (Y鏄� N鍚�)';
+comment on column FLOW_NODE.FORM_PATH is '瀹℃壒琛ㄥ崟璺緞';
+comment on column FLOW_NODE.VERSION is '鐗堟湰';
+comment on column FLOW_NODE.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column FLOW_NODE.UPDATE_TIME is '鏇存柊鏃堕棿';
+comment on column FLOW_NODE.DEL_FLAG is '鍒犻櫎鏍囧織';
+comment on column FLOW_NODE.TENANT_ID is '绉熸埛id';
+comment on column FLOW_NODE.PERMISSION_FLAG is '鏉冮檺鏍囪瘑锛堟潈闄愮被鍨�:鏉冮檺鏍囪瘑锛屽彲浠ュ涓紝鐢ㄩ�楀彿闅斿紑)';
+
+create table FLOW_SKIP
+(
+    ID             NUMBER(20)    not null,
+    DEFINITION_ID  NUMBER(20)    not null,
+    NOW_NODE_CODE  VARCHAR2(100) not null,
+    NOW_NODE_TYPE  NUMBER(1),
+    NEXT_NODE_CODE VARCHAR2(100) not null,
+    NEXT_NODE_TYPE NUMBER(1),
+    SKIP_NAME      VARCHAR2(100),
+    SKIP_TYPE      VARCHAR2(40),
+    SKIP_CONDITION VARCHAR2(200),
+    COORDINATE     VARCHAR2(100),
+    CREATE_TIME    DATE,
+    UPDATE_TIME    DATE,
+    DEL_FLAG       VARCHAR2(1) default '0',
+    TENANT_ID      VARCHAR2(40)
+);
+
+alter table FLOW_SKIP add constraint PK_FLOW_SKIP primary key (ID);
+
+comment on table FLOW_SKIP is '鑺傜偣璺宠浆鍏宠仈琛�';
+comment on column FLOW_SKIP.ID is '涓婚敭id';
+comment on column FLOW_SKIP.DEFINITION_ID is '娴佺▼瀹氫箟id';
+comment on column FLOW_SKIP.NOW_NODE_CODE is '褰撳墠娴佺▼鑺傜偣绫诲瀷 (0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧)';
+comment on column FLOW_SKIP.NOW_NODE_TYPE is '涓嬩竴涓祦绋嬭妭鐐圭被鍨� (0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧)';
+comment on column FLOW_SKIP.NEXT_NODE_CODE is '涓嬩竴涓祦绋嬭妭鐐圭紪鐮�';
+comment on column FLOW_SKIP.NEXT_NODE_TYPE is '涓嬩竴涓祦绋嬭妭鐐圭被鍨� (0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧)';
+comment on column FLOW_SKIP.SKIP_NAME is '璺宠浆鍚嶇О';
+comment on column FLOW_SKIP.SKIP_TYPE is '璺宠浆绫诲瀷 (PASS瀹℃壒閫氳繃 REJECT閫�鍥�)';
+comment on column FLOW_SKIP.SKIP_CONDITION is '璺宠浆鏉′欢';
+comment on column FLOW_SKIP.COORDINATE is '鍧愭爣';
+comment on column FLOW_SKIP.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column FLOW_SKIP.UPDATE_TIME is '鏇存柊鏃堕棿';
+comment on column FLOW_SKIP.DEL_FLAG is '鍒犻櫎鏍囧織';
+comment on column FLOW_SKIP.TENANT_ID is '绉熸埛id';
+
+create table FLOW_INSTANCE
+(
+    ID              NUMBER       not null,
+    DEFINITION_ID   NUMBER       not null,
+    BUSINESS_ID     VARCHAR2(40) not null,
+    NODE_TYPE       NUMBER(1),
+    NODE_CODE       VARCHAR2(100),
+    NODE_NAME       VARCHAR2(100),
+    VARIABLE        CLOB,
+    FLOW_STATUS     VARCHAR2(20),
+    ACTIVITY_STATUS NUMBER(1)    default 1,
+    DEF_JSON        CLOB,
+    CREATE_BY       VARCHAR2(64) default '',
+    CREATE_TIME     DATE,
+    UPDATE_TIME     DATE,
+    EXT             VARCHAR2(500),
+    DEL_FLAG        VARCHAR2(1)  default '0',
+    TENANT_ID       VARCHAR2(40)
+);
+
+alter table FLOW_INSTANCE add constraint PK_FLOW_INSTANCE primary key (ID);
+
+comment on table FLOW_INSTANCE is '娴佺▼瀹炰緥琛�';
+comment on column FLOW_INSTANCE.ID is '涓婚敭id';
+comment on column FLOW_INSTANCE.DEFINITION_ID is '瀵瑰簲flow_definition琛ㄧ殑id';
+comment on column FLOW_INSTANCE.BUSINESS_ID is '涓氬姟id';
+comment on column FLOW_INSTANCE.NODE_TYPE is '寮�濮嬭妭鐐圭被鍨� (0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧)';
+comment on column FLOW_INSTANCE.NODE_CODE is '寮�濮嬭妭鐐圭紪鐮�';
+comment on column FLOW_INSTANCE.NODE_NAME is '寮�濮嬭妭鐐瑰悕绉�';
+comment on column FLOW_INSTANCE.VARIABLE is '浠诲姟鍙橀噺';
+comment on column FLOW_INSTANCE.FLOW_STATUS is '娴佺▼鐘舵�侊紙0寰呮彁浜� 1瀹℃壒涓� 2 瀹℃壒閫氳繃 3鑷姩閫氳繃 4缁堟 5浣滃簾 6鎾ら攢 7鍙栧洖  8宸插畬鎴� 9宸查��鍥� 10澶辨晥锛�';
+comment on column FLOW_INSTANCE.ACTIVITY_STATUS is '娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級';
+comment on column FLOW_INSTANCE.DEF_JSON is '娴佺▼瀹氫箟json';
+comment on column FLOW_INSTANCE.CREATE_BY is '鍒涘缓鑰�';
+comment on column FLOW_INSTANCE.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column FLOW_INSTANCE.UPDATE_TIME is '鏇存柊鏃堕棿';
+comment on column FLOW_INSTANCE.EXT is '鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤';
+comment on column FLOW_INSTANCE.DEL_FLAG is '鍒犻櫎鏍囧織';
+comment on column FLOW_INSTANCE.TENANT_ID is '绉熸埛id';
+
+create table FLOW_TASK
+(
+    ID            NUMBER(20) not null,
+    DEFINITION_ID NUMBER(20) not null,
+    INSTANCE_ID   NUMBER(20) not null,
+    NODE_CODE     VARCHAR2(100),
+    NODE_NAME     VARCHAR2(100),
+    NODE_TYPE     NUMBER(1),
+    FORM_CUSTOM   VARCHAR2(1) default 'N',
+    FORM_PATH     VARCHAR2(100),
+    CREATE_TIME   DATE,
+    UPDATE_TIME   DATE,
+    DEL_FLAG      VARCHAR2(1) default '0',
+    TENANT_ID     VARCHAR2(40)
+);
+
+alter table FLOW_TASK add constraint PK_FLOW_TASK primary key (ID);
+
+comment on table FLOW_TASK is '寰呭姙浠诲姟琛�';
+comment on column FLOW_TASK.ID is '涓婚敭id';
+comment on column FLOW_TASK.DEFINITION_ID is '瀵瑰簲flow_definition琛ㄧ殑id';
+comment on column FLOW_TASK.INSTANCE_ID is '瀵瑰簲flow_instance琛ㄧ殑id';
+comment on column FLOW_TASK.NODE_CODE is '鑺傜偣缂栫爜';
+comment on column FLOW_TASK.NODE_NAME is '鑺傜偣鍚嶇О';
+comment on column FLOW_TASK.NODE_TYPE is '鑺傜偣绫诲瀷 (0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧)';
+comment on column FLOW_TASK.FORM_CUSTOM is '瀹℃壒琛ㄥ崟鏄惁鑷畾涔� (Y鏄� N鍚�)';
+comment on column FLOW_TASK.FORM_PATH is '瀹℃壒琛ㄥ崟璺緞';
+comment on column FLOW_TASK.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column FLOW_TASK.UPDATE_TIME is '鏇存柊鏃堕棿';
+comment on column FLOW_TASK.DEL_FLAG is '鍒犻櫎鏍囧織';
+comment on column FLOW_TASK.TENANT_ID is '绉熸埛id';
+
+create table FLOW_HIS_TASK
+(
+    ID               NUMBER(20) not null,
+    DEFINITION_ID    NUMBER(20) not null,
+    INSTANCE_ID      NUMBER(20) not null,
+    TASK_ID          NUMBER(20) not null,
+    NODE_CODE        VARCHAR2(100),
+    NODE_NAME        VARCHAR2(100),
+    NODE_TYPE        NUMBER(1),
+    TARGET_NODE_CODE VARCHAR2(200),
+    TARGET_NODE_NAME VARCHAR2(200),
+    APPROVER         VARCHAR2(40),
+    COOPERATE_TYPE   NUMBER(1)   default 0,
+    COLLABORATOR     VARCHAR2(40),
+    SKIP_TYPE        VARCHAR2(10),
+    FLOW_STATUS      VARCHAR2(20),
+    FORM_CUSTOM      VARCHAR2(1) default 'N',
+    FORM_PATH        VARCHAR2(100),
+    MESSAGE          VARCHAR2(500),
+    VARIABLE         CLOB,
+    EXT              VARCHAR2(500),
+    CREATE_TIME      DATE,
+    UPDATE_TIME      DATE,
+    DEL_FLAG         VARCHAR2(1) default '0',
+    TENANT_ID        VARCHAR2(40)
+
+);
+
+alter table FLOW_HIS_TASK add constraint PK_FLOW_HIS_TASK primary key (ID);
+
+comment on table FLOW_HIS_TASK is '鍘嗗彶浠诲姟璁板綍琛�';
+comment on column FLOW_HIS_TASK.ID is '涓婚敭id';
+comment on column FLOW_HIS_TASK.DEFINITION_ID is '瀵瑰簲flow_definition琛ㄧ殑id';
+comment on column FLOW_HIS_TASK.INSTANCE_ID is '瀵瑰簲flow_instance琛ㄧ殑id';
+comment on column FLOW_HIS_TASK.TASK_ID is '瀵瑰簲flow_task琛ㄧ殑id';
+comment on column FLOW_HIS_TASK.NODE_CODE is '寮�濮嬭妭鐐圭紪鐮�';
+comment on column FLOW_HIS_TASK.NODE_NAME is '寮�濮嬭妭鐐瑰悕绉�';
+comment on column FLOW_HIS_TASK.NODE_TYPE is '寮�濮嬭妭鐐圭被鍨� (0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧)';
+comment on column FLOW_HIS_TASK.TARGET_NODE_CODE is '鐩爣鑺傜偣缂栫爜';
+comment on column FLOW_HIS_TASK.TARGET_NODE_NAME is '鐩爣鑺傜偣鍚嶇О';
+comment on column FLOW_HIS_TASK.SKIP_TYPE is '娴佽浆绫诲瀷锛圥ASS閫氳繃 REJECT閫�鍥� NONE鏃犲姩浣滐級';
+comment on column FLOW_HIS_TASK.FLOW_STATUS is '娴佺▼鐘舵�侊紙1瀹℃壒涓� 2 瀹℃壒閫氳繃 9宸查��鍥� 10澶辨晥锛�';
+comment on column FLOW_HIS_TASK.FORM_CUSTOM is '瀹℃壒琛ㄥ崟鏄惁鑷畾涔� (Y鏄� N鍚�)';
+comment on column FLOW_HIS_TASK.FORM_PATH is '瀹℃壒琛ㄥ崟璺緞';
+comment on column FLOW_HIS_TASK.MESSAGE is '瀹℃壒鎰忚';
+comment on column FLOW_HIS_TASK.VARIABLE is '浠诲姟鍙橀噺';
+comment on column FLOW_HIS_TASK.EXT is '鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤';
+comment on column FLOW_HIS_TASK.CREATE_TIME is '浠诲姟寮�濮嬫椂闂�';
+comment on column FLOW_HIS_TASK.UPDATE_TIME is '瀹℃壒瀹屾垚鏃堕棿';
+comment on column FLOW_HIS_TASK.DEL_FLAG is '鍒犻櫎鏍囧織';
+comment on column FLOW_HIS_TASK.TENANT_ID is '绉熸埛id';
+comment on column FLOW_HIS_TASK.APPROVER is '瀹℃壒鑰�';
+comment on column FLOW_HIS_TASK.COOPERATE_TYPE is '鍗忎綔鏂瑰紡(1瀹℃壒 2杞姙 3濮旀淳 4浼氱 5绁ㄧ 6鍔犵 7鍑忕)';
+comment on column FLOW_HIS_TASK.COLLABORATOR is '鍗忎綔浜�';
+
+create table FLOW_USER
+(
+    ID           NUMBER(20)  not null,
+    TYPE         VARCHAR2(1) not null,
+    PROCESSED_BY VARCHAR2(80),
+    ASSOCIATED   NUMBER(20)  not null,
+    CREATE_TIME  DATE,
+    CREATE_BY    VARCHAR2(80),
+    UPDATE_TIME  DATE,
+    DEL_FLAG     VARCHAR2(1) default '0',
+    TENANT_ID    VARCHAR2(40)
+);
+
+alter table FLOW_USER add constraint PK_FLOW_USER primary key (ID);
+
+comment on table FLOW_USER is '寰呭姙浠诲姟琛�';
+comment on column FLOW_USER.ID is '涓婚敭id';
+comment on column FLOW_USER.TYPE is '浜哄憳绫诲瀷锛�1寰呭姙浠诲姟鐨勫鎵逛汉鏉冮檺 2寰呭姙浠诲姟鐨勮浆鍔炰汉鏉冮檺 3寰呭姙浠诲姟鐨勫鎵樹汉鏉冮檺锛�';
+comment on column FLOW_USER.PROCESSED_BY is '鏉冮檺浜�)';
+comment on column FLOW_USER.ASSOCIATED is '浠诲姟琛╥d';
+comment on column FLOW_USER.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column FLOW_USER.CREATE_BY is '鑺傜偣鍚嶇О';
+comment on column FLOW_USER.UPDATE_TIME is '鏇存柊鏃堕棿';
+comment on column FLOW_USER.DEL_FLAG is '鍒犻櫎鏍囧織';
+comment on column FLOW_USER.TENANT_ID is '绉熸埛id';
+
+create index USER_PROCESSED_TYPE on FLOW_USER (PROCESSED_BY, TYPE);
+
+-- ----------------------------
+-- 娴佺▼鍒嗙被琛�
+-- ----------------------------
+CREATE TABLE flow_category
+(
+    category_id NUMBER (20) NOT NULL,
+    tenant_id VARCHAR2 (20) DEFAULT '000000',
+    parent_id NUMBER (20) DEFAULT 0,
+    ancestors VARCHAR2 (500) DEFAULT '',
+    category_name VARCHAR2 (30) NOT NULL,
+    order_num NUMBER (4) DEFAULT 0,
+    del_flag    CHAR(1) DEFAULT '0',
+    create_dept NUMBER (20),
+    create_by NUMBER (20),
+    create_time DATE,
+    update_by NUMBER (20),
+    update_time DATE
+);
+
+alter table flow_category add constraint pk_flow_category primary key (category_id);
+
+COMMENT ON TABLE flow_category IS '娴佺▼鍒嗙被';
+COMMENT ON COLUMN flow_category.category_id IS '娴佺▼鍒嗙被ID';
+COMMENT ON COLUMN flow_category.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON COLUMN flow_category.parent_id IS '鐖舵祦绋嬪垎绫籭d';
+COMMENT ON COLUMN flow_category.ancestors IS '绁栫骇鍒楄〃';
+COMMENT ON COLUMN flow_category.category_name IS '娴佺▼鍒嗙被鍚嶇О';
+COMMENT ON COLUMN flow_category.order_num IS '鏄剧ず椤哄簭';
+COMMENT ON COLUMN flow_category.del_flag IS '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
+COMMENT ON COLUMN flow_category.create_dept IS '鍒涘缓閮ㄩ棬';
+COMMENT ON COLUMN flow_category.create_by IS '鍒涘缓鑰�';
+COMMENT ON COLUMN flow_category.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN flow_category.update_by IS '鏇存柊鑰�';
+COMMENT ON COLUMN flow_category.update_time IS '鏇存柊鏃堕棿';
+
+INSERT INTO flow_category VALUES (100, '000000', 0, '0', 'OA瀹℃壒', 0, '0', 103, 1, SYSDATE, NULL, NULL);
+INSERT INTO flow_category VALUES (101, '000000', 100, '0,100', '鍋囧嫟绠$悊', 0, '0', 103, 1, SYSDATE, NULL, NULL);
+INSERT INTO flow_category VALUES (102, '000000', 100, '0,100', '浜轰簨绠$悊', 1, '0', 103, 1, SYSDATE, NULL, NULL);
+INSERT INTO flow_category VALUES (103, '000000', 101, '0,100,101', '璇峰亣', 0, '0', 103, 1, SYSDATE, NULL, NULL);
+INSERT INTO flow_category VALUES (104, '000000', 101, '0,100,101', '鍑哄樊', 1, '0', 103, 1, SYSDATE, NULL, NULL);
+INSERT INTO flow_category VALUES (105, '000000', 101, '0,100,101', '鍔犵彮', 2, '0', 103, 1, SYSDATE, NULL, NULL);
+INSERT INTO flow_category VALUES (106, '000000', 101, '0,100,101', '鎹㈢彮', 3, '0', 103, 1, SYSDATE, NULL, NULL);
+INSERT INTO flow_category VALUES (107, '000000', 101, '0,100,101', '澶栧嚭', 4, '0', 103, 1, SYSDATE, NULL, NULL);
+INSERT INTO flow_category VALUES (108, '000000', 102, '0,100,102', '杞', 1, '0', 103, 1, SYSDATE, NULL, NULL);
+INSERT INTO flow_category VALUES (109, '000000', 102, '0,100,102', '绂昏亴', 2, '0', 103, 1, SYSDATE, NULL, NULL);
+
+
+-- ----------------------------
+-- 璇峰亣鍗曚俊鎭�
+-- ----------------------------
+CREATE TABLE test_leave
+(
+    id NUMBER (20) NOT NULL,
+    tenant_id VARCHAR2 (20) DEFAULT '000000',
+    leave_type VARCHAR2 (255) NOT NULL,
+    start_date  DATE NOT NULL,
+    end_date    DATE NOT NULL,
+    leave_days NUMBER (10) NOT NULL,
+    remark VARCHAR2 (255),
+    status VARCHAR2 (255),
+    create_dept NUMBER (20),
+    create_by NUMBER (20),
+    create_time DATE,
+    update_by NUMBER (20),
+    update_time DATE
+);
+
+alter table test_leave add constraint pk_test_leave primary key (id);
+
+COMMENT ON TABLE test_leave IS '璇峰亣鐢宠琛�';
+COMMENT ON COLUMN test_leave.id IS 'ID';
+COMMENT ON COLUMN test_leave.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON COLUMN test_leave.leave_type IS '璇峰亣绫诲瀷';
+COMMENT ON COLUMN test_leave.start_date IS '寮�濮嬫椂闂�';
+COMMENT ON COLUMN test_leave.end_date IS '缁撴潫鏃堕棿';
+COMMENT ON COLUMN test_leave.leave_days IS '璇峰亣澶╂暟';
+COMMENT ON COLUMN test_leave.remark IS '璇峰亣鍘熷洜';
+COMMENT ON COLUMN test_leave.status IS '鐘舵��';
+COMMENT ON COLUMN test_leave.create_dept IS '鍒涘缓閮ㄩ棬';
+COMMENT ON COLUMN test_leave.create_by IS '鍒涘缓鑰�';
+COMMENT ON COLUMN test_leave.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN test_leave.update_by IS '鏇存柊鑰�';
+COMMENT ON COLUMN test_leave.update_time IS '鏇存柊鏃堕棿';
+
+INSERT INTO sys_menu VALUES ('11616', '宸ヤ綔娴�', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11618', '鎴戠殑浠诲姟', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11622', '娴佺▼鍒嗙被', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, SYSDATE, NULL, NULL, '');
+
+INSERT INTO sys_menu VALUES ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:query', '#', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:add', '#', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:remove', '#', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:export', '#', 103, 1, SYSDATE, NULL, NULL, '');
+
+INSERT INTO sys_menu VALUES ('11638', '璇峰亣鐢宠', '5', '1', 'leave', 'workflow/leave/index', '', '1', '0', 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, SYSDATE, NULL, NULL, '璇峰亣鐢宠鑿滃崟');
+INSERT INTO sys_menu VALUES ('11639', '璇峰亣鐢宠鏌ヨ', '11638', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11640', '璇峰亣鐢宠鏂板', '11638', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11641', '璇峰亣鐢宠淇敼', '11638', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11642', '璇峰亣鐢宠鍒犻櫎', '11638', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, SYSDATE, NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11643', '璇峰亣鐢宠瀵煎嚭', '11638', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, SYSDATE, NULL, NULL, '');
+
+INSERT INTO sys_dict_type VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, SYSDATE, NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
+INSERT INTO sys_dict_type VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, SYSDATE, NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
+INSERT INTO sys_dict_type VALUES (15, '000000', '浠诲姟鐘舵��', 'wf_task_status', 103, 1, SYSDATE, NULL, NULL, '浠诲姟鐘舵��');
+INSERT INTO sys_dict_data VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '宸叉挙閿�');
+INSERT INTO sys_dict_data VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, SYSDATE, NULL, NULL, '鑽夌');
+INSERT INTO sys_dict_data VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '寰呭鏍�');
+INSERT INTO sys_dict_data VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, SYSDATE, NULL, NULL, '宸插畬鎴�');
+INSERT INTO sys_dict_data VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '宸蹭綔搴�');
+INSERT INTO sys_dict_data VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '宸查��鍥�');
+INSERT INTO sys_dict_data VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '宸茬粓姝�');
+INSERT INTO sys_dict_data VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, SYSDATE, NULL, NULL, '鑷畾涔夎〃鍗�');
+INSERT INTO sys_dict_data VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '鍔ㄦ�佽〃鍗�');
+INSERT INTO sys_dict_data VALUES (48, '000000', 1, '鎾ら攢', 'cancel', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '鎾ら攢');
+INSERT INTO sys_dict_data VALUES (49, '000000', 2, '閫氳繃', 'pass', 'wf_task_status', '', 'success', 'N', 103, 1, SYSDATE, NULL, NULL, '閫氳繃');
+INSERT INTO sys_dict_data VALUES (50, '000000', 3, '寰呭鏍�', 'waiting', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '寰呭鏍�');
+INSERT INTO sys_dict_data VALUES (51, '000000', 4, '浣滃簾', 'invalid', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '浣滃簾');
+INSERT INTO sys_dict_data VALUES (52, '000000', 5, '閫�鍥�', 'back', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '閫�鍥�');
+INSERT INTO sys_dict_data VALUES (53, '000000', 6, '缁堟', 'termination', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '缁堟');
+INSERT INTO sys_dict_data VALUES (54, '000000', 7, '杞姙', 'transfer', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '杞姙');
+INSERT INTO sys_dict_data VALUES (55, '000000', 8, '濮旀墭', 'depute', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '濮旀墭');
+INSERT INTO sys_dict_data VALUES (56, '000000', 9, '鎶勯��', 'copy', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '鎶勯��');
+INSERT INTO sys_dict_data VALUES (57, '000000', 10, '鍔犵', 'sign', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '鍔犵');
+INSERT INTO sys_dict_data VALUES (58, '000000', 11, '鍑忕', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '鍑忕');
+INSERT INTO sys_dict_data VALUES (59, '000000', 11, '瓒呮椂', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '瓒呮椂');
diff --git a/script/sql/postgres/flowable.sql b/script/sql/postgres/flowable.sql
deleted file mode 100644
index 8a6078d..0000000
--- a/script/sql/postgres/flowable.sql
+++ /dev/null
@@ -1,275 +0,0 @@
-insert into sys_menu values('11616', '宸ヤ綔娴�'  , '0',    '6', 'workflow',          '',                                 '', '1', '0', 'M', '0', '0', '',                       'workflow', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11617', '妯″瀷绠$悊', '11616', '2', 'model',             'workflow/model/index',             '', '1', '1', 'C', '0', '0', 'workflow:model:list',    'model', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11618', '鎴戠殑浠诲姟', '0', '7', 'task',              '',                                 '', '1', '0', 'M', '0', '0', '',                       'my-task', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting',       'workflow/task/taskWaiting',              '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish',       'workflow/task/taskFinish',              '', '1', '1', 'C', '0', '0', '',                       'finish', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList',       'workflow/task/taskCopyList',              '', '1', '1', 'C', '0', '0', '',                       'my-copy', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '',                       'process-definition', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance',   'workflow/processInstance/index',   '', '1', '1', 'C', '0', '0', '',                       'tree-table', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11622', '娴佺▼鍒嗙被', '11616', '1', 'category',          'workflow/category/index',          '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument',        'workflow/task/myDocument',         '', '1', '1', 'C', '0', '0', '',                       'guide', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor',           '',                                 '', '1', '0', 'M', '0', '0', '',                       'monitor', 103, 1, now(), NULL, NULL, '');
-insert into sys_menu values('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting',    'workflow/task/allTaskWaiting',     '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, now(), NULL, NULL, '');
-
-
--- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
-insert into sys_menu values ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, now(), null, null, '');
-insert into sys_menu values ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add',   '#', 103, 1, now(), null, null, '');
-insert into sys_menu values ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit',  '#', 103, 1, now(), null, null, '');
-insert into sys_menu values ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, now(), null, null, '');
-insert into sys_menu values ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, now(), null, null, '');
--- 璇峰亣鍗曚俊鎭�
-create table test_leave
-(
-    id          bigint not null
-        constraint test_leave_pk
-            primary key,
-    leave_type  varchar(255),
-    start_date  timestamp,
-    end_date    timestamp,
-    leave_days  bigint,
-    remark      varchar(255),
-    status      varchar(255),
-    create_dept bigint,
-    create_by   bigint,
-    create_time timestamp,
-    update_by   bigint,
-    update_time timestamp,
-    tenant_id   varchar(20)
-);
-
-comment on table test_leave is '璇峰亣鐢宠琛�';
-comment on column test_leave.id is '涓婚敭';
-comment on column test_leave.leave_type is '璇峰亣绫诲瀷';
-comment on column test_leave.start_date is '寮�濮嬫椂闂�';
-comment on column test_leave.end_date is '缁撴潫鏃堕棿';
-comment on column test_leave.remark is '璇峰亣鍘熷洜';
-comment on column test_leave.status is '鐘舵��';
-comment on column test_leave.create_dept is '鍒涘缓閮ㄩ棬';
-comment on column test_leave.create_by is '鍒涘缓鑰�';
-comment on column test_leave.create_time is '鍒涘缓鏃堕棿';
-comment on column test_leave.update_by is '鏇存柊鑰�';
-comment on column test_leave.update_time is '鏇存柊鏃堕棿';
-comment on column test_leave.tenant_id is '绉熸埛缂栫爜';
-
-alter table test_leave
-    owner to postgres;
-
--- 娴佺▼鍒嗙被淇℃伅琛�
-create table wf_category
-(
-    id            bigint not null
-        constraint wf_category_pk
-            primary key,
-    category_name varchar(255),
-    category_code varchar(255),
-    parent_id     bigint,
-    sort_num      bigint,
-    tenant_id     varchar(20),
-    create_dept   bigint,
-    create_by     bigint,
-    create_time   timestamp,
-    update_by     bigint,
-    update_time   timestamp
-);
-
-comment on table wf_category is '娴佺▼鍒嗙被';
-comment on column wf_category.id is '涓婚敭';
-comment on column wf_category.category_name is '鍒嗙被鍚嶇О';
-comment on column wf_category.category_code is '鍒嗙被缂栫爜';
-comment on column wf_category.parent_id is '鐖剁骇id';
-comment on column wf_category.sort_num is '鎺掑簭';
-comment on column wf_category.tenant_id is '绉熸埛id';
-comment on column wf_category.create_dept is '鍒涘缓閮ㄩ棬';
-comment on column wf_category.create_by is '鍒涘缓鑰�';
-comment on column wf_category.create_time is '鍒涘缓鏃堕棿';
-comment on column wf_category.update_by is '淇敼鑰�';
-comment on column wf_category.update_time is '淇敼鏃堕棿';
-
-alter table wf_category
-    owner to postgres;
-
-create unique index uni_category_code
-    on wf_category (category_code);
-
-INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, now(), 1, now());
-
-create table wf_task_back_node
-(
-    id            bigint not null
-        constraint pk_wf_task_back_node
-        primary key,
-    node_id       varchar(255) not null,
-    node_name     varchar(255) not null,
-    order_no      bigint not null,
-    instance_id   varchar(255) not null,
-    task_type     varchar(255) not null,
-    assignee      varchar(2000) not null,
-    tenant_id     varchar(20),
-    create_dept   bigint,
-    create_by     bigint,
-    create_time   timestamp,
-    update_by     bigint,
-    update_time   timestamp
-);
-
-comment on table wf_task_back_node is '鑺傜偣瀹℃壒璁板綍';
-comment on column wf_task_back_node.id is '涓婚敭';
-comment on column wf_task_back_node.node_id is '鑺傜偣id';
-comment on column wf_task_back_node.node_name is '鑺傜偣鍚嶇О';
-comment on column wf_task_back_node.order_no is '鎺掑簭';
-comment on column wf_task_back_node.instance_id is '娴佺▼瀹炰緥id';
-comment on column wf_task_back_node.task_type is '鑺傜偣绫诲瀷';
-comment on column wf_task_back_node.assignee is '瀹℃壒浜�';
-comment on column wf_task_back_node.tenant_id is '绉熸埛id';
-comment on column wf_task_back_node.create_dept is '鍒涘缓閮ㄩ棬';
-comment on column wf_task_back_node.create_by is '鍒涘缓鑰�';
-comment on column wf_task_back_node.create_time is '鍒涘缓鏃堕棿';
-comment on column wf_task_back_node.update_by is '淇敼鑰�';
-comment on column wf_task_back_node.update_time is '淇敼鏃堕棿';
-
-alter table wf_task_back_node
-    owner to postgres;
-
-create table wf_definition_config
-(
-    id            bigint not null
-        constraint pk_wf_definition_config
-        primary key,
-    table_name    varchar(255) not null,
-    definition_id varchar(255) not null,
-    process_key   varchar(255) not null,
-    version       bigint       not null,
-    tenant_id     varchar(20),
-    remark        varchar(500),
-    create_dept   bigint,
-    create_by     bigint,
-    create_time   timestamp,
-    update_by     bigint,
-    update_time   timestamp
-);
-
-comment on table wf_definition_config is '娴佺▼瀹氫箟閰嶇疆';
-comment on column wf_definition_config.id is '涓婚敭';
-comment on column wf_definition_config.table_name is '琛ㄥ悕';
-comment on column wf_definition_config.definition_id is '娴佺▼瀹氫箟ID';
-comment on column wf_definition_config.process_key is '娴佺▼KEY';
-comment on column wf_definition_config.version is '娴佺▼鐗堟湰';
-comment on column wf_definition_config.tenant_id is '绉熸埛id';
-comment on column wf_definition_config.remark is '澶囨敞';
-comment on column wf_definition_config.create_dept is '鍒涘缓閮ㄩ棬';
-comment on column wf_definition_config.create_by is '鍒涘缓鑰�';
-comment on column wf_definition_config.create_time is '鍒涘缓鏃堕棿';
-comment on column wf_definition_config.update_by is '淇敼鑰�';
-comment on column wf_definition_config.update_time is '淇敼鏃堕棿';
-
-alter table wf_definition_config
-    owner to postgres;
-create unique index uni_definition_id
-    on wf_definition_config (definition_id);
-
-create table wf_form_manage
-(
-    id            bigint not null
-        constraint pk_wf_form_manage
-        primary key,
-    form_name     varchar(255) not null,
-    form_type     varchar(255) not null,
-    router        varchar(255) not null,
-    remark        varchar(500),
-    tenant_id     varchar(20),
-    create_dept   bigint,
-    create_by     bigint,
-    create_time   timestamp,
-    update_by     bigint,
-    update_time   timestamp
-);
-
-comment on table wf_form_manage is '琛ㄥ崟绠$悊';
-comment on column wf_form_manage.id is '涓婚敭';
-comment on column wf_form_manage.form_name is '琛ㄥ崟鍚嶇О';
-comment on column wf_form_manage.form_type is '琛ㄥ崟绫诲瀷';
-comment on column wf_form_manage.router is '璺敱鍦板潃/琛ㄥ崟ID';
-comment on column wf_form_manage.remark is '澶囨敞';
-comment on column wf_form_manage.tenant_id is '绉熸埛id';
-comment on column wf_form_manage.create_dept is '鍒涘缓閮ㄩ棬';
-comment on column wf_form_manage.create_by is '鍒涘缓鑰�';
-comment on column wf_form_manage.create_time is '鍒涘缓鏃堕棿';
-comment on column wf_form_manage.update_by is '淇敼鑰�';
-comment on column wf_form_manage.update_time is '淇敼鏃堕棿';
-
-insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '璇峰亣鐢宠', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, now(), 1, now());
-
-create table wf_node_config
-(
-    id               bigint not null
-        constraint pk_wf_node_config
-            primary key,
-    form_id          bigint,
-    form_type        varchar(255),
-    node_name        varchar(255) not null,
-    node_id          varchar(255) not null,
-    definition_id    varchar(255) not null,
-    apply_user_task  char(1) default '0',
-    tenant_id        varchar(20),
-    create_dept      bigint,
-    create_by        bigint,
-    create_time      timestamp,
-    update_by        bigint,
-    update_time      timestamp
-);
-
-comment on table wf_node_config is '鑺傜偣閰嶇疆';
-comment on column wf_node_config.id is '涓婚敭';
-comment on column wf_node_config.form_id is '琛ㄥ崟id';
-comment on column wf_node_config.form_type is '琛ㄥ崟绫诲瀷';
-comment on column wf_node_config.node_id is '鑺傜偣id';
-comment on column wf_node_config.node_name is '鑺傜偣鍚嶇О';
-comment on column wf_node_config.definition_id is '娴佺▼瀹氫箟id';
-comment on column wf_node_config.apply_user_task is '鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級';
-comment on column wf_node_config.tenant_id is '绉熸埛id';
-comment on column wf_node_config.create_dept is '鍒涘缓閮ㄩ棬';
-comment on column wf_node_config.create_by is '鍒涘缓鑰�';
-comment on column wf_node_config.create_time is '鍒涘缓鏃堕棿';
-comment on column wf_node_config.update_by is '淇敼鑰�';
-comment on column wf_node_config.update_time is '淇敼鏃堕棿';
-
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '璇峰亣鐢宠', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, now(), NULL, NULL, '璇峰亣鐢宠鑿滃崟');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, now(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '璇峰亣鐢宠鏂板', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, now(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '璇峰亣鐢宠淇敼', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '璇峰亣鐢宠鍒犻櫎', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, now(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '璇峰亣鐢宠瀵煎嚭', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, now(), NULL, NULL, '');
-
-INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, now(), NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
-INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, now(), NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
-
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸叉挙閿�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, now(), NULL, NULL, '鑽夌');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,now(), NULL, NULL, '寰呭鏍�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, now(), NULL, NULL, '宸插畬鎴�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸蹭綔搴�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸查��鍥�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,now(), NULL, NULL, '宸茬粓姝�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, now(), NULL, NULL, '鑷畾涔夎〃鍗�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '鍔ㄦ�佽〃鍗�');
-
--- 琛ㄥ崟绠$悊 SQL
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11628, '琛ㄥ崟绠$悊', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, now(), null, null, '琛ㄥ崟绠$悊鑿滃崟');
-
--- 琛ㄥ崟绠$悊鎸夐挳 SQL
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11644, '琛ㄥ崟绠$悊鏌ヨ', 11628, '1',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query',        '', 103, 1, now(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11645, '琛ㄥ崟绠$悊鏂板', 11628, '2',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add',          '', 103, 1, now(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11646, '琛ㄥ崟绠$悊淇敼', 11628, '3',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit',         '', 103, 1, now(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11647, '琛ㄥ崟绠$悊鍒犻櫎', 11628, '4',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove',       '', 103, 1, now(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11648, '琛ㄥ崟绠$悊瀵煎嚭', 11628, '5',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export',       'tree-table', 103, 1, now(), null, null, '');
diff --git a/script/sql/postgres/snail_job_postgre.sql b/script/sql/postgres/postgres_ry_job.sql
similarity index 97%
rename from script/sql/postgres/snail_job_postgre.sql
rename to script/sql/postgres/postgres_ry_job.sql
index c8abc68..1a08a99 100644
--- a/script/sql/postgres/snail_job_postgre.sql
+++ b/script/sql/postgres/postgres_ry_job.sql
@@ -2,7 +2,7 @@
  SnailJob Database Transfer Tool
  Source Server Type    : MySQL
  Target Server Type    : PostgreSQL
- Date: 2024-07-06 11:45:40
+ Date: 2024-12-27 22:13:49
 */
 
 
@@ -68,6 +68,7 @@
 COMMENT ON TABLE sj_group_config IS '缁勯厤缃�';
 
 INSERT INTO sj_group_config VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
+INSERT INTO sj_group_config VALUES (2, 'prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
 
 -- sj_notify_config
 CREATE TABLE sj_notify_config
@@ -75,7 +76,7 @@
     id                     bigserial PRIMARY KEY,
     namespace_id           varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
     group_name             varchar(64)  NOT NULL,
-    business_id            varchar(64)  NOT NULL,
+    notify_name            varchar(64)  NOT NULL DEFAULT '',
     system_task_type       smallint     NOT NULL DEFAULT 3,
     notify_status          smallint     NOT NULL DEFAULT 0,
     recipient_ids          varchar(128) NOT NULL,
@@ -88,12 +89,12 @@
     update_dt              timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
 );
 
-CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name, business_id);
+CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name);
 
 COMMENT ON COLUMN sj_notify_config.id IS '涓婚敭';
 COMMENT ON COLUMN sj_notify_config.namespace_id IS '鍛藉悕绌洪棿id';
 COMMENT ON COLUMN sj_notify_config.group_name IS '缁勫悕绉�';
-COMMENT ON COLUMN sj_notify_config.business_id IS '涓氬姟id  ( job_id鎴杦orkflow_id鎴杝cene_name ) ';
+COMMENT ON COLUMN sj_notify_config.notify_name IS '閫氱煡鍚嶇О';
 COMMENT ON COLUMN sj_notify_config.system_task_type IS '浠诲姟绫诲瀷 1. 閲嶈瘯浠诲姟 2. 閲嶈瘯鍥炶皟 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟';
 COMMENT ON COLUMN sj_notify_config.notify_status IS '閫氱煡鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�';
 COMMENT ON COLUMN sj_notify_config.recipient_ids IS '鎺ユ敹浜篿d鍒楄〃';
@@ -296,6 +297,7 @@
     max_retry_count  int          NOT NULL DEFAULT 5,
     back_off         smallint     NOT NULL DEFAULT 1,
     trigger_interval varchar(16)  NOT NULL DEFAULT '',
+    notify_ids       varchar(128) NOT NULL DEFAULT '',
     deadline_request bigint       NOT NULL DEFAULT 60000,
     executor_timeout int          NOT NULL DEFAULT 5,
     route_key        smallint     NOT NULL DEFAULT 4,
@@ -314,6 +316,7 @@
 COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '鏈�澶ч噸璇曟鏁�';
 COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1銆侀粯璁ょ瓑绾� 2銆佸浐瀹氶棿闅旀椂闂� 3銆丆RON 琛ㄨ揪寮�';
 COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '闂撮殧鏃堕暱';
+COMMENT ON COLUMN sj_retry_scene_config.notify_ids IS '閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃';
 COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 璋冪敤閾捐秴鏃� 鍗曚綅姣';
 COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
 COMMENT ON COLUMN sj_retry_scene_config.route_key IS '璺敱绛栫暐';
@@ -463,6 +466,8 @@
     retry_interval   int          NOT NULL DEFAULT 0,
     bucket_index     int          NOT NULL DEFAULT 0,
     resident         smallint     NOT NULL DEFAULT 0,
+    notify_ids       varchar(128) NOT NULL DEFAULT '',
+    owner_id         bigint       NULL,
     description      varchar(256) NOT NULL DEFAULT '',
     ext_attrs        varchar(256) NULL     DEFAULT '',
     deleted          smallint     NOT NULL DEFAULT 0,
@@ -495,6 +500,8 @@
 COMMENT ON COLUMN sj_job.retry_interval IS '閲嶈瘯闂撮殧 ( s ) ';
 COMMENT ON COLUMN sj_job.bucket_index IS 'bucket';
 COMMENT ON COLUMN sj_job.resident IS '鏄惁鏄父椹讳换鍔�';
+COMMENT ON COLUMN sj_job.notify_ids IS '閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃';
+COMMENT ON COLUMN sj_job.owner_id IS '璐熻矗浜篿d';
 COMMENT ON COLUMN sj_job.description IS '鎻忚堪';
 COMMENT ON COLUMN sj_job.ext_attrs IS '鎵╁睍瀛楁';
 COMMENT ON COLUMN sj_job.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
@@ -502,7 +509,7 @@
 COMMENT ON COLUMN sj_job.update_dt IS '淇敼鏃堕棿';
 COMMENT ON TABLE sj_job IS '浠诲姟淇℃伅';
 
-INSERT INTO sj_job VALUES (1, 'dev', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', '', 0, now(), now());
+INSERT INTO sj_job VALUES (1, 'dev', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1, '', '', 0, now(), now());
 
 -- sj_job_log_message
 CREATE TABLE sj_job_log_message
@@ -720,6 +727,7 @@
     description      varchar(256) NOT NULL DEFAULT '',
     flow_info        text         NULL     DEFAULT NULL,
     wf_context       text         NULL     DEFAULT NULL,
+    notify_ids       varchar(128) NOT NULL DEFAULT '',
     bucket_index     int          NOT NULL DEFAULT 0,
     version          int          NOT NULL,
     ext_attrs        varchar(256) NULL     DEFAULT '',
@@ -744,6 +752,7 @@
 COMMENT ON COLUMN sj_workflow.description IS '鎻忚堪';
 COMMENT ON COLUMN sj_workflow.flow_info IS '娴佺▼淇℃伅';
 COMMENT ON COLUMN sj_workflow.wf_context IS '涓婁笅鏂�';
+COMMENT ON COLUMN sj_workflow.notify_ids IS '閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃';
 COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket';
 COMMENT ON COLUMN sj_workflow.version IS '鐗堟湰鍙�';
 COMMENT ON COLUMN sj_workflow.ext_attrs IS '鎵╁睍瀛楁';
diff --git a/script/sql/postgres/postgres_ry_vue_5.X.sql b/script/sql/postgres/postgres_ry_vue_5.X.sql
index 995d738..d18cfeb 100644
--- a/script/sql/postgres/postgres_ry_vue_5.X.sql
+++ b/script/sql/postgres/postgres_ry_vue_5.X.sql
@@ -5,7 +5,7 @@
 (
     id                 int8             not null,
     user_id            int8             not null,
-    tenant_id          varchar(20)      default null::varchar,
+    tenant_id          varchar(20)      default '000000'::varchar,
     auth_id            varchar(255)     not null,
     source             varchar(255)     not null,
     open_id            varchar(255)     default null::varchar,
@@ -64,7 +64,7 @@
 comment on column  sys_social.create_time       is '鍒涘缓鏃堕棿';
 comment on column  sys_social.update_by         is '鏇存柊鑰�';
 comment on column  sys_social.update_time       is '鏇存柊鏃堕棿';
-comment on column  sys_social.del_flag          is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_social.del_flag          is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 
 -- ----------------------------
 -- 绉熸埛琛�
@@ -109,7 +109,7 @@
 comment on column  sys_tenant.expire_time        is '杩囨湡鏃堕棿';
 comment on column  sys_tenant.account_count      is '鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級';
 comment on column  sys_tenant.status             is '绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column  sys_tenant.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_tenant.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column  sys_tenant.create_dept        is '鍒涘缓閮ㄩ棬';
 comment on column  sys_tenant.create_by          is '鍒涘缓鑰�';
 comment on column  sys_tenant.create_time        is '鍒涘缓鏃堕棿';
@@ -151,7 +151,7 @@
 comment on column  sys_tenant_package.menu_ids           is '鍏宠仈鑿滃崟id';
 comment on column  sys_tenant_package.remark             is '澶囨敞';
 comment on column  sys_tenant_package.status             is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column  sys_tenant_package.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_tenant_package.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column  sys_tenant_package.create_dept        is '鍒涘缓閮ㄩ棬';
 comment on column  sys_tenant_package.create_by          is '鍒涘缓鑰�';
 comment on column  sys_tenant_package.create_time        is '鍒涘缓鏃堕棿';
@@ -196,7 +196,7 @@
 comment on column sys_dept.phone        is '鑱旂郴鐢佃瘽';
 comment on column sys_dept.email        is '閭';
 comment on column sys_dept.status       is '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column sys_dept.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_dept.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column sys_dept.create_dept  is '鍒涘缓閮ㄩ棬';
 comment on column sys_dept.create_by    is '鍒涘缓鑰�';
 comment on column sys_dept.create_time  is '鍒涘缓鏃堕棿';
@@ -259,7 +259,7 @@
 comment on column sys_user.avatar       is '澶村儚鍦板潃';
 comment on column sys_user.password     is '瀵嗙爜';
 comment on column sys_user.status       is '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column sys_user.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_user.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column sys_user.login_ip     is '鏈�鍚庣櫥闄咺P';
 comment on column sys_user.login_date   is '鏈�鍚庣櫥闄嗘椂闂�';
 comment on column sys_user.create_dept  is '鍒涘缓閮ㄩ棬';
@@ -357,7 +357,7 @@
 comment on column sys_role.menu_check_strictly  is '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
 comment on column sys_role.dept_check_strictly  is '閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
 comment on column sys_role.status               is '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column sys_role.del_flag             is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_role.del_flag             is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column sys_role.create_dept          is '鍒涘缓閮ㄩ棬';
 comment on column sys_role.create_by            is '鍒涘缓鑰�';
 comment on column sys_role.create_time          is '鍒涘缓鏃堕棿';
@@ -427,7 +427,7 @@
 -- ----------------------------
 -- 涓�绾ц彍鍗�
 insert into sys_menu values('1', '绯荤粺绠$悊', '0', '1', 'system',           null, '', '1', '0', 'M', '0', '0', '', 'system',   103, 1, now(), null, null, '绯荤粺绠$悊鐩綍');
-insert into sys_menu values('6', '绯荤粺绠$悊', '0', '2', 'tenant',           null, '', '1', '0', 'M', '0', '0', '', 'chart',    103, 1, now(), null, null, '绉熸埛绠$悊鐩綍');
+insert into sys_menu values('6', '绉熸埛绠$悊', '0', '2', 'tenant',           null, '', '1', '0', 'M', '0', '0', '', 'chart',    103, 1, now(), null, null, '绉熸埛绠$悊鐩綍');
 insert into sys_menu values('2', '绯荤粺鐩戞帶', '0', '3', 'monitor',          null, '', '1', '0', 'M', '0', '0', '', 'monitor',  103, 1, now(), null, null, '绯荤粺鐩戞帶鐩綍');
 insert into sys_menu values('3', '绯荤粺宸ュ叿', '0', '4', 'tool',             null, '', '1', '0', 'M', '0', '0', '', 'tool',     103, 1, now(), null, null, '绯荤粺宸ュ叿鐩綍');
 insert into sys_menu values('4', 'PLUS瀹樼綉', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', '0', '0', 'M', '0', '0', '', 'guide',    103, 1, now(), null, null, 'RuoYi-Vue-Plus瀹樼綉鍦板潃');
@@ -617,6 +617,8 @@
 insert into sys_role_menu values ('3', '106');
 insert into sys_role_menu values ('3', '107');
 insert into sys_role_menu values ('3', '108');
+insert into sys_role_menu values ('3', '118');
+insert into sys_role_menu values ('3', '123');
 insert into sys_role_menu values ('3', '500');
 insert into sys_role_menu values ('3', '501');
 insert into sys_role_menu values ('3', '1001');
@@ -664,6 +666,12 @@
 insert into sys_role_menu values ('3', '1043');
 insert into sys_role_menu values ('3', '1044');
 insert into sys_role_menu values ('3', '1045');
+insert into sys_role_menu values ('3', '1050');
+insert into sys_role_menu values ('3', '1061');
+insert into sys_role_menu values ('3', '1062');
+insert into sys_role_menu values ('3', '1063');
+insert into sys_role_menu values ('3', '1064');
+insert into sys_role_menu values ('3', '1065');
 insert into sys_role_menu values ('3', '1500');
 insert into sys_role_menu values ('3', '1501');
 insert into sys_role_menu values ('3', '1502');
@@ -676,6 +684,25 @@
 insert into sys_role_menu values ('3', '1509');
 insert into sys_role_menu values ('3', '1510');
 insert into sys_role_menu values ('3', '1511');
+insert into sys_role_menu values ('3', '1600');
+insert into sys_role_menu values ('3', '1601');
+insert into sys_role_menu values ('3', '1602');
+insert into sys_role_menu values ('3', '1603');
+insert into sys_role_menu values ('3', '1620');
+insert into sys_role_menu values ('3', '1621');
+insert into sys_role_menu values ('3', '1622');
+insert into sys_role_menu values ('3', '1623');
+insert into sys_role_menu values ('3', '11618');
+insert into sys_role_menu values ('3', '11619');
+insert into sys_role_menu values ('3', '11629');
+insert into sys_role_menu values ('3', '11632');
+insert into sys_role_menu values ('3', '11633');
+insert into sys_role_menu values ('3', '11638');
+insert into sys_role_menu values ('3', '11639');
+insert into sys_role_menu values ('3', '11640');
+insert into sys_role_menu values ('3', '11641');
+insert into sys_role_menu values ('3', '11642');
+insert into sys_role_menu values ('3', '11643');
 insert into sys_role_menu values ('4', '5');
 insert into sys_role_menu values ('4', '1500');
 insert into sys_role_menu values ('4', '1501');
@@ -741,10 +768,10 @@
     oper_url       varchar(255)  default ''::varchar,
     oper_ip        varchar(128)  default ''::varchar,
     oper_location  varchar(255)  default ''::varchar,
-    oper_param     varchar(2000) default ''::varchar,
-    json_result    varchar(2000) default ''::varchar,
+    oper_param     varchar(4000) default ''::varchar,
+    json_result    varchar(4000) default ''::varchar,
     status         int4          default 0,
-    error_msg      varchar(2000) default ''::varchar,
+    error_msg      varchar(4000) default ''::varchar,
     oper_time      timestamp,
     cost_time      int8          default 0,
     constraint sys_oper_log_pk primary key (oper_id)
@@ -1209,7 +1236,7 @@
 insert into sys_oss_config values (1, '000000', 'minio',  'ruoyi',            'ruoyi123',        'ruoyi',             '', '127.0.0.1:9000',                      '','N', '',            '1', '0', '', 103, 1, now(), 1, now(), null);
 insert into sys_oss_config values (2, '000000', 'qiniu',  'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 's3-cn-north-1.qiniucs.com',           '','N', '',            '1', '1', '', 103, 1, now(), 1, now(), null);
 insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 'oss-cn-beijing.aliyuncs.com',         '','N', '',            '1', '1', '', 103, 1, now(), 1, now(), null);
-insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi-1250000000',  '', 'cos.ap-beijing.myqcloud.com',         '','N', 'ap-beijing',  '1', '1', '', 103, 1, now(), 1, now(), null);
+insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi-1240000000',  '', 'cos.ap-beijing.myqcloud.com',         '','N', 'ap-beijing',  '1', '1', '', 103, 1, now(), 1, now(), null);
 insert into sys_oss_config values (5, '000000', 'image',  'ruoyi',            'ruoyi123',        'ruoyi',             'image', '127.0.0.1:9000',                 '','N', '',            '1', '1', '', 103, 1, now(), 1, now(), NULL);
 
 -- ----------------------------
@@ -1244,7 +1271,7 @@
 comment on column sys_client.active_timeout         is 'token娲昏穬瓒呮椂鏃堕棿';
 comment on column sys_client.timeout                is 'token鍥哄畾瓒呮椂';
 comment on column sys_client.status                 is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
-comment on column sys_client.del_flag               is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_client.del_flag               is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
 comment on column sys_client.create_dept            is '鍒涘缓閮ㄩ棬';
 comment on column sys_client.create_by              is '鍒涘缓鑰�';
 comment on column sys_client.create_time            is '鍒涘缓鏃堕棿';
diff --git a/script/sql/postgres/postgres_ry_workflow.sql b/script/sql/postgres/postgres_ry_workflow.sql
new file mode 100644
index 0000000..80cd414
--- /dev/null
+++ b/script/sql/postgres/postgres_ry_workflow.sql
@@ -0,0 +1,405 @@
+-- ----------------------------
+-- 0銆亀arm-flow-all.sql锛屽湴鍧�锛歨ttps://gitee.com/dromara/warm-flow/blob/master/sql/postgresql/postgresql-warm-flow-all.sql
+-- ----------------------------
+CREATE TABLE flow_definition
+(
+    id              int8         NOT NULL,                                 -- 涓婚敭id
+    flow_code       varchar(40)  NOT NULL,                                 -- 娴佺▼缂栫爜
+    flow_name       varchar(100) NOT NULL,                                 -- 娴佺▼鍚嶇О
+    category        varchar(100) NULL,                                     -- 娴佺▼绫诲埆
+    "version"       varchar(20)  NOT NULL,                                 -- 娴佺▼鐗堟湰
+    is_publish      int2         NOT NULL DEFAULT 0,                       -- 鏄惁鍙戝竷锛�0鏈彂甯� 1宸插彂甯� 9澶辨晥锛�
+    form_custom     bpchar(1)    NULL     DEFAULT 'N':: character varying, -- 瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級
+    form_path       varchar(100) NULL,                                     -- 瀹℃壒琛ㄥ崟璺緞
+    activity_status int2         NOT NULL DEFAULT 1,                       -- 娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級
+    listener_type   varchar(100) NULL,                                     -- 鐩戝惉鍣ㄧ被鍨�
+    listener_path   varchar(400) NULL,                                     -- 鐩戝惉鍣ㄨ矾寰�
+    ext             varchar(500) NULL,                                     -- 鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤
+    create_time     timestamp    NULL,                                     -- 鍒涘缓鏃堕棿
+    update_time     timestamp    NULL,                                     -- 鏇存柊鏃堕棿
+    del_flag        bpchar(1)    NULL     DEFAULT '0':: character varying, -- 鍒犻櫎鏍囧織
+    tenant_id       varchar(40)  NULL,                                     -- 绉熸埛id
+    CONSTRAINT flow_definition_pkey PRIMARY KEY (id)
+);
+COMMENT ON TABLE flow_definition IS '娴佺▼瀹氫箟琛�';
+
+COMMENT ON COLUMN flow_definition.id IS '涓婚敭id';
+COMMENT ON COLUMN flow_definition.flow_code IS '娴佺▼缂栫爜';
+COMMENT ON COLUMN flow_definition.flow_name IS '娴佺▼鍚嶇О';
+COMMENT ON COLUMN flow_definition.category IS '娴佺▼绫诲埆';
+COMMENT ON COLUMN flow_definition."version" IS '娴佺▼鐗堟湰';
+COMMENT ON COLUMN flow_definition.is_publish IS '鏄惁鍙戝竷锛�0鏈彂甯� 1宸插彂甯� 9澶辨晥锛�';
+COMMENT ON COLUMN flow_definition.form_custom IS '瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級';
+COMMENT ON COLUMN flow_definition.form_path IS '瀹℃壒琛ㄥ崟璺緞';
+COMMENT ON COLUMN flow_definition.activity_status IS '娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級';
+COMMENT ON COLUMN flow_definition.listener_type IS '鐩戝惉鍣ㄧ被鍨�';
+COMMENT ON COLUMN flow_definition.listener_path IS '鐩戝惉鍣ㄨ矾寰�';
+COMMENT ON COLUMN flow_definition.ext IS '鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤';
+COMMENT ON COLUMN flow_definition.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN flow_definition.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN flow_definition.del_flag IS '鍒犻櫎鏍囧織';
+COMMENT ON COLUMN flow_definition.tenant_id IS '绉熸埛id';
+
+CREATE TABLE flow_node
+(
+    id              int8          NOT NULL,                             -- 涓婚敭id
+    node_type       int2          NOT NULL,                             -- 鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�
+    definition_id   int8          NOT NULL,                             -- 娴佺▼瀹氫箟id
+    node_code       varchar(100)  NOT NULL,                             -- 娴佺▼鑺傜偣缂栫爜
+    node_name       varchar(100)  NULL,                                 -- 娴佺▼鑺傜偣鍚嶇О
+    permission_flag varchar(200)  NULL,                                 -- 鏉冮檺鏍囪瘑锛堟潈闄愮被鍨�:鏉冮檺鏍囪瘑锛屽彲浠ュ涓紝鐢ㄩ�楀彿闅斿紑)
+    node_ratio      numeric(6, 3) NULL,                                 -- 娴佺▼绛剧讲姣斾緥鍊�
+    coordinate      varchar(100)  NULL,                                 -- 鍧愭爣
+    skip_any_node   varchar(100)  NULL DEFAULT 'N':: character varying, -- 鏄惁鍙互閫�鍥炰换鎰忚妭鐐癸紙Y鏄� N鍚︼級鍗冲皢鍒犻櫎
+    any_node_skip   varchar(100)  NULL,                                 -- 浠绘剰缁撶偣璺宠浆
+    listener_type   varchar(100)  NULL,                                 -- 鐩戝惉鍣ㄧ被鍨�
+    listener_path   varchar(400)  NULL,                                 -- 鐩戝惉鍣ㄨ矾寰�
+    handler_type    varchar(100)  NULL,                                 -- 澶勭悊鍣ㄧ被鍨�
+    handler_path    varchar(400)  NULL,                                 -- 澶勭悊鍣ㄨ矾寰�
+    form_custom     bpchar(1)     NULL DEFAULT 'N':: character varying, -- 瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級
+    form_path       varchar(100)  NULL,                                 -- 瀹℃壒琛ㄥ崟璺緞
+    "version"       varchar(20)   NOT NULL,                             -- 鐗堟湰
+    create_time     timestamp     NULL,                                 -- 鍒涘缓鏃堕棿
+    update_time     timestamp     NULL,                                 -- 鏇存柊鏃堕棿
+    del_flag        bpchar(1)     NULL DEFAULT '0':: character varying, -- 鍒犻櫎鏍囧織
+    tenant_id       varchar(40)   NULL,                                 -- 绉熸埛id
+    CONSTRAINT flow_node_pkey PRIMARY KEY (id)
+);
+COMMENT ON TABLE flow_node IS '娴佺▼鑺傜偣琛�';
+
+COMMENT ON COLUMN flow_node.id IS '涓婚敭id';
+COMMENT ON COLUMN flow_node.node_type IS '鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�';
+COMMENT ON COLUMN flow_node.definition_id IS '娴佺▼瀹氫箟id';
+COMMENT ON COLUMN flow_node.node_code IS '娴佺▼鑺傜偣缂栫爜';
+COMMENT ON COLUMN flow_node.node_name IS '娴佺▼鑺傜偣鍚嶇О';
+COMMENT ON COLUMN flow_node.permission_flag IS '鏉冮檺鏍囪瘑锛堟潈闄愮被鍨�:鏉冮檺鏍囪瘑锛屽彲浠ュ涓紝鐢ㄩ�楀彿闅斿紑)';
+COMMENT ON COLUMN flow_node.node_ratio IS '娴佺▼绛剧讲姣斾緥鍊�';
+COMMENT ON COLUMN flow_node.coordinate IS '鍧愭爣';
+COMMENT ON COLUMN flow_node.skip_any_node IS '鏄惁鍙互閫�鍥炰换鎰忚妭鐐癸紙Y鏄� N鍚︼級鍗冲皢鍒犻櫎';
+COMMENT ON COLUMN flow_node.any_node_skip IS '浠绘剰缁撶偣璺宠浆';
+COMMENT ON COLUMN flow_node.listener_type IS '鐩戝惉鍣ㄧ被鍨�';
+COMMENT ON COLUMN flow_node.listener_path IS '鐩戝惉鍣ㄨ矾寰�';
+COMMENT ON COLUMN flow_node.handler_type IS '澶勭悊鍣ㄧ被鍨�';
+COMMENT ON COLUMN flow_node.handler_path IS '澶勭悊鍣ㄨ矾寰�';
+COMMENT ON COLUMN flow_node.form_custom IS '瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級';
+COMMENT ON COLUMN flow_node.form_path IS '瀹℃壒琛ㄥ崟璺緞';
+COMMENT ON COLUMN flow_node."version" IS '鐗堟湰';
+COMMENT ON COLUMN flow_node.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN flow_node.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN flow_node.del_flag IS '鍒犻櫎鏍囧織';
+COMMENT ON COLUMN flow_node.tenant_id IS '绉熸埛id';
+
+
+CREATE TABLE flow_skip
+(
+    id             int8         NOT NULL,                             -- 涓婚敭id
+    definition_id  int8         NOT NULL,                             -- 娴佺▼瀹氫箟id
+    now_node_code  varchar(100) NOT NULL,                             -- 褰撳墠娴佺▼鑺傜偣鐨勭紪鐮�
+    now_node_type  int2         NULL,                                 -- 褰撳墠鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�
+    next_node_code varchar(100) NOT NULL,                             -- 涓嬩竴涓祦绋嬭妭鐐圭殑缂栫爜
+    next_node_type int2         NULL,                                 -- 涓嬩竴涓妭鐐圭被鍨嬶紙0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�
+    skip_name      varchar(100) NULL,                                 -- 璺宠浆鍚嶇О
+    skip_type      varchar(40)  NULL,                                 -- 璺宠浆绫诲瀷锛圥ASS瀹℃壒閫氳繃 REJECT閫�鍥烇級
+    skip_condition varchar(200) NULL,                                 -- 璺宠浆鏉′欢
+    coordinate     varchar(100) NULL,                                 -- 鍧愭爣
+    create_time    timestamp    NULL,                                 -- 鍒涘缓鏃堕棿
+    update_time    timestamp    NULL,                                 -- 鏇存柊鏃堕棿
+    del_flag       bpchar(1)    NULL DEFAULT '0':: character varying, -- 鍒犻櫎鏍囧織
+    tenant_id      varchar(40)  NULL,                                 -- 绉熸埛id
+    CONSTRAINT flow_skip_pkey PRIMARY KEY (id)
+);
+COMMENT ON TABLE flow_skip IS '鑺傜偣璺宠浆鍏宠仈琛�';
+
+COMMENT ON COLUMN flow_skip.id IS '涓婚敭id';
+COMMENT ON COLUMN flow_skip.definition_id IS '娴佺▼瀹氫箟id';
+COMMENT ON COLUMN flow_skip.now_node_code IS '褰撳墠娴佺▼鑺傜偣鐨勭紪鐮�';
+COMMENT ON COLUMN flow_skip.now_node_type IS '褰撳墠鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�';
+COMMENT ON COLUMN flow_skip.next_node_code IS '涓嬩竴涓祦绋嬭妭鐐圭殑缂栫爜';
+COMMENT ON COLUMN flow_skip.next_node_type IS '涓嬩竴涓妭鐐圭被鍨嬶紙0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�';
+COMMENT ON COLUMN flow_skip.skip_name IS '璺宠浆鍚嶇О';
+COMMENT ON COLUMN flow_skip.skip_type IS '璺宠浆绫诲瀷锛圥ASS瀹℃壒閫氳繃 REJECT閫�鍥烇級';
+COMMENT ON COLUMN flow_skip.skip_condition IS '璺宠浆鏉′欢';
+COMMENT ON COLUMN flow_skip.coordinate IS '鍧愭爣';
+COMMENT ON COLUMN flow_skip.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN flow_skip.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN flow_skip.del_flag IS '鍒犻櫎鏍囧織';
+COMMENT ON COLUMN flow_skip.tenant_id IS '绉熸埛id';
+
+CREATE TABLE flow_instance
+(
+    id              int8         NOT NULL,                                 -- 涓婚敭id
+    definition_id   int8         NOT NULL,                                 -- 瀵瑰簲flow_definition琛ㄧ殑id
+    business_id     varchar(40)  NOT NULL,                                 -- 涓氬姟id
+    node_type       int2         NOT NULL,                                 -- 鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�
+    node_code       varchar(40)  NOT NULL,                                 -- 娴佺▼鑺傜偣缂栫爜
+    node_name       varchar(100) NULL,                                     -- 娴佺▼鑺傜偣鍚嶇О
+    variable        text         NULL,                                     -- 浠诲姟鍙橀噺
+    flow_status     varchar(20)  NOT NULL,                                 -- 娴佺▼鐘舵�侊紙0寰呮彁浜� 1瀹℃壒涓� 2 瀹℃壒閫氳繃 8宸插畬鎴� 9宸查��鍥� 10澶辨晥锛�
+    activity_status int2         NOT NULL DEFAULT 1,                       -- 娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級
+    def_json        text         NULL,                                     -- 娴佺▼瀹氫箟json
+    create_by       varchar(64)  NULL     DEFAULT '':: character varying,  -- 鍒涘缓鑰�
+    create_time     timestamp    NULL,                                     -- 鍒涘缓鏃堕棿
+    update_time     timestamp    NULL,                                     -- 鏇存柊鏃堕棿
+    ext             varchar(500) NULL,                                     -- 鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤
+    del_flag        bpchar(1)    NULL     DEFAULT '0':: character varying, -- 鍒犻櫎鏍囧織
+    tenant_id       varchar(40)  NULL,                                     -- 绉熸埛id
+    CONSTRAINT flow_instance_pkey PRIMARY KEY (id)
+);
+COMMENT ON TABLE flow_instance IS '娴佺▼瀹炰緥琛�';
+
+COMMENT ON COLUMN flow_instance.id IS '涓婚敭id';
+COMMENT ON COLUMN flow_instance.definition_id IS '瀵瑰簲flow_definition琛ㄧ殑id';
+COMMENT ON COLUMN flow_instance.business_id IS '涓氬姟id';
+COMMENT ON COLUMN flow_instance.node_type IS '鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�';
+COMMENT ON COLUMN flow_instance.node_code IS '娴佺▼鑺傜偣缂栫爜';
+COMMENT ON COLUMN flow_instance.node_name IS '娴佺▼鑺傜偣鍚嶇О';
+COMMENT ON COLUMN flow_instance.variable IS '浠诲姟鍙橀噺';
+COMMENT ON COLUMN flow_instance.flow_status IS '娴佺▼鐘舵�侊紙0寰呮彁浜� 1瀹℃壒涓� 2 瀹℃壒閫氳繃 3鑷姩閫氳繃 4缁堟 5浣滃簾 6鎾ら攢 7鍙栧洖  8宸插畬鎴� 9宸查��鍥� 10澶辨晥锛�';
+COMMENT ON COLUMN flow_instance.activity_status IS '娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級';
+COMMENT ON COLUMN flow_instance.def_json IS '娴佺▼瀹氫箟json';
+COMMENT ON COLUMN flow_instance.create_by IS '鍒涘缓鑰�';
+COMMENT ON COLUMN flow_instance.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN flow_instance.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN flow_instance.ext IS '鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤';
+COMMENT ON COLUMN flow_instance.del_flag IS '鍒犻櫎鏍囧織';
+COMMENT ON COLUMN flow_instance.tenant_id IS '绉熸埛id';
+
+CREATE TABLE flow_task
+(
+    id            int8         NOT NULL,                             -- 涓婚敭id
+    definition_id int8         NOT NULL,                             -- 瀵瑰簲flow_definition琛ㄧ殑id
+    instance_id   int8         NOT NULL,                             -- 瀵瑰簲flow_instance琛ㄧ殑id
+    node_code     varchar(100) NOT NULL,                             -- 鑺傜偣缂栫爜
+    node_name     varchar(100) NULL,                                 -- 鑺傜偣鍚嶇О
+    node_type     int2         NOT NULL,                             -- 鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�
+    form_custom   bpchar(1)    NULL DEFAULT 'N':: character varying, -- 瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級
+    form_path     varchar(100) NULL,                                 -- 瀹℃壒琛ㄥ崟璺緞
+    create_time   timestamp    NULL,                                 -- 鍒涘缓鏃堕棿
+    update_time   timestamp    NULL,                                 -- 鏇存柊鏃堕棿
+    del_flag      bpchar(1)    NULL DEFAULT '0':: character varying, -- 鍒犻櫎鏍囧織
+    tenant_id     varchar(40)  NULL,                                 -- 绉熸埛id
+    CONSTRAINT flow_task_pkey PRIMARY KEY (id)
+);
+COMMENT ON TABLE flow_task IS '寰呭姙浠诲姟琛�';
+
+COMMENT ON COLUMN flow_task.id IS '涓婚敭id';
+COMMENT ON COLUMN flow_task.definition_id IS '瀵瑰簲flow_definition琛ㄧ殑id';
+COMMENT ON COLUMN flow_task.instance_id IS '瀵瑰簲flow_instance琛ㄧ殑id';
+COMMENT ON COLUMN flow_task.node_code IS '鑺傜偣缂栫爜';
+COMMENT ON COLUMN flow_task.node_name IS '鑺傜偣鍚嶇О';
+COMMENT ON COLUMN flow_task.node_type IS '鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�';
+COMMENT ON COLUMN flow_task.form_custom IS '瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級';
+COMMENT ON COLUMN flow_task.form_path IS '瀹℃壒琛ㄥ崟璺緞';
+COMMENT ON COLUMN flow_task.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN flow_task.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN flow_task.del_flag IS '鍒犻櫎鏍囧織';
+COMMENT ON COLUMN flow_task.tenant_id IS '绉熸埛id';
+
+CREATE TABLE flow_his_task
+(
+    id               int8         NOT NULL,                                 -- 涓婚敭id
+    definition_id    int8         NOT NULL,                                 -- 瀵瑰簲flow_definition琛ㄧ殑id
+    instance_id      int8         NOT NULL,                                 -- 瀵瑰簲flow_instance琛ㄧ殑id
+    task_id          int8         NOT NULL,                                 -- 瀵瑰簲flow_task琛ㄧ殑id
+    node_code        varchar(200) NULL,                                     -- 寮�濮嬭妭鐐圭紪鐮�
+    node_name        varchar(200) NULL,                                     -- 寮�濮嬭妭鐐瑰悕绉�
+    node_type        int2         NULL,                                     -- 寮�濮嬭妭鐐圭被鍨嬶紙0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�
+    target_node_code varchar(200) NULL,                                     -- 鐩爣鑺傜偣缂栫爜
+    target_node_name varchar(200) NULL,                                     -- 缁撴潫鑺傜偣鍚嶇О
+    approver         varchar(40)  NULL,                                     -- 瀹℃壒鑰�
+    cooperate_type   int2         NOT NULL DEFAULT 0,                       -- 鍗忎綔鏂瑰紡(1瀹℃壒 2杞姙 3濮旀淳 4浼氱 5绁ㄧ 6鍔犵 7鍑忕)
+    collaborator     varchar(40)  NULL,                                     -- 鍗忎綔浜�(鍙湁杞姙銆佷細绛俱�佺エ绛俱�佸娲�)
+    skip_type        varchar(10)  NULL,                                     -- 娴佽浆绫诲瀷锛圥ASS閫氳繃 REJECT閫�鍥� NONE鏃犲姩浣滐級
+    flow_status      varchar(20)  NOT NULL,                                 -- 娴佺▼鐘舵�侊紙0寰呮彁浜� 1瀹℃壒涓� 2 瀹℃壒閫氳繃 8宸插畬鎴� 9宸查��鍥� 10澶辨晥锛�
+    form_custom      bpchar(1)    NULL     DEFAULT 'N':: character varying, -- 瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級
+    form_path        varchar(100) NULL,                                     -- 瀹℃壒琛ㄥ崟璺緞
+    ext              varchar(500) NULL,                                     -- 鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤
+    message          varchar(500) NULL,                                     -- 瀹℃壒鎰忚
+    variable         text         NULL,                                     -- 浠诲姟鍙橀噺
+    create_time      timestamp    NULL,                                     -- 鍒涘缓鏃堕棿
+    update_time      timestamp    NULL,                                     -- 鏇存柊鏃堕棿
+    del_flag         bpchar(1)    NULL     DEFAULT '0':: character varying, -- 鍒犻櫎鏍囧織
+    tenant_id        varchar(40)  NULL,                                     -- 绉熸埛id
+    CONSTRAINT flow_his_task_pkey PRIMARY KEY (id)
+);
+COMMENT ON TABLE flow_his_task IS '鍘嗗彶浠诲姟璁板綍琛�';
+
+COMMENT ON COLUMN flow_his_task.id IS '涓婚敭id';
+COMMENT ON COLUMN flow_his_task.definition_id IS '瀵瑰簲flow_definition琛ㄧ殑id';
+COMMENT ON COLUMN flow_his_task.instance_id IS '瀵瑰簲flow_instance琛ㄧ殑id';
+COMMENT ON COLUMN flow_his_task.task_id IS '瀵瑰簲flow_task琛ㄧ殑id';
+COMMENT ON COLUMN flow_his_task.node_code IS '寮�濮嬭妭鐐圭紪鐮�';
+COMMENT ON COLUMN flow_his_task.node_name IS '寮�濮嬭妭鐐瑰悕绉�';
+COMMENT ON COLUMN flow_his_task.node_type IS '寮�濮嬭妭鐐圭被鍨嬶紙0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�';
+COMMENT ON COLUMN flow_his_task.target_node_code IS '鐩爣鑺傜偣缂栫爜';
+COMMENT ON COLUMN flow_his_task.target_node_name IS '缁撴潫鑺傜偣鍚嶇О';
+COMMENT ON COLUMN flow_his_task.approver IS '瀹℃壒鑰�';
+COMMENT ON COLUMN flow_his_task.cooperate_type IS '鍗忎綔鏂瑰紡(1瀹℃壒 2杞姙 3濮旀淳 4浼氱 5绁ㄧ 6鍔犵 7鍑忕)';
+COMMENT ON COLUMN flow_his_task.collaborator IS '鍗忎綔浜�';
+COMMENT ON COLUMN flow_his_task.skip_type IS '娴佽浆绫诲瀷锛圥ASS閫氳繃 REJECT閫�鍥� NONE鏃犲姩浣滐級';
+COMMENT ON COLUMN flow_his_task.flow_status IS '娴佺▼鐘舵�侊紙1瀹℃壒涓� 2 瀹℃壒閫氳繃 9宸查��鍥� 10澶辨晥锛�';
+COMMENT ON COLUMN flow_his_task.form_custom IS '瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級';
+COMMENT ON COLUMN flow_his_task.form_path IS '瀹℃壒琛ㄥ崟璺緞';
+COMMENT ON COLUMN flow_his_task.message IS '瀹℃壒鎰忚';
+COMMENT ON COLUMN flow_his_task.variable IS '浠诲姟鍙橀噺';
+COMMENT ON COLUMN flow_his_task.ext IS '鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤';
+COMMENT ON COLUMN flow_his_task.create_time IS '浠诲姟寮�濮嬫椂闂�';
+COMMENT ON COLUMN flow_his_task.update_time IS '瀹℃壒瀹屾垚鏃堕棿';
+COMMENT ON COLUMN flow_his_task.del_flag IS '鍒犻櫎鏍囧織';
+COMMENT ON COLUMN flow_his_task.tenant_id IS '绉熸埛id';
+
+CREATE TABLE flow_user
+(
+    id           int8        NOT NULL,                             -- 涓婚敭id
+    "type"       bpchar(1)   NOT NULL,                             -- 浜哄憳绫诲瀷锛�1寰呭姙浠诲姟鐨勫鎵逛汉鏉冮檺 2寰呭姙浠诲姟鐨勮浆鍔炰汉鏉冮檺 3娴佺▼瀹炰緥鐨勬妱閫佷汉鏉冮檺 4寰呭姙浠诲姟鐨勫鎵樹汉鏉冮檺锛�
+    processed_by varchar(80) NULL,                                 -- 鏉冮檺浜�
+    associated   int8        NOT NULL,                             -- 浠诲姟琛╥d
+    create_time  timestamp   NULL,                                 -- 鍒涘缓鏃堕棿
+    create_by    varchar(80) NULL,                                 -- 鍒涘缓浜�
+    update_time  timestamp   NULL,                                 -- 鏇存柊鏃堕棿
+    del_flag     bpchar(1)   NULL DEFAULT '0':: character varying, -- 鍒犻櫎鏍囧織
+    tenant_id    varchar(40) NULL,                                 -- 绉熸埛id
+    CONSTRAINT flow_user_pk PRIMARY KEY (id)
+);
+CREATE INDEX user_processed_type ON flow_user USING btree (processed_by, type);
+COMMENT ON TABLE flow_user IS '娴佺▼鐢ㄦ埛琛�';
+
+COMMENT ON COLUMN flow_user.id IS '涓婚敭id';
+COMMENT ON COLUMN flow_user."type" IS '浜哄憳绫诲瀷锛�1寰呭姙浠诲姟鐨勫鎵逛汉鏉冮檺 2寰呭姙浠诲姟鐨勮浆鍔炰汉鏉冮檺 3寰呭姙浠诲姟鐨勫鎵樹汉鏉冮檺锛�';
+COMMENT ON COLUMN flow_user.processed_by IS '鏉冮檺浜�';
+COMMENT ON COLUMN flow_user.associated IS '浠诲姟琛╥d';
+COMMENT ON COLUMN flow_user.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN flow_user.create_by IS '鍒涘缓浜�';
+COMMENT ON COLUMN flow_user.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN flow_user.del_flag IS '鍒犻櫎鏍囧織';
+COMMENT ON COLUMN flow_user.tenant_id IS '绉熸埛id';
+
+-- ----------------------------
+-- 娴佺▼鍒嗙被琛�
+-- ----------------------------
+CREATE TABLE flow_category
+(
+    category_id   int8         NOT NULL,
+    tenant_id     VARCHAR(20)  DEFAULT '000000'::varchar,
+    parent_id     int8         DEFAULT 0,
+    ancestors     VARCHAR(500) DEFAULT ''::varchar,
+    category_name VARCHAR(30)  NOT NULL,
+    order_num     INT          DEFAULT 0,
+    del_flag      CHAR         DEFAULT '0'::bpchar,
+    create_dept   int8,
+    create_by     int8,
+    create_time   TIMESTAMP,
+    update_by     int8,
+    update_time   TIMESTAMP,
+    PRIMARY KEY (category_id)
+);
+
+COMMENT ON TABLE flow_category IS '娴佺▼鍒嗙被';
+COMMENT ON COLUMN flow_category.category_id IS '娴佺▼鍒嗙被ID';
+COMMENT ON COLUMN flow_category.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON COLUMN flow_category.parent_id IS '鐖舵祦绋嬪垎绫籭d';
+COMMENT ON COLUMN flow_category.ancestors IS '绁栫骇鍒楄〃';
+COMMENT ON COLUMN flow_category.category_name IS '娴佺▼鍒嗙被鍚嶇О';
+COMMENT ON COLUMN flow_category.order_num IS '鏄剧ず椤哄簭';
+COMMENT ON COLUMN flow_category.del_flag IS '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�';
+COMMENT ON COLUMN flow_category.create_dept IS '鍒涘缓閮ㄩ棬';
+COMMENT ON COLUMN flow_category.create_by IS '鍒涘缓鑰�';
+COMMENT ON COLUMN flow_category.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN flow_category.update_by IS '鏇存柊鑰�';
+COMMENT ON COLUMN flow_category.update_time IS '鏇存柊鏃堕棿';
+
+INSERT INTO flow_category VALUES (100, '000000', 0, '0', 'OA瀹℃壒', 0, '0', 103, 1, now(), NULL, NULL);
+INSERT INTO flow_category VALUES (101, '000000', 100, '0,100', '鍋囧嫟绠$悊', 0, '0', 103, 1, now(), NULL, NULL);
+INSERT INTO flow_category VALUES (102, '000000', 100, '0,100', '浜轰簨绠$悊', 1, '0', 103, 1, now(), NULL, NULL);
+INSERT INTO flow_category VALUES (103, '000000', 101, '0,100,101', '璇峰亣', 0, '0', 103, 1, now(), NULL, NULL);
+INSERT INTO flow_category VALUES (104, '000000', 101, '0,100,101', '鍑哄樊', 1, '0', 103, 1, now(), NULL, NULL);
+INSERT INTO flow_category VALUES (105, '000000', 101, '0,100,101', '鍔犵彮', 2, '0', 103, 1, now(), NULL, NULL);
+INSERT INTO flow_category VALUES (106, '000000', 101, '0,100,101', '鎹㈢彮', 3, '0', 103, 1, now(), NULL, NULL);
+INSERT INTO flow_category VALUES (107, '000000', 101, '0,100,101', '澶栧嚭', 4, '0', 103, 1, now(), NULL, NULL);
+INSERT INTO flow_category VALUES (108, '000000', 102, '0,100,102', '杞', 1, '0', 103, 1, now(), NULL, NULL);
+INSERT INTO flow_category VALUES (109, '000000', 102, '0,100,102', '绂昏亴', 2, '0', 103, 1, now(), NULL, NULL);
+
+-- ----------------------------
+-- 璇峰亣鍗曚俊鎭�
+-- ----------------------------
+CREATE TABLE test_leave
+(
+    id          int8         NOT NULL,
+    tenant_id   VARCHAR(20)  DEFAULT '000000'::varchar,
+    leave_type  VARCHAR(255) NOT NULL,
+    start_date  TIMESTAMP    NOT NULL,
+    end_date    TIMESTAMP    NOT NULL,
+    leave_days  int2          NOT NULL,
+    remark      VARCHAR(255),
+    status      VARCHAR(255),
+    create_dept int8,
+    create_by   int8,
+    create_time TIMESTAMP,
+    update_by   int8,
+    update_time TIMESTAMP,
+    PRIMARY KEY (id)
+);
+
+COMMENT ON TABLE test_leave IS '璇峰亣鐢宠琛�';
+COMMENT ON COLUMN test_leave.id IS 'id';
+COMMENT ON COLUMN test_leave.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON COLUMN test_leave.leave_type IS '璇峰亣绫诲瀷';
+COMMENT ON COLUMN test_leave.start_date IS '寮�濮嬫椂闂�';
+COMMENT ON COLUMN test_leave.end_date IS '缁撴潫鏃堕棿';
+COMMENT ON COLUMN test_leave.leave_days IS '璇峰亣澶╂暟';
+COMMENT ON COLUMN test_leave.remark IS '璇峰亣鍘熷洜';
+COMMENT ON COLUMN test_leave.status IS '鐘舵��';
+COMMENT ON COLUMN test_leave.create_dept IS '鍒涘缓閮ㄩ棬';
+COMMENT ON COLUMN test_leave.create_by IS '鍒涘缓鑰�';
+COMMENT ON COLUMN test_leave.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN test_leave.update_by IS '鏇存柊鑰�';
+COMMENT ON COLUMN test_leave.update_time IS '鏇存柊鏃堕棿';
+
+INSERT INTO sys_menu VALUES ('11616', '宸ヤ綔娴�', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11618', '鎴戠殑浠诲姟', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11622', '娴佺▼鍒嗙被', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:query', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:add', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:remove', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:export', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11638', '璇峰亣鐢宠', '5', '1', 'leave', 'workflow/leave/index', '', '1', '0', 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, now(), NULL, NULL, '璇峰亣鐢宠鑿滃崟');
+INSERT INTO sys_menu VALUES ('11639', '璇峰亣鐢宠鏌ヨ', '11638', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11640', '璇峰亣鐢宠鏂板', '11638', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11641', '璇峰亣鐢宠淇敼', '11638', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11642', '璇峰亣鐢宠鍒犻櫎', '11638', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES ('11643', '璇峰亣鐢宠瀵煎嚭', '11638', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, now(), NULL, NULL, '');
+
+INSERT INTO sys_dict_type VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, now(), NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
+INSERT INTO sys_dict_type VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, now(), NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
+INSERT INTO sys_dict_type VALUES (15, '000000', '浠诲姟鐘舵��', 'wf_task_status', 103, 1, now(), NULL, NULL, '浠诲姟鐘舵��');
+INSERT INTO sys_dict_data VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸叉挙閿�');
+INSERT INTO sys_dict_data VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, now(), NULL, NULL, '鑽夌');
+INSERT INTO sys_dict_data VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '寰呭鏍�');
+INSERT INTO sys_dict_data VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, now(), NULL, NULL, '宸插畬鎴�');
+INSERT INTO sys_dict_data VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸蹭綔搴�');
+INSERT INTO sys_dict_data VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸查��鍥�');
+INSERT INTO sys_dict_data VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸茬粓姝�');
+INSERT INTO sys_dict_data VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, now(), NULL, NULL, '鑷畾涔夎〃鍗�');
+INSERT INTO sys_dict_data VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '鍔ㄦ�佽〃鍗�');
+INSERT INTO sys_dict_data VALUES (48, '000000', 1, '鎾ら攢', 'cancel', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '鎾ら攢');
+INSERT INTO sys_dict_data VALUES (49, '000000', 2, '閫氳繃', 'pass', 'wf_task_status', '', 'success', 'N', 103, 1, now(), NULL, NULL, '閫氳繃');
+INSERT INTO sys_dict_data VALUES (50, '000000', 3, '寰呭鏍�', 'waiting', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '寰呭鏍�');
+INSERT INTO sys_dict_data VALUES (51, '000000', 4, '浣滃簾', 'invalid', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '浣滃簾');
+INSERT INTO sys_dict_data VALUES (52, '000000', 5, '閫�鍥�', 'back', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '閫�鍥�');
+INSERT INTO sys_dict_data VALUES (53, '000000', 6, '缁堟', 'termination', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '缁堟');
+INSERT INTO sys_dict_data VALUES (54, '000000', 7, '杞姙', 'transfer', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '杞姙');
+INSERT INTO sys_dict_data VALUES (55, '000000', 8, '濮旀墭', 'depute', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '濮旀墭');
+INSERT INTO sys_dict_data VALUES (56, '000000', 9, '鎶勯��', 'copy', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '鎶勯��');
+INSERT INTO sys_dict_data VALUES (57, '000000', 10, '鍔犵', 'sign', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '鍔犵');
+INSERT INTO sys_dict_data VALUES (58, '000000', 11, '鍑忕', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '鍑忕');
+INSERT INTO sys_dict_data VALUES (59, '000000', 11, '瓒呮椂', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '瓒呮椂');
+
diff --git a/script/sql/snail_job.sql b/script/sql/ry_job.sql
similarity index 97%
rename from script/sql/snail_job.sql
rename to script/sql/ry_job.sql
index c3aa760..c6ec01b 100644
--- a/script/sql/snail_job.sql
+++ b/script/sql/ry_job.sql
@@ -40,13 +40,14 @@
   DEFAULT CHARSET = utf8mb4 COMMENT ='缁勯厤缃�';
 
 INSERT INTO `sj_group_config` VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
+INSERT INTO `sj_group_config` VALUES (2, 'prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
 
 CREATE TABLE `sj_notify_config`
 (
     `id`                     bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
     `namespace_id`           varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
     `group_name`             varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
-    `business_id`            varchar(64)         NOT NULL COMMENT '涓氬姟id (job_id鎴杦orkflow_id鎴杝cene_name)',
+    `notify_name`            varchar(64)         NOT NULL DEFAULT '' COMMENT '閫氱煡鍚嶇О',
     `system_task_type`       tinyint(4)          NOT NULL DEFAULT 3 COMMENT '浠诲姟绫诲瀷 1. 閲嶈瘯浠诲姟 2. 閲嶈瘯鍥炶皟 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟',
     `notify_status`          tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫氱煡鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�',
     `recipient_ids`          varchar(128)        NOT NULL COMMENT '鎺ユ敹浜篿d鍒楄〃',
@@ -58,7 +59,7 @@
     `create_dt`              datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
     `update_dt`              datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
     PRIMARY KEY (`id`),
-    KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `business_id`)
+    KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`)
 ) ENGINE = InnoDB
   AUTO_INCREMENT = 0
   DEFAULT CHARSET = utf8mb4 COMMENT ='閫氱煡閰嶇疆';
@@ -187,6 +188,7 @@
     `max_retry_count`  int(11)             NOT NULL DEFAULT 5 COMMENT '鏈�澶ч噸璇曟鏁�',
     `back_off`         tinyint(4)          NOT NULL DEFAULT 1 COMMENT '1銆侀粯璁ょ瓑绾� 2銆佸浐瀹氶棿闅旀椂闂� 3銆丆RON 琛ㄨ揪寮�',
     `trigger_interval` varchar(16)         NOT NULL DEFAULT '' COMMENT '闂撮殧鏃堕暱',
+    `notify_ids`       varchar(128)        NOT NULL DEFAULT '' COMMENT '閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃',
     `deadline_request` bigint(20) unsigned NOT NULL DEFAULT 60000 COMMENT 'Deadline Request 璋冪敤閾捐秴鏃� 鍗曚綅姣',
     `executor_timeout` int(11) unsigned    NOT NULL DEFAULT 5 COMMENT '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇',
     `route_key`        tinyint(4)          NOT NULL DEFAULT 4 COMMENT '璺敱绛栫暐',
@@ -299,6 +301,8 @@
     `retry_interval`   int(11)             NOT NULL DEFAULT 0 COMMENT '閲嶈瘯闂撮殧(s)',
     `bucket_index`     int(11)             NOT NULL DEFAULT 0 COMMENT 'bucket',
     `resident`         tinyint(4)          NOT NULL DEFAULT 0 COMMENT '鏄惁鏄父椹讳换鍔�',
+    `notify_ids`       varchar(128)        NOT NULL DEFAULT '' COMMENT '閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃',
+    `owner_id`         bigint(20)          NULL                 COMMENT '璐熻矗浜篿d',
     `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
     `ext_attrs`        varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
     `deleted`          tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎 1銆佸垹闄�',
@@ -312,7 +316,7 @@
   AUTO_INCREMENT = 0
   DEFAULT CHARSET = utf8mb4 COMMENT ='浠诲姟淇℃伅';
 
-INSERT INTO `sj_job` VALUES (1, 'dev', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', '', 0 , now(), now());
+INSERT INTO `sj_job` VALUES (1, 'dev', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1, '', '', 0 , now(), now());
 
 CREATE TABLE `sj_job_log_message`
 (
@@ -450,6 +454,7 @@
     `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
     `flow_info`        text                         DEFAULT NULL COMMENT '娴佺▼淇℃伅',
     `wf_context`       text                         DEFAULT NULL COMMENT '涓婁笅鏂�',
+    `notify_ids`       varchar(128)        NOT NULL DEFAULT '' COMMENT '閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃',
     `bucket_index`     int(11)             NOT NULL DEFAULT 0 COMMENT 'bucket',
     `version`          int(11)             NOT NULL COMMENT '鐗堟湰鍙�',
     `ext_attrs`        varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
diff --git a/script/sql/ry_vue_5.X.sql b/script/sql/ry_vue_5.X.sql
index 3e3562d..48e5f35 100644
--- a/script/sql/ry_vue_5.X.sql
+++ b/script/sql/ry_vue_5.X.sql
@@ -5,7 +5,7 @@
 (
     id                 bigint           not null        comment '涓婚敭',
     user_id            bigint           not null        comment '鐢ㄦ埛ID',
-    tenant_id          varchar(20)      default null    comment '绉熸埛id',
+    tenant_id          varchar(20)      default '000000' comment '绉熸埛id',
     auth_id            varchar(255)     not null        comment '骞冲彴+骞冲彴鍞竴id',
     source             varchar(255)     not null        comment '鐢ㄦ埛鏉ユ簮',
     open_id            varchar(255)     default null    comment '骞冲彴缂栧彿鍞竴id',
@@ -31,7 +31,7 @@
     create_time        datetime                         comment '鍒涘缓鏃堕棿',
     update_by          bigint(20)                       comment '鏇存柊鑰�',
     update_time        datetime                         comment '鏇存柊鏃堕棿',
-    del_flag           char(1)          default '0'     comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    del_flag           char(1)          default '0'     comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
     PRIMARY KEY (id)
 ) engine=innodb comment = '绀句細鍖栧叧绯昏〃';
 
@@ -55,7 +55,7 @@
     expire_time       datetime                      comment '杩囨湡鏃堕棿',
     account_count     int           default -1      comment '鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級',
     status            char(1)       default '0'     comment '绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-    del_flag          char(1)       default '0'     comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    del_flag          char(1)       default '0'     comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
     create_dept       bigint(20)                    comment '鍒涘缓閮ㄩ棬',
     create_by         bigint(20)                    comment '鍒涘缓鑰�',
     create_time       datetime                      comment '鍒涘缓鏃堕棿',
@@ -82,7 +82,7 @@
     remark                  varchar(200)               comment '澶囨敞',
     menu_check_strictly     tinyint(1)     default 1   comment '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
     status                  char(1)        default '0' comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-    del_flag                char(1)        default '0' comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    del_flag                char(1)        default '0' comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
     create_dept             bigint(20)                 comment '鍒涘缓閮ㄩ棬',
     create_by               bigint(20)                 comment '鍒涘缓鑰�',
     create_time             datetime                   comment '鍒涘缓鏃堕棿',
@@ -107,7 +107,7 @@
     phone             varchar(11)     default null               comment '鑱旂郴鐢佃瘽',
     email             varchar(50)     default null               comment '閭',
     status            char(1)         default '0'                comment '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-    del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
     create_dept       bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
     create_by         bigint(20)      default null               comment '鍒涘缓鑰�',
     create_time       datetime                                   comment '鍒涘缓鏃堕棿',
@@ -149,7 +149,7 @@
     avatar            bigint(20)                                 comment '澶村儚鍦板潃',
     password          varchar(100)    default ''                 comment '瀵嗙爜',
     status            char(1)         default '0'                comment '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-    del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
     login_ip          varchar(128)    default ''                 comment '鏈�鍚庣櫥褰旾P',
     login_date        datetime                                   comment '鏈�鍚庣櫥褰曟椂闂�',
     create_dept       bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
@@ -212,7 +212,7 @@
     menu_check_strictly  tinyint(1)      default 1                  comment '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
     dept_check_strictly  tinyint(1)      default 1                  comment '閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
     status               char(1)         not null                   comment '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-    del_flag             char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    del_flag             char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
     create_dept          bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
     create_by            bigint(20)      default null               comment '鍒涘缓鑰�',
     create_time          datetime                                   comment '鍒涘缓鏃堕棿',
@@ -441,6 +441,8 @@
 insert into sys_role_menu values ('3', '106');
 insert into sys_role_menu values ('3', '107');
 insert into sys_role_menu values ('3', '108');
+insert into sys_role_menu values ('3', '118');
+insert into sys_role_menu values ('3', '123');
 insert into sys_role_menu values ('3', '500');
 insert into sys_role_menu values ('3', '501');
 insert into sys_role_menu values ('3', '1001');
@@ -488,6 +490,12 @@
 insert into sys_role_menu values ('3', '1043');
 insert into sys_role_menu values ('3', '1044');
 insert into sys_role_menu values ('3', '1045');
+insert into sys_role_menu values ('3', '1050');
+insert into sys_role_menu values ('3', '1061');
+insert into sys_role_menu values ('3', '1062');
+insert into sys_role_menu values ('3', '1063');
+insert into sys_role_menu values ('3', '1064');
+insert into sys_role_menu values ('3', '1065');
 insert into sys_role_menu values ('3', '1500');
 insert into sys_role_menu values ('3', '1501');
 insert into sys_role_menu values ('3', '1502');
@@ -500,6 +508,25 @@
 insert into sys_role_menu values ('3', '1509');
 insert into sys_role_menu values ('3', '1510');
 insert into sys_role_menu values ('3', '1511');
+insert into sys_role_menu values ('3', '1600');
+insert into sys_role_menu values ('3', '1601');
+insert into sys_role_menu values ('3', '1602');
+insert into sys_role_menu values ('3', '1603');
+insert into sys_role_menu values ('3', '1620');
+insert into sys_role_menu values ('3', '1621');
+insert into sys_role_menu values ('3', '1622');
+insert into sys_role_menu values ('3', '1623');
+insert into sys_role_menu values ('3', '11618');
+insert into sys_role_menu values ('3', '11619');
+insert into sys_role_menu values ('3', '11629');
+insert into sys_role_menu values ('3', '11632');
+insert into sys_role_menu values ('3', '11633');
+insert into sys_role_menu values ('3', '11638');
+insert into sys_role_menu values ('3', '11639');
+insert into sys_role_menu values ('3', '11640');
+insert into sys_role_menu values ('3', '11641');
+insert into sys_role_menu values ('3', '11642');
+insert into sys_role_menu values ('3', '11643');
 insert into sys_role_menu values ('4', '5');
 insert into sys_role_menu values ('4', '1500');
 insert into sys_role_menu values ('4', '1501');
@@ -554,10 +581,10 @@
     oper_url          varchar(255)    default ''                 comment '璇锋眰URL',
     oper_ip           varchar(128)    default ''                 comment '涓绘満鍦板潃',
     oper_location     varchar(255)    default ''                 comment '鎿嶄綔鍦扮偣',
-    oper_param        varchar(2000)   default ''                 comment '璇锋眰鍙傛暟',
-    json_result       varchar(2000)   default ''                 comment '杩斿洖鍙傛暟',
+    oper_param        varchar(4000)   default ''                 comment '璇锋眰鍙傛暟',
+    json_result       varchar(4000)   default ''                 comment '杩斿洖鍙傛暟',
     status            int(1)          default 0                  comment '鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�',
-    error_msg         varchar(2000)   default ''                 comment '閿欒娑堟伅',
+    error_msg         varchar(4000)   default ''                 comment '閿欒娑堟伅',
     oper_time         datetime                                   comment '鎿嶄綔鏃堕棿',
     cost_time         bigint(20)      default 0                  comment '娑堣�楁椂闂�',
     primary key (oper_id),
@@ -840,7 +867,7 @@
 insert into sys_oss_config values (1, '000000', 'minio',  'ruoyi',            'ruoyi123',        'ruoyi',             '', '127.0.0.1:9000',                '','N', '',             '1' ,'0', '', 103, 1, sysdate(), 1, sysdate(), null);
 insert into sys_oss_config values (2, '000000', 'qiniu',  'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 's3-cn-north-1.qiniucs.com',     '','N', '',             '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null);
 insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 'oss-cn-beijing.aliyuncs.com',   '','N', '',             '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null);
-insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi-1250000000',  '', 'cos.ap-beijing.myqcloud.com',   '','N', 'ap-beijing',   '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null);
+insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi-1240000000',  '', 'cos.ap-beijing.myqcloud.com',   '','N', 'ap-beijing',   '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null);
 insert into sys_oss_config values (5, '000000', 'image',  'ruoyi',            'ruoyi123',        'ruoyi',             'image', '127.0.0.1:9000',           '','N', '',             '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null);
 
 -- ----------------------------
@@ -856,7 +883,7 @@
     active_timeout      int(11)       default 1800        comment 'token娲昏穬瓒呮椂鏃堕棿',
     timeout             int(11)       default 604800      comment 'token鍥哄畾瓒呮椂',
     status              char(1)       default '0'         comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
-    del_flag            char(1)       default '0'         comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    del_flag            char(1)       default '0'         comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
     create_dept         bigint(20)    default null        comment '鍒涘缓閮ㄩ棬',
     create_by           bigint(20)    default null        comment '鍒涘缓鑰�',
     create_time         datetime      default null        comment '鍒涘缓鏃堕棿',
diff --git a/script/sql/ry_workflow.sql b/script/sql/ry_workflow.sql
new file mode 100644
index 0000000..9455636
--- /dev/null
+++ b/script/sql/ry_workflow.sql
@@ -0,0 +1,253 @@
+-- ----------------------------
+-- 0銆亀arm-flow-all.sql锛屽湴鍧�锛歨ttps://gitee.com/dromara/warm-flow/blob/master/sql/mysql/warm-flow-all.sql
+-- ----------------------------
+CREATE TABLE `flow_definition`
+(
+    `id`              bigint unsigned NOT NULL COMMENT '涓婚敭id',
+    `flow_code`       varchar(40)     NOT NULL COMMENT '娴佺▼缂栫爜',
+    `flow_name`       varchar(100)    NOT NULL COMMENT '娴佺▼鍚嶇О',
+    `category`        varchar(100)             DEFAULT NULL COMMENT '娴佺▼绫诲埆',
+    `version`         varchar(20)     NOT NULL COMMENT '娴佺▼鐗堟湰',
+    `is_publish`      tinyint(1)      NOT NULL DEFAULT '0' COMMENT '鏄惁鍙戝竷锛�0鏈彂甯� 1宸插彂甯� 9澶辨晥锛�',
+    `form_custom`     char(1)                  DEFAULT 'N' COMMENT '瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級',
+    `form_path`       varchar(100)             DEFAULT NULL COMMENT '瀹℃壒琛ㄥ崟璺緞',
+    `activity_status` tinyint(1)      NOT NULL DEFAULT '1' COMMENT '娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級',
+    `listener_type`   varchar(100)             DEFAULT NULL COMMENT '鐩戝惉鍣ㄧ被鍨�',
+    `listener_path`   varchar(400)             DEFAULT NULL COMMENT '鐩戝惉鍣ㄨ矾寰�',
+    `ext`             varchar(500)             DEFAULT NULL COMMENT '涓氬姟璇︽儏 瀛樹笟鍔¤〃瀵硅薄json瀛楃涓�',
+    `create_time`     datetime                 DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+    `update_time`     datetime                 DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+    `del_flag`        char(1)                  DEFAULT '0' COMMENT '鍒犻櫎鏍囧織',
+    `tenant_id`       varchar(40)              DEFAULT NULL COMMENT '绉熸埛id',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='娴佺▼瀹氫箟琛�';
+
+CREATE TABLE `flow_node`
+(
+    `id`              bigint unsigned NOT NULL COMMENT '涓婚敭id',
+    `node_type`       tinyint(1)      NOT NULL COMMENT '鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+    `definition_id`   bigint          NOT NULL COMMENT '娴佺▼瀹氫箟id',
+    `node_code`       varchar(100)    NOT NULL COMMENT '娴佺▼鑺傜偣缂栫爜',
+    `node_name`       varchar(100)  DEFAULT NULL COMMENT '娴佺▼鑺傜偣鍚嶇О',
+    `permission_flag` varchar(200)  DEFAULT NULL COMMENT '鏉冮檺鏍囪瘑锛堟潈闄愮被鍨�:鏉冮檺鏍囪瘑锛屽彲浠ュ涓紝鐢ㄩ�楀彿闅斿紑)',
+    `node_ratio`      decimal(6, 3) DEFAULT NULL COMMENT '娴佺▼绛剧讲姣斾緥鍊�',
+    `coordinate`      varchar(100)  DEFAULT NULL COMMENT '鍧愭爣',
+    `skip_any_node`   varchar(100)  DEFAULT 'N' COMMENT '鏄惁鍙互閫�鍥炰换鎰忚妭鐐癸紙Y鏄� N鍚︼級鍗冲皢鍒犻櫎',
+    `any_node_skip`   varchar(100)  DEFAULT NULL COMMENT '浠绘剰缁撶偣璺宠浆',
+    `listener_type`   varchar(100)  DEFAULT NULL COMMENT '鐩戝惉鍣ㄧ被鍨�',
+    `listener_path`   varchar(400)  DEFAULT NULL COMMENT '鐩戝惉鍣ㄨ矾寰�',
+    `handler_type`    varchar(100)  DEFAULT NULL COMMENT '澶勭悊鍣ㄧ被鍨�',
+    `handler_path`    varchar(400)  DEFAULT NULL COMMENT '澶勭悊鍣ㄨ矾寰�',
+    `form_custom`     char(1)       DEFAULT 'N' COMMENT '瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級',
+    `form_path`       varchar(100)  DEFAULT NULL COMMENT '瀹℃壒琛ㄥ崟璺緞',
+    `version`         varchar(20)     NOT NULL COMMENT '鐗堟湰',
+    `create_time`     datetime      DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+    `update_time`     datetime      DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+    `del_flag`        char(1)       DEFAULT '0' COMMENT '鍒犻櫎鏍囧織',
+    `tenant_id`       varchar(40)   DEFAULT NULL COMMENT '绉熸埛id',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='娴佺▼鑺傜偣琛�';
+
+CREATE TABLE `flow_skip`
+(
+    `id`             bigint unsigned NOT NULL COMMENT '涓婚敭id',
+    `definition_id`  bigint          NOT NULL COMMENT '娴佺▼瀹氫箟id',
+    `now_node_code`  varchar(100)    NOT NULL COMMENT '褰撳墠娴佺▼鑺傜偣鐨勭紪鐮�',
+    `now_node_type`  tinyint(1)   DEFAULT NULL COMMENT '褰撳墠鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+    `next_node_code` varchar(100)    NOT NULL COMMENT '涓嬩竴涓祦绋嬭妭鐐圭殑缂栫爜',
+    `next_node_type` tinyint(1)   DEFAULT NULL COMMENT '涓嬩竴涓妭鐐圭被鍨嬶紙0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+    `skip_name`      varchar(100) DEFAULT NULL COMMENT '璺宠浆鍚嶇О',
+    `skip_type`      varchar(40)  DEFAULT NULL COMMENT '璺宠浆绫诲瀷锛圥ASS瀹℃壒閫氳繃 REJECT閫�鍥烇級',
+    `skip_condition` varchar(200) DEFAULT NULL COMMENT '璺宠浆鏉′欢',
+    `coordinate`     varchar(100) DEFAULT NULL COMMENT '鍧愭爣',
+    `create_time`    datetime     DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+    `update_time`    datetime     DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+    `del_flag`       char(1)      DEFAULT '0' COMMENT '鍒犻櫎鏍囧織',
+    `tenant_id`      varchar(40)  DEFAULT NULL COMMENT '绉熸埛id',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='鑺傜偣璺宠浆鍏宠仈琛�';
+
+CREATE TABLE `flow_instance`
+(
+    `id`              bigint      NOT NULL COMMENT '涓婚敭id',
+    `definition_id`   bigint      NOT NULL COMMENT '瀵瑰簲flow_definition琛ㄧ殑id',
+    `business_id`     varchar(40) NOT NULL COMMENT '涓氬姟id',
+    `node_type`       tinyint(1)  NOT NULL COMMENT '鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+    `node_code`       varchar(40) NOT NULL COMMENT '娴佺▼鑺傜偣缂栫爜',
+    `node_name`       varchar(100)         DEFAULT NULL COMMENT '娴佺▼鑺傜偣鍚嶇О',
+    `variable`        text COMMENT '浠诲姟鍙橀噺',
+    `flow_status`     varchar(20) NOT NULL COMMENT '娴佺▼鐘舵�侊紙0寰呮彁浜� 1瀹℃壒涓� 2 瀹℃壒閫氳繃 3鑷姩閫氳繃 4缁堟 5浣滃簾 6鎾ら攢 7鍙栧洖  8宸插畬鎴� 9宸查��鍥� 10澶辨晥锛�',
+    `activity_status` tinyint(1)  NOT NULL DEFAULT '1' COMMENT '娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級',
+    `def_json`        text COMMENT '娴佺▼瀹氫箟json',
+    `create_by`       varchar(64)          DEFAULT '' COMMENT '鍒涘缓鑰�',
+    `create_time`     datetime             DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+    `update_time`     datetime             DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+    `ext`             varchar(500)         DEFAULT NULL COMMENT '鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤',
+    `del_flag`        char(1)              DEFAULT '0' COMMENT '鍒犻櫎鏍囧織',
+    `tenant_id`       varchar(40)          DEFAULT NULL COMMENT '绉熸埛id',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='娴佺▼瀹炰緥琛�';
+
+CREATE TABLE `flow_task`
+(
+    `id`            bigint       NOT NULL COMMENT '涓婚敭id',
+    `definition_id` bigint       NOT NULL COMMENT '瀵瑰簲flow_definition琛ㄧ殑id',
+    `instance_id`   bigint       NOT NULL COMMENT '瀵瑰簲flow_instance琛ㄧ殑id',
+    `node_code`     varchar(100) NOT NULL COMMENT '鑺傜偣缂栫爜',
+    `node_name`     varchar(100) DEFAULT NULL COMMENT '鑺傜偣鍚嶇О',
+    `node_type`     tinyint(1)   NOT NULL COMMENT '鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+    `form_custom`   char(1)      DEFAULT 'N' COMMENT '瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級',
+    `form_path`     varchar(100) DEFAULT NULL COMMENT '瀹℃壒琛ㄥ崟璺緞',
+    `create_time`   datetime     DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+    `update_time`   datetime     DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+    `del_flag`      char(1)      DEFAULT '0' COMMENT '鍒犻櫎鏍囧織',
+    `tenant_id`     varchar(40)  DEFAULT NULL COMMENT '绉熸埛id',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='寰呭姙浠诲姟琛�';
+
+CREATE TABLE `flow_his_task`
+(
+    `id`               bigint(20) unsigned NOT NULL COMMENT '涓婚敭id',
+    `definition_id`    bigint(20)          NOT NULL COMMENT '瀵瑰簲flow_definition琛ㄧ殑id',
+    `instance_id`      bigint(20)          NOT NULL COMMENT '瀵瑰簲flow_instance琛ㄧ殑id',
+    `task_id`          bigint(20)          NOT NULL COMMENT '瀵瑰簲flow_task琛ㄧ殑id',
+    `node_code`        varchar(100)                 DEFAULT NULL COMMENT '寮�濮嬭妭鐐圭紪鐮�',
+    `node_name`        varchar(100)                 DEFAULT NULL COMMENT '寮�濮嬭妭鐐瑰悕绉�',
+    `node_type`        tinyint(1)                   DEFAULT NULL COMMENT '寮�濮嬭妭鐐圭被鍨嬶紙0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+    `target_node_code` varchar(200)                 DEFAULT NULL COMMENT '鐩爣鑺傜偣缂栫爜',
+    `target_node_name` varchar(200)                 DEFAULT NULL COMMENT '缁撴潫鑺傜偣鍚嶇О',
+    `approver`         varchar(40)                  DEFAULT NULL COMMENT '瀹℃壒鑰�',
+    `cooperate_type`   tinyint(1)          NOT NULL DEFAULT '0' COMMENT '鍗忎綔鏂瑰紡(1瀹℃壒 2杞姙 3濮旀淳 4浼氱 5绁ㄧ 6鍔犵 7鍑忕)',
+    `collaborator`     varchar(40)                  DEFAULT NULL COMMENT '鍗忎綔浜�',
+    `skip_type`        varchar(10)         NOT NULL COMMENT '娴佽浆绫诲瀷锛圥ASS閫氳繃 REJECT閫�鍥� NONE鏃犲姩浣滐級',
+    `flow_status`      varchar(20)         NOT NULL COMMENT '娴佺▼鐘舵�侊紙1瀹℃壒涓� 2 瀹℃壒閫氳繃 9宸查��鍥� 10澶辨晥锛�',
+    `form_custom`      char(1)                      DEFAULT 'N' COMMENT '瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級',
+    `form_path`        varchar(100)                 DEFAULT NULL COMMENT '瀹℃壒琛ㄥ崟璺緞',
+    `message`          varchar(500)                 DEFAULT NULL COMMENT '瀹℃壒鎰忚',
+    `variable`         TEXT                         DEFAULT NULL COMMENT '浠诲姟鍙橀噺',
+    `ext`              varchar(500)                 DEFAULT NULL COMMENT '涓氬姟璇︽儏 瀛樹笟鍔¤〃瀵硅薄json瀛楃涓�',
+    `create_time`      datetime                     DEFAULT NULL COMMENT '浠诲姟寮�濮嬫椂闂�',
+    `update_time`      datetime                     DEFAULT NULL COMMENT '瀹℃壒瀹屾垚鏃堕棿',
+    `del_flag`         char(1)                      DEFAULT '0' COMMENT '鍒犻櫎鏍囧織',
+    `tenant_id`        varchar(40)                  DEFAULT NULL COMMENT '绉熸埛id',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='鍘嗗彶浠诲姟璁板綍琛�';
+
+
+CREATE TABLE `flow_user`
+(
+    `id`           bigint unsigned NOT NULL COMMENT '涓婚敭id',
+    `type`         char(1)         NOT NULL COMMENT '浜哄憳绫诲瀷锛�1寰呭姙浠诲姟鐨勫鎵逛汉鏉冮檺 2寰呭姙浠诲姟鐨勮浆鍔炰汉鏉冮檺 3寰呭姙浠诲姟鐨勫鎵樹汉鏉冮檺锛�',
+    `processed_by` varchar(80) DEFAULT NULL COMMENT '鏉冮檺浜�',
+    `associated`   bigint          NOT NULL COMMENT '浠诲姟琛╥d',
+    `create_time`  datetime    DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+    `create_by`    varchar(80) DEFAULT NULL COMMENT '鍒涘缓浜�',
+    `update_time`  datetime    DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+    `del_flag`     char(1)     DEFAULT '0' COMMENT '鍒犻櫎鏍囧織',
+    `tenant_id`    varchar(40) DEFAULT NULL COMMENT '绉熸埛id',
+    PRIMARY KEY (`id`) USING BTREE,
+    KEY `user_processed_type` (`processed_by`, `type`)
+) ENGINE = InnoDB COMMENT ='娴佺▼鐢ㄦ埛琛�';
+
+-- ----------------------------
+-- 娴佺▼鍒嗙被琛�
+-- ----------------------------
+create table flow_category
+(
+    category_id   bigint(20)  not null comment '娴佺▼鍒嗙被ID',
+    tenant_id     varchar(20)  default '000000' comment '绉熸埛缂栧彿',
+    parent_id     bigint(20)   default 0 comment '鐖舵祦绋嬪垎绫籭d',
+    ancestors     varchar(500) default '' comment '绁栫骇鍒楄〃',
+    category_name varchar(30) not null comment '娴佺▼鍒嗙被鍚嶇О',
+    order_num     int(4)       default 0 comment '鏄剧ず椤哄簭',
+    del_flag      char(1)      default '0' comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
+    create_dept   bigint(20)  null comment '鍒涘缓閮ㄩ棬',
+    create_by     bigint(20)  null comment '鍒涘缓鑰�',
+    create_time   datetime    null comment '鍒涘缓鏃堕棿',
+    update_by     bigint(20)  null comment '鏇存柊鑰�',
+    update_time   datetime    null comment '鏇存柊鏃堕棿',
+    primary key (category_id)
+) engine = innodb comment = '娴佺▼鍒嗙被';
+
+INSERT INTO flow_category values (100, '000000', 0, '0', 'OA瀹℃壒', 0, '0', 103, 1, sysdate(), null, null);
+INSERT INTO flow_category values (101, '000000', 100, '0,100', '鍋囧嫟绠$悊', 0, '0', 103, 1, sysdate(), null, null);
+INSERT INTO flow_category values (102, '000000', 100, '0,100', '浜轰簨绠$悊', 1, '0', 103, 1, sysdate(), null, null);
+INSERT INTO flow_category values (103, '000000', 101, '0,100,101', '璇峰亣', 0, '0', 103, 1, sysdate(), null, null);
+INSERT INTO flow_category values (104, '000000', 101, '0,100,101', '鍑哄樊', 1, '0', 103, 1, sysdate(), null, null);
+INSERT INTO flow_category values (105, '000000', 101, '0,100,101', '鍔犵彮', 2, '0', 103, 1, sysdate(), null, null);
+INSERT INTO flow_category values (106, '000000', 101, '0,100,101', '鎹㈢彮', 3, '0', 103, 1, sysdate(), null, null);
+INSERT INTO flow_category values (107, '000000', 101, '0,100,101', '澶栧嚭', 4, '0', 103, 1, sysdate(), null, null);
+INSERT INTO flow_category values (108, '000000', 102, '0,100,102', '杞', 1, '0', 103, 1, sysdate(), null, null);
+INSERT INTO flow_category values (109, '000000', 102, '0,100,102', '绂昏亴', 2, '0', 103, 1, sysdate(), null, null);
+
+-- ----------------------------
+-- 璇峰亣鍗曚俊鎭�
+-- ----------------------------
+create table test_leave
+(
+    id          bigint(20)   not null comment 'id',
+    tenant_id   varchar(20) default '000000' comment '绉熸埛缂栧彿',
+    leave_type  varchar(255) not null comment '璇峰亣绫诲瀷',
+    start_date  datetime     not null comment '寮�濮嬫椂闂�',
+    end_date    datetime     not null comment '缁撴潫鏃堕棿',
+    leave_days  int(10)      not null comment '璇峰亣澶╂暟',
+    remark      varchar(255) null comment '璇峰亣鍘熷洜',
+    status      varchar(255) null comment '鐘舵��',
+    create_dept bigint       null comment '鍒涘缓閮ㄩ棬',
+    create_by   bigint       null comment '鍒涘缓鑰�',
+    create_time datetime     null comment '鍒涘缓鏃堕棿',
+    update_by   bigint       null comment '鏇存柊鑰�',
+    update_time datetime     null comment '鏇存柊鏃堕棿',
+    PRIMARY KEY (id) USING BTREE
+) ENGINE = InnoDB COMMENT = '璇峰亣鐢宠琛�';
+
+insert into sys_menu values ('11616', '宸ヤ綔娴�', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, sysdate(),NULL, NULL, '');
+insert into sys_menu values ('11618', '鎴戠殑浠诲姟', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values ('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values ('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values ('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values ('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values ('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values ('11622', '娴佺▼鍒嗙被', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values ('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values ('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values ('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, '');
+-- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1,sysdate(), null, null, '');
+insert into sys_menu values ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add', '#', 103, 1,sysdate(), null, null, '');
+insert into sys_menu values ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit', '#', 103, 1,sysdate(), null, null, '');
+insert into sys_menu values ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove', '#', 103,1, sysdate(), null, null, '');
+insert into sys_menu values ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export', '#', 103,1, sysdate(), null, null, '');
+-- 璇峰亣娴嬭瘯鐩稿叧鎸夐挳
+insert into sys_menu VALUES (11638, '璇峰亣鐢宠',     5,    1, 'leave', 'workflow/leave/index', '', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '璇峰亣鐢宠鑿滃崟');
+insert into sys_menu VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu VALUES (11640, '璇峰亣鐢宠鏂板', 11638, 2, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu VALUES (11641, '璇峰亣鐢宠淇敼', 11638, 3, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu VALUES (11642, '璇峰亣鐢宠鍒犻櫎', 11638, 4, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu VALUES (11643, '璇峰亣鐢宠瀵煎嚭', 11638, 5, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate(), NULL, NULL, '');
+
+INSERT INTO sys_dict_type VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, sysdate(), NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
+INSERT INTO sys_dict_type VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, sysdate(), NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
+INSERT INTO sys_dict_type VALUES (15, '000000', '浠诲姟鐘舵��', 'wf_task_status', 103, 1, sysdate(), NULL, NULL, '浠诲姟鐘舵��');
+INSERT INTO sys_dict_data VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL,'宸叉挙閿�');
+INSERT INTO sys_dict_data VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, sysdate(), NULL, NULL, '鑽夌');
+INSERT INTO sys_dict_data VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL,'寰呭鏍�');
+INSERT INTO sys_dict_data VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL,'宸插畬鎴�');
+INSERT INTO sys_dict_data VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL,'宸蹭綔搴�');
+INSERT INTO sys_dict_data VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL,'宸查��鍥�');
+INSERT INTO sys_dict_data VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL,NULL, '宸茬粓姝�');
+INSERT INTO sys_dict_data VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL,'鑷畾涔夎〃鍗�');
+INSERT INTO sys_dict_data VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL,'鍔ㄦ�佽〃鍗�');
+INSERT INTO sys_dict_data VALUES (48, '000000', 1, '鎾ら攢', 'cancel', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '鎾ら攢');
+INSERT INTO sys_dict_data VALUES (49, '000000', 2, '閫氳繃', 'pass', 'wf_task_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '閫氳繃');
+INSERT INTO sys_dict_data VALUES (50, '000000', 3, '寰呭鏍�', 'waiting', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '寰呭鏍�');
+INSERT INTO sys_dict_data VALUES (51, '000000', 4, '浣滃簾', 'invalid', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '浣滃簾');
+INSERT INTO sys_dict_data VALUES (52, '000000', 5, '閫�鍥�', 'back', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '閫�鍥�');
+INSERT INTO sys_dict_data VALUES (53, '000000', 6, '缁堟', 'termination', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '缁堟');
+INSERT INTO sys_dict_data VALUES (54, '000000', 7, '杞姙', 'transfer', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '杞姙');
+INSERT INTO sys_dict_data VALUES (55, '000000', 8, '濮旀墭', 'depute', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '濮旀墭');
+INSERT INTO sys_dict_data VALUES (56, '000000', 9, '鎶勯��', 'copy', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '鎶勯��');
+INSERT INTO sys_dict_data VALUES (57, '000000', 10, '鍔犵', 'sign', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '鍔犵');
+INSERT INTO sys_dict_data VALUES (58, '000000', 11, '鍑忕', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '鍑忕');
+INSERT INTO sys_dict_data VALUES (59, '000000', 11, '瓒呮椂', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '瓒呮椂');
+
diff --git a/script/sql/sqlserver/flowable.sql b/script/sql/sqlserver/flowable.sql
deleted file mode 100644
index 2397c35..0000000
--- a/script/sql/sqlserver/flowable.sql
+++ /dev/null
@@ -1,456 +0,0 @@
-insert into sys_menu values('11616', '宸ヤ綔娴�'  , '0',    '6', 'workflow',          '',                                 '', '1', '0', 'M', '0', '0', '',                       'workflow', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11617', '妯″瀷绠$悊', '11616', '2', 'model',             'workflow/model/index',             '', '1', '1', 'C', '0', '0', 'workflow:model:list',    'model', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11618', '鎴戠殑浠诲姟', '0', '7', 'task',              '',                                 '', '1', '0', 'M', '0', '0', '',                       'my-task', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting',       'workflow/task/taskWaiting',              '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish',       'workflow/task/taskFinish',              '', '1', '1', 'C', '0', '0', '',                       'finish', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList',       'workflow/task/taskCopyList',              '', '1', '1', 'C', '0', '0', '',                       'my-copy', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '',                       'process-definition', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance',   'workflow/processInstance/index',   '', '1', '1', 'C', '0', '0', '',                       'tree-table', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11622', '娴佺▼鍒嗙被', '11616', '1', 'category',          'workflow/category/index',          '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument',        'workflow/task/myDocument',         '', '1', '1', 'C', '0', '0', '',                       'guide', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor',           '',                                 '', '1', '0', 'M', '0', '0', '',                       'monitor', 103, 1, getdate(), NULL, NULL, '');
-insert into sys_menu values('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting',    'workflow/task/allTaskWaiting',     '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, getdate(), NULL, NULL, '');
-
-
--- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
-insert into sys_menu values ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, getdate(), null, null, '');
-insert into sys_menu values ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add',   '#', 103, 1, getdate(), null, null, '');
-insert into sys_menu values ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit',  '#', 103, 1, getdate(), null, null, '');
-insert into sys_menu values ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, getdate(), null, null, '');
-insert into sys_menu values ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, getdate(), null, null, '');
--- 璇峰亣鍗曚俊鎭�
-create table test_leave
-(
-    id          bigint        not null
-        primary key,
-    leave_type  nvarchar(255) not null,
-    start_date  datetime2     not null,
-    end_date    datetime2     not null,
-    leave_days  int           not null,
-    remark      nvarchar(255),
-    status      nvarchar(255),
-    create_dept bigint,
-    create_by   bigint,
-    create_time datetime2,
-    update_by   bigint,
-    update_time datetime2,
-    tenant_id   nvarchar(20)
-)
-go
-
-exec sp_addextendedproperty 'MS_Description', N'璇峰亣鐢宠琛�', 'SCHEMA', 'dbo', 'TABLE', 'test_leave'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'璇峰亣绫诲瀷', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
-     'leave_type'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'寮�濮嬫椂闂�', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
-     'start_date'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'缁撴潫鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'end_date'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'璇峰亣澶╂暟', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
-     'leave_days'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'璇峰亣鍘熷洜', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'remark'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鐘舵��', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'status'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
-     'create_dept'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'create_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
-     'create_time'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'update_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
-     'update_time'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'tenant_id'
-go
-
--- 娴佺▼鍒嗙被淇℃伅琛�
-create table wf_category
-(
-    id            bigint not null
-        primary key,
-    category_name nvarchar(255),
-    category_code nvarchar(255)
-        constraint uni_category_code
-        unique,
-    parent_id     bigint,
-    sort_num      int,
-    tenant_id     nvarchar(20),
-    create_dept   bigint,
-    create_by     bigint,
-    create_time   datetime2,
-    update_by     bigint,
-    update_time   datetime2
-)
-go
-
-exec sp_addextendedproperty 'MS_Description', N'娴佺▼鍒嗙被', 'SCHEMA', 'dbo', 'TABLE', 'wf_category'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒嗙被鍚嶇О', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
-     'category_name'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒嗙被缂栫爜', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
-     'category_code'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鐖剁骇id', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'parent_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鎺掑簭', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'sort_num'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
-     'tenant_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
-     'create_dept'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'create_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
-     'create_time'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'update_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
-     'update_time'
-go
-
-INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, getdate(), 1, getdate());
-
-create table wf_task_back_node
-(
-    id            bigint not null primary key,
-    node_id       nvarchar(255) not null,
-    node_name     nvarchar(255) not null,
-    order_no      int not null,
-    instance_id   nvarchar(255) not null,
-    task_type     nvarchar(255) not null,
-    assignee      nvarchar(2000) not null,
-    tenant_id     nvarchar(20),
-    create_dept   bigint,
-    create_by     bigint,
-    create_time   datetime2,
-    update_by     bigint,
-    update_time   datetime2
-)
-
-go
-exec sp_addextendedproperty 'MS_Description', N'鑺傜偣瀹℃壒璁板綍', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鑺傜偣id', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
-     'node_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鑺傜偣鍚嶇О', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
-     'node_name'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鎺掑簭', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'order_no'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'娴佺▼瀹炰緥id', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'instance_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鑺傜偣绫诲瀷', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'task_type'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'瀹℃壒浜�', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'assignee'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
-     'tenant_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
-     'create_dept'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'create_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
-     'create_time'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'update_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
-     'update_time'
-go
-
-create table wf_definition_config
-(
-    id            bigint not null primary key,
-    table_name    nvarchar(255)  not null,
-    definition_id nvarchar(255)  not null
-        constraint uni_definition_id
-        unique,
-    process_key   nvarchar(255)  not null,
-    version       bigint         not null,
-    remark        nvarchar(500) DEFAULT ('') null,
-    tenant_id     nvarchar(20),
-    create_dept   bigint,
-    create_by     bigint,
-    create_time   datetime2,
-    update_by     bigint,
-    update_time   datetime2
-)
-
-go
-exec sp_addextendedproperty 'MS_Description', N'娴佺▼瀹氫箟閰嶇疆', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', 'id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'琛ㄥ悕', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
-     'table_name'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'娴佺▼瀹氫箟ID', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
-     'definition_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'娴佺▼KEY', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
-     'process_key'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'娴佺▼鐗堟湰', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
-     'version'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'澶囨敞', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
-     'remark'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
-     'tenant_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
-     'create_dept'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', 'create_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
-     'create_time'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', 'update_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
-     'update_time'
-go
-
-create table wf_form_manage
-(
-    id            bigint not null primary key,
-    form_name     nvarchar(255) not null,
-    form_type     nvarchar(255) not null,
-    router        nvarchar(255) not null,
-    remark        nvarchar(500) null,
-    tenant_id     nvarchar(20),
-    create_dept   bigint,
-    create_by     bigint,
-    create_time   datetime2,
-    update_by     bigint,
-    update_time   datetime2
-)
-
-go
-exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟绠$悊', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', 'id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟鍚嶇О', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
-     'form_name'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟绫诲瀷', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
-     'form_type'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'璺敱鍦板潃/琛ㄥ崟ID', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
-     'router'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'澶囨敞', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
-     'remark'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
-     'tenant_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
-     'create_dept'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', 'create_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
-     'create_time'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', 'update_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
-     'update_time'
-go
-
-insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '璇峰亣鐢宠', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, getdate(), 1, getdate());
-
-create table wf_node_config
-(
-    id               bigint not null primary key,
-    form_id          bigint,
-    form_type        nvarchar(255) ,
-    node_name        nvarchar(255) not null,
-    node_id          nvarchar(255) not null,
-    definition_id    nvarchar(255) not null,
-    apply_user_task  nchar default ('0')  null,
-    tenant_id        nvarchar(20),
-    create_dept      bigint,
-    create_by        bigint,
-    create_time      datetime2,
-    update_by        bigint,
-    update_time      datetime2
-)
-
-go
-exec sp_addextendedproperty 'MS_Description', N'鑺傜偣閰嶇疆', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', 'id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟id', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'form_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟绫诲瀷', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'form_type'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鑺傜偣鍚嶇О', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'node_name'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鑺傜偣id', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'node_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'娴佺▼瀹氫箟id', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'definition_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'apply_user_task'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'tenant_id'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'create_dept'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', 'create_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'create_time'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', 'update_by'
-go
-
-exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
-     'update_time'
-go
-
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '璇峰亣鐢宠', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, getdate(), NULL, NULL, '璇峰亣鐢宠鑿滃崟');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, getdate(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '璇峰亣鐢宠鏂板', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, getdate(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '璇峰亣鐢宠淇敼', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, getdate(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '璇峰亣鐢宠鍒犻櫎', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, getdate(), NULL, NULL, '');
-INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '璇峰亣鐢宠瀵煎嚭', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, getdate(), NULL, NULL, '');
-
-INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, getdate(), NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
-INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, getdate(), NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
-
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, getdate(), NULL, NULL, '宸叉挙閿�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, getdate(), NULL, NULL, '鑽夌');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,getdate(), NULL, NULL, '寰呭鏍�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, getdate(), NULL, NULL, '宸插畬鎴�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, getdate(), NULL, NULL, '宸蹭綔搴�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, getdate(), NULL, NULL, '宸查��鍥�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,getdate(), NULL, NULL, '宸茬粓姝�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, getdate(), NULL, NULL, '鑷畾涔夎〃鍗�');
-INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, getdate(), NULL, NULL, '鍔ㄦ�佽〃鍗�');
-
--- 琛ㄥ崟绠$悊 SQL
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11628, '琛ㄥ崟绠$悊', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, getdate(), null, null, '琛ㄥ崟绠$悊鑿滃崟');
-
--- 琛ㄥ崟绠$悊鎸夐挳 SQL
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11644, '琛ㄥ崟绠$悊鏌ヨ', 11628, '1',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query',        '', 103, 1, getdate(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11645, '琛ㄥ崟绠$悊鏂板', 11628, '2',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add',          '', 103, 1, getdate(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11646, '琛ㄥ崟绠$悊淇敼', 11628, '3',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit',         '', 103, 1, getdate(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11647, '琛ㄥ崟绠$悊鍒犻櫎', 11628, '4',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove',       '', 103, 1, getdate(), null, null, '');
-
-insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
-values(11648, '琛ㄥ崟绠$悊瀵煎嚭', 11628, '5',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export',       'tree-table', 103, 1, getdate(), null, null, '');
diff --git a/script/sql/sqlserver/snail_job_sqlserver.sql b/script/sql/sqlserver/sqlserver_ry_job.sql
similarity index 97%
rename from script/sql/sqlserver/snail_job_sqlserver.sql
rename to script/sql/sqlserver/sqlserver_ry_job.sql
index 249842b..97addc3 100644
--- a/script/sql/sqlserver/snail_job_sqlserver.sql
+++ b/script/sql/sqlserver/sqlserver_ry_job.sql
@@ -2,7 +2,7 @@
  SnailJob Database Transfer Tool
  Source Server Type    : MySQL
  Target Server Type    : Microsoft SQL Server
- Date: 2024-07-06 12:55:47
+ Date: 2024-12-27 22:24:37
 */
 
 
@@ -203,6 +203,8 @@
 
 INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate())
 GO
+INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'prod', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate())
+GO
 
 -- sj_notify_config
 CREATE TABLE sj_notify_config
@@ -210,7 +212,7 @@
     id                     bigint        NOT NULL PRIMARY KEY IDENTITY,
     namespace_id           nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
     group_name             nvarchar(64)  NOT NULL,
-    business_id            nvarchar(64)  NOT NULL,
+    notify_name            nvarchar(64)  NOT NULL DEFAULT '',
     system_task_type       tinyint       NOT NULL DEFAULT 3,
     notify_status          tinyint       NOT NULL DEFAULT 0,
     recipient_ids          nvarchar(128) NOT NULL,
@@ -224,7 +226,7 @@
 )
 GO
 
-CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name, business_id)
+CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name)
 GO
 
 EXEC sp_addextendedproperty
@@ -249,10 +251,10 @@
 GO
 
 EXEC sp_addextendedproperty
-     'MS_Description', N'涓氬姟id  ( job_id鎴杦orkflow_id鎴杝cene_name ) ',
+     'MS_Description', N'閫氱煡鍚嶇О',
      'SCHEMA', N'dbo',
      'TABLE', N'sj_notify_config',
-     'COLUMN', N'business_id'
+     'COLUMN', N'notify_name'
 GO
 
 EXEC sp_addextendedproperty
@@ -915,6 +917,7 @@
     max_retry_count  int           NOT NULL DEFAULT 5,
     back_off         tinyint       NOT NULL DEFAULT 1,
     trigger_interval nvarchar(16)  NOT NULL DEFAULT '',
+    notify_ids       nvarchar(128) NOT NULL DEFAULT '',
     deadline_request bigint        NOT NULL DEFAULT 60000,
     executor_timeout int           NOT NULL DEFAULT 5,
     route_key        tinyint       NOT NULL DEFAULT 4,
@@ -981,6 +984,13 @@
      'SCHEMA', N'dbo',
      'TABLE', N'sj_retry_scene_config',
      'COLUMN', N'trigger_interval'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'notify_ids'
 GO
 
 EXEC sp_addextendedproperty
@@ -1413,6 +1423,8 @@
     retry_interval   int           NOT NULL DEFAULT 0,
     bucket_index     int           NOT NULL DEFAULT 0,
     resident         tinyint       NOT NULL DEFAULT 0,
+    notify_ids       nvarchar(128) NOT NULL DEFAULT '',
+    owner_id         bigint        NULL,
     description      nvarchar(256) NOT NULL DEFAULT '',
     ext_attrs        nvarchar(256) NULL     DEFAULT '',
     deleted          tinyint       NOT NULL DEFAULT 0,
@@ -1576,6 +1588,20 @@
 GO
 
 EXEC sp_addextendedproperty
+     'MS_Description', N'閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'notify_ids'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'璐熻矗浜篿d',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'owner_id'
+GO
+
+EXEC sp_addextendedproperty
      'MS_Description', N'鎻忚堪',
      'SCHEMA', N'dbo',
      'TABLE', N'sj_job',
@@ -1616,7 +1642,7 @@
      'TABLE', N'sj_job'
 GO
 
-INSERT INTO sj_job (namespace_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, description, ext_attrs, deleted, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, N'testJobExecutor', 2, N'60', 1, 60, 3, 1, 1, 116, 0, N'', N'', 0, getdate(), getdate())
+INSERT INTO sj_job (namespace_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, notify_ids, owner_id, description, ext_attrs, deleted, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, N'testJobExecutor', 2, N'60', 1, 60, 3, 1, 1, 116, 0, N'', 1, N'', N'', 0, getdate(), getdate())
 GO
 
 -- sj_job_log_message
@@ -2306,6 +2332,7 @@
     description      nvarchar(256) NOT NULL DEFAULT '',
     flow_info        nvarchar(max) NULL     DEFAULT NULL,
     wf_context       nvarchar(max) NULL     DEFAULT NULL,
+    notify_ids       nvarchar(128) NOT NULL DEFAULT '',
     bucket_index     int           NOT NULL DEFAULT 0,
     version          int           NOT NULL,
     ext_attrs        nvarchar(256) NULL     DEFAULT '',
@@ -2409,6 +2436,13 @@
      'SCHEMA', N'dbo',
      'TABLE', N'sj_workflow',
      'COLUMN', N'wf_context'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫氱煡鍛婅鍦烘櫙閰嶇疆id鍒楄〃',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'notify_ids'
 GO
 
 EXEC sp_addextendedproperty
@@ -2742,4 +2776,3 @@
      'SCHEMA', N'dbo',
      'TABLE', N'sj_workflow_task_batch'
 GO
-
diff --git a/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql
index ad9a0b5..9f8481a 100644
--- a/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql
+++ b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql
@@ -2,7 +2,7 @@
 (
     id                 bigint            NOT NULL,
     user_id            bigint            NOT NULL,
-    tenant_id          nvarchar(20)      NULL,
+    tenant_id          nvarchar(20)      DEFAULT ('000000') NULL,
     auth_id            nvarchar(255)     NOT NULL,
     source             nvarchar(255)     NOT NULL,
     open_id            nvarchar(255)     NULL,
@@ -175,7 +175,7 @@
     'COLUMN', N'oauth_token_secret'
 GO
 EXEC sys.sp_addextendedproperty
-    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�' ,
     'SCHEMA', N'dbo',
     'TABLE', N'sys_social',
     'COLUMN', N'del_flag'
@@ -210,7 +210,11 @@
     'TABLE', N'sys_social',
     'COLUMN', N'update_time'
 GO
-
+EXEC sp_addextendedproperty
+    'MS_Description', N'绀句細鍖栧叧绯昏〃',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social'
+GO
 
 CREATE TABLE sys_tenant
 (
@@ -326,7 +330,7 @@
     'COLUMN', N'status'
 GO
 EXEC sys.sp_addextendedproperty
-    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�' ,
     'SCHEMA', N'dbo',
     'TABLE', N'sys_tenant',
     'COLUMN', N'del_flag'
@@ -423,7 +427,7 @@
     'COLUMN', N'status'
 GO
 EXEC sys.sp_addextendedproperty
-    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�' ,
     'SCHEMA', N'dbo',
     'TABLE', N'sys_tenant_package',
     'COLUMN', N'del_flag'
@@ -1013,7 +1017,7 @@
     'COLUMN', N'status'
 GO
 EXEC sys.sp_addextendedproperty
-    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�' ,
     'SCHEMA', N'dbo',
     'TABLE', N'sys_dept',
     'COLUMN', N'del_flag'
@@ -1235,7 +1239,7 @@
 GO
 INSERT sys_dict_data VALUES (19, N'000000', 2, N'淇敼', N'2', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'淇敼鎿嶄綔')
 GO
-INSERT sys_dict_data VALUES (20, N'000000', 3, N'鍒犻櫎', N'3', N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'鍒犻櫎鎿嶄綔')
+INSERT sys_dict_data VALUES (20, N'000000', 3, N'鍒犻櫎', N3, N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'鍒犻櫎鎿嶄綔')
 GO
 INSERT sys_dict_data VALUES (21, N'000000', 4, N'鎺堟潈', N'4', N'sys_oper_type', N'', N'primary', N'N', 103, 1, getdate(), NULL, NULL, N'鎺堟潈鎿嶄綔')
 GO
@@ -2002,10 +2006,10 @@
     oper_url       nvarchar(255)  DEFAULT ''    NULL,
     oper_ip        nvarchar(128)  DEFAULT ''    NULL,
     oper_location  nvarchar(255)  DEFAULT ''    NULL,
-    oper_param     nvarchar(2000) DEFAULT ''    NULL,
-    json_result    nvarchar(2000) DEFAULT ''    NULL,
+    oper_param     nvarchar(4000) DEFAULT ''    NULL,
+    json_result    nvarchar(4000) DEFAULT ''    NULL,
     status         int            DEFAULT ((0)) NULL,
-    error_msg      nvarchar(2000) DEFAULT ''    NULL,
+    error_msg      nvarchar(4000) DEFAULT ''    NULL,
     oper_time      datetime2(7)                 NULL,
     cost_time      bigint         DEFAULT ((0)) NULL,
     CONSTRAINT PK__sys_oper__34723BF9BD954573 PRIMARY KEY CLUSTERED (oper_id)
@@ -2338,7 +2342,7 @@
     'COLUMN', N'status'
 GO
 EXEC sys.sp_addextendedproperty
-    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�' ,
     'SCHEMA', N'dbo',
     'TABLE', N'sys_role',
     'COLUMN', N'del_flag'
@@ -2475,6 +2479,10 @@
 GO
 INSERT sys_role_menu VALUES (3, 108);
 GO
+INSERT sys_role_menu VALUES (3, 118);
+GO
+INSERT sys_role_menu VALUES (3, 123);
+GO
 INSERT sys_role_menu VALUES (3, 500);
 GO
 INSERT sys_role_menu VALUES (3, 501);
@@ -2569,6 +2577,18 @@
 GO
 INSERT sys_role_menu VALUES (3, 1045);
 GO
+INSERT sys_role_menu VALUES (3, 1050);
+GO
+INSERT sys_role_menu VALUES (3, 1061);
+GO
+INSERT sys_role_menu VALUES (3, 1062);
+GO
+INSERT sys_role_menu VALUES (3, 1063);
+GO
+INSERT sys_role_menu VALUES (3, 1064);
+GO
+INSERT sys_role_menu VALUES (3, 1065);
+GO
 INSERT sys_role_menu VALUES (3, 1500);
 GO
 INSERT sys_role_menu VALUES (3, 1501);
@@ -2592,6 +2612,44 @@
 INSERT sys_role_menu VALUES (3, 1510);
 GO
 INSERT sys_role_menu VALUES (3, 1511);
+GO
+INSERT sys_role_menu VALUES (3, 1600);
+GO
+INSERT sys_role_menu VALUES (3, 1601);
+GO
+INSERT sys_role_menu VALUES (3, 1602);
+GO
+INSERT sys_role_menu VALUES (3, 1603);
+GO
+INSERT sys_role_menu VALUES (3, 1620);
+GO
+INSERT sys_role_menu VALUES (3, 1621);
+GO
+INSERT sys_role_menu VALUES (3, 1622);
+GO
+INSERT sys_role_menu VALUES (3, 1623);
+GO
+INSERT sys_role_menu VALUES (3, 11618);
+GO
+INSERT sys_role_menu VALUES (3, 11619);
+GO
+INSERT sys_role_menu VALUES (3, 11629);
+GO
+INSERT sys_role_menu VALUES (3, 11632);
+GO
+INSERT sys_role_menu VALUES (3, 11633);
+GO
+INSERT sys_role_menu VALUES (3, 11638);
+GO
+INSERT sys_role_menu VALUES (3, 11639);
+GO
+INSERT sys_role_menu VALUES (3, 11640);
+GO
+INSERT sys_role_menu VALUES (3, 11641);
+GO
+INSERT sys_role_menu VALUES (3, 11642);
+GO
+INSERT sys_role_menu VALUES (3, 11643);
 GO
 INSERT sys_role_menu VALUES (4, 5);
 GO
@@ -2723,7 +2781,7 @@
     'COLUMN', N'status'
 GO
 EXEC sys.sp_addextendedproperty
-    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�' ,
     'SCHEMA', N'dbo',
     'TABLE', N'sys_user',
     'COLUMN', N'del_flag'
@@ -3115,7 +3173,7 @@
 GO
 INSERT INTO sys_oss_config VALUES (N'2', N'000000', N'qiniu', N'XXXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi',            N'', N's3-cn-north-1.qiniucs.com',         N'',N'N', N'',           N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL)
 GO
-INSERT INTO sys_oss_config VALUES (N'3', N'000000', N'aliyun', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi',            N'', N'oss-cn-beijing.aliyuncs.com',       N'',N'N', N'',           N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL)
+INSERT INTO sys_oss_config VALUES (N3, N'000000', N'aliyun', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi',            N'', N'oss-cn-beijing.aliyuncs.com',       N'',N'N', N'',           N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL)
 GO
 INSERT INTO sys_oss_config VALUES (N'4', N'000000', N'qcloud', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi-1250000000', N'', N'cos.ap-beijing.myqcloud.com',       N'',N'N', N'ap-beijing', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL)
 GO
@@ -3202,7 +3260,7 @@
     'COLUMN', N'status'
 GO
 EXEC sp_addextendedproperty
-    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
     'SCHEMA', N'dbo',
     'TABLE', N'sys_client',
     'COLUMN', N'del_flag'
diff --git a/script/sql/sqlserver/sqlserver_ry_workflow.sql b/script/sql/sqlserver/sqlserver_ry_workflow.sql
new file mode 100644
index 0000000..ea4b720
--- /dev/null
+++ b/script/sql/sqlserver/sqlserver_ry_workflow.sql
@@ -0,0 +1,1336 @@
+CREATE TABLE flow_definition (
+    id bigint NOT NULL,
+    flow_code nvarchar(40) NOT NULL,
+    flow_name nvarchar(100) NOT NULL,
+    category nvarchar(100) NULL,
+    version nvarchar(20) NOT NULL,
+    is_publish tinyint DEFAULT('0') NULL,
+    form_custom nchar(1) DEFAULT('N') NULL,
+    form_path nvarchar(100) NULL,
+    activity_status tinyint DEFAULT('1') NULL,
+    listener_type nvarchar(100) NULL,
+    listener_path nvarchar(400) NULL,
+    ext nvarchar(500) NULL,
+    create_time datetime2(7)  NULL,
+    update_time datetime2(7)  NULL,
+    del_flag nchar(1) DEFAULT('0') NULL,
+    tenant_id nvarchar(40) NULL,
+    CONSTRAINT PK__flow_def__3213E83FEE39AE33 PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓婚敭id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼缂栫爜',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'flow_code'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鍚嶇О',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'flow_name'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼绫诲埆',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'category'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鐗堟湰',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'version'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏄惁鍙戝竷锛�0鏈彂甯� 1宸插彂甯� 9澶辨晥锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'is_publish'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'form_custom'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒琛ㄥ崟璺緞',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'form_path'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'activity_status'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鐩戝惉鍣ㄧ被鍨�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'listener_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鐩戝惉鍣ㄨ矾寰�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'listener_path'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓氬姟璇︽儏 瀛樹笟鍔¤〃瀵硅薄json瀛楃涓�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'ext'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒犻櫎鏍囧織',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绉熸埛id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼瀹氫箟琛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition'
+GO
+
+CREATE TABLE flow_node (
+    id bigint NOT NULL,
+    node_type tinyint NOT NULL,
+    definition_id bigint NOT NULL,
+    node_code nvarchar(100) NOT NULL,
+    node_name nvarchar(100) NULL,
+    permission_flag nvarchar(200) NULL,
+    node_ratio decimal(6,3)  NULL,
+    coordinate nvarchar(100) NULL,
+    skip_any_node nvarchar(100) DEFAULT('N') NULL,
+    any_node_skip nvarchar(100) NULL,
+    listener_type nvarchar(100) NULL,
+    listener_path nvarchar(400) NULL,
+    handler_type nvarchar(100) NULL,
+    handler_path nvarchar(400) NULL,
+    form_custom nchar(1) DEFAULT('N') NULL,
+    form_path nvarchar(100) NULL,
+    version nvarchar(20) NOT NULL,
+    create_time datetime2(7)  NULL,
+    update_time datetime2(7)  NULL,
+    del_flag nchar(1) DEFAULT('0') NULL,
+    tenant_id nvarchar(40) NULL,
+    CONSTRAINT PK__flow_nod__3213E83F372470DE PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓婚敭id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'node_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼瀹氫箟id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'definition_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鑺傜偣缂栫爜',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'node_code'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鑺傜偣鍚嶇О',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'node_name'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏉冮檺鏍囪瘑锛堟潈闄愮被鍨�:鏉冮檺鏍囪瘑锛屽彲浠ュ涓紝鐢ㄩ�楀彿闅斿紑)',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'permission_flag'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼绛剧讲姣斾緥鍊�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'node_ratio'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍧愭爣',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'coordinate'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏄惁鍙互閫�鍥炰换鎰忚妭鐐癸紙Y鏄� N鍚︼級鍗冲皢鍒犻櫎',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'skip_any_node'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'浠绘剰缁撶偣璺宠浆',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'any_node_skip'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鐩戝惉鍣ㄧ被鍨�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'listener_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鐩戝惉鍣ㄨ矾寰�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'listener_path'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'澶勭悊鍣ㄧ被鍨�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'handler_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'澶勭悊鍣ㄨ矾寰�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'handler_path'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'form_custom'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒琛ㄥ崟璺緞',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'form_path'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鐗堟湰',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'version'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒犻櫎鏍囧織',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绉熸埛id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鑺傜偣琛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node'
+GO
+
+CREATE TABLE flow_skip (
+    id bigint NOT NULL,
+    definition_id bigint NOT NULL,
+    now_node_code nvarchar(100) NOT NULL,
+    now_node_type tinyint  NULL,
+    next_node_code nvarchar(100) NOT NULL,
+    next_node_type tinyint  NULL,
+    skip_name nvarchar(100) NULL,
+    skip_type nvarchar(40) NULL,
+    skip_condition nvarchar(200) NULL,
+    coordinate nvarchar(100) NULL,
+    create_time datetime2(7)  NULL,
+    update_time datetime2(7)  NULL,
+    del_flag nchar(1) DEFAULT('0') NULL,
+    tenant_id nvarchar(40) NULL,
+    CONSTRAINT PK__flow_ski__3213E83F073FEE6E PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓婚敭id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼瀹氫箟id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'definition_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'褰撳墠娴佺▼鑺傜偣鐨勭紪鐮�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'now_node_code'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'褰撳墠鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'now_node_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓嬩竴涓祦绋嬭妭鐐圭殑缂栫爜',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'next_node_code'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓嬩竴涓妭鐐圭被鍨嬶紙0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'next_node_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'璺宠浆鍚嶇О',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'skip_name'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'璺宠浆绫诲瀷锛圥ASS瀹℃壒閫氳繃 REJECT閫�鍥烇級',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'skip_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'璺宠浆鏉′欢',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'skip_condition'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍧愭爣',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'coordinate'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒犻櫎鏍囧織',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绉熸埛id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鑺傜偣璺宠浆鍏宠仈琛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip'
+GO
+
+CREATE TABLE flow_instance (
+    id bigint NOT NULL,
+    definition_id bigint NOT NULL,
+    business_id nvarchar(40) NOT NULL,
+    node_type tinyint NOT NULL,
+    node_code nvarchar(40) NOT NULL,
+    node_name nvarchar(100) NULL,
+    variable nvarchar(max) NULL,
+    flow_status nvarchar(20) NOT NULL,
+    activity_status tinyint DEFAULT('1') NULL,
+    def_json nvarchar(max) NULL,
+    create_by nvarchar(64) NULL,
+    create_time datetime2(7)  NULL,
+    update_time datetime2(7)  NULL,
+    ext nvarchar(500) NULL,
+    del_flag nchar(1) DEFAULT('0') NULL,
+    tenant_id nvarchar(40) NULL,
+    CONSTRAINT PK__flow_ins__3213E83F5190FEE1 PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+TEXTIMAGE_ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓婚敭id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀵瑰簲flow_definition琛ㄧ殑id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'definition_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓氬姟id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'business_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'node_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鑺傜偣缂栫爜',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'node_code'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鑺傜偣鍚嶇О',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'node_name'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'浠诲姟鍙橀噺',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'variable'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鐘舵�侊紙0寰呮彁浜� 1瀹℃壒涓� 2 瀹℃壒閫氳繃 3鑷姩閫氳繃 4缁堟 5浣滃簾 6鎾ら攢 7鍙栧洖  8宸插畬鎴� 9宸查��鍥� 10澶辨晥锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'flow_status'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼婵�娲荤姸鎬侊紙0鎸傝捣 1婵�娲伙級',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'activity_status'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼瀹氫箟json',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'def_json'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鑰�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鎵╁睍瀛楁锛岄鐣欑粰涓氬姟绯荤粺浣跨敤',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'ext'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒犻櫎鏍囧織',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绉熸埛id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼瀹炰緥琛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance'
+GO
+
+CREATE TABLE flow_task (
+    id bigint NOT NULL,
+    definition_id bigint NOT NULL,
+    instance_id bigint NOT NULL,
+    node_code nvarchar(100) NOT NULL,
+    node_name nvarchar(100) NULL,
+    node_type tinyint NOT NULL,
+    form_custom nchar(1) DEFAULT('N') NULL,
+    form_path nvarchar(100) NULL,
+    create_time datetime2(7)  NULL,
+    update_time datetime2(7)  NULL,
+    del_flag nchar(1) DEFAULT('0') NULL,
+    tenant_id nvarchar(40) NULL,
+    CONSTRAINT PK__flow_tas__3213E83F5AE1F1BA PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓婚敭id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀵瑰簲flow_definition琛ㄧ殑id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'definition_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀵瑰簲flow_instance琛ㄧ殑id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'instance_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鑺傜偣缂栫爜',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'node_code'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鑺傜偣鍚嶇О',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'node_name'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鑺傜偣绫诲瀷锛�0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'node_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'form_custom'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒琛ㄥ崟璺緞',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'form_path'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒犻櫎鏍囧織',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绉熸埛id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'寰呭姙浠诲姟琛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task'
+GO
+
+CREATE TABLE flow_his_task (
+    id bigint NOT NULL,
+    definition_id bigint NOT NULL,
+    instance_id bigint NOT NULL,
+    task_id bigint NOT NULL,
+    node_code nvarchar(200) NULL,
+    node_name nvarchar(200) NULL,
+    node_type tinyint  NULL,
+    target_node_code nvarchar(100) NULL,
+    target_node_name nvarchar(100) NULL,
+    approver nvarchar(40) NULL,
+    cooperate_type tinyint DEFAULT('0') NULL,
+    collaborator nvarchar(40) NULL,
+    skip_type nvarchar(10) NOT NULL,
+    flow_status nvarchar(20) NOT NULL,
+    form_custom nchar(1) DEFAULT('N') NULL,
+    form_path nvarchar(100) NULL,
+    message nvarchar(500) NULL,
+    variable nvarchar(max) NULL,
+    ext nvarchar(500) NULL,
+    create_time datetime2(7)  NULL,
+    update_time datetime2(7)  NULL,
+    del_flag nchar(1) DEFAULT('0') NULL,
+    tenant_id nvarchar(40) NULL,
+    CONSTRAINT PK__flow_his__3213E83F67951564 PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓婚敭id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀵瑰簲flow_definition琛ㄧ殑id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'definition_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀵瑰簲flow_instance琛ㄧ殑id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'instance_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀵瑰簲flow_task琛ㄧ殑id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'task_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'寮�濮嬭妭鐐圭紪鐮�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'node_code'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'寮�濮嬭妭鐐瑰悕绉�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'node_name'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'寮�濮嬭妭鐐圭被鍨嬶紙0寮�濮嬭妭鐐� 1涓棿鑺傜偣 2缁撴潫鑺傜偣 3浜掓枼缃戝叧 4骞惰缃戝叧锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'node_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鐩爣鑺傜偣缂栫爜',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'target_node_code'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'缁撴潫鑺傜偣鍚嶇О',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'target_node_name'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒鑰�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'approver'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍗忎綔鏂瑰紡(1瀹℃壒 2杞姙 3濮旀淳 4浼氱 5绁ㄧ 6鍔犵 7鍑忕)',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'cooperate_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍗忎綔浜�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'collaborator'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佽浆绫诲瀷锛圥ASS閫氳繃 REJECT閫�鍥� NONE鏃犲姩浣滐級',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'skip_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鐘舵�侊紙1瀹℃壒涓� 2 瀹℃壒閫氳繃 9宸查��鍥� 10澶辨晥锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'flow_status'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒琛ㄥ崟鏄惁鑷畾涔夛紙Y鏄� N鍚︼級',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'form_custom'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒琛ㄥ崟璺緞',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'form_path'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒鎰忚',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'message'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'浠诲姟鍙橀噺',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'variable'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓氬姟璇︽儏 瀛樹笟鍔¤〃瀵硅薄json瀛楃涓�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'ext'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'浠诲姟寮�濮嬫椂闂�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹℃壒瀹屾垚鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒犻櫎鏍囧織',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绉熸埛id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task',
+'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍘嗗彶浠诲姟璁板綍琛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_his_task'
+GO
+
+CREATE TABLE flow_user (
+    id bigint NOT NULL,
+    type nchar(1) NOT NULL,
+    processed_by nvarchar(80) NULL,
+    associated bigint NOT NULL,
+    create_time datetime2(7)  NULL,
+    create_by nvarchar(80) NULL,
+    update_time datetime2(7)  NULL,
+    del_flag nchar(1) DEFAULT('0') NULL,
+    tenant_id nvarchar(40) NULL,
+    CONSTRAINT PK__flow_use__3213E83FFA38CA8B PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+CREATE NONCLUSTERED INDEX user_processed_type ON flow_user (processed_by ASC, type ASC)
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓婚敭id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'浜哄憳绫诲瀷锛�1寰呭姙浠诲姟鐨勫鎵逛汉鏉冮檺 2寰呭姙浠诲姟鐨勮浆鍔炰汉鏉冮檺 3寰呭姙浠诲姟鐨勫鎵樹汉鏉冮檺锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏉冮檺浜�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'processed_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'浠诲姟琛╥d',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'associated'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓浜�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒犻櫎鏍囧織',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绉熸埛id',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鐢ㄦ埛琛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user'
+GO
+
+CREATE TABLE flow_category (
+    category_id bigint NOT NULL,
+    tenant_id nvarchar(20) DEFAULT('000000') NULL,
+    parent_id bigint  DEFAULT(0) NULL,
+    ancestors nvarchar(500) DEFAULT('') NULL,
+    category_name nvarchar(30) NOT NULL,
+    order_num int  DEFAULT(0) NULL,
+    del_flag nchar(1) DEFAULT('0') NULL,
+    create_dept bigint  NULL,
+    create_by bigint  NULL,
+    create_time datetime2(7)  NULL,
+    update_by bigint  NULL,
+    update_time datetime2(7)  NULL,
+    CONSTRAINT PK__flow_cat__D54EE9B4AE98B9C1 PRIMARY KEY CLUSTERED (category_id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鍒嗙被ID',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'category_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绉熸埛缂栧彿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鐖舵祦绋嬪垎绫籭d',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'parent_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绁栫骇鍒楄〃',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'ancestors'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鍒嗙被鍚嶇О',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'category_name'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏄剧ず椤哄簭',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'order_num'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 1浠h〃鍒犻櫎锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓閮ㄩ棬',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'create_dept'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鑰�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鑰�',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'update_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category',
+'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'娴佺▼鍒嗙被',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_category'
+GO
+
+INSERT flow_category VALUES (100, N'000000', 0, N'0', N'OA瀹℃壒', 0, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+INSERT flow_category VALUES (101, N'000000', 100, N'0,100', N'鍋囧嫟绠$悊', 0, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+INSERT flow_category VALUES (102, N'000000', 100, N'0,100', N'浜轰簨绠$悊', 1, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+INSERT flow_category VALUES (103, N'000000', 101, N'0,100,101', N'璇峰亣', 0, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+INSERT flow_category VALUES (104, N'000000', 101, N'0,100,101', N'鍑哄樊', 1, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+INSERT flow_category VALUES (105, N'000000', 101, N'0,100,101', N'鍔犵彮', 2, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+INSERT flow_category VALUES (106, N'000000', 101, N'0,100,101', N'鎹㈢彮', 3, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+INSERT flow_category VALUES (107, N'000000', 101, N'0,100,101', N'澶栧嚭', 4, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+INSERT flow_category VALUES (108, N'000000', 102, N'0,100,102', N'杞', 1, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+INSERT flow_category VALUES (109, N'000000', 102, N'0,100,102', N'绂昏亴', 2, N'0', 103, 1, getdate(), NULL, NULL);
+GO
+
+CREATE TABLE test_leave (
+    id bigint NOT NULL,
+    tenant_id nvarchar(20) DEFAULT('000000') NULL,
+    leave_type nvarchar(255) NOT NULL,
+    start_date datetime2(7) NOT NULL,
+    end_date datetime2(7) NOT NULL,
+    leave_days int NOT NULL,
+    remark nvarchar(255) NULL,
+    status nvarchar(255) NULL,
+    create_dept bigint  NULL,
+    create_by bigint  NULL,
+    create_time datetime2(7)  NULL,
+    update_by bigint  NULL,
+    update_time datetime2(7)  NULL,
+    CONSTRAINT PK__test_lea__3213E83F348788FA PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'id',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'绉熸埛缂栧彿',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'璇峰亣绫诲瀷',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'leave_type'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'寮�濮嬫椂闂�',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'start_date'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'缁撴潫鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'end_date'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'璇峰亣澶╂暟',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'leave_days'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'璇峰亣鍘熷洜',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'remark'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鐘舵��',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'status'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓閮ㄩ棬',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'create_dept'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鑰�',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鑰�',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'update_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave',
+'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'璇峰亣鐢宠琛�',
+'SCHEMA', N'dbo',
+'TABLE', N'test_leave'
+GO
+
+INSERT sys_menu VALUES (11616, N'宸ヤ綔娴�', 0, 6, N'workflow', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'workflow', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11618, N'鎴戠殑浠诲姟', 0, 7, N'task', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'my-task', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11619, N'鎴戠殑寰呭姙', 11618, 2, N'taskWaiting', N'workflow/task/taskWaiting', N'', 1, 1, N'C', N'0', N'0', N'', N'waiting', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11632, N'鎴戠殑宸插姙', 11618, 3, N'taskFinish', N'workflow/task/taskFinish', N'', 1, 1, N'C', N'0', N'0', N'', N'finish', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11633, N'鎴戠殑鎶勯��', 11618, 4, N'taskCopyList', N'workflow/task/taskCopyList', N'', 1, 1, N'C', N'0', N'0', N'', N'my-copy', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11620, N'娴佺▼瀹氫箟', 11616, 3, N'processDefinition', N'workflow/processDefinition/index', N'', 1, 1, N'C', N'0', N'0', N'', N'process-definition', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11621, N'娴佺▼瀹炰緥', 11630, 1, N'processInstance', N'workflow/processInstance/index', N'', 1, 1, N'C', N'0', N'0', N'', N'tree-table', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11622, N'娴佺▼鍒嗙被', 11616, 1, N'category', N'workflow/category/index', N'', 1, 0, N'C', N'0', N'0', N'workflow:category:list', N'category', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11629, N'鎴戝彂璧风殑', 11618, 1, N'myDocument', N'workflow/task/myDocument', N'', 1, 1, N'C', N'0', N'0', N'', N'guide', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11630, N'娴佺▼鐩戞帶', 11616, 4, N'monitor', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'monitor', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11631, N'寰呭姙浠诲姟', 11630, 2, N'allTaskWaiting', N'workflow/task/allTaskWaiting', N'', 1, 1, N'C', N'0', N'0', N'', N'waiting', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+
+-- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
+INSERT sys_menu VALUES (11623, N'娴佺▼鍒嗙被鏌ヨ', 11622, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:query', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11624, N'娴佺▼鍒嗙被鏂板', 11622, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:add', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11625, N'娴佺▼鍒嗙被淇敼', 11622, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11626, N'娴佺▼鍒嗙被鍒犻櫎', 11622, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11627, N'娴佺▼鍒嗙被瀵煎嚭', 11622, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:export', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+
+-- 璇峰亣娴嬭瘯鐩稿叧鎸夐挳
+INSERT sys_menu VALUES (11638, N'璇峰亣鐢宠', 5, 1, N'leave', N'workflow/leave/index', N'', 1, 0, N'C', N'0', N'0', N'workflow:leave:list', N'#', 103, 1, GETDATE(), NULL, NULL, N'璇峰亣鐢宠鑿滃崟');
+GO
+INSERT sys_menu VALUES (11639, N'璇峰亣鐢宠鏌ヨ', 11638, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:query', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11640, N'璇峰亣鐢宠鏂板', 11638, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:add', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11641, N'璇峰亣鐢宠淇敼', 11638, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11642, N'璇峰亣鐢宠鍒犻櫎', 11638, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (11643, N'璇峰亣鐢宠瀵煎嚭', 11638, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:export', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
+
+INSERT sys_dict_type VALUES (13, N'000000', N'涓氬姟鐘舵��', N'wf_business_status', 103, 1, GETDATE(), NULL, NULL, N'涓氬姟鐘舵�佸垪琛�');
+GO
+INSERT sys_dict_type VALUES (14, N'000000', N'琛ㄥ崟绫诲瀷', N'wf_form_type', 103, 1, GETDATE(), NULL, NULL, N'琛ㄥ崟绫诲瀷鍒楄〃');
+GO
+INSERT sys_dict_type VALUES (15, N'000000', N'浠诲姟鐘舵��', N'wf_task_status', 103, 1, GETDATE(), NULL, NULL, N'浠诲姟鐘舵��');
+GO
+
+INSERT sys_dict_data VALUES (39, N'000000', 1, N'宸叉挙閿�', N'cancel', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'宸叉挙閿�');
+GO
+INSERT sys_dict_data VALUES (40, N'000000', 2, N'鑽夌', N'draft', N'wf_business_status', N'', N'info', N'N', 103, 1, GETDATE(), NULL, NULL, N'鑽夌');
+GO
+INSERT sys_dict_data VALUES (41, N'000000', 3, N'寰呭鏍�', N'waiting', N'wf_business_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'寰呭鏍�');
+GO
+INSERT sys_dict_data VALUES (42, N'000000', 4, N'宸插畬鎴�', N'finish', N'wf_business_status', N'', N'success', N'N', 103, 1, GETDATE(), NULL, NULL, N'宸插畬鎴�');
+GO
+INSERT sys_dict_data VALUES (43, N'000000', 5, N'宸蹭綔搴�', N'invalid', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'宸蹭綔搴�');
+GO
+INSERT sys_dict_data VALUES (44, N'000000', 6, N'宸查��鍥�', N'back', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'宸查��鍥�');
+GO
+INSERT sys_dict_data VALUES (45, N'000000', 7, N'宸茬粓姝�', N'termination', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'宸茬粓姝�');
+GO
+INSERT sys_dict_data VALUES (46, N'000000', 1, N'鑷畾涔夎〃鍗�', N'static', N'wf_form_type', N'', N'success', N'N', 103, 1, GETDATE(), NULL, NULL, N'鑷畾涔夎〃鍗�');
+GO
+INSERT sys_dict_data VALUES (47, N'000000', 2, N'鍔ㄦ�佽〃鍗�', N'dynamic', N'wf_form_type', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'鍔ㄦ�佽〃鍗�');
+GO
+INSERT sys_dict_data VALUES (48, N'000000', 1, N'鎾ら攢', N'cancel', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'鎾ら攢');
+GO
+INSERT sys_dict_data VALUES (49, N'000000', 2, N'閫氳繃', N'pass', N'wf_task_status', N'', N'success', N'N', 103, 1, GETDATE(), NULL, NULL, N'閫氳繃');
+GO
+INSERT sys_dict_data VALUES (50, N'000000', 3, N'寰呭鏍�', N'waiting', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'寰呭鏍�');
+GO
+INSERT sys_dict_data VALUES (51, N'000000', 4, N'浣滃簾', N'invalid', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'浣滃簾');
+GO
+INSERT sys_dict_data VALUES (52, N'000000', 5, N'閫�鍥�', N'back', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'閫�鍥�');
+GO
+INSERT sys_dict_data VALUES (53, N'000000', 6, N'缁堟', N'termination', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'缁堟');
+GO
+INSERT sys_dict_data VALUES (54, N'000000', 7, N'杞姙', N'transfer', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'杞姙');
+GO
+INSERT sys_dict_data VALUES (55, N'000000', 8, N'濮旀墭', N'depute', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'濮旀墭');
+GO
+INSERT sys_dict_data VALUES (56, N'000000', 9, N'鎶勯��', N'copy', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'鎶勯��');
+GO
+INSERT sys_dict_data VALUES (57, N'000000', 10, N'鍔犵', N'sign', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'鍔犵');
+GO
+INSERT sys_dict_data VALUES (58, N'000000', 11, N'鍑忕', N'sign_off', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'鍑忕');
+GO
+INSERT sys_dict_data VALUES (59, N'000000', 11, N'瓒呮椂', N'timeout', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'瓒呮椂');
+GO

--
Gitblit v1.9.3