diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/common/constant/ProcessConstants.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/common/constant/ProcessConstants.java index 76bc9538..08e1e9c5 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/common/constant/ProcessConstants.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/common/constant/ProcessConstants.java @@ -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"; + /** * 流程跳过 diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/utils/ModelUtils.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/utils/ModelUtils.java index 9a51125d..ebe0d272 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/utils/ModelUtils.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/utils/ModelUtils.java @@ -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对象 diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java index d544475b..e58828ac 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java @@ -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 processFormList(String procInsId, String deployId, HistoricTaskInstance taskIns) { + private List processFormList(String procInsId, String deployId) { List 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 activityInstanceList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(procInsId).finished() + .activityTypes(CollUtil.newHashSet(BpmnXMLConstants.ELEMENT_EVENT_START, BpmnXMLConstants.ELEMENT_TASK_USER)) + .orderByHistoricActivityInstanceStartTime().asc() + .list(); + List 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 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 formInfoList = deployFormMapper.selectVoList(new LambdaQueryWrapper() + .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 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 procFormList) { procFormList = procFormList == null ? new ArrayList<>() : procFormList; List activityInstanceList = historyService.createHistoricActivityInstanceQuery() diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java index d3e205cb..1df07cf4 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java @@ -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 list = taskService.createTaskQuery() .processInstanceId(processInsId) @@ -597,7 +604,6 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ } return; } - BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId); // 优先处理非多实例任务 Iterator iterator = list.iterator(); while (iterator.hasNext()) { diff --git a/ruoyi-ui/src/plugins/package/designer/plugins/descriptor/flowableDescriptor.json b/ruoyi-ui/src/plugins/package/designer/plugins/descriptor/flowableDescriptor.json index a9bca641..2db0b314 100644 --- a/ruoyi-ui/src/plugins/package/designer/plugins/descriptor/flowableDescriptor.json +++ b/ruoyi-ui/src/plugins/package/designer/plugins/descriptor/flowableDescriptor.json @@ -196,6 +196,12 @@ "name": "formKey", "isAttr": true, "type": "String" + }, + { + "name": "localScope", + "isAttr": true, + "type": "Boolean", + "default": false } ] }, diff --git a/ruoyi-ui/src/plugins/package/penal/form/ElementForm.vue b/ruoyi-ui/src/plugins/package/penal/form/ElementForm.vue index e50c4d1a..d15fd5e2 100644 --- a/ruoyi-ui/src/plugins/package/penal/form/ElementForm.vue +++ b/ruoyi-ui/src/plugins/package/penal/form/ElementForm.vue @@ -1,11 +1,20 @@