feat(流程独立节点表单): 新增流程独立节点表单,可在用户任务节点配置表单(不兼容旧版本)

This commit is contained in:
konbai
2022-08-07 17:56:35 +08:00
parent 1ff440c235
commit b6c6813498
12 changed files with 443 additions and 86 deletions

View File

@@ -36,7 +36,7 @@ public class WfTaskBo {
private String targetKey;
@ApiModelProperty("流程变量信息")
private Map<String, Object> values;
private Map<String, Object> variables;
@ApiModelProperty("审批人")
private String assignee;

View File

@@ -0,0 +1,42 @@
package com.ruoyi.workflow.domain.vo;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.flowable.core.FormConf;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.util.List;
/**
* 流程详情视图对象
*
* @author KonBAI
* @createTime 2022/8/7 15:01
*/
@Data
@ApiModel("流程详情视图对象")
public class WfDetailVo {
/**
* 任务表单信息
*/
private FormConf taskFormData;
/**
* 历史任务信息
*/
private List<WfTaskVo> historyTaskList;
/**
* 流程表单列表
*/
private List<FormConf> processFormList;
/**
* 是否存在任务表单信息
* @return true:存在false:不存在
*/
public Boolean isExistTaskForm() {
return ObjectUtil.isNotEmpty(this.taskFormData);
}
}

View File

@@ -4,6 +4,7 @@ import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.workflow.domain.bo.WfProcessBo;
import com.ruoyi.workflow.domain.vo.WfDefinitionVo;
import com.ruoyi.workflow.domain.vo.WfDetailVo;
import com.ruoyi.workflow.domain.vo.WfTaskVo;
import java.util.Map;
@@ -42,6 +43,14 @@ public interface IWfProcessService {
*/
void startProcessByDefKey(String procDefKey, Map<String, Object> variables);
/**
* 查询流程任务详情信息
* @param procInsId 流程实例ID
* @param deployId 流程部署ID
* @param taskId 任务ID
*/
WfDetailVo queryProcessDetail(String procInsId, String deployId, String taskId);
/**
* 查询我的流程列表
* @param pageQuery 分页参数

View File

@@ -5,42 +5,58 @@ import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.flowable.common.constant.TaskConstants;
import com.ruoyi.flowable.core.FormConf;
import com.ruoyi.flowable.factory.FlowServiceFactory;
import com.ruoyi.flowable.utils.ModelUtils;
import com.ruoyi.flowable.utils.ProcessFormUtils;
import com.ruoyi.flowable.utils.TaskUtils;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.workflow.domain.WfDeployForm;
import com.ruoyi.workflow.domain.bo.WfProcessBo;
import com.ruoyi.workflow.domain.vo.WfDefinitionVo;
import com.ruoyi.workflow.domain.vo.WfDeployFormVo;
import com.ruoyi.workflow.domain.vo.WfDetailVo;
import com.ruoyi.workflow.domain.vo.WfTaskVo;
import com.ruoyi.workflow.mapper.WfDeployFormMapper;
import com.ruoyi.workflow.service.IWfProcessService;
import com.ruoyi.workflow.service.IWfTaskService;
import lombok.RequiredArgsConstructor;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
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.variable.api.history.HistoricVariableInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -49,6 +65,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author KonBAI
@@ -60,6 +77,8 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
private final IWfTaskService wfTaskService;
private final ISysUserService userService;
private final ISysRoleService roleService;
private final ISysDeptService deptService;
private final WfDeployFormMapper deployFormMapper;
/**
@@ -118,7 +137,8 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
WfDeployFormVo deployFormVo = deployFormMapper.selectVoOne(new LambdaQueryWrapper<WfDeployForm>()
.eq(WfDeployForm::getDeployId, deployId)
.eq(WfDeployForm::getFormKey, startEvent.getFormKey()));
.eq(WfDeployForm::getFormKey, startEvent.getFormKey())
.eq(WfDeployForm::getNodeKey, startEvent.getId()));
return deployFormVo.getContent();
}
@@ -174,6 +194,32 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
}
}
/**
* 流程详情信息
*
* @param procInsId 流程实例ID
* @param deployId 流程部署ID
* @param taskId 任务ID
* @return
*/
@Override
public WfDetailVo queryProcessDetail(String procInsId, String deployId, String taskId) {
WfDetailVo detailVo = new WfDetailVo();
HistoricTaskInstance taskIns = historyService.createHistoricTaskInstanceQuery()
.taskId(taskId)
.includeIdentityLinks()
.includeProcessVariables()
.includeTaskLocalVariables()
.singleResult();
if (taskIns == null) {
throw new ServiceException("没有可办理的任务!");
}
detailVo.setTaskFormData(currTaskFormData(deployId, taskIns));
detailVo.setHistoryTaskList(historyTaskList(procInsId));
detailVo.setProcessFormList(processFormList(procInsId, deployId, taskIns));
return detailVo;
}
@Override
public TableDataInfo<WfTaskVo> queryPageOwnProcessList(PageQuery pageQuery) {
Page<WfTaskVo> page = new Page<>();
@@ -405,4 +451,167 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
}
return taskService.getVariables(taskId);
}
/**
* 获取当前任务流程表单信息
*/
private FormConf currTaskFormData(String deployId, HistoricTaskInstance taskIns) {
WfDeployFormVo deployFormVo = deployFormMapper.selectVoOne(new LambdaQueryWrapper<WfDeployForm>()
.eq(WfDeployForm::getDeployId, deployId)
.eq(WfDeployForm::getFormKey, taskIns.getFormKey())
.eq(WfDeployForm::getNodeKey, taskIns.getTaskDefinitionKey()));
if (ObjectUtil.isNotEmpty(deployFormVo)) {
FormConf currTaskFormData = JsonUtils.parseObject(deployFormVo.getContent(), FormConf.class);
if (null != currTaskFormData) {
currTaskFormData.setFormBtns(false);
ProcessFormUtils.fillFormData(currTaskFormData, taskIns.getTaskLocalVariables());
return currTaskFormData;
}
}
return null;
}
/**
* 获取流程表单信息(不包括当前任务节点)
*/
private List<FormConf> processFormList(String procInsId, String deployId, HistoricTaskInstance taskIns) {
List<FormConf> procFormList = new ArrayList<>();
HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery().processInstanceId(procInsId).includeProcessVariables().singleResult();
Process process = repositoryService.getBpmnModel(historicProcIns.getProcessDefinitionId()).getMainProcess();
buildStartFormData(historicProcIns, process, deployId, procFormList);
buildUserTaskFormData(procInsId, deployId, taskIns.getTaskDefinitionKey(), process, procFormList);
return procFormList;
}
private void buildStartFormData(HistoricProcessInstance historicProcIns, Process process, String deployId, List<FormConf> procFormList) {
procFormList = procFormList == null ? new ArrayList<>() : procFormList;
HistoricActivityInstance startInstance = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(historicProcIns.getId())
.activityId(historicProcIns.getStartActivityId())
.singleResult();
StartEvent startEvent = (StartEvent) process.getFlowElement(startInstance.getActivityId());
WfDeployFormVo startFormInfo = deployFormMapper.selectVoOne(new LambdaQueryWrapper<WfDeployForm>()
.eq(WfDeployForm::getDeployId, deployId)
.eq(WfDeployForm::getFormKey, startEvent.getFormKey())
.eq(WfDeployForm::getNodeKey, startEvent.getId()));
if (ObjectUtil.isNotNull(startFormInfo)) {
FormConf formConf = JsonUtils.parseObject(startFormInfo.getContent(), FormConf.class);
if (null != formConf) {
formConf.setTitle(startEvent.getName());
formConf.setDisabled(true);
formConf.setFormBtns(false);
ProcessFormUtils.fillFormData(formConf, historicProcIns.getProcessVariables());
procFormList.add(formConf);
}
}
}
private void buildUserTaskFormData(String procInsId, String deployId, String taskActivityId, Process process, List<FormConf> procFormList) {
procFormList = procFormList == null ? new ArrayList<>() : procFormList;
List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(procInsId).finished()
.activityType(BpmnXMLConstants.ELEMENT_TASK_USER)
.orderByHistoricActivityInstanceStartTime().asc()
.list();
for (HistoricActivityInstance instanceItem : activityInstanceList) {
// 跳过当前节点
if (instanceItem.getActivityId().equals(taskActivityId)) {
continue;
}
UserTask userTask = (UserTask) process.getFlowElement(instanceItem.getActivityId(), true);
String formKey = userTask.getFormKey();
if (formKey == null) {
continue;
}
// 查询任务节点参数并转换成Map
Map<String, Object> variables = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(procInsId)
.taskId(instanceItem.getTaskId())
.list()
.stream()
.collect(Collectors.toMap(HistoricVariableInstance::getVariableName, HistoricVariableInstance::getValue));
WfDeployFormVo deployFormVo = deployFormMapper.selectVoOne(new LambdaQueryWrapper<WfDeployForm>()
.eq(WfDeployForm::getDeployId, deployId)
.eq(WfDeployForm::getFormKey, formKey)
.eq(WfDeployForm::getNodeKey, userTask.getId()));
if (ObjectUtil.isNotNull(deployFormVo)) {
FormConf formConf = JsonUtils.parseObject(deployFormVo.getContent(), FormConf.class);
if (null != formConf) {
formConf.setTitle(userTask.getName());
formConf.setDisabled(true);
formConf.setFormBtns(false);
ProcessFormUtils.fillFormData(formConf, variables);
procFormList.add(formConf);
}
}
}
}
/**
* 获取历史任务信息列表
*/
private List<WfTaskVo> historyTaskList(String procInsId) {
List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(procInsId)
.orderByHistoricTaskInstanceStartTime().desc()
.list();
List<Comment> commentList = taskService.getProcessInstanceComments(procInsId);
List<WfTaskVo> taskVoList = new ArrayList<>(taskInstanceList.size());
taskInstanceList.forEach(taskInstance -> {
WfTaskVo taskVo = new WfTaskVo();
taskVo.setProcDefId(taskInstance.getProcessDefinitionId());
taskVo.setTaskId(taskInstance.getId());
taskVo.setTaskDefKey(taskInstance.getTaskDefinitionKey());
taskVo.setTaskName(taskInstance.getName());
taskVo.setCreateTime(taskInstance.getStartTime());
taskVo.setFinishTime(taskInstance.getEndTime());
if (StringUtils.isNotBlank(taskInstance.getAssignee())) {
SysUser user = userService.selectUserById(Long.parseLong(taskInstance.getAssignee()));
taskVo.setAssigneeId(user.getUserId());
taskVo.setAssigneeName(user.getNickName());
taskVo.setDeptName(user.getDept().getDeptName());
}
// 展示审批人员
List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(taskInstance.getId());
StringBuilder stringBuilder = new StringBuilder();
for (HistoricIdentityLink identityLink : linksForTask) {
if ("candidate".equals(identityLink.getType())) {
if (StringUtils.isNotBlank(identityLink.getUserId())) {
SysUser user = userService.selectUserById(Long.parseLong(identityLink.getUserId()));
stringBuilder.append(user.getNickName()).append(",");
}
if (StringUtils.isNotBlank(identityLink.getGroupId())) {
if (identityLink.getGroupId().startsWith(TaskConstants.ROLE_GROUP_PREFIX)) {
Long roleId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.ROLE_GROUP_PREFIX));
SysRole role = roleService.selectRoleById(roleId);
stringBuilder.append(role.getRoleName()).append(",");
} else if (identityLink.getGroupId().startsWith(TaskConstants.DEPT_GROUP_PREFIX)) {
Long deptId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.DEPT_GROUP_PREFIX));
SysDept dept = deptService.selectDeptById(deptId);
stringBuilder.append(dept.getDeptName()).append(",");
}
}
}
}
if (StringUtils.isNotBlank(stringBuilder)) {
taskVo.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1));
}
if (ObjectUtil.isNotNull(taskInstance.getDurationInMillis())) {
taskVo.setDuration(DateUtil.formatBetween(taskInstance.getDurationInMillis(), BetweenFormatter.Level.SECOND));
}
// 获取意见评论内容
if (CollUtil.isNotEmpty(commentList)) {
List<Comment> comments = new ArrayList<>();
for (Comment comment : commentList) {
if (comment.getTaskId().equals(taskInstance.getId())) {
comments.add(comment);
}
}
taskVo.setCommentList(comments);
}
taskVoList.add(taskVo);
});
return taskVoList;
}
}

View File

@@ -82,13 +82,13 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
}
if (DelegationState.PENDING.equals(task.getDelegationState())) {
taskService.addComment(taskBo.getTaskId(), taskBo.getInstanceId(), FlowComment.DELEGATE.getType(), taskBo.getComment());
taskService.resolveTask(taskBo.getTaskId(), taskBo.getValues());
taskService.resolveTask(taskBo.getTaskId());
} else {
taskService.addComment(taskBo.getTaskId(), taskBo.getInstanceId(), FlowComment.NORMAL.getType(), taskBo.getComment());
Long userId = LoginHelper.getUserId();
taskService.setAssignee(taskBo.getTaskId(), userId.toString());
if (ObjectUtil.isNotEmpty(taskBo.getValues())) {
taskService.complete(taskBo.getTaskId(), taskBo.getValues());
if (ObjectUtil.isNotEmpty(taskBo.getVariables())) {
taskService.complete(taskBo.getTaskId(), taskBo.getVariables(), true);
} else {
taskService.complete(taskBo.getTaskId());
}