TraceStudio-dev/docs/web1.1_filemanager/FEATURE_FILE_OVERWRITE_DIALOG.md
2026-01-07 21:31:22 +08:00

7.7 KiB
Raw Blame History

文件覆盖保护功能

🎯 功能概述

为保存工作流功能添加了文件覆盖保护机制。当保存的工作流文件已存在时,系统会弹出友好的对话框,让用户选择如何处理。

更新版本: v0.2.2.1
更新日期: 2026-01-07
涉及文件: web/src/stores/useStore.ts


功能特性

保存工作流时的智能检测

当用户点击保存工作流按钮时:

  1. 检查文件是否存在 - 调用 GET /api/files/info 检查目标路径
  2. 文件不存在 - 直接保存
  3. 文件已存在 - 弹出选择对话框

对话框选项

⚠️ 文件已存在
工作流 数据分析.utrace 已存在。
请选择操作:

┌─────────────────────────┐
│ 🔄 覆盖现有文件         │  → 直接覆盖,不改变文件名
├─────────────────────────┤
│ ✏️ 重命名后保存         │  → 提示输入新名称
├─────────────────────────┤
│ ❌ 取消                 │  → 取消保存操作
└─────────────────────────┘

🎨 UI 设计

对话框样式

  • 背景遮罩: 半透明黑色 rgba(0, 0, 0, 0.7)
  • 模态框: 深色主题 #1e293b,圆角 12px
  • 按钮: 不同颜色区分操作
    • 覆盖: 红色 #ef4444
    • 重命名: 绿色 #22c55e
    • 取消: 灰色 #94a3b8
  • 交互: 悬停时按钮上移,带阴影

键盘支持

  • ESC 键: 取消操作,关闭对话框

📖 使用流程

场景 1: 覆盖现有文件

步骤 1: 编辑工作流,标题为"数据分析"
步骤 2: 点击 💾 保存按钮
步骤 3: 检测到 数据分析.utrace 已存在
步骤 4: 弹出对话框,用户选择"🔄 覆盖现有文件"
步骤 5: 文件被覆盖,显示 "✅ 工作流已保存到: users/guest/workflows/数据分析.utrace"

场景 2: 重命名后保存

步骤 1: 编辑工作流,标题为"数据分析"
步骤 2: 点击 💾 保存按钮
步骤 3: 检测到 数据分析.utrace 已存在
步骤 4: 弹出对话框,用户选择"✏️ 重命名后保存"
步骤 5: 弹出输入框: "请输入新的工作流名称: 数据分析"
步骤 6: 用户输入 "数据分析_v2"
步骤 7: 工作流标题自动更新为 "数据分析_v2"
步骤 8: 保存为 数据分析_v2.utrace

场景 3: 取消保存

步骤 1: 点击 💾 保存按钮
步骤 2: 检测到文件已存在
步骤 3: 弹出对话框,用户选择"❌ 取消"或按 ESC 键
步骤 4: 对话框关闭,不执行任何保存操作

🔧 技术实现

文件存在检查

// 1. 构建文件完整路径
const filename = `${workflowTitle.replace(/[^a-zA-Z0-9\u4e00-\u9fa5_-]/g, '_')}.utrace`
const fullPath = `users/${currentUser}/workflows/${filename}`

// 2. 调用 API 检查文件是否存在
const checkResponse = await fetch(
  `http://127.0.0.1:8000/api/files/info?path=${encodeURIComponent(fullPath)}`
)
const fileExists = checkResponse.ok

动态对话框创建

使用原生 DOM API 创建模态对话框,避免依赖 React 组件:

const choice = await new Promise<'overwrite' | 'rename' | 'cancel'>((resolve) => {
  // 创建遮罩层
  const dialog = document.createElement('div')
  dialog.style.cssText = '...'
  
  // 创建模态框
  const modal = document.createElement('div')
  modal.innerHTML = `
    <button id="btn-overwrite">🔄 覆盖现有文件</button>
    <button id="btn-rename">✏️ 重命名后保存</button>
    <button id="btn-cancel">❌ 取消</button>
  `
  
  // 绑定事件
  modal.querySelector('#btn-overwrite').addEventListener('click', () => {
    document.body.removeChild(dialog)
    resolve('overwrite')
  })
  
  // ESC 键支持
  document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') resolve('cancel')
  })
})

