feat(editing-planner): 生成进度展示 — 任务 2.17 #158

Merged
xiaoxia merged 1 commits from feature/task-2.17-generation-progress into develop 2026-07-01 20:14:47 +08:00
Owner

任务 2.17:生成进度展示

实现内容

  • 新增 GenerationProgressModal 组件,支持三阶段 UI:setup(配置)→ progress(进度轮询)→ completed / failed(结果)
  • 集成 React Query 轮询机制:refetchInterval 2s 轮询任务状态,终态自动停止
  • 进度展示:SVG 进度环 + 进度条 + 步骤文案 + 任务 ID
  • 失败处理:错误信息展示 + 可重试时显示重试按钮
  • 对接 createGenerationTask / getTask / retryTask API

技术实现

  • 使用 React Query 的 refetchInterval 实现任务状态轮询
  • SVG circle 动画进度环(stroke-dasharray/stroke-dashoffset)
  • 自动阶段切换:useEffect 监听 taskData.status 变化
  • V21 设计系统,CSS 类名前缀 ep-gen-

涉及文件

  • apps/web/src/api/tasks.ts — 新增 getTask/retryTask API
  • apps/web/src/pages/editing-planner/components/GenerationProgressModal.tsx — 新组件
  • apps/web/src/pages/editing-planner/EditingPlanner.tsx — 集成任务创建和轮询
  • apps/web/src/pages/editing-planner/EditingPlanner.css — 新增样式

验证

  • TypeScript 检查通过(零错误)
  • 多阶段 UI 正常切换
  • 轮询机制正常工作
## 任务 2.17:生成进度展示 ### 实现内容 - 新增 GenerationProgressModal 组件,支持三阶段 UI:setup(配置)→ progress(进度轮询)→ completed / failed(结果) - 集成 React Query 轮询机制:refetchInterval 2s 轮询任务状态,终态自动停止 - 进度展示:SVG 进度环 + 进度条 + 步骤文案 + 任务 ID - 失败处理:错误信息展示 + 可重试时显示重试按钮 - 对接 createGenerationTask / getTask / retryTask API ### 技术实现 - 使用 React Query 的 `refetchInterval` 实现任务状态轮询 - SVG circle 动画进度环(stroke-dasharray/stroke-dashoffset) - 自动阶段切换:useEffect 监听 taskData.status 变化 - V21 设计系统,CSS 类名前缀 `ep-gen-` ### 涉及文件 - `apps/web/src/api/tasks.ts` — 新增 getTask/retryTask API - `apps/web/src/pages/editing-planner/components/GenerationProgressModal.tsx` — 新组件 - `apps/web/src/pages/editing-planner/EditingPlanner.tsx` — 集成任务创建和轮询 - `apps/web/src/pages/editing-planner/EditingPlanner.css` — 新增样式 ### 验证 - TypeScript 检查通过(零错误) - 多阶段 UI 正常切换 - 轮询机制正常工作
xiaoxia added 1 commit 2026-07-01 18:10:19 +08:00
feat(editing-planner): 实现生成进度展示 — 任务 2.17
Deploy / Build Production Runtime Images (push) Has been skipped
Deploy / Deploy Production (push) Has been skipped
Deploy / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 186h43m22s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 186h43m25s
Deploy / Deploy Staging (push) Failing after 186h43m53s
CI/CD Pipeline / Frontend Lint (push) Failing after 186h44m20s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 186h44m24s
6ce40d76ea
- 新增 GenerationProgressModal 组件:三阶段 UI(setup → progress → completed/failed)
- 集成 React Query 轮询:refetchInterval 2s 轮询任务状态,终态自动停止
- 进度展示:SVG 进度环 + 进度条 + 步骤文案 + 任务 ID
- 失败处理:错误信息展示 + 可重试时显示重试按钮
- 对接 createGenerationTask / getTask / retryTask API
- V21 设计系统,CSS 类名前缀 ep-gen-
Author
Owner

