refactor: delete EditingPlanner.tsx (#1899 #1900)

This commit is contained in:
2026-09-14 20:43:22 +08:00
parent 09f1189d65
commit eb5aef7890
@@ -1,326 +0,0 @@
/**
* 模板编辑器 — 制作/编辑剪辑模板
* 四行布局:顶栏(42px) → 模式栏(48px) → 三栏主体 → 底栏(40px)
*
* 主组件仅保留 Hook 组装与整体布局
* 全局配置 → hooks/useGlobalSettings
* 配音素材 → hooks/useVoiceMaterials
* 撤销重做 → hooks/useUndoRedo
* 抽屉管理 → hooks/useEditorDrawers
* 播放控制 → hooks/usePlaybackControl
* 片段操作 → hooks/useClipOperations
* 模板管理 → hooks/useTemplateManagement
*/
import React, { useState } from "react"
import { useSearchParams } from "react-router-dom"
import { MODE_LABELS } from "@/api/editing-planner"
import { MODE_LIST } from "./constants"
import MediaPanel from "./components/MediaPanel"
import PreviewPlayer from "./components/PreviewPlayer"
import TimelinePanel from "./components/TimelinePanel"
import TopBar from "./components/TopBar"
import ModeBar from "./components/ModeBar"
import RightPanel from "./components/RightPanel"
import StatusBar from "./components/StatusBar"
import EditorDrawers from "./components/EditorDrawers"
import SaveModal from "./components/SaveModal"
import { useUndoRedo } from "./hooks/useUndoRedo"
import { useEditorDrawers } from "./hooks/useEditorDrawers"
import { usePlaybackControl } from "./hooks/usePlaybackControl"
import { useClipOperations } from "./hooks/useClipOperations"
import { useTemplateManagement, FILTER_CATEGORIES } from "./hooks/useTemplateManagement"
import { useGlobalSettings } from "./hooks/useGlobalSettings"
import { useVoiceMaterials } from "./hooks/useVoiceMaterials"
import type { ClipData } from "./types"
import "./EditingPlanner.css"
const EditingPlanner: React.FC = () => {
const [searchParams] = useSearchParams()
const urlTemplateId = searchParams.get("templateId") || ""
const urlPlanId = searchParams.get("planId") || ""
/* ── 片段(撤销/重做) ── */
const {
state: clips,
set: setClips,
undo,
redo,
canUndo,
canRedo,
reset: resetClips,
} = useUndoRedo<ClipData[]>([])
/* ── 全局配置 ── */
const {
titleConfig,
setTitleConfig,
subtitleSettings,
setSubtitleSettings,
bgmSettings,
setBgmSettings,
watermarkSettings,
setWatermarkSettings,
introOutroSettings,
setIntroOutroSettings,
pipSettings,
setPipSettings,
filterSettings,
setFilterSettings,
chromaKeySettings,
setChromaKeySettings,
stickerSettings,
setStickerSettings,
} = useGlobalSettings()
/* ── 右侧栏 Tab ── */
const [rightTab, setRightTab] = useState<"properties" | "clips">("properties")
/* ── 配音素材 ── */
const {
voiceMaterials,
loading: voiceMaterialsLoading,
refetch: refetchVoiceMaterials,
} = useVoiceMaterials()
/* ── 派生计算 ── */
const totalDuration = clips.reduce((sum, c) => sum + c.duration, 0)
/* ── Hook: 抽屉管理 ── */
const drawers = useEditorDrawers()
/* ── Hook: 播放控制 ── */
const playback = usePlaybackControl(totalDuration)
/* ── Hook: 片段操作 ── */
const clipOps = useClipOperations({ clips, setClips })
/* ── Hook: 模板管理 ── */
const tpl = useTemplateManagement({
urlTemplateId,
urlPlanId,
resetClips,
setClips,
setSelectedClipId: clipOps.setSelectedClipId,
setTitleConfig,
setSubtitleSettings,
setBgmSettings,
clips,
totalDuration,
titleConfig,
subtitleSettings,
bgmSettings,
watermarkSettings,
introOutroSettings,
pipSettings,
filterSettings,
chromaKeySettings,
stickerSettings,
})
/* ──────────── 渲染 ──────────── */
return (
<div className="ep-v8-root">
{/* ═══ 第1行:顶栏 42px ═══ */}
<TopBar
currentTemplate={tpl.currentTemplate}
canUndo={canUndo}
canRedo={canRedo}
onUndo={undo}
onRedo={redo}
onOpenSaveModal={tpl.handleOpenSaveModal}
/>
{/* ═══ 第2行:模式栏 56px ═══ */}
<ModeBar
modeList={MODE_LIST}
currentMode={tpl.currentMode}
onModeChange={tpl.handleModeChange}
/>
{/* ═══ 第3行:三栏主体 ═══ */}
<div className="ep-main-body">
{/* 左栏 220px:模板列表 */}
<MediaPanel
templates={tpl.filteredTemplates}
loading={tpl.loadingTemplates}
searchQuery={tpl.searchQuery}
currentFilter={tpl.currentFilter}
filterCategories={FILTER_CATEGORIES}
loadedTemplateId={tpl.loadedTemplateId}
onLoadTemplate={tpl.handleLoadTemplate}
onSearchChange={tpl.setSearchQuery}
onFilterChange={tpl.setCurrentFilter}
/>
{/* 中栏 flex-1 */}
<div className="ep-center-col">
{/* 上半部:视频预览 + 封面预览 */}
<PreviewPlayer
clips={clips}
selectedClipId={clipOps.selectedClipId}
isPlaying={playback.isPlaying}
titleConfig={titleConfig}
subtitleSettings={{
enabled: subtitleSettings.enabled,
position: subtitleSettings.position,
font: subtitleSettings.font,
size: subtitleSettings.fontSize,
animation: subtitleSettings.animation,
}}
onClipSelect={clipOps.handleClipSelect}
onPlayPause={() => playback.setIsPlaying(!playback.isPlaying)}
/>
{/* 下半部:水平时间线 */}
<TimelinePanel
clips={clips}
selectedClipId={clipOps.selectedClipId}
currentMode={tpl.currentMode}
onClipSelect={clipOps.handleClipSelect}
onClipReorder={clipOps.handleClipReorder}
onClipRemove={clipOps.handleClipRemove}
onAddClip={clipOps.handleAddClip}
onClipTrim={clipOps.handleClipTrim}
onClipSplit={clipOps.handleClipSplit}
onClipResetTrim={clipOps.handleClipResetTrim}
currentTime={playback.currentTime}
pixelsPerSecond={playback.pixelsPerSecond}
onZoomChange={playback.handleZoomChange}
onSeek={playback.handleSeek}
totalDuration={totalDuration}
/>
</div>
{/* 右栏 260px:设置面板 */}
<RightPanel
titleConfig={titleConfig}
onTitleConfigChange={setTitleConfig}
rightTab={rightTab}
onTabChange={setRightTab}
selectedClip={clipOps.selectedClip}
subtitleSettings={subtitleSettings}
bgmSettings={bgmSettings}
clipsCount={clips.length}
totalDuration={totalDuration}
currentMode={tpl.currentMode}
onSubtitleSettingsChange={(partial) =>
setSubtitleSettings((prev) => ({ ...prev, ...partial }))
}
onBgmSettingsChange={(partial) => setBgmSettings((prev) => ({ ...prev, ...partial }))}
onClipUpdate={clipOps.handleClipUpdate}
onOpenBgmDrawer={() => drawers.setBgmDrawerOpen(true)}
onOpenSubtitleDrawer={() => drawers.setSubtitleDrawerOpen(true)}
voiceMaterials={voiceMaterials}
voiceMaterialsLoading={voiceMaterialsLoading}
onRefreshVoiceMaterials={refetchVoiceMaterials}
onClipVoiceSelect={clipOps.handleClipVoiceSelect}
onOpenTransitionDrawer={drawers.openTransitionDrawer}
onOpenSpeedDrawer={drawers.openSpeedDrawer}
onOpenTtsDrawer={drawers.openTtsDrawer}
onOpenWatermarkDrawer={() => drawers.setWatermarkDrawerOpen(true)}
onOpenIntroOutroDrawer={() => drawers.setIntroOutroDrawerOpen(true)}
onOpenPipDrawer={() => drawers.setPipDrawerOpen(true)}
onOpenFilterDrawer={() => drawers.setFilterDrawerOpen(true)}
onOpenGreenScreenDrawer={() => drawers.setChromaKeyDrawerOpen(true)}
onOpenStickerDrawer={() => drawers.setStickerDrawerOpen(true)}
clips={clips}
selectedClipId={clipOps.selectedClipId}
onClipSelect={clipOps.handleClipSelect}
onClipMoveUp={(clipId) => {
const idx = clips.findIndex((c) => c.id === clipId)
if (idx > 0) clipOps.handleClipReorder(idx, idx - 1)
}}
onClipMoveDown={(clipId) => {
const idx = clips.findIndex((c) => c.id === clipId)
if (idx < clips.length - 1) clipOps.handleClipReorder(idx, idx + 1)
}}
onClipRemove={clipOps.handleClipRemove}
onClipAdd={() => clipOps.handleAddClip("pip", 3)}
/>
</div>
{/* ═══ 第4行:底栏 40px ═══ */}
<StatusBar
clipsCount={clips.length}
totalDuration={totalDuration}
currentModeLabel={MODE_LABELS[tpl.currentMode]}
templateSegments={tpl.currentTemplate?.segments.length || 0}
/>
{/* ═══ 弹窗 ═══ */}
<SaveModal
open={tpl.saveModalOpen}
loading={tpl.saveLoading}
isUpdate={!!tpl.loadedTemplateId}
draftName={tpl.draftName}
draftCategory={tpl.draftCategory}
draftTags={tpl.draftTags}
categories={tpl.categories}
estimatedDuration={totalDuration}
onNameChange={tpl.setDraftName}
onCategoryChange={tpl.setDraftCategory}
onTagsChange={tpl.setDraftTags}
onSave={tpl.handleSave}
onCancel={() => tpl.setSaveModalOpen(false)}
/>
{/* ═══ Drawer 集合 ═══ */}
<EditorDrawers
bgmDrawerOpen={drawers.bgmDrawerOpen}
bgmSettings={bgmSettings}
onBgmSettingsChange={setBgmSettings}
onCloseBgmDrawer={() => drawers.setBgmDrawerOpen(false)}
subtitleDrawerOpen={drawers.subtitleDrawerOpen}
subtitleSettings={subtitleSettings}
onSubtitleSettingsChange={setSubtitleSettings}
onCloseSubtitleDrawer={() => drawers.setSubtitleDrawerOpen(false)}
transitionDrawerOpen={drawers.transitionDrawerOpen}
transitionTargetClipId={drawers.transitionTargetClipId}
clips={clips}
onTransitionChange={(config) =>
clipOps.handleTransitionChange(drawers.transitionTargetClipId, config)
}
onCloseTransitionDrawer={() => drawers.setTransitionDrawerOpen(false)}
speedDrawerOpen={drawers.speedDrawerOpen}
speedTargetClipId={drawers.speedTargetClipId}
onSpeedChange={(config) => clipOps.handleSpeedChange(drawers.speedTargetClipId, config)}
onApplySpeedAll={clipOps.handleApplySpeedAll}
onCloseSpeedDrawer={() => drawers.setSpeedDrawerOpen(false)}
ttsDrawerOpen={drawers.ttsDrawerOpen}
ttsTargetClipId={drawers.ttsTargetClipId}
onTtsChange={(config) => clipOps.handleTtsChange(drawers.ttsTargetClipId, config)}
onCloseTtsDrawer={() => drawers.setTtsDrawerOpen(false)}
watermarkDrawerOpen={drawers.watermarkDrawerOpen}
watermarkSettings={watermarkSettings}
onWatermarkChange={setWatermarkSettings}
onCloseWatermarkDrawer={() => drawers.setWatermarkDrawerOpen(false)}
introOutroDrawerOpen={drawers.introOutroDrawerOpen}
introOutroSettings={introOutroSettings}
onIntroOutroChange={setIntroOutroSettings}
onCloseIntroOutroDrawer={() => drawers.setIntroOutroDrawerOpen(false)}
pipDrawerOpen={drawers.pipDrawerOpen}
pipSettings={pipSettings}
totalDuration={totalDuration}
onPipChange={setPipSettings}
onClosePipDrawer={() => drawers.setPipDrawerOpen(false)}
filterDrawerOpen={drawers.filterDrawerOpen}
filterSettings={filterSettings}
onFilterChange={setFilterSettings}
onCloseFilterDrawer={() => drawers.setFilterDrawerOpen(false)}
chromaKeyDrawerOpen={drawers.chromaKeyDrawerOpen}
chromaKeySettings={chromaKeySettings}
onChromaKeyChange={setChromaKeySettings}
onCloseChromaKeyDrawer={() => drawers.setChromaKeyDrawerOpen(false)}
stickerDrawerOpen={drawers.stickerDrawerOpen}
stickerSettings={stickerSettings}
onStickerChange={setStickerSettings}
onCloseStickerDrawer={() => drawers.setStickerDrawerOpen(false)}
/>
</div>
)
}
export default EditingPlanner