Activiti使用总结

请假申请流程

新增请假

通过流程定义key决定启动什么流程,并将当前表单id设置BusinessKey,用于后续表单数据查询或回显,设置流程变量,决定由谁执行下一步任务(用于查询我的待办)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 新增请假
*
* @param leaveapply 请假
* @return 结果
*/
@Override
public int insertLeaveapply(Leaveapply leaveapply)
{
int rows = leaveapplyMapper.insertLeaveapply(leaveapply);
// 发起请假流程
identityService.setAuthenticatedUserId(leaveapply.getUserId());
HashMap<String, Object> variables = new HashMap<>();
variables.put("applyuserid", leaveapply.getUserId());
variables.put("deptleader", leaveapply.getDeptleader());

// 启动流程
runtimeService.startProcessInstanceByKey("leave", String.valueOf(leaveapply.getId()), variables);
// runtimeService.startProcessInstanceById("leave:1:5018", String.valueOf(leaveapply.getId()), variables);

// 自动完成第一个任务
Task autoTask = taskService.createTaskQuery().processDefinitionKey("leave").processInstanceBusinessKey(String.valueOf(leaveapply.getId())).singleResult();
taskService.complete(autoTask.getId());
return rows;
}

通过设置流程变量,可以将任务指派给对应的人。

我的待办

通过**taskAssignee(username)**指定用户查询待办任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 查询我的待办任务列表
*/
@ApiOperation("查询我的待办任务列表")
@PostMapping("/mylist")
@ResponseBody
public TableDataInfo mylist(TaskInfo param)
{
SysUser user = getSysUser();
String username = user.getLoginName();
// 查询我的待办
TaskQuery condition = taskService.createTaskQuery().taskAssignee(username);
if (StringUtils.isNotEmpty(param.getTaskName())) {
condition.taskName(param.getTaskName());
}
if (StringUtils.isNotEmpty(param.getProcessName())) {
condition.processDefinitionName(param.getProcessName());
}
// 过滤掉流程挂起的待办任务
int total = condition.active().orderByTaskCreateTime().desc().list().size();
int start = (param.getPageNum()-1) * param.getPageSize();
List<Task> taskList = condition.active().orderByTaskCreateTime().desc().listPage(start, param.getPageSize());
List<TaskInfo> tasks = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
taskList.stream().forEach(a->{
ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(a.getProcessInstanceId()).singleResult();
TaskInfo info = new TaskInfo();
info.setAssignee(a.getAssignee());
info.setBusinessKey(process.getBusinessKey());
info.setCreateTime(sdf.format(a.getCreateTime()));
info.setTaskName(a.getName());
info.setExecutionId(a.getExecutionId());
info.setProcessInstanceId(a.getProcessInstanceId());
info.setProcessName(process.getProcessDefinitionName());
info.setStarter(process.getStartUserId());
info.setStartTime(sdf.format(process.getStartTime()));
info.setTaskId(a.getId());
// 查询表单编号
String formKey = formService.getTaskFormData(a.getId()).getFormKey();
info.setFormKey(formKey);
tasks.add(info);
});
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(0);
rspData.setRows(tasks);
rspData.setTotal(total);
return rspData;
}

部门领导审批或人事审批

通过BusinessKey查询业务表单数据,用于回显。页面通过formKey表单编号决定调用对应的接口和显示对应的审批页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 部门领导审批
* @return
*/
@GetMapping("/deptleadercheck")
public String deptleadercheck(String taskid, ModelMap mmap)
{
Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
String processId = t.getProcessInstanceId();
ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
if (p != null) {
Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
mmap.put("apply", apply);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mmap.put("startTime", sdf.format(apply.getStartTime()));
mmap.put("endTime", sdf.format(apply.getEndTime()));
mmap.put("taskid", taskid);
mmap.put("userlist", userService.selectUserList(new SysUser()));
}
return prefix + "/deptleadercheck";
}

/**
* 人事审批
* @return
*/
@GetMapping("/hrcheck")
public String hrcheck(String taskid, ModelMap mmap)
{
Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
String processId = t.getProcessInstanceId();
ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
if (p != null) {
Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
mmap.put("apply", apply);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mmap.put("startTime", sdf.format(apply.getStartTime()));
mmap.put("endTime", sdf.format(apply.getEndTime()));
mmap.put("taskid", taskid);
}
return prefix + "/hrcheck";
}

通过设置表单编号,页面可以通过这个编号判断需要显示什么表单。

办理任务

在完成任务时,也可以设置流程变量,可以用于决定流程走向,也可以用于指定下一个任务的待办人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@ApiOperation("办理一个用户任务")
@RequestMapping(value = "/completeTask/{taskId}", method = RequestMethod.POST)
@ResponseBody
public AjaxResult completeTask(@PathVariable("taskId") String taskId, @RequestBody(required=false) Map<String, Object> variables) {
SysUser user = getSysUser();
String username = user.getLoginName();
// 设置任务的执行人为指定的用户
taskService.setAssignee(taskId, username);
// 查出流程实例id
String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
if (variables == null) {
taskService.complete(taskId);
} else {
// 添加审批意见
if (variables.get("comment") != null) {
taskService.addComment(taskId, processInstanceId, (String) variables.get("comment"));
variables.remove("comment");
}
taskService.complete(taskId, variables);
}
return AjaxResult.success();
}

