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"; 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; 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对象 * @param model bpmnModel对象

View File

@@ -1,6 +1,7 @@
package com.ruoyi.workflow.service.impl; package com.ruoyi.workflow.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.BetweenFormatter; import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException; 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.DateUtils;
import com.ruoyi.common.utils.JsonUtils; import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils; 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.constant.TaskConstants;
import com.ruoyi.flowable.core.FormConf; import com.ruoyi.flowable.core.FormConf;
import com.ruoyi.flowable.core.domain.ProcessQuery; import com.ruoyi.flowable.core.domain.ProcessQuery;
@@ -36,10 +38,8 @@ import com.ruoyi.workflow.service.IWfProcessService;
import com.ruoyi.workflow.service.IWfTaskService; import com.ruoyi.workflow.service.IWfTaskService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.flowable.bpmn.constants.BpmnXMLConstants; import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.StartEvent; import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricActivityInstanceQuery; import org.flowable.engine.history.HistoricActivityInstanceQuery;
import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstance;
@@ -638,7 +638,7 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
detailVo.setBpmnXml(IoUtil.readUtf8(inputStream)); detailVo.setBpmnXml(IoUtil.readUtf8(inputStream));
detailVo.setTaskFormData(currTaskFormData(deployId, taskIns)); detailVo.setTaskFormData(currTaskFormData(deployId, taskIns));
detailVo.setHistoryProcNodeList(historyProcNodeList(procInsId)); detailVo.setHistoryProcNodeList(historyProcNodeList(procInsId));
detailVo.setProcessFormList(processFormList(procInsId, deployId, taskIns)); detailVo.setProcessFormList(processFormList(procInsId, deployId));
detailVo.setFlowViewer(getFlowViewer(procInsId)); detailVo.setFlowViewer(getFlowViewer(procInsId));
return detailVo; 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<>(); List<FormConf> procFormList = new ArrayList<>();
HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery().processInstanceId(procInsId).includeProcessVariables().singleResult(); HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery().processInstanceId(procInsId).includeProcessVariables().singleResult();
Process process = repositoryService.getBpmnModel(historicProcIns.getProcessDefinitionId()).getMainProcess(); BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcIns.getProcessDefinitionId());
List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
buildStartFormData(historicProcIns, process, deployId, procFormList); .processInstanceId(procInsId).finished()
buildUserTaskFormData(procInsId, deployId, process, procFormList); .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; return procFormList;
} }
@Deprecated
private void buildStartFormData(HistoricProcessInstance historicProcIns, Process process, String deployId, List<FormConf> procFormList) { private void buildStartFormData(HistoricProcessInstance historicProcIns, Process process, String deployId, List<FormConf> procFormList) {
procFormList = procFormList == null ? new ArrayList<>() : procFormList; procFormList = procFormList == null ? new ArrayList<>() : procFormList;
HistoricActivityInstance startInstance = historyService.createHistoricActivityInstanceQuery() 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) { private void buildUserTaskFormData(String procInsId, String deployId, Process process, List<FormConf> procFormList) {
procFormList = procFormList == null ? new ArrayList<>() : procFormList; procFormList = procFormList == null ? new ArrayList<>() : procFormList;
List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery() List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()

View File

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

View File

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

View File

@@ -1,11 +1,20 @@
<template> <template>
<div class="panel-tab__content"> <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-form-item label="表单" prop="formKey">
<el-select v-model="formKey" placeholder="请选择表单" @change="updateElementFormKey" clearable> <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-option v-for="item in formOptions" :key="item.formId" :label="item.formName" :value="`key_${item.formId}`" />
</el-select> </el-select>
</el-form-item> </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-form-item label="表单标识">-->
<!-- <el-input v-model="formKey" clearable @change="updateElementFormKey" />--> <!-- <el-input v-model="formKey" clearable @change="updateElementFormKey" />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
@@ -169,6 +178,7 @@ export default {
return { return {
formOptions: [], formOptions: [],
formKey: "", formKey: "",
localScope: false,
businessKey: "", businessKey: "",
optionModelTitle: "", optionModelTitle: "",
fieldList: [], fieldList: [],
@@ -212,6 +222,7 @@ export default {
resetFormList() { resetFormList() {
this.bpmnELement = window.bpmnInstances.bpmnElement; this.bpmnELement = window.bpmnInstances.bpmnElement;
this.formKey = this.bpmnELement.businessObject.formKey; this.formKey = this.bpmnELement.businessObject.formKey;
this.localScope = this.bpmnELement.businessObject.localScope;
// 获取元素扩展属性 或者 创建扩展属性 // 获取元素扩展属性 或者 创建扩展属性
this.elExtensionElements = this.elExtensionElements =
this.bpmnELement.businessObject.get("extensionElements") || window.bpmnInstances.moddle.create("bpmn:ExtensionElements", { values: [] }); this.bpmnELement.businessObject.get("extensionElements") || window.bpmnInstances.moddle.create("bpmn:ExtensionElements", { values: [] });
@@ -234,6 +245,9 @@ export default {
updateElementFormKey() { updateElementFormKey() {
window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { formKey: this.formKey }); window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { formKey: this.formKey });
}, },
updateElementFormScope() {
window.bpmnInstances.modeling.updateProperties(this.bpmnELement, { localScope: this.localScope });
},
updateElementBusinessKey() { updateElementBusinessKey() {
window.bpmnInstances.modeling.updateModdleProperties(this.bpmnELement, this.formData, { businessKey: this.businessKey }); window.bpmnInstances.modeling.updateModdleProperties(this.bpmnELement, this.formData, { businessKey: this.businessKey });
}, },