mirror of
https://github.com/Powerful-517/yys-editor.git
synced 2025-08-23 08:04:50 +00:00
持久化支持
This commit is contained in:
@@ -14,7 +14,7 @@ import { useVueFlow } from '@vue-flow/core';
|
|||||||
import DialogManager from './components/DialogManager.vue';
|
import DialogManager from './components/DialogManager.vue';
|
||||||
|
|
||||||
const filesStore = useFilesStore();
|
const filesStore = useFilesStore();
|
||||||
const { updateNode } = useVueFlow();
|
const { updateNode,toObject,fromObject } = useVueFlow();
|
||||||
|
|
||||||
const width = ref('100%');
|
const width = ref('100%');
|
||||||
const height = ref('100vh');
|
const height = ref('100vh');
|
||||||
@@ -100,6 +100,7 @@ watch(
|
|||||||
if (oldVal && flowEditorRef.value && flowEditorRef.value.getViewport) {
|
if (oldVal && flowEditorRef.value && flowEditorRef.value.getViewport) {
|
||||||
const viewport = flowEditorRef.value.getViewport();
|
const viewport = flowEditorRef.value.getViewport();
|
||||||
filesStore.updateFileViewport(oldVal, viewport);
|
filesStore.updateFileViewport(oldVal, viewport);
|
||||||
|
filesStore.updateFileFlowData(oldVal, toObject());
|
||||||
}
|
}
|
||||||
lastActiveFile.value = newVal;
|
lastActiveFile.value = newVal;
|
||||||
}
|
}
|
||||||
@@ -135,9 +136,9 @@ watch(
|
|||||||
<FlowEditor
|
<FlowEditor
|
||||||
ref="flowEditorRef"
|
ref="flowEditorRef"
|
||||||
:height="contentHeight"
|
:height="contentHeight"
|
||||||
:nodes="filesStore.activeFileNodes"
|
:nodes="filesStore.getFileFlowData(filesStore.activeFile)?.nodes || []"
|
||||||
:edges="filesStore.activeFileEdges"
|
:edges="filesStore.getFileFlowData(filesStore.activeFile)?.edges || []"
|
||||||
:viewport="filesStore.getFileViewport(filesStore.activeFile)"
|
:viewport="filesStore.getFileFlowData(filesStore.activeFile)?.viewport || { x: 0, y: 0, zoom: 1 }"
|
||||||
:key="filesStore.activeFile"
|
:key="filesStore.activeFile"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -189,18 +189,6 @@ onUnmounted(() => {
|
|||||||
const lastActiveFile = ref(filesStore.activeFile);
|
const lastActiveFile = ref(filesStore.activeFile);
|
||||||
|
|
||||||
const flowEditorRef = ref();
|
const flowEditorRef = ref();
|
||||||
|
|
||||||
watch(
|
|
||||||
() => filesStore.activeFile,
|
|
||||||
(newVal, oldVal) => {
|
|
||||||
// 切换前保存旧 tab 的 viewport
|
|
||||||
if (oldVal && flowEditorRef.value && flowEditorRef.value.getViewport) {
|
|
||||||
const viewport = flowEditorRef.value.getViewport();
|
|
||||||
filesStore.updateFileViewport(oldVal, viewport);
|
|
||||||
}
|
|
||||||
lastActiveFile.value = newVal;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -209,8 +197,8 @@ watch(
|
|||||||
<!-- 中间流程图区域 -->
|
<!-- 中间流程图区域 -->
|
||||||
<div class="flow-container">
|
<div class="flow-container">
|
||||||
<VueFlow
|
<VueFlow
|
||||||
:nodes="filesStore.activeFileNodes"
|
:nodes="props.nodes"
|
||||||
:edges="filesStore.activeFileEdges"
|
:edges="props.edges"
|
||||||
@nodes-change="handleNodesChange"
|
@nodes-change="handleNodesChange"
|
||||||
@edges-change="handleEdgesChange"
|
@edges-change="handleEdgesChange"
|
||||||
@connect="handleConnect"
|
@connect="handleConnect"
|
||||||
|
@@ -15,9 +15,7 @@ interface FlowFile {
|
|||||||
visible: boolean;
|
visible: boolean;
|
||||||
type: string;
|
type: string;
|
||||||
groups: FileGroup[];
|
groups: FileGroup[];
|
||||||
nodes?: Node[];
|
flowData?: any;
|
||||||
edges?: Edge[];
|
|
||||||
viewport?: { x: number; y: number; zoom: number };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useFilesStore = defineStore('files', () => {
|
export const useFilesStore = defineStore('files', () => {
|
||||||
@@ -33,21 +31,23 @@ export const useFilesStore = defineStore('files', () => {
|
|||||||
// 获取当前活动文件的节点和边
|
// 获取当前活动文件的节点和边
|
||||||
const activeFileNodes = computed(() => {
|
const activeFileNodes = computed(() => {
|
||||||
const file = fileList.value.find(f => f.name === activeFile.value);
|
const file = fileList.value.find(f => f.name === activeFile.value);
|
||||||
return file?.nodes || [];
|
return file?.flowData?.nodes || [];
|
||||||
});
|
});
|
||||||
|
|
||||||
const activeFileEdges = computed(() => {
|
const activeFileEdges = computed(() => {
|
||||||
const file = fileList.value.find(f => f.name === activeFile.value);
|
const file = fileList.value.find(f => f.name === activeFile.value);
|
||||||
return file?.edges || [];
|
return file?.flowData?.edges || [];
|
||||||
});
|
});
|
||||||
|
|
||||||
// 添加新文件
|
// 添加新文件
|
||||||
const addFile = (file: FlowFile) => {
|
const addFile = (file: FlowFile) => {
|
||||||
// 确保新文件包含空的节点和边数组
|
|
||||||
const newFile = {
|
const newFile = {
|
||||||
...file,
|
...file,
|
||||||
|
flowData: {
|
||||||
nodes: [],
|
nodes: [],
|
||||||
edges: []
|
edges: [],
|
||||||
|
viewport: { x: 0, y: 0, zoom: 1 }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
fileList.value.push(newFile);
|
fileList.value.push(newFile);
|
||||||
activeFile.value = file.name;
|
activeFile.value = file.name;
|
||||||
@@ -72,21 +72,18 @@ export const useFilesStore = defineStore('files', () => {
|
|||||||
const addNode = (node: Node) => {
|
const addNode = (node: Node) => {
|
||||||
const file = fileList.value.find(f => f.name === activeFile.value);
|
const file = fileList.value.find(f => f.name === activeFile.value);
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
if (!file.flowData) file.flowData = { nodes: [], edges: [], viewport: { x: 0, y: 0, zoom: 1 } };
|
||||||
if (!file.nodes) file.nodes = [];
|
file.flowData.nodes.push(node);
|
||||||
file.nodes.push(node);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新节点
|
// 更新节点
|
||||||
const updateNode = (nodeId: string, updateData: Partial<Node>) => {
|
const updateNode = (nodeId: string, updateData: Partial<Node>) => {
|
||||||
const file = fileList.value.find(f => f.name === activeFile.value);
|
const file = fileList.value.find(f => f.name === activeFile.value);
|
||||||
if (!file || !file.nodes) return;
|
if (!file || !file.flowData || !file.flowData.nodes) return;
|
||||||
|
const nodeIndex = file.flowData.nodes.findIndex(n => n.id === nodeId);
|
||||||
const nodeIndex = file.nodes.findIndex(n => n.id === nodeId);
|
|
||||||
if (nodeIndex === -1) return;
|
if (nodeIndex === -1) return;
|
||||||
|
file.flowData.nodes[nodeIndex] = {
|
||||||
file.nodes[nodeIndex] = {
|
...file.flowData.nodes[nodeIndex],
|
||||||
...file.nodes[nodeIndex],
|
|
||||||
...updateData,
|
...updateData,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -94,12 +91,11 @@ export const useFilesStore = defineStore('files', () => {
|
|||||||
// 删除节点
|
// 删除节点
|
||||||
const removeNode = (nodeId: string) => {
|
const removeNode = (nodeId: string) => {
|
||||||
const file = fileList.value.find(f => f.name === activeFile.value);
|
const file = fileList.value.find(f => f.name === activeFile.value);
|
||||||
if (!file || !file.nodes) return;
|
if (!file || !file.flowData || !file.flowData.nodes) return;
|
||||||
|
file.flowData.nodes = file.flowData.nodes.filter(n => n.id !== nodeId);
|
||||||
file.nodes = file.nodes.filter(n => n.id !== nodeId);
|
|
||||||
// 同时删除相关的边
|
// 同时删除相关的边
|
||||||
if (file.edges) {
|
if (file.flowData.edges) {
|
||||||
file.edges = file.edges.filter(e => e.source !== nodeId && e.target !== nodeId);
|
file.flowData.edges = file.flowData.edges.filter(e => e.source !== nodeId && e.target !== nodeId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -107,25 +103,22 @@ export const useFilesStore = defineStore('files', () => {
|
|||||||
const addEdge = (edge: Edge) => {
|
const addEdge = (edge: Edge) => {
|
||||||
const file = fileList.value.find(f => f.name === activeFile.value);
|
const file = fileList.value.find(f => f.name === activeFile.value);
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
if (!file.flowData) file.flowData = { nodes: [], edges: [], viewport: { x: 0, y: 0, zoom: 1 } };
|
||||||
if (!file.edges) file.edges = [];
|
file.flowData.edges.push(edge);
|
||||||
file.edges.push(edge);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除边
|
// 删除边
|
||||||
const removeEdge = (edgeId: string) => {
|
const removeEdge = (edgeId: string) => {
|
||||||
const file = fileList.value.find(f => f.name === activeFile.value);
|
const file = fileList.value.find(f => f.name === activeFile.value);
|
||||||
if (!file || !file.edges) return;
|
if (!file || !file.flowData || !file.flowData.edges) return;
|
||||||
|
file.flowData.edges = file.flowData.edges.filter(e => e.id !== edgeId);
|
||||||
file.edges = file.edges.filter(e => e.id !== edgeId);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新节点位置
|
// 更新节点位置
|
||||||
const updateNodePosition = (nodeId: string, position: { x: number; y: number }) => {
|
const updateNodePosition = (nodeId: string, position: { x: number; y: number }) => {
|
||||||
const file = fileList.value.find(f => f.name === activeFile.value);
|
const file = fileList.value.find(f => f.name === activeFile.value);
|
||||||
if (!file || !file.nodes) return;
|
if (!file || !file.flowData || !file.flowData.nodes) return;
|
||||||
|
const node = file.flowData.nodes.find(n => n.id === nodeId);
|
||||||
const node = file.nodes.find(n => n.id === nodeId);
|
|
||||||
if (node) {
|
if (node) {
|
||||||
node.position = position;
|
node.position = position;
|
||||||
}
|
}
|
||||||
@@ -134,25 +127,37 @@ export const useFilesStore = defineStore('files', () => {
|
|||||||
// 更新节点顺序
|
// 更新节点顺序
|
||||||
const updateNodesOrder = (nodes: Node[]) => {
|
const updateNodesOrder = (nodes: Node[]) => {
|
||||||
const file = fileList.value.find(f => f.name === activeFile.value);
|
const file = fileList.value.find(f => f.name === activeFile.value);
|
||||||
if (!file) return;
|
if (!file || !file.flowData) return;
|
||||||
file.nodes = nodes;
|
file.flowData.nodes = nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新文件的 viewport
|
// 更新文件的 viewport
|
||||||
const updateFileViewport = (fileName: string, viewport: { x: number; y: number; zoom: number }) => {
|
const updateFileViewport = (fileName: string, viewport: { x: number; y: number; zoom: number }) => {
|
||||||
const file = fileList.value.find(f => f.name === fileName);
|
const file = fileList.value.find(f => f.name === fileName);
|
||||||
if (file) file.viewport = viewport;
|
if (file && file.flowData) file.flowData.viewport = viewport;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFileViewport = (fileName: string): ViewportTransform => {
|
const getFileViewport = (fileName: string): ViewportTransform => {
|
||||||
const file = fileList.value.find(f => f.name === fileName);
|
const file = fileList.value.find(f => f.name === fileName);
|
||||||
const v = file?.viewport;
|
const v = file?.flowData?.viewport;
|
||||||
if (v && typeof v.x === 'number' && typeof v.y === 'number' && typeof v.zoom === 'number') {
|
if (v && typeof v.x === 'number' && typeof v.y === 'number' && typeof v.zoom === 'number') {
|
||||||
return v as ViewportTransform;
|
return v as ViewportTransform;
|
||||||
}
|
}
|
||||||
return { x: 0, y: 0, zoom: 1 };
|
return { x: 0, y: 0, zoom: 1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 更新文件的 flowData
|
||||||
|
const updateFileFlowData = (fileName: string, flowData: any) => {
|
||||||
|
const file = fileList.value.find(f => f.name === fileName);
|
||||||
|
if (file) file.flowData = flowData;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取文件的 flowData
|
||||||
|
const getFileFlowData = (fileName: string): any => {
|
||||||
|
const file = fileList.value.find(f => f.name === fileName);
|
||||||
|
return file?.flowData;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fileList,
|
fileList,
|
||||||
activeFile,
|
activeFile,
|
||||||
@@ -170,5 +175,7 @@ export const useFilesStore = defineStore('files', () => {
|
|||||||
updateNodesOrder,
|
updateNodesOrder,
|
||||||
updateFileViewport,
|
updateFileViewport,
|
||||||
getFileViewport,
|
getFileViewport,
|
||||||
|
updateFileFlowData,
|
||||||
|
getFileFlowData,
|
||||||
};
|
};
|
||||||
});
|
});
|
Reference in New Issue
Block a user