代码审查报告 — PR #158(任务 2.17 生成进度展示)

审查范围: 4 个文件,+482/-14

  • api/tasks.ts — 新增 getTask 轮询接口
  • EditingPlanner.css — 进度弹窗样式(149 行)
  • EditingPlanner.tsx — 集成新弹窗 + React Query 轮询
  • components/GenerationProgressModal.tsx — 新组件(251 行)

审查结论:有条件通过(2 P2 + 3 P3,不阻塞合并)

整体设计合理:三阶段状态机(setup → progress → completed/failed)清晰,React Query 轮询在终态自动停止,SVG 进度环 + 进度条双重视觉反馈体验好。CSS 命名规范,类型安全。以下是建议修复项。


P2 — 建议修复

P2-1:handleRetry 未用返回值更新缓存,可能闪现旧失败状态

const handleRetry = () => {
  if (!taskId) return;
  retryTask(taskId).then(() => {
    setGenPhase("progress");  // 切换 phase → React Query 重新启用
    // 但此时 query cache 里还是 failed 状态的数据
    // 需要等 refetch 完成后 useEffect 才会把 phase 切回 progress
    // 极端情况下可能先闪一下 failed UI 再切 progress
  })
};

建议:用 queryClient.setQueryData 立即更新缓存,避免闪烁:

import { useQueryClient } from "@tanstack/react-query";

const queryClient = useQueryClient();

const handleRetry = async () => {
  if (!taskId) return;
  try {
    const updated = await retryTask(taskId);
    queryClient.setQueryData(["task", taskId], updated);
    setGenPhase("progress");
    showToast("任务已重新提交", "success");
  } catch {
    showToast("重试失败", "error");
  }
};

P2-2:ep-gen-duration-input CSS 类缺失

setup 阶段的 <input> 使用了 className="ep-gen-duration-input",但 CSS 文件中没有定义这个类。输入框会回退到浏览器默认样式,与整体设计不一致。

建议:在 CSS 中补充样式,或使用项目已有的 input 组件/类名。


P3 — 可选优化

P3-1:prevOpen ref 逻辑是空操作

const prevOpen = useRef(false);
useEffect(() => {
  if (prevOpen.current && !open) {
    /* modal just closed — parent handles reset */
  }
  prevOpen.current = open;
}, [open]);

这个 effect 没有任何实际作用(注释也说了 parent handles reset)。建议删除,减少无谓的 re-render。

P3-2:getStepLabel 对 unknown step 的 fallback 可读性一般

const getStepLabel = (step: string) =>
  STEP_LABELS[step] || step.replace(/_/g, " ");

step.replace(/_/g, " ") 输出全小写(如 "downloading assets"),建议首字母大写:

step.replace(/_/g, " ").replace(/^\w/, c => c.toUpperCase())

P3-3:completed 阶段未展示 result_count

TaskItemresult_count 相关信息(通过 CreateGenerationTaskResponse),但 completed 阶段 UI 只展示了 userMessage,没有展示生成了多少个视频/素材。可考虑在结果页增加一行"共生成 N 个视频"。


👍 亮点

  • 三阶段状态机设计清晰,GenPhase 类型约束合理
  • React Query 的 refetchInterval 函数式用法正确:终态返回 false 自动停止轮询
  • SVG 进度环的 strokeDashoffset 计算正确,颜色跟随步骤状态变化
  • handleCloseProgressModal 统一清理 genPhase + taskId,避免状态残留
  • CSS 严格使用设计系统变量(--space-md--text-primary 等),响应式一致

总结: 功能完整,代码质量良好。2 个 P2 建议修复(���试缓存更新 + 缺失 CSS),不阻塞合并。mergeable=True,可以直接合并。

