add 添加会签任务加签减签,添加任务作废理由

This commit is contained in:
gssong 2023-07-02 09:40:10 +08:00
parent ecbd2b046e
commit 54837deda0
11 changed files with 458 additions and 2 deletions

View File

@ -32,4 +32,24 @@ public interface FlowConstant {
*/ */
String CANDIDATE = "candidate"; String CANDIDATE = "candidate";
/**
* 会签任务总数
*/
String NUMBER_OF_INSTANCES = "nrOfInstances";
/**
* 正在执行的会签总数
*/
String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances";
/**
* 已完成的会签任务总数
*/
String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances";
/**
* 循环的索引值可以使用elementIndexVariable属性修改loopCounter的变量名
*/
String LOOP_COUNTER = "loopCounter";
} }

View File

@ -147,4 +147,26 @@ public class ActTaskController extends BaseController {
return toAjax(iActTaskService.transferTask(transmitBo)); return toAjax(iActTaskService.transferTask(transmitBo));
} }
/**
* 会签任务加签
*
* @param addMultiBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@PostMapping("/addMultiInstanceExecution")
public R<Void> addMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody AddMultiBo addMultiBo) {
return toAjax(iActTaskService.addMultiInstanceExecution(addMultiBo));
}
/**
* 会签任务减签
*
* @param deleteMultiBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@PostMapping("/deleteMultiInstanceExecution")
public R<Void> deleteMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody DeleteMultiBo deleteMultiBo) {
return toAjax(iActTaskService.deleteMultiInstanceExecution(deleteMultiBo));
}
} }

View File

@ -0,0 +1,40 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 加签参数请求
*
* @author may
*/
@Data
public class AddMultiBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务ID
*/
@NotBlank(message = "任务ID不能为空", groups = AddGroup.class)
private String taskId;
/**
* 加签人员id
*/
@NotEmpty(message = "加签人员不能为空", groups = AddGroup.class)
private List<Long> assignees;
/**
* 加签人员名称
*/
@NotEmpty(message = "加签人员不能为空", groups = AddGroup.class)
private List<String> assigneeNames;
}

View File

@ -0,0 +1,52 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 减签参数请求
*
* @author may
*/
@Data
public class DeleteMultiBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务ID
*/
@NotBlank(message = "任务ID不能为空", groups = AddGroup.class)
private String taskId;
/**
* 减签人员
*/
@NotEmpty(message = "减签人员不能为空", groups = AddGroup.class)
private List<String> taskIds;
/**
* 执行id
*/
@NotEmpty(message = "执行id不能为空", groups = AddGroup.class)
private List<String> executionIds;
/**
* 人员id
*/
@NotEmpty(message = "减签人员id不能为空", groups = AddGroup.class)
private List<Long> assigneeIds;
/**
* 人员名称
*/
@NotEmpty(message = "减签人员不能为空", groups = AddGroup.class)
private List<String> assigneeNames;
}

View File

@ -0,0 +1,33 @@
package org.dromara.workflow.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 多实例信息
*
* @author may
*/
@Data
public class MultiInstanceVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 会签类型串行并行
*/
private Object type;
/**
* 会签人员KEY
*/
private String assignee;
/**
* 会签人员集合KEY
*/
private String assigneeList;
}

View File

@ -0,0 +1,58 @@
package org.dromara.workflow.flowable.cmd;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES;
/**
* 串行加签
*
* @author may
*/
public class AddSequenceMultiInstanceCmd implements Command<Void> {
/**
* 执行id
*/
private final String executionId;
/**
* 会签人员集合KEY
*/
private final String assigneeList;
/**
* 加签人员
*/
private final List<Long> assignees;
public AddSequenceMultiInstanceCmd(String executionId, String assigneeList, List<Long> assignees) {
this.executionId = executionId;
this.assigneeList = assigneeList;
this.assignees = assignees;
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
ExecutionEntity entity = executionEntityManager.findById(executionId);
//多实例任务总数加assignees.size()
Integer nrOfInstances = (Integer) entity.getVariable(NUMBER_OF_INSTANCES);
entity.setVariable(NUMBER_OF_INSTANCES, nrOfInstances + assignees.size());
// 设置流程变量
List<Long> userIds = (List) entity.getVariable(assigneeList);
userIds.addAll(assignees);
Map<String, Object> variables = new HashMap<>(16);
variables.put(assigneeList, userIds);
entity.setVariables(variables);
return null;
}
}

