refactor(editing-planner): Phase 1 - extract constants and selectors #900

Merged
xiaoxia merged 2 commits from refactor/editing-planner-phase1 into develop 2026-07-26 03:34:12 +08:00
4 changed files with 70 additions and 19 deletions
@@ -63,19 +63,15 @@ import SaveModal from "./components/SaveModal"
import type { SubtitleStyleConfig } from "./types/subtitle"
import { DEFAULT_SUBTITLE_STYLE } from "./types/subtitle"
import { DEFAULT_BGM_MIX_CONFIG, type BgmMixConfig } from "@/api/bgm"
import { MODE_LIST, FILTER_CATEGORIES } from "./constants"
import {
calculateTotalDuration,
getCurrentTemplate,
getFilteredTemplates,
getSelectedClip,
} from "./utils/selectors"
import "./EditingPlanner.css"
/* ──────────── 常量 ──────────── */
const MODE_LIST: { key: TemplateMode; label: string; icon: string }[] = [
{ key: "pip", label: "混剪", icon: "🖼️" },
{ key: "voice_over", label: "人物口播", icon: "🎙️" },
{ key: "one_take", label: "一镜到底", icon: "🎥" },
{ key: "voice_pip", label: "口播+混剪", icon: "🎭" },
]
const FILTER_CATEGORIES = ["全部", "种草", "知识", "日常", "推荐"]
/* ──────────── 组件 ──────────── */
const EditingPlanner: React.FC = () => {
@@ -449,9 +445,9 @@ const EditingPlanner: React.FC = () => {
/* ──────────── 计算 ──────────── */
const currentTemplate = templates.find((t) => t.id === loadedTemplateId)
const totalDuration = clips.reduce((sum, c) => sum + c.duration, 0)
const selectedClip = clips.find((c) => c.id === selectedClipId) || null
const currentTemplate = getCurrentTemplate(templates, loadedTemplateId)
const totalDuration = calculateTotalDuration(clips)
const selectedClip = getSelectedClip(clips, selectedClipId)
/* rAF 帧推进 — 播放时平滑更新播放头位置 */
useEffect(() => {
@@ -478,11 +474,7 @@ const EditingPlanner: React.FC = () => {
}
}, [isPlaying, totalDuration])
const filteredTemplates = templates.filter((t) => {
if (currentFilter !== "全部" && t.category !== currentFilter) return false
if (searchQuery && !t.name.toLowerCase().includes(searchQuery.toLowerCase())) return false
return true
})
const filteredTemplates = getFilteredTemplates(templates, currentFilter, searchQuery)
/* ──────────── 事件 ──────────── */
@@ -0,0 +1,12 @@
import type { TemplateMode } from "@/api/editing-planner"
/* ──────────── 常量 ──────────── */
export const MODE_LIST: { key: TemplateMode; label: string; icon: string }[] = [
{ key: "pip", label: "混剪", icon: "🖼️" },
{ key: "voice_over", label: "人物口播", icon: "🎙️" },
{ key: "one_take", label: "一镜到底", icon: "🎥" },
{ key: "voice_pip", label: "口播+混剪", icon: "🎭" },
]
export const FILTER_CATEGORIES = ["全部", "种草", "知识", "日常", "推荐"]
@@ -0,0 +1,41 @@
import type { EditingTemplate } from "@/api/editing-planner"
import type { ClipData } from "../types"
/**
* 计算所有片段的总时长
*/
export function calculateTotalDuration(clips: ClipData[]): number {
return clips.reduce((sum, c) => sum + c.duration, 0)
}
/**
* 获取当前选中的模板
*/
export function getCurrentTemplate(
templates: EditingTemplate[],
loadedTemplateId: string | null,
): EditingTemplate | undefined {
return templates.find((t) => t.id === loadedTemplateId)
}
/**
* 根据分类和搜索词筛选模板
*/
export function getFilteredTemplates(
templates: EditingTemplate[],
currentFilter: string,
searchQuery: string,
): EditingTemplate[] {
return templates.filter((t) => {
if (currentFilter !== "全部" && t.category !== currentFilter) return false
if (searchQuery && !t.name.toLowerCase().includes(searchQuery.toLowerCase())) return false
return true
})
}
/**
* 获取当前选中的片段
*/
export function getSelectedClip(clips: ClipData[], selectedClipId: string | null): ClipData | null {
return clips.find((c) => c.id === selectedClipId) || null
}
+6
View File
@@ -8,6 +8,12 @@ import { describe, it, expect } from "vitest"
// 主组件
import "@/pages/editing-planner/EditingPlanner"
// 常量
import "@/pages/editing-planner/constants"
// 工具函数
import "@/pages/editing-planner/utils/selectors"
// 子组件
import "@/pages/editing-planner/components/BgmSelector"
import "@/pages/editing-planner/components/ClipPropertiesPanel"