Files
xiaoxia-saas/apps/web/src/pages/editing-planner/components/PreviewPlayer.tsx
T
xiaoxia afcfcf45ee
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (push) Successful in 19s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 13s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 14s
CI/CD Pipeline / Build Staging API Image (push) Successful in 46s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m39s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m19s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m50s
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 43h10m14s
CI/CD Pipeline / PR Build Web Image (push) Failing after 43h11m24s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 43h10m56s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 43h9m45s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 43h10m55s
CI/CD Pipeline / PR Build API Image (push) Failing after 43h10m55s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 43h9m45s
CI/CD Pipeline / Frontend Lint (push) Failing after 43h10m50s
fix(frontend): #1896 删除侵权华康字体修复PreviewPlayer字体映射 (#1908)
fix(frontend): #1896 删除侵权华康字体修复PreviewPlayer字体映射

问题:
1. "华康俪金黑"@font-face字体文件缺失(404)且有版权风险
2. PreviewPlayer直接用中文font_preset/font作为fontFamily,浏览器不识别

修改:
- 删除"华康俪金黑"字体选项(FONT_OPTIONS+FONT_FAMILY_MAP)和@font-face声明
- 统一 editing-planner/constants/clipProperties.ts 和 subtitleStyle.ts 从 generate/constants 重新导出 FONT_OPTIONS,避免多处维护
- PreviewPlayer.tsx 标题/字幕 fontFamily 通过 getFontFamily() 映射为浏览器可识别字体栈
- FrontendPreviewPlayer.tsx 标题 fontFamily 同样通过 getFontFamily() 映射
- TitleStylePanel/PanelTitleConfig/SubtitleStylePanel 等组件因复用统一常量自动生效
- 最终保留5个字体:思源黑体、思源宋体、苹方、微软雅黑、楷体
- PingFang 别名保留在 FONT_FAMILY_MAP 中以兼容旧数据,但不在 UI 选项中显示

Refs #1896
2026-09-14 20:12:21 +08:00

131 lines
3.9 KiB
TypeScript

/**
* 预览区 — V8 原型 1:1 还原
* 手机模型预览
*/
import React from "react"
import type { ClipData, ClipType } from "../types"
import type { TitleConfig } from "@/api/template-editor"
import { getFontFamily } from "@/pages/generate/constants"
interface SubtitleSettings {
enabled: boolean
position: string
font: string
size: number
animation: string
}
interface PreviewPlayerProps {
clips: ClipData[]
selectedClipId: string | null
isPlaying: boolean
titleConfig?: TitleConfig
subtitleSettings?: SubtitleSettings
onClipSelect: (clipId: string) => void
onPlayPause: () => void
}
const CLIP_TYPE_ICONS: Record<ClipType, string> = {
voice: "🎙️",
pip: "🖼️",
}
const CLIP_TYPE_LABELS: Record<ClipType, string> = {
voice: "口播",
pip: "混剪",
}
const PreviewPlayer: React.FC<PreviewPlayerProps> = ({
clips,
selectedClipId,
isPlaying,
titleConfig,
subtitleSettings,
onPlayPause,
}) => {
const selectedClip = clips.find((c) => c.id === selectedClipId)
const displayClip = selectedClip || clips[0]
return (
<div className="ep-preview-area">
{/* 手机模型预览 */}
<div className="ep-phone-preview">
<div className="ep-phone-status-bar">
<span>9:41</span>
<span>📶 🔋</span>
</div>
<div className="ep-phone-content">
{displayClip ? (
<>
<button className="ep-phone-play-btn" onClick={onPlayPause}>
{isPlaying ? "⏸" : "▶"}
</button>
<div className="ep-phone-progress">
<div
className="ep-phone-progress-fill"
style={{ width: isPlaying ? "45%" : "0%" }}
/>
</div>
<div className="ep-phone-clip-label">
{CLIP_TYPE_ICONS[displayClip.type] || "🎬"}{" "}
{CLIP_TYPE_LABELS[displayClip.type] || "片段"}
</div>
</>
) : (
<span className="ep-phone-empty-hint">暂无片段</span>
)}
{/* 标题实时预览 */}
{titleConfig && !titleConfig.ai_auto_select && titleConfig.content && (
<div
className="ep-preview-title"
style={{
fontSize: `${Math.min(titleConfig.font_size, 20)}px`,
fontFamily: getFontFamily(titleConfig.font_preset),
fontWeight: "bold",
fontStyle: "normal",
textShadow: "2px 2px 4px rgba(0,0,0,0.5)",
WebkitTextStroke: "1px rgba(0,0,0,0.6)",
top:
titleConfig.position === "top"
? "6.25%"
: titleConfig.position === "center"
? "50%"
: "auto",
bottom: titleConfig.position === "bottom" ? "30px" : "auto",
transform: titleConfig.position === "center" ? "translateY(-50%)" : "none",
color: titleConfig.font_color,
}}
>
{titleConfig.content}
</div>
)}
{/* 字幕实时预览 */}
{subtitleSettings?.enabled && (
<div
className="ep-preview-subtitle"
style={{
fontSize: `${Math.min(subtitleSettings.size, 14)}px`,
fontFamily: getFontFamily(subtitleSettings.font),
top:
subtitleSettings.position === "top"
? "8px"
: subtitleSettings.position === "center"
? "50%"
: "auto",
bottom: subtitleSettings.position === "bottom" ? "8px" : "auto",
transform: subtitleSettings.position === "center" ? "translateY(-50%)" : "none",
}}
>
字幕预览文字
</div>
)}
</div>
</div>
</div>
)
}
export default PreviewPlayer