fix(#1677): AI Review 反馈修复——标题校验/TTS依赖收窄/排序健壮性/预览数硬上限

- 单视频标题校验与 buildPayload.validateGenerateInputs 对齐:aiAutoSelect
  自动模式允许空标题(后端生成,既有设计),手动模式必填,逻辑显式化
- TTS 试听 effect 依赖收窄到 previewTitles[0](variant0Title),编辑其他
  变体标题不再触发多余 TTS 请求
- BatchGenerationGrid 排序加 (variantIndex || 0) 兜底防 NaN
- CanvasPreviewGrid 渲染数加 MAX_PREVIEW_COUNT(10) 硬上限,防媒体元素过多卡顿
This commit is contained in:
xiaoxia
2026-09-05 12:36:28 +08:00
parent ac28530528
commit 20fe447efb
3 changed files with 16 additions and 7 deletions
+11 -5
View File
@@ -132,6 +132,8 @@ const GeneratePage: React.FC = () => {
const [previewVoiceAudioUrl, setPreviewVoiceAudioUrl] = useState<string | null>(null)
const ttsAbortRef = useRef<AbortController | null>(null)
// TTS 试听文案:批量跟随变体0标题(仅取首项,避免编辑其他变体标题触发多余 TTS 请求)
const variant0Title = isBatch ? previewTitles[0] || "" : ""
useEffect(() => {
const voiceAsset = voiceMaterials.find((m) => m.id === selectedVoice)
@@ -141,7 +143,7 @@ const GeneratePage: React.FC = () => {
}
// 批量模式下 TTS 文案跟随变体0标题;单视频跟随主标题
const ttsTitle = isBatch ? previewTitles[0] || "" : titleSettings.title
const ttsTitle = isBatch ? variant0Title || "" : titleSettings.title
const voiceId = selectedClonedVoice || selectedVoice
if (!voiceId || !ttsTitle) {
setPreviewVoiceAudioUrl(null)
@@ -174,7 +176,7 @@ const GeneratePage: React.FC = () => {
selectedVoice,
selectedClonedVoice,
titleSettings.title,
previewTitles,
variant0Title,
isBatch,
voiceMaterials,
])
@@ -321,9 +323,13 @@ const GeneratePage: React.FC = () => {
message.warning("请为每个勾选的视频输入标题")
return
}
} else if (!titleSettings.aiAutoSelect && !titleSettings.title?.trim()) {
message.warning("请先选择或输入标题")
return
} else if (!titleSettings.title?.trim()) {
// 与 buildPayload.validateGenerateInputs 一致:AI 自动选标题模式(aiAutoSelect
// 允许空标题由后端生成;手动模式必须填写,避免提交空标题
if (!titleSettings.aiAutoSelect) {
message.warning("请先选择或输入标题")
return
}
}
if (!previewReady) {
message.warning("预览素材正在加载,请稍候")
@@ -22,7 +22,7 @@ const BatchGenerationGrid: React.FC<BatchGenerationGridProps> = ({
titles,
onRetryTask,
}) => {
const sorted = [...tasks].sort((a, b) => a.variantIndex - b.variantIndex)
const sorted = [...tasks].sort((a, b) => (a.variantIndex || 0) - (b.variantIndex || 0))
return (
<div className="xx-form-section">
@@ -12,6 +12,7 @@ import type { AssetItem } from "@/api/assets"
import type { EditingTemplate } from "@/api/editing-planner"
import type { TitleSettings } from "../types"
import FrontendPreviewPlayer from "./FrontendPreviewPlayer"
import { MAX_PREVIEW_COUNT } from "../constants"
interface CanvasPreviewGridProps {
count: number
@@ -41,9 +42,11 @@ const CanvasPreviewGrid: React.FC<CanvasPreviewGridProps> = ({
onToggleSelect,
selectable = true,
}) => {
// 硬上限保护:同时播放的媒体元素数量不超过 MAX_PREVIEW_COUNT10),避免浏览器卡顿
const safeCount = Math.max(1, Math.min(count, MAX_PREVIEW_COUNT))
return (
<div className="xx-canvas-grid">
{Array.from({ length: count }, (_, i) => {
{Array.from({ length: safeCount }, (_, i) => {
const checked = selectedIds.includes(i)
return (
<div