887e66b0f9
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m26s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m28s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m16s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m17s
CI/CD Pipeline / Build Staging Web Image (push) Failing after 3m18s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m20s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m4s
CI/CD Pipeline / Unit Tests (push) Failing after 8m0s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 3m15s
CI/CD Pipeline / CI Gate (push) Has been skipped
200 lines
4.8 KiB
TypeScript
200 lines
4.8 KiB
TypeScript
import { useState, useCallback, type Dispatch, type SetStateAction } from "react"
|
|
import type { TemplateMode } from "@/api/editing-planner"
|
|
import type { MediaAsset, TitleConfig } from "@/api/template-editor"
|
|
import type {
|
|
ClipData,
|
|
WatermarkConfig,
|
|
IntroOutroConfig,
|
|
PipConfig,
|
|
FilterConfig,
|
|
ChromaKeyConfig,
|
|
StickerConfig,
|
|
} from "../types"
|
|
import type { SubtitleStyleConfig } from "../types/subtitle"
|
|
import type { BgmMixConfig } from "@/api/bgm"
|
|
import { useTemplateList } from "./template-management/useTemplateList"
|
|
import { useTemplateDetail } from "./template-management/useTemplateDetail"
|
|
import { usePlanLoading } from "./template-management/usePlanLoading"
|
|
import { useTemplateSave } from "./template-management/useTemplateSave"
|
|
import { FILTER_CATEGORIES } from "../constants"
|
|
|
|
interface UseTemplateManagementParams {
|
|
urlTemplateId: string
|
|
urlPlanId: string
|
|
resetClips: (clips: ClipData[]) => void
|
|
setClips: (updater: (prev: ClipData[]) => ClipData[]) => void
|
|
setSelectedClipId: (id: string | null) => void
|
|
setMediaAssets: (assets: MediaAsset[]) => void
|
|
setTitleConfig: Dispatch<SetStateAction<TitleConfig>>
|
|
setSubtitleSettings: Dispatch<SetStateAction<SubtitleStyleConfig>>
|
|
setBgmSettings: Dispatch<SetStateAction<BgmMixConfig>>
|
|
clips: ClipData[]
|
|
totalDuration: number
|
|
titleConfig: TitleConfig
|
|
subtitleSettings: SubtitleStyleConfig
|
|
bgmSettings: BgmMixConfig
|
|
watermarkSettings: WatermarkConfig
|
|
introOutroSettings: IntroOutroConfig
|
|
pipSettings: PipConfig
|
|
filterSettings: FilterConfig
|
|
chromaKeySettings: ChromaKeyConfig
|
|
stickerSettings: StickerConfig
|
|
}
|
|
|
|
/**
|
|
* 模板管理 Hook
|
|
* 模板列表/分类/加载/保存/模式切换/筛选搜索
|
|
*/
|
|
export const useTemplateManagement = (params: UseTemplateManagementParams) => {
|
|
const {
|
|
urlTemplateId,
|
|
urlPlanId,
|
|
resetClips,
|
|
setClips,
|
|
setSelectedClipId,
|
|
setMediaAssets,
|
|
setTitleConfig,
|
|
setSubtitleSettings,
|
|
setBgmSettings,
|
|
clips,
|
|
totalDuration,
|
|
titleConfig,
|
|
subtitleSettings,
|
|
bgmSettings,
|
|
watermarkSettings,
|
|
introOutroSettings,
|
|
pipSettings,
|
|
filterSettings,
|
|
chromaKeySettings,
|
|
stickerSettings,
|
|
} = params
|
|
|
|
const [currentMode, setCurrentMode] = useState<TemplateMode>("pip")
|
|
const [loadedPlanId] = useState<string | null>(urlPlanId || null)
|
|
|
|
/* ── 模板列表 ── */
|
|
const {
|
|
templates,
|
|
categories,
|
|
loadingTemplates,
|
|
loadedTemplateId,
|
|
setLoadedTemplateId,
|
|
currentFilter,
|
|
setCurrentFilter,
|
|
searchQuery,
|
|
setSearchQuery,
|
|
filteredTemplates,
|
|
currentTemplate,
|
|
loadTemplates,
|
|
} = useTemplateList(setMediaAssets, urlTemplateId || null)
|
|
|
|
/* ── 保存 ── */
|
|
const {
|
|
saveModalOpen,
|
|
setSaveModalOpen,
|
|
draftName,
|
|
setDraftName,
|
|
draftCategory,
|
|
setDraftCategory,
|
|
draftTags,
|
|
setDraftTags,
|
|
saveLoading,
|
|
handleOpenSaveModal,
|
|
handleSave,
|
|
} = useTemplateSave({
|
|
currentMode,
|
|
clips,
|
|
totalDuration,
|
|
titleConfig,
|
|
subtitleSettings,
|
|
bgmSettings,
|
|
watermarkSettings,
|
|
introOutroSettings,
|
|
pipSettings,
|
|
filterSettings,
|
|
chromaKeySettings,
|
|
stickerSettings,
|
|
loadedTemplateId,
|
|
loadTemplates,
|
|
})
|
|
|
|
/* ── 模板详情加载 ── */
|
|
useTemplateDetail({
|
|
loadedTemplateId,
|
|
resetClips,
|
|
setCurrentMode,
|
|
setTitleConfig,
|
|
setSubtitleSettings,
|
|
setBgmSettings,
|
|
setDraftName,
|
|
setDraftCategory,
|
|
setDraftTags,
|
|
})
|
|
|
|
/* ── 计划草稿加载 ── */
|
|
usePlanLoading({
|
|
loadedPlanId,
|
|
resetClips,
|
|
setLoadedTemplateId,
|
|
setDraftName,
|
|
setTitleConfig,
|
|
setSubtitleSettings,
|
|
setBgmSettings,
|
|
})
|
|
|
|
/* ── 事件 ── */
|
|
const handleLoadTemplate = useCallback(
|
|
(templateId: string) => {
|
|
setLoadedTemplateId(templateId)
|
|
setSelectedClipId(null)
|
|
},
|
|
[setLoadedTemplateId, setSelectedClipId],
|
|
)
|
|
|
|
const handleModeChange = useCallback(
|
|
(mode: TemplateMode) => {
|
|
setCurrentMode(mode)
|
|
if (mode === "voice_over") {
|
|
setClips((prev) => prev.map((c) => ({ ...c, type: "voice" as const })))
|
|
} else if (mode === "pip") {
|
|
setClips((prev) => prev.map((c) => ({ ...c, type: "pip" as const })))
|
|
}
|
|
},
|
|
[setClips],
|
|
)
|
|
|
|
return {
|
|
// state
|
|
templates,
|
|
categories,
|
|
loadingTemplates,
|
|
loadedTemplateId,
|
|
setLoadedTemplateId,
|
|
currentMode,
|
|
setCurrentMode,
|
|
currentFilter,
|
|
setCurrentFilter,
|
|
searchQuery,
|
|
setSearchQuery,
|
|
saveModalOpen,
|
|
setSaveModalOpen,
|
|
draftName,
|
|
setDraftName,
|
|
draftCategory,
|
|
setDraftCategory,
|
|
draftTags,
|
|
setDraftTags,
|
|
saveLoading,
|
|
filteredTemplates,
|
|
currentTemplate,
|
|
// methods
|
|
loadTemplates,
|
|
handleLoadTemplate,
|
|
handleModeChange,
|
|
handleOpenSaveModal,
|
|
handleSave,
|
|
}
|
|
}
|
|
|
|
export { FILTER_CATEGORIES }
|