feat: 剪辑计划编辑器前端实现 #106
Reference in New Issue
Block a user
Delete Branch "feat/editing-planner-frontend"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
变更内容
新增功能
/editing-planner)/my-templates)技术实现
文件变更
apps/web/src/api/editingPlanner.ts— API 模块 + mock 数据apps/web/src/pages/editing-planner/— 编辑器页面apps/web/src/pages/my-templates/— 我的模板页面apps/web/src/router/index.tsx— 新增路由apps/web/src/components/layout/Header.tsx— 新增导航项🤖 Generated with Claude Code
🔍 代码审查报告 — PR #106 剪辑计划编辑器前端
Head SHA:
fff47a7a3d1d71dcd78272ecd4060ae17be21586变更范围: 7 文件,+1654 行,全新代码
审查结论:❌ 不通过(2 个 P0 需修复)
✅ 做得好的地方
__msgShown防重复 toast(与 PR #99 全局拦截器配合)🔴 P0 — 必须修复
P0-1: TemplateMode 类型值与后端 API 完全不匹配
前端定义:
后端 API Schema(PR #105)存储和传输的是英文字符串:
pip/voice_over/one_take/voice_pip(后端正在修复person_narration→voice_over,voice_over_mix→voice_pip)。如果 mock 切到真实 API,前端发送
mode: "画中画",后端会返回 422(不在 VALID_MODES 中)。 后端返回mode: "pip",前端类型校验也会失败。修复方案:
在 UI 展示处用
MODE_LABELS[tpl.mode]显示中文,数据存储和 API 传输统一用英文值。P0-2: EditingPlanner 不读取 URL 参数,MyTemplates 的编辑/生成跳转失效
MyTemplates 页面通过 URL 参数跳转:
但 EditingPlanner 组件完全没有
useSearchParams、useEffect或useLocation,不会读取 URL 参数。结果是:修复方案: 在 EditingPlanner 中添加
useEffect,在模板列表加载完成后读取template参数并调用loadTemplate,读取generate=1参数并自动打开生成弹窗。🟡 P1 — 建议修复
P1-1: EditingPlanner.tsx 单文件 848 行,应拆分
编辑器组件过于庞大,包含了模式切换、片段管理、标题/字幕/BGM 设置面板、保存弹窗、生成弹窗等全部逻辑。建议拆分为:
ModeSelector— 模式切换按钮组TimelinePanel— 时间线 + 片段拖拽TitleSettingsPanel— 标题设置SubtitleSettingsPanel— 字幕设置BgmSettingsPanel— BGM 设置SaveTemplateModal— 保存弹窗GenerateModal— 生成弹窗P1-2:
GenerateFromTemplatePayload与后端不对齐前端:
{ voiceover_id: string }— 发送配音 ID后端 PR #105:
{ voiceover_duration: Optional[float] }— 接收配音时长(秒)语义完全不同。后端需要配音时长来校验 ±30% 偏差,前端发送的是配音文件 ID。
修复: 对齐为
{ voiceover_duration: number },在弹窗中让用户输入配音时长,或在用户选择配音后自动传入时长。P1-3: 分类保存用 Input 手动输入,应关联 TemplateCategory
保存模板弹窗中,分类字段用
Input手动输入文字。但后端有template_categories表 + 分类 CRUD API。用户可能输入已存在的分类名变体(如「生活 vlog」vs「生活」),导致分类碎片化。修复: 改用
Select,选项来源为getTemplateCategories(),同时支持创建新分类。P1-4:
SaveTemplatePayload缺少estimated_duration字段后端 Schema 中
CreateTemplateRequest包含estimated_duration。前端SaveTemplatePayload没有这个字段,mock 函数中手动计算了。切换到真实 API 时,需要在前端计算并传入,或者让后端自动计算(但这需要后端修改)。🔵 P2 — 建议改进
P2-1: Slider 未校验
duration_min <= duration_max片段的最短/最长时长各用一个 Slider,没有联动约束。用户可以把最短设为 30s、最长设为 5s,导致后端校验拒绝或剪辑逻辑异常。建议用
RangeSlider或在updateSegment中做约束。P2-2: Mock 数据的
getEditingTemplates不支持分页后端 API 有
skip+limit分页,mock 函数返回全量数据。切换到真实 API 后,前端可能需要添加分页逻辑或确认 limit=200 足够。P2-3: 模块级全局计数器
_segIdlet _segId = 0在模块级别,每次页面刷新重置。在 mock 模式下不会冲突,但如果多组件实例共存(如未来路由 keep-alive),可能产生 ID 碰撞。建议用useRef或crypto.randomUUID()。📋 总结
P0 修复后即可通过审查。 UI 设计和交互逻辑整体质量不错,主要是前后端对齐问题和 URL 参数处理的遗漏。
所有代码审计问题已修复,请复审。
已修复项:
TypeScript 检查通过,零错误。
✅ PR #106 复审通过
Head SHA:
067439a1ddef上轮问题修复确认
"pip" | "voice_over" | "one_take" | "voice_pip",与后端 EditingMode 枚举完全对齐;MODE_LABELS 提供中文显示映射useSearchParams,useEffect 自动加载?template=xxx并在generate=1时打开生成弹窗GenerateFromTemplatePayload.voiceover_duration: number,mutation 正确传参Select关联getTemplateCategories()APIcalcEstimatedDuration(segments)自动计算max={seg.duration_max},最长 Slidermin={seg.duration_min},互锁代码质量评价
同意合并。
v0.1.91 测试问题修复 (
a29e30eb)问题1 [高优先级]: editingPlanner.ts mock → 真实 API
/api/v1/templates端点问题2 [低优先级]: 清理遗留文件
src/api/editPlans.ts(确认无任何引用)⚠️ 注意: 本地代码库中未发现后端
/api/v1/templates的路由定义(apps/api/app/api/routes/下无 templates 路由文件)。如果端点确实已上线,请确认后端代码是否已合并到当前分支。TypeScript 检查通过 ✅