新增:文档体系重构+CHANGELOG补充+发布产物清理
This commit is contained in:
36
docs/03-模块文档/文件内容/README.md
Normal file
36
docs/03-模块文档/文件内容/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# 文件内容模块文档
|
||||
|
||||
文件内容显示和状态管理相关文档。
|
||||
|
||||
## 📖 文档列表
|
||||
|
||||
- [file-content-state-fix.md](./file-content-state-fix.md) - 文件内容区状态管理改进
|
||||
- [file-content-fix-bugfixes.md](./file-content-fix-bugfixes.md) - 文件内容相关错误修复
|
||||
|
||||
## 🎯 功能说明
|
||||
|
||||
### 状态管理优化
|
||||
支持跨目录编辑文件的工作流:
|
||||
- 切换目录浏览时,保留对原文件的关联
|
||||
- 方便跨目录复制内容
|
||||
- 提升编辑效率
|
||||
|
||||
### 修复内容
|
||||
- 文件选择状态处理
|
||||
- 文件路径引用管理
|
||||
- UI 状态同步优化
|
||||
- Office 文件预览(Excel/Word)
|
||||
|
||||
## 📅 最近更新
|
||||
|
||||
### 2026-02-16
|
||||
- **Excel/Word 预览修复**:改用 Wails IPC 机制读取二进制文件,解决 "Failed to fetch" 错误
|
||||
|
||||
### 2026-01-28
|
||||
- **状态管理优化**:修复文件名不显示、切换目录闪烁等问题
|
||||
- **二进制文件检测**:智能检测并显示友好提示
|
||||
|
||||
## 💡 相关文档
|
||||
|
||||
- [../文件系统/](../文件系统/) - 文件系统核心模块
|
||||
- [../启动优化/](../启动优化/) - 启动流程优化
|
||||
440
docs/03-模块文档/文件内容/file-content-fix-bugfixes.md
Normal file
440
docs/03-模块文档/文件内容/file-content-fix-bugfixes.md
Normal file
@@ -0,0 +1,440 @@
|
||||
# 文件内容区显示问题修复(Bug Fixes)
|
||||
|
||||
---
|
||||
|
||||
## 修复记录:Excel/Word 预览失败
|
||||
|
||||
### 修复日期
|
||||
2026-02-16
|
||||
|
||||
### 问题描述
|
||||
用户点击 Excel 文件时,预览区域显示错误:
|
||||
```
|
||||
❌ Excel 预览失败
|
||||
Failed to fetch
|
||||
💡 提示:尝试使用外部应用打开文件
|
||||
```
|
||||
|
||||
### 根本原因
|
||||
在 Wails 应用中,前端通过 `fetch` 请求本地 HTTP 服务器 (`http://localhost:18765`) 获取 Office 文件内容。这种方式在 Wails 的 webview 环境中可能会失败:
|
||||
1. Wails webview 对外部 HTTP 请求有限制
|
||||
2. 本地文件服务器的启动时机可能存在竞态条件
|
||||
3. 网络请求在桌面应用环境中不够可靠
|
||||
|
||||
### 解决方案
|
||||
改用 Wails IPC 机制直接读取二进制文件,不再依赖本地 HTTP 服务器。
|
||||
|
||||
### 修改的文件
|
||||
|
||||
#### 1. 后端:添加二进制文件读取 API
|
||||
**位置:** `internal/filesystem/service.go`
|
||||
|
||||
添加 `ReadFileAsBase64` 方法:
|
||||
```go
|
||||
// ReadFileAsBase64 读取二进制文件并返回 base64 编码的字符串
|
||||
func (s *FileSystemService) ReadFileAsBase64(path string) (string, error) {
|
||||
// 路径验证
|
||||
if err := s.validatePath(path); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 检查文件扩展名是否在允许列表中
|
||||
ext := strings.ToLower(filepath.Ext(path))
|
||||
if !s.fileTypeManager.IsAllowed(ext) {
|
||||
return "", fmt.Errorf("不允许的文件类型: %s", ext)
|
||||
}
|
||||
|
||||
// 限制文件大小(最大 100MB)
|
||||
const maxFileSize = 100 * 1024 * 1024
|
||||
// ... 读取文件并编码为 base64 ...
|
||||
|
||||
// 返回 data URI 格式
|
||||
return fmt.Sprintf("data:%s;base64,%s", mimeType, encoded), nil
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 后端:暴露 API 接口
|
||||
**位置:** `app.go`
|
||||
|
||||
```go
|
||||
// ReadFileAsBase64 读取二进制文件并返回 base64 编码的字符串
|
||||
func (a *App) ReadFileAsBase64(path string) (string, error) {
|
||||
return a.filesystem.ReadFileAsBase64(path)
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 前端:添加 API 调用
|
||||
**位置:** `frontend/src/api/system.ts`
|
||||
|
||||
```typescript
|
||||
export async function readFileAsBase64(path: string): Promise<string> {
|
||||
if (!window.go?.main?.App?.ReadFileAsBase64) {
|
||||
throw new Error('ReadFileAsBase64 API 不可用')
|
||||
}
|
||||
return await window.go.main.App.ReadFileAsBase64(path)
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. 前端:修改预览函数
|
||||
**位置:** `frontend/src/components/FileSystem/components/FileEditorPanel.vue`
|
||||
|
||||
修改前(通过 HTTP 服务器):
|
||||
```javascript
|
||||
const response = await fetch(`${serverURL}/localfs/${encodedPath}`)
|
||||
const blob = await response.blob()
|
||||
```
|
||||
|
||||
修改后(通过 Wails IPC):
|
||||
```javascript
|
||||
// 直接通过 Wails API 读取文件(base64 编码)
|
||||
const dataUri = await readFileAsBase64(filePath)
|
||||
|
||||
// 将 data URI 转换为 Blob
|
||||
const response = await fetch(dataUri)
|
||||
const blob = await response.blob()
|
||||
```
|
||||
|
||||
### 优点
|
||||
- **更可靠**:直接通过 Wails IPC 通信,不依赖网络请求
|
||||
- **更安全**:在后端进行文件类型验证和大小限制
|
||||
- **更简洁**:移除了复杂的重试逻辑和错误处理
|
||||
|
||||
### 测试验证
|
||||
- [x] Excel 文件预览正常显示
|
||||
- [x] Word 文件预览正常显示
|
||||
- [x] 文件大小限制生效
|
||||
- [x] 不允许的文件类型被正确拒绝
|
||||
|
||||
---
|
||||
|
||||
## 修复记录:文件内容区状态管理
|
||||
|
||||
### 修复日期
|
||||
2026-01-28
|
||||
|
||||
## 问题描述
|
||||
|
||||
用户报告了三个问题:
|
||||
1. **闪烁问题**:打开新的目录或文件后,整个文件管理区域闪烁刷新
|
||||
2. **文件名不显示**:文件内容区上面之前有文件名现在没有了
|
||||
3. **切换目录后文件名消失**:点击切换到别的目录后,文件名消失了
|
||||
4. **二进制文件乱码**:点击没有后缀的文件时,加载了一堆乱码字符(实际是二进制文件)
|
||||
|
||||
## 根本原因
|
||||
|
||||
### 问题1:函数名错误
|
||||
在计算属性 `isFileInCurrentDirectory` 中使用了不存在的 `normalizePath` 函数,应该使用 `normalizeFilePath`。这导致了运行时错误,使得计算失败并返回空值。
|
||||
|
||||
**错误代码:**
|
||||
```javascript
|
||||
return normalizePath(fileDir) === normalizePath(filePath.value)
|
||||
```
|
||||
|
||||
### 问题2:频繁的计算和重新渲染
|
||||
- `isFileInCurrentDirectory` 计算属性频繁调用 `normalizeFilePath`,性能较差
|
||||
- `listDirectory` 函数在目录切换时立即清空 `selectedFileItem`,导致视觉闪烁
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 修复1:使用正确的函数名
|
||||
|
||||
**位置:** `frontend/src/components/FileSystem.vue:1437-1449`
|
||||
|
||||
**修复内容:**
|
||||
```javascript
|
||||
// 判断当前打开的文件是否在当前目录中(优化性能,减少计算)
|
||||
const isFileInCurrentDirectory = computed(() => {
|
||||
if (!selectedFilePath.value || !filePath.value) return false
|
||||
|
||||
// 提取文件的父目录
|
||||
const lastBackslash = selectedFilePath.value.lastIndexOf('\\')
|
||||
const lastSlash = selectedFilePath.value.lastIndexOf('/')
|
||||
const lastSeparator = Math.max(lastBackslash, lastSlash)
|
||||
|
||||
if (lastSeparator === -1) return false
|
||||
|
||||
const fileDir = selectedFilePath.value.substring(0, lastSeparator)
|
||||
|
||||
// 直接比较路径,避免频繁调用 normalizeFilePath
|
||||
// 只在必要时才进行路径标准化
|
||||
const fileDirNormalized = fileDir.replace(/\\/g, '/').replace(/\/$/, '')
|
||||
const currentPathNormalized = filePath.value.replace(/\\/g, '/').replace(/\/$/, '')
|
||||
|
||||
return fileDirNormalized.toLowerCase() === currentPathNormalized.toLowerCase()
|
||||
})
|
||||
```
|
||||
|
||||
**改进点:**
|
||||
- 不再调用 `normalizeFilePath` 函数,改用简单的字符串替换
|
||||
- 性能优化:直接进行字符串比较而不是函数调用
|
||||
- 统一路径格式:将反斜杠转换为正斜杠,并移除尾部斜杠
|
||||
- 忽略大小写:使用 `toLowerCase()` 进行大小写不敏感比较
|
||||
|
||||
### 修复2:添加错误处理
|
||||
|
||||
**位置:** `frontend/src/components/FileSystem.vue:1452-1473`
|
||||
|
||||
**修复内容:**
|
||||
```javascript
|
||||
const currentFileName = computed(() => {
|
||||
if (isBrowsingZip.value && selectedFilePath.value) {
|
||||
const parts = selectedFilePath.value.split('/')
|
||||
return parts[parts.length - 1] || parts[parts.length - 2] || ''
|
||||
}
|
||||
if (selectedFilePath.value) {
|
||||
try {
|
||||
if (isFileInCurrentDirectory.value) {
|
||||
return getFileName(selectedFilePath.value)
|
||||
} else {
|
||||
return selectedFilePath.value
|
||||
}
|
||||
} catch (error) {
|
||||
debugWarn('[currentFileName] 计算失败,返回文件名:', error)
|
||||
return getFileName(selectedFilePath.value)
|
||||
}
|
||||
}
|
||||
return ''
|
||||
})
|
||||
```
|
||||
|
||||
**改进点:**
|
||||
- 添加 try-catch 错误处理
|
||||
- 即使计算失败也能返回基本的文件名
|
||||
- 防止因计算错误导致文件名完全不显示
|
||||
|
||||
### 修复3:减少视觉闪烁
|
||||
|
||||
**位置:** `frontend/src/components/FileSystem.vue:847-883`
|
||||
|
||||
**修复内容:**
|
||||
```javascript
|
||||
const listDirectory = async () => {
|
||||
if (!filePath.value) return
|
||||
|
||||
if (isBrowsingZip.value && filePath.value !== originalPathBeforeZip.value) {
|
||||
debugLog('检测到路径切换,退出 ZIP 模式')
|
||||
exitZipMode()
|
||||
}
|
||||
|
||||
addToHistory(filePath.value)
|
||||
pushToNavigationHistory(filePath.value)
|
||||
fileLoading.value = true
|
||||
try {
|
||||
fileList.value = await listDir(filePath.value)
|
||||
|
||||
// 目录加载完成后,检查原选中的文件是否还在新目录中
|
||||
// 如果不在,清空 selectedFileItem,避免视觉闪烁
|
||||
if (selectedFileItem.value) {
|
||||
const stillExists = fileList.value.some(f => f.path === selectedFileItem.value.path)
|
||||
if (!stillExists) {
|
||||
selectedFileItem.value = null
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedFilePath.value) {
|
||||
debugLog('[listDirectory] 目录已切换,保留原文件引用:', selectedFilePath.value)
|
||||
}
|
||||
} catch (error) {
|
||||
Message.error('列出目录失败: ' + error.message)
|
||||
selectedFileItem.value = null
|
||||
} finally {
|
||||
fileLoading.value = false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**改进点:**
|
||||
- 延迟清空 `selectedFileItem`,等到新目录加载完成后再检查
|
||||
- 如果原文件仍在新目录中,保持选中状态
|
||||
- 如果原文件不在新目录中,再清空选中状态
|
||||
- 减少了不必要的视觉闪烁
|
||||
|
||||
### 修复4:优化样式
|
||||
|
||||
**位置:** `frontend/src/components/FileSystem.vue:3389-3406`
|
||||
|
||||
**修复内容:**
|
||||
```css
|
||||
.panel-filename {
|
||||
font-weight: normal;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 500px; /* 从 300px 增加到 500px */
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.panel-filename.file-outside-dir {
|
||||
color: rgb(var(--warning-6));
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.file-location-hint {
|
||||
font-size: 11px;
|
||||
color: var(--color-text-3);
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
display: inline;
|
||||
}
|
||||
```
|
||||
|
||||
**改进点:**
|
||||
- 增加最大宽度到 500px,可以显示更长的路径
|
||||
- 添加 `display: inline-block` 确保布局正确
|
||||
- 提示文字使用 `display: inline` 避免换行
|
||||
|
||||
### 修复5:切换目录时保留文件名
|
||||
|
||||
**位置:** `frontend/src/components/FileSystem.vue:958-967`
|
||||
|
||||
**问题描述:**
|
||||
当用户点击切换到其他目录时,文件名消失了。这是因为在 `selectFile` 函数中,当点击目录时会清空 `selectedFilePath`。
|
||||
|
||||
**修复内容:**
|
||||
```javascript
|
||||
if (item.is_dir) {
|
||||
// 目录:更新路径并列出内容
|
||||
// 注意:不要清空 selectedFilePath,保留原文件内容以便跨目录编辑
|
||||
filePath.value = path
|
||||
addToHistory(path)
|
||||
listDirectory()
|
||||
}
|
||||
```
|
||||
|
||||
**同时修复收藏目录跳转:**
|
||||
**位置:** `frontend/src/components/FileSystem.vue:2866-2875`
|
||||
|
||||
```javascript
|
||||
if (fav && fav.is_dir) {
|
||||
// 目录:列出内容
|
||||
// 注意:不要清空 selectedFilePath,保留原文件内容以便跨目录编辑
|
||||
filePath.value = path
|
||||
addToHistory(path)
|
||||
listDirectory()
|
||||
}
|
||||
```
|
||||
|
||||
**改进点:**
|
||||
- 移除了 `selectedFilePath.value = ''` 语句
|
||||
- 保留了跨目录编辑的文件内容
|
||||
- 用户可以在浏览其他目录时继续编辑原文件
|
||||
|
||||
### 修复6:二进制文件检测
|
||||
|
||||
**位置:** `frontend/src/components/FileSystem.vue:2008-2045`
|
||||
|
||||
**问题描述:**
|
||||
点击没有后缀的文件时,加载了一堆乱码字符。这些文件实际上是二进制文件,但代码没有检测,直接当作文本显示。
|
||||
|
||||
**修复内容:**
|
||||
添加二进制内容检测逻辑:
|
||||
```javascript
|
||||
// 检查前 1000 个字符中二进制字符的比例
|
||||
const checkLength = Math.min(content.length, 1000)
|
||||
let binaryCharCount = 0
|
||||
for (let i = 0; i < checkLength; i++) {
|
||||
const charCode = content.charCodeAt(i)
|
||||
// 检查是否为空字节或其他控制字符(除了常见的换行符、制表符等)
|
||||
if (charCode === 0 || (charCode < 32 && charCode !== 9 && charCode !== 10 && charCode !== 13)) {
|
||||
binaryCharCount++
|
||||
}
|
||||
}
|
||||
|
||||
// 如果二进制字符超过 5%,认为是二进制文件
|
||||
const binaryRatio = binaryCharCount / checkLength
|
||||
if (binaryRatio > 0.05) {
|
||||
// 显示友好的二进制文件提示信息
|
||||
isBinaryFile.value = true
|
||||
isEditMode.value = false
|
||||
// ... 显示提示信息 ...
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
**改进点:**
|
||||
- 自动检测二进制内容(不依赖文件扩展名)
|
||||
- 检查前 1000 个字符中的二进制字符比例
|
||||
- 阈值设置为 5%,平衡误报和漏报
|
||||
- 显示友好的提示信息,而不是乱码
|
||||
- 支持有后缀和无后缀的二进制文件检测
|
||||
|
||||
**检测算法:**
|
||||
- 空字节(charCode === 0)肯定是二进制
|
||||
- 控制字符(charCode < 32)除了 Tab(9)、LF(10)、CR(13) 外都是二进制
|
||||
- 如果二进制字符比例超过 5%,判定为二进制文件
|
||||
|
||||
## 技术要点
|
||||
|
||||
1. **函数命名一致性**:确保所有函数调用都使用正确的名称
|
||||
2. **性能优化**:避免在计算属性中进行昂贵的操作
|
||||
3. **延迟更新**:等到数据加载完成后再更新UI状态
|
||||
4. **错误处理**:在关键路径添加 try-catch,防止连锁失败
|
||||
5. **样式优化**:合理的布局和宽度设置,确保内容正确显示
|
||||
6. **状态保留**:跨目录操作时保留编辑状态,提升用户体验
|
||||
7. **内容检测**:智能检测二进制文件,避免显示乱码
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `frontend/src/components/FileSystem.vue` - 主要修改文件
|
||||
- `frontend/src/utils/fileUtils.js` - 工具函数(normalizeFilePath 等)
|
||||
- `docs/file-content-state-fix.md` - 之前的改进文档
|
||||
|
||||
### 1. 文件名显示测试
|
||||
- [x] 打开文件后,文件名正确显示在内容区标题
|
||||
- [x] 切换目录后,文件名仍然显示(如果之前打开了文件)
|
||||
- [x] 文件在当前目录时,只显示文件名
|
||||
- [x] 文件不在当前目录时,显示完整路径和提示
|
||||
|
||||
### 2. 性能测试
|
||||
- [x] 切换目录时无明显闪烁
|
||||
- [x] 打开文件时响应迅速
|
||||
- [x] 计算属性不会频繁触发重新渲染
|
||||
|
||||
### 3. 错误处理测试
|
||||
- [x] 即使路径计算失败,文件名仍能显示
|
||||
- [x] 控制台不会有运行时错误
|
||||
|
||||
### 4. 跨目录编辑测试
|
||||
- [x] 打开文件A
|
||||
- [x] 切换到目录B
|
||||
- [x] 文件A的内容和文件名仍然保留
|
||||
- [x] 可以继续编辑文件A
|
||||
- [x] 保存时正确保存到文件A的原位置
|
||||
|
||||
### 5. 二进制文件检测测试
|
||||
- [x] 打开无后缀的二进制文件,显示友好提示
|
||||
- [x] 不会显示乱码字符
|
||||
- [x] 检测算法不会误判文本文件
|
||||
- [x] 有后缀的二进制文件也能正确识别
|
||||
|
||||
## 用户体验改进
|
||||
|
||||
### 修复前
|
||||
- ❌ 文件名完全不显示
|
||||
- ❌ 切换目录时整个区域闪烁
|
||||
- ❌ 控制台有函数未定义错误
|
||||
- ❌ 切换目录后文件名消失
|
||||
- ❌ 二进制文件显示乱码
|
||||
|
||||
### 修复后
|
||||
- ✅ 文件名正常显示
|
||||
- ✅ 切换目录时流畅无闪烁
|
||||
- ✅ 性能优化,响应更快
|
||||
- ✅ 错误处理更健壮
|
||||
- ✅ 切换目录后保留文件名和内容
|
||||
- ✅ 二进制文件显示友好提示
|
||||
|
||||
## 技术要点
|
||||
|
||||
1. **函数命名一致性**:确保所有函数调用都使用正确的名称
|
||||
2. **性能优化**:避免在计算属性中进行昂贵的操作
|
||||
3. **延迟更新**:等到数据加载完成后再更新UI状态
|
||||
4. **错误处理**:在关键路径添加 try-catch,防止连锁失败
|
||||
5. **样式优化**:合理的布局和宽度设置,确保内容正确显示
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `frontend/src/components/FileSystem.vue` - 主要修改文件
|
||||
- `frontend/src/utils/fileUtils.js` - 工具函数(normalizeFilePath 等)
|
||||
- `docs/file-content-state-fix.md` - 之前的改进文档
|
||||
186
docs/03-模块文档/文件内容/file-content-state-fix.md
Normal file
186
docs/03-模块文档/文件内容/file-content-state-fix.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# 文件内容区状态管理改进
|
||||
|
||||
## 问题描述
|
||||
|
||||
用户报告:点击文件查看内容后,再点击另一个文件夹,文件内容区仍显示之前文件的内容,看起来与当前目录脱离了关联。
|
||||
|
||||
## 需求分析
|
||||
|
||||
经过进一步沟通,用户实际上希望:
|
||||
- **切换目录浏览时,保留对原文件的关联**
|
||||
- 这样可以方便跨目录编辑文件
|
||||
- 例如:在 A 目录打开文件编辑,然后浏览 B 目录复制内容,再回到编辑器继续编辑原文件
|
||||
|
||||
## 改进方案
|
||||
|
||||
### 修改 1:优化文件列表选择状态
|
||||
|
||||
**位置:** `frontend/src/components/FileSystem.vue:843-847`
|
||||
|
||||
**修改内容:**
|
||||
```javascript
|
||||
// 切换目录时,保留原文件内容状态,方便跨目录编辑
|
||||
// 清空 selectedFileItem,因为原文件可能不在新目录的列表中
|
||||
selectedFileItem.value = null
|
||||
if (selectedFilePath.value) {
|
||||
debugLog('[listDirectory] 目录已切换,保留原文件引用:', selectedFilePath.value)
|
||||
}
|
||||
```
|
||||
|
||||
**效果:**
|
||||
- 保留 `selectedFilePath` 和 `fileContent`,用户可以继续编辑原文件
|
||||
- 清空 `selectedFileItem`,避免在新目录中错误地高亮不存在的文件
|
||||
|
||||
### 修改 2:增强文件路径显示
|
||||
|
||||
**位置:**
|
||||
- `frontend/src/components/FileSystem.vue:1423-1465` - 新增计算属性
|
||||
- `frontend/src/components/FileSystem.vue:192-218` - 更新模板
|
||||
- `frontend/src/components/FileSystem.vue:3369-3385` - 新增样式
|
||||
|
||||
**新增计算属性:**
|
||||
|
||||
1. **`isFileInCurrentDirectory`** - 判断文件是否在当前目录中
|
||||
```javascript
|
||||
const isFileInCurrentDirectory = computed(() => {
|
||||
if (!selectedFilePath.value || !filePath.value) return false
|
||||
const fileDir = selectedFilePath.value.substring(
|
||||
0,
|
||||
Math.max(
|
||||
selectedFilePath.value.lastIndexOf('\\'),
|
||||
selectedFilePath.value.lastIndexOf('/')
|
||||
)
|
||||
)
|
||||
return normalizePath(fileDir) === normalizePath(filePath.value)
|
||||
})
|
||||
```
|
||||
|
||||
2. **`currentFileFullPath`** - 获取文件完整路径(用于tooltip)
|
||||
```javascript
|
||||
const currentFileFullPath = computed(() => {
|
||||
return selectedFilePath.value || ''
|
||||
})
|
||||
```
|
||||
|
||||
3. **更新 `currentFileName`** - 根据文件位置智能显示
|
||||
```javascript
|
||||
const currentFileName = computed(() => {
|
||||
// ... ZIP模式处理 ...
|
||||
if (selectedFilePath.value) {
|
||||
// 如果文件在当前目录,只显示文件名;否则显示完整路径
|
||||
if (isFileInCurrentDirectory.value) {
|
||||
return getFileName(selectedFilePath.value)
|
||||
} else {
|
||||
return selectedFilePath.value // 显示完整路径
|
||||
}
|
||||
}
|
||||
return ''
|
||||
})
|
||||
```
|
||||
|
||||
**模板更新:**
|
||||
```vue
|
||||
<span
|
||||
class="panel-filename"
|
||||
:class="{ 'file-outside-dir': !isFileInCurrentDirectory && selectedFilePath }"
|
||||
>
|
||||
{{ currentFileName }}
|
||||
<template v-if="!isFileInCurrentDirectory && selectedFilePath">
|
||||
<span class="file-location-hint"> (不在当前目录)</span>
|
||||
</template>
|
||||
</span>
|
||||
```
|
||||
|
||||
**样式更新:**
|
||||
```css
|
||||
.panel-filename.file-outside-dir {
|
||||
color: rgb(var(--warning-6));
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.file-location-hint {
|
||||
font-size: 11px;
|
||||
color: var(--color-text-3);
|
||||
font-weight: normal;
|
||||
}
|
||||
```
|
||||
|
||||
## 用户体验改进
|
||||
|
||||
### 改进前的问题
|
||||
- 切换目录后,文件内容区显示旧文件
|
||||
- 只显示文件名(如 "file.txt")
|
||||
- 用户不清楚这个文件在哪里
|
||||
- 可能造成混淆
|
||||
|
||||
### 改进后的效果
|
||||
- 切换目录时保留文件内容,方便跨目录编辑 ✅
|
||||
- 文件在当前目录时:只显示文件名(简洁)
|
||||
- 文件不在当前目录时:
|
||||
- 显示完整路径(如 "C:\path\to\file.txt")
|
||||
- 添加 "(不在当前目录)" 提示
|
||||
- 文件名以橙色高亮显示
|
||||
- 鼠标悬停显示完整路径 tooltip
|
||||
|
||||
### 使用场景示例
|
||||
|
||||
1. **场景1:跨目录复制**
|
||||
- 用户在 `C:\Project` 打开 `config.ini` 编辑
|
||||
- 浏览到 `D:\Templates` 复制配置
|
||||
- 回到编辑器,`config.ini` 内容仍然保留,可以继续编辑
|
||||
- 标题显示:"C:\Project\config.ini (不在当前目录)",清晰明了
|
||||
|
||||
2. **场景2:浏览参考文件**
|
||||
- 用户在 `C:\Work` 编辑 `main.js`
|
||||
- 浏览到 `C:\Docs` 查看 API 文档
|
||||
- 回到编辑器,`main.js` 内容保留
|
||||
- 用户可以参考文档内容继续编辑
|
||||
|
||||
## 技术细节
|
||||
|
||||
### 状态管理
|
||||
- `selectedFilePath`: 选中的文件完整路径(保留,不因切换目录而清空)
|
||||
- `selectedFileItem`: 文件列表中的选中项(切换目录时清空)
|
||||
- `fileContent`: 文件内容(保留,支持跨目录编辑)
|
||||
|
||||
### 路径标准化
|
||||
使用 `normalizePath()` 函数确保路径比较的一致性,处理不同操作系统的路径分隔符差异。
|
||||
|
||||
### 视觉提示
|
||||
- **橙色文字**:警告色,提醒用户注意
|
||||
- **完整路径**:让用户知道文件的准确位置
|
||||
- **文字提示**:"(不在当前目录)" 明确告知状态
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. **基本功能测试**
|
||||
- 打开文件A查看内容
|
||||
- 切换到其他文件夹
|
||||
- 验证文件内容仍然保留
|
||||
- 验证标题显示完整路径和提示
|
||||
|
||||
2. **跨目录编辑测试**
|
||||
- 在目录A打开文件
|
||||
- 切换到目录B
|
||||
- 修改文件内容
|
||||
- 点击保存
|
||||
- 验证文件保存到原位置(目录A)
|
||||
|
||||
3. **UI显示测试**
|
||||
- 文件在当前目录:只显示文件名
|
||||
- 文件不在当前目录:显示完整路径 + 橙色 + 提示文字
|
||||
- 鼠标悬停:显示完整路径 tooltip
|
||||
|
||||
4. **边界情况**
|
||||
- ZIP 模式下的行为
|
||||
- 导航历史(后退/前进)
|
||||
- 路径包含特殊字符
|
||||
|
||||
## 相关代码
|
||||
|
||||
- `FileSystem.vue:833-859` - `listDirectory()` 函数
|
||||
- `FileSystem.vue:944-957` - `selectFile()` 函数
|
||||
- `FileSystem.vue:961-1025` - `readFile()` 函数
|
||||
- `FileSystem.vue:1423-1465` - 计算属性(`isFileInCurrentDirectory`, `currentFileName`, `currentFileFullPath`)
|
||||
- `FileSystem.vue:192-218` - 模板更新
|
||||
- `FileSystem.vue:3369-3385` - 样式更新
|
||||
Reference in New Issue
Block a user