Merge branch 'feature/REQ-1609' into 'master'
Feature/req 1609 See merge request universal/infrastructure/backend/workflow-engine!2
This commit is contained in:
commit
7b4b19d087
43561
BPMN_Spec_2.0.2.pdf
Normal file
43561
BPMN_Spec_2.0.2.pdf
Normal file
File diff suppressed because one or more lines are too long
23
Changelog.md
23
Changelog.md
@ -1,5 +1,28 @@
|
||||
# Change logs
|
||||
|
||||
### 1.2.1-SNAPSHOT
|
||||
|
||||
> - 重构前端 JSON 转 BPMN 协议的实现, 适配新的需求
|
||||
这里的前端依赖 [该开源工程](https://gitee.com/gailunJAVA/dingding-mid-business-java)
|
||||
|
||||
### 1.2.0-SNAPSHOT
|
||||
|
||||
> - 接入 RocketMQ, 统一采用 `cn.axzo.workflow.core.listener` 包下的接口来实现
|
||||
> - 新增运行中流程实例的执行顺序推测
|
||||
> - 中台业务的接入工作流, 对流程变量中跟人相关信息的变更
|
||||
|
||||
### 1.1.0-SNAPSHOT
|
||||
|
||||
> - 枢智版本
|
||||
> - 调整一些 API 的命令以及模型
|
||||
> - 枢智业务上的一些入侵查询功能, 采用 NativeQuery 的方式处理, 不影响引擎
|
||||
> - 新增 BpmActivityEventListener 事件接口, 方便获取流程定义中某个节点的事件
|
||||
|
||||
### 1.0.2-SNAPSHOT
|
||||
|
||||
> - 枢智版本
|
||||
> - 更新会签或或签时, 针对到每个任务的审批记录状态异常的问题
|
||||
|
||||
### 1.0.1-SNAPSHOT
|
||||
|
||||
> - 枢智版本
|
||||
|
||||
32
ProjectDesc.md
Normal file
32
ProjectDesc.md
Normal file
@ -0,0 +1,32 @@
|
||||
## 1. 本工程结构说明
|
||||
|
||||
- workflow-engine-api: Feign 接口 module, 采用 SpringBoot Starter 方式对外提供, 该报中使用对象模型, 都引用自 common 模块.
|
||||
需要特别注意的是, 由于绝大部分的 Feign API 都会提供对应的 WebApi, 但由于 MVC 与 OpenFeign 默认不会同时解析对应的
|
||||
MappingAdapter, 而目前所有的 Feign API 的实现都是 Server 模块中的 Controller, 所以在 Server 模块中的 Controller 需要单独设置
|
||||
Feign 的请求路径.
|
||||
- workflow-engine-common: 通用的公共模型以及常量
|
||||
- workflow-engine-core: 该 module 的目的是以 jar 包的方式,提供给二/三方应用集成,而不依赖本工程.
|
||||
- workflow-engine-server: 本工程的启动目录, 提供 Web 相关功能以及特性
|
||||
|
||||
## 2. 启动方式
|
||||
|
||||
> 在 workflow-engine-server 模块下, 设置好了 bootstrap.yml, 一般情况直接设置对应的 active profiles 即可.
|
||||
> 由于各个环境中的组件地址可能存在配置的是基于 K8S DNS 的内网域名,本地启动会无法连接, 所以建议通过 VM Options/ Program
|
||||
> arguments/ Environment 等方式对 Nacos 中的默认配置进行覆盖即可.
|
||||
>
|
||||
> **严禁随意调整 Bootstrap.yml 配置文件内容**
|
||||
|
||||
目前提供了四种 Profile 的 nacos 地址配置信息
|
||||
|
||||
- local: 一般用于本地开发
|
||||
> 该环境比较特殊, 用于连接自己本地的数据库, 注意账号密码请用本地覆盖
|
||||
> ```text
|
||||
> -Dspring.datasource.username=root -Dspring.datasource.password=123456
|
||||
> ```
|
||||
> 
|
||||
|
||||
- dev: 一般用于开发联调
|
||||
- test: 一般用于提测
|
||||
- pre: 一般用于上线前验收
|
||||
|
||||
|
||||
409
README.md
409
README.md
@ -4,11 +4,15 @@
|
||||
|
||||
- [商业版](https://www.flowable.com/)
|
||||
- [开源版](https://www.flowable.com/open-source)
|
||||
## 2. Flowable 相关表结构说明
|
||||
|
||||
> jBPM -> Activiti -> camunda -> Flowable 6.7.2
|
||||
|
||||
## 2. Flowable 概述
|
||||
|
||||
> Flowable的数据库名称以ACT_开头。第二部分是表用例的两个字符的标识。
|
||||
|
||||
**Activiti 标准延续:**
|
||||
|
||||
```text
|
||||
- ACT_FO_*:“FO“代表表单引擎相关库。包含表单定义,部署,实例等。
|
||||
- ACT_RE_*:“RE”代表存储库。具有此前缀的表包含“静态”信息,例如流程定义和流程资源。
|
||||
@ -17,35 +21,395 @@
|
||||
- ACT_GE_*:“GE“代表自动生成的数据,包括bpmn.xml、flowable自带流程图等文件,用于各种用例。
|
||||
```
|
||||
|
||||
[库表定义](https://blog.csdn.net/qq_31237581/article/details/130132221)
|
||||
[库表字段定义大致含义参考](https://blog.csdn.net/qq_31237581/article/details/130132221)
|
||||
|
||||
**Flowable 的扩展:**
|
||||
```text
|
||||
- flw_*:Flowable 新版本扩展功能相关的表,流程迁移的表。
|
||||
```
|
||||
|
||||
### 2.1 术语表
|
||||
|
||||
| 术语名称 | 描述 |
|
||||
|----------|---------------------------------------------------------------------------------|
|
||||
| 流程引擎 | 是一种按照某种特性配置或程序进行执行的工具, 在此特征 Flowable 业务框架。 |
|
||||
| 流程模型 | 模型类似一种盒子,用来装东西,在 Flowable 中,模型用来装“流程定义”, 且只能装一个流程定义。 |
|
||||
| 流程定义 | 流程定义是一种告诉流程引擎该如何运行、流转的元配置数据。通常它会产生 BPMN 协议文件和 png 的可视化流程图片文件。一个模型下的流程定义可以有多个版本。 |
|
||||
| 活动(审批节点) | 特指流程定义中需要被外部介入的节点,例如"用户任务"节点。 |
|
||||
| 网关 | 流程定义中的某种节点类型, 在流程实例中,主要是用于条件分支,协助引擎确定下一步的执行路径。 |
|
||||
| 多实例任务 | 针对"任务"节点的特色树形,代表该任务分配多个人后可以会签/或签, 而如果未设置多实例树形,那么就是是多个候选人审批,也仅会只有一个人 |
|
||||
| 租户 | 在本工程中,租户数据等于工作台 ID,主要用于较强判断相关数据的归属。 |
|
||||
| 流程实例 | 按照流程定义创建的一个具体的实例,在业务场景实际使用过程中,通常都需要关注流程实例相关信息,如实例 ID。 |
|
||||
| 流程任务 | 流程定义中标记的“审批节点"的实例,在业务场景实例使用过程中,某个人能审批一个或多个任务时,这个“任务”就是流程任务。 |
|
||||
|
||||
### 2.2 本工程常用的库表
|
||||
|
||||
```text
|
||||
// 运行时(仅保存运行中的流程相关数据)
|
||||
act_ru_execution (执行中的实体)
|
||||
act_ru_task (执行中的任务)
|
||||
act_ru_variable (执行中的变量)
|
||||
|
||||
// 元数据配置信息
|
||||
act_re_model (流程模型)
|
||||
act_re_procdef (流程定义)
|
||||
act_re_deployment (流程部署)
|
||||
|
||||
// 历史数据 (运行时产生的数据也会及时写入历史)
|
||||
act_hi_procinst (历史的流程实例)
|
||||
act_hi_taskinst (历史的任务实例)
|
||||
act_hi_varinst (历史的变量实例)
|
||||
|
||||
act_ge_bytearray (很多元数据)
|
||||
```
|
||||
|
||||
## 3.国内工作流常用操作的名称解释
|
||||
|
||||
| 流程操作 | 描述 |
|
||||
|-------|--------------------------------------------------------------------------------------------------------------|
|
||||
| 认领 | 当前节点候选人或归属于候选组的人,对当前节点进行认领 |
|
||||
| 取消认领 | 当前节点处理人,取消自己处理任务的权限,使任务进入待认领状态 |
|
||||
| 审批 | 当前节点处理人,对当前流程节点进行审核操作,完成后进入下一节点 |
|
||||
| 驳回/回退 | 当前节点处理人,将流程驳回至之前已经处理过的任务节点,要求重新处理 |
|
||||
| 委派/委托 | 当前节点处理人,将自己的主办或者经办权限转移委托至别的用户代为处理,处理完后回到当前处理人手中,并由当前处理人处理完后进入下一节点 |
|
||||
| 转办 | 当前节点处理人,将操作权限转给别人处理,处理完后进入下一节点(自己不再处理) |
|
||||
| 催办 | 对于时效要求高的流程,发起人可催办提醒当前节点处理人,一般以消息通知方式提醒处理人 |
|
||||
| 撤销 | 发起人操作,可以撤销当前流程 |
|
||||
| 取回 | 当前节点上一节点处理人操作,当前节点处理人还未处理,上一节点处理人可以将其退回自己手中重新操作(取回重办) |
|
||||
| 终止 | 当前节点处理人,终止当前流程 |
|
||||
| 抄送 | 当前节点处理人,处理完成之后将处理结果抄送给其他人,这里创建备注信息,并给所有抄送人创建子任务(待阅),子任务不影响流程流转 |
|
||||
| 向前加签 | 当前节点处理人,需要让其他人核对流程,其他人核对完成后,回到当前节点处理人手中,当前节点处理人处理完后进入下一节点 |
|
||||
| 向后加签 | 当前节点处理人,需要让其他人核对流程,其他人核对完成后,直接进入下一节点 |
|
||||
| 会签 | 一般的会签就是指在流程管理中发起人可以同时对多个人发起会签,多个人可以同时处理,只有所有负责人审批通过,审批节点才会通过。(支持一票否决/一票通过/投票按照百 分比给出结论通过或不通过) |
|
||||
| 交接 | 流程管理员权限,管理员将离职或换岗员工的待执行、待领取、代办他人、委托他人代办的任务转交给接管人,并删除与该员工相关的委托代理关系。交接员工所有直接参与的流 程实例中对应的参与者将自动由系统修改为接管人。(强制) |
|
||||
| 暂存 | 复杂表单,一次性填写不完,需要保存草稿功能,开始节点的暂存 |
|
||||
| 流程操作 | 描述 |
|
||||
|-------|-------------------------------------------------------------------------------------------------------------|
|
||||
| 认领 | 当前节点候选人或归属于候选组的人,对当前节点进行认领 |
|
||||
| 取消认领 | 当前节点处理人,取消自己处理任务的权限,使任务进入待认领状态 |
|
||||
| 审批 | 当前节点处理人,对当前流程任务(关联了一活动)进行审核操作,完成后进入下一节点 |
|
||||
| 驳回/回退 | 当前节点处理人,将流程驳回至之前已经处理过的任务节点,要求重新处理 |
|
||||
| 委派/委托 | 当前节点处理人,将自己的主办或者经办权限转移委托至别的用户代为处理,处理完后回到当前处理人手中,并由当前处理人处理完后进入下一节点 |
|
||||
| 转办 | 当前节点处理人,将操作权限转给别人处理,处理完后进入下一节点(自己不再处理) |
|
||||
| 催办 | 对于时效要求高的流程,发起人可催办提醒当前节点处理人,一般以消息通知方式提醒处理人 |
|
||||
| 撤销 | 发起人操作,可以撤销当前流程 |
|
||||
| 取回 | 当前节点上一节点处理人操作,当前节点处理人还未处理,上一节点处理人可以将其退回自己手中重新操作(取回重办) |
|
||||
| 终止 | 当前节点处理人,终止当前流程 |
|
||||
| 抄送 | 当前节点处理人,处理完成之后将处理结果抄送给其他人,这里创建备注信息,并给所有抄送人创建子任务(待阅),子任务不影响流程流转 |
|
||||
| 向前加签 | 当前节点处理人,需要让其他人核对流程,其他人核对完成后,回到当前节点处理人手中,当前节点处理人处理完后进入下一节点 |
|
||||
| 向后加签 | 当前节点处理人,需要让其他人核对流程,其他人核对完成后,直接进入下一节点 |
|
||||
| 会签 | 一般的会签就是指在流程管理中发起人可以同时对多个人发起会签,多个人可以同时处理,只有所有负责人审批通过,审批节点才会通过。(支持一票否决/一票通过/投票按照百 分比给出结论通过或不通过) |
|
||||
| 交接 | 流程管理员权限,管理员将离职或换岗员工的待执行、待领取、代办他人、委托他人代办的任务转交给接管人,并删除与该员工相关的委托代理关系。交接员工所有直接参与的流 程实例中对应的参与者将自动由系统修改为接管人。(强制) |
|
||||
| 暂存 | 复杂表单,一次性填写不完,需要保存草稿功能,开始节点的暂存 |
|
||||
|
||||
已完成:
|
||||
## 4. 如何配置一个流程?
|
||||
|
||||
> 流程的运行依赖一种规则,得让引擎知道何时开始执行流程? 何时终止? 如何识别和控制每个步骤该怎么处理? 执行过程中如何走向不同的路径?
|
||||
> 比如: 我们常见的需求, 某个节点需要会签/或签, 或者某个节点需要判断条件是否执行该步骤等等.
|
||||
>
|
||||
> 以上这些规则都需要再创建流程实例时, 提前就告诉引擎, 且运行过程和步骤中是不可变的. 引擎自己也未提供相应能力.
|
||||
>
|
||||
> 这种规则在 Flowable 的世界中,是以 BPMN2.0 协议规则进行编写和持久化.
|
||||
|
||||
## 4.1 简单识别流程定义
|
||||
|
||||

|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef" exporter="Flowable Open Source Modeler" exporterVersion="6.7.2">
|
||||
<process id="a1" name="1" isExecutable="true">
|
||||
<startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
|
||||
<exclusiveGateway id="sid-516CA2A3-F5BA-4AFF-8314-F87F2B9E2CF2" default="sid-6949581E-4B60-4263-9966-EF0C7D4D7D4F"></exclusiveGateway>
|
||||
<userTask id="sid-6D86C326-54D1-4155-B564-9267C2E097BF" name="事业部审核" flowable:formFieldValidation="true"></userTask>
|
||||
<sequenceFlow id="sid-5BFB5B2B-C9A8-42D2-9AB5-AD886D1E5235" sourceRef="sid-516CA2A3-F5BA-4AFF-8314-F87F2B9E2CF2" targetRef="sid-6D86C326-54D1-4155-B564-9267C2E097BF"></sequenceFlow>
|
||||
<userTask id="sid-08E30960-3B2C-40D4-8B8D-34BBC7213F2F" name="财务审核" flowable:formFieldValidation="true"></userTask>
|
||||
<endEvent id="sid-DB91A9BE-D1AE-4410-B502-86331F330066"></endEvent>
|
||||
<exclusiveGateway id="sid-86533789-DD27-4186-BB4F-4F9526CD930C"></exclusiveGateway>
|
||||
<sequenceFlow id="sid-531523D8-9C8A-4F07-8786-D9389A9E693B" sourceRef="sid-6D86C326-54D1-4155-B564-9267C2E097BF" targetRef="sid-86533789-DD27-4186-BB4F-4F9526CD930C"></sequenceFlow>
|
||||
<sequenceFlow id="sid-3D02CE81-4BBE-4611-AE68-6CF23DB0BB22" sourceRef="sid-86533789-DD27-4186-BB4F-4F9526CD930C" targetRef="sid-DB91A9BE-D1AE-4410-B502-86331F330066"></sequenceFlow>
|
||||
<userTask id="sid-9134DB2B-33BF-423A-B916-1065A12A7D34" name="部门主管审核" flowable:formFieldValidation="true"></userTask>
|
||||
<sequenceFlow id="sid-C62405A5-DC20-4273-A550-D5477143908E" sourceRef="startEvent1" targetRef="sid-9134DB2B-33BF-423A-B916-1065A12A7D34"></sequenceFlow>
|
||||
<sequenceFlow id="sid-7C7099A5-12BA-4E87-BE02-3A70788A2DE9" sourceRef="sid-9134DB2B-33BF-423A-B916-1065A12A7D34" targetRef="sid-516CA2A3-F5BA-4AFF-8314-F87F2B9E2CF2"></sequenceFlow>
|
||||
<userTask id="sid-613723D4-E36F-4902-AE52-37F3CF6E75C9" name="董事会审核" flowable:formFieldValidation="true"></userTask>
|
||||
<sequenceFlow id="sid-454E0650-77EE-4E00-AE5C-0A6CDFF8A975" sourceRef="sid-08E30960-3B2C-40D4-8B8D-34BBC7213F2F" targetRef="sid-613723D4-E36F-4902-AE52-37F3CF6E75C9"></sequenceFlow>
|
||||
<sequenceFlow id="sid-3E71B6E4-5A4B-4066-B653-029CBD856D9D" sourceRef="sid-613723D4-E36F-4902-AE52-37F3CF6E75C9" targetRef="sid-86533789-DD27-4186-BB4F-4F9526CD930C"></sequenceFlow>
|
||||
<sequenceFlow id="sid-6949581E-4B60-4263-9966-EF0C7D4D7D4F" sourceRef="sid-516CA2A3-F5BA-4AFF-8314-F87F2B9E2CF2" targetRef="sid-08E30960-3B2C-40D4-8B8D-34BBC7213F2F"></sequenceFlow>
|
||||
</process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_a1">
|
||||
<bpmndi:BPMNPlane bpmnElement="a1" id="BPMNPlane_a1">
|
||||
<bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
|
||||
<omgdc:Bounds height="30.0" width="30.0" x="120.0" y="193.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="sid-516CA2A3-F5BA-4AFF-8314-F87F2B9E2CF2" id="BPMNShape_sid-516CA2A3-F5BA-4AFF-8314-F87F2B9E2CF2">
|
||||
<omgdc:Bounds height="40.0" width="40.0" x="370.0" y="188.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="sid-6D86C326-54D1-4155-B564-9267C2E097BF" id="BPMNShape_sid-6D86C326-54D1-4155-B564-9267C2E097BF">
|
||||
<omgdc:Bounds height="80.0" width="100.0" x="450.0" y="60.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="sid-08E30960-3B2C-40D4-8B8D-34BBC7213F2F" id="BPMNShape_sid-08E30960-3B2C-40D4-8B8D-34BBC7213F2F">
|
||||
<omgdc:Bounds height="80.0" width="100.0" x="450.0" y="285.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="sid-DB91A9BE-D1AE-4410-B502-86331F330066" id="BPMNShape_sid-DB91A9BE-D1AE-4410-B502-86331F330066">
|
||||
<omgdc:Bounds height="28.0" width="28.0" x="810.5" y="204.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="sid-86533789-DD27-4186-BB4F-4F9526CD930C" id="BPMNShape_sid-86533789-DD27-4186-BB4F-4F9526CD930C">
|
||||
<omgdc:Bounds height="40.0" width="40.0" x="720.0" y="198.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="sid-9134DB2B-33BF-423A-B916-1065A12A7D34" id="BPMNShape_sid-9134DB2B-33BF-423A-B916-1065A12A7D34">
|
||||
<omgdc:Bounds height="80.0" width="100.0" x="210.0" y="168.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
|
||||
<bpmndi:BPMNShape bpmnElement="sid-613723D4-E36F-4902-AE52-37F3CF6E75C9" id="BPMNShape_sid-613723D4-E36F-4902-AE52-37F3CF6E75C9">
|
||||
<omgdc:Bounds height="80.0" width="100.0" x="595.0" y="285.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge bpmnElement="sid-454E0650-77EE-4E00-AE5C-0A6CDFF8A975" id="BPMNEdge_sid-454E0650-77EE-4E00-AE5C-0A6CDFF8A975" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
|
||||
<omgdi:waypoint x="549.95" y="325.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="594.9999999999807" y="325.0"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="sid-3D02CE81-4BBE-4611-AE68-6CF23DB0BB22" id="BPMNEdge_sid-3D02CE81-4BBE-4611-AE68-6CF23DB0BB22" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="14.0" flowable:targetDockerY="14.0">
|
||||
<omgdi:waypoint x="759.5520035885168" y="218.38622754491018"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="810.5002402842656" y="218.08303445075305"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="sid-6949581E-4B60-4263-9966-EF0C7D4D7D4F" id="BPMNEdge_sid-6949581E-4B60-4263-9966-EF0C7D4D7D4F" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
|
||||
<omgdi:waypoint x="390.5" y="227.44187392795882"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="390.5" y="325.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="450.0" y="325.0"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="sid-531523D8-9C8A-4F07-8786-D9389A9E693B" id="BPMNEdge_sid-531523D8-9C8A-4F07-8786-D9389A9E693B" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.0" flowable:targetDockerY="20.0">
|
||||
<omgdi:waypoint x="549.95" y="100.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="740.0" y="100.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="740.0" y="198.0"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="sid-7C7099A5-12BA-4E87-BE02-3A70788A2DE9" id="BPMNEdge_sid-7C7099A5-12BA-4E87-BE02-3A70788A2DE9" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.0" flowable:targetDockerY="20.0">
|
||||
<omgdi:waypoint x="309.9499999999041" y="208.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="370.0" y="208.0"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement"sid-C62405A5-DC20-4273-A550-D5477143908E" id="BPMNEdge_sid-C62405A5-DC20-4273-A550-D5477143908E" flowable:sourceDockerX="15.0" flowable:sourceDockerY="15.0" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
|
||||
<omgdi:waypoint x="149.94999883049306" y="208.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="209.99999999995785" y="208.0"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="sid-5BFB5B2B-C9A8-42D2-9AB5-AD886D1E5235" id="BPMNEdge_sid-5BFB5B2B-C9A8-42D2-9AB5-AD886D1E5235" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
|
||||
<omgdi:waypoint x="390.5" y="188.5"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="390.5" y="100.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="450.0" y="100.0"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="sid-3E71B6E4-5A4B-4066-B653-029CBD856D9D" id="BPMNEdge_sid-3E71B6E4-5A4B-4066-B653-029CBD856D9D" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.0" flowable:targetDockerY="20.0">
|
||||
<omgdi:waypoint x="694.9499999999887" y="325.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="740.0" y="325.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="740.0" y="237.90928437792334"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</definitions>
|
||||
```
|
||||
|
||||
点击查看完整的[BPMN 协议规范](BPMN_Spec_2.0.2.pdf)文件
|
||||
|
||||
> 通过上面的 BPMN 协议的具体内容, 我们可以发现协议内容主要分为两大块, 一块是以`<process>`包裹, 它是主要的规则描述,
|
||||
> 另一块是以`<bpmndi:BPMNDiagram>`包裹, 它是规则可视化的元数据, 这部分一般我们无需关心, 但只要我们的业务涉及到流程配置的反显,
|
||||
> 它又必不可少.
|
||||
|
||||
### 4.2 Process 节点内容简易描述
|
||||
|
||||
> 通过上面的协议内容, 可以发现有以下节点, 我们对出现过的节点简单描述
|
||||
|
||||
- process 代表是一个可以被引擎处理的流程
|
||||
- startEvent 开始事件节点(**这里的需要注意命名, Event 代表是事件, 也就是说一个流程实例的开始, 是基于事件的,截止 23 年, 在
|
||||
Flowable 中开始事件分为 9 种, 我们只用了空启动事件**)
|
||||
|
||||
> - 空启动事件
|
||||
> - 定时器事件
|
||||
> - 信号启动事件
|
||||
> - 消息启动事件
|
||||
> - 异常启动事件
|
||||
> - 注册开始事件
|
||||
> - 开始变量监听事件
|
||||
> - 升级开始事件
|
||||
> - 条件启动事件
|
||||
- exclusiveGateway 排它网关(**控制流程如何流转, 是最常用的一个基础组件,只要涉及到条件流转,都需要用它,在 Flowable 中,网关也有
|
||||
4 种, 我们只用了排它网关和并行网关**)
|
||||
> - 排它网关
|
||||
> - 并行网关
|
||||
> - 事件网关
|
||||
> - 包容网关
|
||||
- userTask 用户任务(**需要人为介入的节点,一般情况下只要人类不对该节点做动作,那么流程就永远卡在这里,不再执行**)
|
||||
- sequenceFlow 顺序流(**用于连接两个节点间的连线,很重要的组件,如果连线不正确,或者中断,会直接影响引擎的执行**)
|
||||
- endEvent 结束事件节点
|
||||
|
||||
### 4.3 流程模型与流程定义
|
||||
|
||||
> 以上仅仅是冰山一角, 大致了解了最初级的协议内容后, 同时我们也称上面的协议内容为**流程定义**, 流程定义是一种较为底层的元数据.
|
||||
>
|
||||
> 因为我们一般针对某个流程规则, 会时不时的修改和调整, 修改后如何保证使用方无感知, 但对于工作流来说又是可追溯的,
|
||||
> 所以需要再抽象一层来保存同一个流程的所有修改过程, 我们称这个抽象层为**流程模型**.
|
||||
> 也就是说, 一个流程模型是一个流程, 这个流程的的多次修改(多版本)都在这个模型下. 而使用方也就只用关心流程模型的唯一标识即可.
|
||||
>
|
||||
> 我们编辑好流程模型与流程定义后, 还需要对流程模型(定义)发布, 才能真正的被使用. 发布后, 这一次的流程定义将定型,不再允许改变当前版本的内容.
|
||||
> 如需修改规则, 则会产生新的版本.
|
||||
|
||||
流程模型: 对应库表: act_re_model
|
||||
流程定义: 对应库表: act_re_procdef
|
||||
流程发布: 对应库表: act_re_deployment/act_ge_bytearray
|
||||
|
||||
以上仅仅是冰山一角, 大致了解了最初级的协议内容后, 同时我们也称上面的协议内容为`流程定义`, 我们再看看如何运行它?
|
||||
|
||||
## 5. 如何运行一个流程?
|
||||
|
||||
> 在介绍上面的协议内容时, 说了我们只用了空启动事件, 那我们怎么启动呢? 虽然说它是事件, 但我们实际发起流程并不是直接操作的事件,
|
||||
> 而是操作引擎为我们提供API.
|
||||
> `org.flowable.engine.RuntimeService#ProcessInstanceBuilder#start()`
|
||||
|
||||
### 5.1 简单了解 Flowable 引擎常用的 API (门面模式)
|
||||
|
||||
> API 的相关作用,都在对应类有注解, 自行查阅
|
||||
|
||||
- org.flowable.engine.RuntimeService 运行时相关
|
||||
- org.flowable.engine.RepositoryService 元数据相关
|
||||
- org.flowable.engine.HistoryService 历史数据相关
|
||||
- org.flowable.engine.TaskService 审批任务相关
|
||||
|
||||
### 5.2 运行(前/中)的困惑?
|
||||
|
||||
> 有没有发现一个问题? 我们从头到现在几乎没有说审批人相关问题或配置, 包括 BPMN 协议内容中也没有审批人的信息. 能发起成功吗?
|
||||
>
|
||||
> 首先回答: 能正常发起,并且流程也能处理运转. 只是像之前说的没有人为操作, 流程会永远的停止在第一个审批节点,
|
||||
> 然后这前提是规则里面至少有一个 userTask.
|
||||
> 如果 BPMN 规则里面,只有 startEvent 直接连接的 endEvent, 那么发起即结束.
|
||||
|
||||
## 6. 流程引擎内部是如何运行的?
|
||||
|
||||
> Flowable 分为多个引擎, 包括 BPMN 引擎/CMMN 引擎/DMN 引擎/Form 引擎/IDM 引擎, 而我们主要关注 BPMN 引擎即可.
|
||||
> 所有的引擎的内部功能统一的采用了命令模式, 引擎内部的每一步动作都是依靠一个Agenda(待办)
|
||||
> 来临时存储后续动作的"命令".
|
||||
>
|
||||
> 所以我们研究引擎需要研究各种命令(XXXCmd). 这些命令是进入引擎内部的入口, 可以通过查看
|
||||
> org.flowable.common.engine.impl.interceptor.Command 的继承关系看到具体的命令. 当然引擎还有更多的逻辑,
|
||||
> 例如真正处理各种类型任务节点的是对应的行为(XXXBehavior),
|
||||
> 可以通过查看 `org.flowable.engine.impl.delegate.ActivityBehavior`
|
||||
> 的继承关系看到具体的行为.
|
||||
>
|
||||
> 例如: 想看发起过程需要研究: StartProcessInstanceCmd#execute
|
||||
|
||||
### 6.1 运行逻辑与操作库表总结
|
||||
|
||||
> 通常情况系下,业务要接入引擎,需要从模型配置开始,整体操作逻辑如下:
|
||||
> 流程模型配置 -> 流程定义配置 -> 发布模型及定义 -> 业务发起指定模型 -> 引擎生成对应审批任务及事件 ->
|
||||
> 业务操作任务通过/拒绝或撤销 -> 引擎流转节点直至结束.
|
||||
>
|
||||
> 大致逻辑了解后,再描述下具体调用 API 以及每个步骤操作的库表
|
||||
|
||||
### 6.2 创建模型
|
||||
|
||||
> 创建模型可以同步将定义传入,形成原子操作,当然操作上也是允许分步配置的.
|
||||
>
|
||||
API: cn.axzo.workflow.client.feign.bpmn.ProcessModelApi#create
|
||||
|
||||
操作的库表: act_re_model/act_ge_bytearray
|
||||
|
||||
### 6.3 创建/更新流程定义
|
||||
|
||||
> 如果未在模型创建时,同步传入定义内容, 则可以通过独立更新方式,仅更新定义内容. 需要注意的是流程定义是有版本概念的,
|
||||
> 但激活的仅能只有一个版本,其他均为挂起
|
||||
> API:
|
||||
|
||||
**(模型中更新)**: cn.axzo.workflow.client.feign.bpmn.ProcessModelApi#update
|
||||
|
||||
**(独立更新)**: cn.axzo.workflow.client.feign.bpmn.ProcessDefinitionApi#updateProcessDefinition
|
||||
|
||||
操作的库表: act_re_model/act_ge_bytearray
|
||||
|
||||
### 6.4 发布模型
|
||||
|
||||
> 发布模型的方式有很多,这里只列举了一种, 通过 ID 部署, 也可以通过 Key 部署, Key 是模型的必要属性, 业务也可以通过这个 Key
|
||||
> 进行流程的发起.
|
||||
>
|
||||
API: cn.axzo.workflow.client.feign.bpmn.ProcessModelApi#deployById
|
||||
|
||||
操作的库表: act_re_procdef/act_re_deployment
|
||||
|
||||
### 6.5 创建流程实例
|
||||
|
||||
> 业务接入后,主要使用的 API, 基于某个流程模型进行实例的发起.
|
||||
>
|
||||
API: cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi#createProcessInstance
|
||||
|
||||
操作的库表:
|
||||
|
||||
**(运行时)**: act_ru_execution/act_ru_task/act_ru_actinst/act_ru_variable/
|
||||
|
||||
**(历史数据)**: act_hi_procinst/act_hi_taskinst/act_hi_actinst/act_hi_varinst/
|
||||
|
||||
### 6.6 流程任务审批
|
||||
|
||||
> 单纯操作流程任务相关的 API, 可以被业务使用.
|
||||
>
|
||||
API:
|
||||
|
||||
**(通过任务)**: cn.axzo.workflow.client.feign.bpmn.ProcessTaskApi.approveTask
|
||||
|
||||
**(拒绝任务)**: cn.axzo.workflow.client.feign.bpmn.ProcessTaskApi.rejectTask
|
||||
|
||||
操作的库表:
|
||||
|
||||
**(运行时)**: act_ru_task/act_ru_variable/act_ru_actinst/
|
||||
|
||||
**(历史数据)**: act_hi_taskinst/act_hi_varinst/act_hi_actinst/act_hi_procinst/
|
||||
|
||||
### 6.7 流程评论+附件
|
||||
|
||||
API:
|
||||
|
||||
**(添加评论)**: cn.axzo.workflow.core.service.BpmnProcessTaskService.commentTask
|
||||
|
||||
**(添加附件)**: cn.axzo.workflow.core.service.BpmnProcessTaskService.attachmentTask
|
||||
|
||||
操作的库表:
|
||||
|
||||
**(评论)**: act_hi_comment
|
||||
|
||||
**(附件)**: act_hi_attachment
|
||||
|
||||
## 7. 如何与外部交互?
|
||||
|
||||
> 工作流引擎作为服务端, 与外部系统交互分为两类, 一类是操作引擎, 一般提供 API 入口, 由外部推动. 另一类是引擎内部状态通知给使用方,
|
||||
> 是由服务端广播出去.
|
||||
|
||||
### 7.1 外部操作引擎
|
||||
|
||||
> 本工程提供两种使用接入方式, 一种是 jar 包集成, 可参考[这个说明](workflow-engine-core/src/main/resources/readme.md),
|
||||
> 另一种是 Feign API 集成, 主要参考`workflow-engine-server`module
|
||||
> 中包路径为 `src/main/java/cn/axzo/workflow/server/controller/web` 下的文件.
|
||||
|
||||
### 7.2 引擎内部事件广播
|
||||
|
||||
> 引擎内部的事件类型非常多, org.flowable.common.engine.api.delegate.event.FlowableEngineEventType 通过这个类可以看到引擎会触发的事件类型.
|
||||
>
|
||||
> 本工程根据公司需要, 将引擎部分事件广播给使用方, 其他事件则不广播. 同时这些事件也被用于本工程的一些场景的消费.
|
||||
|
||||
**广播的事件接口**
|
||||
|
||||
- cn.axzo.workflow.core.listener.BpmnActivityEventListener
|
||||
- cn.axzo.workflow.core.listener.BpmnTaskEventListener
|
||||
- cn.axzo.workflow.core.listener.BpmnProcessEventListener
|
||||
|
||||
**以下总结哪些接口触发哪些事件**
|
||||
|
||||
- cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi.createProcessInstance
|
||||
|
||||
> 发起流程 MQ 触发规则:
|
||||
> 1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件
|
||||
> 2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件
|
||||
|
||||
- cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi.cancelProcessInstance
|
||||
|
||||
> 取消流程 MQ 触发规则:
|
||||
> 1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件
|
||||
> 2. 当前流程实例会触发 process-instance-cancelled 事件
|
||||
|
||||
- cn.axzo.workflow.client.feign.bpmn.ProcessTaskApi.approveTask
|
||||
|
||||
> 任务节点通过审批 MQ 触发规则:
|
||||
> 1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,
|
||||
如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)
|
||||
> 2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件
|
||||
> 2.2. 流程实例正常结束会触发 process-instance-completed 事件
|
||||
|
||||
- cn.axzo.workflow.client.feign.bpmn.ProcessTaskApi.rejectTask
|
||||
|
||||
> MQ 触发规则:
|
||||
> 1. 当前审批任务会触发 process-task-deleted 事件
|
||||
> 2. 当前流程实例会触发 process-instance-rejected 事件
|
||||
|
||||
## 8. Flowable 过时的中文文档参考
|
||||
|
||||
[Flowable BPMN 用户手册 v6.3.0](https://tkjohn.github.io/flowable-userguide/)
|
||||
|
||||
## 99.建设状态(过时)
|
||||
|
||||
### 99.1 已完成:
|
||||
|
||||
1. 全新搭建工作流微服务
|
||||
2. 工作流模型中 JSON 格式的协议支持
|
||||
@ -55,7 +419,7 @@
|
||||
5. 重构工作流服务 Process 引擎相关接口,并按照框架简单接入和测试内置表单
|
||||
6. 重构业务分类/流程状态/审批状态运行时以及历史数据的处理方式
|
||||
|
||||
待办项:
|
||||
### 99.2 待办项:
|
||||
|
||||
1. BPMN 协议兼容(XML/JSON已支持)
|
||||
2. 工作流内部接入组织架构
|
||||
@ -63,4 +427,3 @@
|
||||
4. 审批模型审批人配置管理与持久化
|
||||
5. 审批模型表单能力的接入和调整
|
||||
5. Flowable Event MQ 事件生产与消费
|
||||
|
||||
|
||||
BIN
imgs/img.png
Normal file
BIN
imgs/img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
imgs/start-config.png
Normal file
BIN
imgs/start-config.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
12
pom.xml
12
pom.xml
@ -15,7 +15,7 @@
|
||||
<name>workflow-engine</name>
|
||||
|
||||
<properties>
|
||||
<revision>1.2.0-SNAPSHOT</revision>
|
||||
<revision>1.2.1-SNAPSHOT</revision>
|
||||
<axzo-bom.version>2.0.0-SNAPSHOT</axzo-bom.version>
|
||||
<axzo-dependencies.version>2.0.0-SNAPSHOT</axzo-dependencies.version>
|
||||
<lombok.version>1.18.22</lombok.version>
|
||||
@ -60,6 +60,16 @@
|
||||
<artifactId>workflow-engine-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.maokai</groupId>
|
||||
<artifactId>maokai-api</artifactId>
|
||||
<version>${axzo-dependencies.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.karma</groupId>
|
||||
<artifactId>karma-api</artifactId>
|
||||
<version>${axzo-dependencies.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
package cn.axzo.workflow.client.feign.bpmn;
|
||||
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 流程活动的 API
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/17 16:28
|
||||
*/
|
||||
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}")
|
||||
public interface ProcessActivityApi {
|
||||
|
||||
/**
|
||||
* 业务节点唤醒
|
||||
*/
|
||||
@GetMapping("/api/process/activity/trigger")
|
||||
CommonResponse<Boolean> trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId);
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package cn.axzo.workflow.client.feign.bpmn;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO;
|
||||
@ -77,11 +78,21 @@ public interface ProcessDefinitionApi {
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定模型的 Category 激活
|
||||
* 获取指定模型的定义 ID
|
||||
*
|
||||
* @return 流程定义ID
|
||||
*/
|
||||
@GetMapping("/api/process/definition/active/getByCategory")
|
||||
CommonResponse<String> getActiveProcessDefinitionId(@NotBlank(message = "租户不能为空") @RequestParam String tenantId,
|
||||
@NotBlank(message = "分类不能为空") @RequestParam String category);
|
||||
CommonResponse<String> getActiveProcessDefinitionId(@RequestParam(required = false) String tenantId,
|
||||
@NotBlank(message = "分类不能为空") @RequestParam(required = false) String category);
|
||||
|
||||
/**
|
||||
* 获取指定模型激活的流程定义 JSON 模型
|
||||
*
|
||||
* @return 流程定义ID
|
||||
*/
|
||||
@GetMapping("/api/process/definition/active/json/model")
|
||||
CommonResponse<BpmnModelUpdateDTO> getActiveProcessDefinitionJsonModel(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId,
|
||||
@NotBlank(message = "分类不能为空") @RequestParam(required = false) String category,
|
||||
@RequestParam(required = false) String tenantId);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.workflow.client.feign.bpmn;
|
||||
|
||||
import cn.axzo.workflow.common.model.dto.CooperationOrgDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO;
|
||||
@ -105,4 +106,8 @@ public interface ProcessInstanceApi {
|
||||
@GetMapping("/api/process/instance/node/forecasting")
|
||||
CommonResponse<List<ProcessNodeDetailVO>> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId,
|
||||
@Nullable @RequestParam(required = false) String tenantId);
|
||||
|
||||
@GetMapping("/api/process/instance/cooperation-org")
|
||||
CommonResponse<CooperationOrgDTO> getCooperationOrg(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
|
||||
@Nullable @RequestParam(required = false) String tenantId);
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO;
|
||||
import cn.axzo.workflow.common.model.response.form.model.FormModelBaseVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
@ -18,6 +18,8 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程模型 API
|
||||
@ -30,7 +32,7 @@ public interface ProcessModelApi {
|
||||
|
||||
@Operation(summary = "流程模型列表")
|
||||
@GetMapping("/api/process/model/page")
|
||||
CommonResponse<BpmPageResult<FormModelBaseVO>> page(@Validated @RequestBody BpmnModelSearchDTO dto);
|
||||
CommonResponse<BpmPageResult<BpmnModelDetailVO>> page(@Validated @RequestBody BpmnModelSearchDTO dto);
|
||||
|
||||
/**
|
||||
* 创建流程,
|
||||
@ -46,7 +48,7 @@ public interface ProcessModelApi {
|
||||
@Operation(summary = "通过模型ID查询指定流程模型")
|
||||
@GetMapping("/api/process/model/get")
|
||||
CommonResponse<BpmnModelDetailVO> getById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId,
|
||||
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId);
|
||||
@RequestParam(required = false) String tenantId);
|
||||
|
||||
|
||||
/**
|
||||
@ -64,10 +66,9 @@ public interface ProcessModelApi {
|
||||
*
|
||||
* @return true 能更新,表明该模型关联的所有定义版本都是挂起状态
|
||||
*/
|
||||
@Operation(summary = "校验指定的模型是否能修改")
|
||||
@PutMapping("/api/process/model/update/check")
|
||||
CommonResponse<Boolean> checkCanUpdate(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId,
|
||||
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId);
|
||||
@Operation(summary = "获取指定模型的扩展属性")
|
||||
@GetMapping("/api/process/model/ext")
|
||||
CommonResponse<BpmnModelExtVO> getModelExt(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId);
|
||||
|
||||
/**
|
||||
* 修改流程信息
|
||||
@ -84,7 +85,8 @@ public interface ProcessModelApi {
|
||||
@Operation(summary = "通过模型 ID 部署流程模型")
|
||||
@PostMapping("/api/process/model/deploy")
|
||||
CommonResponse<String> deployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId,
|
||||
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId);
|
||||
@RequestParam(required = false, defaultValue = "") String modelTenantId,
|
||||
@RequestParam(required = false) String operator);
|
||||
|
||||
/**
|
||||
* 部署模型
|
||||
@ -93,12 +95,14 @@ public interface ProcessModelApi {
|
||||
@Operation(summary = "通过模型 KEY 部署流程模型")
|
||||
@PostMapping("/api/process/model/deployByKey")
|
||||
CommonResponse<String> deployByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey,
|
||||
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId);
|
||||
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String modelTenantId,
|
||||
@RequestParam(required = false) String operator);
|
||||
|
||||
@Operation(summary = "通过模块 ID 取消部署流程模型")
|
||||
@PostMapping("/api/process/model/undeploy")
|
||||
CommonResponse<Void> unDeployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId,
|
||||
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId);
|
||||
@RequestParam(required = false, defaultValue = "") String tenantId,
|
||||
@RequestParam(required = false) String operator);
|
||||
|
||||
/**
|
||||
* 删除模型
|
||||
@ -112,4 +116,14 @@ public interface ProcessModelApi {
|
||||
@DeleteMapping("/api/process/model/deleteByKey")
|
||||
CommonResponse<Void> deleteByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam String processModelKey,
|
||||
@NotBlank(message = "租户不能为空") @RequestParam String tenantId);
|
||||
|
||||
@Operation(summary = "修改模型状态")
|
||||
@PostMapping("/api/process/model/changeStatus")
|
||||
CommonResponse<Void> changeStatus(@NotBlank(message = "模型 ID 不能为空") @RequestParam String modelId,
|
||||
@NotNull(message = "状态不能为空") @RequestParam Integer status,
|
||||
@RequestParam(required = false) String operator);
|
||||
|
||||
@Operation(summary = "查询流程模型使用的分类列表")
|
||||
@GetMapping("/api/process/model/category/ids")
|
||||
CommonResponse<List<String>> getModelCategoryList();
|
||||
}
|
||||
|
||||
@ -2,14 +2,16 @@ package cn.axzo.workflow.client.feign.bpmn;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAssigneeDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO;
|
||||
import cn.axzo.workflow.common.valid.group.ValidGroup;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
@ -46,41 +48,6 @@ public interface ProcessTaskApi {
|
||||
@GetMapping("/api/process/task/page/done")
|
||||
CommonResponse<BpmPageResult<BpmnTaskDonePageItemVO>> getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto);
|
||||
|
||||
/**
|
||||
* 同意
|
||||
*
|
||||
* <pre>
|
||||
* MQ 触发规则:
|
||||
* 1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,
|
||||
* 如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)
|
||||
* 2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件
|
||||
* 2.2. 流程实例正常结束会触发 process-instance-completed 事件
|
||||
* </pre>
|
||||
*/
|
||||
@PutMapping("/api/process/task/approve")
|
||||
CommonResponse<Boolean> approveTask(@Validated(ValidGroup.Insert.class) @RequestBody BpmnTaskAuditDTO dto);
|
||||
|
||||
/**
|
||||
* 拒绝
|
||||
*
|
||||
* <pre>
|
||||
* MQ 触发规则:
|
||||
* 1. 当前审批任务会触发 process-task-deleted 事件
|
||||
* 2. 当前流程实例会触发 process-instance-rejected 事件
|
||||
* </pre>
|
||||
*/
|
||||
@PutMapping("/api/process/task/reject")
|
||||
CommonResponse<Boolean> rejectTask(@Validated(ValidGroup.Update.class) @RequestBody BpmnTaskAuditDTO dto);
|
||||
|
||||
/**
|
||||
* 转办
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "直接修改审批任务的审批人")
|
||||
@PutMapping("/api/process/task/assignee")
|
||||
CommonResponse<Boolean> assigneeTask(@Validated @RequestBody BpmnTaskAssigneeDTO dto);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例的审批过程信息
|
||||
@ -106,4 +73,110 @@ public interface ProcessTaskApi {
|
||||
@GetMapping("/api/process/task/active/list")
|
||||
CommonResponse<List<BpmnTaskInstanceVO>> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId);
|
||||
|
||||
|
||||
/**
|
||||
* 同意
|
||||
*
|
||||
* <pre>
|
||||
* MQ 触发规则:
|
||||
* 1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,
|
||||
* 如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)
|
||||
* 2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件
|
||||
* 2.2. 流程实例正常结束会触发 process-instance-completed 事件
|
||||
* </pre>
|
||||
*/
|
||||
@PutMapping("/api/process/task/approve")
|
||||
CommonResponse<Boolean> approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto);
|
||||
|
||||
/**
|
||||
* 驳回
|
||||
*
|
||||
* <pre>
|
||||
* MQ 触发规则:
|
||||
* 1. 当前审批任务会触发 process-task-deleted 事件
|
||||
* 2. 当前流程实例会触发 process-instance-rejected 事件
|
||||
* </pre>
|
||||
*/
|
||||
@PutMapping("/api/process/task/reject")
|
||||
CommonResponse<Boolean> rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto);
|
||||
|
||||
|
||||
/**
|
||||
* 转交
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "直接修改审批任务的审批人")
|
||||
@PutMapping("/api/process/task/transfer")
|
||||
CommonResponse<Boolean> transferTask(@Validated @RequestBody BpmnTaskAssigneeDTO dto);
|
||||
|
||||
|
||||
/**
|
||||
* 评论
|
||||
*
|
||||
* @param dto 评论请求参数
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "审批流程评论")
|
||||
@PutMapping("/api/process/task/comment")
|
||||
CommonResponse<Boolean> commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto);
|
||||
|
||||
|
||||
/**
|
||||
* 加签
|
||||
*
|
||||
* @param dto 加签请求参数
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "审批流程加签")
|
||||
@PutMapping("/api/process/task/countersign")
|
||||
CommonResponse<Boolean> countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto);
|
||||
|
||||
/**
|
||||
* 催办
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "审批流程催办")
|
||||
@PutMapping("/api/process/task/remind")
|
||||
CommonResponse<Boolean> remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto);
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 抄送
|
||||
// *
|
||||
// * @param dto
|
||||
// * @return
|
||||
// */
|
||||
// @Operation(summary = "审批流程抄送")
|
||||
// @PutMapping("/api/process/task/copy")
|
||||
// CommonResponse<Boolean> copyTask(@Validated @RequestBody BpmnTaskAssigneeDTO dto);
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 回退
|
||||
// *
|
||||
// * @param dto
|
||||
// * @return
|
||||
// */
|
||||
// @Operation(summary = "审批流程回退")
|
||||
// @PutMapping("/api/process/task/rollback")
|
||||
// CommonResponse<Boolean> rollbackTask(@Validated @RequestBody BpmnTaskAssigneeDTO dto);
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 撤回
|
||||
// *
|
||||
// * @param dto
|
||||
// * @return
|
||||
// */
|
||||
// @Operation(summary = "审批流程撤回")
|
||||
// @PutMapping("/api/process/task/revocation")
|
||||
// CommonResponse<Boolean> revocationTask(@Validated @RequestBody BpmnTaskAssigneeDTO dto);
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
package cn.axzo.workflow.client.feign.manage;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO;
|
||||
import cn.axzo.workflow.common.model.request.category.CategorySearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.category.CategoryItemVO;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* OMS流程业务管理API
|
||||
*
|
||||
* @author zuoqinbo
|
||||
* @version V1.0
|
||||
* @date 2023/11/6 16:01
|
||||
*/
|
||||
|
||||
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}")
|
||||
public interface ProcessCategoryApi {
|
||||
|
||||
/**
|
||||
* 获取指定业务分类
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/api/process/category/get")
|
||||
CommonResponse<CategoryItemVO> get(@RequestParam Long id);
|
||||
|
||||
@GetMapping("/api/process/category/getByIds")
|
||||
CommonResponse<List<CategoryItemVO>> getByIds(@RequestParam List<Long> ids);
|
||||
|
||||
/**
|
||||
* 新增业务分类
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/process/category/create")
|
||||
CommonResponse<CategoryItemVO> create(@Validated @RequestBody CategoryCreateDTO req);
|
||||
|
||||
/**
|
||||
* 更新业务分类
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@PutMapping("/api/process/category/update")
|
||||
CommonResponse<CategoryItemVO> update(@Validated @RequestBody CategoryUpdateDTO dto);
|
||||
|
||||
/**
|
||||
* 删除指定业务分类
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping("/api/process/category/delete")
|
||||
CommonResponse<Boolean> delete(@RequestParam Long id);
|
||||
|
||||
/**
|
||||
* 更新指定分类状态
|
||||
* @param id
|
||||
* @param state
|
||||
* @return
|
||||
*/
|
||||
@PutMapping("/api/process/category/update/state")
|
||||
CommonResponse<Boolean> updateState(@RequestParam Long id, @RequestParam Boolean state);
|
||||
|
||||
/**
|
||||
* 获取指定业务分类集合
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/process/category/list")
|
||||
CommonResponse<List<CategoryItemVO>> list(@RequestBody CategorySearchDTO dto);
|
||||
|
||||
/**
|
||||
* 搜索业务分类
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/process/category/page/search")
|
||||
CommonResponse<BpmPageResult<CategoryItemVO>> search(@RequestBody CategorySearchDTO dto);
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package cn.axzo.workflow.client.feign.manage;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* OMS流程业务管理API
|
||||
*
|
||||
* @author zuoqinbo
|
||||
* @version V1.0
|
||||
* @date 2023/11/6 16:01
|
||||
*/
|
||||
|
||||
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}")
|
||||
public interface ProcessConfigApi {
|
||||
|
||||
/**
|
||||
* 获取流程操作按钮列表
|
||||
*
|
||||
* @param webContextPath 容器上下文路径
|
||||
* @return 流程操作按钮列表
|
||||
*/
|
||||
@GetMapping("/api/process/config/button/list")
|
||||
CommonResponse<List<BpmnButtonMetaInfo>> getDefaultButtons();
|
||||
|
||||
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
package cn.axzo.workflow.common.constant;
|
||||
|
||||
public interface BpmConstants {
|
||||
|
||||
String BPMN_FILE_SUFFIX = ".bpmn";
|
||||
String FORM_FILE_SUFFIX = ".form";
|
||||
String SERVER_APP_ID = "server-app-id";
|
||||
/**
|
||||
* 引擎自己的隐藏指令
|
||||
*/
|
||||
String FLOWABLE_SKIP_EXPRESSION_ENABLE = "_FLOWABLE_SKIP_EXPRESSION_ENABLED";
|
||||
/**
|
||||
* 指定单位标识
|
||||
*/
|
||||
String INTERNAL_EXECUTIVE_UNIT_ID = "_INTERNAL_EXECUTIVE_UNIT_ID";
|
||||
|
||||
String INTERNAL_INITIATOR = "_INTERNAL_INITIATOR";
|
||||
String INTERNAL_INITIATOR_OU_ID = "_INTERNAL_INITIATOR_OU_ID";
|
||||
String INTERNAL_INITIATOR_OU_NAME = "_INTERNAL_INITIATOR_OU_NAME";
|
||||
String INTERNAL_END_USER_ID = "_INTERNAL_END_USER_ID";
|
||||
String INTERNAL_END_TENANT_ID = "_INTERNAL_END_TENANT_ID";
|
||||
String INTERNAL_END_USER_NAME = "_INTERNAL_END_USER_NAME";
|
||||
String INTERNAL_TASK_COMMENT = "_INTERNAL_CUSTOM_TASK_COMMENT";
|
||||
String INTERNAL_DELETE_PROCESS_FLAG = "_INTERNAL_DELETE_PROCESS_FLAG";
|
||||
String INTERNAL_PROCESS_TYPE_CANCEL = "_INTERNAL_PROCESS_TYPE_CANCEL";
|
||||
String INTERNAL_PROCESS_TYPE_REJECT = "_INTERNAL_PROCESS_TYPE_REJECT";
|
||||
String INTERNAL_SPECIFY_NEXT_APPROVER = "_INTERNAL_SPECIFY_NEXT_APPROVER";
|
||||
// String INTERNAL_TASK_RELATION_ASSIGNEE_INFO = "[_ASSIGNEE_INFO_]";
|
||||
// 用于多实例审批时,保存计算出来的审批人
|
||||
String INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO = "[_ASSIGNEE_LIST_INFO_]";
|
||||
// 单任务节点,
|
||||
String INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT = "[_ASSIGNEE_INFO_SNAPSHOT_]";
|
||||
String INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT = "[_ASSIGNEE_LIST_INFO_SNAPSHOT_]";
|
||||
|
||||
|
||||
String PROCESS_PREFIX = "Flowable";
|
||||
String START_EVENT_ID = "startEventNode";
|
||||
String END_EVENT_ID = "endEventNode";
|
||||
String BPM_MODEL_CATEGORY = "bpm_model_category";
|
||||
String BPM_ALLOW_SKIP_USER_TASK = "_INTERNAL_SKIP_USER_TASK";
|
||||
/**
|
||||
* 用于国内审批节点填写审批建议
|
||||
* <p>
|
||||
* 其他类型 @see org.flowable.engine.impl.persistence.entity.CommentEntity
|
||||
*/
|
||||
String COMMENT_TYPE_ADVICE = "advice";
|
||||
|
||||
String INITIATOR_REVOKE_THE_APPROVAL = "发起人主动撤销审批";
|
||||
String APPROVAL_ENDS_AUTOMATICALLY = "审批拒绝自动结束";
|
||||
|
||||
String NUMBER_OF_INSTANCES = "nrOfInstances";
|
||||
String MULTI_INSTANCE_LOOP_COUNTER = "loopCounter";
|
||||
|
||||
/**
|
||||
* 会签表达式
|
||||
*/
|
||||
String AND_SIGN_EXPRESSION = "${nrOfInstances == nrOfCompletedInstances}";
|
||||
|
||||
/**
|
||||
* 或签表达式
|
||||
*/
|
||||
String OR_SIGN_EXPRESSION = "${nrOfCompletedInstances > 0}";
|
||||
|
||||
/**
|
||||
* 全局的启用/上架等状态描述
|
||||
*/
|
||||
Integer ENABLED = 1;
|
||||
|
||||
/**
|
||||
* 全局的停用/下架等状态描述
|
||||
*/
|
||||
Integer DISABLED = 0;
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
package cn.axzo.workflow.common.constant;
|
||||
|
||||
public interface BpmnConstants {
|
||||
|
||||
String BPMN_FILE_SUFFIX = ".bpmn";
|
||||
String FORM_FILE_SUFFIX = ".form";
|
||||
String SERVER_APP_ID = "server-app-id";
|
||||
/**
|
||||
* 引擎自己的隐藏指令
|
||||
*/
|
||||
String FLOWABLE_SKIP_EXPRESSION_ENABLE = "[_FLOWABLE_SKIP_EXPRESSION_ENABLED_]";
|
||||
String INTERNAL_INITIATOR = "[_INTERNAL_INITIATOR_]";
|
||||
@Deprecated
|
||||
String OLD_INTERNAL_INITIATOR = "_INTERNAL_INITIATOR";
|
||||
String INTERNAL_END_USER_ID = "[_INTERNAL_END_USER_ID_]";
|
||||
String INTERNAL_END_TENANT_ID = "[_INTERNAL_END_TENANT_ID_]";
|
||||
String INTERNAL_END_USER_NAME = "[_INTERNAL_END_USER_NAME_]";
|
||||
String INTERNAL_INITIATOR_OU_ID = "[_INTERNAL_INITIATOR_OU_ID_]";
|
||||
String INTERNAL_INITIATOR_OU_NAME = "[_INTERNAL_INITIATOR_OU_NAME_]";
|
||||
String INTERNAL_DELETE_PROCESS_FLAG = "[_INTERNAL_DELETE_PROCESS_FLAG_]";
|
||||
String INTERNAL_PROCESS_TYPE_CANCEL = "[_INTERNAL_PROCESS_TYPE_CANCEL_]";
|
||||
String INTERNAL_PROCESS_TYPE_REJECT = "[_INTERNAL_PROCESS_TYPE_REJECT_]";
|
||||
String INTERNAL_SPECIFY_NEXT_APPROVER = "[_INTERNAL_SPECIFY_NEXT_APPROVER_]";
|
||||
String BIZ_ORG_RELATION = "[_BIZ_ORG_RELATION_]";
|
||||
// 用于多实例审批时,保存计算出来的审批人
|
||||
String INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO = "[_ASSIGNEE_LIST_INFO_]";
|
||||
// 单任务节点,
|
||||
String INTERNAL_TASK_RELATION_ASSIGNEE_INFO = "[_ASSIGNEE_INFO_]";
|
||||
@Deprecated
|
||||
String OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT = "[_ASSIGNEE_INFO_SNAPSHOT_]";
|
||||
String INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT = "[_ACTIVITY_INFO_SNAPSHOT_]";
|
||||
String COUNTERSIGN_REMAIN_ASSIGNER_LIST = "[_COUNTERSIGN_REMAIN_ASSIGNER_LIST_]";
|
||||
String COUNTERSIGN_ORIGIN_ASSIGNER = "[_COUNTERSIGN_ORIGIN_ASSIGNER_]";
|
||||
|
||||
String PROCESS_PREFIX = "Flowable";
|
||||
String TASK_ASSIGNEE_SKIP_FLAT = "taskSkip";
|
||||
String FLOW_NODE_JSON = "jsonValue";
|
||||
String FLOW_SERVER_VERSION = "serverVersion";
|
||||
String FLOW_SERVER_VERSION_121 = "1.2.1";
|
||||
String CONFIG_NOTICE = "noticeConfig";
|
||||
String TEMPLATE_NOTICE_MESSAGE_ID = "noticeMessageId";
|
||||
String TEMPLATE_PENDING_MESSAGE_ID = "pendingMessageId";
|
||||
String TEMPLATE_SMS_MESSAGE_ID = "smsMessageId";
|
||||
String CONFIG_BUTTON = "buttonConfig";
|
||||
String CONFIG_BUTTON_META = "button";
|
||||
String CONFIG_FIELD = "fieldConfig";
|
||||
String CONFIG_APPROVAL_METHOD = "approvalMethod";
|
||||
String CONFIG_APPROVER_SCOPE = "approverScope";
|
||||
String CONFIG_APPROVER_SPECIFY = "approverSpecify";
|
||||
String CONFIG_APPROVER_MODE_TYPE = "approverModeType";
|
||||
String CONFIG_APPROVER_EMPTY_HANDLE_TYPE = "approverEmptyHandleType";
|
||||
String CONFIG_FIELD_META = "field";
|
||||
String CONFIG_FIELD_PERMISSION = "fieldPermission";
|
||||
String CONFIG_FIELD_OPTION = "option";
|
||||
String CONFIG_NODE_TYPE = "nodeType";
|
||||
String CONFIG_BUTTON_TYPE_INITIATOR = "initiator";
|
||||
String CONFIG_BUTTON_TYPE_CURRENT = "current";
|
||||
String CONFIG_BUTTON_TYPE_HISTORY = "history";
|
||||
String CONFIG_BUTTON_TYPE_CARBON_COPY = "carbonCopy";
|
||||
|
||||
String ELEMENT_ATTRIBUTE_NAME = "name";
|
||||
String ELEMENT_ATTRIBUTE_VALUE = "value";
|
||||
String ELEMENT_ATTRIBUTE_DESC = "desc";
|
||||
String ELEMENT_ATTRIBUTE_CODE = "code";
|
||||
String ELEMENT_ATTRIBUTE_KEY = "key";
|
||||
String ELEMENT_ATTRIBUTE_ORDER = "order";
|
||||
String ELEMENT_ATTRIBUTE_CHECKED = "checked";
|
||||
String ELEMENT_ATTRIBUTE_DISABLED = "disabled";
|
||||
String ELEMENT_ATTRIBUTE_TYPE = "type";
|
||||
String START_EVENT_ID = "startEventNode";
|
||||
String SEQUENCE_FLOW_ID = "SequenceFlowId";
|
||||
String END_EVENT_ID = "endEventNode";
|
||||
String BPM_MODEL_CATEGORY = "bpm_model_category";
|
||||
String BPM_ALLOW_SKIP_USER_TASK = "_INTERNAL_SKIP_USER_TASK_";
|
||||
String BPM_ALLOW_AUTO_REJECTION = "_INTERNAL_AUTO_REJECTION";
|
||||
/**
|
||||
* 用于国内审批节点填写审批建议
|
||||
* <p>
|
||||
* 其他类型 @see org.flowable.engine.impl.persistence.entity.CommentEntity
|
||||
*/
|
||||
String COMMENT_TYPE_ADVICE = "advice";
|
||||
String COMMENT_TYPE_AUTO_PASSED = "operation-autoPassed";
|
||||
String COMMENT_TYPE_OPERATION_COUNTERSIGN = "operation-countersign";
|
||||
String COMMENT_TYPE_OPERATION_TRANSFER = "operation-transfer";
|
||||
String NUMBER_OF_INSTANCES = "nrOfInstances";
|
||||
String MULTI_INSTANCE_LOOP_COUNTER = "loopCounter";
|
||||
String TASK_COMPLETE_OPERATION_TYPE = "_TASK_COMPLETE_TYPE";
|
||||
/**
|
||||
* 会签表达式
|
||||
*/
|
||||
String AND_SIGN_EXPRESSION = "${nrOfInstances == nrOfCompletedInstances}";
|
||||
|
||||
/**
|
||||
* 或签表达式, 只要当同意的人数大于 1 即可, 拒绝不影响该节点
|
||||
*/
|
||||
String OR_SIGN_EXPRESSION_ONE_PASS = "${nrOfCompletedInstances > 0}";
|
||||
/**
|
||||
* 或签表达式, 只要一个人同意或驳回就结束该节点
|
||||
*/
|
||||
String OR_SIGN_EXPRESSION_ONLY_ONE = "${nrOfInstances != nrOfActiveInstances}";
|
||||
|
||||
/**
|
||||
* 全局的启用/上架等状态描述
|
||||
*/
|
||||
Integer ENABLED = 1;
|
||||
|
||||
/**
|
||||
* 全局的停用/下架等状态描述
|
||||
*/
|
||||
Integer DISABLED = 0;
|
||||
|
||||
//=============== 消息推送时的变量集合中 key 的命名 =================
|
||||
String VAR_INITIATOR_USER_NAME = "initiatorUserName";
|
||||
String VAR_PROCESS_INSTANCE_NAME = "processInstanceName";
|
||||
String VAR_PROCESS_INSTANCE_ID = "processInstanceId";
|
||||
String VAR_PROCESS_START_TIME = "processStartTime";
|
||||
String VAR_PROCESS_END_TIME = "processEndTime";
|
||||
String VAR_PROCESS_TENANT_ID = "tenantId";
|
||||
String VAR_BUSINESS_NAME = "businessName";
|
||||
String VAR_TASK_ID = "taskId";
|
||||
String VAR_TASK_START_TIME = "taskStartTime";
|
||||
String VAR_TASK_USER_NAME = "taskUserName";
|
||||
String VAR_ACTIVITY_ID = "activityId";
|
||||
String VAR_ACTIVITY_NAME = "activityName";
|
||||
String VAR_PROCESS_RESULT = "processResult";
|
||||
String VAR_OPERATOR_TYPE = "operatorType";
|
||||
|
||||
}
|
||||
@ -11,7 +11,5 @@ public interface MetaInfoConstants {
|
||||
String MODEL_TYPE = "modelType";
|
||||
String MODEL_TYPE_PROCESS = "MODEL_PROCESS";
|
||||
String MODEL_TYPE_FORM = "MODEL_FORM";
|
||||
|
||||
|
||||
String MODEL_DESCRIPTION = "modelDescription";
|
||||
}
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
/**
|
||||
* 审批方式枚举
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/16 10:10
|
||||
*/
|
||||
public enum ApprovalMethodEnum {
|
||||
|
||||
human("human", "人工审批"),
|
||||
autoPassed("autoPassed", "自动通过"),
|
||||
autoRejection("autoRejection", "自动驳回"),
|
||||
nobody("nobody", "不审批[仅业务节点可能有该值]"),
|
||||
;
|
||||
|
||||
private String type;
|
||||
private String desc;
|
||||
|
||||
ApprovalMethodEnum(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
/**
|
||||
* 审批人为空时的处理方式枚举
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/16 10:22
|
||||
*/
|
||||
public enum ApproverEmptyHandleTypeEnum {
|
||||
autoPassed("autoPassed", "自动通过"),
|
||||
autoRejection("autoRejection", "自动驳回"),
|
||||
autoSkipped("autoSkipped", "自动跳过"),
|
||||
transferToAdmin("transferToAdmin", "转交给管理员"),
|
||||
specifyAssignee("specifyAssignee", "指定审批人"),
|
||||
;
|
||||
private String type;
|
||||
private String desc;
|
||||
|
||||
ApproverEmptyHandleTypeEnum(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 审批人所在范围枚举
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/16 10:14
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ApproverScopeEnum {
|
||||
entWorkspace("entWorkspace", "企业工作台", "entWorkspaceProcessor"),
|
||||
projectWorkspace("projectWorkspace", "项目工作台","projectWorkspaceProcessor"),
|
||||
preTaskUser("preTaskUser", "上节点审批人所在单位","preTaskUserProcessor"),
|
||||
preTaskSpecified("preTaskSpecified", "上节点审批人指定","preTaskUserProcessor"),
|
||||
;
|
||||
private String type;
|
||||
private String desc;
|
||||
private String processor;
|
||||
|
||||
ApproverScopeEnum(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public boolean selectWorkspace() {
|
||||
return this == ApproverScopeEnum.projectWorkspace;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
/**
|
||||
* 审批人指定枚举
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/16 10:16
|
||||
*/
|
||||
public enum ApproverSpecifyEnum {
|
||||
|
||||
position("position", "指定职位"),
|
||||
role("role", "指定角色"),
|
||||
identity("identity", "指定身份"),
|
||||
initiatorLeader("initiatorLeader", "发起人主管"),
|
||||
initiatorLeaderRecursion("initiatorLeaderRecursion", "发起人多级主管"),
|
||||
fixedPerson("fixedPerson", "固定人员"),
|
||||
preNodeSpecified("preNodeSpecified", "上级节点指定"),
|
||||
;
|
||||
private String type;
|
||||
private String desc;
|
||||
|
||||
ApproverSpecifyEnum(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
/**
|
||||
* 附件类型枚举
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/22 23:19
|
||||
*/
|
||||
public enum AttachmentTypeEnum {
|
||||
|
||||
image("image", "图片"),
|
||||
file("file", "文件"),
|
||||
;
|
||||
|
||||
private String type;
|
||||
private String desc;
|
||||
|
||||
AttachmentTypeEnum(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
|
||||
/**
|
||||
* Flowable Event Enum For RocketMQ
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/9/4 10:38
|
||||
*/
|
||||
public enum BpmnButtonEnum {
|
||||
/**
|
||||
* 同意按钮
|
||||
*/
|
||||
BPMN_APPROVE(1, "BPMN_APPROVE", "同意"),
|
||||
/**
|
||||
* 驳回按钮
|
||||
*/
|
||||
BPMN_REJECT(2, "BPMN_REJECT", "驳回"),
|
||||
/**
|
||||
* 撤回按钮
|
||||
*/
|
||||
BPMN_REVOCATION(3, "BPMN_REVOCATION", "撤回"),
|
||||
/**
|
||||
* 转交按钮
|
||||
*/
|
||||
BPMN_TRANSFER(4, "BPMN_TRANSFER", "转交"),
|
||||
/**
|
||||
* 加签按钮
|
||||
*/
|
||||
BPMN_COUNTERSIGN(5, "BPMN_COUNTERSIGN", "加签"),
|
||||
/**
|
||||
* 评论按钮
|
||||
*/
|
||||
BPMN_COMMENT(6, "BPMN_COMMENT", "评论"),
|
||||
/**
|
||||
* 回退按钮
|
||||
*/
|
||||
BPMN_ROLLBACK(7, "BPMN_ROLLBACK", "回退"),
|
||||
/**
|
||||
* 抄送按钮
|
||||
*/
|
||||
BPMN_COPY(8, "BPMN_COPY", "抄送");
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public String getBtnKey() {
|
||||
return btnKey;
|
||||
}
|
||||
|
||||
public String getBtnName() {
|
||||
return btnName;
|
||||
}
|
||||
|
||||
private final int order;
|
||||
private final String btnKey;
|
||||
private final String btnName;
|
||||
|
||||
|
||||
BpmnButtonEnum(int order, String btnKey, String btnName) {
|
||||
this.order = order;
|
||||
this.btnKey = btnKey;
|
||||
this.btnName = btnName;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* 加签类型
|
||||
*
|
||||
* @author zuoqinbo
|
||||
*/
|
||||
public enum BpmnCountersignType {
|
||||
/**
|
||||
* 向前加签
|
||||
*/
|
||||
FORWARD_COUNTERSIGN("FORWARD_COUNTERSIGN", "向前加签"),
|
||||
/**
|
||||
* 向后加签
|
||||
*/
|
||||
BACK_COUNTERSIGN("BACK_COUNTERSIGN", "向后加签");
|
||||
|
||||
private String type;
|
||||
private String desc;
|
||||
|
||||
BpmnCountersignType(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public boolean isEqual(String type) {
|
||||
return this.type.equals(type);
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
|
||||
public static BpmnCountersignType isValidAppType(String countersignType) {
|
||||
if (StringUtils.isBlank(countersignType)) {
|
||||
return null;
|
||||
}
|
||||
BpmnCountersignType[] countersignTypeEnums = BpmnCountersignType.values();
|
||||
for (BpmnCountersignType countersign : countersignTypeEnums) {
|
||||
if (countersign.getType().equals(countersignType)) {
|
||||
return countersign;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -2,10 +2,12 @@ package cn.axzo.workflow.common.enums;
|
||||
|
||||
|
||||
public enum BpmnFlowNodeMode {
|
||||
STARTNODE("STARTNODE", "发起节点"),
|
||||
GENERAL("GENERAL", "普通"),
|
||||
OR("OR", "或签"),
|
||||
AND("AND", "会签");
|
||||
AND("AND", "会签"),
|
||||
BUSINESS("BUSINESS", "业务节点"),
|
||||
COPY("COPY", "抄送节点"),
|
||||
;
|
||||
|
||||
private String type;
|
||||
private String desc;
|
||||
@ -14,6 +16,7 @@ public enum BpmnFlowNodeMode {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public boolean isEqual(String type) {
|
||||
return this.type.equals(type);
|
||||
}
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public enum BpmnFlowNodeType {
|
||||
|
||||
//0 发起人 1审批 2抄送 3条件 4路由
|
||||
NODE_STARTER("NODE_STARTER", "发起人节点"), // ROOT
|
||||
NODE_EXCLUSIVE_GATEWAY("NODE_EXCLUSIVE_GATEWAY", "排它网关"), // CONDITIONS
|
||||
NODE_CONDITION("NODE_CONDITION", "条件节点 - 隶属于排它网关"), // CONDITION
|
||||
NODE_PARALLEL_GATEWAY("NODE_PARALLEL_GATEWAY", "并行网关"),
|
||||
NODE_PARALLEL("NODE_PARALLEL", "并行节点 - 隶属于并行网关"),
|
||||
NODE_TASK("NODE_TASK", "审核节点"), // APPROVAL
|
||||
NODE_BUSINESS("NODE_BUSINESS", "业务节点"),
|
||||
NODE_CARBON_COPY("NODE_CARBON_COPY", "抄送节点"),
|
||||
NODE_TRIGGER("NODE_TRIGGER", "触发器节点"),
|
||||
NODE_EMPTY("NODE_EMPTY", "空节点"),
|
||||
;
|
||||
|
||||
private String type;
|
||||
private String desc;
|
||||
|
||||
BpmnFlowNodeType(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public boolean isEqual(String type) {
|
||||
return this.type.equals(type);
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static BpmnFlowNodeType valueOfType(String type) {
|
||||
return Arrays.stream(BpmnFlowNodeType.values())
|
||||
.filter(i -> Objects.equals(i.getType(), type))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_NOTICE_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_PENDING_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_SMS_MESSAGE_ID;
|
||||
|
||||
/**
|
||||
* 通知类型枚举
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/22 11:02
|
||||
*/
|
||||
public enum BpmnNoticeEnum {
|
||||
|
||||
notice("notice", TEMPLATE_NOTICE_MESSAGE_ID, "通知模板"),
|
||||
pending("pending", TEMPLATE_PENDING_MESSAGE_ID, "待办模板"),
|
||||
sms("sms", TEMPLATE_SMS_MESSAGE_ID, "短信模板"),
|
||||
;
|
||||
private final String key;
|
||||
private final String configName;
|
||||
private final String desc;
|
||||
|
||||
BpmnNoticeEnum(String key, String configName, String desc) {
|
||||
this.key = key;
|
||||
this.configName = configName;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getConfigName() {
|
||||
return configName;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
@ -2,11 +2,13 @@ package cn.axzo.workflow.common.enums;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public enum BpmProcessInstanceResultEnum {
|
||||
public enum BpmnProcessInstanceResultEnum {
|
||||
PROCESSING("PROCESSING", "审批中"),
|
||||
APPROVED("APPROVED", "已通过"),
|
||||
REJECTED("REJECTED", "已驳回"),
|
||||
CANCELLED("CANCELLED", "已撤销"),
|
||||
TRANSFER("TRANSFER", "已转交"),
|
||||
COUNTERSIGN("COUNTERSIGN", "已加签"),
|
||||
;
|
||||
/**
|
||||
* 结果
|
||||
@ -17,7 +19,7 @@ public enum BpmProcessInstanceResultEnum {
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
BpmProcessInstanceResultEnum(String status, String desc) {
|
||||
BpmnProcessInstanceResultEnum(String status, String desc) {
|
||||
this.status = status;
|
||||
this.desc = desc;
|
||||
}
|
||||
@ -43,7 +45,7 @@ public enum BpmProcessInstanceResultEnum {
|
||||
CANCELLED.getStatus()).contains(result);
|
||||
}
|
||||
|
||||
public static BpmProcessInstanceResultEnum valueOfStatus(String status) {
|
||||
public static BpmnProcessInstanceResultEnum valueOfStatus(String status) {
|
||||
return Arrays.stream(values()).filter(it -> it.getStatus().equals(status)).findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
@ -1,21 +1,28 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
|
||||
public enum BpmFlowNodeType {
|
||||
|
||||
//0 发起人 1审批 2抄送 3条件 4路由
|
||||
NODE_STARTER("NODE_STARTER", "发起人节点"),
|
||||
NODE_ROUTER("NODE_ROUTER", "路由节点节点"),
|
||||
NODE_CONDITION("NODE_CONDITION", "条件节点"),
|
||||
NODE_TASK("NODE_TASK", "审核节点");
|
||||
/**
|
||||
* 加签类型
|
||||
*
|
||||
* @author zuoqinbo
|
||||
*/
|
||||
public enum BpmnReminderType {
|
||||
/**
|
||||
* 短信
|
||||
*/
|
||||
TEXT_MESSAGE("TEXT_MESSAGE", "短信"),
|
||||
/**
|
||||
* 站内信
|
||||
*/
|
||||
INBOX_MESSAGE("INBOX_MESSAGE", "站内信");
|
||||
|
||||
private String type;
|
||||
private String desc;
|
||||
|
||||
BpmFlowNodeType(String type, String desc) {
|
||||
BpmnReminderType(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public boolean isEqual(String type) {
|
||||
return this.type.equals(type);
|
||||
}
|
||||
@ -1,33 +1,33 @@
|
||||
package cn.axzo.workflow.core.common.enums;
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
|
||||
/**
|
||||
* Flowable Event Enum For RocketMQ
|
||||
* 流程活动节点相关的 MQ 事件枚举定义
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/9/4 10:38
|
||||
* @since 2023/11/21 17:24
|
||||
*/
|
||||
public enum FlowableEventModuleEnum {
|
||||
PROCESS_CREATED("process", "process-created", "流程创建"),
|
||||
public enum ProcessActivityEventEnum {
|
||||
|
||||
PROCESS_ACTIVITY_STARTED("process-activity", "process-activity-started", "流程活动节点已开始"),
|
||||
PROCESS_ACTIVITY_COMPLETED("process-activity", "process-activity-completed", "流程活动节点已完成"),
|
||||
PROCESS_ACTIVITY_CANCELLED("process-activity", "process-activity-cancelled", "流程活动节点已取消"),
|
||||
;
|
||||
|
||||
private final String module;
|
||||
|
||||
private final String tag;
|
||||
|
||||
private final String desc;
|
||||
private Event.EventCode eventCode;
|
||||
|
||||
private final Event.EventCode eventCode;
|
||||
|
||||
FlowableEventModuleEnum(String module, String tag, String desc) {
|
||||
this.module = module;
|
||||
this.tag = tag;
|
||||
this.desc = desc;
|
||||
ProcessActivityEventEnum(String module, String tag, String desc) {
|
||||
this.eventCode = Event.EventCode.builder()
|
||||
.module(module)
|
||||
.name(tag)
|
||||
.build();
|
||||
this.module = module;
|
||||
this.tag = tag;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getModule() {
|
||||
@ -13,7 +13,7 @@ public enum ProcessInstanceEventEnum {
|
||||
PROCESS_INSTANCE_CREATED("process-instance", "process-instance-created", "流程实例已创建"),
|
||||
PROCESS_INSTANCE_STARTED("process-instance", "process-instance-started", "流程实例已开始"),
|
||||
PROCESS_INSTANCE_CANCELLED("process-instance", "process-instance-cancelled", "流程实例已取消"),
|
||||
PROCESS_INSTANCE_REJECTED("process-instance", "process-instance-rejected", "流程实例已拒绝"),
|
||||
PROCESS_INSTANCE_REJECTED("process-instance", "process-instance-rejected", "流程实例已驳回"),
|
||||
PROCESS_INSTANCE_COMPLETED("process-instance", "process-instance-completed", "流程实例已结束"),
|
||||
;
|
||||
private final String module;
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
|
||||
/**
|
||||
* 流程消息推送相关的 MQ 事件枚举定义
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/22 13:58
|
||||
*/
|
||||
public enum ProcessMessagePushEventEnum {
|
||||
|
||||
PROCESS_PUSH_NOTICE("process-push", "process-push-notice", "站内信推送"),
|
||||
PROCESS_PUSH_PENDING("process-push", "process-push-pending", "待办推送"),
|
||||
PROCESS_PUSH_PENDING_COMPLETE("process-push", "process-push-pending-complete", "完成待办"),
|
||||
PROCESS_PUSH_SMS("process-push", "process-push-sms", "短信推送"),
|
||||
;
|
||||
|
||||
|
||||
private final String module;
|
||||
private final String tag;
|
||||
private final String desc;
|
||||
private Event.EventCode eventCode;
|
||||
|
||||
ProcessMessagePushEventEnum(String model, String tag, String desc) {
|
||||
this.eventCode = Event.EventCode.builder()
|
||||
.module(model)
|
||||
.name(tag)
|
||||
.build();
|
||||
this.module = model;
|
||||
this.tag = tag;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getModule() {
|
||||
return module;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public Event.EventCode getEventCode() {
|
||||
return eventCode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
import java.util.Arrays;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author syl
|
||||
* @date 2023/11/21
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum WorkspaceType {
|
||||
|
||||
/**
|
||||
* 工作台类型
|
||||
* 1- 企业 2-项目 6-oms
|
||||
*/
|
||||
ENT(1, "企业"),
|
||||
WORKSPACE(2, "项目"),
|
||||
OMS(6, "oms工作台");
|
||||
|
||||
private Integer code;
|
||||
private String desc;
|
||||
|
||||
public static WorkspaceType getType(Integer code) {
|
||||
return Arrays.stream(values()).filter(it -> it.getCode().equals(code))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package cn.axzo.workflow.common.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 组织架构人员选择器
|
||||
* 协同组织列表的限制条件
|
||||
*
|
||||
* @author tanjie@axzo.cn
|
||||
* @date 2023/11/14 11:29
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CooperationOrgDTO implements Serializable {
|
||||
/**
|
||||
* 企业组织架构范围
|
||||
**/
|
||||
private List<OrgScope> orgScopes;
|
||||
/**
|
||||
* 班组组织架构范围
|
||||
**/
|
||||
private List<OrgScope> workerTeamScopes;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class OrgScope implements Serializable {
|
||||
/**
|
||||
* 工作台类型
|
||||
*/
|
||||
private Integer workspaceType;
|
||||
/**
|
||||
* 工作台ID
|
||||
*/
|
||||
private Long workspaceId;
|
||||
/**
|
||||
* 单位 ID/班组单位 ID
|
||||
*/
|
||||
private Long ouId;
|
||||
}
|
||||
|
||||
}
|
||||
@ -12,35 +12,14 @@ import java.io.Serializable;
|
||||
public class BpmPageParam implements Serializable {
|
||||
private static final Integer PAGE_NO = 1;
|
||||
private static final Integer PAGE_SIZE = 10;
|
||||
@ApiModelProperty(
|
||||
value = "页码,从 1 开始",
|
||||
required = true,
|
||||
example = "1"
|
||||
)
|
||||
@NotNull(
|
||||
message = "页码不能为空"
|
||||
)
|
||||
@Min(
|
||||
value = 1L,
|
||||
message = "页码最小值为 1"
|
||||
)
|
||||
@ApiModelProperty(value = "页码,从 1 开始", required = true, example = "1")
|
||||
@NotNull(message = "页码不能为空")
|
||||
@Min(value = 1L, message = "页码最小值为 1")
|
||||
private Integer pageNo;
|
||||
@ApiModelProperty(
|
||||
value = "每页条数,最大值为 100",
|
||||
required = true,
|
||||
example = "10"
|
||||
)
|
||||
@NotNull(
|
||||
message = "每页条数不能为空"
|
||||
)
|
||||
@Min(
|
||||
value = 1L,
|
||||
message = "页码最小值为 1"
|
||||
)
|
||||
@Max(
|
||||
value = 100L,
|
||||
message = "页码最大值为 100"
|
||||
)
|
||||
@ApiModelProperty(value = "每页条数,最大值为 9999", required = true, example = "10")
|
||||
@NotNull(message = "每页条数不能为空")
|
||||
@Min(value = 1L, message = "页码最小值为 1")
|
||||
@Max(value = 9999L, message = "页码最大值为 9999")
|
||||
private Integer pageSize;
|
||||
|
||||
public BpmPageParam() {
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程定义中的按钮配置
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/13 13:44
|
||||
*/
|
||||
@ApiModel("JSON 版本的 BPMN 协议模型中的按钮管理")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class BpmnButtonConf implements Serializable {
|
||||
|
||||
/**
|
||||
* 发起人的按钮配置信息, 需要给全量按钮的配置
|
||||
*/
|
||||
@ApiModelProperty(value = "发起人的按钮配置信息")
|
||||
private List<BpmnButtonMetaInfo> initiator;
|
||||
|
||||
|
||||
/**
|
||||
* 当前审批人的按钮配置信息, JSON 格式
|
||||
*/
|
||||
@ApiModelProperty(value = "当前审批人的按钮配置信息")
|
||||
private List<BpmnButtonMetaInfo> current;
|
||||
|
||||
/**
|
||||
* 历史审批人的按钮配置信息, JSON 格式
|
||||
*/
|
||||
@ApiModelProperty(value = "历史审批人的按钮配置信息")
|
||||
private List<BpmnButtonMetaInfo> history;
|
||||
|
||||
/**
|
||||
* 抄送人的按钮配置信息, JSON 格式
|
||||
*/
|
||||
@ApiModelProperty(value = "抄送人的按钮配置信息")
|
||||
private List<BpmnButtonMetaInfo> carbonCopy;
|
||||
|
||||
public List<BpmnButtonMetaInfo> getInitiator() {
|
||||
return initiator;
|
||||
}
|
||||
|
||||
public void setInitiator(List<BpmnButtonMetaInfo> initiator) {
|
||||
this.initiator = initiator;
|
||||
}
|
||||
|
||||
public List<BpmnButtonMetaInfo> getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public void setCurrent(List<BpmnButtonMetaInfo> current) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
public List<BpmnButtonMetaInfo> getHistory() {
|
||||
return history;
|
||||
}
|
||||
|
||||
public void setHistory(List<BpmnButtonMetaInfo> history) {
|
||||
this.history = history;
|
||||
}
|
||||
|
||||
public List<BpmnButtonMetaInfo> getCarbonCopy() {
|
||||
return carbonCopy;
|
||||
}
|
||||
|
||||
public void setCarbonCopy(List<BpmnButtonMetaInfo> carbonCopy) {
|
||||
this.carbonCopy = carbonCopy;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 按钮元数据
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/14 23:53
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class BpmnButtonMetaInfo implements Serializable {
|
||||
|
||||
private Integer order;
|
||||
|
||||
private String btnKey;
|
||||
|
||||
private String btnName;
|
||||
|
||||
/**
|
||||
* 复选框的值
|
||||
*/
|
||||
private Boolean checked;
|
||||
|
||||
/**
|
||||
* 是否禁用勾选
|
||||
*/
|
||||
private Boolean disabled;
|
||||
|
||||
}
|
||||
@ -0,0 +1,172 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 条件
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/13 20:33
|
||||
*/
|
||||
@ApiModel("JSON 版本的 BPMN 协议模型中的条件")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class BpmnCondition {
|
||||
/**
|
||||
* 条件的中文名称, 前端使用的参数
|
||||
*/
|
||||
@ApiModelProperty(value = "条件的中文名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* string(字符串)/number(数字)/radio(单选)/checkbox(复选)
|
||||
*/
|
||||
@ApiModelProperty(value = "基础属性:字段类型", notes = "string, number, radio, checkbox", example = "string")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 字段 code
|
||||
*/
|
||||
@ApiModelProperty(value = "基础属性:字段 code", notes = "字段管理中字段的 Code", example = "fieldCode")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 操作符(与字段类型有关)
|
||||
* <p>
|
||||
* 当字段类型为 string 时, 操作符为 contains, notContains <br/>
|
||||
* 当字段类型为 number 时, 操作符为 eq, ne, gt, gte, lt, lte, between <br/>
|
||||
* 当字段类型为 radio 时, 操作符为 eq <br/>
|
||||
* 当字段类型为 checkbox 时, 操作符为 in <br/>
|
||||
*/
|
||||
@ApiModelProperty(value = "基础属性:操作符", notes = "操作符", example = "eq")
|
||||
private String operator;
|
||||
|
||||
/**
|
||||
* 默认的比较值
|
||||
*/
|
||||
@ApiModelProperty(value = "基础属性:默认的比较值", notes = "同时也用于 fieldDateType = radio", example = "1")
|
||||
private String defaultValue;
|
||||
|
||||
/**
|
||||
* 只有 fieldDateType = checkbox 才有值
|
||||
*/
|
||||
@ApiModelProperty(value = "当 fieldDateType = checkbox时, 选中的值")
|
||||
private List<String> defaultValues;
|
||||
|
||||
/**
|
||||
* 只有 operator = between 才有值 lt, lte
|
||||
*/
|
||||
@ApiModelProperty(value = "当 fieldDateType = number 并且 operator = between 时, 左侧操作符")
|
||||
private String leftOperator;
|
||||
|
||||
/**
|
||||
* 只有 operator = between 才有值 lt, lte,
|
||||
*/
|
||||
@ApiModelProperty(value = "当 fieldDateType = number 并且 operator = between 时, 右侧操作符")
|
||||
private String rightOperator;
|
||||
|
||||
/**
|
||||
* 只有 operator = between 才有值
|
||||
*/
|
||||
@ApiModelProperty(value = "当 fieldDateType = number 并且 operator = between 时, 左侧比较值")
|
||||
private String leftValue;
|
||||
|
||||
/**
|
||||
* 只有 operator = between 才有值
|
||||
*/
|
||||
@ApiModelProperty(value = "当 fieldDateType = number 并且 operator = between 时, 右侧比较值")
|
||||
private String rightValue;
|
||||
|
||||
/**
|
||||
* 记录前端的下拉选项, 后端无任何逻辑
|
||||
*/
|
||||
@ApiModelProperty(value = "记录前端的下拉选项, 后端无任何逻辑")
|
||||
private List<BpmnFieldOptionConf> options;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public String getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void setDefaultValue(String defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public List<String> getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
public void setDefaultValues(List<String> defaultValues) {
|
||||
this.defaultValues = defaultValues;
|
||||
}
|
||||
|
||||
public String getLeftOperator() {
|
||||
return leftOperator;
|
||||
}
|
||||
|
||||
public void setLeftOperator(String leftOperator) {
|
||||
this.leftOperator = leftOperator;
|
||||
}
|
||||
|
||||
public String getRightOperator() {
|
||||
return rightOperator;
|
||||
}
|
||||
|
||||
public void setRightOperator(String rightOperator) {
|
||||
this.rightOperator = rightOperator;
|
||||
}
|
||||
|
||||
public String getLeftValue() {
|
||||
return leftValue;
|
||||
}
|
||||
|
||||
public void setLeftValue(String leftValue) {
|
||||
this.leftValue = leftValue;
|
||||
}
|
||||
|
||||
public String getRightValue() {
|
||||
return rightValue;
|
||||
}
|
||||
|
||||
public void setRightValue(String rightValue) {
|
||||
this.rightValue = rightValue;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 条件组
|
||||
* <p>
|
||||
* 目前条件中的所有项都是"并且",所以没有第二个属性,如果以后有"或者"的情况,再加
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/13 19:58
|
||||
*/
|
||||
@ApiModel("JSON 版本的 BPMN 协议模型中的条件组")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class BpmnConditionGroup {
|
||||
|
||||
@ApiModelProperty(value = "条件组")
|
||||
private List<BpmnCondition> conditions;
|
||||
|
||||
/**
|
||||
* 同条件组内的多个条件之间的模式,默认为"and"
|
||||
*/
|
||||
private String conditionsType = "and";
|
||||
|
||||
public List<BpmnCondition> getConditions() {
|
||||
return conditions;
|
||||
}
|
||||
|
||||
public void setConditions(List<BpmnCondition> conditions) {
|
||||
this.conditions = conditions;
|
||||
}
|
||||
|
||||
public String getConditionsType() {
|
||||
return conditionsType;
|
||||
}
|
||||
|
||||
public void setConditionsType(String conditionsType) {
|
||||
this.conditionsType = conditionsType;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程定义中的字段管理
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/13 13:53
|
||||
*/
|
||||
@ApiModel("JSON 版本的 BPMN 协议模型中的字段管理")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class BpmnFieldConf implements Serializable {
|
||||
|
||||
/**
|
||||
* 字段的 code
|
||||
*/
|
||||
@ApiModelProperty(value = "字段的 code", example = "fieldCode", notes = "字段的 code 必须唯一")
|
||||
@NotBlank(message = "字段的 code 不能为空")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 字段的名称
|
||||
*/
|
||||
@ApiModelProperty(value = "字段的名称", example = "字段名称")
|
||||
@NotBlank(message = "字段的名称不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 字段的类型 string, number, radio, checkbox
|
||||
*/
|
||||
@ApiModelProperty(value = "字段的类型", example = "string", notes = "string, number, radio, checkbox")
|
||||
@NotBlank(message = "字段的类型不能为空")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 单选或多选的下拉选择框中的数据, 只有单选或多选的时候才会有值,并且内部的属性不应该为空
|
||||
*/
|
||||
@ApiModelProperty(value = "单选或多选的下拉选择框中的数据")
|
||||
private List<BpmnFieldOptionConf> options;
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 单选/多选的选项配置
|
||||
*/
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class BpmnFieldOptionConf implements Serializable {
|
||||
|
||||
/**
|
||||
* 选项的名称
|
||||
*/
|
||||
@ApiModelProperty(value = "选项的名称", example = "选项1")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 选项的值
|
||||
*/
|
||||
@ApiModelProperty(value = "选项的值", example = "1")
|
||||
private String value;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 新版本的流程定义模型 JSON 结构
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/18 16:57
|
||||
*/
|
||||
@ApiModel("新版本的流程定义模型 JSON 结构")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class BpmnJsonModel implements Serializable {
|
||||
|
||||
/**
|
||||
* 流程的Json 结构
|
||||
*/
|
||||
@ApiModelProperty(value = "流程的 Json 结构")
|
||||
private BpmnJsonNode node;
|
||||
|
||||
/**
|
||||
* 通知管理配置
|
||||
*/
|
||||
@ApiModelProperty(value = "通知管理配置")
|
||||
@Valid
|
||||
private BpmnNoticeConf noticeConf;
|
||||
|
||||
/**
|
||||
* 流程定义的全局默认按钮权限数据
|
||||
*/
|
||||
@ApiModelProperty(value = "流程按钮配置")
|
||||
@Valid
|
||||
private BpmnButtonConf buttonConf;
|
||||
|
||||
/**
|
||||
* 流程定义的全局字段管理数据
|
||||
*/
|
||||
@ApiModelProperty(value = "流程字段配置")
|
||||
@Valid
|
||||
private List<BpmnFieldConf> fieldConf;
|
||||
}
|
||||
@ -1,15 +1,17 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmFlowNodeType;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.HashMap;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JSON 版本的 BPMN 协议模型
|
||||
@ -19,25 +21,52 @@ import java.util.Map;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class BpmnJsonNode {
|
||||
public class BpmnJsonNode implements Serializable {
|
||||
|
||||
/**
|
||||
* 节点唯一标识
|
||||
*/
|
||||
@ApiModelProperty(value = "节点ID")
|
||||
@NotBlank(message = "节点的 ID 不能为空")
|
||||
private String id;
|
||||
/**
|
||||
* 上级节点唯一标识
|
||||
*/
|
||||
@ApiModelProperty(value = "父节点ID")
|
||||
private String parentId;
|
||||
@ApiModelProperty(value = "节点类型 NODE_STARTER/NODE_TASK/NODE_ROUTER/NODE_CONDITION")
|
||||
private BpmFlowNodeType type;
|
||||
/**
|
||||
* 节点类型 NODE_STARTER(发起人) NODE_TASK(审核节点) NODE_BUSINESS(业务节点) NODE_CARBON_COPY(抄送节点) NODE_EMPTY(空节点)
|
||||
* NODE_EXCLUSIVE_GATEWAY(排它网关) NODE_CONDITION(分支)
|
||||
*/
|
||||
@ApiModelProperty(value = "节点类型")
|
||||
@NotNull(message = "节点类型不能为空")
|
||||
private BpmnFlowNodeType type;
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
@ApiModelProperty(value = "节点名称")
|
||||
private String name;
|
||||
/**
|
||||
* 子节点信息(一般子节点的类型为审批节点/业务节点/抄送节点; 条件分支用 branches 字段)
|
||||
*/
|
||||
@ApiModelProperty(value = "子节点信息")
|
||||
private BpmnJsonNode children;
|
||||
/**
|
||||
* 分支节点信息(只用存储条件分支的信息, 而不能将审批节点/业务节点/抄送节点放到这里)
|
||||
*/
|
||||
@ApiModelProperty(value = "分支节点信息")
|
||||
private List<BpmnJsonNode> branches;
|
||||
/**
|
||||
* 节点扩展属性, 比如审批方式/审批人指定等针对节点的配置信息
|
||||
*/
|
||||
@ApiModelProperty(value = "节点扩展属性")
|
||||
private BpmnJsonNodeProperty property;
|
||||
|
||||
|
||||
/* 内部使用,不需要外界传 */
|
||||
private transient Map incoming = new HashMap();
|
||||
private transient List<String> incoming = new ArrayList<>();
|
||||
/* 内部使用, 用于 JSON 格式转换 */
|
||||
private transient BpmnJsonNode preJsonNode;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@ -55,11 +84,11 @@ public class BpmnJsonNode {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public BpmFlowNodeType getType() {
|
||||
public BpmnFlowNodeType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(BpmFlowNodeType type) {
|
||||
public void setType(BpmnFlowNodeType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@ -95,11 +124,19 @@ public class BpmnJsonNode {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public Map getIncoming() {
|
||||
public List<String> getIncoming() {
|
||||
return incoming;
|
||||
}
|
||||
|
||||
public void setIncoming(Map incoming) {
|
||||
public void setIncoming(List<String> incoming) {
|
||||
this.incoming = incoming;
|
||||
}
|
||||
|
||||
public BpmnJsonNode getPreJsonNode() {
|
||||
return preJsonNode;
|
||||
}
|
||||
|
||||
public void setPreJsonNode(BpmnJsonNode preJsonNode) {
|
||||
this.preJsonNode = preJsonNode;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverScopeEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* JSON 版本的 BPMN 协议中 UserTask 节点的属性扩展模型
|
||||
*/
|
||||
@ -12,41 +20,110 @@ import lombok.Data;
|
||||
@Data
|
||||
public class BpmnJsonNodeProperty {
|
||||
|
||||
//************* 审批方式Start **************//
|
||||
/**
|
||||
* 是否是多实例Task节点;
|
||||
* 审批方式: human(人工审批), autoPassed(自动通过), autoRejection(自动驳回), nobody(不审批[仅业务节点可能有该值])
|
||||
*/
|
||||
@ApiModelProperty("是否是多实例Task节点")
|
||||
private Boolean isMultiTask;
|
||||
@ApiModelProperty(value = "任务节点: 审批方式", notes = "human: 人工审批, autoPassed: 自动通过, autoRejection: 自动驳回, nobody: " +
|
||||
"不审批[仅业务节点可能有该值]")
|
||||
@NotBlank(message = "审批方式不能为空")
|
||||
private ApprovalMethodEnum approvalMethod;
|
||||
//************* 审批方式End **************//
|
||||
|
||||
|
||||
//************* 审批人所在范围Start **************//
|
||||
/**
|
||||
* 审批人所在范围: entWorkspace(企业工作台), projectWorkspace(项目工作台), preTaskUser(上节点审批人所在单位)
|
||||
*/
|
||||
@ApiModelProperty(value = "任务节点: 审批人所在范围", notes = "entWorkspace: 企业工作台, projectWorkspace: 项目工作台, preTaskUser:" +
|
||||
" 上节点审批人所在单位")
|
||||
private ApproverScopeEnum approverScope;
|
||||
//************* 审批人所在范围End **************//
|
||||
|
||||
|
||||
//************* 审批人指定Start **************//
|
||||
/**
|
||||
* 审批人指定: position(指定岗位), role(指定角色), identity(指定身份), initiatorLeader(发起人主管), initiatorLeaderRecursion(发起人多级主管),
|
||||
* fixedPerson(固定人员)
|
||||
*/
|
||||
@ApiModelProperty(value = "任务节点: 审批人指定", notes = "position: 指定岗位, role: 指定角色, identity: 指定身份, initiatorLeader: " +
|
||||
"发起人主管, initiatorLeaderRecursion: 发起人多级主管, fixedPerson: 固定人员")
|
||||
@NotBlank(message = "审批人指定不能为空")
|
||||
private ApproverSpecifyEnum approverSpecify;
|
||||
|
||||
/**
|
||||
* 具体的配置值
|
||||
* <p>
|
||||
* 如果是固定人员,那么这里是人员集合
|
||||
* [{"assignee":"111","assigneeType": "", "assignerName":"wangli", "personId": "", "tenantId":"296", "ouId":""}]
|
||||
*/
|
||||
@ApiModelProperty(value = "任务节点: 审批人指定的具体值")
|
||||
private String specifyValue;
|
||||
//************* 审批人指定End **************//
|
||||
|
||||
|
||||
//************* 多人审批时审批方式Start **************//
|
||||
/**
|
||||
* 是否是多实例Task节点, 在安心筑业务中, 所有节点应该都是多实例节点
|
||||
*/
|
||||
@ApiModelProperty(value = "任务节点: 是否是多实例Task节点", notes = "在安心筑业务中, 所有节点应该都是多实例节点")
|
||||
private Boolean isMultiTask = true;
|
||||
|
||||
/**
|
||||
* Task 多实例模式;OR:"或签",AND:"会签"
|
||||
*/
|
||||
@ApiModelProperty(value = "Task 多实例模式;OR:或签,AND:会签")
|
||||
@ApiModelProperty(value = "任务节点: 多实例模式;OR:或签,AND:会签")
|
||||
@NotNull(message = "多实例模式不能为空")
|
||||
private BpmnFlowNodeMode multiMode;
|
||||
//************* 多人审批时审批方式End **************//
|
||||
|
||||
|
||||
//************* 审批人为空时Start **************//
|
||||
/**
|
||||
* 审批人为空处理方式 autoPassed: 自动通过, autoRejection: 自动驳回, transferToAdmin: 转交给管理员
|
||||
*/
|
||||
@ApiModelProperty(value = "任务节点: 审批人为空处理方式", notes = "autoPassed: 自动通过, autoRejection: 自动驳回, transferToAdmin: 转交给管理员")
|
||||
@NotBlank(message = "审批人为空处理方式不能为空")
|
||||
private ApproverEmptyHandleTypeEnum approverEmptyHandleType;
|
||||
|
||||
@ApiModelProperty(value = "审批人为空时,指定的人", notes = "list 的 String 格式, String 是 BpmnTaskDelegateAssigner 对象")
|
||||
private String emptyApproverSpecify;
|
||||
//************* 审批人为空时的策略End **************//
|
||||
|
||||
|
||||
/**
|
||||
* 审批人为空是否允许自动跳过
|
||||
* 表单字段权限, JSON 格式,按照 UI 进行自定义组装, 引擎不做任何解析, 之后的需求会让业务方前端开发来消费这里的配置
|
||||
*/
|
||||
@ApiModelProperty(value = "审批人为空是否允许自动跳过")
|
||||
private Boolean allowSkip = false;
|
||||
@ApiModelProperty(value = "发起人节点/任务节点: 字段权限集合", notes = "后端不做任何解析, 前端给什么样,就返什么样")
|
||||
private String fieldPermission;
|
||||
|
||||
/**
|
||||
* 条件节点中是否是默认分支,可以都不传;
|
||||
* 按钮权限
|
||||
*/
|
||||
@ApiModelProperty(value = "条件节点中是否是默认分支,可以都不传")
|
||||
private Boolean defaultCondition;
|
||||
@ApiModelProperty(value = "发起人节点/任务节点: 按钮权限集合")
|
||||
private BpmnButtonConf buttonPermission;
|
||||
|
||||
|
||||
//************* 条件节点Start **************//
|
||||
/**
|
||||
* 条件节点专属属性: 是否是默认分支;
|
||||
*/
|
||||
@ApiModelProperty(value = "条件节点: 是否是默认条件分支")
|
||||
@NotNull(message = "是否是默认条件分支不能为空")
|
||||
private Boolean defaultBranch;
|
||||
|
||||
/**
|
||||
* 条件分支的Key
|
||||
* 条件节点专属属性: 条件分组集合
|
||||
*/
|
||||
@ApiModelProperty(value = "条件分支的Key")
|
||||
private String conditionBranchKey;
|
||||
@ApiModelProperty(value = "条件节点: 条件分组集合")
|
||||
private List<BpmnConditionGroup> groups;
|
||||
|
||||
/**
|
||||
* 条件节点当ConditionKey的值是多少,走该分支
|
||||
* 条件节点专属属性: 条件组之间的计算模型,目前仅支持 or
|
||||
*/
|
||||
@ApiModelProperty(value = "条件节点当ConditionKey的值是多少,走该分支")
|
||||
private Integer conditionBranchValue;
|
||||
@ApiModelProperty(value = "条件组之间的计算模型,目前仅支持 or")
|
||||
private String groupsType = "or";
|
||||
//************* 条件节点End **************//
|
||||
|
||||
/**
|
||||
* 发起时使用的表单 key
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 流程定义中的通知配置
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/13 13:38
|
||||
*/
|
||||
@ApiModel("JSON 版本的 BPMN 协议模型中的通知管理")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class BpmnNoticeConf implements Serializable {
|
||||
|
||||
/**
|
||||
* 通知的配置
|
||||
*/
|
||||
@Valid
|
||||
// @NotNull(message = "消息模板不能为空")
|
||||
private BpmnNoticeProperty notice;
|
||||
|
||||
/**
|
||||
* 待办的配置
|
||||
*/
|
||||
@Valid
|
||||
@NotNull(message = "待办模板不能为空")
|
||||
private BpmnPendingProperty pending;
|
||||
|
||||
/**
|
||||
* 短信的配置
|
||||
*/
|
||||
private BpmnSmsProperty sms;
|
||||
|
||||
public BpmnNoticeProperty getNotice() {
|
||||
return notice;
|
||||
}
|
||||
|
||||
public void setNotice(BpmnNoticeProperty notice) {
|
||||
this.notice = notice;
|
||||
}
|
||||
|
||||
public BpmnPendingProperty getPending() {
|
||||
return pending;
|
||||
}
|
||||
|
||||
public void setPending(BpmnPendingProperty pending) {
|
||||
this.pending = pending;
|
||||
}
|
||||
|
||||
public BpmnSmsProperty getSms() {
|
||||
return sms;
|
||||
}
|
||||
|
||||
public void setSms(BpmnSmsProperty sms) {
|
||||
this.sms = sms;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 站内信
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/12/2 18:36
|
||||
*/
|
||||
@ApiModel("JSON 版本的 BPMN 协议模型中的通知管理的站内信")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class BpmnNoticeProperty implements Serializable {
|
||||
|
||||
/**
|
||||
* 通知消息模板 ID
|
||||
*/
|
||||
@ApiModelProperty(value = "通知消息模板 ID")
|
||||
// @NotBlank(message = "通知消息模板 ID 不能为空")
|
||||
private String noticeMessageId;
|
||||
|
||||
/**
|
||||
* 用于前端回显数据, 服务端不解析
|
||||
*/
|
||||
@ApiModelProperty(value = "用于前端回显数据, 服务端不解析")
|
||||
private String viewJson;
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 待办
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/12/2 18:36
|
||||
*/
|
||||
@ApiModel("JSON 版本的 BPMN 协议模型中的通知管理的待办")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class BpmnPendingProperty {
|
||||
/**
|
||||
* 待办消息模板 ID
|
||||
*/
|
||||
@ApiModelProperty(value = "待办消息模板 ID")
|
||||
@NotBlank(message = "待办消息模板 ID 不能为空")
|
||||
private String pendingMessageId;
|
||||
|
||||
/**
|
||||
* 用于前端回显数据, 服务端不解析
|
||||
*/
|
||||
@ApiModelProperty(value = "用于前端回显数据, 服务端不解析")
|
||||
private String viewJson;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 短信
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/12/2 18:36
|
||||
*/
|
||||
@ApiModel("JSON 版本的 BPMN 协议模型中的通知管理的短信")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class BpmnSmsProperty {
|
||||
|
||||
/**
|
||||
* 短信模板 ID
|
||||
*/
|
||||
@ApiModelProperty(value = "短信模板 ID")
|
||||
private String smsId;
|
||||
|
||||
/**
|
||||
* 用于前端回显数据, 服务端不解析
|
||||
*/
|
||||
@ApiModelProperty(value = "用于前端回显数据, 服务端不解析")
|
||||
private String viewJson;
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.basic;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.BpmPageParam;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* yoke
|
||||
*
|
||||
* @author zuoqinbo
|
||||
* @version V1.0
|
||||
* @date 2023/11/15 17:20
|
||||
*/
|
||||
@Data
|
||||
public class ProcessBasicInfoQuery extends BpmPageParam {
|
||||
/**
|
||||
* 流程名称
|
||||
* 模糊查询
|
||||
*/
|
||||
private String processName;
|
||||
|
||||
|
||||
/**
|
||||
* 流程所属业务ID列表
|
||||
*/
|
||||
private List<String> businessIdList;
|
||||
|
||||
|
||||
/**
|
||||
* 流程状态 1、开启 0、关闭
|
||||
*
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.basic;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* yoke
|
||||
*
|
||||
* @author zuoqinbo
|
||||
* @version V1.0
|
||||
* @date 2023/11/15 17:20
|
||||
*/
|
||||
@Data
|
||||
public class ProcessBasicInfoResp {
|
||||
|
||||
/**
|
||||
* 流程ID
|
||||
* 模糊查询
|
||||
*/
|
||||
private String processModelId;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
* 模糊查询
|
||||
*/
|
||||
private String processName;
|
||||
|
||||
|
||||
/**
|
||||
* 流程所属业务
|
||||
* 模糊查询
|
||||
*/
|
||||
private String ownBusiness;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 流程所属业务ID列表
|
||||
*/
|
||||
private String ownBusinessId;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 流程工作台ID
|
||||
*/
|
||||
private String workBenchId;
|
||||
|
||||
|
||||
/**
|
||||
* 流程工作台名称
|
||||
*/
|
||||
private String workBenchName;
|
||||
|
||||
/**
|
||||
* 流程状态 1、开启 0、关闭
|
||||
*
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
|
||||
/**
|
||||
* 当前版本号
|
||||
*/
|
||||
private String version;
|
||||
|
||||
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.definition;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonModel;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@ -20,8 +20,20 @@ public class BpmnProcessDefinitionUpdateDTO {
|
||||
@ApiModelProperty(value = "流程模型 ID")
|
||||
private String processModelId;
|
||||
|
||||
@ApiModelProperty(value = "KEY")
|
||||
private String key;
|
||||
|
||||
@ApiModelProperty(value = "分类")
|
||||
private String category;
|
||||
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty(value = "JSON 转义的流程定义内容", notes = "枢智业务线在用")
|
||||
@Valid
|
||||
@NotNull(message = "模型定义内容不能为空")
|
||||
private BpmnJsonNode bpmJson;
|
||||
private BpmnJsonModel jsonModel;
|
||||
}
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.model;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonModel;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 创建流程模型的入参模型
|
||||
@ -15,11 +17,10 @@ import javax.validation.constraints.NotBlank;
|
||||
@ApiModel("创建流程模型的入参模型")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class BpmnModelCreateDTO {
|
||||
public class BpmnModelCreateDTO implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "流程模型标识", example = "process_key", hidden = true)
|
||||
@Length(max = 255, message = "流程标识最长只支持255个字符")
|
||||
@NotBlank(message = "流程模型表示不能为空")
|
||||
private String key;
|
||||
|
||||
/**
|
||||
@ -33,7 +34,8 @@ public class BpmnModelCreateDTO {
|
||||
/**
|
||||
* 自定义分类
|
||||
*/
|
||||
@ApiModelProperty(value = "自定义分类", notes = "由业务自定义", example = "1")
|
||||
@ApiModelProperty(value = "自定义分类", notes = "由业务自定义")
|
||||
@NotBlank(message = "自定义分类不能为空")
|
||||
private String category;
|
||||
|
||||
/**
|
||||
@ -42,16 +44,13 @@ public class BpmnModelCreateDTO {
|
||||
@ApiModelProperty(value = "描述", notes = "存放与底层模型中 meta_info 中")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 流程的Json 结构
|
||||
*/
|
||||
@ApiModelProperty(value = "流程的Json 结构", example = "1")
|
||||
private BpmnJsonNode node;
|
||||
@ApiModelProperty(value = "流程模型的 Json 结构")
|
||||
@Valid
|
||||
private BpmnJsonModel jsonModel;
|
||||
|
||||
/**
|
||||
* 租户Id
|
||||
*/
|
||||
@ApiModelProperty(value = "租户Id", example = "1")
|
||||
@NotBlank(message = "租户 ID 不能为空")
|
||||
private String tenantId;
|
||||
private String tenantId = "";
|
||||
}
|
||||
|
||||
@ -6,6 +6,8 @@ import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程模型搜索入参模型
|
||||
*/
|
||||
@ -29,8 +31,8 @@ public class BpmnModelSearchDTO extends BpmPageParam {
|
||||
/**
|
||||
* 流程分类
|
||||
*/
|
||||
@ApiModelProperty(value = "流程模型分类", example = "1")
|
||||
private String category;
|
||||
@ApiModelProperty(value = "流程模型分类集合", example = "1")
|
||||
private List<String> categories;
|
||||
|
||||
/**
|
||||
* 模型状态
|
||||
@ -39,9 +41,15 @@ public class BpmnModelSearchDTO extends BpmPageParam {
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 工作台ID
|
||||
* 工作台ID集合
|
||||
*/
|
||||
@ApiModelProperty(value = "租户 ID", example = "1")
|
||||
private String tenantId;
|
||||
@ApiModelProperty(value = "租户 ID 集合", example = "1")
|
||||
private List<String> tenantIds;
|
||||
|
||||
/**
|
||||
* 业务需求的参数,是否代运营
|
||||
*/
|
||||
@ApiModelProperty(value = "是否为代运营")
|
||||
private Boolean agent;
|
||||
|
||||
}
|
||||
|
||||
@ -21,6 +21,9 @@ public class BpmnProcessDefinitionPageDTO extends BpmPageParam {
|
||||
@NotBlank(message = "流程标识不能为空")
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* 如果是配置台(公共模型)则不传或传空字符串
|
||||
*/
|
||||
@ApiModelProperty(value = "租户Id", example = "1")
|
||||
private String tenantId;
|
||||
private String tenantId = "";
|
||||
}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.process;
|
||||
|
||||
import cn.axzo.workflow.common.model.dto.CooperationOrgDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -22,15 +25,32 @@ public class BpmnProcessInstanceCreateDTO {
|
||||
private String processDefinitionId;
|
||||
/**
|
||||
* 流程定义的标识
|
||||
* <p>
|
||||
* [对应业务分类的 businessId]
|
||||
*/
|
||||
@NotEmpty(message = "流程定义的标识不能为空")
|
||||
private String processDefinitionKey;
|
||||
|
||||
/**
|
||||
* 模型归属租户 ID
|
||||
* <p>
|
||||
* 为空时,默认是编辑公共流程模型, 如果是代运营创建,则必填
|
||||
*/
|
||||
@ApiModelProperty(value = "发起的模型是属于哪个租户")
|
||||
private String tenantId = "";
|
||||
|
||||
/**
|
||||
* 流程实例关联的变量
|
||||
*/
|
||||
private Map<String, Object> variables = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 组织关系
|
||||
*/
|
||||
@ApiModelProperty(value = "组织关系")
|
||||
@NotNull(message = "组织关系不能为空")
|
||||
private CooperationOrgDTO cooperationOrg;
|
||||
|
||||
/**
|
||||
* 业务的唯一标识
|
||||
* <p>
|
||||
@ -40,6 +60,8 @@ public class BpmnProcessInstanceCreateDTO {
|
||||
private String businessKey;
|
||||
|
||||
@ApiModelProperty(value = "发起人信息")
|
||||
@Valid
|
||||
@NotNull(message = "发起人不能为空")
|
||||
private BpmnTaskDelegateAssigner initiator;
|
||||
|
||||
/**
|
||||
@ -52,5 +74,7 @@ public class BpmnProcessInstanceCreateDTO {
|
||||
* 下级审批人
|
||||
*/
|
||||
@ApiModelProperty(value = "下级审批人", notes = "可为空,定义选择审批人,如果不为空,则覆盖下一级任务的审核人")
|
||||
@Valid
|
||||
private BpmnTaskDelegateAssigner nextApprover;
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.process;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.request.BpmPageParam;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
@ -30,8 +30,8 @@ public class BpmnProcessInstanceMyPageReqVO extends BpmPageParam {
|
||||
@ApiModelProperty(value = "业务KEY")
|
||||
private String businessKey;
|
||||
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已拒绝,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmProcessInstanceResultEnum result;
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已驳回,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmnProcessInstanceResultEnum result;
|
||||
|
||||
@ApiModelProperty(value = "自定义分类")
|
||||
private String category;
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 附件模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/22 23:17
|
||||
*/
|
||||
@ApiModel("附件模型")
|
||||
@Data
|
||||
public class AttachmentDTO {
|
||||
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 附件类型, 图片还是附件
|
||||
*/
|
||||
@ApiModelProperty(value = "附件类型")
|
||||
@NotNull(message = "附件类型不能为空")
|
||||
private AttachmentTypeEnum type;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
@ApiModelProperty(value = "文件名称不能为空")
|
||||
@NotBlank(message = "文件名称不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 文件描述
|
||||
*/
|
||||
@ApiModelProperty(value = "文件描述")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 文件地址
|
||||
*/
|
||||
@ApiModelProperty(value = "附件地址")
|
||||
@NotBlank(message = "附件地址不能为空")
|
||||
private String url;
|
||||
|
||||
}
|
||||
@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 转交审批任务的入参模型
|
||||
@ -20,10 +21,19 @@ public class BpmnTaskAssigneeDTO {
|
||||
@NotBlank(message = "任务 ID 不能为空")
|
||||
private String taskId;
|
||||
|
||||
@ApiModelProperty(value = "转交意见")
|
||||
private String advice;
|
||||
|
||||
/**
|
||||
* 附件列表
|
||||
*/
|
||||
@ApiModelProperty(value = "附件列表")
|
||||
private List<AttachmentDTO> attachmentList;
|
||||
|
||||
@ApiModelProperty(value = "审批任务原审批人", notes = "可以为空,意义在于可以将没有指派给任何人的任务转交给其他人")
|
||||
private BpmnTaskDelegateAssigner originAssigner;
|
||||
|
||||
@ApiModelProperty(value = "审批任务转发给谁", notes = "可以为空,意义在于如果分配给某离职的人,可能需要置为空")
|
||||
private BpmnTaskDelegateAssigner targetAssigner;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 对审批任务添加附件的入参模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/10/31 10:08
|
||||
*/
|
||||
@ApiModel("对审批任务添加附件的入参模型")
|
||||
@Data
|
||||
public class BpmnTaskAttachmentDTO {
|
||||
|
||||
@ApiModelProperty(value = "附件类型", notes = "一般是指格式, 如 png/jpeg/jpg/pdf 等, 强烈建议前端回传")
|
||||
@NotBlank(message = "附件类型不能为空")
|
||||
private String type;
|
||||
|
||||
@ApiModelProperty(value = "关联的审批流程实例 ID")
|
||||
@NotBlank(message = "流程实例 ID 不能为空")
|
||||
private String processInstanceId;
|
||||
|
||||
@ApiModelProperty(value = "关联的审批任务 ID")
|
||||
@NotBlank(message = "任务 ID 不能为空")
|
||||
private String taskId;
|
||||
|
||||
@ApiModelProperty(value = "附件名称", notes = "如果为空,则使用文件名")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "附件描述", notes = "现在的业务不会使用到")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty(value = "附件地址")
|
||||
@NotBlank(message = "附件地址不能为空")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 该字段引擎本来支撑,但不建议给前端使用
|
||||
*/
|
||||
// private InputStream content;
|
||||
}
|
||||
@ -1,12 +1,14 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import cn.axzo.workflow.common.valid.group.ValidGroup;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 审批任务节点的入参模型
|
||||
@ -14,10 +16,11 @@ import javax.validation.constraints.NotNull;
|
||||
*/
|
||||
@ApiModel("审批任务节点的入参模型")
|
||||
@Data
|
||||
@Validated
|
||||
public class BpmnTaskAuditDTO {
|
||||
|
||||
@ApiModelProperty(value = "任务编号", required = true, example = "1024")
|
||||
@NotEmpty(message = "任务编号不能为空", groups = {ValidGroup.Insert.class, ValidGroup.Update.class})
|
||||
@NotEmpty(message = "任务编号不能为空")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
@ -26,15 +29,24 @@ public class BpmnTaskAuditDTO {
|
||||
@ApiModelProperty(value = "审批意见")
|
||||
private String advice;
|
||||
|
||||
/**
|
||||
* 附件列表
|
||||
*/
|
||||
@ApiModelProperty(value = "附件列表")
|
||||
private List<AttachmentDTO> attachmentList;
|
||||
|
||||
/**
|
||||
* 当前审核人信息
|
||||
*/
|
||||
@NotNull(message = "审批人信息不能为空", groups = {ValidGroup.Insert.class, ValidGroup.Update.class})
|
||||
@ApiModelProperty(value = "当前审核人信息", notes = "可为空,则该任务不验证用户归属")
|
||||
@Valid
|
||||
@NotNull(message = "审批人不能为空")
|
||||
private BpmnTaskDelegateAssigner approver;
|
||||
|
||||
/**
|
||||
* 下级审批人
|
||||
*/
|
||||
@ApiModelProperty(value = "下级审批人信息", notes = "可为空,定义选择审批人,如果不为空,则覆盖下一级任务的审核人")
|
||||
@Valid
|
||||
private BpmnTaskDelegateAssigner nextApprover;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 对审批任务添加评论的入参模型
|
||||
@ -24,9 +25,9 @@ public class BpmnTaskCommentDTO {
|
||||
@NotBlank(message = "流程实例 ID 不能为空")
|
||||
private String processInstanceId;
|
||||
|
||||
@ApiModelProperty(value = "租户 ID")
|
||||
@NotBlank(message = "tenantId")
|
||||
private String tenantId;
|
||||
@ApiModelProperty(value = "操作人")
|
||||
@NotNull
|
||||
private BpmnTaskDelegateAssigner operator;
|
||||
|
||||
@ApiModelProperty(value = "评论内容")
|
||||
private String comment;
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 统一的工作流中的人员模型,兼容不同的业务方,如安心筑"唯一"人的定义需要工作台+身份 ID+身份类型;而枢智业务则只需要简单的 userId 即可
|
||||
* <p>
|
||||
* 为了解决各种业务的差异,统一定义该模型,已大范围覆盖小范围的方式进行兼容.
|
||||
*
|
||||
* @author zuoqinbo
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class BpmnTaskCountersignDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8106887960942113552L;
|
||||
|
||||
@ApiModelProperty(value = "审批任务ID")
|
||||
@NotEmpty(message = "任务ID不能为空")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 加签类型
|
||||
* 向前加签、向后加签
|
||||
*
|
||||
* @see cn.axzo.workflow.common.enums.BpmnCountersignType
|
||||
*/
|
||||
@ApiModelProperty(value = "加签类型")
|
||||
@NotEmpty(message = "加签类型不能为空")
|
||||
private String countersignType = "FORWARD_COUNTERSIGN";
|
||||
|
||||
@ApiModelProperty(value = "加签意见")
|
||||
private String advice;
|
||||
|
||||
/**
|
||||
* 附件列表
|
||||
*/
|
||||
@ApiModelProperty(value = "附件列表")
|
||||
private List<AttachmentDTO> attachmentList;
|
||||
|
||||
|
||||
@ApiModelProperty(value = "加签任务转发给谁")
|
||||
@NotNull(message = "加签任务接收人不能为空")
|
||||
private List<BpmnTaskDelegateAssigner> targetAssignerList;
|
||||
|
||||
@ApiModelProperty(value = "加签任务原发起人")
|
||||
@NotNull(message = "加签任务发起人不能为空")
|
||||
private BpmnTaskDelegateAssigner originAssigner;
|
||||
|
||||
|
||||
}
|
||||
@ -1,22 +1,31 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* 统一的工作流中的人员模型,兼容不同的业务方,如安心筑"唯一"人的定义需要工作台+身份 ID+身份类型;而枢智业务则只需要简单的 userId 即可
|
||||
* 统一的工作流中的人员模型,兼容不同的业务方,如安心筑"唯一"人的定义需要工作台+身份 ID+身份类型;<br/>
|
||||
* 而枢智业务则只需要简单的 userId 即可
|
||||
* <p>
|
||||
* 为了解决各种业务的差异,统一定义该模型,已大范围覆盖小范围的方式进行兼容.
|
||||
* 为了解决各种业务的差异,统一定义该模型,以大范围覆盖小范围的方式进行兼容.
|
||||
*
|
||||
* @author wangli
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@Validated
|
||||
public class BpmnTaskDelegateAssigner implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8106887960942113552L;
|
||||
@ -63,10 +72,16 @@ public class BpmnTaskDelegateAssigner implements Serializable {
|
||||
@NotBlank(message = "租户不能为空")
|
||||
private String tenantId;
|
||||
|
||||
public String buildAssigneeId() {
|
||||
/**
|
||||
* 人所在的单位 ID
|
||||
* 仅安心筑使用
|
||||
*/
|
||||
private String ouId;
|
||||
|
||||
public final String buildAssigneeId() {
|
||||
if (StringUtils.hasLength(assigneeType)) {
|
||||
return assignee + "_" + assigneeType;
|
||||
return tenantId + "|" + assignee + "|" + assigneeType;
|
||||
}
|
||||
return assignee;
|
||||
return tenantId + "|" + assignee;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.request.BpmPageParam;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
@ -36,8 +36,8 @@ public class BpmnTaskPageSearchDTO extends BpmPageParam {
|
||||
@ApiModelProperty(value = "业务 KEY")
|
||||
private String businessKey;
|
||||
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已拒绝,CANCELLED:已取消)", example = "APPROVED")
|
||||
private List<BpmProcessInstanceResultEnum> results;
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已驳回,CANCELLED:已取消)", example = "APPROVED")
|
||||
private List<BpmnProcessInstanceResultEnum> results;
|
||||
|
||||
@ApiModelProperty(value = "流程任务名", example = "芋道")
|
||||
private String name;
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 催办功能入参模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/22 10:33
|
||||
*/
|
||||
@ApiModel("催办功能入参模型")
|
||||
@Data
|
||||
public class BpmnTaskRemindDTO {
|
||||
|
||||
/**
|
||||
* 审批节点唯一标识
|
||||
*/
|
||||
@ApiModelProperty(value = "审批节点唯一标识")
|
||||
private String taskDefinitionKey;
|
||||
|
||||
/**
|
||||
* 催办方式
|
||||
* <p>
|
||||
* 站内信:notice 短信:sms
|
||||
*/
|
||||
@NotEmpty(message = "催办方式不能为空")
|
||||
private List<String> remindTypes;
|
||||
|
||||
/**
|
||||
* 流程实例 ID
|
||||
*/
|
||||
@ApiModelProperty("流程实例 ID")
|
||||
@NotBlank(message = "流程实例 ID 不能为空")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 租户 ID
|
||||
*/
|
||||
@ApiModelProperty("租户 ID")
|
||||
private String tenantId;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 扩展的历史任务表搜索入参模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/12/9 23:50
|
||||
*/
|
||||
@ApiModel("扩展的历史任务表搜索入参模型")
|
||||
@Data
|
||||
public class ExtHiTaskSearchDTO {
|
||||
|
||||
@ApiModelProperty("流程实例 ID")
|
||||
private String processInstanceId;
|
||||
|
||||
@ApiModelProperty("流程任务节点标识")
|
||||
private String taskDefinitionKey;
|
||||
|
||||
@ApiModelProperty("流程任务 ID")
|
||||
private String taskId;
|
||||
|
||||
@ApiModelProperty("操作人")
|
||||
private String assignee;
|
||||
|
||||
@ApiModelProperty("任务状态")
|
||||
private BpmnProcessInstanceResultEnum status;
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package cn.axzo.workflow.common.model.request.bpmn.task;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* workflow-engine
|
||||
*
|
||||
* @author zuoqinbo
|
||||
* @version V1.0
|
||||
* @date 2023/11/10 14:26
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ProcessNotify {
|
||||
|
||||
|
||||
/**
|
||||
* 待办模版ID
|
||||
*/
|
||||
private String todoTemplateId;
|
||||
|
||||
|
||||
/**
|
||||
* 通知消息模板ID
|
||||
*/
|
||||
private String msgNotifyTemplateId;
|
||||
|
||||
/**
|
||||
* 短信模板ID
|
||||
*/
|
||||
private String texMsgTemplateId;
|
||||
|
||||
}
|
||||
@ -32,8 +32,13 @@ public class CategoryCreateDTO {
|
||||
@ApiModelProperty(value = "状态", example = "true or false")
|
||||
private Boolean status;
|
||||
|
||||
@ApiModelProperty(value = "创建人姓名", example = "张三")
|
||||
private String operatorName;
|
||||
|
||||
@ApiModelProperty(value = "工作台类型值")
|
||||
private String workspaceCodeType;
|
||||
|
||||
@ApiModelProperty(value = "租户", example = "1")
|
||||
@NotBlank(message = "租户不能为空")
|
||||
private String tenantId;
|
||||
private String tenantId = "";
|
||||
|
||||
}
|
||||
|
||||
@ -27,7 +27,10 @@ public class CategorySearchDTO extends BpmPageParam {
|
||||
@ApiModelProperty(value = "状态", example = "0 or 1")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty(value = "工作台类型值")
|
||||
private String workspaceTypeCode;
|
||||
|
||||
@ApiModelProperty(value = "租户 ID", example = "1")
|
||||
@NotBlank(message = "租户不能为空")
|
||||
private String tenantId;
|
||||
private String tenantId = "";
|
||||
}
|
||||
|
||||
@ -47,6 +47,9 @@ public class BpmnModelBaseVO {
|
||||
@ApiModelProperty(value = "部署 ID")
|
||||
private String deploymentId;
|
||||
|
||||
@ApiModelProperty(value = "模型的编辑器源 ID", hidden = true)
|
||||
private transient String editorSourceId;
|
||||
|
||||
@ApiModelProperty(value = "模型元信息")
|
||||
private String metaInfo;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.model;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonModel;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@ -20,6 +20,11 @@ public class BpmnModelDetailVO extends BpmnModelBaseVO {
|
||||
* 流程的 Json 结构
|
||||
*/
|
||||
@ApiModelProperty(value = "流程的 Json 结构")
|
||||
private BpmnJsonNode bpmJson;
|
||||
private BpmnJsonModel bpmJson;
|
||||
|
||||
@ApiModelProperty(value = "启用状态")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty(value = "描述")
|
||||
private String description;
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.model;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 模型扩展VO
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/21 11:03
|
||||
*/
|
||||
@Data
|
||||
public class BpmnModelExtVO {
|
||||
|
||||
@ApiModelProperty(value = "模型ID")
|
||||
private String modelId;
|
||||
|
||||
@ApiModelProperty(value = "模型状态")
|
||||
private Integer status;
|
||||
}
|
||||
@ -1,10 +1,13 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.process;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonModel;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.Date;
|
||||
|
||||
@ApiModel("流程定义响应模型")
|
||||
@Data
|
||||
@ -30,10 +33,19 @@ public class BpmnProcessDefinitionVO {
|
||||
@NotEmpty(message = "流程分类不能为空")
|
||||
private String category;
|
||||
|
||||
@ApiModelProperty(value = "中断状态 1:激活 2:挂起", required = true, example = "1", notes = "参见 SuspensionState 枚举")
|
||||
@ApiModelProperty(value = "状态 1:生效中(激活) 2:历史(挂起)", required = true, example = "1", notes = "参见 SuspensionState 枚举")
|
||||
private Integer suspensionState;
|
||||
|
||||
@ApiModelProperty(value = "流程模型 JSON 数据")
|
||||
private BpmnJsonModel jsonModel;
|
||||
|
||||
@ApiModelProperty(value = "租户 ID")
|
||||
private String tenantId;
|
||||
|
||||
@ApiModelProperty(value = "创建时间", example = "2023-11-18 22:00:00")
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty(value = "操作人信息")
|
||||
private BpmnTaskDelegateAssigner operator;
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.process;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@ -23,8 +23,8 @@ public class BpmnProcessInstancePageItemVO {
|
||||
@ApiModelProperty(value = "流程分类", required = true, notes = "参见 bpm_model_category 数据字典", example = "1")
|
||||
private String category;
|
||||
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已拒绝,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmProcessInstanceResultEnum result;
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已驳回,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmnProcessInstanceResultEnum result;
|
||||
|
||||
@ApiModelProperty(value = "提交时间", required = true)
|
||||
private Date startTime;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.process;
|
||||
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
@ -26,8 +26,8 @@ public class BpmnProcessInstanceVO {
|
||||
@ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1")
|
||||
private String category;
|
||||
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已拒绝,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmProcessInstanceResultEnum result;
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已驳回,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmnProcessInstanceResultEnum result;
|
||||
|
||||
@ApiModelProperty(value = "提交时间")
|
||||
private Date createAt;
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.process;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程实例下的节点信息
|
||||
*
|
||||
@ -34,4 +38,14 @@ public class ProcessNodeDetailVO {
|
||||
*/
|
||||
private String formKey;
|
||||
|
||||
/**
|
||||
* 按钮配置信息,内部已计算兜底配置
|
||||
*/
|
||||
private BpmnButtonConf buttonConf;
|
||||
|
||||
/**
|
||||
* 推测出来的审批人
|
||||
*/
|
||||
private List<BpmnTaskDelegateAssigner> forecastAssigners;
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.task;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@ -24,7 +24,7 @@ public class BpmnHistoricTaskInstanceGroupVO {
|
||||
private String processInstanceId;
|
||||
|
||||
@ApiModelProperty(value = "审批任务节点的最终的状态")
|
||||
private BpmProcessInstanceResultEnum result;
|
||||
private BpmnProcessInstanceResultEnum result;
|
||||
|
||||
@ApiModelProperty(value = "该审批节点下的所有任务")
|
||||
private List<BpmnHistoricTaskInstanceVO> tasks;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.task;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
@ -49,8 +50,8 @@ public class BpmnHistoricTaskInstanceVO {
|
||||
@ApiModelProperty(value = "租户")
|
||||
private String tenantId;
|
||||
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已拒绝,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmProcessInstanceResultEnum result;
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已驳回,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmnProcessInstanceResultEnum result;
|
||||
|
||||
@ApiModelProperty(value = "任务审批意见")
|
||||
private String advice;
|
||||
@ -58,9 +59,15 @@ public class BpmnHistoricTaskInstanceVO {
|
||||
@ApiModelProperty(value = "当前任务关联评论信息")
|
||||
private List<BpmnHistoricCommentVO> comments;
|
||||
|
||||
@ApiModelProperty(value = "任务关联的附件")
|
||||
private List<AttachmentDTO> attachments;
|
||||
|
||||
@ApiModelProperty(value = "删除原因")
|
||||
private String deleteReason;
|
||||
|
||||
@ApiModelProperty(value = "操作描述")
|
||||
private String operationDesc;
|
||||
|
||||
@ApiModelProperty(value = "审批人的快照信息", notes = "完整的审批人信息,assignee 仅是唯一标识")
|
||||
private BpmnTaskDelegateAssigner assigneeSnapshot;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package cn.axzo.workflow.common.model.response.bpmn.task;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@ -21,8 +21,8 @@ public class BpmnTaskDonePageItemVO extends BpmnTaskTodoPageItemVO {
|
||||
@ApiModelProperty(value = "持续时间", required = true, example = "1000")
|
||||
private Long durationInMillis;
|
||||
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已拒绝,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmProcessInstanceResultEnum result;
|
||||
@ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已驳回,CANCELLED:已取消)", example = "APPROVED")
|
||||
private BpmnProcessInstanceResultEnum result;
|
||||
|
||||
@ApiModelProperty(value = "审批建议", required = true, example = "不请假了!")
|
||||
private String comment;
|
||||
|
||||
@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ApiModel("自定义分类详情响应模型")
|
||||
@Data
|
||||
public class CategoryItemVO {
|
||||
@ -25,4 +27,13 @@ public class CategoryItemVO {
|
||||
|
||||
@ApiModelProperty(value = "状态")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty(value = "操作人姓名")
|
||||
private String operatorName;
|
||||
|
||||
@ApiModelProperty(value = "工作台类型值")
|
||||
private String workspaceTypeCode;
|
||||
|
||||
@ApiModelProperty(value = "更新时间")
|
||||
private Date updateAt;
|
||||
}
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
package cn.axzo.workflow.common.model.response.mq;
|
||||
|
||||
import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 消息推送 MQ payload 模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/22 15:06
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class MessagePushDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 推送的消息的类型
|
||||
*/
|
||||
private ProcessMessagePushEventEnum type;
|
||||
|
||||
/**
|
||||
* 流程实例 ID
|
||||
*/
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 流程任务 ID
|
||||
*/
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 消息模板 ID
|
||||
*/
|
||||
private String templateId;
|
||||
|
||||
/**
|
||||
* 消息的接收人
|
||||
*/
|
||||
private BpmnTaskDelegateAssigner receivePerson;
|
||||
|
||||
/**
|
||||
* 可用的变量集合
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package cn.axzo.workflow.common.model.response.mq;
|
||||
|
||||
import cn.axzo.workflow.common.enums.ProcessActivityEventEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程活动 MQ payload 模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/21 18:01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ProcessActivityDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 流程实例相关 MQ 事件的数据类型
|
||||
*/
|
||||
private ProcessActivityEventEnum type;
|
||||
|
||||
/**
|
||||
* 节点唯一标识
|
||||
*/
|
||||
private String activityId;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 流程实例
|
||||
*/
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 流程定义版本
|
||||
*/
|
||||
private String processDefinitionId;
|
||||
|
||||
/**
|
||||
* 如果是"业务节点", 需要业务使用该 id 进行推动流程后续执行
|
||||
*/
|
||||
private String triggerId;
|
||||
|
||||
/**
|
||||
* 流程实例的所有变量
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
/**
|
||||
* 通过的人员
|
||||
*/
|
||||
private List<BpmnTaskDelegateAssigner> passedAssigners;
|
||||
|
||||
/**
|
||||
* 模型对应的通知模板配置信息
|
||||
*/
|
||||
private BpmnNoticeConf noticeConf;
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package cn.axzo.workflow.common.model.response.mq;
|
||||
|
||||
import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
@ -88,4 +89,9 @@ public class ProcessInstanceDTO implements Serializable {
|
||||
* 取消流程实例的特殊字段
|
||||
*/
|
||||
private String cancelReason;
|
||||
|
||||
/**
|
||||
* 模型对应的通知模板配置信息
|
||||
*/
|
||||
private BpmnNoticeConf noticeConf;
|
||||
}
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
package cn.axzo.workflow.common.model.response.mq;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnNoticeEnum;
|
||||
import cn.axzo.workflow.common.enums.ProcessTaskEventEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -78,4 +81,14 @@ public class ProcessTaskDTO implements Serializable {
|
||||
* 审批人信息
|
||||
*/
|
||||
private BpmnTaskDelegateAssigner approver;
|
||||
|
||||
/**
|
||||
* 通知方式
|
||||
*/
|
||||
private List<BpmnNoticeEnum> noticeMethod;
|
||||
|
||||
/**
|
||||
* 模型对应的通知模板配置信息
|
||||
*/
|
||||
private BpmnNoticeConf noticeConf;
|
||||
}
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
//package cn.axzo.workflow.client.model.response.process;
|
||||
//
|
||||
//import lombok.Data;
|
||||
//import org.flowable.engine.history.HistoricProcessInstance;
|
||||
//import org.springframework.util.CollectionUtils;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.Collections;
|
||||
//import java.util.Date;
|
||||
//import java.util.List;
|
||||
//
|
||||
///**
|
||||
// * TODO
|
||||
// *
|
||||
// * @author wangli
|
||||
// * @since 2023/7/26 20:32
|
||||
// */
|
||||
//@Data
|
||||
//public class CustomProcInstVO {
|
||||
//
|
||||
// private String businessKey;
|
||||
//
|
||||
// private String name;
|
||||
//
|
||||
// private String category;
|
||||
//
|
||||
// private String startUserId;
|
||||
//
|
||||
// private Date startTime;
|
||||
//
|
||||
// private String businessStatus;
|
||||
//
|
||||
// private Date endTime;
|
||||
//
|
||||
// public static CustomProcInstVO vo(HistoricProcessInstance instance, String category) {
|
||||
// CustomProcInstVO vo = new CustomProcInstVO();
|
||||
// vo.setName(instance.getName());
|
||||
// vo.setCategory(category);
|
||||
// vo.setBusinessKey(instance.getBusinessKey());
|
||||
// vo.setStartUserId(instance.getStartUserId());
|
||||
// vo.setStartTime(instance.getStartTime());
|
||||
// vo.setEndTime(instance.getEndTime());
|
||||
// vo.setBusinessStatus(instance.getBusinessStatus());
|
||||
// return vo;
|
||||
// }
|
||||
//
|
||||
// public static List<CustomProcInstVO> vos(List<HistoricProcessInstance> list, String category) {
|
||||
// if (CollectionUtils.isEmpty(list)) {
|
||||
// return Collections.emptyList();
|
||||
// }
|
||||
// List<CustomProcInstVO> vos = new ArrayList<>();
|
||||
// list.forEach(i -> vos.add(vo(i, category)));
|
||||
// return vos;
|
||||
// }
|
||||
//}
|
||||
@ -20,6 +20,10 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.basics</groupId>
|
||||
<artifactId>basics-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-processor-spring-boot-starter</artifactId>
|
||||
@ -76,5 +80,10 @@
|
||||
<groupId>cn.axzo.workflow</groupId>
|
||||
<artifactId>workflow-engine-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.workflow</groupId>
|
||||
<artifactId>workflow-engine-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
package cn.axzo.workflow.core.common.enums;
|
||||
|
||||
public enum BpmProcessInstanceStatusEnum {
|
||||
RUNNING(1, "进行中"),
|
||||
FINISH(2, "已完成");
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private final Integer status;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
BpmProcessInstanceStatusEnum(Integer status, String desc) {
|
||||
this.status = status;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
@ -11,14 +11,21 @@ import lombok.Getter;
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BpmErrorCode implements IProjectRespCode {
|
||||
public enum BpmnErrorCode implements IProjectRespCode {
|
||||
// ========== category 01-001 ==========
|
||||
CATEGORY_VALUE_EXISTS("01001", "分类值【{}】已经存在"),
|
||||
CATEGORY_ID_NOT_EXISTS("01002", "指定分类【{}】不存在"),
|
||||
CATEGORY_DATA_ERROR("01003", "分类数据异常"),
|
||||
|
||||
// ========== convertor 02-001 ==========
|
||||
CONVERTOR_UNKNOW_NODE_TYPE("02001", "节点类型【{}】暂不支持"),
|
||||
CONVERTOR_META_DATA_FORMAT_ERROR("02002", "JSON 数据格式有误"),
|
||||
CONVERTOR_META_DATA_FORMAT_ERROR("02002", "JSON 数据格式有误-{}: {}"),
|
||||
CONVERTOR_COMMON_ERROR("02003", "JSON 转 BPMN 失败, 原因:【{}】"),
|
||||
CONVERTOR_NODE_TYPE_NOT_SUPPORT("02004", "【{}】节点类型, ID:【{}】暂不支持"),
|
||||
CONVERTOR_OPERATION_STRING_TYPE_ERROR("02005", "条件节点运算符【{}】暂不支持"),
|
||||
CONVERTOR_OPERATION_NUMBER_TYPE_ERROR("02006", "条件节点运算符【{}】暂不支持"),
|
||||
CONVERTOR_OPERATION_RADIO_TYPE_ERROR("02007", "条件节点运算符【{}】暂不支持"),
|
||||
CONVERTOR_OPERATION_CHECKBOX_TYPE_ERROR("02008", "条件节点运算符【{}】暂不支持"),
|
||||
|
||||
|
||||
// ========== bpmn model 03-001 ==========
|
||||
@ -42,12 +49,17 @@ public enum BpmErrorCode implements IProjectRespCode {
|
||||
PROCESS_OPERATION_PARAM_VALID_ERROR("05001", "参数缺失, 请确保传入了 ID 或 businessKey 对流程实例进行操作"),
|
||||
PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS("05002", "流程取消失败,流程不处于运行中"),
|
||||
PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF("05003", "流程取消失败,该流程不是你发起的"),
|
||||
PROCESS_INSTANCE_NOT_EXISTS("05004", "流程实例不存在"),
|
||||
PROCESS_INSTANCE_NOT_EXISTS("05004", "流程实例不存在或已结束"),
|
||||
PROCESS_INSTANCE_ID_NOT_EXISTS("05005", "流程实例【{}】不存在"),
|
||||
PROCESS_INSTANCE_CANCELLED("05006", "流程实例已取消"),
|
||||
// ========== bpmn task 06-001 ==========
|
||||
TASK_COMPLETE_FAIL_NOT_EXISTS("06001", "未找到指定审批任务"),
|
||||
TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF("06002", "该任务的审批人不是你"),
|
||||
TASK_APOSTILLE_NOT_SUPPORT("06003", "当前加签模式不支持"),
|
||||
TASK_REMIND_ERROR_NOT_EXISTS("06004", "当前审批节点没有待审批任务, 不能催办"),
|
||||
ACTIVITY_TRIGGER_NOT_EXISTS("06005", "触发 ID:【{}】不存在"),
|
||||
CALC_TASK_ASSIGNEE_ERROR("06006", "执行计算审批候选人出现异常: {}"),
|
||||
|
||||
// ========== form Model 07-001 ==========
|
||||
FORM_MODEL_NOT_EXISTS("07001", "表单模型不存在"),
|
||||
FORM_MODEL_ID_NOT_EXISTS("07002", "表单模型ID【{}】不存在"),
|
||||
@ -57,6 +69,14 @@ public enum BpmErrorCode implements IProjectRespCode {
|
||||
// ========== form Instance 09-001 ==========
|
||||
// ========== flowable Engine 10-001 ==========
|
||||
ENGINE_EXECUTION_LOST_ID_ERROR("10001", "Execution 丢失"),
|
||||
ENGINE_USER_TASK_CALC_ERROR("10002", "计算用户任务节点的审批发生异常: 【{}】"),
|
||||
ENGINE_USER_TASK_TYPE_NOT_SUPPORT("10003", "审批指定方式暂不支持"),
|
||||
// ========== flowable Engine 99-001 ==========
|
||||
MES_PUSH_OBJECT_BUILD_ERROR("99001", "构建消息推送对象异常"),
|
||||
REPEAT_SUBMIT_TIME_ERROR_TIPS("99002", "重复提交间隔时间不能小于{}秒"),
|
||||
REPEAT_SUBMIT_ERROR_TIPS("99002", "{}"),
|
||||
|
||||
|
||||
|
||||
|
||||
// // ========== 流程模型 01-001 ==========
|
||||
@ -16,6 +16,7 @@ public enum BpmnProcessTaskResultEnum {
|
||||
// 引擎默认的标识,不允许修改
|
||||
DELETE_MI_EXECUTION("Delete MI execution", "多实例任务被删除"),
|
||||
INITIATOR_REVOCATION("INITIATOR_REVOCATION", "发起者主动撤销"),
|
||||
REJECTION_AUTO_COMPLETED("REJECTION_AUTO_COMPLETED", "审批驳回自动结束"),
|
||||
BACKED("BACKED", "退回");
|
||||
|
||||
private final String status;
|
||||
|
||||
@ -19,10 +19,6 @@ public class WorkflowEngineException extends ServiceException {
|
||||
this.code = code.getRespCode();
|
||||
}
|
||||
|
||||
public WorkflowEngineException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package cn.axzo.workflow.core.common.utils;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmFlowNodeType;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNodeProperty;
|
||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||
@ -35,18 +35,21 @@ import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmConstants.AND_SIGN_EXPRESSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmConstants.BPM_ALLOW_SKIP_USER_TASK;
|
||||
import static cn.axzo.workflow.common.constant.BpmConstants.END_EVENT_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
|
||||
import static cn.axzo.workflow.common.constant.BpmConstants.OR_SIGN_EXPRESSION;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmErrorCode.CONVERTOR_META_DATA_FORMAT_ERROR;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmErrorCode.CONVERTOR_UNKNOW_NODE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.END_EVENT_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.OR_SIGN_EXPRESSION_ONE_PASS;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_META_DATA_FORMAT_ERROR;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_UNKNOW_NODE_TYPE;
|
||||
import static org.flowable.bpmn.model.ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION;
|
||||
import static org.flowable.engine.delegate.BaseExecutionListener.EVENTNAME_END;
|
||||
import static org.flowable.engine.delegate.BaseExecutionListener.EVENTNAME_START;
|
||||
|
||||
/**
|
||||
* 该工具是以前枢智版本使用,候选迭代都通过 BpmnJsonConverterUtil 该工具操作
|
||||
*/
|
||||
@Slf4j
|
||||
@Deprecated
|
||||
public class BpmTransformUtil {
|
||||
public static byte[] transformBpmnJsonToXml(BpmnJsonNode bpmnJson, Model model) {
|
||||
return transformBpmnJsonToXml(bpmnJson, model, null);
|
||||
@ -60,7 +63,7 @@ public class BpmTransformUtil {
|
||||
process.setId(model.getKey());
|
||||
process.setName(model.getName());
|
||||
|
||||
if (BpmFlowNodeType.NODE_STARTER.equals(bpmnJson.getType())) {
|
||||
if (BpmnFlowNodeType.NODE_STARTER.equals(bpmnJson.getType())) {
|
||||
process.addFlowElement(createStartEvent(bpmnJson.getId(), Objects.nonNull(bpmnJson.getProperty()) ?
|
||||
bpmnJson.getProperty().getFormKey() : ""));
|
||||
}
|
||||
@ -114,17 +117,24 @@ public class BpmTransformUtil {
|
||||
if (StringUtils.isNotBlank(parentId)) {
|
||||
BpmnJsonNode parentNode = childNodeMap.get(parentId);
|
||||
if (parentNode != null) {
|
||||
if (BpmFlowNodeType.NODE_CONDITION.equals(parentNode.getType())) {
|
||||
if (BpmnFlowNodeType.NODE_CONDITION.equals(parentNode.getType())) {
|
||||
sequenceFlowId = parentNode.getId();
|
||||
flow.setName(parentNode.getName());
|
||||
if (!ObjectUtils.isEmpty(parentNode.getProperty()) && !Boolean.TRUE.equals(parentNode.getProperty().getDefaultCondition())) {
|
||||
if (!ObjectUtils.isEmpty(parentNode.getProperty()) && !Boolean.TRUE.equals(parentNode.getProperty().getDefaultBranch())) {
|
||||
//解析条件表达式
|
||||
StringBuffer conditionExpression = new StringBuffer();
|
||||
conditionExpression.append("${ ");
|
||||
conditionExpression.append("var:eq('" + parentNode.getProperty().getConditionBranchKey() + "', " + parentNode.getProperty().getConditionBranchValue() + ")");
|
||||
conditionExpression.append(" }");
|
||||
|
||||
flow.setConditionExpression(conditionExpression.toString());
|
||||
// StringBuffer conditionExpression = new StringBuffer();
|
||||
// conditionExpression.append("${ ")
|
||||
// .append("var:eq('")
|
||||
// .append(parentNode.getProperty()
|
||||
// .getConditionBranchKey())
|
||||
// .append("', ")
|
||||
// .append(parentNode.getProperty()
|
||||
// .getConditionBranchValue())
|
||||
// .append(")");
|
||||
// conditionExpression.append(" }");
|
||||
//
|
||||
// flow.setConditionExpression(conditionExpression
|
||||
// .toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,12 +168,11 @@ public class BpmTransformUtil {
|
||||
public static String create(String fromId, BpmnJsonNode flowNode, Process process, BpmnModel bpmnModel,
|
||||
List<SequenceFlow> sequenceFlows, Map<String, BpmnJsonNode> childNodeMap) throws InvocationTargetException, IllegalAccessException {
|
||||
String nodeType = flowNode.getType().getType();
|
||||
if (BpmFlowNodeType.NODE_ROUTER.isEqual(nodeType)) {
|
||||
if (BpmnFlowNodeType.NODE_EXCLUSIVE_GATEWAY.isEqual(nodeType)) {
|
||||
return createExclusiveGatewayBuilder(fromId, flowNode, process, bpmnModel, sequenceFlows, childNodeMap);
|
||||
} else if (BpmFlowNodeType.NODE_TASK.isEqual(nodeType)) {
|
||||
} else if (BpmnFlowNodeType.NODE_TASK.isEqual(nodeType)) {
|
||||
childNodeMap.put(flowNode.getId(), flowNode);
|
||||
Map incoming = flowNode.getIncoming();
|
||||
incoming.put("incoming", Collections.singletonList(fromId));
|
||||
flowNode.setIncoming(Collections.singletonList(fromId));
|
||||
String id = createTask(process, flowNode, sequenceFlows, childNodeMap);
|
||||
// 如果当前任务还有后续任务,则遍历创建后续任务
|
||||
BpmnJsonNode children = flowNode.getChildren();
|
||||
@ -172,10 +181,9 @@ public class BpmTransformUtil {
|
||||
} else {
|
||||
return id;
|
||||
}
|
||||
} else if (BpmFlowNodeType.NODE_STARTER.isEqual(nodeType)) {
|
||||
} else if (BpmnFlowNodeType.NODE_STARTER.isEqual(nodeType)) {
|
||||
childNodeMap.put(flowNode.getId(), flowNode);
|
||||
Map incoming = flowNode.getIncoming();
|
||||
incoming.put("incoming", Collections.singletonList(fromId));
|
||||
flowNode.setIncoming(Collections.singletonList(fromId));
|
||||
String id = createTask(process, flowNode, sequenceFlows, childNodeMap);
|
||||
// 如果当前任务还有后续任务,则遍历创建后续任务
|
||||
BpmnJsonNode children = flowNode.getChildren();
|
||||
@ -216,7 +224,7 @@ public class BpmTransformUtil {
|
||||
List<Map> conditions = Lists.newCopyOnWriteArrayList();
|
||||
for (BpmnJsonNode element : branches) {
|
||||
if (!ObjectUtils.isEmpty(element.getProperty())) {
|
||||
Boolean typeElse = element.getProperty().getDefaultCondition();
|
||||
Boolean typeElse = element.getProperty().getDefaultBranch();
|
||||
if (Boolean.TRUE.equals(typeElse)) {
|
||||
exclusiveGateway.setDefaultFlow(element.getId());
|
||||
}
|
||||
@ -232,19 +240,19 @@ public class BpmTransformUtil {
|
||||
Map condition = new HashMap();
|
||||
|
||||
//解析条件表达式
|
||||
StringBuffer conditionExpression = new StringBuffer();
|
||||
conditionExpression.append("${ ");
|
||||
conditionExpression.append("var:eq('" + element.getProperty().getConditionBranchKey() + "', " + element.getProperty().getConditionBranchValue() + ") ");
|
||||
conditionExpression.append(" }");
|
||||
condition.put("nodeName", nodeName);
|
||||
condition.put("expression", conditionExpression.toString());
|
||||
// StringBuffer conditionExpression = new StringBuffer();
|
||||
// conditionExpression.append("${ ");
|
||||
// conditionExpression.append("var:eq('" + element.getProperty().getConditionBranchKey
|
||||
// () + "', " + element.getProperty().getConditionBranchValue() + ") ");
|
||||
// conditionExpression.append(" }");
|
||||
// condition.put("nodeName", nodeName);
|
||||
// condition.put("expression", conditionExpression.toString());
|
||||
|
||||
conditions.add(condition);
|
||||
continue;
|
||||
}
|
||||
// 只生成一个任务,同时设置当前任务的条件
|
||||
Map incomingObj = children.getIncoming();
|
||||
incomingObj.put("incoming", Collections.singletonList(exclusiveGatewayId));
|
||||
children.setIncoming(Collections.singletonList(exclusiveGatewayId));
|
||||
String identifier = create(exclusiveGatewayId, children, process, bpmnModel, sequenceFlows, childNodeMap);
|
||||
List<SequenceFlow> flows = sequenceFlows.stream().filter(flow -> StringUtils.equals(exclusiveGatewayId,
|
||||
flow.getSourceRef()))
|
||||
@ -255,7 +263,6 @@ public class BpmTransformUtil {
|
||||
e.setName(nodeName);
|
||||
}
|
||||
// 设置条件表达式
|
||||
// TODO 不知道什么意思
|
||||
// if (Objects.isNull(e.getConditionExpression()) && StringUtils
|
||||
// .isNotBlank(expression)) {
|
||||
// e.setConditionExpression(expression);
|
||||
@ -273,16 +280,15 @@ public class BpmTransformUtil {
|
||||
if (Objects.nonNull(childNode) && StringUtils.isNotBlank(childNode.getId())) {
|
||||
String parentId = childNode.getParentId();
|
||||
BpmnJsonNode parentChildNode = childNodeMap.get(parentId);
|
||||
if (BpmFlowNodeType.NODE_ROUTER.equals(parentChildNode.getType())) {
|
||||
if (BpmnFlowNodeType.NODE_EXCLUSIVE_GATEWAY.equals(parentChildNode.getType())) {
|
||||
String endExId = parentChildNode.getId() + "end";
|
||||
process.addFlowElement(createExclusiveGateWayEnd(endExId));
|
||||
if (incoming == null || incoming.isEmpty()) {
|
||||
return create(exclusiveGatewayId, childNode, process, bpmnModel, sequenceFlows,
|
||||
childNodeMap);
|
||||
} else {
|
||||
Map incomingObj = childNode.getIncoming();
|
||||
// 所有 service task 连接 end exclusive gateway
|
||||
incomingObj.put("incoming", incoming);
|
||||
childNode.setIncoming(incoming);
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(incoming.get(0));
|
||||
// 1.0 先进行边连接, 暂存 nextNode
|
||||
BpmnJsonNode nextNode = childNode.getChildren();
|
||||
@ -339,8 +345,7 @@ public class BpmTransformUtil {
|
||||
|
||||
private static String createTask(Process process, BpmnJsonNode flowNode, List<SequenceFlow> sequenceFlows,
|
||||
Map<String, BpmnJsonNode> childNodeMap) {
|
||||
Map incomingJson = flowNode.getIncoming();
|
||||
List<String> incoming = (List<String>) incomingJson.get("incoming");
|
||||
List<String> incoming = flowNode.getIncoming();
|
||||
// 自动生成id
|
||||
// String id = id("serviceTask");
|
||||
String id = flowNode.getId();
|
||||
@ -383,15 +388,16 @@ public class BpmTransformUtil {
|
||||
// 设置多实例属性
|
||||
userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
|
||||
if (BpmnFlowNodeMode.OR.getType().equals(mode.getType())) {
|
||||
multiInstanceLoopCharacteristics.setCompletionCondition(OR_SIGN_EXPRESSION);
|
||||
multiInstanceLoopCharacteristics.setCompletionCondition(OR_SIGN_EXPRESSION_ONE_PASS);
|
||||
} else if (BpmnFlowNodeMode.AND.getType().equals(mode.getType())) {
|
||||
multiInstanceLoopCharacteristics.setCompletionCondition(AND_SIGN_EXPRESSION);
|
||||
}
|
||||
}
|
||||
// 设置审批人为空时,允许自动通过
|
||||
if (!ObjectUtils.isEmpty(flowNode.getProperty()) && flowNode.getProperty().getAllowSkip()) {
|
||||
userTask.setSkipExpression("${" + BPM_ALLOW_SKIP_USER_TASK + "}");
|
||||
}
|
||||
// if (!ObjectUtils.isEmpty(flowNode.getProperty()) && flowNode.getProperty()
|
||||
// .getAllowSkip()) {
|
||||
// userTask.setSkipExpression("${" + BPM_ALLOW_SKIP_USER_TASK + "}");
|
||||
// }
|
||||
if (!ObjectUtils.isEmpty(flowNode.getProperty()) && StringUtils.isNotBlank(flowNode.getProperty().getFormKey())) {
|
||||
userTask.setFormKey(flowNode.getProperty().getFormKey());
|
||||
}
|
||||
|
||||
@ -4,14 +4,24 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BpmCollectionUtils {
|
||||
public class BpmnCollectionUtils {
|
||||
|
||||
public static boolean containsAny(Object source, Object... targets) {
|
||||
return Arrays.asList(targets).contains(source);
|
||||
@ -0,0 +1,114 @@
|
||||
package cn.axzo.workflow.core.common.utils;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnCondition;
|
||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_OPERATION_CHECKBOX_TYPE_ERROR;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_OPERATION_NUMBER_TYPE_ERROR;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_OPERATION_RADIO_TYPE_ERROR;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_OPERATION_STRING_TYPE_ERROR;
|
||||
|
||||
/**
|
||||
* 表达式翻译器
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/16 23:30
|
||||
*/
|
||||
public final class BpmnExpressionTranslator {
|
||||
private BpmnExpressionTranslator() {}
|
||||
|
||||
public static String translateString(BpmnCondition condition) {
|
||||
// ${var:contains('variableName', 'hello')};
|
||||
// ${!var:contains('variableName', 'hello')}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (Objects.equals(condition.getOperator(), "contains")) {
|
||||
sb.append("var:contains('")
|
||||
.append(condition.getCode())
|
||||
.append("', '")
|
||||
.append(condition.getDefaultValue())
|
||||
.append("')");
|
||||
} else if (Objects.equals(condition.getOperator(), "notContains")) {
|
||||
sb.append("!var:contains('")
|
||||
.append(condition.getCode())
|
||||
.append("', '")
|
||||
.append(condition.getDefaultValue())
|
||||
.append("')");
|
||||
} else {
|
||||
// 其他非法的操作符都过滤掉,或在这里抛出异常
|
||||
throw new WorkflowEngineException(CONVERTOR_OPERATION_STRING_TYPE_ERROR, condition.getOperator());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String translateNumber(BpmnCondition condition) {
|
||||
List<String> operators = Lists.newArrayList("eq", "ne", "gt", "gte", "lt", "lte", "between");
|
||||
if (operators.contains(condition.getOperator())) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if ("between".equals(condition.getOperator())) {
|
||||
sb.append("var:")
|
||||
.append(condition.getLeftOperator())
|
||||
.append("('")
|
||||
.append(condition.getCode())
|
||||
.append("', ")
|
||||
.append(condition.getLeftValue())
|
||||
.append(")")
|
||||
.append(" && ")
|
||||
.append("var:")
|
||||
.append(condition.getRightOperator())
|
||||
.append("('")
|
||||
.append(condition.getCode())
|
||||
.append("', ")
|
||||
.append(condition.getRightValue())
|
||||
.append(")");
|
||||
} else {
|
||||
sb.append("var:")
|
||||
.append(condition.getOperator())
|
||||
.append("('")
|
||||
.append(condition.getCode())
|
||||
.append("', ")
|
||||
.append(condition.getDefaultValue())
|
||||
.append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
} else {
|
||||
throw new WorkflowEngineException(CONVERTOR_OPERATION_NUMBER_TYPE_ERROR, condition.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
public static String translateRadio(BpmnCondition condition) {
|
||||
if (Objects.equals(condition.getOperator(), "eq")) {
|
||||
return "var:" +
|
||||
condition.getOperator() +
|
||||
"('" +
|
||||
condition.getCode() +
|
||||
"', " +
|
||||
condition.getDefaultValue() +
|
||||
")";
|
||||
} else {
|
||||
throw new WorkflowEngineException(CONVERTOR_OPERATION_RADIO_TYPE_ERROR, condition.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
public static String translateCheckbox(BpmnCondition condition) {
|
||||
if (Objects.equals(condition.getOperator(), "in")) {
|
||||
StringBuilder sb = new StringBuilder("var:containsAny(")
|
||||
.append("'")
|
||||
.append(condition.getCode())
|
||||
.append("', ");
|
||||
condition.getDefaultValues().forEach(i -> {
|
||||
sb.append("'").append(i).append("',");
|
||||
});
|
||||
sb.delete(sb.length() - 1, sb.length());
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
} else {
|
||||
throw new WorkflowEngineException(CONVERTOR_OPERATION_CHECKBOX_TYPE_ERROR, condition.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,13 +1,98 @@
|
||||
package cn.axzo.workflow.core.common.utils;
|
||||
|
||||
import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnFieldConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonModel;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO;
|
||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.core.converter.json.AbstractBpmnJsonConverter;
|
||||
import cn.axzo.workflow.core.converter.json.EndEventJsonConverter;
|
||||
import cn.axzo.workflow.core.converter.json.ExclusiveGatewayJsonConverter;
|
||||
import cn.axzo.workflow.core.converter.json.NotSupportConverter;
|
||||
import cn.axzo.workflow.core.converter.json.ParallelGatewayJsonConverter;
|
||||
import cn.axzo.workflow.core.converter.json.ReceiveTaskJsonConverter;
|
||||
import cn.axzo.workflow.core.converter.json.SequenceFlowJsonConverter;
|
||||
import cn.axzo.workflow.core.converter.json.ServiceTaskJsonConverter;
|
||||
import cn.axzo.workflow.core.converter.json.StartEventJsonConverter;
|
||||
import cn.axzo.workflow.core.converter.json.UserTaskJsonConverter;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.flowable.bpmn.BpmnAutoLayout;
|
||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||
import org.flowable.bpmn.model.BaseElement;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.EndEvent;
|
||||
import org.flowable.bpmn.model.ExclusiveGateway;
|
||||
import org.flowable.bpmn.model.ExtensionAttribute;
|
||||
import org.flowable.bpmn.model.ExtensionElement;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.Gateway;
|
||||
import org.flowable.bpmn.model.ParallelGateway;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.ReceiveTask;
|
||||
import org.flowable.bpmn.model.SequenceFlow;
|
||||
import org.flowable.bpmn.model.ServiceTask;
|
||||
import org.flowable.bpmn.model.StartEvent;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.image.ProcessDiagramGenerator;
|
||||
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import static cn.axzo.workflow.core.common.enums.BpmErrorCode.CONVERTOR_COMMON_ERROR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_META;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_CARBON_COPY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_CURRENT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_HISTORY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_META;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_OPTION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NOTICE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_CHECKED;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_CODE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_DISABLED;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_KEY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_NAME;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_ORDER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_VALUE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.END_EVENT_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_NODE_JSON;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.SEQUENCE_FLOW_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.START_EVENT_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_NOTICE_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_PENDING_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_SMS_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_CONDITION;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_COMMON_ERROR;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getButtonConfig;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getFieldConfig;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNoticeConfig;
|
||||
|
||||
/**
|
||||
* BPMN json 格式转换工具
|
||||
@ -15,7 +100,26 @@ import static cn.axzo.workflow.core.common.enums.BpmErrorCode.CONVERTOR_COMMON_E
|
||||
* @author wangli
|
||||
* @since 2023/10/12 11:43
|
||||
*/
|
||||
public class BpmnJsonConverterUtil {
|
||||
public final class BpmnJsonConverterUtil {
|
||||
private BpmnJsonConverterUtil() {
|
||||
}
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BpmnJsonConverterUtil.class);
|
||||
private static final Map<Class<? extends BaseElement>, AbstractBpmnJsonConverter<? extends BaseElement>> CONVERTERS =
|
||||
new HashMap<>();
|
||||
|
||||
static {
|
||||
CONVERTERS.put(NotSupportConverter.NotSupportFlowElement.class, new NotSupportConverter());
|
||||
CONVERTERS.put(StartEvent.class, new StartEventJsonConverter());
|
||||
CONVERTERS.put(SequenceFlow.class, new SequenceFlowJsonConverter());
|
||||
CONVERTERS.put(EndEvent.class, new EndEventJsonConverter());
|
||||
|
||||
CONVERTERS.put(ExclusiveGateway.class, new ExclusiveGatewayJsonConverter());
|
||||
CONVERTERS.put(ParallelGateway.class, new ParallelGatewayJsonConverter());
|
||||
CONVERTERS.put(UserTask.class, new UserTaskJsonConverter());
|
||||
CONVERTERS.put(ServiceTask.class, new ServiceTaskJsonConverter());
|
||||
CONVERTERS.put(ReceiveTask.class, new ReceiveTaskJsonConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 BpmnModel 转成 JSON 格式对应对象
|
||||
@ -23,71 +127,495 @@ public class BpmnJsonConverterUtil {
|
||||
* @param bpmnModel Flowable 标准模型
|
||||
* @return {@link BpmnJsonNode} json 格式对象,可以直接解析
|
||||
*/
|
||||
public static BpmnJsonNode convertToJson(BpmnModel bpmnModel) {
|
||||
return new BpmnJsonNode();
|
||||
public static BpmnJsonModel convertToJson(BpmnModel bpmnModel) {
|
||||
BpmnJsonModel model = new BpmnJsonModel();
|
||||
Process mainProcess = bpmnModel.getMainProcess();
|
||||
BpmnJsonNode bpmnJsonNode = JSON.parseObject(mainProcess.getAttributeValue(null, FLOW_NODE_JSON),
|
||||
BpmnJsonNode.class);
|
||||
model.setNode(bpmnJsonNode);
|
||||
getNoticeConfig(mainProcess).ifPresent(model::setNoticeConf);
|
||||
getButtonConfig(mainProcess).ifPresent(model::setButtonConf);
|
||||
getFieldConfig(mainProcess).ifPresent(model::setFieldConf);
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 json 格式数据转的 BpmnJsonNode 对象,转换成 Flowable 标准的模型 {@link BpmnModel}
|
||||
*
|
||||
* @param bpmnJsonNode json 格式对象,可以直接解析
|
||||
* @param noticeConf
|
||||
* @param buttonConf
|
||||
* @param fieldConf
|
||||
* @return {@link BpmnModel}
|
||||
*/
|
||||
public static BpmnModel convertToBpmn(BpmnJsonNode bpmnJsonNode) {
|
||||
public static BpmnModel convertToBpmn(BpmnJsonNode bpmnJsonNode, String id, String name, String documentation,
|
||||
BpmnNoticeConf noticeConf, BpmnButtonConf buttonConf,
|
||||
List<BpmnFieldConf> fieldConf) {
|
||||
if (Objects.isNull(bpmnJsonNode)) {
|
||||
throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "JSON 数据为空");
|
||||
}
|
||||
switch (bpmnJsonNode.getType()) {
|
||||
case NODE_STARTER:
|
||||
break;
|
||||
// 提交的 BpmnJsonNode 全部都是任务是可执行节点, 这里的转换是全局都会增加开始和结束节点. 因为前段的提交的数据是不包含开始和结束
|
||||
BpmnModel bpmnModel = new BpmnModel();
|
||||
|
||||
ExtensionAttribute serverVersion = new ExtensionAttribute();
|
||||
serverVersion.setName(FLOW_SERVER_VERSION);
|
||||
serverVersion.setValue(FLOW_SERVER_VERSION_121);
|
||||
ExtensionAttribute jsonMetaValue = new ExtensionAttribute();
|
||||
jsonMetaValue.setName(FLOW_NODE_JSON);
|
||||
jsonMetaValue.setValue(JSON.toJSONString(bpmnJsonNode));
|
||||
|
||||
Process mainProcess = new Process();
|
||||
mainProcess.setId(id);
|
||||
mainProcess.setName(name);
|
||||
mainProcess.setDocumentation(documentation);
|
||||
mainProcess.addAttribute(serverVersion);
|
||||
mainProcess.addAttribute(jsonMetaValue);
|
||||
|
||||
// 设置流程的通知管理配置
|
||||
setProcessNoticeConfig(noticeConf, mainProcess);
|
||||
// 设置流程的默认的按钮配置
|
||||
setProcessButtonConfig(buttonConf, mainProcess);
|
||||
// 设置流程的字段元数据配置
|
||||
setProcessFieldConfig(fieldConf, mainProcess);
|
||||
|
||||
bpmnModel.addProcess(mainProcess);
|
||||
|
||||
// 创建固定的开始节点
|
||||
mainProcess.addFlowElement(convertJsonToElement(StartEvent.class, mainProcess));
|
||||
|
||||
// 创建固定的结束节点
|
||||
mainProcess.addFlowElement(convertJsonToElement(EndEvent.class, mainProcess));
|
||||
|
||||
// 解析前端传入的模型设计 json
|
||||
List<String> lastNodeIds = create(bpmnJsonNode, mainProcess, bpmnModel, START_EVENT_ID);
|
||||
|
||||
if (CollectionUtils.isEmpty(lastNodeIds)) {
|
||||
throw new WorkflowEngineException(CONVERTOR_COMMON_ERROR, "未找到链接结束节点的节点数据");
|
||||
}
|
||||
return new BpmnModel();
|
||||
|
||||
lastNodeIds.forEach(lastNodeId -> {
|
||||
SequenceFlow sequenceFlow = new SequenceFlow();
|
||||
sequenceFlow.setId(id(SEQUENCE_FLOW_ID));
|
||||
sequenceFlow.setSourceRef(lastNodeId);
|
||||
sequenceFlow.setTargetRef(END_EVENT_ID);
|
||||
mainProcess.addFlowElement(sequenceFlow);
|
||||
});
|
||||
new BpmnAutoLayout(bpmnModel).execute();
|
||||
return bpmnModel;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String jsonStr = "{\n" +
|
||||
" \"id\": \"NODE_STARTER\",\n" +
|
||||
" \"type\": \"NODE_STARTER\",\n" +
|
||||
" \"name\": \"发起\",\n" +
|
||||
" \"children\": {\n" +
|
||||
" \"id\": \"NODE_CONFIG\",\n" +
|
||||
" \"parentId\": \"NODE_STARTER\",\n" +
|
||||
" \"type\": \"NODE_TASK\",\n" +
|
||||
" \"name\": \"权限配置\",\n" +
|
||||
" \"children\": {\n" +
|
||||
" \"id\": \"NODE_RELEASE_DEV\",\n" +
|
||||
" \"parentId\": \"NODE_CONFIG\",\n" +
|
||||
" \"type\": \"NODE_TASK\",\n" +
|
||||
" \"name\": \"发布 DEV\",\n" +
|
||||
" \"children\": {\n" +
|
||||
" \"id\": \"NODE_RELEASE_TEST\",\n" +
|
||||
" \"parentId\": \"NODE_RELEASE_DEV\",\n" +
|
||||
" \"type\": \"NODE_TASK\",\n" +
|
||||
" \"name\": \"发布 TEST\",\n" +
|
||||
" \"children\": {\n" +
|
||||
" \"id\": \"NODE_RELEASE_PRE\",\n" +
|
||||
" \"parentId\": \"NODE_RELEASE_TEST\",\n" +
|
||||
" \"type\": \"NODE_TASK\",\n" +
|
||||
" \"name\": \"发布 PRE\",\n" +
|
||||
" \"children\": {\n" +
|
||||
" \"id\": \"NODE_RELEASE_PROD\",\n" +
|
||||
" \"parentId\": \"NODE_RELEASE_PRE\",\n" +
|
||||
" \"type\": \"NODE_TASK\",\n" +
|
||||
" \"name\": \"发布生产\",\n" +
|
||||
" \"children\": {\n" +
|
||||
" \"id\": \"NODE_ACCEPTANCE\",\n" +
|
||||
" \"parentId\": \"NODE_RELEASE_PROD\",\n" +
|
||||
" \"type\": \"NODE_TASK\",\n" +
|
||||
" \"name\": \"产品验收\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }";
|
||||
BpmnJsonNode bpmnJsonNode = JSON.parseObject(jsonStr, BpmnJsonNode.class);
|
||||
BpmnModel bpmnModel = convertToBpmn(bpmnJsonNode);
|
||||
System.out.println("bpmnModel = " + bpmnModel);
|
||||
private static void setProcessFieldConfig(List<BpmnFieldConf> fieldConf, Process mainProcess) {
|
||||
if (CollectionUtils.isEmpty(fieldConf)) {
|
||||
return;
|
||||
}
|
||||
ExtensionElement fieldConfigElement = new ExtensionElement();
|
||||
fieldConfigElement.setName(CONFIG_FIELD);
|
||||
|
||||
if (!CollectionUtils.isEmpty(fieldConf)) {
|
||||
fieldConf.forEach(i -> {
|
||||
ExtensionElement field = new ExtensionElement();
|
||||
field.setName(CONFIG_FIELD_META);
|
||||
|
||||
ExtensionAttribute fieldDataType = new ExtensionAttribute();
|
||||
fieldDataType.setName(ELEMENT_ATTRIBUTE_TYPE);
|
||||
fieldDataType.setValue(i.getType());
|
||||
field.addAttribute(fieldDataType);
|
||||
|
||||
ExtensionAttribute fieldName = new ExtensionAttribute();
|
||||
fieldName.setName(ELEMENT_ATTRIBUTE_NAME);
|
||||
fieldName.setValue(i.getName());
|
||||
field.addAttribute(fieldName);
|
||||
|
||||
ExtensionAttribute fieldCode = new ExtensionAttribute();
|
||||
fieldCode.setName(ELEMENT_ATTRIBUTE_CODE);
|
||||
fieldCode.setValue(i.getCode());
|
||||
field.addAttribute(fieldCode);
|
||||
|
||||
if (!CollectionUtils.isEmpty(i.getOptions())) {
|
||||
i.getOptions().forEach(j -> {
|
||||
ExtensionElement option = new ExtensionElement();
|
||||
option.setName(CONFIG_FIELD_OPTION);
|
||||
|
||||
ExtensionAttribute optionName = new ExtensionAttribute();
|
||||
optionName.setName(ELEMENT_ATTRIBUTE_NAME);
|
||||
optionName.setValue(j.getName());
|
||||
option.addAttribute(optionName);
|
||||
|
||||
ExtensionAttribute optionValue = new ExtensionAttribute();
|
||||
optionValue.setName(ELEMENT_ATTRIBUTE_VALUE);
|
||||
optionValue.setValue(j.getValue());
|
||||
option.addAttribute(optionValue);
|
||||
|
||||
field.addChildElement(option);
|
||||
});
|
||||
}
|
||||
fieldConfigElement.addChildElement(field);
|
||||
});
|
||||
}
|
||||
mainProcess.addExtensionElement(fieldConfigElement);
|
||||
}
|
||||
|
||||
private static void setProcessButtonConfig(BpmnButtonConf buttonConf, Process mainProcess) {
|
||||
if (Objects.isNull(buttonConf)) {
|
||||
return;
|
||||
}
|
||||
ExtensionElement buttonConfigElement = new ExtensionElement();
|
||||
buttonConfigElement.setName(CONFIG_BUTTON);
|
||||
|
||||
buildMetaButton(buttonConf.getInitiator(), CONFIG_BUTTON_TYPE_INITIATOR, buttonConfigElement);
|
||||
buildMetaButton(buttonConf.getCurrent(), CONFIG_BUTTON_TYPE_CURRENT, buttonConfigElement);
|
||||
buildMetaButton(buttonConf.getHistory(), CONFIG_BUTTON_TYPE_HISTORY, buttonConfigElement);
|
||||
buildMetaButton(buttonConf.getCarbonCopy(), CONFIG_BUTTON_TYPE_CARBON_COPY, buttonConfigElement);
|
||||
|
||||
mainProcess.addExtensionElement(buttonConfigElement);
|
||||
}
|
||||
|
||||
public static void buildMetaButton(List<BpmnButtonMetaInfo> buttonMetaInfos, String buttonType,
|
||||
ExtensionElement buttonConfigElement) {
|
||||
if (!CollectionUtils.isEmpty(buttonMetaInfos)) {
|
||||
ExtensionElement initiator = new ExtensionElement();
|
||||
initiator.setName(buttonType);
|
||||
buttonMetaInfos.forEach(i -> {
|
||||
ExtensionElement button = new ExtensionElement();
|
||||
button.setName(CONFIG_BUTTON_META);
|
||||
|
||||
ExtensionAttribute keyAttribute = new ExtensionAttribute();
|
||||
keyAttribute.setName(ELEMENT_ATTRIBUTE_KEY);
|
||||
keyAttribute.setValue(i.getBtnKey());
|
||||
button.addAttribute(keyAttribute);
|
||||
|
||||
ExtensionAttribute nameAttribute = new ExtensionAttribute();
|
||||
nameAttribute.setName(ELEMENT_ATTRIBUTE_NAME);
|
||||
nameAttribute.setValue(i.getBtnName());
|
||||
button.addAttribute(nameAttribute);
|
||||
|
||||
ExtensionAttribute valueAttribute = new ExtensionAttribute();
|
||||
valueAttribute.setName(ELEMENT_ATTRIBUTE_CHECKED);
|
||||
valueAttribute.setValue(String.valueOf(i.getChecked()));
|
||||
button.addAttribute(valueAttribute);
|
||||
|
||||
ExtensionAttribute orderAttribute = new ExtensionAttribute();
|
||||
orderAttribute.setName(ELEMENT_ATTRIBUTE_ORDER);
|
||||
orderAttribute.setValue(String.valueOf(i.getOrder()));
|
||||
button.addAttribute(orderAttribute);
|
||||
|
||||
ExtensionAttribute disabledAttribute = new ExtensionAttribute();
|
||||
disabledAttribute.setName(ELEMENT_ATTRIBUTE_DISABLED);
|
||||
disabledAttribute.setValue(String.valueOf(i.getDisabled()));
|
||||
button.addAttribute(disabledAttribute);
|
||||
initiator.addChildElement(button);
|
||||
});
|
||||
buttonConfigElement.addChildElement(initiator);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setProcessNoticeConfig(BpmnNoticeConf noticeConf, Process mainProcess) {
|
||||
if (Objects.isNull(noticeConf)) {
|
||||
return;
|
||||
}
|
||||
ExtensionElement noticeConfigElement = new ExtensionElement();
|
||||
noticeConfigElement.setName(CONFIG_NOTICE);
|
||||
|
||||
// 通知消息模板配置
|
||||
if (Objects.nonNull(noticeConf.getNotice()) && Objects.nonNull(noticeConf.getNotice().getNoticeMessageId())) {
|
||||
ExtensionElement noticeMessage = new ExtensionElement();
|
||||
noticeMessage.setName(TEMPLATE_NOTICE_MESSAGE_ID);
|
||||
ExtensionAttribute noticeMessageAttribute = new ExtensionAttribute();
|
||||
noticeMessageAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
|
||||
noticeMessageAttribute.setValue(noticeConf.getNotice().getNoticeMessageId());
|
||||
noticeMessage.addAttribute(noticeMessageAttribute);
|
||||
noticeMessage.setElementText(StringUtils.hasLength(noticeConf.getNotice().getViewJson()) ?
|
||||
noticeConf.getNotice().getViewJson() : "");
|
||||
noticeConfigElement.addChildElement(noticeMessage);
|
||||
}
|
||||
|
||||
// 代办消息模板配置
|
||||
if (Objects.nonNull(noticeConf.getPending()) && Objects.nonNull(noticeConf.getPending().getPendingMessageId())) {
|
||||
ExtensionElement pendingMessage = new ExtensionElement();
|
||||
pendingMessage.setName(TEMPLATE_PENDING_MESSAGE_ID);
|
||||
ExtensionAttribute pendingMessageAttribute = new ExtensionAttribute();
|
||||
pendingMessageAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
|
||||
pendingMessageAttribute.setValue(noticeConf.getPending().getPendingMessageId());
|
||||
pendingMessage.addAttribute(pendingMessageAttribute);
|
||||
pendingMessage.setElementText(StringUtils.hasLength(noticeConf.getPending().getViewJson()) ?
|
||||
noticeConf.getPending().getViewJson() : "");
|
||||
noticeConfigElement.addChildElement(pendingMessage);
|
||||
}
|
||||
|
||||
// 短信模板配置
|
||||
if (Objects.nonNull(noticeConf.getSms()) && Objects.nonNull(noticeConf.getSms().getSmsId())) {
|
||||
ExtensionElement smsMessage = new ExtensionElement();
|
||||
smsMessage.setName(TEMPLATE_SMS_MESSAGE_ID);
|
||||
ExtensionAttribute smsMessageAttribute = new ExtensionAttribute();
|
||||
smsMessageAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
|
||||
smsMessageAttribute.setValue(noticeConf.getSms().getSmsId());
|
||||
smsMessage.addAttribute(smsMessageAttribute);
|
||||
smsMessage.setElementText(StringUtils.hasLength(noticeConf.getSms().getViewJson()) ?
|
||||
noticeConf.getSms().getViewJson() : "");
|
||||
noticeConfigElement.addChildElement(smsMessage);
|
||||
}
|
||||
mainProcess.addExtensionElement(noticeConfigElement);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] transformBytes(BpmnModel bpmnModel) {
|
||||
byte[] xmlMeta = new BpmnXMLConverter().convertToXML(bpmnModel);
|
||||
String xmlResult = new String(xmlMeta);
|
||||
log.debug("xmlMeta: " + xmlResult);
|
||||
return xmlMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 BpmnModel 的 TargetNamespace
|
||||
*
|
||||
* @param bpmnModel 被设置的模型
|
||||
* @param category category 的值
|
||||
*/
|
||||
public static void setCategory(BpmnModel bpmnModel, String category) {
|
||||
bpmnModel.setTargetNamespace(category);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建对应类型节点并保存在 bpmnModel 中
|
||||
*
|
||||
* @param preNodeIds 上级节点的 Id 结合,用于链接当前创建节点
|
||||
* @param bpmnJsonNode 前端传入节点数据,不是全数据,而是对应层级
|
||||
* @param mainProcess 主 Process 对象
|
||||
* @param bpmnModel 最终的 BPMN model
|
||||
* @return 创建的节点的 ID
|
||||
*/
|
||||
private static List<String> create(BpmnJsonNode bpmnJsonNode, Process mainProcess,
|
||||
BpmnModel bpmnModel, String... preNodeIds) {
|
||||
// 设置来源节点
|
||||
bpmnJsonNode.setIncoming(Lists.newArrayList(preNodeIds));
|
||||
|
||||
Class<? extends BaseElement> clz;
|
||||
switch (bpmnJsonNode.getType()) {
|
||||
case NODE_STARTER:
|
||||
// 该节点主要解决仿钉钉的设计器里面无法设置标准开始和结束节点,而是特殊的一个发起人节点
|
||||
case NODE_TASK:
|
||||
clz = UserTask.class;
|
||||
break;
|
||||
case NODE_EXCLUSIVE_GATEWAY:
|
||||
clz = ExclusiveGateway.class;
|
||||
break;
|
||||
case NODE_PARALLEL_GATEWAY:
|
||||
clz = ParallelGateway.class;
|
||||
break;
|
||||
case NODE_CONDITION:
|
||||
// 这个节点非常特殊,整个协议转换完全不会走到这里
|
||||
clz = SequenceFlow.class;
|
||||
break;
|
||||
case NODE_BUSINESS:
|
||||
// "业务节点"是很特殊包装节点,因为它在前端有两种配法:
|
||||
// 一种是: 可以不配置人, 当运行到该节点时, 需要由外部发送信号来触发(这个信号的发送方通常是程序应用), 流程继续运行.
|
||||
// 另外一种是: 可以配置人, 当运行到该节点时, 有需要人为来处理. 这种情况下, 该节点就是一个普通的任务节点.
|
||||
clz = ReceiveTask.class;
|
||||
if (!Objects.equals(ApprovalMethodEnum.nobody, bpmnJsonNode.getProperty().getApprovalMethod())) {
|
||||
clz = UserTask.class;
|
||||
}
|
||||
break;
|
||||
case NODE_TRIGGER:
|
||||
// 这个类型目前暂不支持
|
||||
case NODE_CARBON_COPY:
|
||||
// 这里可以细化, 待后续有实际场景了,再处理, 现目前只有 "抄送" 功能可能会用到
|
||||
clz = ServiceTask.class;
|
||||
break;
|
||||
default:
|
||||
clz = NotSupportConverter.NotSupportFlowElement.class;
|
||||
break;
|
||||
}
|
||||
|
||||
// 根据 BpmnJsonNode 创建节点
|
||||
FlowElement flowElement = convertJsonToElement(clz, bpmnJsonNode, mainProcess);
|
||||
mainProcess.addFlowElement(flowElement);
|
||||
|
||||
if (Lists.newArrayList(preNodeIds).isEmpty()) {
|
||||
// first time entrance, do nothing.
|
||||
} else if (Lists.newArrayList(preNodeIds).size() == 1 && !NODE_CONDITION.equals(bpmnJsonNode.getType())) {
|
||||
mainProcess.addFlowElement(convertJsonToElement(SequenceFlow.class, bpmnJsonNode, mainProcess));
|
||||
} else {
|
||||
// 将网关分支的最末级节点 ID 关联到网关的 children 节点上,网关协议转换才算闭环
|
||||
Arrays.stream(preNodeIds).forEach(income -> {
|
||||
bpmnJsonNode.setIncoming(Lists.newArrayList(income));
|
||||
FlowElement sequenceFlow = convertJsonToElement(SequenceFlow.class, bpmnJsonNode, mainProcess);
|
||||
mainProcess.addFlowElement(sequenceFlow);
|
||||
});
|
||||
}
|
||||
|
||||
// 只有网关才会涉及到 branch
|
||||
List<String> branchLastNodeIds = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(bpmnJsonNode.getBranches())) {
|
||||
Gateway gateway = (Gateway) flowElement;
|
||||
for (BpmnJsonNode branch : bpmnJsonNode.getBranches()) {
|
||||
// branch == node_condition
|
||||
BpmnJsonNode nextJsonNode =
|
||||
(Objects.isNull(branch.getChildren()) || Objects.isNull(branch.getChildren().getType()) || Objects.equals(NODE_EMPTY, branch.getChildren().getType()))
|
||||
? bpmnJsonNode.getChildren() : branch.getChildren();
|
||||
|
||||
if (Objects.isNull(nextJsonNode) || Objects.isNull(nextJsonNode.getId()) ||
|
||||
(Objects.equals(NODE_EMPTY, nextJsonNode.getType()) &&
|
||||
(Objects.isNull(nextJsonNode.getChildren()) || Objects.isNull(nextJsonNode.getChildren().getId())))) {
|
||||
BpmnJsonNode tempEndNode = new BpmnJsonNode();
|
||||
tempEndNode.setIncoming(Lists.newArrayList(gateway.getId()));
|
||||
tempEndNode.setId(END_EVENT_ID);
|
||||
nextJsonNode = tempEndNode;
|
||||
} else {
|
||||
if (Objects.equals(NODE_EMPTY, nextJsonNode.getType()) && Objects.nonNull(nextJsonNode.getChildren())) {
|
||||
nextJsonNode = nextJsonNode.getChildren();
|
||||
}
|
||||
nextJsonNode.setIncoming(Lists.newArrayList(gateway.getId()));
|
||||
|
||||
// 将 node_condition 放入计算节点的上级属性中,方便顺序流转换器对条件进行处理
|
||||
nextJsonNode.setPreJsonNode(branch);
|
||||
}
|
||||
SequenceFlow sequenceFlow = (SequenceFlow) convertJsonToElement(SequenceFlow.class, nextJsonNode,
|
||||
mainProcess);
|
||||
mainProcess.addFlowElement(sequenceFlow);
|
||||
|
||||
// 设置网关默认流
|
||||
if (Objects.nonNull(branch.getProperty()) && Boolean.TRUE.equals(branch.getProperty().getDefaultBranch())) {
|
||||
// 如果是默认流, 以防止前端输入错误, 强制置空
|
||||
sequenceFlow.setConditionExpression(null);
|
||||
gateway.setDefaultFlow(sequenceFlow.getId());
|
||||
}
|
||||
|
||||
if (Objects.nonNull(branch.getChildren()) && StringUtils.hasLength(branch.getChildren().getId())
|
||||
&& !Objects.equals(NODE_EMPTY, branch.getChildren().getType())) {
|
||||
branchLastNodeIds.addAll(create(branch.getChildren(), mainProcess, bpmnModel));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 开始处理下级节点
|
||||
BpmnJsonNode children = bpmnJsonNode.getChildren();
|
||||
if (Objects.isNull(children) || (Objects.equals(NODE_EMPTY, children.getType()) && (Objects.isNull(children.getChildren()) || Objects.isNull(children.getChildren().getId()))) || !StringUtils.hasLength(children.getId())) {
|
||||
if (CollectionUtils.isEmpty(branchLastNodeIds)) {
|
||||
return Lists.newArrayList(flowElement.getId());
|
||||
} else {
|
||||
return branchLastNodeIds;
|
||||
}
|
||||
} else {
|
||||
if (Objects.equals(NODE_EMPTY, children.getType()) && Objects.nonNull(children.getChildren()) && Objects.nonNull(children.getChildren().getId())) {
|
||||
children = children.getChildren();
|
||||
}
|
||||
if (CollectionUtils.isEmpty(branchLastNodeIds)) {
|
||||
return create(children, mainProcess, bpmnModel, flowElement.getId());
|
||||
}
|
||||
return create(children, mainProcess, bpmnModel, branchLastNodeIds.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
|
||||
private static void setDefaultFlow(BpmnJsonNode bpmnJsonNode, Process mainProcess, FlowElement sequenceFlow) {
|
||||
// 查找并设置网关的默认流
|
||||
if (Objects.nonNull(bpmnJsonNode.getPreJsonNode()) && Objects.nonNull(bpmnJsonNode.getPreJsonNode().getProperty())
|
||||
&& Boolean.TRUE.equals(bpmnJsonNode.getPreJsonNode().getProperty().getDefaultBranch())) {
|
||||
FlowElement preFlowNode;
|
||||
if (Objects.nonNull(preFlowNode =
|
||||
mainProcess.getFlowElement(bpmnJsonNode.getPreJsonNode().getId(), true))
|
||||
&& preFlowNode instanceof Gateway) {
|
||||
Gateway gateway = (Gateway) preFlowNode;
|
||||
gateway.setDefaultFlow(sequenceFlow.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static FlowElement convertJsonToElement(Class<? extends BaseElement> clz, Process process) {
|
||||
return convertJsonToElement(clz, null, process);
|
||||
}
|
||||
|
||||
private static FlowElement convertJsonToElement(Class<? extends BaseElement> clz, BpmnJsonNode bpmnJsonNode,
|
||||
Process process) {
|
||||
AbstractBpmnJsonConverter converter = CONVERTERS.getOrDefault(clz, new NotSupportConverter());
|
||||
FlowElement flowElement = converter.convertJsonToElement(bpmnJsonNode, process);
|
||||
if (Objects.nonNull(bpmnJsonNode)) {
|
||||
converter.addNodeTypeAttribute(flowElement, copy(bpmnJsonNode));
|
||||
converter.addJsonValueAttribute(flowElement, copy(bpmnJsonNode));
|
||||
}
|
||||
return flowElement;
|
||||
}
|
||||
|
||||
private static BpmnJsonNode copy(BpmnJsonNode source) {
|
||||
if (Objects.isNull(source)) {
|
||||
return null;
|
||||
}
|
||||
BpmnJsonNode target = new BpmnJsonNode();
|
||||
target.setId(source.getId());
|
||||
target.setParentId(source.getParentId());
|
||||
target.setType(source.getType());
|
||||
target.setName(source.getName());
|
||||
target.setProperty(source.getProperty());
|
||||
target.setIncoming(source.getIncoming());
|
||||
return target;
|
||||
}
|
||||
|
||||
public static String id(String prefix) {
|
||||
return prefix + "_" + UUID.randomUUID().toString().replace("-", "").toLowerCase();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
// String fileName = "/Users/wangli/work/company/yizhi/workflow-engine/workflow-engine-server/src/main" +
|
||||
// "/resources/配置台模型.json";
|
||||
// String fileName = "/Users/wangli/work/company/yizhi/workflow-engine/workflow-engine-server/src/main" +
|
||||
// "/resources/权限点模型.json";
|
||||
String fileName = "/Users/wangli/work/company/yizhi/workflow-engine/workflow-engine-server/src/main" +
|
||||
"/resources/temp2.json";
|
||||
byte[] bytes = Files.readAllBytes(Paths.get(fileName));
|
||||
String content = new String(bytes, StandardCharsets.UTF_8);
|
||||
|
||||
BpmnModelCreateDTO model = JSON.parseObject(content, BpmnModelCreateDTO.class);
|
||||
BpmnModel bpmnModel = convertToBpmn(model.getJsonModel().getNode(), "id", "测试", "remark",
|
||||
model.getJsonModel().getNoticeConf(),
|
||||
model.getJsonModel().getButtonConf(), model.getJsonModel().getFieldConf());
|
||||
System.out.println("bpmnModel = " + bpmnModel);
|
||||
|
||||
convertToJson(bpmnModel);
|
||||
|
||||
transformBytes(bpmnModel);
|
||||
generateImage(bpmnModel);
|
||||
}
|
||||
|
||||
public static void generateImage(BpmnModel bpmnModel) {
|
||||
String pngName = "/Users/wangli/work/company/yizhi/workflow-engine/workflow-engine-server/src/main" +
|
||||
"/resources/test.png";
|
||||
ProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
|
||||
|
||||
// 设置字体渲染选项
|
||||
System.setProperty("java.awt.headless", "false");
|
||||
System.setProperty("awt.useSystemAAFontSettings", "on");
|
||||
System.setProperty("swing.aatext", "true");
|
||||
System.setProperty("sun.java2d.xrender", "true");
|
||||
|
||||
try {
|
||||
// 创建输出流
|
||||
OutputStream outputStream = Files.newOutputStream(new File(pngName).toPath());
|
||||
// 生成图像并写入输出流
|
||||
InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", new ArrayList<>(), 1.0d, true);
|
||||
|
||||
// 将图像流写入输出流
|
||||
try {
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = imageStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 处理异常
|
||||
} finally {
|
||||
try {
|
||||
imageStream.close();
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
// 处理异常
|
||||
}
|
||||
}
|
||||
// 关闭输出流
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
// 处理异常
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,272 @@
|
||||
package cn.axzo.workflow.core.common.utils;
|
||||
|
||||
import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverScopeEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnFieldConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnFieldOptionConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeProperty;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnPendingProperty;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnSmsProperty;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.ExtensionElement;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.ReceiveTask;
|
||||
import org.flowable.bpmn.model.ServiceTask;
|
||||
import org.flowable.bpmn.model.Task;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_EMPTY_HANDLE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_SCOPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_SPECIFY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_META;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_CARBON_COPY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_CURRENT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_HISTORY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_META;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_OPTION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NODE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NOTICE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_CHECKED;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_CODE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_DISABLED;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_KEY;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_NAME;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_ORDER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_VALUE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_NOTICE_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_PENDING_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_SMS_MESSAGE_ID;
|
||||
|
||||
/**
|
||||
* 协助解析 BPMN 文件中的自定义扩展字段和属性
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/15 22:51
|
||||
*/
|
||||
public final class BpmnMetaParserHelper {
|
||||
private BpmnMetaParserHelper() {}
|
||||
|
||||
public static Optional<String> getProcessServerVersion(Process process) {
|
||||
return Optional.ofNullable(process.getAttributeValue(null, FLOW_SERVER_VERSION));
|
||||
}
|
||||
|
||||
public static Optional<BpmnNoticeConf> getNoticeConfig(Process process) {
|
||||
List<ExtensionElement> elements = process.getExtensionElements().getOrDefault(CONFIG_NOTICE,
|
||||
Collections.emptyList());
|
||||
if (CollectionUtils.isEmpty(elements)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
BpmnNoticeConf conf = new BpmnNoticeConf();
|
||||
elements.get(0).getChildElements().forEach((k, v) -> {
|
||||
if (TEMPLATE_NOTICE_MESSAGE_ID.equals(k)) {
|
||||
BpmnNoticeProperty notice = new BpmnNoticeProperty();
|
||||
notice.setNoticeMessageId(v.get(0).getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE));
|
||||
notice.setViewJson(v.get(0).getElementText());
|
||||
conf.setNotice(notice);
|
||||
} else if (TEMPLATE_PENDING_MESSAGE_ID.equals(k)) {
|
||||
BpmnPendingProperty pending = new BpmnPendingProperty();
|
||||
pending.setPendingMessageId(v.get(0).getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE));
|
||||
pending.setViewJson(v.get(0).getElementText());
|
||||
conf.setPending(pending);
|
||||
} else if (TEMPLATE_SMS_MESSAGE_ID.equals(k)) {
|
||||
BpmnSmsProperty sms = new BpmnSmsProperty();
|
||||
sms.setSmsId(v.get(0).getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE));
|
||||
sms.setViewJson(v.get(0).getElementText());
|
||||
conf.setSms(sms);
|
||||
}
|
||||
});
|
||||
return Optional.of(conf);
|
||||
}
|
||||
|
||||
public static Optional<BpmnButtonConf> getButtonConfig(Process process) {
|
||||
return parseButtonConfig(process.getExtensionElements().getOrDefault(CONFIG_BUTTON, Collections.emptyList()));
|
||||
}
|
||||
|
||||
private static Optional<BpmnButtonConf> parseButtonConfig(List<ExtensionElement> elements) {
|
||||
if (CollectionUtils.isEmpty(elements) || CollectionUtils.isEmpty(elements.get(0).getChildElements())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
BpmnButtonConf conf = new BpmnButtonConf();
|
||||
elements.get(0).getChildElements().forEach((k, v) -> {
|
||||
List<BpmnButtonMetaInfo> buttonMetaInfos = new ArrayList<>();
|
||||
buildButtonMetaInfo(v, buttonMetaInfos);
|
||||
if (CONFIG_BUTTON_TYPE_INITIATOR.equals(k)) {
|
||||
conf.setInitiator(buttonMetaInfos);
|
||||
} else if (CONFIG_BUTTON_TYPE_CURRENT.equals(k)) {
|
||||
conf.setCurrent(buttonMetaInfos);
|
||||
} else if (CONFIG_BUTTON_TYPE_HISTORY.equals(k)) {
|
||||
conf.setHistory(buttonMetaInfos);
|
||||
} else if (CONFIG_BUTTON_TYPE_CARBON_COPY.equals(k)) {
|
||||
conf.setCarbonCopy(buttonMetaInfos);
|
||||
}
|
||||
});
|
||||
return Optional.of(conf);
|
||||
}
|
||||
|
||||
public static Optional<BpmnButtonConf> getButtonConfig(Process process, String taskDefinitionKey) {
|
||||
if (StringUtils.hasLength(taskDefinitionKey)) {
|
||||
Task task = (Task) process.getFlowElement(taskDefinitionKey);
|
||||
if (Objects.isNull(task)) {
|
||||
return getButtonConfig(process);
|
||||
} else {
|
||||
Optional<BpmnButtonConf> optConfig =
|
||||
parseButtonConfig(task.getExtensionElements().getOrDefault(CONFIG_BUTTON,
|
||||
Collections.emptyList()));
|
||||
if (optConfig.isPresent()) {
|
||||
return optConfig;
|
||||
} else {
|
||||
return getButtonConfig(process);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return getButtonConfig(process);
|
||||
}
|
||||
}
|
||||
|
||||
private static void buildButtonMetaInfo(List<ExtensionElement> v, List<BpmnButtonMetaInfo> buttonMetaInfos) {
|
||||
v.get(0).getChildElements().get(CONFIG_BUTTON_META).forEach(i -> {
|
||||
BpmnButtonMetaInfo buttonMetaInfo = new BpmnButtonMetaInfo();
|
||||
buttonMetaInfo.setBtnKey(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_KEY));
|
||||
buttonMetaInfo.setBtnName(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_NAME));
|
||||
buttonMetaInfo.setChecked(Boolean.valueOf(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_CHECKED)));
|
||||
buttonMetaInfo.setOrder(Integer.valueOf(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_ORDER)));
|
||||
buttonMetaInfo.setDisabled(Boolean.valueOf(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_DISABLED)));
|
||||
buttonMetaInfos.add(buttonMetaInfo);
|
||||
});
|
||||
}
|
||||
|
||||
public static Optional<List<BpmnFieldConf>> getFieldConfig(Process process) {
|
||||
List<ExtensionElement> elements = process.getExtensionElements().getOrDefault(CONFIG_FIELD,
|
||||
Collections.emptyList());
|
||||
if (CollectionUtils.isEmpty(elements)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
List<BpmnFieldConf> fields = new ArrayList<>();
|
||||
elements.get(0).getChildElements().getOrDefault(CONFIG_FIELD_META, Collections.emptyList()).forEach(i -> {
|
||||
BpmnFieldConf conf = new BpmnFieldConf();
|
||||
conf.setType(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_TYPE));
|
||||
conf.setName(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_NAME));
|
||||
conf.setCode(i.getAttributeValue(null, ELEMENT_ATTRIBUTE_CODE));
|
||||
|
||||
List<BpmnFieldOptionConf> options = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(i.getChildElements())) {
|
||||
i.getChildElements().get(CONFIG_FIELD_OPTION).forEach(j -> {
|
||||
BpmnFieldOptionConf option = new BpmnFieldOptionConf();
|
||||
option.setName(j.getAttributeValue(null, ELEMENT_ATTRIBUTE_NAME));
|
||||
option.setValue(j.getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE));
|
||||
options.add(option);
|
||||
});
|
||||
conf.setOptions(options);
|
||||
}
|
||||
|
||||
fields.add(conf);
|
||||
});
|
||||
return Optional.of(fields);
|
||||
}
|
||||
|
||||
public static Optional<BpmnFlowNodeType> getNodeType(FlowElement flowElement) {
|
||||
if (flowElement instanceof UserTask
|
||||
|| flowElement instanceof ServiceTask
|
||||
|| flowElement instanceof ReceiveTask) {
|
||||
return defaultValid(flowElement, CONFIG_NODE_TYPE)
|
||||
.map(element -> BpmnFlowNodeType.valueOf(element.getElementText()));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static Optional<ApprovalMethodEnum> getApprovalMethod(UserTask userTask) {
|
||||
return defaultValid(userTask, CONFIG_APPROVAL_METHOD)
|
||||
.map(element -> ApprovalMethodEnum.valueOf(element.getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE)));
|
||||
}
|
||||
|
||||
public static Optional<ApproverScopeEnum> getApproverScope(UserTask userTask) {
|
||||
return defaultValid(userTask, CONFIG_APPROVER_SCOPE)
|
||||
.map(element -> ApproverScopeEnum.valueOf(element.getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE)));
|
||||
}
|
||||
|
||||
public static Optional<ApproverSpecifyEnum> getApproverSpecify(UserTask userTask) {
|
||||
return defaultValid(userTask, CONFIG_APPROVER_SPECIFY)
|
||||
.map(element -> ApproverSpecifyEnum.valueOf(element.getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE)));
|
||||
}
|
||||
|
||||
public static Optional<String> getApproverSpecifyValue(UserTask userTask) {
|
||||
return defaultValid(userTask, CONFIG_APPROVER_SPECIFY)
|
||||
.map(element -> StringUtils.hasLength(element.getElementText())
|
||||
? element.getElementText()
|
||||
: "[]");
|
||||
}
|
||||
|
||||
public static Optional<ApproverEmptyHandleTypeEnum> getApproverEmptyHandleType(UserTask userTask) {
|
||||
return defaultValid(userTask, CONFIG_APPROVER_EMPTY_HANDLE_TYPE)
|
||||
.map(element -> ApproverEmptyHandleTypeEnum.valueOf(element.getAttributeValue(null,
|
||||
ELEMENT_ATTRIBUTE_VALUE)));
|
||||
}
|
||||
|
||||
public static Optional<String> getEmptyApproverSpecify(UserTask userTask) {
|
||||
return defaultValid(userTask, CONFIG_APPROVER_EMPTY_HANDLE_TYPE)
|
||||
.map(element -> StringUtils.hasLength(element.getElementText())
|
||||
? element.getElementText()
|
||||
: "[]");
|
||||
}
|
||||
|
||||
|
||||
private static Optional<ExtensionElement> defaultValid(FlowElement flowElement, String elementName) {
|
||||
if (CollectionUtils.isEmpty(flowElement.getExtensionElements())
|
||||
|| !flowElement.getExtensionElements().containsKey(elementName)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
List<ExtensionElement> elements = flowElement.getExtensionElements().getOrDefault(elementName,
|
||||
Collections.emptyList());
|
||||
if (CollectionUtils.isEmpty(elements)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(elements.get(0));
|
||||
}
|
||||
|
||||
public static Optional<UserTask> getPreNode(FlowElement userTask, DelegateExecution execution,
|
||||
BpmnModel bpmnModel) {
|
||||
if (Objects.isNull(bpmnModel)) {
|
||||
bpmnModel = ProcessDefinitionUtil.getBpmnModel(execution.getProcessDefinitionId());
|
||||
}
|
||||
if (userTask instanceof UserTask) {
|
||||
UserTask task = (UserTask) userTask;
|
||||
if (CollectionUtils.isEmpty(task.getIncomingFlows())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
//preNode
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(task.getIncomingFlows().get(0).getSourceRef());
|
||||
|
||||
if (Objects.isNull(flowElement)) {
|
||||
return Optional.empty();
|
||||
} else if (!(flowElement instanceof UserTask)) {
|
||||
return getPreNode(flowElement, execution, bpmnModel);
|
||||
} else {
|
||||
return Optional.of((UserTask) flowElement);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@ -15,17 +15,17 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BpmMyBatisUtils {
|
||||
public class BpmnMyBatisUtils {
|
||||
private static final String MYSQL_ESCAPE_CHARACTER = "`";
|
||||
|
||||
public BpmMyBatisUtils() {
|
||||
public BpmnMyBatisUtils() {
|
||||
}
|
||||
|
||||
public static <T> Page<T> buildPage(BpmPageParam pageParam) {
|
||||
return buildPage(pageParam, (Collection)null);
|
||||
}
|
||||
|
||||
public static <T> Page<T> buildPage(BpmPageParam pageParam, Collection<BpmSortingField> sortingFields) {
|
||||
public static <T> Page<T> buildPage(BpmPageParam pageParam, Collection<BpmnSortingField> sortingFields) {
|
||||
Page<T> page = new Page((long)pageParam.getPageNo(), (long)pageParam.getPageSize());
|
||||
if (!CollectionUtil.isEmpty(sortingFields)) {
|
||||
page.addOrder((List)sortingFields.stream().map((sortingField) -> {
|
||||
@ -7,9 +7,9 @@ package cn.axzo.workflow.core.common.utils;
|
||||
public class BpmnNativeQueryUtil {
|
||||
|
||||
public static String sqlConnectors(StringBuilder stringBuilder) {
|
||||
if (stringBuilder.indexOf("WHERE") < 0) {
|
||||
if (stringBuilder.indexOf("ON") < 0 && stringBuilder.indexOf("WHERE") < 0) {
|
||||
return " WHERE";
|
||||
} else if (stringBuilder.indexOf("LEFT") >= 0 && stringBuilder.indexOf("ON") < 0) {
|
||||
} else if (stringBuilder.indexOf("JOIN") >= 0 && stringBuilder.indexOf("ON") < 0) {
|
||||
return " ON";
|
||||
}
|
||||
return " AND";
|
||||
@ -20,7 +20,7 @@ public class BpmnNativeQueryUtil {
|
||||
if ((start = stringBuilder.indexOf("SELECT")) < 0) {
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
if (stringBuilder.indexOf("LEFT JOIN") < 0) {
|
||||
if (stringBuilder.indexOf("JOIN") < 0) {
|
||||
return stringBuilder.replace(start + 7, 8, "count(1)").toString();
|
||||
} else {
|
||||
return stringBuilder.replace(start + 7, 10, "count(1)").toString();
|
||||
|
||||
@ -2,16 +2,16 @@ package cn.axzo.workflow.core.common.utils;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class BpmSortingField implements Serializable {
|
||||
public class BpmnSortingField implements Serializable {
|
||||
public static final String ORDER_ASC = "asc";
|
||||
public static final String ORDER_DESC = "desc";
|
||||
private String field;
|
||||
private String order;
|
||||
|
||||
public BpmSortingField() {
|
||||
public BpmnSortingField() {
|
||||
}
|
||||
|
||||
public BpmSortingField(String field, String order) {
|
||||
public BpmnSortingField(String field, String order) {
|
||||
this.field = field;
|
||||
this.order = order;
|
||||
}
|
||||
@ -20,7 +20,7 @@ public class BpmSortingField implements Serializable {
|
||||
return this.field;
|
||||
}
|
||||
|
||||
public BpmSortingField setField(String field) {
|
||||
public BpmnSortingField setField(String field) {
|
||||
this.field = field;
|
||||
return this;
|
||||
}
|
||||
@ -29,7 +29,7 @@ public class BpmSortingField implements Serializable {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
public BpmSortingField setOrder(String order) {
|
||||
public BpmnSortingField setOrder(String order) {
|
||||
this.order = order;
|
||||
return this;
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package cn.axzo.workflow.core.common.utils;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
|
||||
/**
|
||||
* 线程本地变量表
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/18 21:42
|
||||
*/
|
||||
public class ContextHolder {
|
||||
|
||||
private static final TransmittableThreadLocal<BpmnTaskDelegateAssigner> CONTEXT = new TransmittableThreadLocal<>();
|
||||
|
||||
private ContextHolder() {}
|
||||
|
||||
public static void set(BpmnTaskDelegateAssigner assigner) {
|
||||
CONTEXT.set(assigner);
|
||||
}
|
||||
|
||||
public static BpmnTaskDelegateAssigner get() {
|
||||
return CONTEXT.get();
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
CONTEXT.remove();
|
||||
}
|
||||
}
|
||||
@ -193,7 +193,6 @@ public class DateUtils extends PropertyEditorSupport {
|
||||
try {
|
||||
_date = sformat.parse(date);
|
||||
} catch (ParseException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return sformat.format(_date);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user