一.简介
**会签:**在一个流程中的某一个 Task 上,这个 Task 需要多个用户审批,当多个用户全部审批通过,或者多个用户中的某几个用户审批通过,就算通过。
例如:之前的请假流程,假设这个请假流程需要组长和经理都审批了,才算审批通过,那么就需要设置这个 Task 是会签节点。
**或签:**意思就是 A 的请假流程提交给 B、C、D,但是并不需要 B/C/D 同时审批通过,只需要 B/C/D 中的任意一个审批即可,这就是或签,注意,我这里的表述,只需要 B/C/D 任意一个审批即可,这个审批即可以是审批通过,也可以是审批拒绝,反正只要审批,这个 UserTask 就算完成了。
二.会签流程图
首先来画一下这个请假流程图,这个流程图基本上还是和之前的一样,截图如下:
三.请假处理
1.前端提交请假流程
2.服务端处理请假请求
3.服务端返回待审批数据
4.服务端批准 OR 拒绝
前4步见上一篇文章,这边不重复写
5.服务端返回流程数据
服务端展示流程数据。就是当用户提交流程之后,想要查看自己的流程处理到哪一步了,截图如下:
这张图中的数据其实包含了两部分,一部分是已经执行完的流程,还有一部分是正在执行中的流程,所以在查询中,分为两步来完成,代码如下:
public RespBean searchResult() {
String name = SecurityContextHolder.getContext().getAuthentication().getName();
List<HistoryInfo> infos = new ArrayList<>();
//未完成流程
List<HistoricProcessInstance> unFinishedHistoricProcessInstances = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(name).unfinished().orderByProcessInstanceStartTime().desc().list();
for (HistoricProcessInstance unFinishedHistoricProcessInstance : unFinishedHistoricProcessInstances) {
HistoryInfo historyInfo = new HistoryInfo();
Date startTime = unFinishedHistoricProcessInstance.getStartTime();
Date endTime = unFinishedHistoricProcessInstance.getEndTime();
List<HistoricVariableInstance> historicVariableInstances = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(unFinishedHistoricProcessInstance.getId())
.list();
System.out.println("historicVariableInstances = " + historicVariableInstances);
for (HistoricVariableInstance historicVariableInstance : historicVariableInstances) {
String variableName = historicVariableInstance.getVariableName();
Object value = historicVariableInstance.getValue();
if ("reason".equals(variableName)) {
historyInfo.setReason((String) value);
} else if ("days".equals(variableName)) {
historyInfo.setDays(Integer.parseInt(value.toString()));
} else if ("name".equals(variableName)) {
historyInfo.setName((String) value);
} else if (variableName.startsWith("approveUser")) {
historyInfo.getApproveUsers().add((String) value);
} else if ("userTask".equals(variableName)) {
historyInfo.getCandidateUsers().add((String) value);
}
}
historyInfo.setStatus(3);
historyInfo.setStartTime(startTime);
historyInfo.setEndTime(endTime);
infos.add(historyInfo);
}
//已结束流程
List<HistoricProcessInstance> finishHistoricProcessInstances = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(name)
.finished()
.orderByProcessInstanceStartTime().desc().list();
for (HistoricProcessInstance historicProcessInstance : finishHistoricProcessInstances) {
HistoryInfo historyInfo = new HistoryInfo();
Date startTime = historicProcessInstance.getStartTime();
Date endTime = historicProcessInstance.getEndTime();
List<HistoricVariableInstance> historicVariableInstances = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(historicProcessInstance.getId())
.list();
System.out.println(historicVariableInstances);
for (HistoricVariableInstance historicVariableInstance : historicVariableInstances) {
String variableName = historicVariableInstance.getVariableName();
Object value = historicVariableInstance.getValue();
if ("reason".equals(variableName)) {
historyInfo.setReason((String) value);
} else if ("days".equals(variableName)) {
historyInfo.setDays(Integer.parseInt(value.toString()));
} else if ("approved".equals(variableName)) {
Boolean v = (Boolean) value;
if (v) {
historyInfo.setStatus(1);
} else {
historyInfo.setStatus(2);
}
} else if ("name".equals(variableName)) {
historyInfo.setName((String) value);
} else if (variableName.startsWith("approveUser")) {
historyInfo.getApproveUsers().add((String) value);
} else if ("userTask".equals(variableName)) {
historyInfo.getCandidateUsers().add((String) value);
}
}
historyInfo.setStartTime(startTime);
historyInfo.setEndTime(endTime);
infos.add(historyInfo);
}
return RespBean.ok("ok", infos);
}
整体上分为两部分,前面是查询未执行完的流程,后面是查询已经执行完毕的流程。对于未执行完的流程,我们在 historyInfo 中设置 status 为 3,表示待审批。当我们去读取一个流程的历史变量时,有一个以 approveUser 开头的变量,这个就表示这个流程已经被谁审批过了,我们将这个存到一个 List 集合中,将来返回给前端。流程的历史变量中还有一个 userTask,表示这个流程中这个节点待审批的用户都有谁,我们也将之保存到 List 集合中,将来返回给前端。
6.前端渲染审批数据
最后,看看前端如何渲染第5步返回的数据,HTML代码如下:
<div>
<el-tag>历史请假列表</el-tag>
<el-table border strip :data="historyInfos">
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="startTime" label="提交时间"></el-table-column>
<el-table-column prop="endTime" label="审批时间"></el-table-column>
<el-table-column prop="reason" label="事由"></el-table-column>
<el-table-column prop="days" label="天数"></el-table-column>
<el-table-column label="审批人">
<template #default="scope">
<template v-for="(cu,i) in scope.row.candidateUsers" :key="i">
<el-tag v-if="scope.row.approveUsers.indexOf(cu)!=-1" type="success">
{{cu}}
</el-tag>
<el-tag v-else style="color: gray">{{cu}}</el-tag>
</template>
</template>
</el-table-column>
<el-table-column label="状态">
<template #default="scope">
<el-tag type="success" v-if="scope.row.status==1">已通过</el-tag>
<el-tag type="danger" v-else-if="scope.row.status==2">已拒绝</el-tag>
<el-tag type="info" v-else>待审批</el-tag>
</template>
</el-table-column>
</el-table>
</div>
可以看到,在审批人这个字段中,先去遍历显示这个流程所有的审批人(candidateUsers),在遍历的过程中,如果发现这个用户存在于 approveUsers 集合中,就表示这个用户已经审批,用绿色的 el-tag 显示,否则表示这个用户还没有审批,就用灰色的 el-tag 显示。
四.或签
或签: 就是 A 的请假流程提交给 B、C、D,但是并不需要 B/C/D 同时审批通过,只需要 B/C/D 中的任意一个审批即可,这就是或签,注意,我这里的表述,只需要 B/C/D 任意一个审批即可,这个审批即可以是审批通过,也可以是审批拒绝,反正只要审批,这个 UserTask 就算完成了。
将会签改为或签只需要修改一下 UserTask 的属性即可,截图如下:
完成条件(多实例)这里改为了 ${nrOfCompletedInstances >= 1},表示只要有一个同意或者拒绝,这个 UserTask 就算过了。
改完之后,重新下载这个流程图的 XML 文件,并放到前文中的代码上去运行,就可以看到或签效果了。