处理用户选择

if (choice === 'cancel') {
  return  // 直接返回,不保存
}

if (choice === 'rename') {
  const newName = prompt('请输入新的工作流名称:', currentTitle)
  if (newName) {
    filename = `${newName.replace(/[^a-zA-Z0-9\u4e00-\u9fa5_-]/g, '_')}.utrace`
    setWorkflowTitle(newName)  // 更新标题
  }
}

// choice === 'overwrite' 时,继续使用原文件名保存

🚀 优势

用户体验

  • 防止意外覆盖重要工作流
  • 友好的视觉提示和清晰的选项
  • 支持快速重命名,无需重新编辑标题
  • 键盘快捷键支持ESC 取消)

技术优势

  • 使用 GET /api/files/info 检查,轻量高效
  • Promise 封装,代码逻辑清晰
  • 纯 JavaScript 实现,无额外依赖
  • 自动清理 DOM避免内存泄漏

兼容性

  • 向后兼容,不影响现有功能
  • 在后端 API 不可用时优雅降级(直接保存)

📊 对比其他方案

方案 优点 缺点
直接覆盖 实现简单 可能丢失数据
自动重命名 避免覆盖 文件名混乱(如 file_1, file_2
询问用户 用户可控 需要额外交互

🛠️ 扩展建议

短期优化

  • 显示文件最后修改时间,帮助用户决策
  • 添加"查看现有文件"选项,预览内容
  • 保存历史记录(自动备份)

长期规划

  • 版本管理系统Git 式管理)
  • 文件差异对比Diff 显示)
  • 自动保存功能(定时保存草稿)

🐛 已知限制

1. 依赖后端 API

  • 问题: 需要 GET /api/files/info 接口支持
  • 降级方案: API 不可用时跳过检查,直接保存

2. 文件名冲突

  • 问题: 如果重命名后的文件名仍然存在,会再次弹出对话框
  • 解决: 可以在重命名时检查并提示

3. 并发保存

  • 问题: 多个用户同时保存同名文件可能冲突
  • 解决: 后期可添加文件锁机制

📝 测试用例

测试 1: 新文件保存

前置条件: 工作流标题为 "新工作流",该文件不存在
操作: 点击保存按钮
预期结果: 
  - 不显示对话框
  - 直接保存成功
  - 显示提示 "✅ 工作流已保存到: users/guest/workflows/新工作流.utrace"

测试 2: 覆盖现有文件

前置条件: 工作流标题为 "测试工作流",该文件已存在
操作:
  1. 点击保存按钮
  2. 选择 "🔄 覆盖现有文件"
预期结果:
  - 显示对话框
  - 文件被覆盖
  - 显示保存成功提示

测试 3: 重命名保存

前置条件: 工作流标题为 "测试工作流",该文件已存在
操作:
  1. 点击保存按钮
  2. 选择 "✏️ 重命名后保存"
  3. 输入 "测试工作流_备份"
预期结果:
  - 弹出输入框
  - 工作流标题更新为 "测试工作流_备份"
  - 保存为 测试工作流_备份.utrace

测试 4: 取消保存

前置条件: 工作流标题为 "测试工作流",该文件已存在
操作:
  1. 点击保存按钮
  2. 选择 "❌ 取消" 或按 ESC 键
预期结果:
  - 对话框关闭
  - 不执行保存操作
  - 不显示任何提示

测试 5: API 不可用

前置条件: 后端服务未启动
操作: 点击保存按钮
预期结果:
  - 跳过文件存在检查
  - 直接尝试保存
  - 显示错误提示 "❌ 保存失败,请检查后端服务是否正常运行"

🔄 版本历史

版本 日期 更新内容
v0.2.2.1 2026-01-07 新增文件覆盖保护对话框

📧 反馈

如有问题或建议,请通过以下方式反馈:

  • 提交 Issue: GitHub Issues
  • 功能建议: GitHub Discussions