feat: 标题设置实时预览Canvas + 绘制函数抽取共享模块 #1379

Closed
xiaoxia wants to merge 1 commits from feat/title-preview-canvas-v2 into develop
Owner

背景

步骤重排后,用户在 Step4(标题)选完标题后无法直观看到字体大小、位置等实际效果,需要等 Step5 视频渲染完才能确认。

改动

1. 抽取 Canvas 绘制工具函数为共享模块

  • 新建 utils/drawTitleOnCanvas.ts:将 wrapText()drawTitleOnCanvas() 从 PreviewVideoPanel 搬到此文件并 export
  • 修改 PreviewVideoPanel.tsx:改为从共享模块 import,删除内部重复定义,功能逻辑完全不变

2. 新建 TitlePreviewCanvas 组件

  • 新建 components/title/TitlePreviewCanvas.tsx
  • 容器尺寸按 videoRatio 计算 aspect-ratio,深色渐变背景模拟视频画面
  • 使用共享 drawTitleOnCanvas() 绘制标题(paddingX=24, topOffset=40 与 ASS 一致)
  • useEffect 监听 props 变化 + ResizeObserver 监听容器尺寸变化
  • Canvas DPR 适配,FontFace API 加载字体(失败降级默认字体)

3. 集成到 Step4TitleSettings

  • 标题非空时在样式面板上方显示 TitlePreviewCanvas
  • 带「预览效果」小标签

文件清单

文件 改动
utils/drawTitleOnCanvas.ts 新建 - 共享绘制模块
PreviewVideoPanel.tsx 改为 import 共享模块
title/TitlePreviewCanvas.tsx 新建 - 实时预览组件
Step4TitleSettings.tsx 集成预览 Canvas

验证要点

  • 纯前端改动,不涉及后端 API
  • Step 流程不变,只改 Step4 组件内部布局
  • PreviewVideoPanel 的 Canvas 绘制逻辑功能不变
## 背景 步骤重排后,用户在 Step4(标题)选完标题后无法直观看到字体大小、位置等实际效果,需要等 Step5 视频渲染完才能确认。 ## 改动 ### 1. 抽取 Canvas 绘制工具函数为共享模块 - **新建** `utils/drawTitleOnCanvas.ts`:将 `wrapText()` 和 `drawTitleOnCanvas()` 从 PreviewVideoPanel 搬到此文件并 export - **修改** `PreviewVideoPanel.tsx`:改为从共享模块 import,删除内部重复定义,功能逻辑完全不变 ### 2. 新建 TitlePreviewCanvas 组件 - **新建** `components/title/TitlePreviewCanvas.tsx` - 容器尺寸按 videoRatio 计算 aspect-ratio,深色渐变背景模拟视频画面 - 使用共享 `drawTitleOnCanvas()` 绘制标题(paddingX=24, topOffset=40 与 ASS 一致) - useEffect 监听 props 变化 + ResizeObserver 监听容器尺寸变化 - Canvas DPR 适配,FontFace API 加载字体(失败降级默认字体) ### 3. 集成到 Step4TitleSettings - 标题非空时在样式面板上方显示 TitlePreviewCanvas - 带「预览效果」小标签 ## 文件清单 | 文件 | 改动 | |------|------| | `utils/drawTitleOnCanvas.ts` | 新建 - 共享绘制模块 | | `PreviewVideoPanel.tsx` | 改为 import 共享模块 | | `title/TitlePreviewCanvas.tsx` | 新建 - 实时预览组件 | | `Step4TitleSettings.tsx` | 集成预览 Canvas | ## 验证要点 - 纯前端改动,不涉及后端 API - Step 流程不变,只改 Step4 组件内部布局 - PreviewVideoPanel 的 Canvas 绘制逻辑功能不变
xiaoxia added the feature label 2026-08-15 17:37:12 +08:00
xiaoxia added 1 commit 2026-08-15 17:37:12 +08:00
feat: 标题设置实时预览Canvas + 绘制函数抽取共享模块
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 / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 36s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m14s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 43s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 47s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 1m24s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m33s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m50s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m52s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m49s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 4m4s
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
AI Code Review / AI Code Review (pull_request) Successful in 4m5s
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 6s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 19s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Waiting to run
b1c5e5f55c
- 新建 utils/drawTitleOnCanvas.ts:抽取 wrapText/drawTitleOnCanvas 为共享模块
- PreviewVideoPanel.tsx 改为 import 共享模块,删除内部重复定义
- 新建 TitlePreviewCanvas 组件:深色渐变背景 + Canvas 实时绘制标题
  - useEffect 监听 props 变化 + ResizeObserver 监听容器尺寸
  - FontFace API 加载字体,失败降级默认字体
  - DPR 适配,paddingX=24/topOffset=40 与 ASS 一致
