You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

6.3 KiB

时间轴分镜时长编辑器 - 实施记录

任务: 在分镜轨道的分镜块中添加可点击的时长编辑器
日期: 2026-01-28
状态: 已完成

📋 任务上下文

需求描述

用户需要在时间轴分镜块的更多菜单按钮前添加一个时长显示(如 5s),点击后弹出 Popover 来输入具体的时长数值,以便快速更改分镜时长。

设计方案

选择方案1:紧凑型内联编辑器

  • 紧凑、不占空间
  • 操作流畅,符合用户心智模型
  • 视觉统一,融入现有设计系统
  • 实现简单,代码量少

已完成步骤

1. 创建 DurationEditor 组件

文件: client/src/components/features/timeline/DurationEditor.tsx

功能特性:

  • 可点击的时长标签(等宽字体,Hover 高亮)
  • Popover 弹出输入框
  • 自动聚焦并全选内容
  • Enter 确认 / Esc 取消
  • 失焦自动应用
  • 最小时长验证(0.5s)
  • 错误提示显示
  • 防止事件冒泡

样式:

  • 使用 globals.css 主题变量
  • 等宽字体 (font-mono)
  • 紧凑型 Popover (w-32)
  • 上方弹出 (side="top")
  • 右对齐 (align="end")

2. 集成到 TimelineItem 组件

文件: client/src/components/features/timeline/TimelineItem.tsx

修改内容:

  • 导入 DurationEditor 组件
  • 在分镜块右侧替换原有时长文字
  • 仅在分镜轨道显示编辑器
  • 条件渲染:trackType === 'storyboard' && onResizeRight 存在
  • 时长变化回调:调用 onResizeRight + onDragEnd
  • 保持非分镜轨道原有显示

3. 代码质量检查

  • Linter 检查通过(无错误)
  • TypeScript 类型检查通过
  • 组件 Props 接口完整
  • 事件处理正确(阻止冒泡)

4. 文档记录

  • Changelog: docs/client/changelogs/2026-01-28-timeline-duration-editor.md
  • 实施计划: docs/计划/timeline-duration-editor-implementation.md

🎯 实施细节

核心实现逻辑

DurationEditor 组件:

// 时长标签 → Popover Trigger
<button onClick={() => setOpen(true)}>
  {duration.toFixed(1)}s
</button>

// Popover 内容
<PopoverContent>
  <Input
    type="number"
    value={inputValue}
    onChange={handleInputChange}
    onKeyDown={(e) => {
      if (e.key === 'Enter') applyDuration();
      if (e.key === 'Escape') cancelEdit();
    }}
    onBlur={applyDuration}
  />
</PopoverContent>

TimelineItem 集成:

// 分镜轨道:使用 DurationEditor
{trackType === 'storyboard' && (
  <DurationEditor
    duration={endTime - startTime}
    onDurationChange={(newDuration) => {
      const newEndTime = startTime + newDuration;
      onResizeRight(id, newEndTime);
      onDragEnd?.(id); // 持久化
    }}
  />
)}

// 其他轨道:保持原有显示
{trackType !== 'storyboard' && (
  <span>{formatDuration(endTime - startTime)}</span>
)}

状态管理流程

用户点击时长标签
  ↓
Popover 打开,输入框自动聚焦并全选
  ↓
用户输入新时长(实时验证)
  ↓
按 Enter / 失焦
  ↓
验证通过 → onDurationChange 回调
  ↓
计算新 endTime = startTime + newDuration
  ↓
调用 onResizeRight(id, newEndTime)
  ↓
调用 onDragEnd(id) 持久化到后端
  ↓
Popover 关闭

🔍 验证清单

功能验证

  • 在开发环境启动项目
  • 打开时间轴,找到分镜轨道
  • 点击分镜块右侧的时长标签(如 5.0s
  • 验证 Popover 正常弹出
  • 验证输入框自动聚焦并全选
  • 输入新时长值(如 8
  • 按 Enter 确认
  • 验证分镜块宽度同步更新
  • 验证时长标签显示新值(8.0s

边界情况验证

  • 输入小于 0.5 的值,验证错误提示
  • 输入非数字(如 abc),验证错误提示
  • 按 Esc 取消,验证时长不变
  • 点击 Popover 外部,验证自动应用并关闭
  • 分镜块宽度很小时(< 10%),验证时长标签隐藏

交互验证

  • Hover 时长标签,验证高亮效果
  • 点击时长标签时不触发分镜块拖拽
  • 拖拽分镜时 Popover 自动关闭(如果打开)
  • 与更多菜单按钮布局正常(间距合理)

兼容性验证

  • 非分镜轨道(video/sound/subtitle 等)仍显示原有时长文字
  • 锁定轨道时时长编辑器禁用
  • 不影响其他分镜块功能(选中、拖拽、调整)

📊 实施结果

新增文件

  1. client/src/components/features/timeline/DurationEditor.tsx (156 行)
  2. docs/client/changelogs/2026-01-28-timeline-duration-editor.md (168 行)
  3. docs/计划/timeline-duration-editor-implementation.md (本文件)

修改文件

  1. client/src/components/features/timeline/TimelineItem.tsx
    • 导入 DurationEditor (+1 行)
    • 替换时长显示逻辑 (+13 行, -3 行)

代码统计

  • 新增代码: ~170 行
  • 修改代码: ~10 行
  • 组件数: +1 (DurationEditor)

🎉 成果总结

实现的功能

分镜块显示可点击的时长标签
点击弹出 Popover 进行时长编辑
支持键盘快捷操作(Enter/Esc)
实时验证和错误提示
符合项目设计系统(使用主题变量)
完整的文档记录

用户价值

  • 效率提升: 直接输入时长,比拖拽调整更快速精确
  • 减少操作: 无需切换到属性面板
  • 即时反馈: 在时间轴上直接看到效果
  • 专业友好: 支持键盘快捷键

技术亮点

  • 组件化: 独立的 DurationEditor 组件,易于复用
  • 类型安全: 完整的 TypeScript 类型定义
  • 事件隔离: 正确处理事件冒泡,不影响拖拽
  • 主题统一: 使用项目 globals.css 变量
  • 性能优化: 延迟失焦处理,避免冲突

🚀 后续优化建议

  1. 增强功能(可选)

    • 添加 ±0.5s / ±1s 快捷按钮
    • 批量编辑多个分镜时长
    • 智能时长建议(基于素材)
  2. 交互优化

    • 添加时长预览动画
    • 支持拖拽滑块调整时长
    • 显示时长历史记录
  3. 可访问性

    • 添加 ARIA 标签
    • 支持屏幕阅读器
    • 键盘导航优化

实施者: AI Assistant
完成时间: 2026-01-28
执行模式: 研究 → 构思 → 计划 → 执行 → 评审