business/src/main/java/com/ycl/controller/FlowTaskController.java
@@ -5,6 +5,7 @@ import com.ycl.common.core.domain.AjaxResult; import com.ycl.common.enums.BusinessType; import com.ycl.domain.dto.FlowTaskDto; import com.ycl.domain.form.EditFinishedTaskForm; import com.ycl.domain.vo.FlowQueryVo; import com.ycl.domain.vo.FlowTaskVo; import com.ycl.domain.vo.FormDetailVO; @@ -126,6 +127,7 @@ public AjaxResult complete(@RequestBody FlowTaskVo flowTaskVo) { return flowTaskService.complete(flowTaskVo); } @ApiOperation(value = "驳回任务") @Log(title = "驳回任务", businessType = BusinessType.UPDATE) @@ -275,7 +277,7 @@ } /** * 流程节点表单 * 流程节点表单-当前任务及前置任务 * * @param taskId 流程任务编号 * @return @@ -285,6 +287,17 @@ return flowTaskService.flowTaskForm(taskId); } /** * 流程节点表单-当前任务 * * @param taskId 流程任务编号 * @return */ @GetMapping("/current/flowTaskForm") public AjaxResult currentFlowTaskForm(@RequestParam(value = "taskId", required = false) String taskId) { return flowTaskService.currentFlowTaskForm(taskId); } /** * 流程节点信息 business/src/main/java/com/ycl/controller/ProjectProcessController.java
@@ -1,5 +1,8 @@ package com.ycl.controller; import com.ycl.common.annotation.Log; import com.ycl.common.core.domain.AjaxResult; import com.ycl.common.enums.BusinessType; import com.ycl.common.group.Update; import com.ycl.common.group.Add; import com.ycl.domain.form.*; @@ -156,4 +159,11 @@ public Result cancelTaskHangup(@Validated @RequestBody TaskHangupForm form) { return projectProcessService.cancelTaskHangup(form); } @ApiOperation(value = "修改已完成任务") @Log(title = "修改已完成任务", businessType = BusinessType.UPDATE) @PostMapping(value = "/admin/edit/finish/task") public Result editFinishedTask(@RequestBody EditFinishedTaskForm form) { return projectProcessService.editFinishedTask(form); } } business/src/main/java/com/ycl/domain/form/EditFinishedTaskForm.java
New file @@ -0,0 +1,41 @@ package com.ycl.domain.form; import com.ycl.common.enums.business.TaskStatusEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.List; import java.util.Map; /** * <p>流程任务<p> * * @author Tony * @date 2021-04-03 */ @Data @ApiModel("工作流任务相关--请求参数") public class EditFinishedTaskForm { @ApiModelProperty("当前任务Id") private String taskId; @ApiModelProperty("用户Id") private String userId; @ApiModelProperty("流程变量信息") private Map<String, Object> variables; @ApiModelProperty("原先的任务状态") private TaskStatusEnum originalStatus; @ApiModelProperty("现在的任务状态") private TaskStatusEnum nowStatus; @ApiModelProperty("跳过") private TaskJumpForm taskJumpForm; @ApiModelProperty("容缺") private TaskWaitForm taskWaitForm; } business/src/main/java/com/ycl/mapper/ProjectProcessMapper.java
@@ -83,4 +83,26 @@ * @param objectToBytes */ void insertByteArray(@Param("id_") String bytearray_id_, @Param("rev_") int rev_, @Param("name_") String name_, @Param("bytes_") Object objectToBytes); /** * 删除二进制变量 * * @param id */ void deleteByteArray(@Param("id") String id); /** * 删除运行时的flowable变量 * * @param id */ void deleteRunFlowableVar(@Param("id") String id); /** * 删除历史的flowable变量 * * @param id */ void deleteHisFlowableVar(@Param("id") String id); } business/src/main/java/com/ycl/service/IFlowTaskService.java
@@ -1,6 +1,7 @@ package com.ycl.service; import com.ycl.common.core.domain.AjaxResult; import com.ycl.domain.form.EditFinishedTaskForm; import com.ycl.domain.vo.FlowQueryVo; import com.ycl.domain.vo.FlowTaskVo; @@ -207,6 +208,14 @@ */ AjaxResult flowTaskForm(String taskId) throws Exception; /** * 当前任务的表单数据 * * @param taskId * @return */ AjaxResult currentFlowTaskForm(String taskId); /** * 流程节点信息 @@ -237,4 +246,5 @@ * @return */ AjaxResult detail(String processInsId, String taskId); } business/src/main/java/com/ycl/service/ProjectProcessService.java
@@ -1,5 +1,6 @@ package com.ycl.service; import com.ycl.common.core.domain.AjaxResult; import com.ycl.common.core.domain.R; import com.ycl.domain.entity.ProjectProcess; import com.baomidou.mybatisplus.extension.service.IService; @@ -157,4 +158,12 @@ * @param result */ void getIndexWaitTask(String s, int pageSize, int currentPage, Result result); /** * 修改已完成的任务 * * @param vo * @return */ Result editFinishedTask(EditFinishedTaskForm vo); } business/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java
@@ -28,6 +28,7 @@ import com.ycl.domain.entity.ProcessLog; import com.ycl.domain.entity.ProjectProcess; import com.ycl.domain.entity.SysForm; import com.ycl.domain.form.EditFinishedTaskForm; import com.ycl.domain.json.RejectData; import com.ycl.domain.query.ProcessLogQuery; import com.ycl.domain.vo.*; @@ -190,6 +191,7 @@ } return AjaxResult.success("提交成功"); } /** * 容缺补交 @@ -1411,6 +1413,58 @@ } /** * 查询当前任务的表单数据 * * @param taskId * @return * @throws Exception */ @Override public AjaxResult currentFlowTaskForm(String taskId) { // 流程变量 List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery() .includeProcessVariables() .finished() .taskId(taskId) .orderByHistoricTaskInstanceStartTime() .desc() .list(); if (CollectionUtils.isEmpty(hisTaskList) || Objects.isNull(hisTaskList.get(0))) { return AjaxResult.error("未找到该任务信息"); } HistoricTaskInstance historicTaskInstance = hisTaskList.get(0); Map<String, Object> parameters = historicTaskInstance.getProcessVariables(); String processInsId = historicTaskInstance.getProcessInstanceId(); List<FormDetailVO> beforeNodes = this.getBeforeNodeForm(parameters, historicTaskInstance.getFormKey(), historicTaskInstance.getName(), historicTaskInstance.getProcessDefinitionId(), historicTaskInstance.getTaskDefinitionKey(), Boolean.FALSE); // 判断前置任务是不是和当前任务为同一个executeId // 判断当前任务是否被挂起中 String finalProcessInsId = processInsId; List<DoFormDetailVO> vos = beforeNodes.stream() .filter(FormDetailVO::getCurrent) .map(node -> { if (node.getCurrent()) { if (processLogService.taskIsHangup(taskId, finalProcessInsId)) { node.setTaskStatus(TaskStatusEnum.HANGUP); } } // 判断任务是否存在特殊操作(如跳过、转办等),需要在前端展示出来 ProcessLogQuery query = new ProcessLogQuery(); query.setTaskId(node.getTaskId()); query.setProcessInsId(finalProcessInsId); Result result = processLogService.projectProcessLogList(query); List<ProcessLogVO> logList = (List<ProcessLogVO>) result.get("data"); DoFormDetailVO vo = new DoFormDetailVO(); BeanUtils.copyProperties(node, vo); if (CollectionUtils.isNotEmpty(logList)) { vo.setEvents(logList); } return vo; }).collect(Collectors.toList()); return AjaxResult.success(vos.get(0)); } /** * 流程节点表单 * * @param taskId 流程任务编号 @@ -1423,11 +1477,17 @@ Map<String, Object> parameters = new HashMap<>(); List<FormDetailVO> beforeNodes = new ArrayList<>(); String processInsId = ""; HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().includeProcessVariables().finished().taskId(taskId).singleResult(); if (Objects.nonNull(historicTaskInstance)) { parameters = historicTaskInstance.getProcessVariables(); processInsId = historicTaskInstance.getProcessInstanceId(); beforeNodes = this.getBeforeNodeForm(parameters, historicTaskInstance.getFormKey(), historicTaskInstance.getName(), historicTaskInstance.getProcessDefinitionId(), historicTaskInstance.getTaskDefinitionKey(), Boolean.FALSE); List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery() .includeProcessVariables() .finished() .taskId(taskId) .orderByHistoricTaskInstanceStartTime() .desc() .list(); if (CollectionUtils.isNotEmpty(hisTaskList) && Objects.nonNull(hisTaskList.get(0))) { parameters = hisTaskList.get(0).getProcessVariables(); processInsId = hisTaskList.get(0).getProcessInstanceId(); beforeNodes = this.getBeforeNodeForm(parameters, hisTaskList.get(0).getFormKey(), hisTaskList.get(0).getName(), hisTaskList.get(0).getProcessDefinitionId(), hisTaskList.get(0).getTaskDefinitionKey(), Boolean.FALSE); } else { parameters = taskService.getVariables(taskId); processInsId = task.getProcessInstanceId(); @@ -1717,6 +1777,7 @@ return beforeNodes; } /** * 流程节点信息 * business/src/main/java/com/ycl/service/impl/ProjectProcessServiceImpl.java
@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; import com.ycl.common.constant.ProcessConstants; import com.ycl.common.constant.ProcessOverTimeConstants; import com.ycl.common.core.domain.AjaxResult; import com.ycl.common.core.domain.entity.SysDept; import com.ycl.common.core.domain.entity.SysDictData; import com.ycl.common.core.domain.entity.SysRole; @@ -40,6 +41,7 @@ import org.apache.commons.lang3.StringUtils; import org.flowable.bpmn.model.*; import org.flowable.bpmn.model.Process; import org.flowable.common.engine.impl.persistence.StrongUuidGenerator; import org.flowable.common.engine.impl.util.CollectionUtil; import org.flowable.engine.*; import org.flowable.engine.history.HistoricProcessInstance; @@ -53,6 +55,7 @@ import org.flowable.task.api.TaskQuery; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.springframework.beans.BeanUtils; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -2929,4 +2932,207 @@ private List<Task> getCurrentNodeTaskList(String processInstanceId) { return taskService.createTaskQuery().processDefinitionId(processInstanceId).list(); } @Override @Transactional(rollbackFor = Exception.class) public Result editFinishedTask(EditFinishedTaskForm form) { List<HistoricTaskInstance> hisTasks = historyService.createHistoricTaskInstanceQuery().taskId(form.getTaskId()).orderByHistoricTaskInstanceStartTime().desc().list(); if (org.apache.commons.collections4.CollectionUtils.isEmpty(hisTasks) || Objects.isNull(hisTasks.get(0))) { return Result.error("任务不存在"); } HistoricTaskInstance task = hisTasks.get(0); ProjectProcess projectProcess = new LambdaQueryChainWrapper<>(projectProcessMapper) .eq(ProjectProcess::getProcessInsId, task.getProcessInstanceId()) .eq(ProjectProcess::getProcessDefId, task.getProcessDefinitionId()) .one(); if (Objects.isNull(projectProcess)) { return Result.error("项目流程未绑定"); } // 查出字典中需要注入的字段信息 List<String> dictList = dictTypeService.selectDictDataByType("flow_variables").stream().map(SysDictData::getDictValue).collect(Collectors.toList()); Map<String, Object> newV = new HashMap<>(2); if (!org.springframework.util.CollectionUtils.isEmpty(form.getVariables())) { for (String key : form.getVariables().keySet()) { newV.put(task.getTaskDefinitionKey() + "&" + key, form.getVariables().get(key)); // 字典里有就不做处理 if (!org.apache.commons.collections4.CollectionUtils.isEmpty(dictList) && dictList.contains(key)) { newV.put(key,form.getVariables().get(key)); } } } ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); Date now = new Date(); // 1. 表单变量替换 for (String key : newV.keySet()) { FlowableVarVO var = null; if (Objects.isNull(processInstance)) { // 查询历史流程变量 var = projectProcessMapper.getHisByteId(projectProcess.getProcessInsId(), key); } else { // 查询运行时流程变量 var = projectProcessMapper.getRuByteId(projectProcess.getProcessInsId(), key); } if (Objects.nonNull(var)) { // 先删除原来的变量,再把当前的保存进去 projectProcessMapper.deleteHisFlowableVar(var.getID_()); projectProcessMapper.deleteRunFlowableVar(var.getID_()); if (StringUtils.isNotBlank(var.getBYTEARRAY_ID_())) { projectProcessMapper.deleteByteArray(var.getID_()); } } // 保存当前的表单数据 FlowableVarVO run = new FlowableVarVO(); FlowableVarVO v = new FlowableVarVO(); v.setNAME_(key); v.setPROC_INST_ID_(task.getProcessInstanceId()); v.setEXECUTION_ID_(task.getProcessInstanceId()); v.setCREATE_TIME_(now); v.setLAST_UPDATED_TIME_(now); v.setID_(new StrongUuidGenerator().getNextId()); BeanUtils.copyProperties(v, run); run.setID_(new StrongUuidGenerator().getNextId()); if (newV.get(key) instanceof String) { v.setVAR_TYPE_("string"); v.setTEXT_((String) newV.get(key)); run.setVAR_TYPE_("string"); run.setTEXT_((String) newV.get(key)); } else if (newV.get(key) instanceof Integer) { v.setVAR_TYPE_("integer"); v.setLONG_((Long) newV.get(key)); v.setTEXT_((String) newV.get(key)); run.setVAR_TYPE_("integer"); run.setLONG_((Long) newV.get(key)); run.setTEXT_((String) newV.get(key)); } else if (newV.get(key) instanceof Long) { v.setVAR_TYPE_("long"); v.setLONG_((Long) newV.get(key)); v.setTEXT_((String) newV.get(key)); run.setVAR_TYPE_("long"); run.setLONG_((Long) newV.get(key)); run.setTEXT_((String) newV.get(key)); } else if (newV.get(key) instanceof Boolean) { v.setVAR_TYPE_("boolean"); v.setLONG_((Long) newV.get(key)); v.setTEXT_((String) newV.get(key)); run.setVAR_TYPE_("boolean"); run.setLONG_((Long) newV.get(key)); run.setTEXT_((String) newV.get(key)); } else { // 其它类型的表单数据:如图片、文件单独存表的。历史、运行中的流程需各存一份 v.setVAR_TYPE_("serializable"); v.setBYTEARRAY_ID_(new StrongUuidGenerator().getNextId()); projectProcessMapper.insertByteArray(v.getBYTEARRAY_ID_(), 1, "hist.var-" + key, newV.get(key)); run.setVAR_TYPE_("serializable"); run.setBYTEARRAY_ID_(new StrongUuidGenerator().getNextId()); projectProcessMapper.insertByteArray(run.getBYTEARRAY_ID_(), 1, "var-" + key, newV.get(key)); } projectProcessMapper.insertHisFlowableVar(v); projectProcessMapper.insertRunFlowableVar(run); } // 2. 任务状态调整:仅支持 已完成==》容缺/跳过 容缺《===》跳过 if (Objects.nonNull(form.getNowStatus()) && ! Objects.equals(form.getOriginalStatus(), form.getNowStatus())) { if (TaskStatusEnum.FINISHED.equals(form.getOriginalStatus())) { ProcessLog finishedLog = new LambdaQueryChainWrapper<>(processLogService.getBaseMapper()) .eq(ProcessLog::getTaskId, form.getTaskId()) .eq(ProcessLog::getEventType, ProcessLogEventTypeEnum.FINISHED) .one(); if (Objects.nonNull(finishedLog)) { if (TaskStatusEnum.JUMP.equals(form.getNowStatus())) { // 添加跳过日志 publisher.publishEvent(new TaskLogEvent(this, null, finishedLog.getUserId(), projectProcess.getProjectId(), projectProcess.getProcessInsId(), form.getTaskId(), task.getTaskDefinitionKey(), task.getName(), ProcessLogEventTypeEnum.JUMP, new JumpData(form.getTaskJumpForm().getDesc()))); // 删除原来的完成日志 processLogService.removeById(finishedLog.getId()); } else if (TaskStatusEnum.WAIT.equals(form.getNowStatus())) { // 添加容缺日志 publisher.publishEvent(new TaskLogEvent(this, null, finishedLog.getUserId(), projectProcess.getProjectId(), projectProcess.getProcessInsId(), form.getTaskId(), task.getTaskDefinitionKey(), task.getName(), ProcessLogEventTypeEnum.WAIT, new WaitData(form.getTaskWaitForm().getDesc()))); // 删除原来的完成日志 processLogService.removeById(finishedLog.getId()); } else { return Result.error("已完成任务只能调整为容缺或跳过状态"); } } } else if (TaskStatusEnum.WAIT.equals(form.getOriginalStatus())) { ProcessLog waitLog = new LambdaQueryChainWrapper<>(processLogService.getBaseMapper()) .eq(ProcessLog::getTaskId, form.getTaskId()) .eq(ProcessLog::getEventType, ProcessLogEventTypeEnum.WAIT) .one(); if (Objects.nonNull(waitLog)) { if (TaskStatusEnum.JUMP.equals(form.getNowStatus())) { // 添加跳过日志 publisher.publishEvent(new TaskLogEvent(this, null, waitLog.getUserId(), projectProcess.getProjectId(), projectProcess.getProcessInsId(), form.getTaskId(), task.getTaskDefinitionKey(), task.getName(), ProcessLogEventTypeEnum.JUMP, new JumpData(form.getTaskJumpForm().getDesc()))); // 删除原来的容缺日志 processLogService.removeById(waitLog.getId()); } else { return Result.error("容缺任务只能调整为跳过状态"); } } } else if (TaskStatusEnum.JUMP.equals(form.getOriginalStatus())) { ProcessLog jumpLog = new LambdaQueryChainWrapper<>(processLogService.getBaseMapper()) .eq(ProcessLog::getTaskId, form.getTaskId()) .eq(ProcessLog::getEventType, ProcessLogEventTypeEnum.JUMP) .one(); if (Objects.nonNull(jumpLog)) { if (TaskStatusEnum.WAIT.equals(form.getNowStatus())) { // 添加容缺日志 publisher.publishEvent(new TaskLogEvent(this, null, jumpLog.getUserId(), projectProcess.getProjectId(), projectProcess.getProcessInsId(), form.getTaskId(), task.getTaskDefinitionKey(), task.getName(), ProcessLogEventTypeEnum.WAIT, new WaitData(form.getTaskWaitForm().getDesc()))); // 删除原来的跳过日志 processLogService.removeById(jumpLog.getId()); } else { return Result.error("跳过任务只能调整为容缺任务"); } } } } // 3. 保存修改日志 publisher.publishEvent(new TaskLogEvent(this, null, SecurityUtils.getUserId(), projectProcess.getProjectId(), projectProcess.getProcessInsId(), form.getTaskId(), task.getTaskDefinitionKey(), task.getName(), ProcessLogEventTypeEnum.EDIT, null)); return Result.ok("修改成功"); } } business/src/main/resources/mapper/ProjectProcessMapper.xml
@@ -202,4 +202,16 @@ insert into act_ge_bytearray(ID_, REV_, NAME_, BYTES_) values (#{id_}, #{rev_}, #{name_}, #{bytes_, jdbcType=BLOB}) </insert> <delete id="deleteByteArray" parameterType="string"> DELETE FROM act_ge_bytearray WHERE ID_ = #{id} </delete> <delete id="deleteRunFlowableVar" parameterType="string"> DELETE FROM act_ru_variable WHERE ID_ = #{id} </delete> <delete id="deleteHisFlowableVar" parameterType="string"> DELETE FROM act_hi_varinst WHERE ID_ = #{id} </delete> </mapper> common/src/main/java/com/ycl/common/enums/business/ProcessLogEventTypeEnum.java
@@ -22,6 +22,7 @@ SUPERVISE("SUPERVISE", "督办"), HANGUP("HANGUP", "挂起"), CANCEL_HANGUP("CANCEL_HANGUP", "取消挂起"), EDIT("EDIT", "修改"), ;