- Step4TitleSettings 集成:标题非空时在样式面板上方显示预览
- 纯前端重构,不涉及后端 API,不改 Step 流程

🚀 预览环境已部署

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

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

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

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

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

【阻塞级判定】

  • 是否存在阻塞级问题:否
  • 阻塞级问题数量:0 个

📊 审查概览

  • 整体评价:通过
  • 建议级问题数量:2 个

🔴 阻塞级问题(必须修复)

💡 改进建议(不阻塞合并)

  1. [TitlePreviewCanvas.tsx: 86] 冗余的类型断言

    • 具体内容:代码中使用了 (document.fonts as any).add(fontFace)document.fonts 的标准类型定义中包含 add 方法,且参数类型为 FontFace,此处 as any 断言是不必要的,建议删除以保持类型安全。
  2. [TitlePreviewCanvas.tsx: 71-88] 字体加载逻辑可能导致重复绘制

    • 具体内容:在字体加载的 useEffect 中,如果字体已经加载完成(document.fonts.check 为 true),fontFace.load().then() 中的回调会执行 onFontReady(),随后的同步代码 if (document.fonts.check(...)) 也会执行 onFontReady()。这会导致在同一帧内触发两次 draw。建议在 try 块之前先执行 check,如果已加载则直接 return,避免重复的 Promise 创建和回调执行。

良好实践

  • 代码复用:成功将 drawTitleOnCanvaswrapText 提取为独立工具函数,消除了组件间的重复代码,符合 DRY 原则。
  • 高清屏适配:在 drawTitleOnCanvas 中正确处理了 devicePixelRatio,确保在高分屏设备上渲染清晰。
  • 资源清理TitlePreviewCanvas 中正确使用了 ResizeObserver 并在组件卸载时断开连接,避免了内存泄漏;字体加载的异步操作也加入了 cancelled 标志位以避免卸载后的状态更新。

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


🤖 由 AI 代码审查机器人自动生成 | 2026-08-15 09:41:17 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:否 - 阻塞级问题数量:0 个 ### 📊 审查概览 - 整体评价:通过 - 建议级问题数量:2 个 ### 🔴 阻塞级问题(必须修复) 无 ### 💡 改进建议(不阻塞合并) 1. **[TitlePreviewCanvas.tsx: 86] 冗余的类型断言** - 具体内容:代码中使用了 `(document.fonts as any).add(fontFace)`。`document.fonts` 的标准类型定义中包含 `add` 方法,且参数类型为 `FontFace`,此处 `as any` 断言是不必要的,建议删除以保持类型安全。 2. **[TitlePreviewCanvas.tsx: 71-88] 字体加载逻辑可能导致重复绘制** - 具体内容:在字体加载的 `useEffect` 中,如果字体已经加载完成(`document.fonts.check` 为 true),`fontFace.load().then()` 中的回调会执行 `onFontReady()`,随后的同步代码 `if (document.fonts.check(...))` 也会执行 `onFontReady()`。这会导致在同一帧内触发两次 `draw`。建议在 `try` 块之前先执行 `check`,如果已加载则直接 return,避免重复的 Promise 创建和回调执行。 ### ✅ 良好实践 - **代码复用**:成功将 `drawTitleOnCanvas` 和 `wrapText` 提取为独立工具函数,消除了组件间的重复代码,符合 DRY 原则。 - **高清屏适配**:在 `drawTitleOnCanvas` 中正确处理了 `devicePixelRatio`,确保在高分屏设备上渲染清晰。 - **资源清理**:`TitlePreviewCanvas` 中正确使用了 `ResizeObserver` 并在组件卸载时断开连接,避免了内存泄漏;字体加载的异步操作也加入了 `cancelled` 标志位以避免卸载后的状态更新。 --- ✅ 格式检查通过 | ✅ 逻辑审查通过 | ✅ 性能良好 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-15 09:41:17 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia closed this pull request 2026-08-16 16:59:38 +08:00

🗑️ 预览环境已清理

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

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

🗑️ **预览环境已清理** PR #1379 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Some checks are pending
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 / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 36s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m14s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 43s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 47s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 1m24s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m33s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m50s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m52s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m49s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 4m4s
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
AI Code Review / AI Code Review (pull_request) Successful in 4m5s
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 6s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 19s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Waiting to run

Pull request closed

Sign in to join this conversation.