fix(frontend): 修复文件管理器删除与上传稳定性

补齐文件管理器右键子菜单点击展开,新增拖拽上传目标确认,
并在上传完成后自动刷新当前可见目录

目录删除改为区分仅删空目录与强制递归删除,删除后自动回退
失效路径,避免文件树持续报 No such file

同步后端 sftp:rmdir 的 recursive 分支,并将关于页与版本检查
默认仓库链接切换到 Micah123321/nexus-terminal
This commit is contained in:
yinjianm
2026-03-26 03:48:50 +08:00
parent 1a326cc01f
commit cda7e0a018
32 changed files with 661 additions and 115 deletions
@@ -1 +0,0 @@
{"status":"in_progress","completed":0,"failed":0,"pending":3,"total":3,"done":0,"percent":0,"current":"准备进入开发实施:修复新会话下根目录同级树补全","updated_at":"2026-03-26 03:10:00"}
@@ -1,123 +0,0 @@
# 变更提案: file-manager-root-sibling-bootstrap
## 元信息
```yaml
类型: 修复
方案类型: implementation
优先级: P1
状态: 草稿
创建: 2026-03-26
```
---
## 1. 需求
### 背景
工作台文件区近期已调整为固定 `/` 根节点树,但用户反馈在新开终端连接后,`/` 展开时仍只显示 `root`,没有补齐 `/` 下其它同级目录。结合现场代码,文件区启动时会同时涉及 `/` 根目录预加载和当前工作目录(如 `/root`)加载,这可能导致 `/` 的目录响应被当作过时请求忽略,从而树里只保留当前路径链路。
### 目标
- 保持当前工作目录(如 `/root`)仍是当前操作目录。
- 在新会话初始化后,`/` 展开时补齐 `/` 下其它同级目录,而不只显示 `root`
- 避免为了补树而把当前目录错误切回 `/`
### 约束条件
```yaml
范围约束: 优先限制在 FileManager.vue / useSftpActions.ts,避免牵涉后端接口
交互约束: 当前工作目录保持不变,文件树补全属于后台树状态修正
兼容约束: 已有目录展开、路径输入、右键菜单和上传能力不回退
风险约束: 不应把所有过时 readdir 响应都重新接受,只修正根目录初始化场景
```
### 验收标准
- [ ] 新开终端连接后,`/` 根节点展开能显示 `root` 外的同级目录
- [ ] 当前操作目录仍保持在实际工作目录(如 `/root`),不会因补树自动跳回 `/`
- [ ] 前端构建通过
---
## 2. 方案
### 技术方案
`useSftpActions.ts``readdir` 成功处理里,为 `/` 根目录引入一次性“后台树补全”容忍逻辑:若 `/` 的响应因为当前路径请求更晚而变成 stale,但根树尚未加载,则仍允许把 `/` 的子节点合并进 `fileTree`,同时不改 `currentPath``isLoading` 和当前请求指针。这样既保留 `/root` 作为当前工作目录,又能把 `/` 下的一级同级目录补齐到树中。
### 影响范围
```yaml
涉及模块:
- frontend: `packages/frontend/src/composables/useSftpActions.ts`
预计变更文件: 1-3
```
### 风险评估
| 风险 | 等级 | 应对 |
|------|------|------|
| 误把真正过时的目录响应写回树,造成状态回退 | 中 | 仅对 `path === '/'` 且根树尚未加载的初始化场景放行 |
| 根树补全后 currentPath 被错误覆盖为 `/` | 中 | stale 根响应只合并树,不更新 currentPath / isLoading |
| 修复逻辑不足以覆盖其它层级目录的竞态 | 低 | 本轮只解决用户明确报告的 `/` 同级目录缺失问题 |
---
## 3. 技术设计(可选)
### 架构设计
```mermaid
flowchart LR
A[loadDirectory('/')] --> B[readdir success for '/']
C[loadDirectory('/root')] --> D[readdir success for '/root']
B --> E[background root tree bootstrap]
D --> F[currentPath stays /root]
```
### 数据模型
| 字段 | 类型 | 说明 |
|------|------|------|
| `loadingRequestId` | `string \| null` | 当前前台加载请求 ID |
| `fileTree.childrenLoaded` | `boolean` | `/` 根节点是否已完成首轮树加载 |
| `currentPathRef` | `Ref<string>` | 当前操作目录,不应被 stale 根响应覆盖 |
---
## 4. 核心场景
### 场景: 新会话进入 `/root`,同时补齐 `/` 的一级兄弟目录
**模块**: frontend
**条件**: 新终端连接建立后,文件区需要同时知道当前工作目录和 `/` 根树。
**行为**: `/root` 继续作为当前工作目录加载;若 `/` 的目录响应稍后到达且根树尚未完成初始化,仍允许把 `/` 的一级目录合并进树,但不改变当前目录。
**结果**: 用户在树里能看到 `/` 下多个同级目录,同时右上方当前路径仍维持在 `/root`
---
## 5. 技术决策
### file-manager-root-sibling-bootstrap#D001: 仅对 stale 的 `/` 根目录响应做树补全放行,而不是全面接收所有 stale readdir 响应
**日期**: 2026-03-26
**状态**: ✅采纳
**背景**: 用户问题集中在新会话下 `/` 根树只剩当前路径链路;广义接收所有 stale 响应会带来状态回退风险。
**选项分析**:
| 选项 | 优点 | 缺点 |
|------|------|------|
| A: 只对 `/` 且根树未加载的 stale 响应放行 | 改动最小,直接覆盖当前缺陷,风险可控 | 只修复根目录初始化场景 |
| B: 接收所有 stale readdir 响应并更新树 | 可能覆盖更多竞态 | 容易把旧目录状态写回,风险高 |
**决策**: 选择方案A
**理由**: 这次是已知初始化竞态,不需要把整个目录加载协议重写。先做可验证、可控的定点修复更稳妥。
**影响**: frontend
---
## 6. 成果设计
### 设计方向
- **美学基调**: N/A
- **记忆点**: N/A
- **参考**: 用户提供的新终端文件树截图
### 视觉要素
- **配色**: N/A
- **字体**: N/A
- **布局**: N/A
- **动效**: N/A
- **氛围**: N/A
### 技术约束
- **可访问性**: N/A
- **响应式**: N/A
@@ -1,41 +0,0 @@
# 任务清单: file-manager-root-sibling-bootstrap
```yaml
@feature: file-manager-root-sibling-bootstrap
@created: 2026-03-26
@status: pending
@mode: R2
```
## 进度概览
| 完成 | 失败 | 跳过 | 总数 |
|------|------|------|------|
| 0 | 0 | 0 | 3 |
---
## 任务列表
### 1. 根目录同级补全修复
- [ ] 1.1 在 `packages/frontend/src/composables/useSftpActions.ts` 中定位新会话初始化下 `/` 与当前目录并发加载的竞态点 | depends_on: []
- [ ] 1.2 在 `packages/frontend/src/composables/useSftpActions.ts` 中实现 stale `/` 根目录响应的安全树补全逻辑,避免 currentPath 被改回 `/` | depends_on: [1.1]
### 2. 验证与同步
- [ ] 2.1 执行 `packages/frontend` 的构建验证,并同步知识库记录 | depends_on: [1.2]
---
## 执行日志
| 时间 | 任务 | 状态 | 备注 |
|------|------|------|------|
| 2026-03-26 03:10 | DESIGN | completed | 已确认问题集中在 `/` 根树补全而非当前工作目录切换,修复以最小协议变更为主 |
---
## 执行备注
> 当前环境缺少可直接调用的 `python/py`,方案包通过模板降级方式手工创建。
@@ -0,0 +1 @@
{"status":"completed","completed":5,"failed":0,"pending":0,"total":5,"done":5,"percent":100,"current":"文件管理删除、上传和菜单稳定性修复已完成","updated_at":"2026-03-26 04:14:00"}
@@ -0,0 +1,63 @@
# 变更提案: file-manager-delete-upload-stability
## 元信息
```yaml
类型: 修复增强
方案类型: implementation
优先级: P1
状态: 已完成
状态说明: 已完成子菜单点击展开、拖拽上传目标确认、目录删除模式区分与删除后无效路径自动回退
创建: 2026-03-26
```
---
## 1. 需求
### 背景
文件管理器近期完成了资源管理器树与右键菜单改造,但当前仍存在一组影响可用性的连锁问题:终端/上传/压缩子菜单点击无反应,上传后没有自动刷新且拖拽上传没有目标确认,目录删除缺少“空目录删除 / 强制递归删除”的明确选项,并且删除后树会持续触发 `读取目录失败: No such file`
### 目标
- 修复文件右键菜单的子菜单交互。
- 上传后自动刷新,并在拖拽上传时明确目标目录。
- 目录删除提供“仅删除空目录”和“强制递归删除”二次确认。
- 删除后不再持续触发已不存在路径的目录加载错误。
### 约束条件
```yaml
范围约束: 优先收敛在 FileManager.vue、FileManagerContextMenu.vue、useFileManagerContextMenu.ts 和 useSftpActions.ts
后端约束: 可复用现有 sftp:rmdir 能力,必要时仅做最小协议扩展
交互约束: 保持当前资源管理器树和右键菜单风格,不回退到旧文件表格
兼容约束: 单文件/目录右键、多选和空白处右键仍需可用
```
### 验收标准
- [x] 终端 / 上传 / 压缩子菜单可明确展开并可点击执行
- [x] 上传完成后自动刷新,拖拽上传前能确认目标目录
- [x] 删除目录时弹二次确认并区分空目录删除与强制递归删除
- [x] 删除后不再持续报 `读取目录失败: No such file`
- [x] 前端构建通过
---
## 2. 方案
### 技术方案
`FileManagerContextMenu.vue` 中补桌面端点击展开二级菜单与更稳定的 hover/click 保持逻辑;在 `FileManager.vue` 中为拖拽上传新增目标目录提示与确认,并在上传成功回调后触发目标目录刷新;目录删除改成显式二次确认流程,给目录提供“仅删除空目录”和“强制递归删除”两种执行路径。`useSftpActions.ts` 与删除成功后的树更新逻辑同步修正,若当前路径或挂起加载目标落在已删除目录下,则自动回退到父目录或 `/`,避免持续请求不存在路径。
### 影响范围
```yaml
涉及模块:
- frontend: FileManager.vue
- frontend: FileManagerContextMenu.vue
- frontend: useFileManagerContextMenu.ts
- frontend: useSftpActions.ts
预计变更文件: 4-7
```
### 风险评估
| 风险 | 等级 | 应对 |
|------|------|------|
| 删除协议若需扩展 `recursive` 参数,前后端需同步 | 中 | 先核对现有后端 `sftp:rmdir` 能否透传策略,不足时做最小扩展 |
| 拖拽上传增加确认可能影响原有快捷操作感 | 低 | 仅在目标不明确时或跨目录时确认,默认场景仍快速上传 |
| 删除后自动回退目录可能与用户当前聚焦目录预期不一致 | 低 | 仅在当前路径已失效时回退到父目录,优先保证不报错 |
@@ -0,0 +1,49 @@
# 任务清单: file-manager-delete-upload-stability
```yaml
@feature: file-manager-delete-upload-stability
@created: 2026-03-26
@status: in_progress
@mode: R2
```
## 进度概览
| 完成 | 失败 | 跳过 | 总数 |
|------|------|------|------|
| 5 | 0 | 0 | 5 |
---
## 任务列表
### 1. 方案与范围确认
- [√] 1.1 创建文件管理稳定性修复方案包并锁定到文件管理前端链路 | depends_on: []
### 2. 菜单与上传交互修复
- [√] 2.1 修复右键子菜单展开/点击交互 | depends_on: [1.1]
- [√] 2.2 补拖拽上传目标确认和上传完成自动刷新 | depends_on: [2.1]
### 3. 删除与树状态修复
- [√] 3.1 为目录删除增加“空目录删除 / 强制递归删除”二次确认 | depends_on: [2.2]
- [√] 3.2 修复删除后树持续请求不存在路径的问题 | depends_on: [3.1]
### 4. 验证与同步
- [√] 4.1 运行前端构建验证并同步 `.helloagents` 文档与归档记录 | depends_on: [3.2]
---
## 执行日志
| 时间 | 任务 | 状态 | 备注 |
|------|------|------|------|
| 2026-03-26 03:24 | 1.1 | 完成 | 创建 implementation 方案包,范围锁定为文件管理删除、上传和菜单稳定性修复 |
| 2026-03-26 04:03 | 2.1 | 完成 | `FileManagerContextMenu.vue` 桌面端子菜单补点击展开,避免“终端 / 上传 / 压缩”点击无反应 |
| 2026-03-26 04:05 | 2.2 | 完成 | 拖拽上传前新增目标目录确认,并在当前可见目录上传完成后主动刷新 |
| 2026-03-26 04:08 | 3.1 | 完成 | 目录删除改为“仅删空目录 / 强制递归删除”双确认,后端 `sftp:rmdir` 接收 `recursive` 标志 |
| 2026-03-26 04:10 | 3.2 | 完成 | 删除目录后若当前/待加载路径失效,前端自动回退父目录,终止持续 `No such file` 重试 |
| 2026-03-26 04:14 | 4.1 | 完成 | `npm run build --workspace @nexus-terminal/frontend``@nexus-terminal/backend` 均通过 |