64387c00bb
CI/CD Pipeline / Check if frontend-only change (push) Blocked by required conditions
CI/CD Pipeline / Validate - Code Quality (push) Blocked by required conditions
CI/CD Pipeline / Validate - Type Check (mypy) (push) Blocked by required conditions
CI/CD Pipeline / Validate - Migration (alembic) (push) Blocked by required conditions
CI/CD Pipeline / Unit Tests (push) Blocked by required conditions
CI/CD Pipeline / Integration Tests (push) Blocked by required conditions
CI/CD Pipeline / Frontend Lint (push) Blocked by required conditions
CI/CD Pipeline / Frontend Unit Tests (push) Blocked by required conditions
CI/CD Pipeline / PR Build API Image (push) Blocked by required conditions
CI/CD Pipeline / PR Build Web Image (push) Blocked by required conditions
CI/CD Pipeline / PR Build Worker Image (push) Blocked by required conditions
CI/CD Pipeline / Build Staging API Image (push) Blocked by required conditions
CI/CD Pipeline / Build Staging Web Image (push) Blocked by required conditions
CI/CD Pipeline / Build Staging Worker Image (push) Blocked by required conditions
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Blocked by required conditions
CI/CD Pipeline / Staging E2E Tests (push) Blocked by required conditions
CI/CD Pipeline / Staging API Integration Tests (push) Blocked by required conditions
CI/CD Pipeline / Build Production API Image (push) Blocked by required conditions
CI/CD Pipeline / Build Production Web Image (push) Blocked by required conditions
CI/CD Pipeline / Build Production Worker Image (push) Blocked by required conditions
CI/CD Pipeline / Deploy Production (push) Blocked by required conditions
CI/CD Pipeline / Production Browser E2E (push) Blocked by required conditions
CI/CD Pipeline / ACR Image Cleanup (push) Blocked by required conditions
CI/CD Pipeline / Canary Release to Production (push) Blocked by required conditions
101 lines
2.7 KiB
TypeScript
101 lines
2.7 KiB
TypeScript
/**
|
||
* 片头片尾配置面板 — Drawer 形式
|
||
* 两个区块:片头(Intro)/ 片尾(Outro)
|
||
* 每个区块支持:类型选择(无/视频/图片)、素材 URL、时长、过渡动画
|
||
*/
|
||
import React, { useCallback } from "react"
|
||
import { Drawer } from "antd"
|
||
import type {
|
||
IntroOutroConfig,
|
||
IntroOutroItem,
|
||
IntroOutroKind,
|
||
} from "@/pages/editing-planner/types"
|
||
import { DEFAULT_INTRO_OUTRO } from "@/pages/editing-planner/types"
|
||
import IntroOutroBlock from "./intro-outro/IntroOutroBlock"
|
||
|
||
interface IntroOutroPanelProps {
|
||
open: boolean
|
||
onClose: () => void
|
||
config: IntroOutroConfig
|
||
onChange: (config: IntroOutroConfig) => void
|
||
}
|
||
|
||
const IntroOutroPanel: React.FC<IntroOutroPanelProps> = ({ open, onClose, config, onChange }) => {
|
||
/* ── 更新片头 ── */
|
||
const handleIntroChange = useCallback(
|
||
(partial: Partial<IntroOutroItem>) => {
|
||
onChange({ ...config, intro: { ...config.intro, ...partial } })
|
||
},
|
||
[config, onChange],
|
||
)
|
||
|
||
/* ── 更新片尾 ── */
|
||
const handleOutroChange = useCallback(
|
||
(partial: Partial<IntroOutroItem>) => {
|
||
onChange({ ...config, outro: { ...config.outro, ...partial } })
|
||
},
|
||
[config, onChange],
|
||
)
|
||
|
||
/* ── 切换片头类型 ── */
|
||
const handleIntroKindChange = useCallback(
|
||
(kind: IntroOutroKind) => {
|
||
handleIntroChange({ kind, url: kind === "none" ? undefined : "" })
|
||
},
|
||
[handleIntroChange],
|
||
)
|
||
|
||
/* ── 切换片尾类型 ── */
|
||
const handleOutroKindChange = useCallback(
|
||
(kind: IntroOutroKind) => {
|
||
handleOutroChange({ kind, url: kind === "none" ? undefined : "" })
|
||
},
|
||
[handleOutroChange],
|
||
)
|
||
|
||
/* ── 重置 ── */
|
||
const handleReset = useCallback(() => {
|
||
onChange({ ...DEFAULT_INTRO_OUTRO })
|
||
}, [onChange])
|
||
|
||
return (
|
||
<Drawer
|
||
title="🎬 片头片尾设置"
|
||
placement="right"
|
||
width={420}
|
||
open={open}
|
||
onClose={onClose}
|
||
className="intro-outro-panel-drawer"
|
||
>
|
||
{/* ═══ 片头区块 ═══ */}
|
||
<IntroOutroBlock
|
||
title="片头"
|
||
icon="🎞️"
|
||
item={config.intro}
|
||
transitionLabel="进入过渡动画"
|
||
onKindChange={handleIntroKindChange}
|
||
onChange={handleIntroChange}
|
||
/>
|
||
|
||
{/* ═══ 片尾区块 ═══ */}
|
||
<IntroOutroBlock
|
||
title="片尾"
|
||
icon="🏁"
|
||
item={config.outro}
|
||
transitionLabel="退出过渡动画"
|
||
onKindChange={handleOutroKindChange}
|
||
onChange={handleOutroChange}
|
||
/>
|
||
|
||
{/* ── 底部操作 ── */}
|
||
<div className="iop-footer">
|
||
<button className="iop-reset-btn" onClick={handleReset}>
|
||
重置
|
||
</button>
|
||
</div>
|
||
</Drawer>
|
||
)
|
||
}
|
||
|
||
export default IntroOutroPanel
|