199 lines
5.4 KiB
TypeScript
Executable File
199 lines
5.4 KiB
TypeScript
Executable File
/**
|
|
* GeneratePage 表单状态管理
|
|
* 集中管理 7 步向导的所有共享状态、API 加载、URL 参数解析
|
|
*/
|
|
import { useState } from "react"
|
|
import { useSearchParams } from "react-router-dom"
|
|
import type { GeneratedVideo } from "@/api/template-editor"
|
|
import type { EditingTemplate } from "@/api/editing-planner"
|
|
import type { CoverConfig } from "../../types/cover"
|
|
import type { PresetVoiceItem } from "@/api/voices"
|
|
import { DEFAULT_COVER_SETTINGS } from "../../constants"
|
|
import type { TitleSettings } from "../../types"
|
|
import { useTemplateSelection } from "./useTemplateSelection"
|
|
import { useTitleCoverSync } from "./useTitleCoverSync"
|
|
import { useVoiceState } from "./useVoiceState"
|
|
import { usePlanConfigLoader } from "./usePlanConfigLoader"
|
|
|
|
const DEFAULT_TITLE_SETTINGS: TitleSettings = {
|
|
aiAutoSelect: false,
|
|
title: "",
|
|
position: "bottom",
|
|
font: "思源黑体",
|
|
size: 28,
|
|
bold: true,
|
|
italic: false,
|
|
stroke: true,
|
|
shadow: false,
|
|
color: "#ffffff",
|
|
}
|
|
|
|
export interface GenerateFormState {
|
|
/* 步骤 */
|
|
currentStep: number
|
|
setCurrentStep: (step: number | ((prev: number) => number)) => void
|
|
|
|
/* 模板 */
|
|
selectedTemplate: string
|
|
setSelectedTemplate: (id: string) => void
|
|
userTemplates: EditingTemplate[]
|
|
|
|
/* 素材 */
|
|
selectedMaterials: string[]
|
|
setSelectedMaterials: (ids: string[]) => void
|
|
materialMode: "manual" | "auto"
|
|
setMaterialMode: (mode: "manual" | "auto") => void
|
|
smartSelectedIds: string[]
|
|
setSmartSelectedIds: (ids: string[]) => void
|
|
|
|
/* 标题 */
|
|
titleSettings: TitleSettings
|
|
setTitleSettings: (settings: TitleSettings | ((prev: TitleSettings) => TitleSettings)) => void
|
|
|
|
/* 封面 */
|
|
coverSettings: CoverConfig
|
|
setCoverSettings: (settings: CoverConfig | ((prev: CoverConfig) => CoverConfig)) => void
|
|
|
|
/* 配音 */
|
|
selectedVoice: string
|
|
setSelectedVoice: (id: string) => void
|
|
voiceMode: "preset" | "custom" | "clone"
|
|
setVoiceMode: (mode: "preset" | "custom" | "clone") => void
|
|
selectedClonedVoice: string
|
|
setSelectedClonedVoice: (id: string) => void
|
|
presetVoices: PresetVoiceItem[]
|
|
|
|
/* 克隆弹窗 */
|
|
cloneModalOpen: boolean
|
|
setCloneModalOpen: (open: boolean) => void
|
|
|
|
/* 生成数量 */
|
|
generateCount: number
|
|
setGenerateCount: (n: number) => void
|
|
|
|
/* 高级设置 */
|
|
videoRatio: string
|
|
duration: number
|
|
style: string
|
|
autoSubtitles: boolean
|
|
bgm: boolean
|
|
|
|
/* URL 参数 */
|
|
editPlanId: string | null
|
|
planConfigStr: string | null
|
|
|
|
/* 预览弹窗 */
|
|
previewVideo: GeneratedVideo | null
|
|
setPreviewVideo: (v: GeneratedVideo | null) => void
|
|
previewModalOpen: boolean
|
|
setPreviewModalOpen: (open: boolean) => void
|
|
}
|
|
|
|
export const useGenerateFormState = (): GenerateFormState => {
|
|
const [searchParams] = useSearchParams()
|
|
const editPlanId = searchParams.get("edit_plan_id")
|
|
const planConfigStr = searchParams.get("plan_config")
|
|
|
|
/* ── 步骤状态 ── */
|
|
const [currentStep, setCurrentStep] = useState(1)
|
|
|
|
/* ── 模板选择 ── */
|
|
const { selectedTemplate, setSelectedTemplate, userTemplates } = useTemplateSelection()
|
|
|
|
/* ── 素材 ── */
|
|
const [selectedMaterials, setSelectedMaterials] = useState<string[]>([])
|
|
const [materialMode, setMaterialMode] = useState<"manual" | "auto">("manual")
|
|
const [smartSelectedIds, setSmartSelectedIds] = useState<string[]>([])
|
|
|
|
/* ── 标题设置 ── */
|
|
const [titleSettings, setTitleSettings] = useState<TitleSettings>(DEFAULT_TITLE_SETTINGS)
|
|
|
|
/* ── 封面设置 ── */
|
|
const [coverSettings, setCoverSettings] = useState<CoverConfig>(DEFAULT_COVER_SETTINGS)
|
|
|
|
/* ── 模板切换时同步标题/封面 ── */
|
|
useTitleCoverSync({
|
|
selectedTemplate,
|
|
userTemplates,
|
|
setTitleSettings,
|
|
setCoverSettings,
|
|
})
|
|
|
|
/* ── 配音状态 ── */
|
|
const {
|
|
selectedVoice,
|
|
setSelectedVoice,
|
|
voiceMode,
|
|
setVoiceMode,
|
|
selectedClonedVoice,
|
|
setSelectedClonedVoice,
|
|
presetVoices,
|
|
} = useVoiceState()
|
|
|
|
/* ── 克隆声音弹窗 ── */
|
|
const [cloneModalOpen, setCloneModalOpen] = useState(false)
|
|
|
|
/* ── 生成数量 ── */
|
|
const [generateCount, setGenerateCount] = useState(1)
|
|
|
|
/* ── 高级设置(隐藏但保留) ── */
|
|
const [videoRatio] = useState("9:16")
|
|
const [duration] = useState(30)
|
|
const [style] = useState("business")
|
|
const [autoSubtitles] = useState(true)
|
|
const [bgm] = useState(true)
|
|
|
|
/* ── 预览弹窗 ── */
|
|
const [previewVideo, setPreviewVideo] = useState<GeneratedVideo | null>(null)
|
|
const [previewModalOpen, setPreviewModalOpen] = useState(false)
|
|
|
|
/* ── 从 URL / 编辑计划加载配置 ── */
|
|
usePlanConfigLoader({
|
|
editPlanId,
|
|
planConfigStr,
|
|
setTitleSettings,
|
|
setCoverSettings,
|
|
setSelectedMaterials,
|
|
})
|
|
|
|
return {
|
|
currentStep,
|
|
setCurrentStep,
|
|
selectedTemplate,
|
|
setSelectedTemplate,
|
|
userTemplates,
|
|
selectedMaterials,
|
|
setSelectedMaterials,
|
|
materialMode,
|
|
setMaterialMode,
|
|
smartSelectedIds,
|
|
setSmartSelectedIds,
|
|
titleSettings,
|
|
setTitleSettings,
|
|
coverSettings,
|
|
setCoverSettings,
|
|
selectedVoice,
|
|
setSelectedVoice,
|
|
voiceMode,
|
|
setVoiceMode,
|
|
selectedClonedVoice,
|
|
setSelectedClonedVoice,
|
|
presetVoices,
|
|
cloneModalOpen,
|
|
setCloneModalOpen,
|
|
generateCount,
|
|
setGenerateCount,
|
|
videoRatio,
|
|
duration,
|
|
style,
|
|
autoSubtitles,
|
|
bgm,
|
|
editPlanId,
|
|
planConfigStr,
|
|
previewVideo,
|
|
setPreviewVideo,
|
|
previewModalOpen,
|
|
setPreviewModalOpen,
|
|
}
|
|
}
|