mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-08 01:17:23 +08:00
fix: Improve the flowChart component
This commit is contained in:
parent
5ec1f62f8d
commit
ba41753d77
@ -0,0 +1,22 @@
|
|||||||
|
import { App } from "vue"
|
||||||
|
import control from "./src/Control.vue"
|
||||||
|
import nodePanel from "./src/NodePanel.vue"
|
||||||
|
import dataDialog from "./src/DataDialog.vue"
|
||||||
|
|
||||||
|
export const Control = Object.assign(control, {
|
||||||
|
install(app: App) {
|
||||||
|
app.component(control.name, control)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const NodePanel = Object.assign(nodePanel, {
|
||||||
|
install(app: App) {
|
||||||
|
app.component(nodePanel.name, nodePanel)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const DataDialog = Object.assign(dataDialog, {
|
||||||
|
install(app: App) {
|
||||||
|
app.component(dataDialog.name, dataDialog)
|
||||||
|
}
|
||||||
|
})
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="control-container">
|
<div class="control-container">
|
||||||
|
<!-- 功能按钮 -->
|
||||||
<ul>
|
<ul>
|
||||||
<li
|
<li
|
||||||
v-for="(item,key) in titleLists"
|
v-for="(item,key) in titleLists"
|
||||||
@ -9,117 +10,111 @@
|
|||||||
@mouseenter.prevent="onEnter(key)"
|
@mouseenter.prevent="onEnter(key)"
|
||||||
@mouseleave.prevent="focusIndex = -1"
|
@mouseleave.prevent="focusIndex = -1"
|
||||||
>
|
>
|
||||||
<button ref="controlButton" @click="onControl(item,key)">
|
<button
|
||||||
|
:ref="'controlButton' + key"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
:style="{cursor: item.disabled === false ? 'pointer' : 'not-allowed'}"
|
||||||
|
@click="onControl(item,key)"
|
||||||
|
>
|
||||||
<span :class="'iconfont ' + item.icon"></span>
|
<span :class="'iconfont ' + item.icon"></span>
|
||||||
<p>{{ item.text }}</p>
|
<p>{{ item.text }}</p>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<!-- <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>-->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang='ts'>
|
||||||
export default {
|
import { defineComponent ,ref, unref, onMounted } from "vue";
|
||||||
|
import { templateRef } from '@vueuse/core'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
name: "Control",
|
name: "Control",
|
||||||
props: {
|
props: {
|
||||||
lf: Object || String,
|
lf: Object || String,
|
||||||
catTurboData: Boolean,
|
catTurboData: Boolean,
|
||||||
},
|
},
|
||||||
data() {
|
emits: ["catData"],
|
||||||
return {
|
setup(props,{emit}) {
|
||||||
undoDisable: true,
|
const controlButton3 = templateRef<HTMLElement | null>('controlButton3', null)
|
||||||
redoDisable: true,
|
const controlButton4 = templateRef<HTMLElement | null>('controlButton4', null)
|
||||||
focusIndex: -1,
|
|
||||||
titleLists: [
|
let focusIndex = ref(-1)
|
||||||
|
let titleLists = ref([
|
||||||
{
|
{
|
||||||
icon: "icon-zoom-out-hs",
|
icon: "icon-zoom-out-hs",
|
||||||
text: "缩小",
|
text: "缩小",
|
||||||
|
disabled: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "icon-enlarge-hs",
|
icon: "icon-enlarge-hs",
|
||||||
text: "放大",
|
text: "放大",
|
||||||
|
disabled: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "icon-full-screen-hs",
|
icon: "icon-full-screen-hs",
|
||||||
text: "适应",
|
text: "适应",
|
||||||
|
disabled: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "icon-previous-hs",
|
icon: "icon-previous-hs",
|
||||||
text: "上一步",
|
text: "上一步",
|
||||||
|
disabled: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "icon-next-step-hs",
|
icon: "icon-next-step-hs",
|
||||||
text: "下一步",
|
text: "下一步",
|
||||||
|
disabled: true
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
};
|
icon: "icon-download-hs",
|
||||||
|
text: "下载图片",
|
||||||
|
disabled: false
|
||||||
},
|
},
|
||||||
mounted() {
|
{
|
||||||
this.$props.lf.on("history:change", ({ data: { undoAble, redoAble } }) => {
|
icon: "icon-watch-hs",
|
||||||
this.$data.undoDisable = !undoAble;
|
text: "查看数据",
|
||||||
this.$data.redoDisable = !redoAble;
|
disabled: false
|
||||||
});
|
|
||||||
},
|
},
|
||||||
methods: {
|
])
|
||||||
onControl(item, key) {
|
|
||||||
["zoom", "zoom", "resetZoom", "undo", "redo"].forEach((v, i) => {
|
const onControl = (item, key) => {
|
||||||
let domControl = this.$props.lf;
|
["zoom", "zoom", "resetZoom", "undo", "redo", "getSnapshot"].forEach((v, i) => {
|
||||||
|
let domControl = props.lf
|
||||||
if (key === 1) {
|
if (key === 1) {
|
||||||
domControl.zoom(true);
|
domControl.zoom(true)
|
||||||
|
}
|
||||||
|
if (key === 6) {
|
||||||
|
emit("catData")
|
||||||
}
|
}
|
||||||
if (key === i) {
|
if (key === i) {
|
||||||
domControl[v]();
|
domControl[v]()
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
},
|
}
|
||||||
onEnter(key) {
|
|
||||||
this.focusIndex = key;
|
const onEnter = (key) => {
|
||||||
},
|
focusIndex.value = key
|
||||||
$_zoomIn() {
|
}
|
||||||
this.$props.lf.zoom(true);
|
|
||||||
},
|
onMounted(()=>{
|
||||||
$_zoomOut() {
|
props.lf.on("history:change", ({ data: { undoAble, redoAble } }) => {
|
||||||
this.$props.lf.zoom(false);
|
unref(titleLists)[3].disabled = unref(controlButton3).disabled = !undoAble
|
||||||
},
|
unref(titleLists)[4].disabled = unref(controlButton4).disabled = !redoAble
|
||||||
$_zoomReset() {
|
})
|
||||||
this.$props.lf.resetZoom();
|
})
|
||||||
},
|
|
||||||
$_translateRest() {
|
return {
|
||||||
this.$props.lf.resetTranslate();
|
focusIndex,
|
||||||
},
|
titleLists,
|
||||||
$_reset() {
|
onControl,
|
||||||
this.$props.lf.resetZoom();
|
onEnter
|
||||||
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>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@import "./assets/iconfont/iconfont.css";
|
@import "./assets/iconfont/iconfont.css";
|
||||||
.control-container {
|
.control-container {
|
||||||
@ -127,7 +122,6 @@ export default {
|
|||||||
right: 20px;
|
right: 20px;
|
||||||
background: hsla(0, 0%, 100%, 0.8);
|
background: hsla(0, 0%, 100%, 0.8);
|
||||||
box-shadow: 0 1px 4px rgb(0 0 0 / 30%);
|
box-shadow: 0 1px 4px rgb(0 0 0 / 30%);
|
||||||
border-radius: 5px;
|
|
||||||
}
|
}
|
||||||
.iconfont {
|
.iconfont {
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
@ -145,7 +139,10 @@ export default {
|
|||||||
.control-container ul li {
|
.control-container ul li {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
}
|
||||||
/* pointer-events: none; */
|
.control-container ul li button {
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,22 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
|
||||||
<vue-json-pretty :path="'res'" :deep="3" :showLength="true" :data="graphData"></vue-json-pretty>
|
<vue-json-pretty :path="'res'" :deep="3" :showLength="true" :data="graphData"></vue-json-pretty>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang='ts'>
|
||||||
import VueJsonPretty from 'vue-json-pretty'
|
import VueJsonPretty from "vue-json-pretty";
|
||||||
import 'vue-json-pretty/lib/styles.css'
|
import "vue-json-pretty/lib/styles.css";
|
||||||
|
import { defineComponent } from "vue";
|
||||||
export default {
|
export default defineComponent({
|
||||||
|
name: "DataDialog",
|
||||||
props: {
|
props: {
|
||||||
graphData: Object
|
graphData: Object
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
VueJsonPretty,
|
VueJsonPretty
|
||||||
},
|
}
|
||||||
};
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
</style>
|
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!-- 左侧bpmn元素选择器 -->
|
||||||
<div class="node-panel">
|
<div class="node-panel">
|
||||||
<div class="node-item" v-for="item in nodeList" :key="item.text" @mousedown="$_dragNode(item)">
|
<div
|
||||||
|
class="node-item"
|
||||||
|
v-for="item in nodeList"
|
||||||
|
:key="item.text"
|
||||||
|
@mousedown="nodeDragNode(item)"
|
||||||
|
>
|
||||||
<div class="node-item-icon" :class="item.class">
|
<div class="node-item-icon" :class="item.class">
|
||||||
<div v-if="item.type === 'user' || item.type === 'time'" class="shape"></div>
|
<div v-if="item.type === 'user' || item.type === 'time'" class="shape"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -9,40 +15,45 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang='ts'>
|
||||||
export default {
|
import { defineComponent, ref, unref } from "vue";
|
||||||
name: 'NodePanel',
|
export default defineComponent({
|
||||||
|
name: "NodePanel",
|
||||||
props: {
|
props: {
|
||||||
lf: Object,
|
lf: Object,
|
||||||
nodeList: Array,
|
nodeList: Array
|
||||||
},
|
},
|
||||||
data() {
|
setup(props) {
|
||||||
return {
|
let node = ref({
|
||||||
node: {
|
type: "rect",
|
||||||
type: 'rect',
|
|
||||||
property: {
|
property: {
|
||||||
a: 'efrwe',
|
a: "efrwe",
|
||||||
b: 'wewe'
|
b: "wewe"
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
properties: {
|
let properties = ref({
|
||||||
a: 'efrwe',
|
a: "efrwe",
|
||||||
b: 'wewe'
|
b: "wewe"
|
||||||
}
|
});
|
||||||
}
|
|
||||||
},
|
const nodeDragNode = item => {
|
||||||
methods: {
|
props.lf.dnd.startDrag({
|
||||||
$_dragNode(item) {
|
|
||||||
this.$props.lf.dnd.startDrag({
|
|
||||||
type: item.type,
|
type: item.type,
|
||||||
properties: this.$data.properties
|
properties: unref(properties)
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
return {
|
||||||
|
node,
|
||||||
|
properties,
|
||||||
|
nodeDragNode
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
|
<style scoped>
|
||||||
.node-panel {
|
.node-panel {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100px;
|
top: 100px;
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div id="container"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang='ts'>
|
|
||||||
import LogicFlow from "@logicflow/core";
|
|
||||||
import "@logicflow/core/dist/style/index.css";
|
|
||||||
import { onMounted } from "vue";
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
// 节点
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 50,
|
|
||||||
type: "rect",
|
|
||||||
x: 100,
|
|
||||||
y: 150,
|
|
||||||
text: "你好",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 21,
|
|
||||||
type: "circle",
|
|
||||||
x: 300,
|
|
||||||
y: 150,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// 边
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
type: "polyline",
|
|
||||||
sourceNodeId: 50,
|
|
||||||
targetNodeId: 21,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
onMounted(() => {
|
|
||||||
const lf = new LogicFlow({
|
|
||||||
container: document.querySelector("#container"),
|
|
||||||
stopScrollGraph: true,
|
|
||||||
stopZoomGraph: true,
|
|
||||||
width: 500,
|
|
||||||
height: 500,
|
|
||||||
grid: {
|
|
||||||
type: "dot",
|
|
||||||
size: 20,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
lf.render(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
</style>
|
|
@ -6,8 +6,7 @@
|
|||||||
v-if="lf"
|
v-if="lf"
|
||||||
:lf="lf"
|
:lf="lf"
|
||||||
:catTurboData="false"
|
:catTurboData="false"
|
||||||
@catData="$_catData"
|
@catData="catData"
|
||||||
@catTurboData="$_catTurboData"
|
|
||||||
></Control>
|
></Control>
|
||||||
<!-- 节点面板 -->
|
<!-- 节点面板 -->
|
||||||
<NodePanel :lf="lf" :nodeList="nodeList"></NodePanel>
|
<NodePanel :lf="lf" :nodeList="nodeList"></NodePanel>
|
||||||
@ -19,28 +18,25 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
|
||||||
|
<script lang='ts'>
|
||||||
|
import { ref, unref, onMounted, nextTick } from "vue"
|
||||||
import LogicFlow from '@logicflow/core'
|
import LogicFlow from '@logicflow/core'
|
||||||
import { Snapshot, BpmnElement } from '@logicflow/extension'
|
import { Snapshot, BpmnElement } from '@logicflow/extension'
|
||||||
import '@logicflow/core/dist/style/index.css'
|
import '@logicflow/core/dist/style/index.css'
|
||||||
import '@logicflow/extension/lib/style/index.css'
|
import '@logicflow/extension/lib/style/index.css'
|
||||||
import NodePanel from '/@/components/FlowChart/src/NodePanel.vue'
|
import { Control, NodePanel, DataDialog } from '/@/components/FlowChart'
|
||||||
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'
|
|
||||||
|
|
||||||
|
import { toTurboData, toLogicflowData } from '/@/components/FlowChart/src/adpterForTurbo'
|
||||||
|
import { BpmnNode } from '/@/components/FlowChart/src/config'
|
||||||
|
import demoData from './dataTurbo.json'
|
||||||
export default {
|
export default {
|
||||||
name: 'LF',
|
|
||||||
components: { NodePanel, Control, DataDialog },
|
components: { NodePanel, Control, DataDialog },
|
||||||
data() {
|
setup() {
|
||||||
return {
|
let lf = ref(null)
|
||||||
lf: null,
|
let graphData =ref(null)
|
||||||
dialogVisible: false,
|
let dataVisible = ref(false)
|
||||||
graphData: null,
|
let config = ref({
|
||||||
dataVisible: false,
|
|
||||||
config: {
|
|
||||||
grid: true,
|
grid: true,
|
||||||
background: {
|
background: {
|
||||||
color: '#f7f9ff'
|
color: '#f7f9ff'
|
||||||
@ -48,51 +44,54 @@ export default {
|
|||||||
keyboard: {
|
keyboard: {
|
||||||
enabled: true
|
enabled: true
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
nodeList: BpmnNode,
|
let nodeList= BpmnNode
|
||||||
}
|
|
||||||
},
|
function initLf() {
|
||||||
mounted() {
|
|
||||||
this.$_initLf()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
$_initLf() {
|
|
||||||
// 画布配置
|
// 画布配置
|
||||||
LogicFlow.use(Snapshot)
|
LogicFlow.use(Snapshot)
|
||||||
// 使用bpmn插件,引入bpmn元素,这些元素可以在turbo中转换后使用
|
// 使用bpmn插件,引入bpmn元素,这些元素可以在turbo中转换后使用
|
||||||
LogicFlow.use(BpmnElement)
|
LogicFlow.use(BpmnElement)
|
||||||
const lf = new LogicFlow({ ...this.config, container: document.querySelector('#LF-Turbo') })
|
const domLf = new LogicFlow({ ...unref(config), container: document.querySelector('#LF-Turbo') })
|
||||||
this.lf = lf
|
lf.value = domLf
|
||||||
// 设置边类型bpmn:sequenceFlow为默认类型
|
// 设置边类型bpmn:sequenceFlow为默认类型
|
||||||
lf.setDefaultEdgeType('bpmn:sequenceFlow')
|
unref(lf).setDefaultEdgeType('bpmn:sequenceFlow')
|
||||||
this.$_render()
|
onRender()
|
||||||
},
|
}
|
||||||
$_render() {
|
|
||||||
|
function onRender() {
|
||||||
// Turbo数据转换为LogicFlow内部识别的数据结构
|
// Turbo数据转换为LogicFlow内部识别的数据结构
|
||||||
const lFData = toLogicflowData(demoData)
|
const lFData = toLogicflowData(demoData)
|
||||||
this.lf.render(lFData)
|
lf.value.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('/')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function catData() {
|
||||||
|
graphData.value = unref(lf).getGraphData()
|
||||||
|
dataVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
initLf()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
lf,
|
||||||
|
graphData,
|
||||||
|
dataVisible,
|
||||||
|
config,
|
||||||
|
nodeList,
|
||||||
|
catData
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
|
<style scoped>
|
||||||
|
#LF-Turbo {
|
||||||
|
width: 100vw;
|
||||||
|
height: 85%;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
.logic-flow-view {
|
.logic-flow-view {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -107,11 +106,6 @@ export default {
|
|||||||
right: 20px;
|
right: 20px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
#LF-Turbo {
|
|
||||||
width: 100vw;
|
|
||||||
height: 85%;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.time-plus {
|
.time-plus {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user