通过设置流程变量进行判断,决定流程走向。

任务办理历史时间轴

通过activityType(“userTask”)指定查询用户任务的历史数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@ApiOperation("任务办理时间轴")
@RequestMapping(value = "/history/{taskId}", method = RequestMethod.GET)
@ResponseBody
public List<TaskInfo> history(@PathVariable String taskId) {
String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
// 指定查询userTask用户任务
List<HistoricActivityInstance> history = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().list();
List<TaskInfo> infos = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
history.stream().forEach(h->{
TaskInfo info = new TaskInfo();
info.setProcessInstanceId(h.getProcessInstanceId());
info.setStartTime(sdf.format(h.getStartTime()));
if (h.getEndTime() != null) {
info.setEndTime(sdf.format(h.getEndTime()));
}
info.setAssignee(h.getAssignee());
info.setTaskName(h.getActivityName());
List<Comment> comments = taskService.getTaskComments(h.getTaskId());
if (comments.size() > 0) {
info.setComment(comments.get(0).getFullMessage());
}
infos.add(info);
});
return infos;
}

驳回申请

指定用户任务id,和用户任务主键,驳回到指定用户任务

当在Activiti流程中设置一个流程变量时,如果在一个用户任务中设置了流程变量,并且该变量没有在后续的任务中被覆盖或更新,那么该变量将在整个流程实例中保持不变,直到流程结束或变量被显式地删除或更新。

如果您的流程定义中多个用户任务使用了相同的流程变量名称,并且您没有在这些任务之间显式地更改该变量的值,那么这些任务都会看到相同的流程变量值。这是因为流程变量的作用域是整个流程实例,而不是单个任务。

例如,如果您在第一个用户任务中设置了名为applicantId的流程变量,并且后续的用户任务也引用了同一个变量名,那么这些任务都会接收到第一个任务设置的applicantId值,除非在流程执行过程中该值被更改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@ApiOperation("驳回或跳转到指定节点")
@GetMapping(value = "/jump/{taskId}/{sid}")
@ResponseBody
public AjaxResult jump(@PathVariable String taskId, @PathVariable String sid) {
Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
// 寻找流程实例当前任务的activeId
Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult();
String activityId = execution.getActivityId();
FlowNode currentNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityId);
FlowNode targetNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(sid);
// 创建连接线
List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newFlow");
newSequenceFlow.setSourceFlowElement(currentNode);
newSequenceFlow.setTargetFlowElement(targetNode);
newSequenceFlowList.add(newSequenceFlow);
// 备份原有方向
List<SequenceFlow> dataflows = currentNode.getOutgoingFlows();
List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
oriSequenceFlows.addAll(dataflows);
// 清空原有方向
currentNode.getOutgoingFlows().clear();
// 设置新方向
currentNode.setOutgoingFlows(newSequenceFlowList);
// 完成当前任务
taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "跳转节点");
taskService.complete(taskId);
// 恢复原有方向
currentNode.setOutgoingFlows(oriSequenceFlows);
return AjaxResult.success();
}

通过指定用户任务主键,可以回跳到指定节点。

撤销申请

创建结束节点,将当前节点指向结束节点,完成任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@ApiOperation("撤销:强制结束一个流程")
@GetMapping(value = "/forceEnd/{taskId}")
@ResponseBody
public AjaxResult forceEnd(@PathVariable String taskId) {
Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
// 寻找流程实例当前任务的activeId
Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult();
String activityId = execution.getActivityId();
FlowNode currentNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityId);
// 创建结束节点和连接线
EndEvent end = new EndEvent();
end.setName("强制结束");
end.setId("forceEnd");
List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newFlow");
newSequenceFlow.setSourceFlowElement(currentNode);
newSequenceFlow.setTargetFlowElement(end);
newSequenceFlowList.add(newSequenceFlow);
// 备份原有方向
List<SequenceFlow> dataflows = currentNode.getOutgoingFlows();
List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
oriSequenceFlows.addAll(dataflows);
// 清空原有方向
currentNode.getOutgoingFlows().clear();
// 设置新方向
currentNode.setOutgoingFlows(newSequenceFlowList);
// 完成当前任务
taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "撤销流程");
taskService.complete(taskId);
// 恢复原有方向
currentNode.setOutgoingFlows(oriSequenceFlows);
return AjaxResult.success();
}

删除请假

如果请假申请人要删除请假,如果该请假流程流程没有接受,则需要删除流程实例。并且删除该流程执行的历史数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 批量删除请假
*
* @param ids 需要删除的请假主键
* @return 结果
*/
@Override
public int deleteLeaveapplyByIds(String ids)
{
String[] keys = Convert.toStrArray(ids);
for (String key : keys) {
ProcessInstance process = runtimeService.createProcessInstanceQuery().processDefinitionKey("leave").processInstanceBusinessKey(key).singleResult();
if (process != null) {
runtimeService.deleteProcessInstance(process.getId(), "删除");
}
// 删除历史数据
HistoricProcessInstance history = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("leave").processInstanceBusinessKey(key).singleResult();
if (history != null){
historyService.deleteHistoricProcessInstance(history.getId());
}
leaveapplyMapper.deleteLeaveapplyById(Long.parseLong(key));
}
return keys.length;
}