feat: add flowChart components

This commit is contained in:
xiaoxian521 2021-04-15 23:10:28 +08:00
parent f886a38694
commit c7f6ff6514
21 changed files with 1029 additions and 17 deletions

25
package-lock.json generated
View File

@ -390,9 +390,18 @@
}
},
"@logicflow/core": {
"version": "0.2.9",
"resolved": "https://registry.npm.taobao.org/@logicflow/core/download/@logicflow/core-0.2.9.tgz",
"integrity": "sha1-wTU8PV0P58QNm7jPq+PMbVmF5PE="
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@logicflow/core/-/core-0.3.0.tgz",
"integrity": "sha512-FPRTuj0y6Yny+YDZ+faTzA8pZyouEWX1Vr6rH91wJR0J3NOHgb7pV/TJoHSosavFuyyw87nLw9UsyUUgHKVV+A=="
},
"@logicflow/extension": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@logicflow/extension/-/extension-0.3.0.tgz",
"integrity": "sha512-vMmYT8H53oFhOpNftCYQMbNYbTiXqQUxOOKlPcrKkZb0FsXSiEZ/MUKBF3mAarvFlzdMaB5xJjakMfy07/bdvw==",
"requires": {
"@logicflow/core": "^0.3.0",
"ids": "^1.0.0"
}
},
"@nodelib/fs.scandir": {
"version": "2.1.4",
@ -1235,6 +1244,11 @@
"integrity": "sha1-xr5oWKvQE9do6YNmrkfiXViHsa4=",
"dev": true
},
"ids": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/ids/-/ids-1.0.0.tgz",
"integrity": "sha512-Zvtq1xUto4LttpstyOlFum8lKx+i1OmRfg+6A9drFS9iSZsDPMHG4Sof/qwNR4kCU7jBeWFPrY2ocHxiz7cCRw=="
},
"indexes-of": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/indexes-of/download/indexes-of-1.0.1.tgz",
@ -1958,6 +1972,11 @@
"@vue/devtools-api": "^6.0.0-beta.7"
}
},
"vue-json-pretty": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/vue-json-pretty/-/vue-json-pretty-2.0.2.tgz",
"integrity": "sha512-Vn7SX3XR9cfvGRNoTDNID89GmvVUMb7/fLUX3C3n0Qptga0N7hp7Zwspui1I1XN5pE+PeoVghCSYty+bi8KnjA=="
},
"vue-router": {
"version": "4.0.6",
"resolved": "https://registry.npm.taobao.org/vue-router/download/vue-router-4.0.6.tgz",

View File

@ -8,7 +8,8 @@
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@logicflow/core": "^0.2.9",
"@logicflow/core": "^0.3.0",
"@logicflow/extension": "^0.3.0",
"@vueuse/core": "^4.8.1",
"await-to-js": "^2.1.1",
"axios": "^0.21.1",
@ -27,6 +28,7 @@
"v-contextmenu": "^3.0.0-alpha.4",
"vue": "^3.0.11",
"vue-i18n": "^9.1.2",
"vue-json-pretty": "^2.0.2",
"vue-router": "^4.0.6",
"vue-types": "^3.0.2",
"vuedraggable": "^4.0.1",

View File

View File

@ -0,0 +1,115 @@
<template>
<el-tabs tab-position="left">
<el-tab-pane label="添加动作">
<div v-for="item in nodeList" :key="item.type">
<el-button
class="add-node-btn"
type="primary"
size="mini"
@click="$_addNode(item)"
>{{item.label}}</el-button>
</div>
</el-tab-pane>
<el-tab-pane label="添加组">
<el-button class="add-node-btn" type="primary" size="mini" @click="$_addTempalte">模板</el-button>
</el-tab-pane>
</el-tabs>
</template>
<script>
export default {
name: 'AddPanel',
props: {
nodeData: Object,
lf: Object || String
},
data() {
return {
nodeList: [
{
type: 'user',
label: '用户'
},
{
type: 'push',
label: '推送'
}
]
}
},
methods: {
$_addNode(item) {
const { lf, nodeData } = this.$props
const { id, x, y } = nodeData
const nextNode = lf.addNode({
type: item.type,
x: x + 150,
y: y + 150
})
const nextId = nextNode.id
lf.createEdge({ sourceNodeId: id, targetNodeId: nextId })
this.$emit('addNodeFinish')
},
$_addTempalte() {
const { lf, nodeData } = this.$props
const { id, x, y } = nodeData
const timeNode = lf.addNode({
type: 'download',
x,
y: y + 150
})
const userNode = lf.addNode({
type: 'user',
x: x + 150,
y: y + 150
})
const pushNode = lf.addNode({
type: 'push',
x: x + 150,
y: y + 300,
properties: {}
})
const endNode = lf.addNode({
type: 'end',
x: x + 300,
y: y + 150
})
const endNode2 = lf.addNode({
type: 'end',
x: x + 300,
y: y + 300
})
lf.createEdge({ sourceNodeId: id, targetNodeId: timeNode.id })
lf.createEdge({ sourceNodeId: timeNode.id, targetNodeId: userNode.id })
lf.createEdge({
sourceNodeId: userNode.id,
targetNodeId: endNode.id,
endPoint: { x: x + 280, y: y + 150 },
text: {
value: 'Y',
x: x + 230,
y: y + 140
}
})
lf.createEdge({
sourceNodeId: userNode.id,
targetNodeId: pushNode.id,
text: {
value: 'N',
x: x + 160,
y: y + 230
}
})
lf.createEdge({ sourceNodeId: pushNode.id, targetNodeId: endNode2.id, endPoint: { x: x + 280, y: y + 300 } })
this.$emit('addNodeFinish')
}
}
}
</script>
<style scoped>
.add-node-btn {
margin-bottom: 10px;
margin-right: 20px;
}
</style>

View File

View File

@ -0,0 +1,74 @@
<template>
<div>
<el-button-group>
<el-button size="small" @click="$_zoomIn">放大</el-button>
<el-button size="small" @click="$_zoomOut">缩小</el-button>
<el-button size="small" @click="$_zoomReset">大小适应</el-button>
<el-button size="small" @click="$_translateRest">定位还原</el-button>
<el-button size="small" @click="$_reset">还原(大小&定位)</el-button>
<el-button size="small" @click="$_undo" :disabled="undoDisable">上一步(ctrl+z)</el-button>
<el-button size="small" @click="$_redo" :disabled="redoDisable">下一步(ctrl+y)</el-button>
<el-button size="small" @click="$_download">下载图片</el-button>
<el-button size="small" @click="$_catData">查看数据</el-button>
<el-button v-if="catTurboData" size="small" @click="$_catTurboData">查看turbo数据</el-button>
</el-button-group>
</div>
</template>
<script>
export default {
name: 'Control',
props: {
lf: Object || String,
catTurboData: Boolean
},
data() {
return {
undoDisable: true,
redoDisable: true,
}
},
mounted() {
this.$props.lf.on('history:change', ({ data: { undoAble, redoAble } }) => {
this.$data.undoDisable = !undoAble
this.$data.redoDisable = !redoAble
})
},
methods: {
$_zoomIn() {
this.$props.lf.zoom(true)
},
$_zoomOut() {
this.$props.lf.zoom(false)
},
$_zoomReset() {
this.$props.lf.resetZoom()
},
$_translateRest() {
this.$props.lf.resetTranslate()
},
$_reset() {
this.$props.lf.resetZoom()
this.$props.lf.resetTranslate()
},
$_undo() {
this.$props.lf.undo()
},
$_redo() {
this.$props.lf.redo()
},
$_download() {
this.$props.lf.getSnapshot()
},
$_catData() {
this.$emit('catData')
},
$_catTurboData() {
this.$emit('catTurboData')
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,22 @@
<template>
<div>
<vue-json-pretty :path="'res'" :deep="3" :showLength="true" :data="graphData"></vue-json-pretty>
</div>
</template>
<script>
import VueJsonPretty from 'vue-json-pretty'
import 'vue-json-pretty/lib/styles.css'
export default {
props: {
graphData: Object
},
components: {
VueJsonPretty,
},
};
</script>
<style scoped>
</style>

View File

@ -0,0 +1,124 @@
<template>
<div class="node-panel">
<div class="node-item" v-for="item in nodeList" :key="item.text" @mousedown="$_dragNode(item)">
<div class="node-item-icon" :class="item.class">
<div v-if="item.type === 'user' || item.type === 'time'" class="shape"></div>
</div>
<span class="node-label">{{item.text}}</span>
</div>
</div>
</template>
<script>
export default {
name: 'NodePanel',
props: {
lf: Object,
nodeList: Array,
},
data() {
return {
node: {
type: 'rect',
property: {
a: 'efrwe',
b: 'wewe'
}
},
properties: {
a: 'efrwe',
b: 'wewe'
}
}
},
methods: {
$_dragNode(item) {
this.$props.lf.dnd.startDrag({
type: item.type,
properties: this.$data.properties
})
}
}
}
</script>
<style>
.node-panel {
position: absolute;
top: 100px;
left: 50px;
width: 70px;
padding: 20px 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: 20px;
}
.node-item-icon {
height: 30px;
display: flex;
flex-wrap: wrap;
justify-content: center;
background-size: cover;
}
.node-label {
font-size: 12px;
margin-top: 5px;
user-select: none;
}
.node-start {
background: url("./background/start.png") no-repeat;
background-size: cover;
}
.node-rect {
border: 1px solid black;
}
.node-user {
background: url("./background/user.png") no-repeat;
background-size: cover;
}
.node-time {
background: url("./background/time.png") no-repeat;
background-size: cover;
}
.node-push {
background: url("./background/push.png") no-repeat;
background-size: cover;
}
.node-download {
background: url("./background/download.png") no-repeat;
background-size: cover;
}
.node-click {
background: url("./background/click.png") no-repeat;
background-size: cover;
}
.node-end {
background: url("./background/end.png") no-repeat;
background-size: cover;
}
.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-exclusiveGateway {
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;
}
</style>

View File

@ -0,0 +1,166 @@
const TurboType = {
SEQUENCE_FLOW: 1,
START_EVENT: 2,
END_EVENT: 3,
USER_TASK: 4,
SERVICE_TASK: 5,
EXCLUSIVE_GATEWAY: 6,
}
function getTurboType(type) {
switch (type) {
case 'bpmn:sequenceFlow':
return TurboType.SEQUENCE_FLOW
case 'bpmn:startEvent':
return TurboType.START_EVENT
case 'bpmn:endEvent':
return TurboType.END_EVENT
case 'bpmn:userTask':
return TurboType.USER_TASK
case 'bpmn:serviceTask':
return TurboType.SERVICE_TASK
case 'bpmn:exclusiveGateway':
return TurboType.EXCLUSIVE_GATEWAY
default:
return type
}
}
function convertNodeToTurboElement(node) {
const { id, type, x, y, text = '', properties } = node
return {
incoming: [],
outgoing: [],
dockers: [],
type: getTurboType(node.type),
properties: {
...properties,
name: text && text.value || '',
x: x,
y: y,
text,
logicFlowType: type,
},
key: id,
}
}
function convertEdgeToTurboElement(edge) {
const {
id,
type,
sourceNodeId,
targetNodeId,
startPoint,
endPoint,
pointsList,
text = '',
properties } = edge
return {
incoming: [sourceNodeId],
outgoing: [targetNodeId],
type: getTurboType(type),
dockers: [],
properties: {
...properties,
name: text && text.value || '',
text,
startPoint,
endPoint,
pointsList,
logicFlowType: type,
},
key: id,
}
}
export function toTurboData(data) {
const nodeMap = new Map()
const turboData = {
flowElementList: [],
}
data.nodes.forEach((node) => {
const flowElement = convertNodeToTurboElement(node)
turboData.flowElementList.push(flowElement)
nodeMap.set(node.id, flowElement)
})
data.edges.forEach((edge) => {
const flowElement = convertEdgeToTurboElement(edge)
const sourceElement = nodeMap.get(edge.sourceNodeId)
sourceElement.outgoing.push(flowElement.key)
const targetElement = nodeMap.get(edge.targetNodeId)
targetElement.incoming.push(flowElement.key)
turboData.flowElementList.push(flowElement)
})
return turboData
}
function convertFlowElementToEdge(element) {
const { incoming, outgoing, properties, key } = element
const {
text,
startPoint,
endPoint,
pointsList,
logicFlowType
} = properties
const edge = {
id: key,
type: logicFlowType,
sourceNodeId: incoming[0],
targetNodeId: outgoing[0],
text,
startPoint,
endPoint,
pointsList,
properties: {}
}
const excludeProperties = ['startPoint', 'endPoint', 'pointsList', 'text', 'logicFlowType']
Object.keys(element.properties).forEach(property => {
if (excludeProperties.indexOf(property) === -1) {
edge.properties[property] = element.properties[property]
}
})
return edge
}
function convertFlowElementToNode(element) {
const { properties, key } = element
const { x, y, text, logicFlowType } = properties
const node = {
id: key,
type: logicFlowType,
x,
y,
text,
properties: {}
}
const excludeProperties = ['x', 'y', 'text', 'logicFlowType']
Object.keys(element.properties).forEach(property => {
if (excludeProperties.indexOf(property) === -1) {
node.properties[property] = element.properties[property]
}
})
return node
}
export function toLogicflowData(data) {
const lfData = {
nodes: [],
edges: [],
}
const list = data.flowElementList
list && list.length > 0 && list.forEach(element => {
if (element.type === TurboType.SEQUENCE_FLOW) {
const edge = convertFlowElementToEdge(element)
lfData.edges.push(edge)
} else {
const node = convertFlowElementToNode(element)
lfData.nodes.push(node)
}
})
return lfData
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -0,0 +1,55 @@
export const nodeList = [
{
text: '开始',
type: 'start',
class: 'node-start'
},
{
text: '矩形',
type: 'rect',
class: 'node-rect'
},
{
type: 'user',
text: '用户',
class: 'node-user'
},
{
type: 'push',
text: '推送',
class: 'node-push'
},
{
type: 'download',
text: '位置',
class: 'node-download'
},
{
type: 'end',
text: '结束',
class: 'node-end'
},
]
export const BpmnNode = [
{
type: 'bpmn:startEvent',
text: '开始',
class: 'bpmn-start'
},
{
type: 'bpmn:endEvent',
text: '结束',
class: 'bpmn-end'
},
{
type: 'bpmn:exclusiveGateway',
text: '网关',
class: 'bpmn-exclusiveGateway'
},
{
type: 'bpmn:userTask',
text: '用户',
class: 'bpmn-user'
},
]

View File

@ -131,25 +131,24 @@ const routes: Array<RouteRecordRaw> = [
}
},
{
path: '/user',
name: 'user',
path: '/flowChart',
name: 'flowChart',
component: Layout,
redirect: '/user/base',
redirect: '/flowChart/index',
children: [
{
path: '/user/base',
component: () => import(/* webpackChunkName: "user" */ '../views/user.vue'),
path: '/flowChart/index',
component: () => import(/* webpackChunkName: "user" */ '../views/flow-chart/index.vue'),
meta: {
// icon: 'el-icon-user',
title: 'baseinfo',
title: 'flowChart',
showLink: false,
savedPosition: true
}
},
],
meta: {
icon: 'el-icon-user',
title: 'usermanagement',
icon: 'el-icon-set-up',
title: 'flowChart',
showLink: true,
savedPosition: true
}
@ -178,6 +177,30 @@ const routes: Array<RouteRecordRaw> = [
savedPosition: true
}
},
{
path: '/user',
name: 'user',
component: Layout,
redirect: '/user/base',
children: [
{
path: '/user/base',
component: () => import(/* webpackChunkName: "user" */ '../views/user.vue'),
meta: {
// icon: 'el-icon-user',
title: 'baseinfo',
showLink: false,
savedPosition: true
}
},
],
meta: {
icon: 'el-icon-user',
title: 'usermanagement',
showLink: true,
savedPosition: true
}
},
{
path: '/error',
name: 'error',

View File

@ -4,10 +4,18 @@
<template #header>
<div class="card-header">
<span>无缝滚动示例</span>
<el-button class="button" type="text" @click="changeDirection('top')">向上滚动</el-button>
<el-button class="button" type="text" @click="changeDirection('bottom')">向下滚动</el-button>
<el-button class="button" type="text" @click="changeDirection('left')">向左滚动</el-button>
<el-button class="button" type="text" @click="changeDirection('right')">向右滚动</el-button>
<el-button class="button" type="text" @click="changeDirection('top')">
<span :style="{color: classOption.direction === 'top' ? 'red' : ''}">向上滚动</span>
</el-button>
<el-button class="button" type="text" @click="changeDirection('bottom')">
<span :style="{color: classOption.direction === 'bottom' ? 'red' : ''}">向下滚动</span>
</el-button>
<el-button class="button" type="text" @click="changeDirection('left')">
<span :style="{color: classOption.direction === 'left' ? 'red' : ''}">向左滚动</span>
</el-button>
<el-button class="button" type="text" @click="changeDirection('right')">
<span :style="{color: classOption.direction === 'right' ? 'red' : ''}">向右滚动</span>
</el-button>
</div>
</template>
<SeamlessScroll ref="scroll" :data="listData" :class-option="classOption" class="warp">

View File

@ -0,0 +1,272 @@
{
"flowElementList": [
{
"incoming": [],
"outgoing": [
"Flow_33inf2k"
],
"dockers": [],
"type": 2,
"properties": {
"a": "efrwe",
"b": "wewe",
"name": "开始",
"x": 280,
"y": 200,
"text": {
"x": 280,
"y": 200,
"value": "开始"
},
"logicFlowType": "bpmn:startEvent"
},
"key": "Event_1d42u4p"
},
{
"incoming": [
"Flow_379e0o9"
],
"outgoing": [],
"dockers": [],
"type": 3,
"properties": {
"a": "efrwe",
"b": "wewe",
"name": "结束",
"x": 920,
"y": 200,
"text": {
"x": 920,
"y": 200,
"value": "结束"
},
"logicFlowType": "bpmn:endEvent"
},
"key": "Event_08p8i6q"
},
{
"incoming": [
"Flow_0pfouf0"
],
"outgoing": [
"Flow_3918lhh"
],
"dockers": [],
"type": 6,
"properties": {
"a": "efrwe",
"b": "wewe",
"name": "网关",
"x": 580,
"y": 200,
"text": {
"x": 580,
"y": 200,
"value": "网关"
},
"logicFlowType": "bpmn:exclusiveGateway"
},
"key": "Gateway_1fngqgj"
},
{
"incoming": [
"Flow_33inf2k"
],
"outgoing": [
"Flow_0pfouf0"
],
"dockers": [],
"type": 4,
"properties": {
"a": "efrwe",
"b": "wewe",
"name": "用户",
"x": 420,
"y": 200,
"text": {
"x": 420,
"y": 200,
"value": "用户"
},
"logicFlowType": "bpmn:userTask"
},
"key": "Activity_2mgtaia"
},
{
"incoming": [
"Flow_3918lhh"
],
"outgoing": [
"Flow_379e0o9"
],
"dockers": [],
"type": 5,
"properties": {
"a": "efrwe",
"b": "wewe",
"name": "服务",
"x": 760,
"y": 200,
"text": {
"x": 760,
"y": 200,
"value": "服务"
},
"logicFlowType": "bpmn:serviceTask"
},
"key": "Activity_1sp8qc8"
},
{
"incoming": [
"Event_1d42u4p"
],
"outgoing": [
"Activity_2mgtaia"
],
"type": 1,
"dockers": [],
"properties": {
"name": "边",
"text": {
"x": 331,
"y": 200,
"value": "边"
},
"startPoint": {
"x": 298,
"y": 200
},
"endPoint": {
"x": 370,
"y": 200
},
"pointsList": [
{
"x": 298,
"y": 200
},
{
"x": 370,
"y": 200
}
],
"logicFlowType": "bpmn:sequenceFlow"
},
"key": "Flow_33inf2k"
},
{
"incoming": [
"Activity_2mgtaia"
],
"outgoing": [
"Gateway_1fngqgj"
],
"type": 1,
"dockers": [],
"properties": {
"name": "边2",
"text": {
"x": 507,
"y": 200,
"value": "边2"
},
"startPoint": {
"x": 470,
"y": 200
},
"endPoint": {
"x": 555,
"y": 200
},
"pointsList": [
{
"x": 470,
"y": 200
},
{
"x": 555,
"y": 200
}
],
"logicFlowType": "bpmn:sequenceFlow"
},
"key": "Flow_0pfouf0"
},
{
"incoming": [
"Gateway_1fngqgj"
],
"outgoing": [
"Activity_1sp8qc8"
],
"type": 1,
"dockers": [],
"properties": {
"name": "边3",
"text": {
"x": 664,
"y": 200,
"value": "边3"
},
"startPoint": {
"x": 605,
"y": 200
},
"endPoint": {
"x": 710,
"y": 200
},
"pointsList": [
{
"x": 605,
"y": 200
},
{
"x": 710,
"y": 200
}
],
"logicFlowType": "bpmn:sequenceFlow"
},
"key": "Flow_3918lhh"
},
{
"incoming": [
"Activity_1sp8qc8"
],
"outgoing": [
"Event_08p8i6q"
],
"type": 1,
"dockers": [],
"properties": {
"name": "边4",
"text": {
"x": 871,
"y": 200,
"value": "边4"
},
"startPoint": {
"x": 810,
"y": 200
},
"endPoint": {
"x": 902,
"y": 200
},
"pointsList": [
{
"x": 810,
"y": 200
},
{
"x": 902,
"y": 200
}
],
"logicFlowType": "bpmn:sequenceFlow"
},
"key": "Flow_379e0o9"
}
]
}

View File

@ -0,0 +1,132 @@
<template>
<div class="logic-flow-view">
<!-- 辅助工具栏 -->
<Control
class="demo-control"
v-if="lf"
:lf="lf"
:catTurboData="false"
@catData="$_catData"
@catTurboData="$_catTurboData"
></Control>
<!-- 节点面板 -->
<NodePanel :lf="lf" :nodeList="nodeList"></NodePanel>
<!-- 画布 -->
<div id="LF-Turbo"></div>
<!-- 数据查看面板 -->
<el-dialog title="数据" v-model="dataVisible" width="50%">
<DataDialog :graphData="graphData"></DataDialog>
</el-dialog>
</div>
</template>
<script>
import LogicFlow from '@logicflow/core'
import { Snapshot, BpmnElement } from '@logicflow/extension'
import '@logicflow/core/dist/style/index.css'
import '@logicflow/extension/lib/style/index.css'
import NodePanel from '/@/components/FlowChart/src/NodePanel.vue'
import Control from '/@/components/FlowChart/src/Control.vue'
import DataDialog from '/@/components/FlowChart/src/DataDialog.vue'
import { toTurboData, toLogicflowData } from '/@/components/FlowChart/src/adpterForTurbo.ts'
import { BpmnNode } from '/@/components/FlowChart/src/config.ts'
import demoData from './dataTurbo.json'
export default {
name: 'LF',
components: { NodePanel, Control, DataDialog },
data() {
return {
lf: null,
dialogVisible: false,
graphData: null,
dataVisible: false,
config: {
grid: true,
background: {
color: '#f7f9ff'
},
keyboard: {
enabled: true
},
},
nodeList: BpmnNode,
}
},
mounted() {
this.$_initLf()
},
methods: {
$_initLf() {
//
LogicFlow.use(Snapshot)
// 使bpmnbpmnturbo使
LogicFlow.use(BpmnElement)
const lf = new LogicFlow({ ...this.config, container: document.querySelector('#LF-Turbo') })
this.lf = lf
// bpmn:sequenceFlow
lf.setDefaultEdgeType('bpmn:sequenceFlow')
this.$_render()
},
$_render() {
// TurboLogicFlow
const lFData = toLogicflowData(demoData)
this.lf.render(lFData)
},
closeDialog() {
this.$data.dialogVisible = false
},
$_catData() {
this.$data.graphData = this.$data.lf.getGraphData()
this.$data.dataVisible = true
},
$_catTurboData() {
debugger
const graphData = this.$data.lf.getGraphData()
// Turbo
this.$data.graphData = toTurboData(graphData)
this.$data.dataVisible = true
},
goto() {
this.$router.push('/')
}
}
}
</script>
<style>
.logic-flow-view {
height: 100vh;
position: relative;
}
.demo-title {
text-align: center;
margin: 20px;
}
.demo-control {
position: absolute;
top: 50px;
right: 100px;
z-index: 2;
}
#LF-Turbo {
width: 100vw;
height: 85%;
outline: none;
margin: 10px 0 0 10px;
}
.time-plus {
cursor: pointer;
}
.add-panel {
position: absolute;
z-index: 11;
background-color: white;
padding: 10px 5px;
}
.el-drawer__body {
height: 80%;
overflow: auto;
margin-top: -30px;
z-index: 3;
}
</style>