Skip to content

Commit 40c6483

Browse files
committed
新增 角色、部门 审批策略支持认领全部人员参与审批两种模式
1 parent 71fdc25 commit 40c6483

9 files changed

Lines changed: 452 additions & 18 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ FlowLong🐉飞龙工作流
7272
| 超时审批 | 根据设置的超时审批时间,超时后自动审批【自动通过或拒绝】 || ||
7373
| 自动提醒 | 根据设置的提醒时间,提醒审批人审批【可设定提醒次数】实现接口任意方式提醒【短信,邮件,微信,钉钉等】 ||
7474
| 暂存待审 | 流程发起时,可以暂存待审,发起人后续修改,审批重新提交激活流程实例 ||
75+
| 分组策略 | 角色、部门 分组策略支持认领审批、全部人员参与审批 两种模式 ||
7576

7677
# 贡献力量
7778

flowlong-core/src/main/java/com/aizuda/bpm/engine/core/FlowLongEngineImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,8 @@ private boolean afterDoneTask(FlowCreator flowCreator, FlwTask flwTask, Map<Stri
454454
// 主管、角色、部门 任务参与者
455455
List<FlwHisTaskActor> htaList = flowLongContext.getQueryService().getHisTaskActorsByTaskIdAndActorId(flwTask.getId(), flowCreator.getCreateId());
456456
if (ObjectUtils.isNotEmpty(htaList)) {
457-
if (isSupervisor) {
458-
// 主管直接获取当具体前参与者
457+
if (isSupervisor || nodeModel.allJoinGroupStrategy()) {
458+
// 主管直接获取当具体前参与者,分组策略全部人员参与审批
459459
assigneeId = htaList.get(0).getActorId();
460460
} else {
461461
// 角色、部门 获取当前认领人员

flowlong-core/src/main/java/com/aizuda/bpm/engine/impl/GeneralTaskActorProvider.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,21 @@ public List<FlwTaskActor> getTaskActors(NodeModel nodeModel, Execution execution
4242

4343
@Override
4444
public Integer getActorType(NodeModel nodeModel) {
45-
// 0,用户
46-
if (NodeSetType.specifyMembers.eq(nodeModel.getSetType())
47-
|| NodeSetType.initiatorThemselves.eq(nodeModel.getSetType())
48-
|| NodeSetType.initiatorSelected.eq(nodeModel.getSetType())) {
49-
return 0;
50-
}
45+
// 非全部人员参与审批分组策略
46+
if (!nodeModel.allJoinGroupStrategy()) {
5147

52-
// 1,角色
53-
if (NodeSetType.role.eq(nodeModel.getSetType())) {
54-
return 1;
55-
}
48+
// 1,角色
49+
if (NodeSetType.role.eq(nodeModel.getSetType())) {
50+
return 1;
51+
}
5652

57-
// 2,部门
58-
if (NodeSetType.department.eq(nodeModel.getSetType())) {
59-
return 2;
53+
// 2,部门
54+
if (NodeSetType.department.eq(nodeModel.getSetType())) {
55+
return 2;
56+
}
6057
}
6158

62-
// 其它类型可以实现该类重写
59+
// 0,用户
6360
return 0;
6461
}
6562
}

flowlong-core/src/main/java/com/aizuda/bpm/engine/model/NodeModel.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ public class NodeModel implements ModelInstance, Serializable {
102102
* </p>
103103
*/
104104
private Integer examineMode;
105+
/**
106+
* 分组(角色、部门)审批策略,默认 0,认领审批 1,全部人员参与审批
107+
*/
108+
private Integer groupStrategy;
105109
/**
106110
* 自定义连续主管审批层级
107111
*/
@@ -524,6 +528,15 @@ public boolean routeNode() {
524528
return TaskType.routeBranch.eq(type);
525529
}
526530

531+
/**
532+
* 判断是否为全部人员参与审批分组策略
533+
*
534+
* @return true 是 false 否
535+
*/
536+
public boolean allJoinGroupStrategy() {
537+
return Objects.equals(1, groupStrategy);
538+
}
539+
527540
/**
528541
* 判断是否为调用子流程节点
529542
*
@@ -546,9 +559,9 @@ public NodeAssignee nextNodeAssignee(Execution execution, String assigneeId) {
546559
boolean findTaskActor = false;
547560
NodeAssignee nextNodeAssignee = null;
548561
List<NodeAssignee> nodeAssigneeList = this.getNodeAssigneeList();
549-
if (ObjectUtils.isEmpty(nodeAssigneeList)) {
562+
if (ObjectUtils.isEmpty(nodeAssigneeList) || allJoinGroupStrategy()) {
550563
/*
551-
* 模型未设置处理人,那么需要获取自定义参与者
564+
* 模型未设置处理人、分组策略全部人员参与审批,那么需要获取自定义参与者
552565
*/
553566
List<FlwTaskActor> taskActors = execution.getProviderTaskActors(this);
554567
if (ObjectUtils.isNotEmpty(taskActors)) {

flowlong-spring-boot-starter/src/test/java/test/TestFlowLong.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,21 @@ public abstract class TestFlowLong {
3030
*/
3131
protected String testUser3 = "test003";
3232

33+
/**
34+
* 测试用户4
35+
*/
36+
protected String testUser4 = "test004";
37+
38+
/**
39+
* 测试用户5
40+
*/
41+
protected String testUser5 = "test005";
42+
43+
/**
44+
* 测试用户6
45+
*/
46+
protected String testUser6 = "test006";
47+
3348
@Autowired
3449
protected FlowLongEngine flowLongEngine;
3550

flowlong-spring-boot-starter/src/test/java/test/mysql/MysqlTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ public class MysqlTest extends TestFlowLong {
2828
protected FlowCreator testCreator = FlowCreator.of(testUser1, "测试001");
2929
protected FlowCreator test2Creator = FlowCreator.of(testUser2, "测试002");
3030
protected FlowCreator test3Creator = FlowCreator.of(testUser3, "测试003");
31+
protected FlowCreator test4Creator = FlowCreator.of(testUser4, "测试004");
32+
protected FlowCreator test5Creator = FlowCreator.of(testUser5, "测试005");
33+
protected FlowCreator test6Creator = FlowCreator.of(testUser6, "测试006");
3134

3235
/**
3336
* 执行当前活跃用户
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright 2023-2025 Licensed under the Dual Licensing
3+
* website: https://aizuda.com
4+
*/
5+
package test.mysql;
6+
7+
import com.aizuda.bpm.engine.core.Execution;
8+
import com.aizuda.bpm.engine.core.FlowCreator;
9+
import com.aizuda.bpm.engine.core.enums.NodeSetType;
10+
import com.aizuda.bpm.engine.entity.FlwHisInstance;
11+
import com.aizuda.bpm.engine.entity.FlwTaskActor;
12+
import com.aizuda.bpm.engine.impl.GeneralTaskActorProvider;
13+
import com.aizuda.bpm.engine.model.NodeAssignee;
14+
import com.aizuda.bpm.engine.model.NodeModel;
15+
import lombok.extern.slf4j.Slf4j;
16+
import org.junit.jupiter.api.Assertions;
17+
import org.junit.jupiter.api.Test;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
import java.util.Objects;
22+
23+
/**
24+
* 测试分组审批策略
25+
*
26+
* @author 青苗
27+
*/
28+
@Slf4j
29+
public class TestGroupStrategy extends MysqlTest {
30+
31+
@Test
32+
public void testAllJoin() {
33+
Long processId = this.deployByResource("test/testGroupStrategyAllJoin.json", testCreator);
34+
this.flowLongEngine.getContext().setTaskActorProvider(new TestGroupStrategyTaskActorProvider());
35+
flowLongEngine.startInstanceById(processId, testCreator).ifPresent(instance -> {
36+
37+
// 部门领导、测试人员 【或签审核】
38+
this.executeTask(instance.getId(), test5Creator);
39+
40+
// 考勤管理员、财务总监 【顺序签审核】
41+
this.executeTaskByKey(instance.getId(), test4Creator, "flk1752830262547");
42+
this.executeTaskByKey(instance.getId(), test3Creator, "flk1752830262547");
43+
this.executeTaskByKey(instance.getId(), test2Creator, "flk1752830262547");
44+
45+
// 技术总监、CEO 【会签审核】
46+
this.executeTask(instance.getId(), test4Creator);
47+
this.executeTask(instance.getId(), test3Creator);
48+
this.executeTask(instance.getId(), test2Creator);
49+
this.executeTask(instance.getId(), testCreator);
50+
51+
// 流程执行结束
52+
FlwHisInstance fhi = flowLongEngine.queryService().getHistInstance(instance.getId());
53+
Assertions.assertEquals(1, fhi.getInstanceState());
54+
});
55+
}
56+
57+
@Test
58+
public void testMix() {
59+
Long processId = this.deployByResource("test/testGroupStrategyMix.json", testCreator);
60+
this.flowLongEngine.getContext().setTaskActorProvider(new TestGroupStrategyTaskActorProvider());
61+
flowLongEngine.startInstanceById(processId, testCreator).ifPresent(instance -> {
62+
63+
// 部门领导、测试人员 【或签审核】 执行任务认领
64+
this.executeActiveTasks(instance.getId(), flwTask -> flowLongEngine.taskService()
65+
.claimRole(flwTask.getId(), testCreator));
66+
// 执行认领任务
67+
this.executeTask(instance.getId(), testCreator);
68+
69+
// 考勤管理员、财务总监 【顺序签审核】
70+
this.executeTaskByKey(instance.getId(), test4Creator, "flk1752830262547");
71+
this.executeTaskByKey(instance.getId(), test3Creator, "flk1752830262547");
72+
this.executeTaskByKey(instance.getId(), test2Creator, "flk1752830262547");
73+
74+
// 技术总监、CEO 【会签审核】
75+
76+
// 技术总监任务认领
77+
this.executeTask(instance.getId(), FlowCreator.of("role002", "技术总监"), flwTask -> flowLongEngine.taskService()
78+
.claimRole(flwTask.getId(), test2Creator));
79+
// 执行技术总监认领任务
80+
this.executeTask(instance.getId(), test2Creator);
81+
82+
// CEO任务认领
83+
this.executeTask(instance.getId(), FlowCreator.of("role001", "CEO"), flwTask -> flowLongEngine.taskService()
84+
.claimRole(flwTask.getId(), test3Creator));
85+
// 执行CEO认领任务
86+
this.executeTask(instance.getId(), test3Creator);
87+
88+
// 流程执行结束
89+
FlwHisInstance fhi = flowLongEngine.queryService().getHistInstance(instance.getId());
90+
Assertions.assertEquals(1, fhi.getInstanceState());
91+
});
92+
}
93+
94+
class TestGroupStrategyTaskActorProvider extends GeneralTaskActorProvider {
95+
96+
@Override
97+
public boolean isAllowed(NodeModel nodeModel, FlowCreator flowCreator) {
98+
// 执行判断合法性
99+
return true;
100+
}
101+
102+
@Override
103+
public List<FlwTaskActor> getTaskActors(NodeModel nodeModel, Execution execution) {
104+
if (NodeSetType.role.eq(nodeModel.getSetType())) {
105+
if (nodeModel.allJoinGroupStrategy()) {
106+
// 全部人员参与审批分组策略,下面模拟动态提供具体流程参与者信息
107+
List<FlwTaskActor> ftaList = new ArrayList<>();
108+
for (NodeAssignee nodeAssignee : nodeModel.getNodeAssigneeList()) {
109+
String id = nodeAssignee.getId();
110+
if (Objects.equals("role001", id)) {
111+
// CEO
112+
ftaList.add(FlwTaskActor.ofFlowCreator(testCreator));
113+
ftaList.add(FlwTaskActor.ofFlowCreator(test2Creator));
114+
} else if (Objects.equals("role002", id)) {
115+
// 技术总监
116+
ftaList.add(FlwTaskActor.ofFlowCreator(test3Creator));
117+
ftaList.add(FlwTaskActor.ofFlowCreator(test4Creator));
118+
} else if (Objects.equals("role003", id)) {
119+
// 财务总监
120+
ftaList.add(FlwTaskActor.ofFlowCreator(test3Creator));
121+
ftaList.add(FlwTaskActor.ofFlowCreator(test2Creator));
122+
} else if (Objects.equals("role004", id)) {
123+
// 考勤管理员
124+
ftaList.add(FlwTaskActor.ofFlowCreator(test4Creator));
125+
ftaList.add(FlwTaskActor.ofFlowCreator(test3Creator));
126+
} else if (Objects.equals("role005", id)) {
127+
// 部门领导
128+
ftaList.add(FlwTaskActor.ofFlowCreator(testCreator));
129+
ftaList.add(FlwTaskActor.ofFlowCreator(test3Creator));
130+
} else if (Objects.equals("role006", id)) {
131+
// 测试人员
132+
ftaList.add(FlwTaskActor.ofFlowCreator(test5Creator));
133+
ftaList.add(FlwTaskActor.ofFlowCreator(test6Creator));
134+
}
135+
}
136+
137+
// 数据查询列表根据 id 排序、去重审批用户,避免【顺序签】错误
138+
List<FlwTaskActor> flwTaskActors = new ArrayList<>();
139+
for (FlwTaskActor fta : ftaList) {
140+
if (flwTaskActors.stream().noneMatch(t -> Objects.equals(t.getActorId(), fta.getActorId()))) {
141+
flwTaskActors.add(fta);
142+
}
143+
}
144+
return flwTaskActors;
145+
}
146+
}
147+
return super.getTaskActors(nodeModel, execution);
148+
}
149+
}
150+
}

0 commit comments

Comments
 (0)