add 添加任务拾取,任务归还,任务终止,任务委托

This commit is contained in:
gssong 2023-06-09 21:44:56 +08:00
parent 4d63888080
commit f494d0f3f0
8 changed files with 326 additions and 16 deletions

View File

@ -15,6 +15,8 @@ public interface FlowConstant {
String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人"; String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人";
String MESSAGE_SUSPENDED = "当前任务已";
/** /**
* 连线 * 连线
*/ */

View File

@ -1,5 +1,6 @@
package org.dromara.workflow.controller; package org.dromara.workflow.controller;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup; import org.dromara.common.core.validate.AddGroup;
@ -7,12 +8,12 @@ import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log; import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType; import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController; import org.dromara.common.web.core.BaseController;
import org.dromara.workflow.domain.bo.CompleteTaskBo; import org.dromara.workflow.domain.bo.*;
import org.dromara.workflow.domain.bo.StartProcessBo;
import org.dromara.workflow.domain.bo.TaskBo;
import org.dromara.workflow.domain.vo.TaskVo; import org.dromara.workflow.domain.vo.TaskVo;
import org.dromara.workflow.service.IActTaskService; import org.dromara.workflow.service.IActTaskService;
import org.flowable.engine.TaskService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -31,6 +32,8 @@ public class ActTaskController extends BaseController {
private final IActTaskService iActTaskService; private final IActTaskService iActTaskService;
private final TaskService taskService;
/** /**
* 启动任务 * 启动任务
@ -76,4 +79,61 @@ public class ActTaskController extends BaseController {
public TableDataInfo<TaskVo> getTaskFinishByPage(TaskBo taskBo) { public TableDataInfo<TaskVo> getTaskFinishByPage(TaskBo taskBo) {
return iActTaskService.getTaskFinishByPage(taskBo); return iActTaskService.getTaskFinishByPage(taskBo);
} }
/**
* 签收拾取任务
*
* @param taskId 任务id
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@PostMapping("/claim/{taskId}")
public R<Void> claimTask(@NotBlank(message = "任务id不能为空") @PathVariable String taskId) {
try {
taskService.claim(taskId, String.valueOf(LoginHelper.getUserId()));
return R.ok();
} catch (Exception e) {
e.printStackTrace();
return R.fail("签收任务失败:" + e.getMessage());
}
}
/**
* 归还拾取的任务
*
* @param taskId 任务id
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@PostMapping("/returnTask/{taskId}")
public R<Void> returnTask(@NotBlank(message = "任务id不能为空") @PathVariable String taskId) {
try {
taskService.setAssignee(taskId, null);
return R.ok();
} catch (Exception e) {
e.printStackTrace();
return R.fail("归还任务失败:" + e.getMessage());
}
}
/**
* 委派任务
*
* @param delegateBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@PostMapping("/delegateTask")
public R<Void> delegateTask(@Validated({AddGroup.class}) @RequestBody DelegateBo delegateBo) {
return toAjax(iActTaskService.delegateTask(delegateBo));
}
/**
* 终止任务
*
* @param terminationBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.DELETE)
@PostMapping("/terminationTask")
public R<Void> terminationTask(@RequestBody TerminationBo terminationBo) {
return toAjax(iActTaskService.terminationTask(terminationBo));
}
} }

View File

@ -0,0 +1,38 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
/**
* 委派任务请求对象
*
* @author may
*/
@Data
public class DelegateBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 委派人id
*/
@NotBlank(message = "委派人id不能为空", groups = {AddGroup.class})
private String userId;
/**
* 委派人名称
*/
@NotBlank(message = "委派人名称不能为空", groups = {AddGroup.class})
private String nickName;
/**
* 任务id
*/
@NotBlank(message = "任务id不能为空", groups = {AddGroup.class})
private String taskId;
}

View File

@ -0,0 +1,37 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
/**
* 终止任务请求对象
*
* @author may
*/
@Data
public class TerminationBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务id
*/
@NotBlank(message = "任务id为空", groups = AddGroup.class)
private String taskId;
/**
* 转办人id
*/
@NotBlank(message = "转办人不能为空", groups = AddGroup.class)
private String userId;
/**
* 审批意见
*/
private String comment;
}

View File

@ -0,0 +1,51 @@
package org.dromara.workflow.flowable.cmd;
import org.dromara.common.core.exception.ServiceException;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.service.HistoricTaskService;
import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
import java.util.Date;
import java.util.List;
/**
* 修改流程历史
*
* @author may
*/
public class UpdateHiTaskInstCmd implements Command<Boolean> {
private final List<String> taskIds;
private final String processDefinitionId;
private final String processInstanceId;
public UpdateHiTaskInstCmd(List<String> taskIds, String processDefinitionId, String processInstanceId) {
this.taskIds = taskIds;
this.processDefinitionId = processDefinitionId;
this.processInstanceId = processInstanceId;
}
@Override
public Boolean execute(CommandContext commandContext) {
try {
HistoricTaskService historicTaskService = CommandContextUtil.getHistoricTaskService();
for (String taskId : taskIds) {
HistoricTaskInstanceEntity historicTask = historicTaskService.getHistoricTask(taskId);
if (historicTask != null) {
historicTask.setProcessDefinitionId(processDefinitionId);
historicTask.setProcessDefinitionId(processInstanceId);
historicTask.setCreateTime(new Date());
CommandContextUtil.getHistoricTaskService().updateHistoricTask(historicTask, true);
}
}
return true;
} catch (Exception e) {
throw new ServiceException(e.getMessage());
}
}
}

View File

@ -1,9 +1,7 @@
package org.dromara.workflow.service; package org.dromara.workflow.service;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.bo.CompleteTaskBo; import org.dromara.workflow.domain.bo.*;
import org.dromara.workflow.domain.bo.StartProcessBo;
import org.dromara.workflow.domain.bo.TaskBo;
import org.dromara.workflow.domain.vo.TaskVo; import org.dromara.workflow.domain.vo.TaskVo;
import java.util.Map; import java.util.Map;
@ -46,4 +44,20 @@ public interface IActTaskService {
* @return 结果 * @return 结果
*/ */
TableDataInfo<TaskVo> getTaskFinishByPage(TaskBo taskBo); TableDataInfo<TaskVo> getTaskFinishByPage(TaskBo taskBo);
/**
* 委派任务
*
* @param delegateBo 参数
* @return 结果
*/
boolean delegateTask(DelegateBo delegateBo);
/**
* 终止任务
*
* @param terminationBo 参数
* @return 结果
*/
boolean terminationTask(TerminationBo terminationBo);
} }

View File

@ -2,19 +2,22 @@ package org.dromara.workflow.service.impl;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.dto.RoleDTO; import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper; 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.domain.bo.CompleteTaskBo; import org.dromara.workflow.domain.bo.*;
import org.dromara.workflow.domain.bo.StartProcessBo;
import org.dromara.workflow.domain.bo.TaskBo;
import org.dromara.workflow.domain.vo.TaskVo; import org.dromara.workflow.domain.vo.TaskVo;
import org.dromara.workflow.service.IActTaskService; import org.dromara.workflow.service.IActTaskService;
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.HistoryService; import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService; import org.flowable.engine.RuntimeService;
@ -25,6 +28,7 @@ import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery; import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -32,7 +36,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
/** /**
* 任务 服务层实现 * 任务 服务层实现
@ -70,7 +73,7 @@ public class ActTaskServiceImpl implements IActTaskService {
return map; return map;
} }
// 设置启动人 // 设置启动人
Authentication.setAuthenticatedUserId(LoginHelper.getUserId().toString()); Authentication.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId()));
// 启动流程实例提交申请 // 启动流程实例提交申请
Map<String, Object> variables = startProcessBo.getVariables(); Map<String, Object> variables = startProcessBo.getVariables();
// 启动跳过表达式 // 启动跳过表达式
@ -100,12 +103,12 @@ public class ActTaskServiceImpl implements IActTaskService {
public boolean completeTask(CompleteTaskBo completeTaskBo) { public boolean completeTask(CompleteTaskBo completeTaskBo) {
try { try {
List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles(); List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
String userId = LoginHelper.getUserId().toString(); String userId = String.valueOf(LoginHelper.getUserId());
TaskQuery taskQuery = taskService.createTaskQuery(); TaskQuery taskQuery = taskService.createTaskQuery();
taskQuery.taskId(completeTaskBo.getTaskId()) taskQuery.taskId(completeTaskBo.getTaskId())
.taskTenantId(TenantHelper.getTenantId()).taskCandidateOrAssigned(userId); .taskTenantId(TenantHelper.getTenantId()).taskCandidateOrAssigned(userId);
if (CollUtil.isNotEmpty(roles)) { if (CollUtil.isNotEmpty(roles)) {
List<String> groupIds = roles.stream().map(e -> String.valueOf(e.getRoleId())).collect(Collectors.toList()); List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
taskQuery.taskCandidateGroupIn(groupIds); taskQuery.taskCandidateGroupIn(groupIds);
} }
Task task = taskQuery.singleResult(); Task task = taskQuery.singleResult();
@ -130,11 +133,11 @@ public class ActTaskServiceImpl implements IActTaskService {
@Override @Override
public TableDataInfo<TaskVo> getTaskWaitByPage(TaskBo taskBo) { public TableDataInfo<TaskVo> getTaskWaitByPage(TaskBo taskBo) {
List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles(); List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
String userId = LoginHelper.getUserId().toString(); String userId = String.valueOf(LoginHelper.getUserId());
TaskQuery query = taskService.createTaskQuery(); TaskQuery query = taskService.createTaskQuery();
query.taskTenantId(TenantHelper.getTenantId()).taskCandidateOrAssigned(userId); query.taskTenantId(TenantHelper.getTenantId()).taskCandidateOrAssigned(userId);
if (CollUtil.isNotEmpty(roles)) { if (CollUtil.isNotEmpty(roles)) {
List<String> groupIds = roles.stream().map(e -> String.valueOf(e.getRoleId())).collect(Collectors.toList()); List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
query.taskCandidateGroupIn(groupIds); query.taskCandidateGroupIn(groupIds);
} }
if (StringUtils.isNotBlank(taskBo.getName())) { if (StringUtils.isNotBlank(taskBo.getName())) {
@ -156,7 +159,7 @@ public class ActTaskServiceImpl implements IActTaskService {
*/ */
@Override @Override
public TableDataInfo<TaskVo> getTaskFinishByPage(TaskBo taskBo) { public TableDataInfo<TaskVo> getTaskFinishByPage(TaskBo taskBo) {
String userId = LoginHelper.getUserId().toString(); String userId = String.valueOf(LoginHelper.getUserId());
HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery() HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery()
.taskAssignee(userId).taskTenantId(TenantHelper.getTenantId()).finished().orderByHistoricTaskInstanceStartTime().asc(); .taskAssignee(userId).taskTenantId(TenantHelper.getTenantId()).finished().orderByHistoricTaskInstanceStartTime().asc();
if (StringUtils.isNotBlank(taskBo.getName())) { if (StringUtils.isNotBlank(taskBo.getName())) {
@ -170,4 +173,74 @@ public class ActTaskServiceImpl implements IActTaskService {
long count = query.count(); long count = query.count();
return new TableDataInfo<>(list, count); return new TableDataInfo<>(list, count);
} }
/**
* 委派任务
*
* @param delegateBo 参数
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean delegateTask(DelegateBo delegateBo) {
TaskEntity task = (TaskEntity) taskService.createTaskQuery()
.taskTenantId(TenantHelper.getTenantId()).taskId(delegateBo.getTaskId())
.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);
}
try {
TaskEntity newTask = WorkflowUtils.createNewTask(task);
taskService.addComment(newTask.getId(), task.getProcessInstanceId(), "" + LoginHelper.getUsername() + "】委派给【" + delegateBo.getNickName() + "");
//委托任务
taskService.delegateTask(delegateBo.getTaskId(), delegateBo.getUserId());
//办理生成的任务记录
taskService.complete(newTask.getId());
return true;
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(e.getMessage());
}
}
/**
* 终止任务
*
* @param terminationBo 参数
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean terminationTask(TerminationBo terminationBo) {
Task task = taskService.createTaskQuery()
.taskTenantId(TenantHelper.getTenantId()).taskId(terminationBo.getTaskId()).singleResult();
if (ObjectUtil.isEmpty(task)) {
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
}
if (task.isSuspended()) {
throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
}
try {
if (StringUtils.isBlank(terminationBo.getComment())) {
terminationBo.setComment(LoginHelper.getUsername() + "终止了申请");
} else {
terminationBo.setComment(LoginHelper.getUsername() + "终止了申请:" + terminationBo.getComment());
}
taskService.addComment(task.getId(), task.getProcessInstanceId(), terminationBo.getComment());
List<Task> list = taskService.createTaskQuery().taskTenantId(TenantHelper.getTenantId())
.processInstanceId(task.getProcessInstanceId()).list();
if (CollectionUtil.isNotEmpty(list)) {
List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
if (CollectionUtil.isNotEmpty(subTasks)) {
subTasks.forEach(e -> taskService.deleteTask(e.getId()));
}
runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY);
}
return true;
} catch (Exception e) {
throw new ServiceException(e.getMessage());
}
}
} }

View File

@ -2,12 +2,19 @@ package org.dromara.workflow.utils;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.tenant.helper.TenantHelper;
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.editor.language.json.converter.BpmnJsonConverter; import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.engine.ProcessEngine;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
@ -16,6 +23,8 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.rmi.ServerException; import java.rmi.ServerException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -29,6 +38,8 @@ public class WorkflowUtils {
public WorkflowUtils() { public WorkflowUtils() {
} }
private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);
/** /**
* bpmnModel转为xml * bpmnModel转为xml
* *
@ -118,4 +129,28 @@ public class WorkflowUtils {
throw new ServerException(subtask ? "子流程必须存在结束节点!" : "" + "必须存在结束节点!"); throw new ServerException(subtask ? "子流程必须存在结束节点!" : "" + "必须存在结束节点!");
} }
} }
public static TaskEntity createNewTask(Task currentTask) {
TaskEntity task = null;
if (ObjectUtil.isNotEmpty(currentTask)) {
task = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask();
task.setCategory(currentTask.getCategory());
task.setDescription(currentTask.getDescription());
task.setTenantId(currentTask.getTenantId());
task.setAssignee(currentTask.getAssignee());
task.setName(currentTask.getName());
task.setProcessDefinitionId(currentTask.getProcessDefinitionId());
task.setProcessInstanceId(currentTask.getProcessInstanceId());
task.setTaskDefinitionKey(currentTask.getTaskDefinitionKey());
task.setPriority(currentTask.getPriority());
task.setCreateTime(new Date());
task.setTenantId(TenantHelper.getTenantId());
PROCESS_ENGINE.getTaskService().saveTask(task);
}
if (ObjectUtil.isNotNull(task)) {
UpdateHiTaskInstCmd updateHiTaskInstCmd = new UpdateHiTaskInstCmd(Collections.singletonList(task.getId()), task.getProcessDefinitionId(), task.getProcessInstanceId());
PROCESS_ENGINE.getManagementService().executeCommand(updateHiTaskInstCmd);
}
return task;
}
} }