## 代码审查报告 — PR #158(任务 2.17 生成进度展示) **审查范围:** 4 个文件,+482/-14 - `api/tasks.ts` — 新增 `getTask` 轮询接口 - `EditingPlanner.css` — 进度弹窗样式(149 行) - `EditingPlanner.tsx` — 集成新弹窗 + React Query 轮询 - `components/GenerationProgressModal.tsx` — 新组件(251 行) --- ### ✅ 审查结论:**有条件通过**(2 P2 + 3 P3,不阻塞合并) 整体设计合理:三阶段状态机(setup → progress → completed/failed)清晰,React Query 轮询在终态自动停止,SVG 进度环 + 进度条双重视觉反馈体验好。CSS 命名规范,类型安全。以下是建议修复项。 --- ### P2 — 建议修复 **P2-1:`handleRetry` 未用返回值更新缓存,可能闪现旧失败状态** ```tsx const handleRetry = () => { if (!taskId) return; retryTask(taskId).then(() => { setGenPhase("progress"); // 切换 phase → React Query 重新启用 // 但此时 query cache 里还是 failed 状态的数据 // 需要等 refetch 完成后 useEffect 才会把 phase 切回 progress // 极端情况下可能先闪一下 failed UI 再切 progress }) }; ``` 建议:用 `queryClient.setQueryData` 立即更新缓存,避免闪烁: ```tsx import { useQueryClient } from "@tanstack/react-query"; const queryClient = useQueryClient(); const handleRetry = async () => { if (!taskId) return; try { const updated = await retryTask(taskId); queryClient.setQueryData(["task", taskId], updated); setGenPhase("progress"); showToast("任务已重新提交", "success"); } catch { showToast("重试失败", "error"); } }; ``` **P2-2:`ep-gen-duration-input` CSS 类缺失** setup 阶段的 `<input>` 使用了 `className="ep-gen-duration-input"`,但 CSS 文件中没有定义这个类。输入框会回退到浏览器默认样式,与整体设计不一致。 建议:在 CSS 中补充样式,或使用项目已有的 input 组件/类名。 --- ### P3 — 可选优化 **P3-1:`prevOpen` ref 逻辑是空操作** ```tsx const prevOpen = useRef(false); useEffect(() => { if (prevOpen.current && !open) { /* modal just closed — parent handles reset */ } prevOpen.current = open; }, [open]); ``` 这个 effect 没有任何实际作用(注释也说了 parent handles reset)。建议删除,减少无谓的 re-render。 **P3-2:`getStepLabel` 对 unknown step 的 fallback 可读性一般** ```tsx const getStepLabel = (step: string) => STEP_LABELS[step] || step.replace(/_/g, " "); ``` `step.replace(/_/g, " ")` 输出全小写(如 `"downloading assets"`),建议首字母大写: ```tsx step.replace(/_/g, " ").replace(/^\w/, c => c.toUpperCase()) ``` **P3-3:completed 阶段未展示 `result_count`** `TaskItem` 有 `result_count` 相关信息(通过 `CreateGenerationTaskResponse`),但 completed 阶段 UI 只展示了 `userMessage`,没有展示生成了多少个视频/素材。可考虑在结果页增加一行"共生成 N 个视频"。 --- ### 👍 亮点 - 三阶段状态机设计清晰,`GenPhase` 类型约束合理 - React Query 的 `refetchInterval` 函数式用法正确:终态返回 `false` 自动停止轮询 - SVG 进度环的 `strokeDashoffset` 计算正确,颜色跟随步骤状态变化 - `handleCloseProgressModal` 统一清理 `genPhase` + `taskId`,避免状态残留 - CSS 严格使用设计系统变量(`--space-md`、`--text-primary` 等),响应式一致 --- **总结:** 功能完整,代码质量良好。2 个 P2 建议修复(���试缓存更新 + 缺失 CSS),不阻塞合并。mergeable=True,可以直接合并。
xiaoxia merged commit 6c08459d12 into develop 2026-07-01 20:14:47 +08:00
Sign in to join this conversation.