diff --git a/web/src/components/FileSystem/components/FileEditorPanel.vue b/web/src/components/FileSystem/components/FileEditorPanel.vue index 7d2eda2..19f887f 100644 --- a/web/src/components/FileSystem/components/FileEditorPanel.vue +++ b/web/src/components/FileSystem/components/FileEditorPanel.vue @@ -283,6 +283,7 @@ import { getFileName } from '@/utils/fileUtils' import type { FileEditorPanelConfig } from '@/types/file-system' import { renderMermaidDiagrams } from '@/utils/markedExtensions' import { previewExcel, previewWord } from '@/utils/filePreviewHandlers' +import { getFileServerURL } from '@/api/system' // 异步加载 CodeEditor 组件,减少初始包大小 const AsyncCodeEditor = defineAsyncComponent({ @@ -453,14 +454,31 @@ watch(() => [props.config.isWordFile, props.config.currentFileFullPath], async ( const loadExcelPreview = async (filePath: string) => { if (!excelPreviewRef.value) return - // 清空容器 - excelPreviewRef.value.innerHTML = '' - try { - const response = await fetch(`file://${filePath}`) - if (!response.ok) throw new Error('无法读取文件') + // 清空容器 + excelPreviewRef.value.innerHTML = '' + + // 使用本地文件服务器获取文件内容 + const serverURL = await getFileServerURL() + console.log('[loadExcelPreview] 文件路径:', filePath) + console.log('[loadExcelPreview] 服务器 URL:', serverURL) + + // Windows 路径处理:将反斜杠替换为正斜杠 + const normalizedPath = filePath.replace(/\\/g, '/') + console.log('[loadExcelPreview] 规范化路径:', normalizedPath) + + const encodedPath = encodeURIComponent(normalizedPath) + const fullURL = `${serverURL}/localfs/${encodedPath}` + console.log('[loadExcelPreview] 完整 URL:', fullURL) + + const response = await fetch(fullURL) + console.log('[loadExcelPreview] 响应状态:', response.status) + + if (!response.ok) throw new Error(`无法读取文件 (HTTP ${response.status})`) const blob = await response.blob() + console.log('[loadExcelPreview] Blob 大小:', blob.size) + const file = new File([blob], getFileName(filePath), { type: 'application/vnd.ms-excel' }) const result = await previewExcel(file, excelPreviewRef.value) @@ -483,14 +501,31 @@ const loadExcelPreview = async (filePath: string) => { const loadWordPreview = async (filePath: string) => { if (!wordPreviewRef.value) return - // 清空容器 - wordPreviewRef.value.innerHTML = '' - try { - const response = await fetch(`file://${filePath}`) - if (!response.ok) throw new Error('无法读取文件') + // 清空容器 + wordPreviewRef.value.innerHTML = '' + + // 使用本地文件服务器获取文件内容 + const serverURL = await getFileServerURL() + console.log('[loadWordPreview] 文件路径:', filePath) + console.log('[loadWordPreview] 服务器 URL:', serverURL) + + // Windows 路径处理:将反斜杠替换为正斜杠 + const normalizedPath = filePath.replace(/\\/g, '/') + console.log('[loadWordPreview] 规范化路径:', normalizedPath) + + const encodedPath = encodeURIComponent(normalizedPath) + const fullURL = `${serverURL}/localfs/${encodedPath}` + console.log('[loadWordPreview] 完整 URL:', fullURL) + + const response = await fetch(fullURL) + console.log('[loadWordPreview] 响应状态:', response.status) + + if (!response.ok) throw new Error(`无法读取文件 (HTTP ${response.status})`) const blob = await response.blob() + console.log('[loadWordPreview] Blob 大小:', blob.size) + const file = new File([blob], getFileName(filePath), { type: 'application/vnd.ms-word' }) const result = await previewWord(file, wordPreviewRef.value) diff --git a/web/src/components/FileSystem/composables/useFileEdit.ts b/web/src/components/FileSystem/composables/useFileEdit.ts index ae5005a..9765f77 100644 --- a/web/src/components/FileSystem/composables/useFileEdit.ts +++ b/web/src/components/FileSystem/composables/useFileEdit.ts @@ -138,17 +138,16 @@ export function useFileEdit(options: UseFileEditOptions = {}) { FILE_EXTENSIONS.AUDIO.includes(ext) || ['pdf', 'html', 'htm', 'md', 'markdown'].includes(ext) + // Office 文件(可预览) + const isOfficeFile = ['xlsx', 'xls', 'docx', 'doc'].includes(ext) + // 文本或代码文件(可编辑) const isTextFile = FILE_EXTENSIONS.TEXT.includes(ext) || FILE_EXTENSIONS.CODE.includes(ext) || FILE_EXTENSIONS.CONFIG.includes(ext) - // 如果是媒体文件或文本文件,就不是二进制 - if (isMediaFile || isTextFile) return false - - // 确认的二进制文件类型 - const knownBinaryTypes = ['exe', 'dll', 'so', 'bin', 'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'iso', 'img', 'dmg', 'pdb', 'idb', 'lib', 'obj', 'o', 'a'] - if (knownBinaryTypes.includes(ext)) return true + // 如果是媒体文件、Office 文件或文本文件,就不是二进制 + if (isMediaFile || isOfficeFile || isTextFile) return false // 其他扩展名未知,需要内容检测 return null @@ -239,6 +238,15 @@ export function useFileEdit(options: UseFileEditOptions = {}) { const filename = getFilePath(path) const ext = getFileExtension(filename) + // Office 文件直接读取内容进行预览,跳过二进制检测 + if (isExcelFile(filename) || isWordFile(filename)) { + const content = await readFile(path) + fileContent.value = content + originalContent.value = content + isEditMode.value = false + return + } + // 先检查扩展名,如果是已知的二进制文件,直接生成提示信息 const binaryCheck = isBinaryFileByExt(filename) if (binaryCheck === true) { @@ -418,6 +426,12 @@ ${ext ? `文件类型: ${fileTypeDesc}\n` : ''} const saveDraft = () => { if (!currentFilePath.value) return + // Office 文件不支持草稿功能 + const path = getFilePath(currentFilePath.value) + if (isExcelFile(path) || isWordFile(path)) { + return + } + const key = `${STORAGE_KEYS.FILESYSTEM.FILE_DRAFT}-${currentFilePath.value}` const draft = { content: fileContent.value, @@ -436,6 +450,18 @@ ${ext ? `文件类型: ${fileTypeDesc}\n` : ''} * 加载草稿 */ const loadDraft = (path: string) => { + // Office 文件不支持草稿功能,并清除已有的草稿 + if (isExcelFile(path) || isWordFile(path)) { + const key = `${STORAGE_KEYS.FILESYSTEM.FILE_DRAFT}-${path}` + try { + localStorage.removeItem(key) + console.debug('[useFileEdit] 已清除 Office 文件草稿:', path) + } catch (error) { + console.error('清除草稿失败:', error) + } + return + } + const key = `${STORAGE_KEYS.FILESYSTEM.FILE_DRAFT}-${path}` draftKey.value = key