Commit 8ace17d9 authored by yang's avatar yang

修改工作流文档

parent 7b844584
...@@ -4,22 +4,126 @@ ...@@ -4,22 +4,126 @@
#### 工作流开发整体思路 #### 工作流开发整体思路
工作流的开发大致分为以下几步: 工作流的开发大致分为以下几步:
* 流程设计 * 流程设计
* 流程部署 * 流程部署
* 流程启动 * 流程启动
下面以付款申请流程为例。 下面以付款申请流程为例。
#### 一、流程设计 #### 一、流程设计
1. 开始设计流程之前,先在工作流配置界面进行新建模型操作,输入完整界面上各个字段信息后进行保存。 1. 开始设计流程之前,先在工作流配置界面进行新建模型操作,输入完整界面上各个字段信息后进行保存。
**唯一标识****分类**两个字段需要特别注意,这两个字段用于后台业务代码区分具体是哪一个工作流信息。 **唯一标识****分类**两个字段需要特别注意,这两个字段用于后台业务代码区分具体是哪一个工作流信息。
界面如下图所示: 界面如下图所示:
![新建模型界面](/assets/wfl_payment_req_create.png) ![新建模型界面](/assets/wfl_payment_req_create.png)
2. 模型新建之后,需要设计具体的业务流程 2. 模型新建之后,需要设计具体的业务流程
![进入模型界面](/assets/wfl_payment_req_modify_btn.png) ![进入模型界面](/assets/wfl_payment_req_modify_btn.png)
从左边选择相应的节点,描述出整个业务的流程 从左边选择相应的节点(一般情况下只会用到开始事件、结束事件、人工任务、单一网关等节点),描述出整个业务的流程
![描述模型界面](/assets/wfl_payment_req_draw.png) 1. 放置一个开始事件,并在右侧的**名称**属性上设置为 “开始”,见下图:
**各个流程节点的相关配置信息将在后面进行详细的介绍** ![放置开始节点](/assets/wfl_payment_req_start.png)
2. 再添加一个人工任务且名称设置为“部门经理审批”,并通过选中开始事件弹出菜单中的顺序跳转线将该节点与开始事件连接起来。
![连接节点](/assets/wfl_payment_req_connect.png)
3. 编写该工作流的启动代码:
```java
@Service
@Transactional
public class PaymentActivitStartServiceImpl implements IActivitiCommonService {
// 必须实现IActivitiCommonService接口
// workFlowType字段为启动工作流时的唯一识别字段,不可与其他工作流代码重复
private static final String workFlowType = "PAY_PAYMENT";
@Override
public String getWorkFlowType() {
return workFlowType;
}
// 启动工作流时,会自动调用该process方法
@Override
public void process(IRequest iRequest, List list,Map params) {
ProcessInstanceCreateRequest createRequest = getProcessInstanceCreateRequest(list,iRequest,params);
// 启动流程
activitiService.startProcess(iRequest, createRequest);
}
public ProcessInstanceCreateRequest getProcessInstanceCreateRequest(List<HlsCusConContractCashflow> list, IRequest iRequest, Map params) {
ProcessInstanceCreateRequest createRequest = new ProcessInstanceCreateRequest();
// 此处的两个参数,分别对应了新建模型时输入的**唯一标识**以及**分类**
ReProcdef reProcdefs = reProcdefService.queryReProcdef("CSH_PAYMENT_REQ_WORK_FLOW","CSH_PAYMENT");
SysUser sysUser = sysUserService.selectUserById(iRequest.getUserId());
String id = reProcdefs.getId_();
String name = reProcdefs.getName_();
createRequest.setProcessDefinitionId(id);
createRequest.setBusinessKey(list.get(0).getContract_id().toString());
List<RestVariable> variables = new ArrayList<RestVariable>();
List<RestVariable> transientVariables = new ArrayList<RestVariable>();
HlsCusCshPaymentReqLn cshPaymentReqLn = (HlsCusCshPaymentReqLn)params.get("cshPaymentReqLn");
// 注意此处添加的这些参数,将会在流程设计的过程中被使用到
variables.add(newVariable("paymentRedId",cshPaymentReqLn.getPayment_req_id()));
variables.add(newVariable("contractId",cshPaymentReqLn.getSource_doc_id()));
variables.add(newVariable("processDefinitionId",id));
variables.add(newVariable("contractCashflows",list));
variables.add(newVariable("iRequest",iRequest));
double sumAmount = 0L;
for(HlsCusConContractCashflow contractCashflow:list){
sumAmount = add(sumAmount,contractCashflow.getAmount());
}
variables.add(newVariable("sumAmount",new BigDecimal(sumAmount).toPlainString()));
variables.add(newVariable("startUserName",iRequest.getEmployeeCode()));
variables.add(newVariable("documentCategory","CSH_PAYMENT_REQ"));
variables.add(newVariable("documentType","PAYMENT_REQ"));
variables.add(newVariable("documentId",cshPaymentReqLn.getPayment_req_id()));
variables.add(newVariable("pName",name));
variables.add(newVariable("cshPaymentReqLn",cshPaymentReqLn));
variables.add(newVariable("ContractId",cshPaymentReqLn.getContract_id()));
variables.add(newVariable("startUserDescription",sysUser.getDescription()));
createRequest.setVariables(variables);
createRequest.setTransientVariables(transientVariables);
return createRequest;
}
private RestVariable newVariable(String name, Object value){
RestVariable restVariable = new RestVariable();
restVariable.setName("ContractId");
restVariable.setValue
return restVariable;
}
}
```
**在该业务实现代码中,所有通过variables.add进行添加的参数,都可以在工作流设计时直接通过${ PARAM_NAME }使用,详细的用法在后面会进行介绍**
4. 设置“部门经理审批”节点的文档为“${startUserDescription}申请金额${sumAmount}”,其中用到了在代码中设置的两个参数startUserDescriptionsumAmount.
5. 根据业务需要对“部门经理审批”设置审批方式,在这里,根据业务,在右侧的审批方式属性上选择“全部通过”,选择之后,可以看到表单属性自动添加了一条数据。见下图:
![设置审批方式](/assets/wfl_payment_req_way.png)
6. 设置完审批方式后,需要设置改节点的审批规则,在选中”部门经理审批“节点后,点击右侧的审批规则选择按钮进入审批规则的配置界面,新建一条记录,审批规则选择”指定人“,审批者可以通过Lov选择对应的部门经理,在这里选择“马超”.审批权限留空然后保存。保存后,表单属性中的属性会自动增加变为2,设置完的界面见下图
![设置审批规则](/assets/wfl_payment_req_rule.png)
7. 审批规则设置完成后,“部门经理审批”节点的设置基本完成,接下来添加一个单一网关并将“部门经理审批”连接到单一网关,然后添加一个结束事件以及一个名为“总裁审批”的人工任务,并且将单一网关与这两个节点连接,如图:
![添加网关节点](/assets/wfl_payment_req_gateway.png)
8. 将单一网关与“总裁审批”之间的连线右侧属性的**默认跳线**勾选,以便让流程在默认状态时会走向“总裁审批”。
![添加设置默认跳转](/assets/wfl_payment_req_default.png)
9. 将单一网关与结束事件之间的连线右侧的属性中t跳转条件设置为“${approveResult=='REJECTED'}”,其中approveResult为上一节点(部门经理审批)的审批结果,‘REJECTED’为预设的值属性代表审批拒绝,常用的还有APPROVED代表审批同意。如图:
![设置跳转条件](/assets/wfl_payment_req_condi.png)
10. 将“总裁审批”节点按照5-6的步骤设置审批方式为全部通过,审批规则设置为指定人-李林。两个属性设置完成后,对该节点设置**任务监听**为“${approveActionEventTask}”(该监听类(ApproveActionEventTask)用于给指定审批人发送消息,approveActionEventTask为监听类在spring容器中的名称,一般为首字母小写后的类名),添加任务监听是为了在流程到达指定节点时触发一部分预先设置好的业务逻辑。设置好的
![设置跳转条件](/assets/wfl_payment_req_listener.png)
11. 任务监听设置需要先编写一段监听代码,如下
```java
@Component
public class ApproveActionEventTask implements TaskListener,IActivitiBean {
@Autowired
private SysEventService sysEventService;
@Override
public void notify(DelegateTask delegateTask) {
// 触发消息推送事件将消息发给审批人
sysEventService.createNotice(delegateTask.getExecution(),"APPROVE");
}
}
```
12. 按照上面的流程再添加人工任务“董事长审批”以及响应的网关,最终完成付款申请流程的设计,最终设计完成的流程图如下:
![描述模型界面](/assets/wfl_payment_req_draw.png)
#### 二、流程部署 #### 二、流程部署
流程设计好以后,点击流程设计页面操作栏的最后一个按钮()即可发布流程 流程设计好以后,点击流程设计页面操作栏的最后一个按钮()即可发布流程
`未发布过的流程或者改动过的流程,勾会以绿色展示,反之灰色` `未发布过的流程或者改动过的流程,勾会以绿色展示,反之灰色`
...@@ -36,193 +140,11 @@ ...@@ -36,193 +140,11 @@
public void paymentApproval(IRequest iRequest, HttpSession session, List<HlsCusConContractCashflow> list) { public void paymentApproval(IRequest iRequest, HttpSession session, List<HlsCusConContractCashflow> list) {
// ... // ...
Map<String, Object> params = new HashMap<String, Object>(); Map<String, Object> params = new HashMap<String, Object>();
// 注意此处的workFlowType,该参数将和另一个业务类中的Code对应 // 注意此处的workFlowType,该参数将和业务类中的Code对应
params.put("workFlowType", "PAY_PAYMENT"); params.put("workFlowType", "PAY_PAYMENT");
params.put("cshPaymentReqLn", ss.get(0)); params.put("cshPaymentReqLn", ss.get(0));
// 启动工作流流程 // 启动工作流流程
activitiStartService.start(iRequest, list, params); activitiStartService.start(iRequest, list, params);
// ... // ...
} }
``` ```
业务实现类: \ No newline at end of file
```java
@Service
@Transactional
public class PaymentActivitStartServiceImpl implements IActivitiCommonService {
// 该数据对应了请求响应启动工作流时传入的workFlowType
private static final String workFlowType = "PAY_PAYMENT";
@Override
public String getWorkFlowType() {
return workFlowType;
}
// 启动工作流时,会自动调用该方法
@Override
public void process(IRequest iRequest, List list,Map params) {
ProcessInstanceCreateRequest createRequest = getProcessInstanceCreateRequest(list,iRequest,params);
// 启动流程
activitiService.startProcess(iRequest, createRequest);
}
public ProcessInstanceCreateRequest getProcessInstanceCreateRequest(List<HlsCusConContractCashflow> list, IRequest iRequest, Map params) {
ProcessInstanceCreateRequest createRequest = new ProcessInstanceCreateRequest();
// 此处的两个参数,分别对应了新建模型时输入的**唯一标识**以及**分类**
ReProcdef reProcdefs = reProcdefService.queryReProcdef("CSH_PAYMENT_REQ_WORK_FLOW","CSH_PAYMENT");
SysUser sysUser = sysUserService.selectUserById(iRequest.getUserId());
String id = reProcdefs.getId_();
String name = reProcdefs.getName_();
createRequest.setProcessDefinitionId(id);
createRequest.setBusinessKey(list.get(0).getContract_id().toString());
List<RestVariable> variables = new ArrayList<RestVariable>();
List<RestVariable> transientVariables = new ArrayList<RestVariable>();
RestVariable restVariable1 = new RestVariable();
RestVariable restVariable2 = new RestVariable();
RestVariable restVariable3 = new RestVariable();
RestVariable restVariable4 = new RestVariable();
RestVariable restVariable5 = new RestVariable();
RestVariable restVariable13 = new RestVariable();
RestVariable restVariable20 = new RestVariable();
RestVariable restVariable = new RestVariable();
HlsCusCshPaymentReqLn cshPaymentReqLn = (HlsCusCshPaymentReqLn)params.get("cshPaymentReqLn");
restVariable.setName("paymentRedId");
restVariable.setValue(cshPaymentReqLn.getPayment_req_id());
variables.add(restVariable);
restVariable20.setName("contractId");
restVariable20.setValue(cshPaymentReqLn.getSource_doc_id());
variables.add(restVariable20);
restVariable1.setName("processDefinitionId");
restVariable1.setValue(id);
variables.add(restVariable1);
restVariable2.setName("contractCashflows");
restVariable2.setValue(list);
variables.add(restVariable2);
restVariable3.setName("iRequest");
restVariable3.setValue(iRequest);
variables.add(restVariable3);
double sumAmount = 0L;
for(HlsCusConContractCashflow contractCashflow:list){
sumAmount = add(sumAmount,contractCashflow.getAmount());
}
// 注意此处的sumAmount,在流程设计的过程中将会被使用到
restVariable4.setName("sumAmount");
restVariable4.setValue(new BigDecimal(sumAmount).toPlainString());
variables.add(restVariable4);
restVariable5.setName("startUserName");
restVariable5.setValue(iRequest.getEmployeeCode());
variables.add(restVariable5);
RestVariable restVariable6 = new RestVariable();
RestVariable restVariable7 = new RestVariable();
RestVariable restVariable8 = new RestVariable();
restVariable6.setName("documentCategory");
restVariable6.setValue("CSH_PAYMENT_REQ");
variables.add(restVariable6);
restVariable7.setName("documentType");
restVariable7.setValue("PAYMENT_REQ");
variables.add(restVariable7);
restVariable8.setName("documentId");
restVariable8.setValue(cshPaymentReqLn.getPayment_req_id());
variables.add(restVariable8);
RestVariable restVariable9 = new RestVariable();
restVariable9.setName("pName");
restVariable9.setValue(name);
variables.add(restVariable9);
RestVariable restVariable10 = new RestVariable();
restVariable10.setName("cshPaymentReqLn");
restVariable10.setValue(cshPaymentReqLn);
variables.add(restVariable10);
RestVariable restVariable11 = new RestVariable();
restVariable11.setName("ContractId");
restVariable11.setValue(cshPaymentReqLn.getContract_id());
variables.add(restVariable11);
restVariable13.setName("startUserDescription");
restVariable13.setValue(sysUser.getDescription());
variables.add(restVariable13);
createRequest.setVariables(variables);
createRequest.setTransientVariables(transientVariables);
return createRequest;
}
private double add(Double a, Double b) {
BigDecimal aa = new BigDecimal(a.toString());
BigDecimal bb = new BigDecimal(b.toString());
return aa.add(bb).setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
}
}
```
**在该业务实现代码中,所有通过variables.add进行添加的参数,都可以在工作流设计时直接通过${ PARAM_NAME }使用,详细的用法在后面会进行介绍**
--- ---
### 流程设计详细
上面介绍了整个工作流流程启动的流程,但是在流程的设计过程并没有进行介绍,接下来将对流程图的设计以及流程的监听事件等进行介绍。
- 节点
首先进入流程的详细界面,选择一个人工节点,如下图:
![查看人工节点](/assets/wfl_payment_req_detail.png)
可以看到右侧有许多的配置属性,下面是几个常用的属性的用途:
* ID:自动生成,节点唯一标识
* 名称:当前节点中文描述
* 文档:消息机制,可在上下文中取到,如:我是${name},name为实现类里面配置的参数
* 审批方式:默认为全部通过
* 审批方式变量:当审批方式选择一定比例时,可设置变量如0.4,表示当审批人数达到这个比例后将会通过
* 审批规则:选择对应的审批人,可在审批规则中定义
* 加签:若勾选,则当前审批者可添加审批人
* 表单url:表示审批流程中可插入的页面,能让审判者读阅
* 执行监听器:执行监听器start跟end两种分别代表在该节点之前跟在该节点之后,在代理表达式里面可调用对应自己写的java类,格式如下:${endActionEventTask},endActionEventTask为监听类在spring容器中的名称,一般为首字母小写之后的类名。
* 任务监听器:任务监听器可参考执行监听器
1. 文档
可以看到右侧有对该流程的一些配置信息,先看文档,文档中的内容最终可以通过消息机制,当流程完成该流程时会在界面上显示文档中的内容。
![文档](/assets/wfl_payment_req_doc.png)
在文档中的内容,可以通过前面介绍的${}方式,直接使用在**业务代码**中添加的参数信息。
2. 审批方式
![](/assets/wfl_demo_2-1.png)
如上图,在选择审批方式的时候,一共有五种审批方式,这里面的审批方式可在下图中的功能里面配置,如下图所示,
![](/assets/wfl_demo_2-2.png)
![](/assets/wfl_demo_2-3.png)
这里面配置的审批方式会在设计节点的时候查询出来,可在这里删除或者添加新的审批方式,审批方式中的通过条件中,里面的一个变量为系统内置变量,具体含义可在IActivitiConstants.java文件中查看,如下图所示,
![](/assets/wfl_demo_2-4.png)
3. 审批规则
在流程设计的时候,点击审批规则会弹出下面的选择框,如下图所示,
![](/assets/wfl_demo_2-5.png)
审批规则是一个combobox,这里面的选项是在审批规则的功能里面进行配置,如下图所示
![](/assets/wfl_demo_2-6.png)
![](/assets/wfl_demo_2-7.png)
我们可以看到,这里我们需要配置三个选项,分别是代码,描述,表达式,这里表达式对应某个变量或者我们后台写的service,我们通过service取得对应这个审批规则下所有的审批人员,我们可以看到方法后面还跟了一个参数,这个参数在我们选择的时候会放到表单属性里面,在我们介绍表单属性的会具体介绍
4. 表单属性
在右侧点击表单属性可以弹出表单属性的详细信息。(表单属性可以通过审批方式及审批规则自动添加,也可以手动填写)如图:
![表单属性](/assets/wfl_payment_req_form.png)
| 表单属性id | 表单名 | 类型 | 描述 |
| --------- | ------ | ---- | ---- |
| APPROVAL_STRATEGY | ALL_APPROVAL | String | 审批策略为全部通过,指定的所有的审批人全都同意 |
| APPROVAL_CANDIDATE_RULE | - | Enum | 审批候选人,使用Enum类型,可以指定职位或者指定人进行审批,在其中设置id为APPOINTED_EMPLOYEE或APPOINTED_POSITION,表单名为{"parameter":[{"employeeCode":"//指定的employeeCode"}],"businessRules":[]} |
另外若是想在审批页面指定出现哪些按钮,可以通过下图的方式进行配置
![](/assets/wfl_demo_2-11.png)
这里需要注意的是对应的按钮代码是固定的,我们需要配置对应的代码才会出现对应的按钮
5. 任务监听
在右侧点击任务监听后,弹出任务监听详细信息,可以通过选择不同的事件(create创建、assignment分配、complete完成、delete删除)并且配置Delegate expression(这个代理表达式使用${}包裹类名,但是类名为spring容器中对应的处理类的名称,如${approveActionEventTask},一般为对应处理类的名称首字母小写)
- 网关
网关相当于一个if条件判断,通过在网关延伸出的流程线条上可以指定在什么条件流程会朝该方向进行。
通过选中网关延伸出的线条,点击右侧的跳转条件,可以设置跳转到该方向的条件。值得注意的是,在这里设置的条件可以使用上面描述的**业务代码**中设置的任何的参数,使用方式见下图:
![](/assets/wfl_payment_req_condition.png)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment