From f494d0f3f0db6f7df2610412af6cb890594f74d0 Mon Sep 17 00:00:00 2001 From: gssong <1742057357@qq.com> Date: Fri, 9 Jun 2023 21:44:56 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E6=B7=BB=E5=8A=A0=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E6=8B=BE=E5=8F=96=EF=BC=8C=E4=BB=BB=E5=8A=A1=E5=BD=92=E8=BF=98?= =?UTF-8?q?=EF=BC=8C=E4=BB=BB=E5=8A=A1=E7=BB=88=E6=AD=A2=EF=BC=8C=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=A7=94=E6=89=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/FlowConstant.java | 2 + .../controller/ActTaskController.java | 66 ++++++++++++- .../workflow/domain/bo/DelegateBo.java | 38 ++++++++ .../workflow/domain/bo/TerminationBo.java | 37 ++++++++ .../flowable/cmd/UpdateHiTaskInstCmd.java | 51 ++++++++++ .../workflow/service/IActTaskService.java | 20 +++- .../service/impl/ActTaskServiceImpl.java | 93 +++++++++++++++++-- .../dromara/workflow/utils/WorkflowUtils.java | 35 +++++++ 8 files changed, 326 insertions(+), 16 deletions(-) create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java index 61194bd89..34a63b91b 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java @@ -15,6 +15,8 @@ public interface FlowConstant { String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人"; + String MESSAGE_SUSPENDED = "当前任务已"; + /** * 连线 */ diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java index 886cf67c6..d75c6bb8a 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java @@ -1,5 +1,6 @@ package org.dromara.workflow.controller; +import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; 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.enums.BusinessType; 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.workflow.domain.bo.CompleteTaskBo; -import org.dromara.workflow.domain.bo.StartProcessBo; -import org.dromara.workflow.domain.bo.TaskBo; +import org.dromara.workflow.domain.bo.*; import org.dromara.workflow.domain.vo.TaskVo; import org.dromara.workflow.service.IActTaskService; +import org.flowable.engine.TaskService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -31,6 +32,8 @@ public class ActTaskController extends BaseController { private final IActTaskService iActTaskService; + private final TaskService taskService; + /** * 启动任务 @@ -76,4 +79,61 @@ public class ActTaskController extends BaseController { public TableDataInfo getTaskFinishByPage(TaskBo taskBo) { return iActTaskService.getTaskFinishByPage(taskBo); } + + /** + * 签收(拾取)任务 + * + * @param taskId 任务id + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @PostMapping("/claim/{taskId}") + public R 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 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 delegateTask(@Validated({AddGroup.class}) @RequestBody DelegateBo delegateBo) { + return toAjax(iActTaskService.delegateTask(delegateBo)); + } + + /** + * 终止任务 + * + * @param terminationBo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.DELETE) + @PostMapping("/terminationTask") + public R terminationTask(@RequestBody TerminationBo terminationBo) { + return toAjax(iActTaskService.terminationTask(terminationBo)); + } + } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java new file mode 100644 index 000000000..a6846a6d6 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java @@ -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; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java new file mode 100644 index 000000000..61b761678 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java @@ -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; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java new file mode 100644 index 000000000..b87ae816e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java @@ -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 { + + private final List taskIds; + + private final String processDefinitionId; + + private final String processInstanceId; + + public UpdateHiTaskInstCmd(List 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()); + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java index 15b149b0e..e4edc887c 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java @@ -1,9 +1,7 @@ package org.dromara.workflow.service; import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.workflow.domain.bo.CompleteTaskBo; -import org.dromara.workflow.domain.bo.StartProcessBo; -import org.dromara.workflow.domain.bo.TaskBo; +import org.dromara.workflow.domain.bo.*; import org.dromara.workflow.domain.vo.TaskVo; import java.util.Map; @@ -46,4 +44,20 @@ public interface IActTaskService { * @return 结果 */ TableDataInfo getTaskFinishByPage(TaskBo taskBo); + + /** + * 委派任务 + * + * @param delegateBo 参数 + * @return 结果 + */ + boolean delegateTask(DelegateBo delegateBo); + + /** + * 终止任务 + * + * @param terminationBo 参数 + * @return 结果 + */ + boolean terminationTask(TerminationBo terminationBo); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java index 32d413f0e..95063b7f4 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java @@ -2,19 +2,22 @@ package org.dromara.workflow.service.impl; import cn.hutool.core.bean.BeanUtil; 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 org.dromara.common.core.domain.dto.RoleDTO; 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.mybatis.core.page.TableDataInfo; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.workflow.common.constant.FlowConstant; -import org.dromara.workflow.domain.bo.CompleteTaskBo; -import org.dromara.workflow.domain.bo.StartProcessBo; -import org.dromara.workflow.domain.bo.TaskBo; +import org.dromara.workflow.domain.bo.*; import org.dromara.workflow.domain.vo.TaskVo; import org.dromara.workflow.service.IActTaskService; +import org.dromara.workflow.utils.WorkflowUtils; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.engine.HistoryService; 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.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -32,7 +36,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; /** * 任务 服务层实现 @@ -70,7 +73,7 @@ public class ActTaskServiceImpl implements IActTaskService { return map; } // 设置启动人 - Authentication.setAuthenticatedUserId(LoginHelper.getUserId().toString()); + Authentication.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId())); // 启动流程实例(提交申请) Map variables = startProcessBo.getVariables(); // 启动跳过表达式 @@ -100,12 +103,12 @@ public class ActTaskServiceImpl implements IActTaskService { public boolean completeTask(CompleteTaskBo completeTaskBo) { try { List roles = LoginHelper.getLoginUser().getRoles(); - String userId = LoginHelper.getUserId().toString(); + String userId = String.valueOf(LoginHelper.getUserId()); TaskQuery taskQuery = taskService.createTaskQuery(); taskQuery.taskId(completeTaskBo.getTaskId()) .taskTenantId(TenantHelper.getTenantId()).taskCandidateOrAssigned(userId); if (CollUtil.isNotEmpty(roles)) { - List groupIds = roles.stream().map(e -> String.valueOf(e.getRoleId())).collect(Collectors.toList()); + List groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId())); taskQuery.taskCandidateGroupIn(groupIds); } Task task = taskQuery.singleResult(); @@ -130,11 +133,11 @@ public class ActTaskServiceImpl implements IActTaskService { @Override public TableDataInfo getTaskWaitByPage(TaskBo taskBo) { List roles = LoginHelper.getLoginUser().getRoles(); - String userId = LoginHelper.getUserId().toString(); + String userId = String.valueOf(LoginHelper.getUserId()); TaskQuery query = taskService.createTaskQuery(); query.taskTenantId(TenantHelper.getTenantId()).taskCandidateOrAssigned(userId); if (CollUtil.isNotEmpty(roles)) { - List groupIds = roles.stream().map(e -> String.valueOf(e.getRoleId())).collect(Collectors.toList()); + List groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId())); query.taskCandidateGroupIn(groupIds); } if (StringUtils.isNotBlank(taskBo.getName())) { @@ -156,7 +159,7 @@ public class ActTaskServiceImpl implements IActTaskService { */ @Override public TableDataInfo getTaskFinishByPage(TaskBo taskBo) { - String userId = LoginHelper.getUserId().toString(); + String userId = String.valueOf(LoginHelper.getUserId()); HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery() .taskAssignee(userId).taskTenantId(TenantHelper.getTenantId()).finished().orderByHistoricTaskInstanceStartTime().asc(); if (StringUtils.isNotBlank(taskBo.getName())) { @@ -170,4 +173,74 @@ public class ActTaskServiceImpl implements IActTaskService { long count = query.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 list = taskService.createTaskQuery().taskTenantId(TenantHelper.getTenantId()) + .processInstanceId(task.getProcessInstanceId()).list(); + if (CollectionUtil.isNotEmpty(list)) { + List 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()); + } + } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java index ac52c8b00..7ee631121 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java @@ -2,12 +2,19 @@ package org.dromara.workflow.utils; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.ObjectUtil; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import org.dromara.common.core.utils.SpringUtils; 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.model.*; 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.XMLStreamException; @@ -16,6 +23,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.rmi.ServerException; import java.util.Collection; +import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -29,6 +38,8 @@ public class WorkflowUtils { public WorkflowUtils() { } + private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); + /** * bpmnModel转为xml * @@ -118,4 +129,28 @@ public class WorkflowUtils { 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; + } }