View File

@ -0,0 +1,80 @@
package org.dromara.workflow.flowable.cmd;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.dromara.workflow.common.constant.FlowConstant.LOOP_COUNTER;
import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES;
/**
* 串行减签
*
* @author may
*/
public class DeleteSequenceMultiInstanceCmd implements Command<Void> {
/**
* 当前节点审批人员id
*/
private final String currentUserId;
/**
* 执行id
*/
private final String executionId;
/**
* 会签人员集合KEY
*/
private final String assigneeList;
/**
* 减签人员
*/
private final List<Long> assignees;
public DeleteSequenceMultiInstanceCmd(String currentUserId, String executionId, String assigneeList, List<Long> assignees) {
this.currentUserId = currentUserId;
this.executionId = executionId;
this.assigneeList = assigneeList;
this.assignees = assignees;
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
ExecutionEntity entity = executionEntityManager.findById(executionId);
// 设置流程变量
List<Long> userIds = (List) entity.getVariable(assigneeList);
List<Long> userIdList = new ArrayList<>();
userIds.forEach(e -> {
Long userId = assignees.stream().filter(id -> id.equals(e)).findFirst().orElse(null);
if (userId == null) {
userIdList.add(e);
}
});
//当前任务执行位置
int loopCounterIndex = -1;
for (int i = 0; i < userIdList.size(); i++) {
Long userId = userIdList.get(i);
if (currentUserId.equals(userId.toString())) {
loopCounterIndex = i;
}
}
Map<String, Object> variables = new HashMap<>(16);
variables.put(NUMBER_OF_INSTANCES, userIdList.size());
variables.put(assigneeList, userIdList);
variables.put(LOOP_COUNTER, loopCounterIndex);
entity.setVariables(variables);
return null;
}
}

View File

@ -68,4 +68,20 @@ public interface IActTaskService {
* @return 结果 * @return 结果
*/ */
boolean transferTask(TransmitBo transmitBo); boolean transferTask(TransmitBo transmitBo);
/**
* 会签任务加签
*
* @param addMultiBo 参数
* @return 结果
*/
boolean addMultiInstanceExecution(AddMultiBo addMultiBo);
/**
* 会签任务减签
*
* @param deleteMultiBo 参数
* @return 结果
*/
boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo);
} }

View File

@ -303,6 +303,10 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
} }
//节点图形信息 //节点图形信息
map.put("graphicInfoVos", graphicInfoVos); map.put("graphicInfoVos", graphicInfoVos);
//作废理由
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId)
.processInstanceTenantId(TenantHelper.getTenantId()).singleResult();
map.put("deleteReason", historicProcessInstance.getDeleteReason());
return map; return map;
} }

View File

