|
@@ -1,5 +1,14 @@
|
|
|
<script setup lang="ts">
|
|
|
-import {ref, onMounted, InjectionKey, Ref, provide, inject, nextTick, markRaw} from 'vue';
|
|
|
+import {
|
|
|
+ ref,
|
|
|
+ onMounted,
|
|
|
+ InjectionKey,
|
|
|
+ Ref,
|
|
|
+ provide,
|
|
|
+ inject,
|
|
|
+ nextTick,
|
|
|
+ markRaw,
|
|
|
+} from "vue";
|
|
|
import {
|
|
|
HJMethodName,
|
|
|
HJNodeData,
|
|
@@ -7,185 +16,206 @@ import {
|
|
|
nodeTypes,
|
|
|
edgeTypes,
|
|
|
HJMethodProvideName,
|
|
|
- CurrentHeaderOperationProvideName, CurrentSelectedEdgeProvideName, HJFlowProps
|
|
|
+ CurrentHeaderOperationProvideName,
|
|
|
+ CurrentSelectedEdgeProvideName,
|
|
|
+ HJFlowProps,
|
|
|
} from "../types/comTypes";
|
|
|
import Panel from "../panel/index.vue";
|
|
|
-import CommonEdge from '../edges/commonEdge.vue'
|
|
|
+import CommonEdge from "../edges/commonEdge.vue";
|
|
|
import DropzoneBackground from "../background/DropzoneBackground.vue";
|
|
|
-import {useVueFlow, VueFlow, Edge} from "@vue-flow/core";
|
|
|
+import { useVueFlow, VueFlow, Edge } from "@vue-flow/core";
|
|
|
import useDragAndDrop from "../hooks/useDnD";
|
|
|
-import {useLayout} from '../utils/useLayout'
|
|
|
-import {useSnakeLayoutHook} from "../utils/useSnake";
|
|
|
-import {ElMessage} from "element-plus";
|
|
|
-
|
|
|
+import { sortNodesByPosition, useLayout } from "../utils/useLayout";
|
|
|
+import { useSnakeLayoutHook } from "../hooks/snakeHooks";
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
|
|
|
defineOptions({
|
|
|
- name: 'HJFlow'
|
|
|
-})
|
|
|
+ name: "HJFlow",
|
|
|
+});
|
|
|
|
|
|
-const {onConnect, addEdges, fitView, updateNode, findNode} = useVueFlow()
|
|
|
-const {onDragOver, onDrop, onDragLeave, isDragOver} = useDragAndDrop()
|
|
|
-
|
|
|
-onConnect(addEdges)
|
|
|
+const { onConnect, addEdges, fitView, updateNode, findNode } = useVueFlow();
|
|
|
+const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop();
|
|
|
|
|
|
+onConnect(addEdges);
|
|
|
|
|
|
// ========== 外面传进来的参数 ===========
|
|
|
-const nodes = defineModel<HJNodeData[]>('nodesData')
|
|
|
-const edges = defineModel('edgesData')
|
|
|
-const props = defineProps<HJFlowProps>()
|
|
|
-
|
|
|
+const nodes = defineModel<HJNodeData[]>("nodesData");
|
|
|
+const edges = defineModel("edgesData");
|
|
|
+const props = defineProps<HJFlowProps>();
|
|
|
|
|
|
// ==========vueflow 本身的方法操作 ===========
|
|
|
-const doubleClick = ({node}) => {
|
|
|
+const doubleClick = ({ node }) => {
|
|
|
// 如果通过双击弹出额外信息编辑是可以拿到jsonData的,但是如果在自定义node中是拿不到的,非要在自定义中拿就得把额外的信息放到data中。
|
|
|
// 还要看 是否要根据 dragData中的数据生成具体 avue页面。 之后可以尝试通过useVueFlow的find能否找到
|
|
|
- console.log('doubleClick', node);
|
|
|
-}
|
|
|
-
|
|
|
-const currentClickEdgeData = ref<Edge | null>(null)
|
|
|
-provide(CurrentSelectedEdgeProvideName, currentClickEdgeData)
|
|
|
-const onClickEdge = ({edge}) => {
|
|
|
- currentClickEdgeData.value = JSON.parse(JSON.stringify(edge))
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
+ console.log("doubleClick", node);
|
|
|
+};
|
|
|
|
|
|
+const currentClickEdgeData = ref<Edge | null>(null);
|
|
|
+provide(CurrentSelectedEdgeProvideName, currentClickEdgeData);
|
|
|
+const onClickEdge = ({ edge }) => {
|
|
|
+ currentClickEdgeData.value = JSON.parse(JSON.stringify(edge));
|
|
|
+};
|
|
|
|
|
|
// ======= Emits =======
|
|
|
const emits = defineEmits<{
|
|
|
- hjMethod: [name: HJMethodName, node: HJNodeData]
|
|
|
-}>()
|
|
|
+ hjMethod: [name: HJMethodName, node: HJNodeData];
|
|
|
+}>();
|
|
|
|
|
|
// 提供一个孙子组件里面(比如自定义node里面) 调用本组件的方法
|
|
|
// ======= Node操作 =======
|
|
|
-const currentHeaderOperationNodeData = ref<HJNodeData | null >(null) // 当前选中的header操作节点
|
|
|
-provide(CurrentHeaderOperationProvideName, currentHeaderOperationNodeData)
|
|
|
-provide(HJMethodProvideName, ( name: HJMethodName,node: HJNodeData) => {
|
|
|
- currentHeaderOperationNodeData.value = JSON.parse(JSON.stringify(node)) // 复制一份数据
|
|
|
- console.log('provide', name, node);
|
|
|
- emits('hjMethod', name, node)
|
|
|
-})
|
|
|
-
|
|
|
-
|
|
|
+const currentHeaderOperationNodeData = ref<HJNodeData | null>(null); // 当前选中的header操作节点
|
|
|
+provide(CurrentHeaderOperationProvideName, currentHeaderOperationNodeData);
|
|
|
+provide(HJMethodProvideName, (name: HJMethodName, node: HJNodeData) => {
|
|
|
+ currentHeaderOperationNodeData.value = JSON.parse(JSON.stringify(node)); // 复制一份数据
|
|
|
+ console.log("provide", name, node);
|
|
|
+ emits("hjMethod", name, node);
|
|
|
+});
|
|
|
|
|
|
///// === 数据历史纪录 用于回退或者重置按钮 === /////
|
|
|
-let originData: any = null
|
|
|
-let historyList: any[] = []
|
|
|
-
|
|
|
+let originData: any = null;
|
|
|
+let historyList: any[] = [];
|
|
|
|
|
|
///// === 所有的node 和edge change 调用的地方 === /////
|
|
|
const onFlowNodesChange = (data: any) => {
|
|
|
if (
|
|
|
- data.length > 0 &&
|
|
|
- data[0].type &&
|
|
|
- (data[0].type === "add" || data[0].type === "remove")
|
|
|
+ data.length > 0 &&
|
|
|
+ data[0].type &&
|
|
|
+ (data[0].type === "add" || data[0].type === "remove")
|
|
|
) {
|
|
|
-
|
|
|
- historyList.unshift(JSON.stringify({nodes: markRaw(nodes.value), edges: markRaw(edges.value)}))
|
|
|
- console.log('onFlowNodesChange historyList', historyList)
|
|
|
+ historyList.unshift(
|
|
|
+ JSON.stringify({
|
|
|
+ nodes: markRaw(nodes.value),
|
|
|
+ edges: markRaw(edges.value),
|
|
|
+ })
|
|
|
+ );
|
|
|
+ console.log("onFlowNodesChange historyList", historyList);
|
|
|
}
|
|
|
-}
|
|
|
+};
|
|
|
const onFlowEdgesChange = (data: any) => {
|
|
|
if (
|
|
|
- data.length > 0 &&
|
|
|
- data[0].type &&
|
|
|
- (data[0].type === "add" || data[0].type === "remove")
|
|
|
+ data.length > 0 &&
|
|
|
+ data[0].type &&
|
|
|
+ (data[0].type === "add" || data[0].type === "remove")
|
|
|
) {
|
|
|
- historyList.unshift(JSON.stringify({nodes: markRaw(nodes.value), edges: markRaw(edges.value)}))
|
|
|
+ historyList.unshift(
|
|
|
+ JSON.stringify({
|
|
|
+ nodes: markRaw(nodes.value),
|
|
|
+ edges: markRaw(edges.value),
|
|
|
+ })
|
|
|
+ );
|
|
|
}
|
|
|
-}
|
|
|
+};
|
|
|
///// === 所有的node 和edge change 调用的地方 === /////
|
|
|
|
|
|
///// === 初始化 === /////
|
|
|
const initFlow = (nodes: HJNodeData[], edges: any[]) => {
|
|
|
- originData = JSON.stringify({nodes, edges}) // 复制一份数据
|
|
|
- historyList = [] // 初始化历史纪录
|
|
|
-}
|
|
|
+ originData = JSON.stringify({ nodes, edges }); // 复制一份数据
|
|
|
+ historyList = []; // 初始化历史纪录
|
|
|
+};
|
|
|
|
|
|
// 为父组件提供更新node中的data数据的操作 一般只更新information就行了 更新一个node的值
|
|
|
const updateNodeData = (node: HJNodeData) => {
|
|
|
- console.log('updateNodeData', node)
|
|
|
+ console.log("updateNodeData", node);
|
|
|
|
|
|
if (node.id) {
|
|
|
- const findNodeData = findNode(node.id) as HJNodeData
|
|
|
- findNodeData.data.information = node.data.information
|
|
|
- console.log('findNodeData', findNodeData)
|
|
|
+ const findNodeData = findNode(node.id) as HJNodeData;
|
|
|
+ findNodeData.data.information = node.data.information;
|
|
|
+ console.log("findNodeData", findNodeData);
|
|
|
// updateNode(node.id, node)
|
|
|
}
|
|
|
-}
|
|
|
+};
|
|
|
|
|
|
defineExpose({
|
|
|
updateNodeData,
|
|
|
- initFlow
|
|
|
-})
|
|
|
+ initFlow,
|
|
|
+});
|
|
|
|
|
|
// ======= Panel =======
|
|
|
// 测试layout 点击切换布局时候的操作
|
|
|
-const {layout} = useLayout()
|
|
|
+const { layout } = useLayout();
|
|
|
|
|
|
-async function layoutGraph(direction: 'LR' | 'TB') {
|
|
|
- nodes.value = layout(nodes.value, edges.value, direction)
|
|
|
+async function layoutGraph(direction: "LR" | "TB") {
|
|
|
+ nodes.value = layout(nodes.value, edges.value, direction);
|
|
|
+
|
|
|
+ console.log("排序完", nodes.value);
|
|
|
|
|
|
nextTick(() => {
|
|
|
- fitView()
|
|
|
- })
|
|
|
+ fitView();
|
|
|
+ nodes.value = sortNodesByPosition(nodes.value);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
const pannelOperations = {
|
|
|
addNode: (nodeType: HJNodeType) => {
|
|
|
- console.log('addNode', nodeType);
|
|
|
+ console.log("addNode", nodeType);
|
|
|
},
|
|
|
- layout: (direction: 'LR' | 'TB') => {
|
|
|
- layoutGraph(direction)
|
|
|
+ layout: (direction: "LR" | "TB") => {
|
|
|
+ layoutGraph(direction);
|
|
|
},
|
|
|
toSnake: () => {
|
|
|
- console.log('toSnake');
|
|
|
- nodes.value = useSnakeLayoutHook(nodes.value, edges.value)
|
|
|
+ console.log("toSnake");
|
|
|
+ nodes.value = useSnakeLayoutHook(nodes.value, edges.value);
|
|
|
+ nextTick(() => {
|
|
|
+ fitView();
|
|
|
+ });
|
|
|
},
|
|
|
reset: () => {
|
|
|
- console.log('reset');
|
|
|
+ console.log("reset");
|
|
|
if (originData && JSON.parse(originData)) {
|
|
|
- let data = JSON.parse(originData)
|
|
|
+ let data = JSON.parse(originData);
|
|
|
nodes.value = data.nodes;
|
|
|
edges.value = data.edges;
|
|
|
- historyList = []
|
|
|
+ historyList = [];
|
|
|
}
|
|
|
},
|
|
|
back: () => {
|
|
|
- console.log('back');
|
|
|
+ console.log("back");
|
|
|
let firstHistory = historyList.shift();
|
|
|
if (firstHistory) {
|
|
|
- let historyData = JSON.parse(firstHistory)
|
|
|
+ let historyData = JSON.parse(firstHistory);
|
|
|
nodes.value = historyData.nodes;
|
|
|
edges.value = historyData.edges;
|
|
|
} else {
|
|
|
ElMessage.warning("已是初始线路");
|
|
|
}
|
|
|
- }
|
|
|
-}
|
|
|
+ },
|
|
|
+ saveTemplate: () => {
|
|
|
+ emits("hjMethod", HJMethodName.SaveTemplate, nodes.value[0]);
|
|
|
+ },
|
|
|
+};
|
|
|
// ======= Panel ======= ↑↑↑↑↑↑↑↑↑↑↑↑↑↑
|
|
|
-
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <VueFlow v-model:nodes="nodes" v-model:edges="edges" :node-types="nodeTypes" :edgeTypes="edgeTypes"
|
|
|
- @dragover="onDragOver" @dragleave="onDragLeave" @drop="onDrop" @nodeDoubleClick="doubleClick" @edge-click="onClickEdge" @nodes-change="onFlowNodesChange" @edges-change="onFlowEdgesChange">
|
|
|
+ <VueFlow
|
|
|
+ v-model:nodes="nodes"
|
|
|
+ v-model:edges="edges"
|
|
|
+ :node-types="nodeTypes"
|
|
|
+ :edgeTypes="edgeTypes"
|
|
|
+ @dragover="onDragOver"
|
|
|
+ @dragleave="onDragLeave"
|
|
|
+ @drop="onDrop"
|
|
|
+ @nodeDoubleClick="doubleClick"
|
|
|
+ @edge-click="onClickEdge"
|
|
|
+ @nodes-change="onFlowNodesChange"
|
|
|
+ @edges-change="onFlowEdgesChange"
|
|
|
+ >
|
|
|
<DropzoneBackground
|
|
|
- :style="{
|
|
|
- backgroundColor: isDragOver ? '#e7f3ff' : 'transparent',
|
|
|
- transition: 'background-color 0.2s ease',
|
|
|
- }"
|
|
|
+ :style="{
|
|
|
+ backgroundColor: isDragOver ? '#e7f3ff' : 'transparent',
|
|
|
+ transition: 'background-color 0.2s ease',
|
|
|
+ }"
|
|
|
>
|
|
|
-<!-- <p v-if="isDragOver">Drop here</p>-->
|
|
|
+ <!-- <p v-if="isDragOver">Drop here</p>-->
|
|
|
</DropzoneBackground>
|
|
|
|
|
|
<!-- 右面上工具栏操作 -->
|
|
|
- <Panel v-if="showPanel" v-on="pannelOperations" :fun-names="panelBtns"></Panel>
|
|
|
-
|
|
|
-
|
|
|
+ <Panel
|
|
|
+ v-if="showPanel"
|
|
|
+ v-on="pannelOperations"
|
|
|
+ :fun-names="panelBtns"
|
|
|
+ ></Panel>
|
|
|
</VueFlow>
|
|
|
</template>
|
|
|
|
|
|
-<style scoped lang="less">
|
|
|
-
|
|
|
-</style>
|
|
|
+<style scoped lang="less"></style>
|