mirror of
https://github.com/Powerful-517/yys-editor.git
synced 2025-10-14 06:20:58 +00:00
326 lines
10 KiB
TypeScript
326 lines
10 KiB
TypeScript
import {defineStore} from 'pinia';
|
||
import {ref, computed} from 'vue';
|
||
// import type { Edge, Node, ViewportTransform } from '@vue-flow/core';
|
||
import {ElMessageBox} from "element-plus";
|
||
import {useGlobalMessage} from "./useGlobalMessage";
|
||
import {getLogicFlowInstance} from "./useLogicFlow";
|
||
|
||
const {showMessage} = useGlobalMessage();
|
||
|
||
// localStorage 防抖定时器
|
||
let localStorageDebounceTimer: NodeJS.Timeout | null = null;
|
||
const LOCALSTORAGE_DEBOUNCE_DELAY = 1000; // 1秒防抖
|
||
|
||
interface FlowFile {
|
||
label: string;
|
||
name: string;
|
||
visible: boolean;
|
||
type: string;
|
||
graphRawData?: object;
|
||
transform?: {
|
||
"SCALE_X": number,
|
||
"SCALE_Y": number,
|
||
"TRANSLATE_X": number,
|
||
"TRANSLATE_Y": number
|
||
};
|
||
}
|
||
|
||
function getDefaultState() {
|
||
return {
|
||
"fileList": [
|
||
{
|
||
"label": "File 1",
|
||
"name": "File 1",
|
||
"visible": true,
|
||
"type": "FLOW",
|
||
"graphRawData": {
|
||
"nodes": [],
|
||
"edges": []
|
||
},
|
||
"transform": {
|
||
"SCALE_X": 1,
|
||
"SCALE_Y": 1,
|
||
"TRANSLATE_X": 0,
|
||
"TRANSLATE_Y": 0
|
||
}
|
||
}
|
||
],
|
||
"activeFile": "File 1"
|
||
};
|
||
}
|
||
|
||
function clearFilesStoreLocalStorage() {
|
||
localStorage.removeItem('filesStore');
|
||
}
|
||
|
||
function loadStateFromLocalStorage() {
|
||
try {
|
||
const data = localStorage.getItem('filesStore');
|
||
return data ? JSON.parse(data) : null;
|
||
} catch (error) {
|
||
console.error('从 localStorage 加载数据失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
function saveStateToLocalStorage(state: any) {
|
||
// 清除之前的防抖定时器
|
||
if (localStorageDebounceTimer) {
|
||
clearTimeout(localStorageDebounceTimer);
|
||
}
|
||
|
||
// 设置新的防抖定时器
|
||
localStorageDebounceTimer = setTimeout(() => {
|
||
try {
|
||
localStorage.setItem('filesStore', JSON.stringify(state));
|
||
console.log('数据已防抖保存到 localStorage');
|
||
} catch (error) {
|
||
console.error('保存到 localStorage 失败:', error);
|
||
// 如果 localStorage 满了,尝试清理一些数据
|
||
try {
|
||
localStorage.clear();
|
||
localStorage.setItem('filesStore', JSON.stringify(state));
|
||
} catch (clearError) {
|
||
console.error('清理 localStorage 后仍无法保存:', clearError);
|
||
}
|
||
}
|
||
}, LOCALSTORAGE_DEBOUNCE_DELAY);
|
||
}
|
||
|
||
|
||
export const useFilesStore = defineStore('files', () => {
|
||
// 文件列表状态
|
||
const fileList = ref<FlowFile[]>([]);
|
||
const activeFile = ref<string>('');
|
||
|
||
// 计算属性:获取可见的文件
|
||
const visibleFiles = computed(() => {
|
||
return fileList.value.filter(file => file.visible);
|
||
});
|
||
|
||
// 导入数据
|
||
const importData = (data: any) => {
|
||
try {
|
||
if (data.fileList && Array.isArray(data.fileList)) {
|
||
// 新版本格式:包含 fileList 和 activeFile
|
||
fileList.value = data.fileList;
|
||
activeFile.value = data.activeFile || data[0]?.name;
|
||
showMessage('success', '数据导入成功');
|
||
} else if (Array.isArray(data) && data[0]?.visible === true) {
|
||
// 兼容旧版本格式:直接是 fileList 数组
|
||
fileList.value = data;
|
||
activeFile.value = data[0]?.name || "1";
|
||
showMessage('success', '数据导入成功');
|
||
} else {
|
||
// 兼容更旧版本格式:仅包含 groups 数组
|
||
const newFile = {
|
||
label: `File ${fileList.value.length + 1}`,
|
||
name: String(fileList.value.length + 1),
|
||
visible: true,
|
||
type: "FLOW",
|
||
groups: data,
|
||
graphRawData: {
|
||
nodes: [],
|
||
edges: []
|
||
},
|
||
transform: {
|
||
SCALE_X: 1,
|
||
SCALE_Y: 1,
|
||
TRANSLATE_X: 0,
|
||
TRANSLATE_Y: 0
|
||
}
|
||
};
|
||
fileList.value.push(newFile);
|
||
activeFile.value = newFile.name;
|
||
showMessage('success', '数据导入成功');
|
||
}
|
||
} catch (error) {
|
||
console.error('Failed to import file', error);
|
||
showMessage('error', '数据导入失败');
|
||
}
|
||
};
|
||
|
||
// 导出数据
|
||
const exportData = () => {
|
||
try {
|
||
const dataStr = JSON.stringify({
|
||
fileList: fileList.value,
|
||
activeFile: activeFile.value
|
||
}, null, 2);
|
||
const blob = new Blob([dataStr], {type: 'application/json;charset=utf-8'});
|
||
const url = URL.createObjectURL(blob);
|
||
const link = document.createElement('a');
|
||
link.href = url;
|
||
link.download = 'yys-editor-files.json';
|
||
link.click();
|
||
URL.revokeObjectURL(url);
|
||
showMessage('success', '数据导出成功');
|
||
} catch (error) {
|
||
console.error('导出数据失败:', error);
|
||
showMessage('error', '数据导出失败');
|
||
}
|
||
};
|
||
|
||
// 初始化时检查是否有未保存的数据
|
||
const initializeWithPrompt = () => {
|
||
const savedState = loadStateFromLocalStorage();
|
||
const defaultState = getDefaultState();
|
||
|
||
// 如果没有保存的数据,使用默认状态
|
||
if (!savedState) {
|
||
fileList.value = defaultState.fileList;
|
||
activeFile.value = defaultState.activeFile;
|
||
return;
|
||
}
|
||
|
||
const isSame = JSON.stringify(savedState) === JSON.stringify(defaultState);
|
||
if (savedState && !isSame) {
|
||
ElMessageBox.confirm(
|
||
'检测到有未保存的旧数据,是否恢复?',
|
||
'提示',
|
||
{
|
||
confirmButtonText: '恢复',
|
||
cancelButtonText: '不恢复',
|
||
type: 'warning',
|
||
}
|
||
).then(() => {
|
||
fileList.value = savedState.fileList || [];
|
||
activeFile.value = savedState.activeFile || "1";
|
||
showMessage('success', '数据已恢复');
|
||
}).catch(() => {
|
||
clearFilesStoreLocalStorage();
|
||
fileList.value = defaultState.fileList;
|
||
activeFile.value = defaultState.activeFile;
|
||
showMessage('info', '选择了不恢复旧数据');
|
||
});
|
||
} else {
|
||
// 如果有保存的数据且与默认状态相同,直接使用保存的数据
|
||
fileList.value = savedState.fileList || defaultState.fileList;
|
||
activeFile.value = savedState.activeFile || defaultState.activeFile;
|
||
}
|
||
};
|
||
|
||
// 设置自动更新
|
||
const setupAutoSave = () => {
|
||
console.log('自动更新功能已启动,每30秒更新一次');
|
||
setInterval(() => {
|
||
updateTab(); // 使用统一的更新方法
|
||
}, 30000); // 设置间隔时间为30秒
|
||
};
|
||
|
||
// 添加新文件
|
||
const addTab = () => {
|
||
// 添加文件前先保存
|
||
updateTab();
|
||
|
||
requestAnimationFrame(() => {
|
||
const newFileName = `File ${fileList.value.length + 1}`;
|
||
const newFile = {
|
||
label: newFileName,
|
||
name: newFileName,
|
||
visible: true,
|
||
type: 'FLOW',
|
||
graphRawData: {},
|
||
transform: {
|
||
SCALE_X: 1,
|
||
SCALE_Y: 1,
|
||
TRANSLATE_X: 0,
|
||
TRANSLATE_Y: 0
|
||
}
|
||
};
|
||
fileList.value.push(newFile);
|
||
activeFile.value = newFileName;
|
||
});
|
||
};
|
||
|
||
// 关闭文件标签
|
||
const removeTab = (fileName: string | undefined) => {
|
||
if (!fileName) return;
|
||
|
||
const index = fileList.value.findIndex(file => file.name === fileName);
|
||
if (index === -1) return;
|
||
|
||
fileList.value.splice(index, 1);
|
||
|
||
// 如果关闭的是当前活动文件,则切换到其他文件
|
||
if (activeFile.value === fileName) {
|
||
activeFile.value = fileList.value[Math.max(0, index - 1)]?.name || '';
|
||
}
|
||
|
||
// 关闭文件后立即更新
|
||
updateTab();
|
||
};
|
||
|
||
// 更新指定 Tab - 内存操作即时,localStorage 操作防抖
|
||
const updateTab = (fileName?: string) => {
|
||
try {
|
||
const targetFile = fileName || activeFile.value;
|
||
|
||
// 先同步 LogicFlow 数据到内存
|
||
syncLogicFlowDataToStore(targetFile);
|
||
|
||
// 再保存到 localStorage(带防抖)
|
||
const state = {
|
||
fileList: fileList.value,
|
||
activeFile: activeFile.value
|
||
};
|
||
saveStateToLocalStorage(state);
|
||
} catch (error) {
|
||
console.error('更新 Tab 失败:', error);
|
||
showMessage('error', '数据更新失败');
|
||
}
|
||
};
|
||
|
||
// 获取当前 Tab 数据
|
||
const getTab = (fileName?: string) => {
|
||
const targetFile = fileName || activeFile.value;
|
||
return fileList.value.find(f => f.name === targetFile);
|
||
};
|
||
|
||
// 同步 LogicFlow 画布数据到 store 的内部方法
|
||
const syncLogicFlowDataToStore = (fileName?: string) => {
|
||
const logicFlowInstance = getLogicFlowInstance();
|
||
const targetFile = fileName || activeFile.value;
|
||
|
||
if (logicFlowInstance && targetFile) {
|
||
try {
|
||
// 获取画布最新数据
|
||
const graphData = logicFlowInstance.getGraphRawData();
|
||
const transform = logicFlowInstance.getTransform();
|
||
|
||
if (graphData) {
|
||
// 直接保存原始数据到 GraphRawData
|
||
const file = fileList.value.find(f => f.name === targetFile);
|
||
if (file) {
|
||
file.graphRawData = graphData;
|
||
file.transform = transform;
|
||
console.log(`已同步画布数据到文件 "${targetFile}"`);
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.warn('同步画布数据失败:', error);
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
return {
|
||
importData,
|
||
exportData,
|
||
|
||
initializeWithPrompt,
|
||
setupAutoSave,
|
||
|
||
addTab,
|
||
removeTab,
|
||
updateTab,
|
||
getTab,
|
||
|
||
fileList,
|
||
activeFile,
|
||
visibleFiles,
|
||
};
|
||
}); |