2025-04-28 12:25:20 +08:00

281 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 文件操作模块
* @type {module}
*/
import { formatXml, markEdited, resetEditState } from './utils.js';
// 获取Scenario目录路径前缀
let scenarioDirPrefix = null;
/**
* 获取Scenario目录路径
* @returns {string} Scenario目录的绝对路径
*/
async function getScenarioDir() {
if (scenarioDirPrefix) return scenarioDirPrefix;
try {
// 从文件列表API获取Scenario目录路径
const response = await fetch('/api/scenario-files');
if (response.ok) {
const files = await response.json();
if (files && files.length > 0) {
// 提取第一个文件的目录作为Scenario目录
const filePath = files[0].path;
scenarioDirPrefix = filePath.substring(0, filePath.lastIndexOf('/'));
return scenarioDirPrefix;
}
}
return ''; // 如果无法获取,返回空字符串
} catch (error) {
console.error('获取Scenario目录失败:', error);
return '';
}
}
/**
* 加载场景文件列表
* @param {HTMLElement} component - 组件实例
* @returns {Promise<boolean>} 是否成功加载
*/
export async function loadScenarioFiles(component) {
// 设置按钮为刷新中状态
const refreshButton = component.shadowRoot.getElementById('refreshButton');
if (refreshButton) {
refreshButton.classList.add('refreshing');
}
let retryCount = 0;
const maxRetries = 3; // 最多重试3次
const tryLoadFiles = async () => {
try {
const response = await fetch('/api/scenario-files');
if (!response.ok) {
throw new Error(`服务器返回错误: ${response.status} ${response.statusText}`);
}
const files = await response.json();
component.scenarioFiles = files;
// 更新文件选择器
updateFileSelector(component);
return true;
} catch (error) {
if (retryCount < maxRetries) {
retryCount++;
// 指数级退避重试
const retryDelay = Math.pow(2, retryCount) * 500;
await new Promise(resolve => setTimeout(resolve, retryDelay));
return tryLoadFiles();
}
alert(`加载文件列表失败: ${error.message}`);
return false;
} finally {
// 无论成功失败,移除刷新中状态
if (refreshButton) {
refreshButton.classList.remove('refreshing');
}
}
};
const success = await tryLoadFiles();
// 检查是否是用户通过刷新按钮手动触发的刷新
const isManualRefresh = document.activeElement === refreshButton;
if (success && isManualRefresh) {
// 只有在用户明确点击刷新按钮时才清空当前文件
component.currentFile = null;
component.xmlContent = '';
component.updateFileContent();
component.isEdited = resetEditState(component.shadowRoot);
// 更新文件选择器,确保没有文件被选中
const fileSelector = component.shadowRoot.getElementById('scenarioFile');
if (fileSelector) {
fileSelector.value = '';
}
}
return success;
}
/**
* 更新文件选择器
* @param {HTMLElement} component - 组件实例
*/
export function updateFileSelector(component) {
const fileSelector = component.shadowRoot.getElementById('scenarioFile');
if (fileSelector) {
// 清除现有选项,保留第一个
while (fileSelector.options.length > 1) {
fileSelector.remove(1);
}
// 添加文件选项
component.scenarioFiles.forEach(file => {
const option = document.createElement('option');
option.value = file.path;
option.textContent = file.name;
fileSelector.appendChild(option);
});
// 验证文件选择器选项
const options = Array.from(fileSelector.options);
options.forEach((opt, index) => {
if (index === 0) return; // 跳过第一个空选项
});
} else {
console.log('未找到文件选择器元素');
}
}
/**
* 加载文件内容
* @param {HTMLElement} component - 组件实例
* @param {string} filePath - 文件路径
* @returns {Promise<void>}
*/
export async function loadFileContent(component, filePath) {
try {
const response = await fetch(`/api/file-content?path=${encodeURIComponent(filePath)}`);
if (!response.ok) {
throw new Error(`加载文件内容失败: ${response.status} ${response.statusText}`);
}
component.xmlContent = await response.text();
component.currentFile = filePath;
// 检查内容是否为空
if (!component.xmlContent.trim()) {
// 如果是.sce文件且内容为空则报文件内容为空的错误
if (filePath.toLowerCase().endsWith('.sce')) {
throw new Error('文件内容为空');
}
}
component.updateFileContent();
// 重置编辑状态,因为刚刚加载了新文件
component.isEdited = resetEditState(component.shadowRoot);
} catch (error) {
console.error('加载文件内容失败:', error);
component.xmlContent = '<!-- 加载文件内容失败 -->';
component.updateFileContent();
}
}
/**
* 保存文件内容
* @param {HTMLElement} component - 组件实例
* @param {string} filePath - 文件路径
* @param {string} content - 文件内容
* @returns {Promise<boolean>} 是否成功保存
*/
export async function saveFileContent(component, filePath, content) {
try {
// 更新XML内容
if (component.autoSaveToXml) {
component.updateXmlFromVisualEditor();
}
// 格式化XML内容
const formattedContent = formatXml(component.xmlContent);
// 确保使用绝对路径
let absolutePath = filePath;
if (!filePath.startsWith('/')) {
const scenarioDir = await getScenarioDir();
// 如果filePath是相对路径但带有./,则移除它
const cleanPath = filePath.startsWith('./') ? filePath.substring(2) : filePath;
absolutePath = `${scenarioDir}/${cleanPath}`;
}
const response = await fetch('/api/save-file', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
path: absolutePath,
content: formattedContent
})
});
if (!response.ok) {
throw new Error(`保存文件失败: ${response.status} ${response.statusText}`);
}
// 重置编辑状态
component.isEdited = resetEditState(component.shadowRoot);
// 更新当前文件
component.currentFile = absolutePath;
// 刷新文件列表
await loadScenarioFiles(component);
// 选中当前文件
const fileSelector = component.shadowRoot.getElementById('scenarioFile');
if (fileSelector && component.currentFile) {
fileSelector.value = component.currentFile;
}
alert('文件保存成功');
return true;
} catch (error) {
console.error('保存文件失败:', error);
alert(`保存文件失败: ${error.message}`);
return false;
}
}
/**
* 创建新配置
* @param {HTMLElement} component - 组件实例
* @param {string} fileName - 文件名
* @returns {Promise<boolean>} 是否成功创建
*/
export async function createNewConfig(component, fileName) {
try {
// 使用服务器API创建新文件
const response = await fetch('/api/create-config-file', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
fileName: fileName
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(`创建文件失败: ${errorData.error || response.statusText}`);
}
const data = await response.json();
// 更新文件列表
await loadScenarioFiles(component);
// 加载新创建的文件内容
await loadFileContent(component, data.path);
// 选中新创建的文件
const fileSelector = component.shadowRoot.getElementById('scenarioFile');
if (fileSelector) {
fileSelector.value = data.path;
}
return true;
} catch (error) {
console.error('创建新配置文件失败:', error);
alert(`创建新配置文件失败: ${error.message}`);
return false;
}
}