基于若依的ruoyi-nbcio流程管理系统仿钉钉流程初步完成转bpmn设计(还有bug,以后再修改)

本文主要是介绍基于若依的ruoyi-nbcio流程管理系统仿钉钉流程初步完成转bpmn设计(还有bug,以后再修改),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

更多ruoyi-nbcio功能请看演示系统

gitee源代码地址

前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio

演示地址:RuoYi-Nbcio后台管理系统

     今天初步完成仿钉钉流程转bpmn设计的工作,当然还有不少bug,以后有需要或者网友也帮忙改进。

1、前端

   前端主要部分如下:

previewJson() {const getCmpData = name => this.$refs[name].getData()// processDesign 返回的是Promise 因为要做校验console.log("publish getCmpData",getCmpData)const p3 = getCmpData('processDesign')console.log("publish p3",p3)Promise.all([p3]).then(res => {const param = {processData: res[0].formData}this.previewResult = JSON.stringify(param, null, 2);//json格式化this.previewType = "json";this.previewModelVisible = true;}).catch(err => {err.target && (this.activeStep = err.target)err.msg && this.$message.warning(err.msg)})},previewXml() {const getCmpData = name => this.$refs[name].getData()// processDesign 返回的是Promise 因为要做校验console.log("publish getCmpData",getCmpData)const p3 = getCmpData('processDesign')console.log("publish p3",p3)Promise.all([p3]).then(res => {const param = {processData: res[0].formData}var convert = require('xml-js');var json = JSON.stringify(param, null, 2);//json格式化// 启动流程并将表单数据加入流程变量dingdingToBpmn(json).then(res => {console.log("dingdingToBpmn res",res)if(res.code == 200) {this.previewResult = res.msg;this.previewType = "xml";this.previewModelVisible = true}})}).catch(err => {err.target && (this.activeStep = err.target)err.msg && this.$message.warning(err.msg)})},previewBpmn() {const getCmpData = name => this.$refs[name].getData()// processDesign 返回的是Promise 因为要做校验console.log("publish getCmpData",getCmpData)const p3 = getCmpData('processDesign')console.log("publish p3",p3)Promise.all([p3]).then(res => {const param = {processData: res[0].formData}var convert = require('xml-js');var json = JSON.stringify(param, null, 2);//json格式化// 钉钉流程转为bpmn格式dingdingToBpmn(json).then(reponse => {console.log("dingdingToBpmn reponse",reponse)if(reponse.code == 200) {this.processView.title = "Bpmn流程图预览";this.processView.xmlData = reponse.msg;}})this.processView.open = true;}).catch(err => {err.target && (this.activeStep = err.target)err.msg && this.$message.warning(err.msg)})},

 2、后端主要部分如下:

@Overridepublic R<Void> dingdingToBpmn(String ddjson) {	try {JSONObject object = JSON.parseObject(ddjson, JSONObject.class);//JSONObject workflow = object.getJSONObject("process");//ddBpmnModel.addProcess(ddProcess);//ddProcess.setName (workflow.getString("name"));//ddProcess.setId(workflow.getString("processId"));ddProcess = new Process();ddBpmnModel = new BpmnModel();ddSequenceFlows = Lists.newArrayList();ddBpmnModel.addProcess(ddProcess);ddProcess.setId("Process_"+UUID.randomUUID());ddProcess.setName ("dingding演示流程");JSONObject flowNode = object.getJSONObject("processData");StartEvent startEvent = createStartEvent(flowNode);ddProcess.addFlowElement(startEvent);String lastNode = create(startEvent.getId(), flowNode);EndEvent endEvent = createEndEvent();ddProcess.addFlowElement(endEvent);ddProcess.addFlowElement(connect(lastNode, endEvent.getId()));new BpmnAutoLayout(ddBpmnModel).execute();return R.ok(new String(new BpmnXMLConverter().convertToXML(ddBpmnModel)));} catch (Exception e) {e.printStackTrace();throw new RuntimeException("创建失败: e=" + e.getMessage());}}String id(String prefix) {return prefix + "_" + UUID.randomUUID().toString().replace("-", "").toLowerCase();}ServiceTask serviceTask(String name) {ServiceTask serviceTask = new ServiceTask();serviceTask.setName(name);return serviceTask;}SequenceFlow connect(String from, String to) {SequenceFlow flow = new SequenceFlow();flow.setId(id("sequenceFlow"));flow.setSourceRef(from);flow.setTargetRef(to);ddSequenceFlows.add(flow);return flow;}StartEvent createStartEvent(JSONObject flowNode) {String nodeType = flowNode.getString("type");StartEvent startEvent = new StartEvent();startEvent.setId(id("start"));if (Type.INITIATOR_TASK.isEqual(nodeType)) {JSONObject properties = flowNode.getJSONObject("properties");if(StringUtils.isNotEmpty(properties.getString("formKey"))) {startEvent.setFormKey(properties.getString("formKey"));}}return startEvent;}EndEvent createEndEvent() {EndEvent endEvent = new EndEvent();endEvent.setId(id("end"));return endEvent;}String create(String fromId, JSONObject flowNode) throws InvocationTargetException, IllegalAccessException {String nodeType = flowNode.getString("type");if (Type.INITIATOR_TASK.isEqual(nodeType)) {flowNode.put("incoming", Collections.singletonList(fromId));String id = createUserTask(flowNode,nodeType);if(flowNode.containsKey("concurrentNodes")) { //并行网关return createConcurrentGatewayBuilder(id, flowNode);   }if(flowNode.containsKey("conditionNodes")) { //排它网关或叫条件网关return createExclusiveGatewayBuilder(id, flowNode);}    // 如果当前任务还有后续任务,则遍历创建后续任务JSONObject nextNode = flowNode.getJSONObject("childNode");if (Objects.nonNull(nextNode)) {FlowElement flowElement = ddBpmnModel.getFlowElement(id);return create(id, nextNode);} else {return id;}} else if (Type.USER_TASK.isEqual(nodeType) || Type.APPROVER_TASK.isEqual(nodeType)) {flowNode.put("incoming", Collections.singletonList(fromId));     String id = createUserTask(flowNode,nodeType);if(flowNode.containsKey("concurrentNodes")) { //并行网关return createConcurrentGatewayBuilder(id, flowNode);   }if(flowNode.containsKey("conditionNodes")) { //排它网关或叫条件网关return createExclusiveGatewayBuilder(id, flowNode);}  // 如果当前任务还有后续任务,则遍历创建后续任务JSONObject nextNode = flowNode.getJSONObject("childNode");if (Objects.nonNull(nextNode)) {FlowElement flowElement = ddBpmnModel.getFlowElement(id);return create(id, nextNode);          } else {return id;  }} else if (Type.SERVICE_TASK.isEqual(nodeType)) {flowNode.put("incoming", Collections.singletonList(fromId));String id = createServiceTask(flowNode);if(flowNode.containsKey("concurrentNodes")) { //并行网关return createConcurrentGatewayBuilder(id, flowNode);   }if(flowNode.containsKey("conditionNodes")) { //排它网关或叫条件网关return createExclusiveGatewayBuilder(id, flowNode);} // 如果当前任务还有后续任务,则遍历创建后续任务JSONObject nextNode = flowNode.getJSONObject("childNode");if (Objects.nonNull(nextNode)) {FlowElement flowElement = ddBpmnModel.getFlowElement(id);return create(id, nextNode);} else {return id;}}  else {throw new RuntimeException("未知节点类型: nodeType=" + nodeType);}}String createExclusiveGatewayBuilder(String formId, JSONObject flowNode) throws InvocationTargetException, IllegalAccessException {//String name = flowNode.getString("nodeName");String exclusiveGatewayId = id("exclusiveGateway");ExclusiveGateway exclusiveGateway = new ExclusiveGateway();exclusiveGateway.setId(exclusiveGatewayId);exclusiveGateway.setName("排它条件网关");ddProcess.addFlowElement(exclusiveGateway);ddProcess.addFlowElement(connect(formId, exclusiveGatewayId));if (Objects.isNull(flowNode.getJSONArray("conditionNodes")) && Objects.isNull(flowNode.getJSONObject("childNode"))) {return exclusiveGatewayId;}List<JSONObject> flowNodes = Optional.ofNullable(flowNode.getJSONArray("conditionNodes")).map(e -> e.toJavaList(JSONObject.class)).orElse(Collections.emptyList());List<String> incoming = Lists.newArrayListWithCapacity(flowNodes.size());List<JSONObject> conditions = Lists.newCopyOnWriteArrayList();for (JSONObject element : flowNodes) {JSONObject childNode = element.getJSONObject("childNode");JSONObject properties = element.getJSONObject("properties");String nodeName = properties.getString("title");String expression = properties.getString("conditions");if (Objects.isNull(childNode)) {incoming.add(exclusiveGatewayId);JSONObject condition = new JSONObject();condition.fluentPut("nodeName", nodeName).fluentPut("expression", expression);conditions.add(condition);continue;}// 只生成一个任务,同时设置当前任务的条件childNode.put("incoming", Collections.singletonList(exclusiveGatewayId));String identifier = create(exclusiveGatewayId, childNode);List<SequenceFlow> flows = ddSequenceFlows.stream().filter(flow -> StringUtils.equals(exclusiveGatewayId, flow.getSourceRef())).collect(Collectors.toList());flows.stream().forEach(e -> {if (StringUtils.isBlank(e.getName()) && StringUtils.isNotBlank(nodeName)) {e.setName(nodeName);}// 设置条件表达式if (Objects.isNull(e.getConditionExpression()) && StringUtils.isNotBlank(expression)) {e.setConditionExpression(expression);}});if (Objects.nonNull(identifier)) {incoming.add(identifier);}}JSONObject childNode = flowNode.getJSONObject("childNode");if (Objects.nonNull(childNode)) {if (incoming == null || incoming.isEmpty()) {return create(exclusiveGatewayId, childNode);} else {// 所有 service task 连接 end exclusive gatewaychildNode.put("incoming", incoming);FlowElement flowElement = ddBpmnModel.getFlowElement(incoming.get(0));// 1.0 先进行边连接, 暂存 nextNodeJSONObject nextNode = childNode.getJSONObject("childNode");childNode.put("childNode", null);String identifier = create(flowElement.getId(), childNode);for (int i = 1; i < incoming.size(); i++) {ddProcess.addFlowElement(connect(incoming.get(i), identifier));}//  针对 gateway 空任务分支 添加条件表达式if (!conditions.isEmpty()) {FlowElement flowElement1 = ddBpmnModel.getFlowElement(identifier);// 获取从 gateway 到目标节点 未设置条件表达式的节点List<SequenceFlow> flows = ddSequenceFlows.stream().filter(flow -> StringUtils.equals(flowElement1.getId(), flow.getTargetRef())).filter(flow -> StringUtils.equals(flow.getSourceRef(), exclusiveGatewayId)).collect(Collectors.toList());flows.stream().forEach(sequenceFlow -> {if (!conditions.isEmpty()) {JSONObject condition = conditions.get(0);String nodeName = condition.getString("content");String expression = condition.getString("expression");if (StringUtils.isBlank(sequenceFlow.getName()) && StringUtils.isNotBlank(nodeName)) {sequenceFlow.setName(nodeName);}// 设置条件表达式if (Objects.isNull(sequenceFlow.getConditionExpression()) && StringUtils.isNotBlank(expression)) {sequenceFlow.setConditionExpression(expression);}conditions.remove(0);}});}// 1.1 边连接完成后,在进行 nextNode 创建if (Objects.nonNull(nextNode)) {return create(identifier, nextNode);} else {return identifier;}}}return exclusiveGatewayId;}String createConcurrentGatewayBuilder(String fromId, JSONObject flowNode) throws InvocationTargetException, IllegalAccessException {//String name = flowNode.getString("nodeName");//下面创建并行网关并进行连线ParallelGateway parallelGateway = new ParallelGateway();String parallelGatewayId = id("parallelGateway");parallelGateway.setId(parallelGatewayId);parallelGateway.setName("并行网关");ddProcess.addFlowElement(parallelGateway);ddProcess.addFlowElement(connect(fromId, parallelGatewayId));if (Objects.isNull(flowNode.getJSONArray("concurrentNodes"))&& Objects.isNull(flowNode.getJSONObject("childNode"))) {return parallelGatewayId;}//获取并行列表数据List<JSONObject> flowNodes = Optional.ofNullable(flowNode.getJSONArray("concurrentNodes")).map(e -> e.toJavaList(JSONObject.class)).orElse(Collections.emptyList());List<String> incoming = Lists.newArrayListWithCapacity(flowNodes.size());for (JSONObject element : flowNodes) {JSONObject childNode = element.getJSONObject("childNode");if (Objects.isNull(childNode)) {//没子节点,就把并行id加入入口队列incoming.add(parallelGatewayId);continue;}String identifier = create(parallelGatewayId, childNode);if (Objects.nonNull(identifier)) {//否则加入有子节点的用户idincoming.add(identifier);}}JSONObject childNode = flowNode.getJSONObject("childNode");if (Objects.nonNull(childNode)) {// 普通结束网关if (CollectionUtils.isEmpty(incoming)) {return create(parallelGatewayId, childNode);} else {// 所有 user task 连接 end parallel gatewaychildNode.put("incoming", incoming);FlowElement flowElement = ddBpmnModel.getFlowElement(incoming.get(0));// 1.0 先进行边连接, 暂存 nextNodeJSONObject nextNode = childNode.getJSONObject("childNode");childNode.put("childNode", null); //不加这个,下面创建子节点会进入递归了String identifier = create(incoming.get(0), childNode);for (int i = 1; i < incoming.size(); i++) {//其中0之前创建的时候已经连接过了,所以从1开始补另外一条FlowElement flowElementIncoming = ddBpmnModel.getFlowElement(incoming.get(i));ddProcess.addFlowElement(connect(flowElementIncoming.getId(), identifier));}// 1.1 边连接完成后,在进行 nextNode 创建if (Objects.nonNull(nextNode)) {return create(identifier, nextNode);} else {return identifier;}}}if(incoming.size()>0) {return incoming.get(1);}else {return parallelGatewayId;   }}String createUserTask(JSONObject flowNode, String nodeType) {List<String> incoming = flowNode.getJSONArray("incoming").toJavaList(String.class);// 自动生成idString id = id("userTask");if (incoming != null && !incoming.isEmpty()) {UserTask userTask = new UserTask();JSONObject properties = flowNode.getJSONObject("properties");userTask.setName(properties.getString("title"));userTask.setId(id);List<ExtensionAttribute> attributes = new  ArrayList<ExtensionAttribute>();if (Type.INITIATOR_TASK.isEqual(nodeType)) {ExtensionAttribute extAttribute =  new ExtensionAttribute();extAttribute.setNamespace(ProcessConstants.NAMASPASE);extAttribute.setName("dataType");extAttribute.setValue("INITIATOR");attributes.add(extAttribute);userTask.addAttribute(extAttribute);userTask.setAssignee("${initiator}");} else if (Type.USER_TASK.isEqual(nodeType) || Type.APPROVER_TASK.isEqual(nodeType)) {JSONArray approvers = properties.getJSONArray("approvers");JSONObject approver = approvers.getJSONObject(0);ExtensionAttribute extDataTypeAttribute =  new ExtensionAttribute();extDataTypeAttribute.setNamespace(ProcessConstants.NAMASPASE);extDataTypeAttribute.setName("dataType");extDataTypeAttribute.setValue("USERS");userTask.addAttribute(extDataTypeAttribute);ExtensionAttribute extTextAttribute =  new ExtensionAttribute();extTextAttribute.setNamespace(ProcessConstants.NAMASPASE);extTextAttribute.setName("text");extTextAttribute.setValue(approver.getString("nickName"));userTask.addAttribute(extTextAttribute);userTask.setFormKey(properties.getString("formKey"));userTask.setAssignee(approver.getString("userName"));}ddProcess.addFlowElement(userTask);ddProcess.addFlowElement(connect(incoming.get(0), id));}return id;}String createServiceTask(JSONObject flowNode) {List<String> incoming = flowNode.getJSONArray("incoming").toJavaList(String.class);// 自动生成idString id = id("serviceTask");if (incoming != null && !incoming.isEmpty()) {ServiceTask serviceTask = new ServiceTask();serviceTask.setName(flowNode.getString("nodeName"));serviceTask.setId(id);ddProcess.addFlowElement(serviceTask);ddProcess.addFlowElement(connect(incoming.get(0), id));}return id;}enum Type {/*** 并行事件*/CONCURRENT("concurrent", ParallelGateway.class),/*** 排他事件*/EXCLUSIVE("exclusive", ExclusiveGateway.class),/*** 服务任务*/SERVICE_TASK("serviceTask", ServiceTask.class),/*** 发起人任务*/INITIATOR_TASK("start", ServiceTask.class),/*** 审批任务*/APPROVER_TASK("approver", ServiceTask.class),/*** 用户任务*/USER_TASK("userTask", UserTask.class);private String type;private Class<?> typeClass;Type(String type, Class<?> typeClass) {this.type = type;this.typeClass = typeClass;}public final static Map<String, Class<?>> TYPE_MAP = Maps.newHashMap();static {for (Type element : Type.values()) {TYPE_MAP.put(element.type, element.typeClass);}}public boolean isEqual(String type) {return this.type.equals(type);}}

3、效果图如下:   

这篇关于基于若依的ruoyi-nbcio流程管理系统仿钉钉流程初步完成转bpmn设计(还有bug,以后再修改)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/444742

相关文章

通过Docker容器部署Python环境的全流程

《通过Docker容器部署Python环境的全流程》在现代化开发流程中,Docker因其轻量化、环境隔离和跨平台一致性的特性,已成为部署Python应用的标准工具,本文将详细演示如何通过Docker容... 目录引言一、docker与python的协同优势二、核心步骤详解三、进阶配置技巧四、生产环境最佳实践

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

MySQL 临时表与复制表操作全流程案例

《MySQL临时表与复制表操作全流程案例》本文介绍MySQL临时表与复制表的区别与使用,涵盖生命周期、存储机制、操作限制、创建方法及常见问题,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小... 目录一、mysql 临时表(一)核心特性拓展(二)操作全流程案例1. 复杂查询中的临时表应用2. 临时

基于Spring Boot 的小区人脸识别与出入记录管理系统功能

《基于SpringBoot的小区人脸识别与出入记录管理系统功能》文章介绍基于SpringBoot框架与百度AI人脸识别API的小区出入管理系统,实现自动识别、记录及查询功能,涵盖技术选型、数据模型... 目录系统功能概述技术栈选择核心依赖配置数据模型设计出入记录实体类出入记录查询表单出入记录 VO 类(用于

MySQL 升级到8.4版本的完整流程及操作方法

《MySQL升级到8.4版本的完整流程及操作方法》本文详细说明了MySQL升级至8.4的完整流程,涵盖升级前准备(备份、兼容性检查)、支持路径(原地、逻辑导出、复制)、关键变更(空间索引、保留关键字... 目录一、升级前准备 (3.1 Before You Begin)二、升级路径 (3.2 Upgrade

Mysql中设计数据表的过程解析

《Mysql中设计数据表的过程解析》数据库约束通过NOTNULL、UNIQUE、DEFAULT、主键和外键等规则保障数据完整性,自动校验数据,减少人工错误,提升数据一致性和业务逻辑严谨性,本文介绍My... 目录1.引言2.NOT NULL——制定某列不可以存储NULL值2.UNIQUE——保证某一列的每一

Spring Boot 中的默认异常处理机制及执行流程

《SpringBoot中的默认异常处理机制及执行流程》SpringBoot内置BasicErrorController,自动处理异常并生成HTML/JSON响应,支持自定义错误路径、配置及扩展,如... 目录Spring Boot 异常处理机制详解默认错误页面功能自动异常转换机制错误属性配置选项默认错误处理

Spring Boot从main方法到内嵌Tomcat的全过程(自动化流程)

《SpringBoot从main方法到内嵌Tomcat的全过程(自动化流程)》SpringBoot启动始于main方法,创建SpringApplication实例,初始化上下文,准备环境,刷新容器并... 目录1. 入口:main方法2. SpringApplication初始化2.1 构造阶段3. 运行阶