From 27c1f05f74cff8922b62805e54c20fba9b96e84f Mon Sep 17 00:00:00 2001 From: SaaS Frontend Date: Sun, 26 Jul 2026 00:22:38 +0800 Subject: [PATCH 1/2] refactor(editing-planner): Phase 1 - extract constants and selectors --- .../pages/editing-planner/EditingPlanner.tsx | 30 +++++-------- .../src/pages/editing-planner/constants.ts | 12 ++++++ .../pages/editing-planner/utils/selectors.ts | 42 +++++++++++++++++++ .../test/pages/editing-planner/smoke.test.tsx | 6 +++ 4 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 apps/web/src/pages/editing-planner/constants.ts create mode 100644 apps/web/src/pages/editing-planner/utils/selectors.ts mode change 100644 => 100755 apps/web/src/test/pages/editing-planner/smoke.test.tsx diff --git a/apps/web/src/pages/editing-planner/EditingPlanner.tsx b/apps/web/src/pages/editing-planner/EditingPlanner.tsx index a1ba02c91..1ba623099 100755 --- a/apps/web/src/pages/editing-planner/EditingPlanner.tsx +++ b/apps/web/src/pages/editing-planner/EditingPlanner.tsx @@ -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, currentMode, currentFilter, searchQuery) /* ──────────── 事件 ──────────── */ diff --git a/apps/web/src/pages/editing-planner/constants.ts b/apps/web/src/pages/editing-planner/constants.ts new file mode 100644 index 000000000..bdba18cc4 --- /dev/null +++ b/apps/web/src/pages/editing-planner/constants.ts @@ -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 = ["全部", "种草", "知识", "日常", "推荐"] diff --git a/apps/web/src/pages/editing-planner/utils/selectors.ts b/apps/web/src/pages/editing-planner/utils/selectors.ts new file mode 100644 index 000000000..30235f1b1 --- /dev/null +++ b/apps/web/src/pages/editing-planner/utils/selectors.ts @@ -0,0 +1,42 @@ +import type { EditingTemplate, TemplateMode } 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[], + currentMode: TemplateMode, + 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 +} diff --git a/apps/web/src/test/pages/editing-planner/smoke.test.tsx b/apps/web/src/test/pages/editing-planner/smoke.test.tsx old mode 100644 new mode 100755 index 9e3cdbdcc..f4f1f990b --- a/apps/web/src/test/pages/editing-planner/smoke.test.tsx +++ b/apps/web/src/test/pages/editing-planner/smoke.test.tsx @@ -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" -- 2.54.0 From e8f7788e56e7ac68afb951b6fd4f082f03582a56 Mon Sep 17 00:00:00 2001 From: SaaS Frontend Date: Sun, 26 Jul 2026 00:55:26 +0800 Subject: [PATCH 2/2] fix: remove unused currentMode param in getFilteredTemplates --- apps/web/src/pages/editing-planner/EditingPlanner.tsx | 2 +- apps/web/src/pages/editing-planner/utils/selectors.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/web/src/pages/editing-planner/EditingPlanner.tsx b/apps/web/src/pages/editing-planner/EditingPlanner.tsx index 1ba623099..aca676760 100755 --- a/apps/web/src/pages/editing-planner/EditingPlanner.tsx +++ b/apps/web/src/pages/editing-planner/EditingPlanner.tsx @@ -474,7 +474,7 @@ const EditingPlanner: React.FC = () => { } }, [isPlaying, totalDuration]) - const filteredTemplates = getFilteredTemplates(templates, currentMode, currentFilter, searchQuery) + const filteredTemplates = getFilteredTemplates(templates, currentFilter, searchQuery) /* ──────────── 事件 ──────────── */ diff --git a/apps/web/src/pages/editing-planner/utils/selectors.ts b/apps/web/src/pages/editing-planner/utils/selectors.ts index 30235f1b1..06c72f598 100644 --- a/apps/web/src/pages/editing-planner/utils/selectors.ts +++ b/apps/web/src/pages/editing-planner/utils/selectors.ts @@ -1,4 +1,4 @@ -import type { EditingTemplate, TemplateMode } from "@/api/editing-planner" +import type { EditingTemplate } from "@/api/editing-planner" import type { ClipData } from "../types" /** @@ -19,11 +19,10 @@ export function getCurrentTemplate( } /** - * 根据模式、分类和搜索词筛选模板 + * 根据分类和搜索词筛选模板 */ export function getFilteredTemplates( templates: EditingTemplate[], - currentMode: TemplateMode, currentFilter: string, searchQuery: string, ): EditingTemplate[] { -- 2.54.0