欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue+LogicFlow+Flowable實(shí)現(xiàn)工作流

 更新時(shí)間:2023年12月22日 16:15:42   作者:王八八。  
本文主要介紹了Vue+LogicFlow+Flowable實(shí)現(xiàn)工作流,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、實(shí)現(xiàn)效果

前端使用LogicFlow框架繪制流程圖,可以導(dǎo)出為xml工作流標(biāo)準(zhǔn)格式數(shù)據(jù),通過(guò)xml文件傳遞到后端進(jìn)行Flowable流程注冊(cè),并保存到數(shù)據(jù)庫(kù)中。

在這里插入圖片描述

二、BPM傳輸文件格式(.xml)

如需添加承辦人的話,需要在LogicFlow導(dǎo)出文件的基礎(chǔ)上手動(dòng)添加xmlns:flowable="http://flowable.org/bpmn"flowable插件,不然后臺(tái)無(wú)法識(shí)別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="開始節(jié)點(diǎn)" flowable:candidateUsers="admin,admin1,admin2">	
      <bpmn:outgoing>Flow_a3e7d0c</bpmn:outgoing>	
    </bpmn:startEvent>	
    <bpmn:userTask id="Activity_602107f" name="普通節(jié)點(diǎn)" 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="結(jié)束節(jié)點(diǎn)">	
      <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">工作流實(shí)例</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'

