feat(流程设计): 流程设计添加是否 节点表单 选项。若为节点表单,则表单信息仅在此节点可用,默认为全局表单,表单信息在整个流程实例中可用。

This commit is contained in:
konbai
2023-01-15 00:51:43 +08:00
parent 1ba6327747
commit b2b0d91ad8
6 changed files with 123 additions and 16 deletions

View File

@@ -62,6 +62,11 @@ public class ProcessConstants {
*/
public static final String PROCESS_CUSTOM_USER_TYPE = "userType";
/**
* 自定义属性 localScope
*/
public static final String PROCESS_FORM_LOCAL_SCOPE = "localScope";
/**
* 流程跳过

View File

@@ -130,6 +130,35 @@ public class ModelUtils {
return null;
}
/**
* 获取流程元素信息
*
* @param model bpmnModel对象
* @param flowElementId 元素ID
* @return 元素信息
*/
public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) {
Process process = model.getMainProcess();
return process.getFlowElement(flowElementId);
}
/**
* 获取元素表单Key限开始节点和用户节点可用
*
* @param flowElement 元素
* @return 表单Key
*/
public static String getFormKey(FlowElement flowElement) {
if (flowElement != null) {
if (flowElement instanceof StartEvent) {
return ((StartEvent) flowElement).getFormKey();
} else if (flowElement instanceof UserTask) {
return ((UserTask) flowElement).getFormKey();
}
}
return null;
}
/**
* 获取开始节点属性值
* @param model bpmnModel对象

View File

@@ -1,6 +1,7 @@
package com.ruoyi.workflow.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException;
@@ -17,6 +18,7 @@ import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.flowable.common.constant.ProcessConstants;
import com.ruoyi.flowable.common.constant.TaskConstants;
import com.ruoyi.flowable.core.FormConf;
import com.ruoyi.flowable.core.domain.ProcessQuery;
@@ -36,10 +38,8 @@ 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.bpmn.model.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricActivityInstanceQuery;
import org.flowable.engine.history.HistoricProcessInstance;
@@ -638,7 +638,7 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
detailVo.setBpmnXml(IoUtil.readUtf8(inputStream));
detailVo.setTaskFormData(currTaskFormData(deployId, taskIns));
detailVo.setHistoryProcNodeList(historyProcNodeList(procInsId));
detailVo.setProcessFormList(processFormList(procInsId, deployId, taskIns));
detailVo.setProcessFormList(processFormList(procInsId, deployId));
detailVo.setFlowViewer(getFlowViewer(procInsId));
return detailVo;
}
@@ -699,18 +699,64 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
}
/**
* 获取流程表单信息(不包括当前任务节点)
* 获取历史流程表单信息
*/
private List<FormConf> processFormList(String procInsId, String deployId, HistoricTaskInstance taskIns) {
private List<FormConf> processFormList(String procInsId, String deployId) {
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, process, procFormList);
BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcIns.getProcessDefinitionId());
List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(procInsId).finished()
.activityTypes(CollUtil.newHashSet(BpmnXMLConstants.ELEMENT_EVENT_START, BpmnXMLConstants.ELEMENT_TASK_USER))
.orderByHistoricActivityInstanceStartTime().asc()
.list();
List<String> processFormKeys = new ArrayList<>();
for (HistoricActivityInstance activityInstance : activityInstanceList) {
// 获取当前节点流程元素信息
FlowElement flowElement = ModelUtils.getFlowElementById(bpmnModel, activityInstance.getActivityId());
// 获取当前节点表单Key
String formKey = ModelUtils.getFormKey(flowElement);
if (formKey == null) {
continue;
}
boolean localScope = Convert.toBool(ModelUtils.getElementAttributeValue(flowElement, ProcessConstants.PROCESS_FORM_LOCAL_SCOPE), false);
Map<String, Object> variables;
if (localScope) {
// 查询任务节点参数并转换成Map
variables = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(procInsId)
.taskId(activityInstance.getTaskId())
.list()
.stream()
.collect(Collectors.toMap(HistoricVariableInstance::getVariableName, HistoricVariableInstance::getValue));
} else {
if (processFormKeys.contains(formKey)) {
continue;
}
variables = historicProcIns.getProcessVariables();
processFormKeys.add(formKey);
}
// 兼容旧版数据,旧版此处查询可能出现多条
List<WfDeployFormVo> formInfoList = deployFormMapper.selectVoList(new LambdaQueryWrapper<WfDeployForm>()
.eq(WfDeployForm::getDeployId, deployId)
.eq(WfDeployForm::getFormKey, formKey)
.eq(localScope, WfDeployForm::getNodeKey, flowElement.getId()));
if (CollUtil.isNotEmpty(formInfoList)) {
WfDeployFormVo formInfo = formInfoList.get(0);
FormConf formConf = JsonUtils.parseObject(formInfo.getContent(), FormConf.class);
if (null != formConf) {
formConf.setTitle(flowElement.getName());
formConf.setDisabled(true);
formConf.setFormBtns(false);
ProcessFormUtils.fillFormData(formConf, variables);
procFormList.add(formConf);
}
}
}
return procFormList;
}
@Deprecated
private void buildStartFormData(HistoricProcessInstance historicProcIns, Process process, String deployId, List<FormConf> procFormList) {
procFormList = procFormList == null ? new ArrayList<>() : procFormList;
HistoricActivityInstance startInstance = historyService.createHistoricActivityInstanceQuery()
@@ -734,6 +780,7 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
}
}
@Deprecated
private void buildUserTaskFormData(String procInsId, String deployId, Process process, List<FormConf> procFormList) {
procFormList = procFormList == null ? new ArrayList<>() : procFormList;
List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()

View File

@@ -1,12 +1,14 @@
package com.ruoyi.workflow.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.flowable.common.constant.ProcessConstants;
import com.ruoyi.flowable.common.constant.TaskConstants;
import com.ruoyi.flowable.common.enums.FlowComment;
import com.ruoyi.flowable.factory.FlowServiceFactory;
@@ -69,6 +71,8 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
if (Objects.isNull(task)) {
throw new ServiceException("任务不存在");
}
// 获取 bpmn 模型
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
if (DelegationState.PENDING.equals(task.getDelegationState())) {
taskService.addComment(taskBo.getTaskId(), taskBo.getProcInsId(), FlowComment.DELEGATE.getType(), taskBo.getComment());
taskService.resolveTask(taskBo.getTaskId());
@@ -76,7 +80,10 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
taskService.addComment(taskBo.getTaskId(), taskBo.getProcInsId(), FlowComment.NORMAL.getType(), taskBo.getComment());
taskService.setAssignee(taskBo.getTaskId(), TaskUtils.getUserId());
if (ObjectUtil.isNotEmpty(taskBo.getVariables())) {
taskService.complete(taskBo.getTaskId(), taskBo.getVariables(), true);
// 获取模型信息
String localScopeValue = ModelUtils.getUserTaskAttributeValue(bpmnModel, task.getTaskDefinitionKey(), ProcessConstants.PROCESS_FORM_LOCAL_SCOPE);
boolean localScope = Convert.toBool(localScopeValue, false);
taskService.complete(taskBo.getTaskId(), taskBo.getVariables(), localScope);
} else {
taskService.complete(taskBo.getTaskId());
}
@@ -85,7 +92,7 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
taskBo.setTaskName(task.getName());
// 处理下一级审批人
if (StringUtils.isNotBlank(taskBo.getNextUserIds())) {
this.assignNextUsers(task.getProcessDefinitionId(), taskBo.getProcInsId(), taskBo.getNextUserIds());
this.assignNextUsers(bpmnModel, taskBo.getProcInsId(), taskBo.getNextUserIds());
}
// 处理抄送用户
if (!copyService.makeCopy(taskBo)) {
@@ -578,11 +585,11 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
/**
* 指派下一任务审批人
* @param processDefId 流程定义id
* @param bpmnModel bpmn模型
* @param processInsId 流程实例id
* @param userIds 用户ids
*/
private void assignNextUsers(String processDefId, String processInsId, String userIds) {
private void assignNextUsers(BpmnModel bpmnModel, String processInsId, String userIds) {
// 获取所有节点信息
List<Task> list = taskService.createTaskQuery()
.processInstanceId(processInsId)
@@ -597,7 +604,6 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ
}
return;
}
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId);
// 优先处理非多实例任务
Iterator<Task> iterator = list.iterator();
while (iterator.hasNext()) {

View File

@@ -196,6 +196,12 @@
"name": "formKey",
"isAttr": true,
"type": "String"
},
{
"name": "localScope",
"isAttr": true,
"type": "Boolean",
"default": false
}
]
},