@ -16,13 +16,18 @@ import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.workflow.common.constant.FlowConstant; import org.dromara.workflow.common.constant.FlowConstant;
import org.dromara.workflow.common.enums.BusinessStatusEnum; import org.dromara.workflow.common.enums.BusinessStatusEnum;
import org.dromara.workflow.domain.bo.*; import org.dromara.workflow.domain.bo.*;
import org.dromara.workflow.domain.vo.MultiInstanceVo;
import org.dromara.workflow.domain.vo.TaskVo; import org.dromara.workflow.domain.vo.TaskVo;
import org.dromara.workflow.flowable.cmd.AddSequenceMultiInstanceCmd;
import org.dromara.workflow.flowable.cmd.DeleteSequenceMultiInstanceCmd;
import org.dromara.workflow.flowable.cmd.UpdateBusinessStatusCmd; import org.dromara.workflow.flowable.cmd.UpdateBusinessStatusCmd;
import org.dromara.workflow.service.IActTaskService; import org.dromara.workflow.service.IActTaskService;
import org.dromara.workflow.utils.WorkflowUtils; import org.dromara.workflow.utils.WorkflowUtils;
import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.*; import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task; import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery; import org.flowable.task.api.TaskQuery;
@ -169,7 +174,7 @@ public class ActTaskServiceImpl implements IActTaskService {
query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%"); query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%");
} }
if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) { if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
query.processDefinitionKey(taskBo.getProcessDefinitionKey() ); query.processDefinitionKey(taskBo.getProcessDefinitionKey());
} }
List<Task> taskList = query.listPage(taskBo.getPageNum(), taskBo.getPageSize()); List<Task> taskList = query.listPage(taskBo.getPageNum(), taskBo.getPageSize());
List<ProcessInstance> processInstanceList = null; List<ProcessInstance> processInstanceList = null;
@ -213,7 +218,7 @@ public class ActTaskServiceImpl implements IActTaskService {
query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%"); query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%");
} }
if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) { if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
query.processDefinitionKey( taskBo.getProcessDefinitionKey() ); query.processDefinitionKey(taskBo.getProcessDefinitionKey());
} }
List<HistoricTaskInstance> taskInstanceList = query.listPage(taskBo.getPageNum(), taskBo.getPageSize()); List<HistoricTaskInstance> taskInstanceList = query.listPage(taskBo.getPageNum(), taskBo.getPageSize());
List<HistoricProcessInstance> historicProcessInstanceList = null; List<HistoricProcessInstance> historicProcessInstanceList = null;
@ -342,4 +347,94 @@ public class ActTaskServiceImpl implements IActTaskService {
throw new ServiceException(e.getMessage()); throw new ServiceException(e.getMessage());
} }
} }
/**
* 会签任务加签
*
* @param addMultiBo 参数
*/
@Override
public boolean addMultiInstanceExecution(AddMultiBo addMultiBo) {
Task task = taskService.createTaskQuery().taskId(addMultiBo.getTaskId()).taskTenantId(TenantHelper.getTenantId())
.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult();
if (ObjectUtil.isEmpty(task)) {
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
}
if (task.isSuspended()) {
throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
}
String taskDefinitionKey = task.getTaskDefinitionKey();
String processInstanceId = task.getProcessInstanceId();
String processDefinitionId = task.getProcessDefinitionId();
try {
MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
if (multiInstanceVo == null) {
throw new ServiceException("当前环节不是会签节点");
}
if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
for (Long assignee : addMultiBo.getAssignees()) {
runtimeService.addMultiInstanceExecution(taskDefinitionKey, processInstanceId, Collections.singletonMap(multiInstanceVo.getAssignee(), assignee));
}
} else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
AddSequenceMultiInstanceCmd addSequenceMultiInstanceCmd = new AddSequenceMultiInstanceCmd(task.getExecutionId(), multiInstanceVo.getAssigneeList(), addMultiBo.getAssignees());
managementService.executeCommand(addSequenceMultiInstanceCmd);
}
List<String> assigneeNames = addMultiBo.getAssigneeNames();
String username = LoginHelper.getUsername();
TaskEntity newTask = WorkflowUtils.createNewTask(task);
taskService.addComment(newTask.getId(), processInstanceId, username + "加签【" + String.join(StringUtils.SEPARATOR, assigneeNames) + "");
taskService.complete(newTask.getId());
return true;
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(e.getMessage());
}
}
/**
* 会签任务减签
*
* @param deleteMultiBo 参数
*/
@Override
public boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo) {
Task task = taskService.createTaskQuery().taskId(deleteMultiBo.getTaskId()).taskTenantId(TenantHelper.getTenantId())
.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult();
if (ObjectUtil.isEmpty(task)) {
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
}
if (task.isSuspended()) {
throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
}
String taskDefinitionKey = task.getTaskDefinitionKey();
String processInstanceId = task.getProcessInstanceId();
String processDefinitionId = task.getProcessDefinitionId();
try {
MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
if (multiInstanceVo == null) {
throw new ServiceException("当前环节不是会签节点");
}
if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
for (String executionId : deleteMultiBo.getExecutionIds()) {
runtimeService.deleteMultiInstanceExecution(executionId, false);
}
for (String taskId : deleteMultiBo.getTaskIds()) {
historyService.deleteHistoricTaskInstance(taskId);
}
} else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
DeleteSequenceMultiInstanceCmd deleteSequenceMultiInstanceCmd = new DeleteSequenceMultiInstanceCmd(task.getAssignee(), task.getExecutionId(), multiInstanceVo.getAssigneeList(), deleteMultiBo.getAssigneeIds());
managementService.executeCommand(deleteSequenceMultiInstanceCmd);
}
List<String> assigneeNames = deleteMultiBo.getAssigneeNames();
String username = LoginHelper.getUsername();
TaskEntity newTask = WorkflowUtils.createNewTask(task);
taskService.addComment(newTask.getId(), processInstanceId, username + "减签【" + String.join(StringUtils.SEPARATOR, assigneeNames) + "");
taskService.complete(newTask.getId());
return true;
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(e.getMessage());
}
}
} }

View File

@ -17,12 +17,16 @@ import org.dromara.system.domain.SysUserRole;
import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.mapper.SysUserRoleMapper; import org.dromara.system.mapper.SysUserRoleMapper;
import org.dromara.workflow.common.constant.FlowConstant; import org.dromara.workflow.common.constant.FlowConstant;
import org.dromara.workflow.domain.vo.MultiInstanceVo;
import org.dromara.workflow.domain.vo.ParticipantVo; import org.dromara.workflow.domain.vo.ParticipantVo;
import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd; import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd;
import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*; import org.flowable.bpmn.model.*;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.editor.language.json.converter.BpmnJsonConverter; import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.engine.ProcessEngine; import org.flowable.engine.ProcessEngine;
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.flowable.identitylink.api.history.HistoricIdentityLink; import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.task.api.Task; import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.flowable.task.service.impl.persistence.entity.TaskEntity;
@ -224,4 +228,36 @@ public class WorkflowUtils {
} }
return participantVo; return participantVo;
} }
/**
* 判断当前节点是否为会签节点
*
* @param processDefinitionId 流程定义id
* @param taskDefinitionKey 流程定义id
*/
public static MultiInstanceVo isMultiInstance(String processDefinitionId, String taskDefinitionKey) {
BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey);
MultiInstanceVo multiInstanceVo = new MultiInstanceVo();
//判断是否为并行会签节点
if (flowNode.getBehavior() instanceof ParallelMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) {
Expression collectionExpression = behavior.getCollectionExpression();
String assigneeList = collectionExpression.getExpressionText();
String assignee = behavior.getCollectionElementVariable();
multiInstanceVo.setType(behavior);
multiInstanceVo.setAssignee(assignee);
multiInstanceVo.setAssigneeList(assigneeList);
return multiInstanceVo;
//判断是否为串行会签节点
} else if (flowNode.getBehavior() instanceof SequentialMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) {
Expression collectionExpression = behavior.getCollectionExpression();
String assigneeList = collectionExpression.getExpressionText();
String assignee = behavior.getCollectionElementVariable();
multiInstanceVo.setType(behavior);
multiInstanceVo.setAssignee(assignee);
multiInstanceVo.setAssigneeList(assigneeList);
return multiInstanceVo;
}
return null;
}
} }