export default {
    data() {
        return {
            lf: void 0,
            xmlData: void 0,
            definitionsId: void 0,
            processId: void 0,
        }
    },
    components: { BpmnNodePanel },
    created() {},
    mounted() {
        this.loadFlow()
    },
    methods: {
        loadFlow() {
            LogicFlow.use(BpmnElement)
            LogicFlow.use(BpmnXmlAdapter)
            LogicFlow.use(Menu)

            //初始化
            this.lf = new LogicFlow({
                container: this.$refs.container,
                stopScrollGraph: true,
                stopZoomGraph: true,
                grid: false,
                keyboard: {
                    enabled: true,
                },
            });
            // this.lf.setDefaultEdgeType('bezier')
            this.lf.render();
        },
        // 保存
        saveNode() { 
            // 獲取xml數(shù)據(jù)
            this.xmlData = this.lf.getGraphData();

            // 添加flowable擴(kuò)展
            this.xmlData = addFlowable(this.xmlData)

            // 判斷是否為文檔編輯
            if (this.processId) {
                // 修改為原流程id
                this.xmlData = setValueByTag(this.xmlData, 'bpmn:definitions', 'id', this.definitionsId)
                this.xmlData = setValueByTag(this.xmlData, 'bpmn:process', 'id', this.processId)
            } else { 
                // 添加節(jié)點(diǎn)用戶 個(gè)人assignee  候選人candidateUsers 候選組候選人candidateGroups 動(dòng)態(tài)設(shè)置${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: '測(cè)試流程',
                xml: this.xmlData
            }
            
            // 請(qǐng)求后臺(tái)接口(添加工作流)
            addFlow(data)
                .then(res => {
                    console.log(res)
                })
                .catch(err => {
                    console.log(err)
                })
        },
        // 清除
        cleanNode() {
            this.lf.clearData()
        },
        // 重新加載
        reloadNode() {
            // 查詢數(shù)據(jù)
            const data = {
                id: 'ff292b5d-4193-11ee-8e48-502b73dc5fce',
                name: '測(cè)試流程'
            }
            infoFlow(data)
                .then(res => {
                    if (res.result) {
                        // 獲取processId
                        const definitionsNodes = getTypeNameByTag(res.result, 'bpmn:definitions')
                        const processNodes = getTypeNameByTag(res.result, 'bpmn:process')
                        this.definitionsId = definitionsNodes.id
                        this.processId = processNodes.id
                        // 渲染數(shù)據(jù)
                        this.lf.render(res.result);
                    }
                    console.log(res)
                })
                .catch(err => {
                    console.log(err)
                })
        },
        // 刪除數(shù)據(jù)
        deleteNode() { 
            // 查詢數(shù)據(jù)
            const data = {
                id: ''
            }
            deleteFlow(data)
                .then(res => {
                    console.log(res)
                })
                .catch(err => {
                    console.log(err)
                })
        }, 
        // 獲取數(shù)據(jù)
        getList() { 
            getDeployList()
                .then(res => {
                    console.log(res)
                })
                .catch(err => {
                    console.log(err)
                })
        },
        // 流程實(shí)例
        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: 0 0 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">選區(qū)</span>
    </div> -->
    <div class="node-item" @mousedown="addStartNode()">
      <div class="node-item-icon bpmn-start"></div>
      <span class="node-label">開始節(jié)點(diǎn)</span>
    </div>
    <div class="node-item" @mousedown="addUserTask()">
      <div class="node-item-icon bpmn-user"></div>
      <span class="node-label">普通節(jié)點(diǎn)</span>
    </div>
    <!-- <div class="node-item" @mousedown="addServiceTask()">
      <div class="node-item-icon bpmn-service"></div>
      <span class="node-label">系統(tǒng)</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">結(jié)束節(jié)點(diǎn)</span>
    </div>
  </div>
</template>
<script>
import LogicFlow from '@logicflow/core';
export default {
  name: "BpmnNodePanel",
  data() {
    return {}
  },
  props: {
    lf: Object,
  },

  mounted() {
    //選區(qū)框選使用的
    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: "開始節(jié)點(diǎn)",
      });
    },
    addUserTask() {
      (this.$props.lf).dnd.startDrag({
        type: "bpmn:userTask",
        text: "普通節(jié)點(diǎn)", 
      });
    },
    addServiceTask() {
      (this.$props.lf).dnd.startDrag({
        type: "bpmn:serviceTask",
        text: "系統(tǒng)",
      });
    },
    addGateWay() {
      (this.$props.lf).dnd.startDrag({
        type: "bpmn:exclusiveGateway",
        text: "判斷",
      });
    },
    addEndNode() {
      (this.$props.lf).dnd.startDrag({
        type: "bpmn:endEvent",
        text: "結(jié)束節(jié)點(diǎn)",
      });
    },
  },
};
</script>
<style>
.node-panel {
  position: absolute;
  top: 100px;
  left: 10px;
  width: 50px;
  padding: 10px;
  background-color: white;
  box-shadow: 0 0 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擴(kuò)展
 * @param {*} xmlstr 
 * @returns 
 */
export function addFlowable(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 
 */
export function addProp(xmlstr, Elements, key, value) {
    // 創(chuàng)建一個(gè)XML文檔對(duì)象
    const parser = new DOMParser();
    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文檔轉(zhuǎn)換回字符串
    const xmlSerializer = new XMLSerializer();
    const modifiedXmlString = xmlSerializer.serializeToString(xmlDoc);

    return modifiedXmlString;
}

/**
 *根據(jù)標(biāo)簽名稱返回xml內(nèi)容,標(biāo)簽名必須唯一,若不滿足,修改方法
 * @param {*} xmlstr xml字符串
 * @param {element} tagName 標(biāo)簽名稱,如<Name>
 */
export function getTypeNameByTag(xmlstr, tagName) {
    const parser = new DOMParser()
    const xmlDoc = parser.parseFromString(xmlstr, 'application/xml')
    const nameNodes = xmlDoc.getElementsByTagName(tagName)[0]
    if (nameNodes) {
        return nameNodes
    } else {
        return false
    }
}

/**
 * 根據(jù)標(biāo)簽名稱修改內(nèi)容
 * @param {*} xmlstr xml字符串
 * @param {element} tagName 標(biāo)簽名稱,如<Name>
 * @param {*} key 修改對(duì)應(yīng)key
 * @param {*} value 修改值value
 * @returns 
 */
export function setValueByTag(xmlstr, tagName, key, value) {
    // 字符串轉(zhuǎn)xml
    const parser = new DOMParser()
    const xmlDoc = parser.parseFromString(xmlstr, 'application/xml')
    const nameNodes = xmlDoc.getElementsByTagName(tagName)[0]
    nameNodes.setAttribute(key, value);
    // xml轉(zhuǎn)字符串
    const s = new XMLSerializer();
    const xml = s.serializeToString(xmlDoc);

    return xml;
}

4.server.js

import request from '../utils/request';
const url = 'http://localhost:8088'

/**
 * 添加(編輯)工作流
 * @param {*} data
 * @returns
 */
export function addFlow(data) {
    return request({
        url: url + '/flow/addFlow',
        method: 'post',
        data,
    });
}

/**
 * 查詢工作流
 * @param {*} data
 * @returns
 */
export function infoFlow(data) {
    return request({
        url: url + '/flow/infoFlow',
        method: 'post',
        data,
    });
}

/**
 * 刪除工作流
 * @param {*} data
 * @returns
 */
export function deleteFlow(data) {
    return request({
        url: url + '/flow/deleteFlow',
        method: 'post',
        data,
    });
}

/**
 * 獲取工作流定義
 * @param {*} data
 * @returns
 */
export function getDeployList(data) {
    return request({
        url: url + '/flow/getDeployList',
        method: 'post',
        data,
    });
}

/**
 * 工作流實(shí)例
 * @param {*} data
 * @returns
 */
export function flowRun(data) {
    return request({
        url: url + '/flow/deploymentRun',
        method: 'post',
        data,
    });
}

5.request.js

import axios from 'axios';
const service = axios.create({});
service.defaults.timeout = 20000;
// 請(qǐng)求攔截器
service.interceptors.request.use(
    (config) => {
        return config;
    },
    (error) => {
        console.log(error);
        return Promise.reject(error);
    }
);
// 響應(yīng)攔截器
service.interceptors.response.use(
    (response) => {
        return response.data;
    },
    (error) => {
        return Promise.reject(error);
    }
);

export default service;

四、后端代碼(Flowable)

1.FlowController .java

@RestController
public class FlowController {
    @Autowired
    FlowService flowService;

    // 工作流部署(添加、編輯)
    @CrossOrigin
    @PostMapping("/flow/addFlow")
    public Result addFlow(@RequestBody Map<String,String> map){
        return flowService.AddFlow(map.get("id"), map.get("name"), map.get("xml"), map.get("key"));
    }

    // 工作流返回
    @CrossOrigin
    @PostMapping("/flow/infoFlow")
    public Result infoFlow(@RequestBody Map<String,String> map) {
        return flowService.InfoFlow(map.get("id"), map.get("name"));
    }

    // 工作流刪除
    @CrossOrigin
    @PostMapping("/flow/deleteFlow")
    public Result deleteFlow(@RequestBody Map<String,String> map) {
        return flowService.DeleteFlow(map.get("id"));
    }

    // 工作流查詢
    @CrossOrigin
    @PostMapping("/flow/getDeployList")
    public Result getDeployList() {
        return flowService.GetDeployList();
    }

    // 流程實(shí)例
    @CrossOrigin
    @PostMapping("/flow/deploymentRun")
    public Result deploymentRun(@RequestBody Map<String,String> map) {
        return flowService.DeploymentRun(map.get("userId"), map.get("key"));
    }

    // 流程查詢
    @CrossOrigin
    @PostMapping("/flow/infoTask")
    public Result InfoTask(@RequestBody Map<String,String> map) {
        return flowService.InfoTask(map.get("userId"));
    }

    // 流程執(zhí)行
    @CrossOrigin
    @PostMapping("/flow/makeTask")
    public Result MakeTask(@RequestBody Map<String,String> map) {
        return flowService.MakeTask(map.get("userId"));
    }

    // 流程歷史
    @CrossOrigin
    @PostMapping("/flow/taskHistory")
    public Result TaskHistory() {
        return flowService.TaskHistory();
    }

    // 測(cè)試
    @CrossOrigin
    @PostMapping("/test")
    public Result test(@RequestBody AskForLeaveVO test) {
        return flowService.test(test);
    }


}

2.FlowService .java

@Service
public class FlowService {
    @Autowired
    ProcessEngine processEngine;
    @Autowired
    FlowTreeService flowTreeService;

    /**
     * 工作流部署(添加、編輯)
     * @param name 名稱
     * @param xml xml
     * @return
     */
    @Transactional
    public Result AddFlow(String id, String name, String xml, String key){
        try {
            RepositoryService repositoryService = processEngine.getRepositoryService();
            // 創(chuàng)建新流程
            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);
            return Result.ok("添加成功", deployment.getId());

        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("添加失敗");
        }
    }

    /**
     * 工作流返回(返回xml)
     * @param id 查詢id
     * @param name 名稱
     * @return
     */
    @Transactional
    public Result InfoFlow(String id, String name) {
        try {
            // 流程查詢
            RepositoryService repositoryService = processEngine.getRepositoryService();
            InputStream resourceAsStream = repositoryService.getResourceAsStream(id, name + ".bpmn");
            // Java流轉(zhuǎn)String
            String resultXml = new BufferedReader(new InputStreamReader(resourceAsStream,"utf-8"))
                    .lines().collect(Collectors.joining(System.lineSeparator()));

            return Result.ok("查詢成功", resultXml);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.error("查詢失敗");
    }

    /**
     * 工作流刪除
     * @param id
     * @return
     */
    @Transactional
    public  Result DeleteFlow(String id){
        try {
            RepositoryService repositoryService = processEngine.getRepositoryService();
            // 設(shè)置為TRUE 級(jí)聯(lián)刪除流程定義,及時(shí)流程有實(shí)例啟動(dòng),也可以刪除,設(shè)置為false 非級(jí)聯(lián)刪除操作。
            repositoryService.deleteDeployment(id);
            System.out.println("刪除id : " + id);
            return Result.ok("刪除成功", id);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("刪除失敗");
        }
    }

    /**
     * 工作流部署列表查詢
     * @return
     */
    @Transactional
    public Result GetDeployList() {
        try {
            RepositoryService repositoryService = processEngine.getRepositoryService();
            List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
            System.out.println("list : " + list);
            return Result.ok("查詢成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("查詢失敗");
        }
    }

    /**
     * 啟動(dòng)流程實(shí)例
     * @param userId 發(fā)起人
     * @param key 流程key
     * @return
     */
    @Transactional
    public Result DeploymentRun(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);
            //獲取流程實(shí)例的相關(guān)信息
            System.out.println("流程定義的id = " + processInstance.getProcessDefinitionId());
            System.out.println("流程實(shí)例的id = " + processInstance.getId());
            return Result.ok("成功", "流程實(shí)例id = " + processInstance.getId());
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("失敗");
        }
    }

    /**
     * 查詢流程任務(wù)
     * @param userId
     * @return
     */
    @Transactional
    public Result InfoTask(String userId){
        try {
            TaskService taskService = processEngine.getTaskService();
            // 查詢多人任務(wù)
            List<Task> taskList = taskService.createTaskQuery().taskCandidateUser(userId).list();
            System.out.println("taskList" + taskList);
            //遍歷任務(wù)列表
            for(Task task:taskList){
                System.out.println("流程定義id = " + task.getProcessDefinitionId());
                System.out.println("流程實(shí)例id = " + task.getProcessInstanceId());
                System.out.println("任務(wù)id = " + task.getId());
                System.out.println("任務(wù)名稱 = " + task.getName());
            }
            return Result.ok("成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("失敗");
        }
    }

    /**
     * 執(zhí)行流程任務(wù)
     * @param userId
     * @return
     */
    @Transactional
    public Result MakeTask(String userId){
        try {
            TaskService taskService = processEngine.getTaskService();
            // 查詢個(gè)人任務(wù)
            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());
            }
            return Result.ok("成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("失敗");
        }
    }

    /**
     * 查詢歷史流程
     * @param
     * @return
     */
    @Transactional
    public Result TaskHistory(){
        try {
            HistoryService historyService = processEngine.getHistoryService();
            List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()
                    // .processInstanceId("12501") // 特定的實(shí)例
                    .finished() // 完成的
                            // .orderByHistoricActivityInstanceEndTime().asc() // 根據(jù)實(shí)例完成時(shí)間升序排列
                    .list();

            for (HistoricActivityInstance activity : activities) {
                System.out.println("id:" + activity.getActivityId() + "  任務(wù)名:" + activity.getActivityName() + "  類型:" + activity.getActivityType() + "  持續(xù)時(shí)間:" + activity.getDurationInMillis());
            }
            return Result.ok("成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("失敗");
        }
    }
}

到此這篇關(guān)于Vue+LogicFlow+Flowable實(shí)現(xiàn)工作流的文章就介紹到這了,更多相關(guān)Vue 工作流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue中this.$http.post()跨域和請(qǐng)求參數(shù)丟失的解決

    vue中this.$http.post()跨域和請(qǐng)求參數(shù)丟失的解決

    這篇文章主要介紹了vue中this.$http.post()跨域和請(qǐng)求參數(shù)丟失的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue+axios 前端實(shí)現(xiàn)的常用攔截的代碼示例

    vue+axios 前端實(shí)現(xiàn)的常用攔截的代碼示例

    這篇文章主要介紹了vue+axios 前端實(shí)現(xiàn)的常用攔截的代碼示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • 詳解ESLint在Vue中的使用小結(jié)

    詳解ESLint在Vue中的使用小結(jié)

    ESLint是一個(gè)QA工具,這篇文章主要介紹了詳解ESLint在Vue中的使用小結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10
  • vue 在服務(wù)器端直接修改請(qǐng)求的接口地址

    vue 在服務(wù)器端直接修改請(qǐng)求的接口地址

    這篇文章主要介紹了vue 在服務(wù)器端直接修改請(qǐng)求的接口地址的方法,幫助大家更好的理解和使用vue,感興趣的朋友可以了解下
    2020-12-12
  • VUE2.0+Element-UI+Echarts封裝的組件實(shí)例

    VUE2.0+Element-UI+Echarts封裝的組件實(shí)例

    下面小編就為大家分享一篇VUE2.0+Element-UI+Echarts封裝的組件實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • Vue2響應(yīng)式系統(tǒng)介紹

    Vue2響應(yīng)式系統(tǒng)介紹

    這篇文章主要介紹了Vue2響應(yīng)式系統(tǒng),響應(yīng)式系統(tǒng)主要實(shí)現(xiàn)某個(gè)依賴了數(shù)據(jù)的函數(shù),當(dāng)所依賴的數(shù)據(jù)改變的時(shí)候,該函數(shù)要重新執(zhí)行,下文更多相關(guān)介紹需要的小伙伴可以參考一下
    2022-04-04
  • Vue組件間的樣式?jīng)_突污染問(wèn)題詳解

    Vue組件間的樣式?jīng)_突污染問(wèn)題詳解

    默認(rèn)情況下,寫在.vue組件中的樣式會(huì)全局生效,因此很容易造成多個(gè)組件之間的樣式?jīng)_突問(wèn)題。導(dǎo)致組件之間樣式?jīng)_突的根本原因,我們接下來(lái)探究一下
    2022-11-11
  • Vue實(shí)現(xiàn)驗(yàn)證碼登錄的方法實(shí)例

    Vue實(shí)現(xiàn)驗(yàn)證碼登錄的方法實(shí)例

    最近在自己寫頁(yè)面,然后寫登錄注冊(cè)UI的時(shí)候需要一個(gè)驗(yàn)證碼組件,去搜一下沒(méi)找到什么合適的,于是自己寫一個(gè),這篇文章主要給大家介紹了關(guān)于Vue實(shí)現(xiàn)驗(yàn)證碼登錄的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • 正確更改Ant?Design?of?Vue樣式的問(wèn)題

    正確更改Ant?Design?of?Vue樣式的問(wèn)題

    這篇文章主要介紹了正確更改Ant?Design?of?Vue樣式的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • Vue通過(guò)vue-router實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)的全過(guò)程

    Vue通過(guò)vue-router實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)的全過(guò)程

    這篇文章主要介紹了Vue通過(guò)vue-router實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)的操作步驟,文中有詳細(xì)的代碼示例和圖文供大家參考,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,感興趣的朋友可以參考下
    2024-04-04

最新評(píng)論