View File

@@ -1,11 +1,20 @@
<template>
<div class="panel-tab__content">
<el-form size="mini" label-width="80px" @submit.native.prevent>
<el-form size="mini" label-width="90px" @submit.native.prevent>
<el-form-item label="表单" prop="formKey">
<el-select v-model="formKey" placeholder="请选择表单" @change="updateElementFormKey" clearable>
<el-option v-for="item in formOptions" :key="item.formId" :label="item.formName" :value="`key_${item.formId}`" />
</el-select>
</el-form-item>
<el-form-item prop="localScope">
<span slot="label">
<el-tooltip content="若为节点表单,则表单信息仅在此节点可用,默认为全局表单,表单信息在整个流程实例中可用" placement="top-start">
<i class="header-icon el-icon-info"></i>
</el-tooltip>
<span>节点表单</span>
</span>
<el-switch :disabled="type === 'StartEvent'" v-model="localScope" active-text="是" inactive-text="否" @change="updateElementFormScope()" />
</el-form-item>
<!-- <el-form-item label="表单标识">-->
<!-- <el-input v-model="formKey" clearable @change="updateElementFormKey" />-->
<!-- </el-form-item>-->
@@ -169,6 +178,7 @@ export default {
return {
formOptions: [],
formKey: "",
localScope: false,
businessKey: "",
optionModelTitle: "",
fieldList: [],
@@ -212,6 +222,7 @@ export default {
resetFormList() {
this.bpmnELement = window.bpmnInstances.bpmnElement;
this.formKey = this.bpmnELement.businessObject.formKey;
this.localScope = this.bpmnELement.businessObject.localScope;
// 获取元素扩展属性 或者 创建扩展属性
this.elExtensionElements =
this.bpmnELement.businessObject.get("extensionElements") || window.bpmnInstances.moddle.create("bpmn:ExtensionElements", { values: [] });
@@ -234,6 +245,9 @@ export default {
updateElementFormKey() {
window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { formKey: this.formKey });
},
updateElementFormScope() {
window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { localScope: this.localScope });
},
updateElementBusinessKey() {
window.bpmnInstances.modeling.updateModdleProperties(this.bpmnELement, this.formData, { businessKey: this.businessKey });
},