fix(#1677): AI Review 阻塞项修复 — 配音模式切换同步+预览标题双重叠加
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 9s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 10s
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 / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration 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 / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m12s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m58s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 2m32s
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 / Frontend Lint (pull_request) Successful in 3m24s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 3m45s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 2m59s
AI Code Review / AI Code Review (pull_request) Failing after 4m29s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 5m10s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 5s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Failing after 11m0s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped

- 配音同步 effect 响应模式切换:独立→共用时所有变体刷成共用配音;
  独立模式下共用配音变化仅同步变体[0],不覆盖用户单独选择
- 批量预览不再传 titles/title_config 给后端:标题由 CSS 浮层实时叠加,
  避免服务器预览视频烧录标题后与前端浮层双重显示;
  buildPreviewRequest 移除 titleSettings 依赖及 eslint-disable;
  预览指纹不含 titles,标题文字/样式变化不触发重渲染
This commit is contained in:
xiaoxia
2026-09-05 08:38:12 +08:00
parent 970380662e
commit b0ea3565ee
2 changed files with 25 additions and 35 deletions
+23 -33
View File
@@ -90,21 +90,28 @@ const GeneratePage: React.FC = () => {
const isBatch = previewCount > 1
/* ── 配音选择同步:共用配音 ↔ 变体数组 ── */
// 共用配音变化且独立数组[0]为空时,填充到所有变体(独立模式下用户已单独选择的不覆盖
const prevSharedVoiceRef = useRef(selectedVoice)
// 触发场景:①共用配音变化 ②批量模式进入/退出 ③独立→共用切换(需把所有变体刷成共用配音
// 独立模式下:仅同步变体[0](其选择器绑定共用配音),用户单独选择的其他变体不覆盖
const prevVoiceSyncRef = useRef({
voice: selectedVoice,
batch: isBatch,
perVideo: voiceModePerVideo,
})
useEffect(() => {
if (prevSharedVoiceRef.current === selectedVoice) return
prevSharedVoiceRef.current = selectedVoice
if (!isBatch || !voiceModePerVideo) {
// 共用模式:所有变体跟随共用配音
setVoiceLibraryIds((prev) =>
prev.map((id, i) => (i === 0 ? selectedVoice : id || selectedVoice)),
)
} else {
setVoiceLibraryIds((prev) => prev.map((id, i) => (i === 0 ? selectedVoice : id)))
const prev = prevVoiceSyncRef.current
const voiceChanged = prev.voice !== selectedVoice
const modeChanged = prev.batch !== isBatch || prev.perVideo !== voiceModePerVideo
prevVoiceSyncRef.current = { voice: selectedVoice, batch: isBatch, perVideo: voiceModePerVideo }
if (!voiceChanged && !modeChanged) return
if (!isBatch) return
if (!voiceModePerVideo) {
// 共用模式(含刚从独立切回):所有变体跟随共用配音,未选择的补默认值
setVoiceLibraryIds((prevIds) => prevIds.map((id) => id || selectedVoice))
} else if (voiceChanged) {
// 独立模式下共用配音变化:仅同步变体[0](与共用选择器绑定),其余不覆盖
setVoiceLibraryIds((prevIds) => prevIds.map((id, i) => (i === 0 ? selectedVoice : id)))
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedVoice])
}, [selectedVoice, isBatch, voiceModePerVideo, setVoiceLibraryIds])
/* ── 数量选择弹窗 ── */
const [countModalOpen, setCountModalOpen] = useState(false)
@@ -220,22 +227,8 @@ const GeneratePage: React.FC = () => {
? { voice_library_ids: voiceLibraryIds.map((id) => id || voiceLibraryId) }
: {}),
preview_count: previewCount,
titles: previewTitles.some((t) => t?.trim()) ? previewTitles : [],
// 标题样式全局共用(文字由 titles[] 按变体独立提供,后端会把变体文字合并进 title_config
...(titleSettings.title || previewTitles[0]
? {
title_config: {
text: previewTitles[0] || titleSettings.title,
font: titleSettings.font,
font_size: titleSettings.size,
font_color: titleSettings.color,
position: titleSettings.position,
bold: titleSettings.bold,
stroke: titleSettings.stroke,
shadow: titleSettings.shadow,
},
}
: {}),
// 批量预览不传 titles/title_config:标题文字与样式由前端 CSS 浮层实时叠加
// (用户改标题/样式即时可见,无需重渲染);正式生成时才把标题烧录进成片
duration: duration || undefined,
bgm_config: {
enabled: bgm !== false,
@@ -255,14 +248,11 @@ const GeneratePage: React.FC = () => {
voiceModePerVideo,
voiceLibraryIds,
previewCount,
previewTitles,
duration,
bgm,
bgmConfig,
storedSourceEditPlanId,
sourceEditPlanId,
// eslint-disable-next-line react-hooks/exhaustive-deps
titleSettings,
])
const {
@@ -388,10 +378,10 @@ const GeneratePage: React.FC = () => {
}
// 批量模式停留在步骤4,右侧网格显示生成进度,完成后点"下一步"进封面
}, [
previewTitles,
isBatch,
selectedVariantIds.length,
previewReady,
previewTitles,
handleGenerate,
setCurrentStep,
])
@@ -51,9 +51,10 @@ const POLL_TIMEOUT = 180_000
const MAX_NETWORK_RETRIES = 2
/**
* 对配置参数做指纹,用于检测配置是否变化(标题文字变化不触发重渲染,仅CSS浮层叠加)
* 对配置参数做指纹,用于检测配置是否变化(标题文字/样式变化不触发重渲染,仅CSS浮层叠加)
*/
function buildFingerprint(req: CreatePreviewRequest): string {
// 不含 titles/title_config:标题文字与样式由 CSS 浮层实时叠加,变化不触发重渲染
return JSON.stringify({
t: req.template_id,
a: [...(req.asset_ids || [])].sort(),
@@ -62,7 +63,6 @@ function buildFingerprint(req: CreatePreviewRequest): string {
vs: req.voice_library_ids,
pc: req.preview_count,
b: req.bgm_config,
titles: req.titles,
})
}