基于若依的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

相关文章

Linux流媒体服务器部署流程

《Linux流媒体服务器部署流程》文章详细介绍了流媒体服务器的部署步骤,包括更新系统、安装依赖组件、编译安装Nginx和RTMP模块、配置Nginx和FFmpeg,以及测试流媒体服务器的搭建... 目录流媒体服务器部署部署安装1.更新系统2.安装依赖组件3.解压4.编译安装(添加RTMP和openssl模块

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应

修改若依框架Token的过期时间问题

《修改若依框架Token的过期时间问题》本文介绍了如何修改若依框架中Token的过期时间,通过修改`application.yml`文件中的配置来实现,默认单位为分钟,希望此经验对大家有所帮助,也欢迎... 目录修改若依框架Token的过期时间修改Token的过期时间关闭Token的过期时js间总结修改若依

MySQL修改密码的四种实现方式

《MySQL修改密码的四种实现方式》文章主要介绍了如何使用命令行工具修改MySQL密码,包括使用`setpassword`命令和`mysqladmin`命令,此外,还详细描述了忘记密码时的处理方法,包... 目录mysql修改密码四种方式一、set password命令二、使用mysqladmin三、修改u

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav

springboot启动流程过程

《springboot启动流程过程》SpringBoot简化了Spring框架的使用,通过创建`SpringApplication`对象,判断应用类型并设置初始化器和监听器,在`run`方法中,读取配... 目录springboot启动流程springboot程序启动入口1.创建SpringApplicat

使用Python在Excel中插入、修改、提取和删除超链接

《使用Python在Excel中插入、修改、提取和删除超链接》超链接是Excel中的常用功能,通过点击超链接可以快速跳转到外部网站、本地文件或工作表中的特定单元格,有效提升数据访问的效率和用户体验,这... 目录引言使用工具python在Excel中插入超链接Python修改Excel中的超链接Python

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装

MySQL的cpu使用率100%的问题排查流程

《MySQL的cpu使用率100%的问题排查流程》线上mysql服务器经常性出现cpu使用率100%的告警,因此本文整理一下排查该问题的常规流程,文中通过代码示例讲解的非常详细,对大家的学习或工作有一... 目录1. 确认CPU占用来源2. 实时分析mysql活动3. 分析慢查询与执行计划4. 检查索引与表

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push