From 5360ec6ec3bf356a554df624e884a0bb1090fa4b Mon Sep 17 00:00:00 2001 From: gssong <1742057357@qq.com> Date: 星期日, 17 三月 2024 18:25:20 +0800 Subject: [PATCH] add 添加节点审批记录,调整流程驳回 --- ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java | 65 ++++++++ ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java | 12 + ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java | 13 + ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java | 5 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java | 1 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java | 141 +++++++++++++++++ ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java | 10 + ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java | 61 +++++++ ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java | 84 +++++----- ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml | 7 script/sql/flowable.sql | 20 ++ ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java | 9 - 12 files changed, 373 insertions(+), 55 deletions(-) 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 1e9d79b..77996ae 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 @@ -99,4 +99,14 @@ * 妯″瀷鏍囪瘑key鍛藉悕瑙勮寖姝e垯琛ㄨ揪寮� */ String MODEL_KEY_PATTERN = "^[a-zA-Z][a-zA-Z0-9_]{0,254}$"; + + /** + * 鐢ㄦ埛浠诲姟 + */ + String USER_TASK = "userTask"; + + /** + * 浼氱 + */ + String MULTI_INSTANCE = "multiInstance"; } 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 9f50cdc..d494959 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 cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; @@ -12,10 +13,12 @@ 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.WfTaskBackNode; import org.dromara.workflow.domain.bo.*; import org.dromara.workflow.domain.vo.TaskVo; import org.dromara.workflow.domain.vo.VariableVo; import org.dromara.workflow.service.IActTaskService; +import org.dromara.workflow.service.IWfTaskBackNodeService; import org.dromara.workflow.utils.QueryUtils; import org.flowable.engine.TaskService; import org.springframework.validation.annotation.Validated; @@ -23,7 +26,6 @@ import java.util.List; import java.util.Map; -import java.util.Set; /** * 浠诲姟绠$悊 鎺у埗灞� @@ -39,6 +41,8 @@ private final IActTaskService actTaskService; private final TaskService taskService; + + private final IWfTaskBackNodeService iWfTaskBackNodeService; /** @@ -220,7 +224,7 @@ @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping("/backProcess") - public R<String> backProcess(@RequestBody BackProcessBo backProcessBo) { + public R<String> backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo backProcessBo) { return R.ok(actTaskService.backProcess(backProcessBo)); } @@ -264,7 +268,7 @@ * @param processInstanceId 娴佺▼瀹炰緥id */ @GetMapping("/getTaskNodeList/{processInstanceId}") - public R<Set<TaskVo>> getNodeList(@PathVariable String processInstanceId) { - return R.ok(actTaskService.getTaskNodeList(processInstanceId)); + public R<List<WfTaskBackNode>> getNodeList(@PathVariable String processInstanceId) { + return R.ok(CollUtil.reverse(iWfTaskBackNodeService.getListByInstanceId(processInstanceId))); } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java new file mode 100644 index 0000000..6f59727 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java @@ -0,0 +1,61 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 鑺傜偣椹冲洖璁板綍 wf_task_back_node + * + * @author may + * @date 2024-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("wf_task_back_node") +public class WfTaskBackNode extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 涓婚敭 + */ + @TableId(value = "id") + private Long id; + + /** + * 瀹炰緥id + */ + private String instanceId; + + /** + * 鑺傜偣id + */ + private String nodeId; + + /** + * 鑺傜偣鍚嶇О + */ + private String nodeName; + + /** + * 鎺掑簭 + */ + private Integer orderNo; + + /** + * 鑺傜偣绫诲瀷 + */ + private String taskType; + + /** + * 鍔炵悊浜� + */ + private String assignee; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java index 7ac6b38..d0f4369 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java @@ -34,6 +34,7 @@ /** * 椹冲洖鐨勮妭鐐筰d(鐩墠鏈娇鐢紝鐩存帴椹冲洖鍒扮敵璇蜂汉) */ + @NotBlank(message = "椹冲洖鐨勮妭鐐逛笉鑳戒负绌�", groups = AddGroup.class) private String targetActivityId; /** diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java new file mode 100644 index 0000000..9b291fe --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java @@ -0,0 +1,13 @@ +package org.dromara.workflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.WfTaskBackNode; + +/** + * 鑺傜偣椹冲洖璁板綍Mapper鎺ュ彛 + * + * @author may + * @date 2024-03-13 + */ +public interface WfTaskBackNodeMapper extends BaseMapperPlus<WfTaskBackNode, WfTaskBackNode> { +} 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 72a5ea1..45c3de2 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 @@ -8,7 +8,6 @@ import java.util.List; import java.util.Map; -import java.util.Set; /** * 浠诲姟 鏈嶅姟灞� @@ -143,12 +142,4 @@ * @return 缁撴灉 */ List<VariableVo> getInstanceVariable(String taskId); - - /** - * 鑾峰彇鍙┏鍥炲緱浠诲姟鑺傜偣 - * - * @param processInstanceId 娴佺▼瀹炰緥id - * @return 缁撴灉 - */ - Set<TaskVo> getTaskNodeList(String processInstanceId); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java new file mode 100644 index 0000000..97f9406 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java @@ -0,0 +1,65 @@ +package org.dromara.workflow.service; + + +import org.dromara.workflow.domain.WfTaskBackNode; +import org.flowable.task.api.Task; + +import java.util.List; + +/** + * 鑺傜偣椹冲洖璁板綍Service鎺ュ彛 + * + * @author may + * @date 2024-03-13 + */ +public interface IWfTaskBackNodeService { + + /** + * 璁板綍瀹℃壒鑺傜偣 + * + * @param task 浠诲姟 + */ + void recordExecuteNode(Task task); + + /** + * 鎸夋祦绋嬪疄渚媔d鏌ヨ + * + * @param processInstanceId 娴佺▼瀹炰緥id + * @return 缁撴灉 + */ + List<WfTaskBackNode> getListByInstanceId(String processInstanceId); + + /** + * 鎸夌収娴佺▼瀹炰緥id锛岃妭鐐筰d鏌ヨ + * + * @param processInstanceId 娴佺▼瀹炰緥id + * @param nodeId 鑺傜偣id + * @return 缁撴灉 + */ + WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId); + + /** + * 鍒犻櫎椹冲洖鍚庣殑鑺傜偣 + * + * @param processInstanceId 娴佺▼瀹炰緥id + * @param targetActivityId 鑺傜偣id + * @return 缁撴灉 + */ + boolean deleteBackTaskNode(String processInstanceId, String targetActivityId); + + /** + * 鎸夋祦绋嬪疄渚媔d鍒犻櫎 + * + * @param processInstanceId 娴佺▼瀹炰緥id + * @return 缁撴灉 + */ + boolean deleteByInstanceId(String processInstanceId); + + /** + * 鎸夋祦绋嬪疄渚媔d鍒犻櫎 + * + * @param processInstanceIds 娴佺▼瀹炰緥id + * @return 缁撴灉 + */ + boolean deleteByInstanceIds(List<String> processInstanceIds); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java index 3f8678a..f4e8df2 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java @@ -32,6 +32,7 @@ import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler; import org.dromara.workflow.service.IActHiProcinstService; import org.dromara.workflow.service.IActProcessInstanceService; +import org.dromara.workflow.service.IWfTaskBackNodeService; import org.dromara.workflow.utils.QueryUtils; import org.dromara.workflow.utils.WorkflowUtils; import org.flowable.bpmn.model.*; @@ -77,6 +78,7 @@ private final IActHiProcinstService actHiProcinstService; private final ManagementService managementService; private final FlowEventStrategy flowEventStrategy; + private final IWfTaskBackNodeService iWfTaskBackNodeService; @Value("${flowable.activity-font-name}") private String activityFontName; @@ -500,6 +502,7 @@ if (ObjectUtil.isNotEmpty(historicProcessInstanceList)) { historyService.bulkDeleteHistoricProcessInstances(processInstanceIds); } + iWfTaskBackNodeService.deleteByInstanceIds(processInstanceIds); return true; } catch (Exception e) { e.printStackTrace(); @@ -534,6 +537,7 @@ if (ObjectUtil.isNotEmpty(historicProcessInstanceList)) { historyService.bulkDeleteHistoricProcessInstances(processInstanceIds); } + iWfTaskBackNodeService.deleteByInstanceIds(processInstanceIds); return true; } catch (Exception e) { e.printStackTrace(); @@ -551,6 +555,7 @@ public boolean deleteFinishAndHisInstance(List<String> processInstanceIds) { try { historyService.bulkDeleteHistoricProcessInstances(processInstanceIds); + iWfTaskBackNodeService.deleteByInstanceIds(processInstanceIds); return true; } catch (Exception e) { e.printStackTrace(); 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 b623eab..d35e930 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 @@ -19,6 +19,8 @@ import org.dromara.workflow.common.constant.FlowConstant; import org.dromara.workflow.common.enums.BusinessStatusEnum; import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.ActHiTaskinst; +import org.dromara.workflow.domain.WfTaskBackNode; import org.dromara.workflow.domain.bo.*; import org.dromara.workflow.domain.vo.MultiInstanceVo; import org.dromara.workflow.domain.vo.TaskVo; @@ -28,8 +30,10 @@ import org.dromara.workflow.flowable.strategy.FlowEventStrategy; import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler; import org.dromara.workflow.flowable.strategy.FlowTaskEventHandler; +import org.dromara.workflow.mapper.ActHiTaskinstMapper; import org.dromara.workflow.mapper.ActTaskMapper; import org.dromara.workflow.service.IActTaskService; +import org.dromara.workflow.service.IWfTaskBackNodeService; import org.dromara.workflow.utils.QueryUtils; import org.dromara.workflow.utils.WorkflowUtils; import org.flowable.common.engine.api.FlowableObjectNotFoundException; @@ -71,6 +75,8 @@ private final ManagementService managementService; private final FlowEventStrategy flowEventStrategy; private final ActTaskMapper actTaskMapper; + private final IWfTaskBackNodeService iWfTaskBackNodeService; + private final ActHiTaskinstMapper actHiTaskinstMapper; /** * 鍚姩浠诲姟 @@ -187,12 +193,14 @@ //鍔炵悊鎰忚 taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "鍚屾剰" : completeTaskBo.getMessage()); //鍔炵悊浠诲姟 - taskService.setAssignee(task.getId(),userId); + taskService.setAssignee(task.getId(), userId); if (CollUtil.isNotEmpty(completeTaskBo.getVariables())) { taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables()); } else { taskService.complete(completeTaskBo.getTaskId()); } + //璁板綍鎵ц杩囩殑娴佺▼浠诲姟鑺傜偣 + iWfTaskBackNodeService.recordExecuteNode(task); ProcessInstance pi = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult(); if (pi == null) { UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus()); @@ -204,8 +212,7 @@ List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(completeTaskBo.getWfCopyList())) { TaskEntity newTask = WorkflowUtils.createNewTask(task); - taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), - LoginHelper.getLoginUser().getNickname() + "銆愭妱閫併�戠粰" + String.join(",", StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserName))); + taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), LoginHelper.getLoginUser().getNickname() + "銆愭妱閫併�戠粰" + String.join(",", StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserName))); taskService.complete(newTask.getId()); List<Task> taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); WorkflowUtils.createCopyTask(taskList, StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserId)); @@ -244,12 +251,7 @@ String userId = String.valueOf(LoginHelper.getUserId()); queryWrapper.eq("t.business_status_", BusinessStatusEnum.WAITING.getStatus()); queryWrapper.eq(TenantHelper.isEnable(), "t.tenant_id_", TenantHelper.getTenantId()); - queryWrapper.and(w1 -> - w1.eq("t.assignee_", userId) - .or(w2 -> w2.isNull("t.assignee_") - .apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' " + - "and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN " + getInParam(roleIds) + " ) ))", userId)) - ); + queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' " + "and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN " + getInParam(roleIds) + " ) ))", userId))); if (StringUtils.isNotBlank(taskBo.getName())) { queryWrapper.like("t.name_", taskBo.getName()); } @@ -444,8 +446,7 @@ if (task.isSuspended()) { throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); } - HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery() - .processInstanceId(task.getProcessInstanceId()).singleResult(); + HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus()); try { if (StringUtils.isBlank(terminationBo.getComment())) { @@ -480,8 +481,7 @@ */ @Override public boolean transferTask(TransmitBo transmitBo) { - Task task = QueryUtils.taskQuery().taskId(transmitBo.getTaskId()) - .taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult(); + Task task = QueryUtils.taskQuery().taskId(transmitBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult(); if (ObjectUtil.isEmpty(task)) { throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); } @@ -607,7 +607,8 @@ @Transactional(rollbackFor = Exception.class) public String backProcess(BackProcessBo backProcessBo) { TaskQuery query = QueryUtils.taskQuery(); - Task task = query.taskId(backProcessBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult(); + String userId = String.valueOf(LoginHelper.getUserId()); + Task task = query.taskId(backProcessBo.getTaskId()).taskCandidateOrAssigned(userId).singleResult(); if (ObjectUtil.isEmpty(task)) { throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); } @@ -624,20 +625,33 @@ BusinessStatusEnum.checkBackStatus(processInstance.getBusinessStatus()); //鍒ゆ柇鏄惁鏈夊涓换鍔� List<Task> taskList = QueryUtils.taskQuery(processInstanceId).list(); - //鐢宠浜鸿妭鐐� - HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().asc().list().get(0); - String backTaskDefinitionKey = historicTaskInstance.getTaskDefinitionKey(); + String backTaskDefinitionKey = backProcessBo.getTargetActivityId(); taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.BACK.getStatus(), StringUtils.isNotBlank(backProcessBo.getMessage()) ? backProcessBo.getMessage() : "閫�鍥�"); if (taskList.size() > 1) { //褰撳墠澶氫釜浠诲姟椹冲洖鍒板崟涓妭鐐� runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdsToSingleActivityId(taskList.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList()), backTaskDefinitionKey).changeState(); + ActHiTaskinst actHiTaskinst = new ActHiTaskinst(); + actHiTaskinst.setAssignee(userId); + actHiTaskinst.setId(task.getId()); + actHiTaskinstMapper.updateById(actHiTaskinst); } else { //褰撳墠鍗曚釜鑺傜偣椹冲洖鍗曚釜鑺傜偣 runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdTo(task.getTaskDefinitionKey(), backTaskDefinitionKey).changeState(); } + //鍒犻櫎骞惰鐜妭鏈姙鐞嗚褰� + MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); + if (multiInstance == null && taskList.size() > 1) { + List<Task> tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey())); + actHiTaskinstMapper.deleteBatchIds(StreamUtils.toList(tasks, Task::getId)); + } + + + List<HistoricTaskInstance> instanceList = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().desc().list(); List<Task> list = QueryUtils.taskQuery(processInstanceId).list(); for (Task t : list) { - taskService.setAssignee(t.getId(), historicTaskInstance.getAssignee()); + instanceList.stream().filter(e -> e.getTaskDefinitionKey().equals(t.getTaskDefinitionKey())).findFirst().ifPresent(e -> { + taskService.setAssignee(t.getId(), e.getAssignee()); + }); } //鍙戦�佹秷鎭� String message = "鎮ㄧ殑銆�" + processInstance.getName() + "銆戝崟鎹凡缁忚椹冲洖锛岃鎮ㄦ敞鎰忔煡鏀躲��"; @@ -647,11 +661,17 @@ DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId()); managementService.executeCommand(deleteExecutionCmd); } - runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus()); - FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey()); - if (processHandler != null) { - processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false); + + WfTaskBackNode wfTaskBackNode = iWfTaskBackNodeService.getListByInstanceIdAndNodeId(task.getProcessInstanceId(), backProcessBo.getTargetActivityId()); + if (ObjectUtil.isNotNull(wfTaskBackNode) && wfTaskBackNode.getOrderNo() == 0) { + runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus()); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey()); + if (processHandler != null) { + processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false); + } } + //鍒犻櫎椹冲洖鍚庣殑娴佺▼鑺傜偣 + iWfTaskBackNodeService.deleteBackTaskNode(processInstanceId, backProcessBo.getTargetActivityId()); } catch (Exception e) { throw new ServiceException(e.getMessage()); } @@ -696,25 +716,5 @@ } } return variableVoList; - } - - /** - * 鑾峰彇鍙┏鍥炲緱浠诲姟鑺傜偣 - * - * @param processInstanceId 娴佺▼瀹炰緥id - */ - @Override - public Set<TaskVo> getTaskNodeList(String processInstanceId) { - Set<TaskVo> list = new HashSet<>(); - List<HistoricTaskInstance> historicTaskInstances = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list(); - for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) { - if (historicTaskInstance.getEndTime() != null) { - TaskVo taskVo = new TaskVo(); - taskVo.setName(historicTaskInstance.getName()); - taskVo.setTaskDefinitionKey(historicTaskInstance.getTaskDefinitionKey()); - list.add(taskVo); - } - } - return list; } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java new file mode 100644 index 0000000..b656429 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java @@ -0,0 +1,141 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.workflow.domain.WfTaskBackNode; +import org.dromara.workflow.domain.vo.MultiInstanceVo; +import org.dromara.workflow.mapper.WfTaskBackNodeMapper; +import org.dromara.workflow.service.IWfTaskBackNodeService; +import org.dromara.workflow.utils.WorkflowUtils; +import org.flowable.task.api.Task; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +import static org.dromara.workflow.common.constant.FlowConstant.MULTI_INSTANCE; +import static org.dromara.workflow.common.constant.FlowConstant.USER_TASK; + + +/** + * 鑺傜偣椹冲洖璁板綍Service涓氬姟灞傚鐞� + * + * @author may + * @date 2024-03-13 + */ +@RequiredArgsConstructor +@Service +public class WfTaskBackNodeServiceImpl implements IWfTaskBackNodeService { + + private final WfTaskBackNodeMapper wfTaskBackNodeMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void recordExecuteNode(Task task) { + List<WfTaskBackNode> list = getListByInstanceId(task.getProcessInstanceId()); + WfTaskBackNode wfTaskBackNode = new WfTaskBackNode(); + wfTaskBackNode.setNodeId(task.getTaskDefinitionKey()); + wfTaskBackNode.setNodeName(task.getName()); + wfTaskBackNode.setInstanceId(task.getProcessInstanceId()); + wfTaskBackNode.setAssignee(String.valueOf(LoginHelper.getUserId())); + MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); + if (ObjectUtil.isNotEmpty(multiInstance)) { + wfTaskBackNode.setTaskType(MULTI_INSTANCE); + } else { + wfTaskBackNode.setTaskType(USER_TASK); + } + if (CollectionUtil.isEmpty(list)) { + wfTaskBackNode.setOrderNo(0); + wfTaskBackNodeMapper.insert(wfTaskBackNode); + } else { + WfTaskBackNode taskNode = list.stream().filter(e -> e.getNodeId().equals(wfTaskBackNode.getNodeId()) && e.getOrderNo() == 0).findFirst().orElse(null); + if (ObjectUtil.isEmpty(taskNode)) { + wfTaskBackNode.setOrderNo(list.get(0).getOrderNo() + 1); + WfTaskBackNode node = getListByInstanceIdAndNodeId(wfTaskBackNode.getInstanceId(), wfTaskBackNode.getNodeId()); + if (ObjectUtil.isNotEmpty(node)) { + node.setAssignee(node.getAssignee() + StringUtils.SEPARATOR + LoginHelper.getUserId()); + wfTaskBackNodeMapper.updateById(node); + } else { + wfTaskBackNodeMapper.insert(wfTaskBackNode); + } + } + } + } + + @Override + public List<WfTaskBackNode> getListByInstanceId(String processInstanceId) { + LambdaQueryWrapper<WfTaskBackNode> wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); + wrapper.orderByDesc(WfTaskBackNode::getOrderNo); + return wfTaskBackNodeMapper.selectList(wrapper); + } + + @Override + public WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId) { + LambdaQueryWrapper<WfTaskBackNode> queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); + queryWrapper.eq(WfTaskBackNode::getNodeId, nodeId); + return wfTaskBackNodeMapper.selectOne(queryWrapper); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteBackTaskNode(String processInstanceId, String targetActivityId) { + try { + LambdaQueryWrapper<WfTaskBackNode> queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); + queryWrapper.eq(WfTaskBackNode::getNodeId, targetActivityId); + WfTaskBackNode actTaskNode = wfTaskBackNodeMapper.selectOne(queryWrapper); + if (ObjectUtil.isNotNull(actTaskNode)) { + Integer orderNo = actTaskNode.getOrderNo(); + List<WfTaskBackNode> taskNodeList = getListByInstanceId(processInstanceId); + List<Long> ids = new ArrayList<>(); + if (CollectionUtil.isNotEmpty(taskNodeList)) { + for (WfTaskBackNode taskNode : taskNodeList) { + if (taskNode.getOrderNo() >= orderNo) { + ids.add(taskNode.getId()); + } + } + } + if (CollectionUtil.isNotEmpty(ids)) { + wfTaskBackNodeMapper.deleteBatchIds(ids); + } + } + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("鍒犻櫎澶辫触"); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteByInstanceId(String processInstanceId) { + LambdaQueryWrapper<WfTaskBackNode> wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); + List<WfTaskBackNode> list = wfTaskBackNodeMapper.selectList(wrapper); + int delete = wfTaskBackNodeMapper.delete(wrapper); + if (list.size() != delete) { + throw new ServiceException("鍒犻櫎澶辫触"); + } + return true; + } + + @Override + public boolean deleteByInstanceIds(List<String> processInstanceIds) { + LambdaQueryWrapper<WfTaskBackNode> wrapper = new LambdaQueryWrapper<>(); + wrapper.in(WfTaskBackNode::getInstanceId, processInstanceIds); + List<WfTaskBackNode> list = wfTaskBackNodeMapper.selectList(wrapper); + int delete = wfTaskBackNodeMapper.delete(wrapper); + if (list.size() != delete) { + throw new ServiceException("鍒犻櫎澶辫触"); + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml new file mode 100644 index 0000000..4a9179b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper + PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="org.dromara.workflow.mapper.WfTaskBackNodeMapper"> + +</mapper> diff --git a/script/sql/flowable.sql b/script/sql/flowable.sql index b7149e5..7eb8d6b 100644 --- a/script/sql/flowable.sql +++ b/script/sql/flowable.sql @@ -58,6 +58,26 @@ ) engine=innodb comment= '娴佺▼鍒嗙被'; INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, sysdate(), 1, sysdate()); +DROP TABLE if EXISTS wf_task_back_node; +create table wf_task_back_node +( + id varchar(255) not null + primary key, + node_id varchar(255) not null comment '鑺傜偣id', + node_name varchar(255) not null comment '鑺傜偣鍚嶇О', + order_no int not null comment '鎺掑簭', + instance_id varchar(255) null comment '娴佺▼瀹炰緥id', + task_type varchar(255) not null comment '鑺傜偣绫诲瀷', + assignee varchar(2000) not null comment '瀹℃壒浜�', + tenant_id varchar(20) default '000000' null comment '绉熸埛缂栧彿', + create_dept bigint null comment '鍒涘缓閮ㄩ棬', + create_by bigint null comment '鍒涘缓鑰�', + create_time datetime null comment '鍒涘缓鏃堕棿', + update_by bigint null comment '鏇存柊鑰�', + update_time datetime null comment '鏇存柊鏃堕棿' +) + comment '鑺傜偣瀹℃壒璁板綍'; + INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '璇峰亣鐢宠', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '璇峰亣鐢宠鑿滃崟'); INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, sysdate(), NULL, NULL, ''); -- Gitblit v1.9.3