feat: Step2选素材同步写入edit_plan_clips #1469

Merged
xiaoxia merged 1 commits from feat/sync-edit-plan-clips into develop 2026-08-23 17:42:26 +08:00
Owner

背景

后端正在改造 Worker 渲染逻辑,改为直接读取数据库 edit_plan_clips 表渲染(不再从 asset_ids 重建)。前端需要在选素材时把 clips 写入数据库。

改动

  1. 新增 API updateEditPlanClips(templateId, clips, signal?) — PUT /templates/{id}/editor/clips
  2. 新增共享工具 buildClipsFromAssets() — clips 构建逻辑与 FrontendPreviewPlayer.buildPlaybackSegments 完全一致(clamp(assetDuration, seg.duration_min, seg.duration_max)start_time=0
  3. useStep2Materials — 选素材防抖 800ms 后同步写入 clips;手动/智能匹配两种模式都支持;AbortController 取消上一次未完成请求;失败 console.warn,不弹窗不阻塞
  4. prop 透传 — Step2MaterialSelect / GenerateStepContent 透传 templateSegments
  5. 生成参数 — 确认 source_edit_plan_idtitle_configcover_urlasset_ids 都已正确传递(无需额外改动)

验收

  • TypeScript 编译通过
  • ESLint 0 warning
  • Prettier 格式化
  • clips duration 与前端预览一致
## 背景 后端正在改造 Worker 渲染逻辑,改为直接读取数据库 `edit_plan_clips` 表渲染(不再从 `asset_ids` 重建)。前端需要在选素材时把 clips 写入数据库。 ## 改动 1. **新增 API** `updateEditPlanClips(templateId, clips, signal?)` — PUT `/templates/{id}/editor/clips` 2. **新增共享工具** `buildClipsFromAssets()` — clips 构建逻辑与 `FrontendPreviewPlayer.buildPlaybackSegments` 完全一致(`clamp(assetDuration, seg.duration_min, seg.duration_max)`,`start_time=0`) 3. **useStep2Materials** — 选素材防抖 800ms 后同步写入 clips;手动/智能匹配两种模式都支持;AbortController 取消上一次未完成请求;失败 console.warn,不弹窗不阻塞 4. **prop 透传** — Step2MaterialSelect / GenerateStepContent 透传 `templateSegments` 5. **生成参数** — 确认 `source_edit_plan_id`、`title_config`、`cover_url`、`asset_ids` 都已正确传递(无需额外改动) ## 验收 - [x] TypeScript 编译通过 - [x] ESLint 0 warning - [x] Prettier 格式化 - [x] clips duration 与前端预览一致
xiaoxia added 1 commit 2026-08-23 16:16:58 +08:00
feat: sync selected materials to edit_plan_clips on Step2
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 40s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m50s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m52s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m52s
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m16s
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m14s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m25s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m47s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 2m10s
AI Code Review / AI Code Review (pull_request) Successful in 4m43s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 6m16s
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 49s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m0s
9e7f04e312
- New API updateEditPlanClips (PUT /templates/{id}/editor/clips)
- useStep2Materials: debounced 800ms, builds clips with same logic
  as FrontendPreviewPlayer.buildPlaybackSegments (clamp asset
  duration to template segment duration_min/max)
- buildClipsFromAssets shared util ensures duration consistency
  between preview and clips written to DB
- Supports both manual and smart-match modes
- Failures are silent (console.warn), never block the user
- Step2MaterialSelect/GenerateStepContent pass templateSegments

🚀 预览环境已部署

项目 详情
PR号 #1469
预览链接 https://pr-1469.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1469 | | 预览链接 | [https://pr-1469.preview.xiaoxiajianji.com](https://pr-1469.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
Collaborator

代码审查结果 - PR #1469

⚠️ 问题(1个需要修改)

  1. apps/web/src/pages/generate/hooks/useStep2Materials.ts 第80行:当用户取消选择所有素材时(ids.length 为 0),代码直接 return 导致未调用 updateEditPlanClips。这会导致后端无法清空 clips 数据,造成前后端数据不一致,生成任务可能残留旧的 clips 数据。
  2. apps/web/src/pages/generate/utils/buildClipsFromAssets.ts 第48行:当 templateSegments 为空数组时,lastSeg 为 undefined,且 tplSeg 也会为 undefined。虽然代码有 fallback 逻辑 Math.min(assetDuration, 10),但在没有模板结构信息的情况下硬编码 10 秒作为默认时长可能不符合业务预期(通常应阻止生成或报错),建议确认此边界场景的业务逻辑。

💡 建议(2个可选)

  1. apps/web/src/pages/generate/hooks/useStep2Materials.tsuseEffect 依赖数组中未包含 materials,仅通过 useRef 获取最新值。如果素材列表中的元数据(如 duration)在加载后被更新,已选中的 clips 将不会自动同步更新时长。建议评估是否需要监听 materials 的变化或在关键操作时强制刷新。
  2. apps/web/src/pages/generate/utils/buildClipsFromAssets.ts:注释提到逻辑需与 FrontendPreviewPlayer.tsx 保持一致,建议抽取公共逻辑函数或增加单元测试以防止未来修改导致两边逻辑不一致。

格式检查通过 | 逻辑审查需修改 | 性能良好


🤖 由 AI 代码审查机器人自动生成 | 2026-08-23 08:21:42 | 模型:

## 代码审查结果 - PR #1469 ### ⚠️ 问题(1个需要修改) 1. **apps/web/src/pages/generate/hooks/useStep2Materials.ts 第80行**:当用户取消选择所有素材时(`ids.length` 为 0),代码直接 return 导致未调用 `updateEditPlanClips`。这会导致后端无法清空 clips 数据,造成前后端数据不一致,生成任务可能残留旧的 clips 数据。 2. **apps/web/src/pages/generate/utils/buildClipsFromAssets.ts 第48行**:当 `templateSegments` 为空数组时,`lastSeg` 为 undefined,且 `tplSeg` 也会为 undefined。虽然代码有 fallback 逻辑 `Math.min(assetDuration, 10)`,但在没有模板结构信息的情况下硬编码 10 秒作为默认时长可能不符合业务预期(通常应阻止生成或报错),建议确认此边界场景的业务逻辑。 ### 💡 建议(2个可选) 1. **apps/web/src/pages/generate/hooks/useStep2Materials.ts**:`useEffect` 依赖数组中未包含 `materials`,仅通过 `useRef` 获取最新值。如果素材列表中的元数据(如 duration)在加载后被更新,已选中的 clips 将不会自动同步更新时长。建议评估是否需要监听 `materials` 的变化或在关键操作时强制刷新。 2. **apps/web/src/pages/generate/utils/buildClipsFromAssets.ts**:注释提到逻辑需与 `FrontendPreviewPlayer.tsx` 保持一致,建议抽取公共逻辑函数或增加单元测试以防止未来修改导致两边逻辑不一致。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ✅ 性能良好 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-23 08:21:42 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia merged commit 392a20002c into develop 2026-08-23 17:42:26 +08:00

🗑️ 预览环境已清理

PR #1469 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1469 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.