完成票签功能支持
This commit is contained in:
parent
7287f379a8
commit
095b95b0c7
@ -28,7 +28,7 @@ FlowLong🐉飞龙工作流
|
||||
| 顺序会签 | 指同一个审批节点设置多个人,如A、B、C三人,三人按顺序依次收到待办,即A先审批,A提交后B才能审批,需全部同意之后,审批才可到下一审批节点。 | ✅ |
|
||||
| 并行会签 | 指同一个审批节点设置多个人,如A、B、C三人,三人会同时收到待办任务,需全部同意之后,审批才可到下一审批节点。 | ✅ |
|
||||
| 或签 | 一个流程审批节点里有多个处理人,任意一个人处理后就能进入下一个节点 | ✅ |
|
||||
| 票签 | 指同一个审批节点设置多个人,如A、B、C三人,分别定义不同的权重,当投票权重比例大于 50% 就能进入下一个节点 | ◻️ |
|
||||
| 票签 | 指同一个审批节点设置多个人,如A、B、C三人,分别定义不同的权重,当投票权重比例大于 50% 就能进入下一个节点 | ✅ |
|
||||
| 抄送 | 将审批结果通知给抄送列表对应的人 | ✅ |
|
||||
| 驳回 | 将审批重置发送给某节点,重新审批。驳回也叫退回,也可以分退回申请人、退回上一步、任意退回等 | ✅ |
|
||||
| 分配 | 允许用户自行决定任务转办、委派、主办 及其它 | ✅ |
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright 2023-2025 Licensed under the AGPL License
|
||||
*/
|
||||
package com.flowlong.bpm.engine;
|
||||
@ -43,6 +43,14 @@ public interface TaskService {
|
||||
return this.complete(taskId, flowCreator, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成指定实例ID活动任务
|
||||
*
|
||||
* @param instanceId 实例ID
|
||||
* @return
|
||||
*/
|
||||
boolean completeActiveTasksByInstanceId(Long instanceId, FlowCreator flowCreator);
|
||||
|
||||
/**
|
||||
* 更新任务对象
|
||||
*
|
||||
|
@ -168,14 +168,18 @@ public class FlowLongEngineImpl implements FlowLongEngine {
|
||||
* 票签( 总权重大于 50% 表示通过 )
|
||||
*/
|
||||
if (performType == PerformType.voteSign) {
|
||||
List<FlwTaskActor> flwTaskActors = queryService().getTaskActorsByTaskId(flwTask.getId());
|
||||
if (ObjectUtils.isNotEmpty(flwTaskActors)) {
|
||||
Optional<List<FlwTaskActor>> flwTaskActorsOptional = queryService().getActiveTaskActorsByInstanceId(flwInstance.getId());
|
||||
if (flwTaskActorsOptional.isPresent()) {
|
||||
NodeModel nodeModel = process.getProcessModel().getNode(flwTask.getTaskName());
|
||||
int passWeight = nodeModel.getPassWeight() == null ? 50 : nodeModel.getPassWeight();
|
||||
int votedWeight = 100 - flwTaskActors.stream().mapToInt(t -> t.getWeight() == null ? 0 : t.getWeight()).sum();
|
||||
int votedWeight = 100 - flwTaskActorsOptional.get().stream().mapToInt(t -> t.getWeight() == null ? 0 : t.getWeight()).sum();
|
||||
if (votedWeight < passWeight) {
|
||||
// 投票权重小于节点权重继续投票
|
||||
return;
|
||||
} else {
|
||||
// 投票完成关闭投票状态,进入下一个节点
|
||||
Assert.isFalse(taskService().completeActiveTasksByInstanceId(flwInstance.getId(), flowCreator),
|
||||
"Failed to close voting status");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ public class FlwHisTaskActor extends FlwTaskActor {
|
||||
hisTaskActor.actorType = taskActor.getActorType();
|
||||
hisTaskActor.actorId = taskActor.getActorId();
|
||||
hisTaskActor.actorName = taskActor.getActorName();
|
||||
hisTaskActor.weight = taskActor.getWeight();
|
||||
return hisTaskActor;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public class FlwTaskActor implements Serializable {
|
||||
/**
|
||||
* 票签权重
|
||||
*/
|
||||
private Integer weight;
|
||||
protected Integer weight;
|
||||
|
||||
public static FlwTaskActor ofUser(String actorId, String actorName) {
|
||||
return of(actorId, actorName, 0, null);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright 2023-2025 Licensed under the AGPL License
|
||||
*/
|
||||
package com.flowlong.bpm.mybatisplus.service;
|
||||
@ -87,31 +87,44 @@ public class TaskServiceImpl implements TaskService {
|
||||
flwTask.setVariable(args);
|
||||
Assert.isFalse(isAllowed(flwTask, flowCreator.getCreateId()), "当前参与者 [" + flowCreator.getCreateBy() + "]不允许执行任务[taskId=" + taskId + "]");
|
||||
|
||||
// 迁移 task 信息到 flw_his_task
|
||||
FlwHisTask hisTask = FlwHisTask.of(flwTask);
|
||||
hisTask.setFinishTime(DateUtils.getCurrentDate());
|
||||
hisTask.setTaskState(taskState);
|
||||
hisTask.setCreateId(flowCreator.getCreateId());
|
||||
hisTask.setCreateBy(flowCreator.getCreateBy());
|
||||
hisTaskMapper.insert(hisTask);
|
||||
|
||||
// 迁移任务参与者
|
||||
List<FlwTaskActor> taskActors = taskActorMapper.selectListByTaskId(taskId);
|
||||
if (ObjectUtils.isNotEmpty(taskActors)) {
|
||||
// 将 task 参与者信息迁移到 flw_his_task_actor
|
||||
taskActors.forEach(t -> hisTaskActorMapper.insert(FlwHisTaskActor.of(t)));
|
||||
// 移除 flw_task_actor 中 task 参与者信息
|
||||
taskActorMapper.deleteByTaskId(taskId);
|
||||
}
|
||||
|
||||
// 删除 flw_task 中指定 task 信息
|
||||
taskMapper.deleteById(taskId);
|
||||
// 迁移任务至历史表
|
||||
this.moveToHisTask(flwTask, taskState, flowCreator);
|
||||
|
||||
// 任务监听器通知
|
||||
this.taskNotify(eventType, flwTask);
|
||||
return flwTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迁移任务至历史表
|
||||
*
|
||||
* @param flwTask 执行任务
|
||||
* @param taskState 任务状态
|
||||
* @param flowCreator 任务创建者
|
||||
* @return
|
||||
*/
|
||||
protected boolean moveToHisTask(FlwTask flwTask, TaskState taskState, FlowCreator flowCreator) {
|
||||
// 迁移 task 信息到 flw_his_task
|
||||
FlwHisTask hisTask = FlwHisTask.of(flwTask);
|
||||
hisTask.setFinishTime(DateUtils.getCurrentDate());
|
||||
hisTask.setTaskState(taskState);
|
||||
hisTask.setCreateId(flowCreator.getCreateId());
|
||||
hisTask.setCreateBy(flowCreator.getCreateBy());
|
||||
Assert.isFalse(hisTaskMapper.insert(hisTask) > 0, "Migration to FlwHisTask table failed");
|
||||
|
||||
// 迁移任务参与者
|
||||
List<FlwTaskActor> taskActors = taskActorMapper.selectListByTaskId(flwTask.getId());
|
||||
if (ObjectUtils.isNotEmpty(taskActors)) {
|
||||
// 将 task 参与者信息迁移到 flw_his_task_actor
|
||||
taskActors.forEach(t -> Assert.isFalse(hisTaskActorMapper.insert(FlwHisTaskActor.of(t)) > 0,
|
||||
"Migration to FlwHisTaskActor table failed"));
|
||||
// 移除 flw_task_actor 中 task 参与者信息
|
||||
Assert.isFalse(taskActorMapper.deleteByTaskId(flwTask.getId()), "Delete FlwTaskActor table failed");
|
||||
}
|
||||
|
||||
// 删除 flw_task 中指定 task 信息
|
||||
return taskMapper.deleteById(flwTask.getId()) > 0;
|
||||
}
|
||||
|
||||
protected void taskNotify(EventType eventType, FlwTask flwTask) {
|
||||
if (null != taskListener) {
|
||||
@ -119,6 +132,26 @@ public class TaskServiceImpl implements TaskService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成指定实例ID活动任务
|
||||
*
|
||||
* @param instanceId 实例ID
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean completeActiveTasksByInstanceId(Long instanceId, FlowCreator flowCreator) {
|
||||
List<FlwTask> flwTasks = taskMapper.selectList(Wrappers.<FlwTask>lambdaQuery().eq(FlwTask::getInstanceId, instanceId));
|
||||
if (ObjectUtils.isNotEmpty(flwTasks)) {
|
||||
for (FlwTask flwTask : flwTasks) {
|
||||
// 迁移任务至历史表,设置任务状态为终止
|
||||
if (!this.moveToHisTask(flwTask, TaskState.termination, flowCreator)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务对象的finish_Time、createBy、expire_Time、version、variable
|
||||
*
|
||||
@ -134,7 +167,7 @@ public class TaskServiceImpl implements TaskService {
|
||||
/**
|
||||
* 查看任务设置为已阅状态
|
||||
*
|
||||
* @param taskId 任务ID
|
||||
* @param taskId 任务ID
|
||||
* @param taskActor 任务参与者
|
||||
* @return
|
||||
*/
|
||||
|
@ -33,10 +33,10 @@ public class TestVoteSign extends MysqlTest {
|
||||
this.executeActiveTasks(instance.getId(), testCreator);
|
||||
|
||||
// test1 领导审批同意
|
||||
this.executeActiveTasks(instance.getId(), FlowCreator.of(testUser1, "青苗"));
|
||||
this.executeTask(instance.getId(), FlowCreator.of(testUser1, "青苗"));
|
||||
|
||||
// test3 领导审批同意
|
||||
this.executeActiveTasks(instance.getId(), FlowCreator.of(testUser3, "聂秋秋"));
|
||||
this.executeTask(instance.getId(), FlowCreator.of(testUser3, "聂秋秋"));
|
||||
|
||||
// test2 不在执行达到票签值
|
||||
// 抄送人力资源,流程自动结束
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": 1,
|
||||
"name": "报销审批(或签)",
|
||||
"name": "人事审批(票签)",
|
||||
"nodeConfig": {
|
||||
"nodeName": "发起人",
|
||||
"type": 0,
|
||||
|
Loading…
x
Reference in New Issue
Block a user