From 8acae70bd752d774b6ce43f4abd806e31fcc9b66 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Tue, 28 Jul 2026 10:10:26 +0800 Subject: [PATCH 1/2] =?UTF-8?q?refactor(templates):=20=E6=8B=86=E5=88=86?= =?UTF-8?q?=20TemplateDetailModal=20=E4=B8=BA=E5=AD=90=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 三阶段重构: - Phase 1: 提取类型到 template-detail-modal/types.ts - Phase 2: 拆分为 4 个 UI 子组件 - PreviewArea: 预览区 - SegmentList: 素材规则/片段列表 - StyleConfig: 样式配置网格 - DetailFooter: 底部操作区(收藏+按钮) - Phase 3: 主文件 219→106 行(-52%) 保持导入路径向后兼容 --- .../template-library/TemplateDetailModal.tsx | 151 +++--------------- .../template-detail-modal/DetailFooter.tsx | 46 ++++++ .../template-detail-modal/PreviewArea.tsx | 39 +++++ .../template-detail-modal/SegmentList.tsx | 53 ++++++ .../template-detail-modal/StyleConfig.tsx | 33 ++++ .../template-detail-modal/index.ts | 6 + .../template-detail-modal/types.ts | 10 ++ .../src/test/pages/TemplateLibrary.test.tsx | 5 + 8 files changed, 211 insertions(+), 132 deletions(-) mode change 100644 => 100755 apps/web/src/pages/templates/components/template-library/TemplateDetailModal.tsx create mode 100755 apps/web/src/pages/templates/components/template-library/template-detail-modal/DetailFooter.tsx create mode 100755 apps/web/src/pages/templates/components/template-library/template-detail-modal/PreviewArea.tsx create mode 100755 apps/web/src/pages/templates/components/template-library/template-detail-modal/SegmentList.tsx create mode 100755 apps/web/src/pages/templates/components/template-library/template-detail-modal/StyleConfig.tsx create mode 100755 apps/web/src/pages/templates/components/template-library/template-detail-modal/index.ts create mode 100755 apps/web/src/pages/templates/components/template-library/template-detail-modal/types.ts mode change 100644 => 100755 apps/web/src/test/pages/TemplateLibrary.test.tsx diff --git a/apps/web/src/pages/templates/components/template-library/TemplateDetailModal.tsx b/apps/web/src/pages/templates/components/template-library/TemplateDetailModal.tsx old mode 100644 new mode 100755 index 3856607ff..1b59f3b9c --- a/apps/web/src/pages/templates/components/template-library/TemplateDetailModal.tsx +++ b/apps/web/src/pages/templates/components/template-library/TemplateDetailModal.tsx @@ -1,25 +1,16 @@ import React from "react" -import { Button, Descriptions, Tooltip } from "antd" -import { CopyOutlined, ThunderboltOutlined } from "@ant-design/icons" -import type { TemplateItem, TemplateSegment } from "@/api/templates" +import { Descriptions } from "antd" +import type { TemplateDetailModalProps } from "./template-detail-modal/types" +import PreviewArea from "./template-detail-modal/PreviewArea" +import SegmentList from "./template-detail-modal/SegmentList" +import StyleConfig from "./template-detail-modal/StyleConfig" +import DetailFooter from "./template-detail-modal/DetailFooter" import { - gradientForCategory, getTypeColor, formatDuration, - formatConfig, - getMaterialTypeLabel, - calcTotalSegmentDuration, } from "../../utils/templateLibrary" import { TEMPLATE_TYPES } from "../../constants/templateLibrary" - -interface TemplateDetailModalProps { - template: TemplateItem - isFavorite: boolean - onClose: () => void - onToggleFavorite: (id: string) => void - onUse: (template: TemplateItem) => void - onCopy: (template: TemplateItem) => void -} +import { calcTotalSegmentDuration } from "../../utils/templateLibrary" export const TemplateDetailModal: React.FC = ({ template, @@ -31,6 +22,7 @@ export const TemplateDetailModal: React.FC = ({ }) => { const segments = template.segments ?? [] const totalSegmentDuration = calcTotalSegmentDuration(segments) + const typeInfo = TEMPLATE_TYPES.find((t) => t.type === template.category) return (
@@ -38,33 +30,8 @@ export const TemplateDetailModal: React.FC = ({ className="xx-template-modal xx-template-modal-wide" onClick={(e) => e.stopPropagation()} > - {/* 关闭按钮 */} - + - {/* 预览区域 */} -
- {template.thumbnail_url ? ( - {template.name} - ) : ( -
- - {TEMPLATE_TYPES.find((t) => t.type === template.category)?.icon ?? "📋"} - - {template.name} -
- )} -
- - {/* 内容区域 */}
{/* 标题行 */}
@@ -76,7 +43,7 @@ export const TemplateDetailModal: React.FC = ({ background: `${getTypeColor(template.category)}18`, }} > - {TEMPLATE_TYPES.find((t) => t.type === template.category)?.icon} {template.category} + {typeInfo?.icon} {template.category}
@@ -123,95 +90,15 @@ export const TemplateDetailModal: React.FC = ({ ]} /> - {/* 素材规则(片段配置) */} - {segments.length > 0 && ( -
-

🎬 素材规则

-
- {segments - .sort((a, b) => a.segment_order - b.segment_order) - .map((seg: TemplateSegment, idx: number) => ( -
- #{seg.segment_order} - - {getMaterialTypeLabel(seg.material_type)} - - - {seg.description || `片段 ${seg.segment_order}`} - - - - {seg.duration_min}-{seg.duration_max}秒 - - -
- ))} -
-
- 预估总时长:{formatDuration(Math.round(totalSegmentDuration))} -
-
- )} - - {/* 样式配置 */} -
-

🎨 样式配置

-
-
- 字幕样式 - - {formatConfig(template.subtitle_config)} - -
-
- 标题样式 - - {formatConfig(template.title_config)} - -
-
- BGM 配置 - - {formatConfig(template.bgm_config)} - -
-
- 视频比例 - - {template.aspect_ratio ?? "16:9"} - -
-
-
- - {/* 统计信息 */} -
- 已使用 {template.usage_count ?? 0} 次 - -
- - {/* 操作按钮 */} -
- - -
+ + +
diff --git a/apps/web/src/pages/templates/components/template-library/template-detail-modal/DetailFooter.tsx b/apps/web/src/pages/templates/components/template-library/template-detail-modal/DetailFooter.tsx new file mode 100755 index 000000000..8b6445bb6 --- /dev/null +++ b/apps/web/src/pages/templates/components/template-library/template-detail-modal/DetailFooter.tsx @@ -0,0 +1,46 @@ +import React from "react" +import { Button } from "antd" +import { CopyOutlined, ThunderboltOutlined } from "@ant-design/icons" +import type { TemplateItem } from "@/api/templates" + +interface DetailFooterProps { + template: TemplateItem + isFavorite: boolean + onToggleFavorite: (id: string) => void + onUse: (template: TemplateItem) => void + onCopy: (template: TemplateItem) => void +} + +/** 底部操作区:统计 + 收藏 + 按钮 */ +const DetailFooter: React.FC = ({ + template, + isFavorite, + onToggleFavorite, + onUse, + onCopy, +}) => { + return ( + <> +
+ 已使用 {template.usage_count ?? 0} 次 + +
+ +
+ + +
+ + ) +} + +export default DetailFooter diff --git a/apps/web/src/pages/templates/components/template-library/template-detail-modal/PreviewArea.tsx b/apps/web/src/pages/templates/components/template-library/template-detail-modal/PreviewArea.tsx new file mode 100755 index 000000000..f73c9587a --- /dev/null +++ b/apps/web/src/pages/templates/components/template-library/template-detail-modal/PreviewArea.tsx @@ -0,0 +1,39 @@ +import React from "react" +import type { TemplateItem } from "@/api/templates" +import { gradientForCategory } from "../../../utils/templateLibrary" +import { TEMPLATE_TYPES } from "../../../constants/templateLibrary" + +interface PreviewAreaProps { + template: TemplateItem + onClose: () => void +} + +/** 预览区域 */ +const PreviewArea: React.FC = ({ template, onClose }) => { + const typeInfo = TEMPLATE_TYPES.find((t) => t.type === template.category) + + return ( +
+ + {template.thumbnail_url ? ( + {template.name} + ) : ( +
+ {typeInfo?.icon ?? "📋"} + {template.name} +
+ )} +
+ ) +} + +export default PreviewArea diff --git a/apps/web/src/pages/templates/components/template-library/template-detail-modal/SegmentList.tsx b/apps/web/src/pages/templates/components/template-library/template-detail-modal/SegmentList.tsx new file mode 100755 index 000000000..434727543 --- /dev/null +++ b/apps/web/src/pages/templates/components/template-library/template-detail-modal/SegmentList.tsx @@ -0,0 +1,53 @@ +import React from "react" +import { Tooltip } from "antd" +import type { TemplateSegment } from "@/api/templates" +import { getMaterialTypeLabel, getTypeColor, formatDuration } from "../../../utils/templateLibrary" + +interface SegmentListProps { + segments: TemplateSegment[] + totalDuration: number +} + +/** 素材规则 / 片段列表 */ +const SegmentList: React.FC = ({ segments, totalDuration }) => { + if (segments.length === 0) return null + + return ( +
+

🎬 素材规则

+
+ {segments + .sort((a, b) => a.segment_order - b.segment_order) + .map((seg, idx) => ( +
+ #{seg.segment_order} + + {getMaterialTypeLabel(seg.material_type)} + + + {seg.description || `片段 ${seg.segment_order}`} + + + + {seg.duration_min}-{seg.duration_max}秒 + + +
+ ))} +
+
+ 预估总时长:{formatDuration(Math.round(totalDuration))} +
+
+ ) +} + +export default SegmentList diff --git a/apps/web/src/pages/templates/components/template-library/template-detail-modal/StyleConfig.tsx b/apps/web/src/pages/templates/components/template-library/template-detail-modal/StyleConfig.tsx new file mode 100755 index 000000000..335dc7181 --- /dev/null +++ b/apps/web/src/pages/templates/components/template-library/template-detail-modal/StyleConfig.tsx @@ -0,0 +1,33 @@ +import React from "react" +import type { TemplateItem } from "@/api/templates" +import { formatConfig } from "../../../utils/templateLibrary" + +interface StyleConfigProps { + template: TemplateItem +} + +/** 样式配置网格 */ +const StyleConfig: React.FC = ({ template }) => { + const items = [ + { label: "字幕样式", value: formatConfig(template.subtitle_config) }, + { label: "标题样式", value: formatConfig(template.title_config) }, + { label: "BGM 配置", value: formatConfig(template.bgm_config) }, + { label: "视频比例", value: template.aspect_ratio ?? "16:9" }, + ] + + return ( +
+

🎨 样式配置

+
+ {items.map((item) => ( +
+ {item.label} + {item.value} +
+ ))} +
+
+ ) +} + +export default StyleConfig diff --git a/apps/web/src/pages/templates/components/template-library/template-detail-modal/index.ts b/apps/web/src/pages/templates/components/template-library/template-detail-modal/index.ts new file mode 100755 index 000000000..4aa5428c6 --- /dev/null +++ b/apps/web/src/pages/templates/components/template-library/template-detail-modal/index.ts @@ -0,0 +1,6 @@ +export { TemplateDetailModal } from "../TemplateDetailModal" +export * from "./types" +export { default as PreviewArea } from "./PreviewArea" +export { default as SegmentList } from "./SegmentList" +export { default as StyleConfig } from "./StyleConfig" +export { default as DetailFooter } from "./DetailFooter" diff --git a/apps/web/src/pages/templates/components/template-library/template-detail-modal/types.ts b/apps/web/src/pages/templates/components/template-library/template-detail-modal/types.ts new file mode 100755 index 000000000..dc33fbc59 --- /dev/null +++ b/apps/web/src/pages/templates/components/template-library/template-detail-modal/types.ts @@ -0,0 +1,10 @@ +import type { TemplateItem } from "@/api/templates" + +export interface TemplateDetailModalProps { + template: TemplateItem + isFavorite: boolean + onClose: () => void + onToggleFavorite: (id: string) => void + onUse: (template: TemplateItem) => void + onCopy: (template: TemplateItem) => void +} diff --git a/apps/web/src/test/pages/TemplateLibrary.test.tsx b/apps/web/src/test/pages/TemplateLibrary.test.tsx old mode 100644 new mode 100755 index a9b7fd861..99c97942d --- a/apps/web/src/test/pages/TemplateLibrary.test.tsx +++ b/apps/web/src/test/pages/TemplateLibrary.test.tsx @@ -122,6 +122,11 @@ import "@/pages/templates/hooks/useTemplateLibrary" import "@/pages/templates/hooks/useTemplateDetail" import "@/pages/templates/components/template-library/TemplateCard" import "@/pages/templates/components/template-library/TemplateDetailModal" +import "@/pages/templates/components/template-library/template-detail-modal/PreviewArea" +import "@/pages/templates/components/template-library/template-detail-modal/SegmentList" +import "@/pages/templates/components/template-library/template-detail-modal/StyleConfig" +import "@/pages/templates/components/template-library/template-detail-modal/DetailFooter" +import "@/pages/templates/components/template-library/template-detail-modal/types" import "@/pages/templates/components/template-library/TemplateHeader" import "@/pages/templates/components/template-library/TemplateToolbar" import "@/pages/templates/components/template-library/TemplateGrid" -- 2.54.0 From 6b8f227d6d7bb807e417a8ac15e04b5db2703aa5 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Tue, 28 Jul 2026 02:16:45 +0000 Subject: [PATCH 2/2] style: auto-format with black + isort + prettier [skip ci-format-check] --- .../components/template-library/TemplateDetailModal.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/web/src/pages/templates/components/template-library/TemplateDetailModal.tsx b/apps/web/src/pages/templates/components/template-library/TemplateDetailModal.tsx index 1b59f3b9c..ffa15d389 100755 --- a/apps/web/src/pages/templates/components/template-library/TemplateDetailModal.tsx +++ b/apps/web/src/pages/templates/components/template-library/TemplateDetailModal.tsx @@ -5,10 +5,7 @@ import PreviewArea from "./template-detail-modal/PreviewArea" import SegmentList from "./template-detail-modal/SegmentList" import StyleConfig from "./template-detail-modal/StyleConfig" import DetailFooter from "./template-detail-modal/DetailFooter" -import { - getTypeColor, - formatDuration, -} from "../../utils/templateLibrary" +import { getTypeColor, formatDuration } from "../../utils/templateLibrary" import { TEMPLATE_TYPES } from "../../constants/templateLibrary" import { calcTotalSegmentDuration } from "../../utils/templateLibrary" -- 2.54.0