// 文件管理器 - 处理流程文件的加载、保存和管理 function FileManager() { this.currentFileName = "新流程.json"; this.currentDirectory = "默认目录"; // 当前工作目录 this.processFiles = new Map(); // 存储所有流程文件数据,key为完整路径 this.directoryHandle = null; // File System Access API 目录句柄 this.supportsFileSystemAccess = false; // 是否支持 File System Access API this.initializeDefaultFiles(); this.checkFileSystemAccessSupport(); } // 初始化默认文件 FileManager.prototype.initializeDefaultFiles = function() { // 创建一个默认的空流程文件 this.processFiles.set("新流程.json", []); // 可以添加一些示例文件 this.addSampleFile(); }; // 添加示例文件 FileManager.prototype.addSampleFile = function() { var sampleStep = DataUtils.createNewStep(); sampleStep.StepDescription = "示例步骤"; var sampleAction = DataUtils.createNewAction(); sampleAction.Title = "示例动作"; sampleAction.Description = "这是一个示例动作"; var sampleTarget = DataUtils.createNewTargetObject(); sampleTarget.ObjectName = "示例对象"; sampleTarget.Type = ProcessTargetType.EVENT; sampleTarget.Score = 10; sampleAction.TargetObjects.push(sampleTarget); sampleStep.Actions.push(sampleAction); this.processFiles.set("示例流程.json", [sampleStep]); }; // 获取所有文件名 FileManager.prototype.getFileNames = function() { return Array.from(this.processFiles.keys()); }; // 获取当前文件名 FileManager.prototype.getCurrentFileName = function() { return this.currentFileName; }; // 设置当前文件 FileManager.prototype.setCurrentFile = function(fileName) { if (this.processFiles.has(fileName)) { this.currentFileName = fileName; return true; } return false; }; // 加载流程文件 FileManager.prototype.loadProcessFile = function(fileName) { if (this.processFiles.has(fileName)) { var data = this.processFiles.get(fileName); return DataUtils.deepClone(data); } return []; }; // 保存流程文件 FileManager.prototype.saveProcessFile = function(fileName, steps) { try { // 验证数据 for (var i = 0; i < steps.length; i++) { var validation = DataUtils.validateStep(steps[i]); if (!validation.valid) { throw new Error("步骤 " + (i + 1) + ": " + validation.message); } } // 清理数据 var cleanedSteps = []; for (var i = 0; i < steps.length; i++) { var cleanedStep = DataUtils.deepClone(steps[i]); var cleanedActions = []; for (var j = 0; j < cleanedStep.Actions.length; j++) { cleanedActions.push(DataUtils.cleanActionData(cleanedStep.Actions[j])); } cleanedStep.Actions = cleanedActions; cleanedSteps.push(cleanedStep); } // 保存到内存 this.processFiles.set(fileName, cleanedSteps); this.currentFileName = fileName; // 如果支持本地存储,也保存到localStorage if (typeof Storage !== "undefined") { var allFiles = {}; var self = this; this.processFiles.forEach(function(value, key) { allFiles[key] = value; }); localStorage.setItem('sceneStepEditor_files', JSON.stringify(allFiles)); } return { success: true }; } catch (error) { return { success: false, error: error.message }; } }; // 创建新流程文件 FileManager.prototype.createNewProcessFile = function(fileName) { if (!fileName || fileName.trim() === "") { return { success: false, error: "文件名不能为空" }; } // 确保文件名以.json结尾 if (!fileName.endsWith('.json')) { fileName += '.json'; } // 检查文件是否已存在 if (this.processFiles.has(fileName)) { return { success: false, error: "文件已存在" }; } // 创建新文件 this.processFiles.set(fileName, []); this.currentFileName = fileName; return { success: true, fileName: fileName }; }; // 获取当前目录 FileManager.prototype.getCurrentDirectory = function() { return this.currentDirectory; }; // 设置当前目录 FileManager.prototype.setCurrentDirectory = function(directoryName) { this.currentDirectory = directoryName || "默认目录"; }; // 从目录中加载文件 FileManager.prototype.loadFilesFromDirectory = function(files) { var self = this; var loadedCount = 0; var totalFiles = 0; // 计算json文件总数 for (var i = 0; i < files.length; i++) { if (files[i].name.toLowerCase().endsWith('.json')) { totalFiles++; } } if (totalFiles === 0) { return Promise.resolve({ success: false, error: "所选目录中没有找到JSON文件" }); } return new Promise(function(resolve) { // 清空当前文件(保留默认文件) var keysToDelete = []; self.processFiles.forEach(function(value, key) { if (key !== "新流程.json" && key !== "示例流程.json") { keysToDelete.push(key); } }); keysToDelete.forEach(function(key) { self.processFiles.delete(key); }); // 设置目录名(使用第一个文件的父目录名) if (files.length > 0 && files[0].webkitRelativePath) { var pathParts = files[0].webkitRelativePath.split('/'); if (pathParts.length > 1) { self.currentDirectory = pathParts[0]; } } // 逐个读取JSON文件 for (var i = 0; i < files.length; i++) { var file = files[i]; if (file.name.toLowerCase().endsWith('.json')) { // 使用闭包捕获当前文件对象,避免异步回调时变量引用错误 (function(currentFile) { self.readFileContent(currentFile, function(fileName, content, error) { loadedCount++; if (!error) { try { var data = JSON.parse(content); // 验证数据格式 if (Array.isArray(data)) { // 使用相对路径作为key var relativePath = fileName; if (currentFile.webkitRelativePath) { // 移除目录前缀,只保留文件名 var parts = currentFile.webkitRelativePath.split('/'); relativePath = parts[parts.length - 1]; } self.processFiles.set(relativePath, data); console.log("成功加载文件: " + relativePath); } } catch (parseError) { console.warn("无法解析JSON文件: " + fileName, parseError); } } else { console.warn("读取文件失败: " + fileName, error); } // 所有文件处理完成 if (loadedCount === totalFiles) { console.log("目录加载完成,总计加载文件: " + (self.processFiles.size - 2)); resolve({ success: true, loadedFiles: self.processFiles.size - 2, // 减去默认文件数量 directory: self.currentDirectory }); } }); })(file); } } }); }; // 读取文件内容 FileManager.prototype.readFileContent = function(file, callback) { var reader = new FileReader(); reader.onload = function(e) { callback(file.name, e.target.result, null); }; reader.onerror = function(e) { callback(file.name, null, e); }; reader.readAsText(file, 'utf-8'); }; // 获取当前目录下的文件(用于下拉列表显示) FileManager.prototype.getFilesInCurrentDirectory = function() { var files = []; var self = this; this.processFiles.forEach(function(value, key) { // 如果是默认文件或者不包含路径分隔符,直接添加 if (key === "新流程.json" || key === "示例流程.json" || key.indexOf('/') === -1) { files.push(key); } }); return files; }; // 创建新流程文件(保存到当前目录) FileManager.prototype.createNewProcessFileInCurrentDir = function(fileName) { if (!fileName || fileName.trim() === "") { return { success: false, error: "文件名不能为空" }; } // 确保文件名以.json结尾 if (!fileName.endsWith('.json')) { fileName += '.json'; } // 构建完整路径(当前目录下的文件) var fullPath = fileName; // 简化路径,直接使用文件名 // 检查文件是否已存在 if (this.processFiles.has(fullPath)) { return { success: false, error: "文件已存在" }; } // 创建新文件 this.processFiles.set(fullPath, []); this.currentFileName = fullPath; return { success: true, fileName: fullPath, directory: this.currentDirectory }; }; // 检查 File System Access API 支持 FileManager.prototype.checkFileSystemAccessSupport = function() { this.supportsFileSystemAccess = 'showDirectoryPicker' in window && 'showSaveFilePicker' in window; console.log("File System Access API 支持状态:", this.supportsFileSystemAccess); }; // 使用 File System Access API 选择目录 FileManager.prototype.selectDirectoryWithAPI = function() { var self = this; if (!this.supportsFileSystemAccess) { return Promise.reject(new Error("浏览器不支持 File System Access API")); } return window.showDirectoryPicker().then(function(handle) { self.directoryHandle = handle; self.currentDirectory = handle.name; console.log("已选择目录:", handle.name); // 存储目录句柄到 IndexedDB 以便下次使用 self.storeDirectoryHandle(handle); return self.loadFilesFromDirectoryHandle(handle); }); }; // 存储目录句柄到 IndexedDB FileManager.prototype.storeDirectoryHandle = function(handle) { if (typeof indexedDB !== 'undefined') { var request = indexedDB.open('SceneStepEditor', 1); request.onupgradeneeded = function(e) { var db = e.target.result; if (!db.objectStoreNames.contains('directoryHandles')) { db.createObjectStore('directoryHandles'); } }; request.onsuccess = function(e) { var db = e.target.result; var transaction = db.transaction(['directoryHandles'], 'readwrite'); var store = transaction.objectStore('directoryHandles'); store.put(handle, 'currentDirectory'); console.log("目录句柄已保存到 IndexedDB"); }; } }; // 从 IndexedDB 恢复目录句柄 FileManager.prototype.restoreDirectoryHandle = function() { var self = this; if (typeof indexedDB === 'undefined' || !this.supportsFileSystemAccess) { return Promise.resolve(null); } return new Promise(function(resolve) { var request = indexedDB.open('SceneStepEditor', 1); request.onsuccess = function(e) { var db = e.target.result; if (!db.objectStoreNames.contains('directoryHandles')) { resolve(null); return; } var transaction = db.transaction(['directoryHandles'], 'readonly'); var store = transaction.objectStore('directoryHandles'); var getRequest = store.get('currentDirectory'); getRequest.onsuccess = function() { var handle = getRequest.result; if (handle) { // 验证句柄是否仍然有效 handle.queryPermission().then(function(permission) { if (permission === 'granted') { self.directoryHandle = handle; self.currentDirectory = handle.name; console.log("已恢复目录句柄:", handle.name); resolve(handle); } else { resolve(null); } }).catch(function() { resolve(null); }); } else { resolve(null); } }; getRequest.onerror = function() { resolve(null); }; }; request.onerror = function() { resolve(null); }; }); }; // 从目录句柄加载文件 FileManager.prototype.loadFilesFromDirectoryHandle = function(directoryHandle) { var self = this; return new Promise(async function(resolve) { try { var loadedFiles = 0; var filePromises = []; // 清空当前文件(保留默认文件) var keysToDelete = []; self.processFiles.forEach(function(value, key) { if (key !== "新流程.json" && key !== "示例流程.json") { keysToDelete.push(key); } }); keysToDelete.forEach(function(key) { self.processFiles.delete(key); }); // 使用 for await...of 遍历目录中的文件 for await (const entry of directoryHandle.values()) { if (entry.kind === 'file' && entry.name.toLowerCase().endsWith('.json')) { var promise = entry.getFile().then(function(file) { return file.text().then(function(content) { try { var data = JSON.parse(content); if (Array.isArray(data)) { self.processFiles.set(entry.name, data); loadedFiles++; console.log("成功加载文件:", entry.name); } } catch (parseError) { console.warn("无法解析JSON文件:", entry.name, parseError); } }); }).catch(function(error) { console.warn("读取文件失败:", entry.name, error); }); filePromises.push(promise); } } // 等待所有文件读取完成 await Promise.all(filePromises); resolve({ success: true, loadedFiles: loadedFiles, directory: directoryHandle.name }); } catch (error) { console.error("遍历目录失败:", error); resolve({ success: false, error: error.message }); } }); }; // 直接写入文件到选择的目录 FileManager.prototype.writeFileToDirectory = function(fileName, data) { var self = this; if (!this.supportsFileSystemAccess || !this.directoryHandle) { return Promise.reject(new Error("未选择目录或浏览器不支持直接写入")); } // 确保文件名以.json结尾 if (!fileName.endsWith('.json')) { fileName += '.json'; } return this.directoryHandle.getFileHandle(fileName, { create: true }).then(function(fileHandle) { return fileHandle.createWritable().then(function(writable) { var jsonString = JSON.stringify(data, null, 2); return writable.write(jsonString).then(function() { return writable.close().then(function() { console.log("文件已写入目录:", fileName); // 更新内存中的数据 self.processFiles.set(fileName, data); self.currentFileName = fileName; return { success: true, fileName: fileName, directory: self.currentDirectory }; }); }); }); }); };