一、实现效果
前端使用LogicFlow框架绘制流程图,可以导出为xml工作流标准格式数据,通过xml文件传递到后端进行Flowable流程注册,并保存到数据库中。
二、BPM传输文件格式(.xml)
如需添加承办人的话,需要在LogicFlow导出文件的基础上手动添加
xmlns:flowable="http://flowable.org/bpmn"
flowable插件,不然后台无法识别
flowable:candidateUsers
。
<bpmn:definitions xmlns:flowable="http://flowable.org/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_5588fe5_6" targetNamespace="http://logic-flow.org" exporter="logicflow" exporterVersion="1.2.0"><bpmn:process isExecutable="true" id="Process_2a9c067_6"><bpmn:startEvent id="Event_14efe0e" name="开始节点" flowable:candidateUsers="admin,admin1,admin2"><bpmn:outgoing>Flow_a3e7d0c</bpmn:outgoing></bpmn:startEvent><bpmn:userTask id="Activity_602107f" name="普通节点" flowable:candidateUsers="uesr,uesr1,uesr2"><bpmn:incoming>Flow_a3e7d0c</bpmn:incoming><bpmn:outgoing>Flow_3f9a386</bpmn:outgoing></bpmn:userTask><bpmn:endEvent id="Event_49a11b4" name="结束节点"><bpmn:incoming>Flow_3f9a386</bpmn:incoming></bpmn:endEvent><bpmn:sequenceFlow id="Flow_a3e7d0c" sourceRef="Event_14efe0e" targetRef="Activity_602107f"/><bpmn:sequenceFlow id="Flow_3f9a386" sourceRef="Activity_602107f" targetRef="Event_49a11b4"/></bpmn:process><bpmndi:BPMNDiagram id="BPMNDiagram_1"><bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_2a9c067"><bpmndi:BPMNEdge id="Flow_a3e7d0c_di" bpmnElement="Flow_a3e7d0c"><di:waypoint x="343" y="164"/><di:waypoint x="448" y="164"/></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="Flow_3f9a386_di" bpmnElement="Flow_3f9a386"><di:waypoint x="548" y="164"/><di:waypoint x="665" y="164"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="Event_14efe0e_di" bpmnElement="Event_14efe0e"><dc:Bounds x="305" y="144" width="40" height="40"/><bpmndi:BPMNLabel><dc:Bounds x="305" y="197" width="40" height="14"/></bpmndi:BPMNLabel></bpmndi:BPMNShape><bpmndi:BPMNShape id="Activity_602107f_di" bpmnElement="Activity_602107f"><dc:Bounds x="448" y="124" width="100" height="80"/><bpmndi:BPMNLabel><dc:Bounds x="478" y="157" width="40" height="14"/></bpmndi:BPMNLabel></bpmndi:BPMNShape><bpmndi:BPMNShape id="Event_49a11b4_di" bpmnElement="Event_49a11b4"><dc:Bounds x="663" y="144" width="40" height="40"/><bpmndi:BPMNLabel><dc:Bounds x="663" y="197" width="40" height="14"/></bpmndi:BPMNLabel></bpmndi:BPMNShape></bpmndi:BPMNPlane></bpmndi:BPMNDiagram></bpmn:definitions>
三、前端框架(LogicFlow)
- LogicFlow.vue
<template><div class="container" ref="container"></div><BpmnNodePanel :lf="lf"></BpmnNodePanel><div class="node-item"><div class="node-item-icon bpmn-save" @click="saveNode()"></div><span class="node-label">保存</span><div class="node-item-icon bpmn-save" @click="cleanNode()"></div><span class="node-label">清空</span><div class="node-item-icon bpmn-save" @click="reloadNode()"></div><span class="node-label">加载</span><div class="node-item-icon bpmn-save" @click="deleteNode()"></div><span class="node-label">删除</span><div class="node-item-icon bpmn-save" @click="getList()"></div><span class="node-label">获取定义流程</span><div class="node-item-icon bpmn-save" @click="flowRun()"></div><span class="node-label">工作流实例</span></div></template><script>import LogicFlow from'@logicflow/core'import'@logicflow/core/dist/style/index.css'import{ BpmnElement, BpmnXmlAdapter, Menu }from'@logicflow/extension'import'@logicflow/extension/lib/style/index.css'import BpmnNodePanel from"./BpmnNodePanel.vue"import{ addFlow, infoFlow, deleteFlow, getDeployList, flowRun }from"../api/server"import{ addFlowable, addProp, getTypeNameByTag, setValueByTag }from'../utils/xml'exportdefault{data(){return{lf:void0,xmlData:void0,definitionsId:void0,processId:void0,}},components:{ BpmnNodePanel },created(){},mounted(){this.loadFlow()},methods:{loadFlow(){
LogicFlow.use(BpmnElement)
LogicFlow.use(BpmnXmlAdapter)
LogicFlow.use(Menu)//初始化this.lf =newLogicFlow({container:this.$refs.container,stopScrollGraph:true,stopZoomGraph:true,grid:false,keyboard:{enabled:true,},});// this.lf.setDefaultEdgeType('bezier')this.lf.render();},// 保存saveNode(){// 获取xml数据this.xmlData =this.lf.getGraphData();// 添加flowable扩展this.xmlData =addFlowable(this.xmlData)// 判断是否为文档编辑if(this.processId){// 修改为原流程idthis.xmlData =setValueByTag(this.xmlData,'bpmn:definitions','id',this.definitionsId)this.xmlData =setValueByTag(this.xmlData,'bpmn:process','id',this.processId)}else{// 添加节点用户 个人assignee 候选人candidateUsers 候选组候选人candidateGroups 动态设置${employee}// this.xmlData = addProp(this.xmlData, 'bpmn:startEvent', 'flowable:candidateUsers', 'zhao,qian,sun')this.xmlData =addProp(this.xmlData,'bpmn:userTask','flowable:candidateUsers','li,zhou,wang')}const data ={name:'测试流程',xml:this.xmlData
}// 请求后台接口(添加工作流)addFlow(data).then(res=>{
console.log(res)}).catch(err=>{
console.log(err)})},// 清除cleanNode(){this.lf.clearData()},// 重新加载reloadNode(){// 查询数据const data ={id:'ff292b5d-4193-11ee-8e48-502b73dc5fce',name:'测试流程'}infoFlow(data).then(res=>{if(res.result){// 获取processIdconst definitionsNodes =getTypeNameByTag(res.result,'bpmn:definitions')const processNodes =getTypeNameByTag(res.result,'bpmn:process')this.definitionsId = definitionsNodes.id
this.processId = processNodes.id
// 渲染数据this.lf.render(res.result);}
console.log(res)}).catch(err=>{
console.log(err)})},// 删除数据deleteNode(){// 查询数据const data ={id:''}deleteFlow(data).then(res=>{
console.log(res)}).catch(err=>{
console.log(err)})},// 获取数据getList(){getDeployList().then(res=>{
console.log(res)}).catch(err=>{
console.log(err)})},// 流程实例flowRun(){flowRun().then(res=>{
console.log(res)}).catch(err=>{
console.log(err)})},},}</script><style scoped>.container{width:100%;height:100%;}.node-item {position: absolute;top: 350px;left: 10px;width: 50px;padding: 10px;
background-color: white;
box-shadow:00 10px 1px rgb(228,224,219);
border-radius: 6px;
text-align: center;
z-index:101;}.node-item-icon {width: 30px;height: 30px;
margin-left: 10px;
background-size: cover;}.node-label {
font-size: 12px;
margin-top: 5px;
user-select: none;}.bpmn-save {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAA1BJREFUOBFtVE1IVUEYPXOf+tq40Y3vPcmFIdSjIorWoRG0ERWUgnb5FwVhYQSl72oUoZAboxKNFtWiwKRN0M+jpfSzqJAQclHo001tKkjl3emc8V69igP3znzfnO/M9zcDcKT67azmjYWTwl9Vn7Vumeqzj1DVb6cleQY4oAVnIOPb+mKAGxQmKI5CWNJ2aLPatxWa3aB9K7/fB+/Z0jUF6TmMlFLQqrkECWQzOZxYGjTlOl8eeKaIY5yHnFn486xBustDjWT6dG7pmjHOJd+33t0iitTPkK6tEvjxq4h2MozQ6WFSX/LkDUGfFwfhEZj1Auz/U4pyAi5Sznd7uKzznXeVHlI/Aywmk6j7fsUsEuCGADrWARXXwjxWQsUbIupDHJI7kF5dRktg0eN81IbiZXiTESic50iwS+t1oJgL83jAiBupLDCQqwziaWSoAFSeIR3P5Xv5az00wyIn35QRYTwdSYbz8pH8fxUUAtxnFvYmEmgI0wYXUXcCCSpeEVpXlsRhBnCEATxWylL9+EKCAYhe1NGstUa6356kS9NVvt3DU2fd+Wtbm/+lSbylJqsqkSm9CRhvoJVlvKPvF1RKY/FcPn5j4UfIMLn8D4UYb54BNsilTDXKnF4CfTobA0FpoW/LSp306wkXM+XaOJhZaFkcNM82ASNAWMrhrUbRfmyeI1FvRBTpN06WKxa9BK0o2E4Pd3zfBBEwPsv9sQBnmLVbLEIZ/Xe9LYwJu/Er17W6HYVBc7vmuk0xUQ+pqxdom5Fnp55SiytXLPYoMXNM4u4SNSCFWnrVIzKG3EGyMXo6n/BQOe+bX3FClY4PwydVhthOZ9NnS+ntiLh0fxtlUJHAuGaFoVmttpVMeum0p3WEXbcll94l1wM/gZ0Ccczop77VvN2I7TlsZCsuXf1WHvWEhjO8DPtyOVg2/mvK9QqboEth+7pD6NUQC1HN/TwvydGBARi9MZSzLE4b8Ru3XhX2PBxf8E1er2A6516o0w4sIA+lwURhAON82Kwe2iDAC1Watq4XHaGQ7skLcFOtI5lDxuM2gZe6WFIotPAhbaeYlU4to5cuarF1QrcZ/lwrLaCJl66JBocYZnrNlvm2+MBCTmUymPrYZVbjdlr/BxlMjmNmNI3SAAAAAElFTkSuQmCC)
center center no-repeat;cursor: grab;}</style>
2.BpmnNodePanel.vue
<template><div class="node-panel"><!--<div class="node-item" @mousedown="openSelection()"><div class="node-item-icon bpmn-selection"></div><span class="node-label">选区</span></div>--><div class="node-item" @mousedown="addStartNode()"><div class="node-item-icon bpmn-start"></div><span class="node-label">开始节点</span></div><div class="node-item" @mousedown="addUserTask()"><div class="node-item-icon bpmn-user"></div><span class="node-label">普通节点</span></div><!--<div class="node-item" @mousedown="addServiceTask()"><div class="node-item-icon bpmn-service"></div><span class="node-label">系统</span></div>--><!--<div class="node-item" @mousedown="addGateWay()"><div class="node-item-icon bpmn-gateway"></div><span class="node-label">判断</span></div>--><div class="node-item" @mousedown="addEndNode()"><div class="node-item-icon bpmn-end"></div><span class="node-label">结束节点</span></div></div></template><script>import LogicFlow from'@logicflow/core';exportdefault{name:"BpmnNodePanel",data(){return{}},props:{lf: Object,},mounted(){//选区框选使用的let lf =this.$props.lf
lf &&
lf.on("selection:selected",()=>{
lf.updateEditConfig({stopMoveGraph:false,});});},methods:{openSelection(){(this.$props.lf).updateEditConfig({stopMoveGraph:true});},addStartNode(){(this.$props.lf).dnd.startDrag({type:"bpmn:startEvent",text:"开始节点",});},addUserTask(){(this.$props.lf).dnd.startDrag({type:"bpmn:userTask",text:"普通节点",});},addServiceTask(){(this.$props.lf).dnd.startDrag({type:"bpmn:serviceTask",text:"系统",});},addGateWay(){(this.$props.lf).dnd.startDrag({type:"bpmn:exclusiveGateway",text:"判断",});},addEndNode(){(this.$props.lf).dnd.startDrag({type:"bpmn:endEvent",text:"结束节点",});},},};</script><style>.node-panel {position: absolute;top: 100px;left: 10px;width: 50px;padding: 10px;
background-color: white;
box-shadow:00 10px 1px rgb(228,224,219);
border-radius: 6px;
text-align: center;
z-index:101;}.node-item {
margin-bottom: 10px;}.node-item-icon {width: 30px;height: 30px;
margin-left: 10px;
background-size: cover;}.node-label {
font-size: 12px;
margin-top: 5px;
user-select: none;}.bpmn-selection {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=)
center center no-repeat;cursor: grab;}.bpmn-start {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAnBJREFUOBGdVL1rU1EcPfdGBddmaZLiEhdx1MHZQXApraCzQ7GKLgoRBxMfcRELuihWKcXFRcEWF8HBf0DdDCKYRZpnl7p0svLe9Zzbd29eQhTbC8nv+9zf130AT63jvooOGS8Vf9Nt5zxba7sXQwODfkWpkbjTQfCGUd9gIp3uuPP8bZ946g56dYQvnBg+b1HB8VIQmMFrazKcKSvFW2dQTxJnJdQ77urmXWOMBCmXM2Rke4S7UAW+/8ywwFoewmBps2tu7mbTdp8VMOkIRAkKfrVawalJTtIliclFbaOBqa0M2xImHeVIfd/nKAfVq/LGnPss5Kh00VEdSzfwnBXPUpmykNss4lUI9C1ga+8PNrBD5YeqRY2Zz8PhjooIbfJXjowvQJBqkmEkVnktWhwu2SM7SMx7Cj0N9IC0oQXRo8xwAGzQms+xrB/nNSUWVveI48ayrFGyC2+E2C+aWrZHXvOuz+CiV6iycWe1Rd1Q6+QUG07nb5SbPrL4426d+9E1axKjY3AoRrlEeSQo2Eu0T6BWAAr6COhTcWjRaYfKG5csnvytvUr/WY4rrPMB53Uo7jZRjXaG6/CFfNMaXEu75nG47X+oepU7PKJvvzGDY1YLSKHJrK7vFUwXKkaxwhCW3u+sDFMVrIju54RYYbFKpALZAo7sB6wcKyyrd+aBMryMT2gPyD6GsQoRFkGHr14TthZni9ck0z+Pnmee460mHXbRAypKNy3nuMdrWgVKj8YVV8E7PSzp1BZ9SJnJAsXdryw/h5ctboUVi4AFiCd+lQaYMw5z3LGTBKjLQOeUF35k89f58Vv/tGh+l+PE/wG0rgfIUbZK5AAAAABJRU5ErkJggg==)
center center no-repeat;cursor: grab;}.bpmn-end {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAA1BJREFUOBFtVE1IVUEYPXOf+tq40Y3vPcmFIdSjIorWoRG0ERWUgnb5FwVhYQSl72oUoZAboxKNFtWiwKRN0M+jpfSzqJAQclHo001tKkjl3emc8V69igP3znzfnO/M9zcDcKT67azmjYWTwl9Vn7Vumeqzj1DVb6cleQY4oAVnIOPb+mKAGxQmKI5CWNJ2aLPatxWa3aB9K7/fB+/Z0jUF6TmMlFLQqrkECWQzOZxYGjTlOl8eeKaIY5yHnFn486xBustDjWT6dG7pmjHOJd+33t0iitTPkK6tEvjxq4h2MozQ6WFSX/LkDUGfFwfhEZj1Auz/U4pyAi5Sznd7uKzznXeVHlI/Aywmk6j7fsUsEuCGADrWARXXwjxWQsUbIupDHJI7kF5dRktg0eN81IbiZXiTESic50iwS+t1oJgL83jAiBupLDCQqwziaWSoAFSeIR3P5Xv5az00wyIn35QRYTwdSYbz8pH8fxUUAtxnFvYmEmgI0wYXUXcCCSpeEVpXlsRhBnCEATxWylL9+EKCAYhe1NGstUa6356kS9NVvt3DU2fd+Wtbm/+lSbylJqsqkSm9CRhvoJVlvKPvF1RKY/FcPn5j4UfIMLn8D4UYb54BNsilTDXKnF4CfTobA0FpoW/LSp306wkXM+XaOJhZaFkcNM82ASNAWMrhrUbRfmyeI1FvRBTpN06WKxa9BK0o2E4Pd3zfBBEwPsv9sQBnmLVbLEIZ/Xe9LYwJu/Er17W6HYVBc7vmuk0xUQ+pqxdom5Fnp55SiytXLPYoMXNM4u4SNSCFWnrVIzKG3EGyMXo6n/BQOe+bX3FClY4PwydVhthOZ9NnS+ntiLh0fxtlUJHAuGaFoVmttpVMeum0p3WEXbcll94l1wM/gZ0Ccczop77VvN2I7TlsZCsuXf1WHvWEhjO8DPtyOVg2/mvK9QqboEth+7pD6NUQC1HN/TwvydGBARi9MZSzLE4b8Ru3XhX2PBxf8E1er2A6516o0w4sIA+lwURhAON82Kwe2iDAC1Watq4XHaGQ7skLcFOtI5lDxuM2gZe6WFIotPAhbaeYlU4to5cuarF1QrcZ/lwrLaCJl66JBocYZnrNlvm2+MBCTmUymPrYZVbjdlr/BxlMjmNmNI3SAAAAAElFTkSuQmCC)
center center no-repeat;cursor: grab;}.bpmn-user {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==)
center center no-repeat;cursor: grab;}.bpmn-gateway {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAAHeEJUAAAAABGdBTUEAALGPC/xhBQAAAvVJREFUOBGNVEFrE0EU/mY3bQoiFlOkaUJrQUQoWMGePLX24EH0IIoHKQiCV0G8iE1covgLiqA/QTzVm1JPogc9tIJYFaQtlhQxqYjSpunu+L7JvmUTU3AgmTfvffPNN++9WSA1DO182f6xwILzD5btfAoQmwL5KJEwiQyVbSVZ0IgRyV6PTpIJ81E5ZvqfHQR0HUOBHW4L5Et2kQ6Zf7iAOhTFAA8s0pEP7AXO1uAA52SbqGk6h/6J45LaLhO64ByfcUzM39V7ZiAdS2yCePPEIQYvTUHqM/n7dgQNfBKWPjpF4ISk8q3J4nB11qw6X8l+FsF3EhlkEMfrjIer3wJTLwS2aCNcj4DbGxXTw00JmAuO+Ni6bBxVUCvS5d9aa04+so4pHW5jLTywuXAL7jJ+D06sl82Sgl2JuVBQn498zkc2bGKxULHjCnSMadBKYDYYHAtsby1EQ5lNGrQd4Y3v4Zo0XdGEmDno46yCM9Tk+RiJmUYHS/aXHPNTcjxcbTFna000PFJHIVZ5lFRqRpJWk9/+QtlOUYJj9HG5pVFEU7zqIYDVsw2s+AJaD8wTd2umgSCCyUxgGsS1Y6TBwXQQTFuZaHcd8gAGioE90hlsY+wMcs30RduYtxanjMGal8H5dMW67dmT1JFtYUEe8LiQLRsPZ6IIc7A4J5tqco3T0pnv/4u0kyzrYUq7gASuEyI8VXKvB9Odytv6jS/PNaZBln0nioJG/AVQRZvApOdhjj3Jt8QC8Im09SafwdBdvIpztpxWxpeKCC+EsFdS8DCyuCn2munFpL7ctHKp+Xc5cMybeIyMAN33SPL3ZR9QV1XVwLyzHm6Iv0/yeUuUb7PPlZC4D4HZkeu6dpF4v9j9MreGtMbxMMRLIcjJic9yHi7WQ3yVKzZVWUr5UrViJvn1FfUlwe/KYVfYyWRLSGNu16hR01U9IacajXPei0wx/5BqgInvJN+MMNtNme7ReU9SBbgntovn0kKHpFg7UogZvaZiOue/q1SBo9ktHzQAAAAASUVORK5CYII=)
center center no-repeat;cursor: grab;}.bpmn-service {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAYAAADgKtSgAAAAAXNSR0IArs4c6QAAAm9JREFUSEu1lTFo1GAUx38vZ6sOooIoVsWKk23SCp1UkIrg0EHs0M5OOolY9NJz6XXpNaeidOhQB3G1oCLUTXRxK9pe7lykk7YKhdJZuDzJXXMkaXKpBd+Y7//93sv/ve/7hP8YshO2WdKiGPQ0tMpvVTaqBSlm7f0X+EQAU4/JXcNNR5/jsRoATEcnBFqVKhSrtkz6ycySDkqOKTcvF+N/sq1yy9FXwEjDAY9JMRgDDiRYsIJQQHkGdAE11xYzrIvAw+AsP1PW511bRoO1KLysIyh+5ckhfEK5AOxNEig8rNpSSoT7H62yfkQZjGxWCl4nc7Ux2egu6r6D+xnyYBY41q7JkcrPPdXje/6wFga7tqROlOXoMtAX6OPaxkazrNekTpdCtxi0Rg7htpuXuTSXrJIOYLAYrh6DH/5ZqI7LQgNuOboADMUhRgcnl8dktV1zrbIuogzENOuuLUcDeGv8WiKh4ualP2tqrGmdQbiTDk8WbLq2HM6EO/oGuBHTfXFtGWh67t8dOU6jnAKuhoTDri1v0xKcL2l33eArcGhL8wHhFx4/3XEpRCahd1r7DWEpNKdLRidXlu7JZlICq6wvUG4Ga16O3tp9+ZY656aj6wJHQrD3Rge34o21HH0CjashiPbHv/ex9hh1atuqFCpAVet8J8cZUU7E7GtuEUbdvMwnVm45qlkNzFwPJYh4bpZ0WAxehm7BFeBsG2B0vV3ljQM1rZcR5gRmKrbM9jl6HcgrXAr97megXLHlnRVcdjFw06WEMB9pX/WB+D43YuuZS32J/ARhr1OnJTFZ8w29C9SBNfV4vetnLrNpOxT8BWh07BjujplpAAAAAElFTkSuQmCC)
center center no-repeat;cursor: grab;}</style>
3.xml.js
/**
* 添加flowable扩展
* @param {*} xmlstr
* @returns
*/exportfunctionaddFlowable(xmlstr){const part1 = xmlstr.slice(0,43);// 从开头到指定位置之前的部分const part2 = xmlstr.slice(43);// 从指定位置到末尾的部分const newString = part1 +'xmlns:flowable="http://flowable.org/bpmn" '+ part2;// 拼接成新的字符串return newString
}/**
* 添加属性信息
* @param {*} xmlstr
* @returns
*/exportfunctionaddProp(xmlstr, Elements, key, value){// 创建一个XML文档对象const parser =newDOMParser();const xmlDoc = parser.parseFromString(xmlstr,'application/xml');// 查找元素const userTaskElement = xmlDoc.getElementsByTagName(Elements);for(let i =0; i < userTaskElement.length; i++){if(!userTaskElement[i].attributes[key]){
userTaskElement[i].setAttribute(key, value);}}// 将修改后的XML文档转换回字符串const xmlSerializer =newXMLSerializer();const modifiedXmlString = xmlSerializer.serializeToString(xmlDoc);return modifiedXmlString;}/**
*根据标签名称返回xml内容,标签名必须唯一,若不满足,修改方法
* @param {*} xmlstr xml字符串
* @param {element} tagName 标签名称,如<Name>
*/exportfunctiongetTypeNameByTag(xmlstr, tagName){const parser =newDOMParser()const xmlDoc = parser.parseFromString(xmlstr,'application/xml')const nameNodes = xmlDoc.getElementsByTagName(tagName)[0]if(nameNodes){return nameNodes
}else{returnfalse}}/**
* 根据标签名称修改内容
* @param {*} xmlstr xml字符串
* @param {element} tagName 标签名称,如<Name>
* @param {*} key 修改对应key
* @param {*} value 修改值value
* @returns
*/exportfunctionsetValueByTag(xmlstr, tagName, key, value){// 字符串转xmlconst parser =newDOMParser()const xmlDoc = parser.parseFromString(xmlstr,'application/xml')const nameNodes = xmlDoc.getElementsByTagName(tagName)[0]
nameNodes.setAttribute(key, value);// xml转字符串const s =newXMLSerializer();const xml = s.serializeToString(xmlDoc);return xml;}
4.server.js
import request from'../utils/request';const url ='http://localhost:8088'/**
* 添加(编辑)工作流
* @param {*} data
* @returns
*/exportfunctionaddFlow(data){returnrequest({url: url +'/flow/addFlow',method:'post',
data,});}/**
* 查询工作流
* @param {*} data
* @returns
*/exportfunctioninfoFlow(data){returnrequest({url: url +'/flow/infoFlow',method:'post',
data,});}/**
* 删除工作流
* @param {*} data
* @returns
*/exportfunctiondeleteFlow(data){returnrequest({url: url +'/flow/deleteFlow',method:'post',
data,});}/**
* 获取工作流定义
* @param {*} data
* @returns
*/exportfunctiongetDeployList(data){returnrequest({url: url +'/flow/getDeployList',method:'post',
data,});}/**
* 工作流实例
* @param {*} data
* @returns
*/exportfunctionflowRun(data){returnrequest({url: url +'/flow/deploymentRun',method:'post',
data,});}
5.request.js
import axios from'axios';const service = axios.create({});
service.defaults.timeout =20000;// 请求拦截器
service.interceptors.request.use((config)=>{return config;},(error)=>{
console.log(error);return Promise.reject(error);});// 响应拦截器
service.interceptors.response.use((response)=>{return response.data;},(error)=>{return Promise.reject(error);});exportdefault service;
四、后端代码(Flowable)
1.FlowController .java
@RestControllerpublicclassFlowController{@AutowiredFlowService flowService;// 工作流部署(添加、编辑)@CrossOrigin@PostMapping("/flow/addFlow")publicResultaddFlow(@RequestBodyMap<String,String> map){returnflowService.AddFlow(map.get("id"), map.get("name"), map.get("xml"), map.get("key"));}// 工作流返回@CrossOrigin@PostMapping("/flow/infoFlow")publicResultinfoFlow(@RequestBodyMap<String,String> map){returnflowService.InfoFlow(map.get("id"), map.get("name"));}// 工作流删除@CrossOrigin@PostMapping("/flow/deleteFlow")publicResultdeleteFlow(@RequestBodyMap<String,String> map){returnflowService.DeleteFlow(map.get("id"));}// 工作流查询@CrossOrigin@PostMapping("/flow/getDeployList")publicResultgetDeployList(){returnflowService.GetDeployList();}// 流程实例@CrossOrigin@PostMapping("/flow/deploymentRun")publicResultdeploymentRun(@RequestBodyMap<String,String> map){returnflowService.DeploymentRun(map.get("userId"), map.get("key"));}// 流程查询@CrossOrigin@PostMapping("/flow/infoTask")publicResultInfoTask(@RequestBodyMap<String,String> map){returnflowService.InfoTask(map.get("userId"));}// 流程执行@CrossOrigin@PostMapping("/flow/makeTask")publicResultMakeTask(@RequestBodyMap<String,String> map){returnflowService.MakeTask(map.get("userId"));}// 流程历史@CrossOrigin@PostMapping("/flow/taskHistory")publicResultTaskHistory(){returnflowService.TaskHistory();}// 测试@CrossOrigin@PostMapping("/test")publicResulttest(@RequestBodyAskForLeaveVO test){return flowService.test(test);}}
2.FlowService .java
@ServicepublicclassFlowService{@AutowiredProcessEngine processEngine;@AutowiredFlowTreeService flowTreeService;/**
* 工作流部署(添加、编辑)
* @param name 名称
* @param xml xml
* @return
*/@TransactionalpublicResultAddFlow(String id,String name,String xml,String key){try{RepositoryService repositoryService = processEngine.getRepositoryService();// 创建新流程Deployment deployment = repositoryService.createDeployment().addString(name +".bpmn", xml).deploy();// 将工作流信息保存到流程树表flowTreeService.AutoSave(id, deployment.getId(), key);System.out.println("id : "+ id);System.out.println("添加id : "+ deployment.getId());System.out.println("添加key : "+ key);returnResult.ok("添加成功", deployment.getId());}catch(Exception e){
e.printStackTrace();returnResult.error("添加失败");}}/**
* 工作流返回(返回xml)
* @param id 查询id
* @param name 名称
* @return
*/@TransactionalpublicResultInfoFlow(String id,String name){try{// 流程查询RepositoryService repositoryService = processEngine.getRepositoryService();InputStream resourceAsStream = repositoryService.getResourceAsStream(id, name +".bpmn");// Java流转StringString resultXml =newBufferedReader(newInputStreamReader(resourceAsStream,"utf-8")).lines().collect(Collectors.joining(System.lineSeparator()));returnResult.ok("查询成功", resultXml);}catch(Exception e){
e.printStackTrace();}returnResult.error("查询失败");}/**
* 工作流删除
* @param id
* @return
*/@TransactionalpublicResultDeleteFlow(String id){try{RepositoryService repositoryService = processEngine.getRepositoryService();// 设置为TRUE 级联删除流程定义,及时流程有实例启动,也可以删除,设置为false 非级联删除操作。
repositoryService.deleteDeployment(id);System.out.println("删除id : "+ id);returnResult.ok("删除成功", id);}catch(Exception e){
e.printStackTrace();returnResult.error("删除失败");}}/**
* 工作流部署列表查询
* @return
*/@TransactionalpublicResultGetDeployList(){try{RepositoryService repositoryService = processEngine.getRepositoryService();List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();System.out.println("list : "+ list);returnResult.ok("查询成功");}catch(Exception e){
e.printStackTrace();returnResult.error("查询失败");}}/**
* 启动流程实例
* @param userId 发起人
* @param key 流程key
* @return
*/@TransactionalpublicResultDeploymentRun(String userId,String key){try{// Map<String, Object> variables = new HashMap<String, Object>();// variables.put("employee", userId);RuntimeService runtimeService = processEngine.getRuntimeService();ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key);//获取流程实例的相关信息System.out.println("流程定义的id = "+ processInstance.getProcessDefinitionId());System.out.println("流程实例的id = "+ processInstance.getId());returnResult.ok("成功","流程实例id = "+ processInstance.getId());}catch(Exception e){
e.printStackTrace();returnResult.error("失败");}}/**
* 查询流程任务
* @param userId
* @return
*/@TransactionalpublicResultInfoTask(String userId){try{TaskService taskService = processEngine.getTaskService();// 查询多人任务List<Task> taskList = taskService.createTaskQuery().taskCandidateUser(userId).list();System.out.println("taskList"+ taskList);//遍历任务列表for(Task task:taskList){System.out.println("流程定义id = "+ task.getProcessDefinitionId());System.out.println("流程实例id = "+ task.getProcessInstanceId());System.out.println("任务id = "+ task.getId());System.out.println("任务名称 = "+ task.getName());}returnResult.ok("成功");}catch(Exception e){
e.printStackTrace();returnResult.error("失败");}}/**
* 执行流程任务
* @param userId
* @return
*/@TransactionalpublicResultMakeTask(String userId){try{TaskService taskService = processEngine.getTaskService();// 查询个人任务List<Task> list = taskService.createTaskQuery().taskCandidateUser(userId).list();System.out.println("taskList"+ list);for(Task task : list){
taskService.complete(task.getId());System.out.println("task.getId()"+ task.getId());}returnResult.ok("成功");}catch(Exception e){
e.printStackTrace();returnResult.error("失败");}}/**
* 查询历史流程
* @param
* @return
*/@TransactionalpublicResultTaskHistory(){try{HistoryService historyService = processEngine.getHistoryService();List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()// .processInstanceId("12501") // 特定的实例.finished()// 完成的// .orderByHistoricActivityInstanceEndTime().asc() // 根据实例完成时间升序排列.list();for(HistoricActivityInstance activity : activities){System.out.println("id:"+ activity.getActivityId()+" 任务名:"+ activity.getActivityName()+" 类型:"+ activity.getActivityType()+" 持续时间:"+ activity.getDurationInMillis());}returnResult.ok("成功");}catch(Exception e){
e.printStackTrace();returnResult.error("失败");}}}
版权归原作者 王八八。 所有, 如有侵权,请联系我们删除。