更多ruoyi-nbcio功能请看演示系统
gitee源代码地址
前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio
演示地址:RuoYi-Nbcio后台管理系统
这节简单介绍一下仿钉钉流程json转flowable的xml格式的一个简单例子,目前是测试开发阶段,所以先搞个简单例子进行测试,只支持简单的审批人与发起人审批流程,而且是单人的。
1、画出仿钉钉流程如下:
如上所画,除发起人,后面还有单独的两个用户任务节点分别是张三与管理员
2、json格式,这个部分先不做任何修改
如下:
3、xml格式如下:
4、前端的xml的实现,主要是调用后端接口如下:
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 } }) //var options = {compact: true, ignoreComment: true, spaces: 4}; //this.previewResult = convert.json2xml(json, options); }) .catch(err => { err.target && (this.activeStep = err.target) err.msg && this.$message.warning(err.msg) }) },
上面主要是调用dingdingToBpmn接口。
5、后端代码
首先实现这个简单接口服务如下:
/** * 根据仿钉钉流程json转flowable的bpmn的xml格式 * add by nbacheng * @param String ddjson * * * @return */ @Override public 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演示流程"); StartEvent startEvent = createStartEvent(); ddProcess.addFlowElement(startEvent); JSONObject flowNode = object.getJSONObject("processData"); 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() { StartEvent startEvent = new StartEvent(); startEvent.setId(id("start")); 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.PARALLEL.isEqual(nodeType)) { return createParallelGatewayBuilder(fromId, flowNode); } else if (Type.EXCLUSIVE.isEqual(nodeType)) { return createExclusiveGatewayBuilder(fromId, flowNode); } else if (Type.INITIATOR_TASK.isEqual(nodeType)) { flowNode.put("incoming", Collections.singletonList(fromId)); String id = createUserTask(flowNode,nodeType); // 如果当前任务还有后续任务,则遍历创建后续任务 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); // 如果当前任务还有后续任务,则遍历创建后续任务 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); // 如果当前任务还有后续任务,则遍历创建后续任务 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 createUserTask(JSONObject flowNode, String nodeType) { List<String> incoming = flowNode.getJSONArray("incoming").toJavaList(String.class); // 自动生成id String 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); if (Type.INITIATOR_TASK.isEqual(nodeType)) { 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); userTask.setAssignee(approver.getString("userName")); } ddProcess.addFlowElement(userTask); ddProcess.addFlowElement(connect(incoming.get(0), id)); } return id; }
6、用流程设计器打开之前的xml文件如下,初步符合要求,当然还有很多问题,需要后续修改与完善: