d67d6eb2cd
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m40s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m40s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m15s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m3s
CI/CD Pipeline / Build Staging Web Image (push) Failing after 4m3s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m21s
CI/CD Pipeline / Build Staging API Image (push) Successful in 8m27s
CI/CD Pipeline / Unit Tests (push) Successful in 10m29s
CI/CD Pipeline / Integration Tests (push) Successful in 3m42s
CI/CD Pipeline / CI Gate (push) Failing after 830h14m16s
CI/CD Pipeline / Canary Release to Production (push) Failing after 830h14m48s
CI/CD Pipeline / Deploy Production (push) Failing after 830h14m48s
CI/CD Pipeline / ACR Image Cleanup (push) Failing after 830h16m54s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 830h14m49s
CI/CD Pipeline / Staging API Integration Tests (push) Failing after 830h16m54s
CI/CD Pipeline / Build Production Web Image (push) Failing after 830h14m49s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Failing after 830h16m56s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 830h25m18s
CI/CD Pipeline / PR Build Web Image (push) Failing after 830h25m20s
CI/CD Pipeline / Frontend Lint (push) Failing after 830h25m20s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 830h25m24s
CI/CD Pipeline / Production Browser E2E (push) Failing after 830h48m19s
CI/CD Pipeline / Build Production API Image (push) Failing after 830h48m20s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 830h50m25s
CI/CD Pipeline / PR Build API Image (push) Failing after 830h58m51s
126 lines
3.5 KiB
TypeScript
126 lines
3.5 KiB
TypeScript
/**
|
|
* Step 7 确认生成 Hook
|
|
* 封装生成确认页的展示逻辑
|
|
*/
|
|
import { useMemo } from "react"
|
|
import { useQuery } from "@tanstack/react-query"
|
|
import type { EditingTemplate } from "@/api/editing-planner"
|
|
import type { GeneratedVideo } from "@/api/template-editor"
|
|
import type { CoverConfig } from "../types/cover"
|
|
import type { VoiceClone } from "@/api/voice-clone"
|
|
import type { PresetVoiceItem } from "@/api/voices"
|
|
import { getAssetsByKind } from "@/api/assets"
|
|
import { COVER_MODE_LABELS } from "../constants"
|
|
|
|
interface UseStep7GenerateProps {
|
|
templates: EditingTemplate[]
|
|
selectedTemplate: string
|
|
materialMode: "manual" | "auto"
|
|
selectedMaterials: string[]
|
|
smartSelectedIds: string[]
|
|
title: string
|
|
voiceMode: "preset" | "custom" | "clone"
|
|
selectedVoice: string
|
|
selectedClonedVoice: string
|
|
presetVoices: PresetVoiceItem[]
|
|
clonedVoices: VoiceClone[]
|
|
coverSettings: CoverConfig
|
|
generateCount: number
|
|
onGenerateCountChange: (count: number) => void
|
|
generating: boolean
|
|
generated: boolean
|
|
generateError: string | null
|
|
progress: number
|
|
generatedVideos: GeneratedVideo[]
|
|
}
|
|
|
|
export function useStep7Generate({
|
|
templates,
|
|
selectedTemplate,
|
|
materialMode,
|
|
selectedMaterials,
|
|
smartSelectedIds,
|
|
title,
|
|
voiceMode: _voiceMode,
|
|
selectedVoice,
|
|
selectedClonedVoice: _selectedClonedVoice,
|
|
presetVoices: _presetVoices,
|
|
clonedVoices: _clonedVoices,
|
|
coverSettings,
|
|
generateCount,
|
|
onGenerateCountChange,
|
|
generating,
|
|
generated,
|
|
generateError,
|
|
progress,
|
|
generatedVideos,
|
|
}: UseStep7GenerateProps) {
|
|
const templateName = useMemo(
|
|
() => templates.find((t) => t.id === selectedTemplate)?.name ?? "未选择",
|
|
[templates, selectedTemplate],
|
|
)
|
|
|
|
const materialSummary = useMemo(() => {
|
|
if (materialMode === "auto") {
|
|
return `${smartSelectedIds.length} 个素材(智能匹配)`
|
|
}
|
|
return `${selectedMaterials.length} 个素材`
|
|
}, [materialMode, selectedMaterials.length, smartSelectedIds.length])
|
|
|
|
// 从配音素材库中查找 voiceName
|
|
const { data: voiceMaterials = [] } = useQuery({
|
|
queryKey: ["assets", "voice"],
|
|
queryFn: () => getAssetsByKind("voice", { limit: 50 }),
|
|
})
|
|
|
|
const voiceName = useMemo(() => {
|
|
const asset = voiceMaterials.find((v) => v.id === selectedVoice)
|
|
return asset ? asset.name : "未选择"
|
|
}, [voiceMaterials, selectedVoice])
|
|
|
|
const coverSummary = useMemo(() => {
|
|
if (!coverSettings.enabled) return "不使用"
|
|
return COVER_MODE_LABELS[coverSettings.mode] || "智能封面"
|
|
}, [coverSettings])
|
|
|
|
const getGenerationPhase = (p: number) => {
|
|
if (p < 20) return { label: "分析素材与配置", icon: "🔍" }
|
|
if (p < 50) return { label: "智能剪辑合成", icon: "🎬" }
|
|
if (p < 80) return { label: "渲染视频中", icon: "⚡" }
|
|
return { label: "即将完成", icon: "✨" }
|
|
}
|
|
|
|
const handleDecrement = () => {
|
|
onGenerateCountChange(Math.max(1, generateCount - 1))
|
|
}
|
|
|
|
const handleIncrement = () => {
|
|
onGenerateCountChange(Math.min(10, generateCount + 1))
|
|
}
|
|
|
|
const handleScrollToPreview = () => {
|
|
const el = document.querySelector(".xx-preview-section")
|
|
el?.scrollIntoView({ behavior: "smooth", block: "start" })
|
|
}
|
|
|
|
return {
|
|
templateName,
|
|
materialSummary,
|
|
title,
|
|
voiceName,
|
|
coverSummary,
|
|
generateCount,
|
|
handleDecrement,
|
|
handleIncrement,
|
|
generating,
|
|
generated,
|
|
generateError,
|
|
progress,
|
|
generatedVideos,
|
|
getGenerationPhase,
|
|
handleScrollToPreview,
|
|
}
|
|
}
|
|
|
|
export default useStep7Generate
|