引言
activiti原生的编辑器不能实现A8一样的可视化设置UserTask节点的受理人,但是业务需求是想要让用户可以动态的设置每个流程图的受理人,所以开发了节点设置审批人的功能,其中后台有职位表,用来指定职位对应的用户关系。
本文参考了这篇博客的部分代码。
下面是代码:
- 后台模型
@Data
public class ProcessDefinition extends BaseEntity {
private String id;
@Excel(name = "流程名称")
private String name;
@Excel(name = "流程KEY")
private String key;
@Excel(name = "流程版本")
private int version;
@Excel(name = "所属分类")
private String category;
@Excel(name = "流程描述")
private String description;
private String deploymentId;
@Excel(name = "部署时间", databaseFormat = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date deploymentTime;
@Excel(name = "流程图")
private String diagramResourceName;
@Excel(name = "流程定义")
private String resourceName;
/** 流程实例状态 1 激活 2 挂起 */
private String suspendState;
private String suspendStateName;
private List<UserTaskModel> userTaskList;
}
- 用户节点模型
@Data
public class UserTaskModel implements Serializable {
private String id;
private String name;
/**
* 审批人类型
* 0:未指定
* 1:办理人
* 2:候选用户
* 3:候选组
*/
private String type;
/**
* 办理人,办理人只能指定一个人,不能使用逗号分隔。
* 默认执行签收操作taskService.claim(taskId, currentUserId);
* 在ACT_HI_TASKINST和ACT_RU_TASK会产生数据,这两个表里面的Assignee_字段就是设置的办理人姓名或者对象的ID
*/
private String assignee;
/**
* 候选用户,候选用户设置办理人不是很多的情况下使用,而且需要签收,
* 也就是说我们常说的抢件模式,设置候选组的前提是没有指定Assignee,(即没有执行签收操作)。
* 设置候选用户需要主动签收taskService.claim(taskId, currentUserId);
*/
private String candidateUsers;
/**
* 候选组,这个就是这只办理角色或者办理岗位,适合使用在办理人比较多的情况下,而且涉及到几个部门的情形。
* 候选组与候选用户类似,只是要获取候选用户,需要根据候选组找到对应的用户
* 设置候选组需要主动签收taskService.claim(taskId, currentUserId);
*/
private String candidateGroups;
}
- 后台查询流程图所有节点及属性方法
public List<UserTaskModel> getUserTaskList(String deploymentId) throws Exception {
byte[] byteArray = this.getByteArray(deploymentId);
SAXReader saxReader = new SAXReader();
// 获取流程图文件中的userTask节点的所有属性
ByteArrayInputStream bis = new ByteArrayInputStream(byteArray);
Document document = saxReader.read(bis);
Element rootElement = document.getRootElement();
Element process = rootElement.element("process");
List<Element> userTaskList = process.elements("userTask");
ArrayList<UserTaskModel> list = Lists.newArrayList();
// 包装成适合前端展示的集合并返回
for (Element element : userTaskList) {
UserTaskModel userTaskModel = new UserTaskModel();
userTaskModel.setId(element.attributeValue("id"));
userTaskModel.setName(element.attributeValue("name"));
String type = "0";
String assignee = element.attributeValue("assignee");
String candidateUsers = element.attributeValue("candidateUsers");
String candidateGroups = element.attributeValue("candidateGroups");
if (StringUtils.isNotEmpty(candidateGroups)) {
type = "3";
userTaskModel.setCandidateGroups(candidateGroups);
}
if (StringUtils.isNotEmpty(candidateUsers)) {
type = "2";
userTaskModel.setCandidateUsers(candidateUsers);
}
if (StringUtils.isNotEmpty(assignee)) {
type = "1";
userTaskModel.setAssignee(assignee);
}
userTaskModel.setType(type);
list.add(userTaskModel);
}
bis.close();
return list;
}
private byte[] getByteArray(String deploymentId) throws IOException {
// 从ACT_GE_BYTEARRAY表中获取流程图的二进制文件
// 此操作对象必须是已部署的模型,此时流程定义的二进制文件才是以bpmn20.xml结尾的。
String sql =
"select a.* from ACT_GE_BYTEARRAY a where NAME_ LIKE '%bpmn20.xml' and " +
"DEPLOYMENT_ID_= ? ";
final LobHandler lobHandler = new DefaultLobHandler(); // reusable
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
jdbcTemplate.query(sql, new Object[]{
deploymentId},
new AbstractLobStreamingResultSetExtractor<Object>() {
public void streamData(ResultSet rs) throws SQLException, IOException {
FileCopyUtils.copy(lobHandler.getBlobAsBinaryStream(rs, "BYTES_"), bos);
}
}
);
byte[] bytes = bos.toByteArray();
bos.close();
return bytes;
}
- 前台页面伪代码
<el-table @selection-change="handleSelectionChange" :data="tableData" style="width: 100%; margin-top: 10px">
<el-table-column prop="id" label="流程ID" width="180" fixed show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="key" label="流程Key" width="80" show-overflow-tooltip="true"></el-table-column>