123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- <script setup lang="ts">
- import {
- ref,
- onMounted,
- InjectionKey,
- Ref,
- provide,
- inject,
- nextTick,
- markRaw,
- } from "vue";
- import {
- HJMethodName,
- HJNodeData,
- HJNodeType,
- nodeTypes,
- edgeTypes,
- HJMethodProvideName,
- CurrentHeaderOperationProvideName,
- CurrentSelectedEdgeProvideName,
- HJFlowProps,
- } from "../types/comTypes";
- import Panel from "../panel/index.vue";
- import CommonEdge from "../edges/commonEdge.vue";
- import DropzoneBackground from "../background/DropzoneBackground.vue";
- import { useVueFlow, VueFlow, Edge } from "@vue-flow/core";
- import useDragAndDrop from "../hooks/useDnD";
- import { sortNodesByPosition, useLayout } from "../utils/useLayout";
- import { useSnakeLayoutHook } from "../hooks/snakeHooks";
- import { ElMessage } from "element-plus";
- defineOptions({
- name: "HJFlow",
- });
- 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>();
- // ==========vueflow 本身的方法操作 ===========
- 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));
- };
- // ======= Emits =======
- const emits = defineEmits<{
- 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);
- });
- ///// === 数据历史纪录 用于回退或者重置按钮 === /////
- 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")
- ) {
- 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")
- ) {
- 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 = []; // 初始化历史纪录
- };
- // 为父组件提供更新node中的data数据的操作 一般只更新information就行了 更新一个node的值
- const updateNodeData = (node: HJNodeData) => {
- console.log("updateNodeData", node);
- if (node.id) {
- const findNodeData = findNode(node.id) as HJNodeData;
- findNodeData.data.information = node.data.information;
- console.log("findNodeData", findNodeData);
- // updateNode(node.id, node)
- }
- };
- // 清空状态 比如选中某一个节点的状态
- const clearStatus = () => {
- currentHeaderOperationNodeData.value = null;
- currentClickEdgeData.value = null;
- historyList = [];
- };
- // 获取是否是正在编辑的状态 目前只判断节点的新增和删除 外面保存之后要清空状态
- const getChangedStatus = () => {
- return historyList.length > 0;
- };
- defineExpose({
- updateNodeData,
- initFlow,
- clearStatus,
- getChangedStatus
- });
- // ======= Panel =======
- // 测试layout 点击切换布局时候的操作
- const { layout } = useLayout();
- async function layoutGraph(direction: "LR" | "TB") {
- nodes.value = layout(nodes.value, edges.value, direction);
- console.log("排序完", nodes.value);
- nextTick(() => {
- fitView();
- nodes.value = sortNodesByPosition(nodes.value);
- });
- }
- const pannelOperations = {
- addNode: (nodeType: HJNodeType) => {
- console.log("addNode", nodeType);
- },
- layout: (direction: "LR" | "TB") => {
- layoutGraph(direction);
- },
- toSnake: () => {
- console.log("toSnake");
- nodes.value = useSnakeLayoutHook(nodes.value, edges.value);
- nextTick(() => {
- fitView();
- });
- },
- reset: () => {
- console.log("reset");
- if (originData && JSON.parse(originData)) {
- let data = JSON.parse(originData);
- nodes.value = data.nodes;
- edges.value = data.edges;
- historyList = [];
- }
- },
- back: () => {
- console.log("back");
- let firstHistory = historyList.shift();
- if (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"
- >
- <DropzoneBackground
- :style="{
- backgroundColor: isDragOver ? '#e7f3ff' : 'transparent',
- transition: 'background-color 0.2s ease',
- }"
- >
- <!-- <p v-if="isDragOver">Drop here</p>-->
- </DropzoneBackground>
- <!-- 右面上工具栏操作 -->
- <Panel
- v-if="showPanel"
- v-on="pannelOperations"
- :fun-names="panelBtns"
- ></Panel>
- </VueFlow>
- </template>
- <style scoped lang="less"></style>
|