fix: 标题叠加层始终渲染+移除不存在的batch接口调用 #1419

Merged
auto-approve-bot merged 1 commits from fix/preview-title-overlay-and-api into develop 2026-08-18 13:26:01 +08:00
2 changed files with 35 additions and 38 deletions
@@ -132,7 +132,7 @@ const TitleOverlay: React.FC<{ titleSettings: TitleSettings }> = ({ titleSetting
style={{
position: "absolute",
inset: 0,
zIndex: 20,
zIndex: 30,
pointerEvents: "none",
}}
>
@@ -160,6 +160,7 @@ export const PreviewVideoPanel: React.FC<PreviewVideoPanelProps> = ({
titleSettings,
}) => {
const videoAspectStyle = { aspectRatio: (videoRatio || "16:9").replace(":", "/") }
const hasTitle = !!titleSettings?.title?.trim()
return (
<div className="xx-generate-preview">
@@ -168,33 +169,40 @@ export const PreviewVideoPanel: React.FC<PreviewVideoPanelProps> = ({
{assetsReady && assets.length > 0 && <span className="xx-preview-badge"></span>}
</div>
{/* 加载中 */}
{assetsLoading && (
<div className="xx-preview-loading-panel">
<div className="xx-preview-video" style={videoAspectStyle}>
<div className="xx-preview-loading-center">
<LoadingOutlined style={{ fontSize: 36, color: "#fff" }} spin />
<p style={{ marginTop: 12, color: "rgba(255,255,255,0.8)", fontSize: 14 }}>
...
</p>
</div>
{/* 预览容器 — 标题叠加层始终渲染在容器顶层,不受加载状态影响 */}
<div className="xx-preview-video" style={{ ...videoAspectStyle, position: "relative" }}>
{/* 内容层:加载中 or 前端播放器 */}
{assetsLoading ? (
<div
className="xx-preview-loading-center"
style={{
position: "absolute",
inset: 0,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
zIndex: 1,
}}
>
<LoadingOutlined style={{ fontSize: 36, color: "#fff" }} spin />
<p style={{ marginTop: 12, color: "rgba(255,255,255,0.8)", fontSize: 14 }}>
...
</p>
</div>
</div>
)}
{/* 前端预览播放器 + CSS 标题叠加 */}
{!assetsLoading && (
<div className="xx-preview-video" style={{ ...videoAspectStyle, position: "relative" }}>
) : (
<FrontendPreviewPlayer
assets={assets}
template={template}
videoRatio={videoRatio}
ready={assetsReady}
/>
{/* CSS 标题实时预览层 — 与 FFmpeg ASS 渲染坐标对齐 */}
{titleSettings && <TitleOverlay titleSettings={titleSettings} />}
</div>
)}
)}
{/* CSS 标题实时预览层 — 与 FFmpeg ASS 渲染坐标对齐
始终渲染在内容层之上(z-index: 30),只要 titleSettings 有标题文字就显示 */}
{hasTitle && <TitleOverlay titleSettings={titleSettings!} />}
</div>
{/* 素材信息 */}
{assetsReady && assets.length > 0 && (
@@ -1,33 +1,22 @@
/**
* 预览素材加载 Hook
* 根据选中的素材 ID 列表,批量获取素材详情(含 file_url、duration 等)
* 根据选中的素材 ID 列表,逐个获取素材详情(含 file_url、duration 等)
* 供前端预览播放器使用
*
* 注意:后端没有批量接口(/assets/batch 返回 405),
* 因此直接使用 Promise.allSettled 并发请求单个 GET /assets/{id}
*/
import { useState, useEffect, useCallback, useRef } from "react"
import type { AssetItem } from "@/api/assets"
import type { AxiosResponse } from "axios"
/** 批量获取素材详情的 API 路径 */
const ASSETS_BATCH_URL = "/assets/batch"
/**
* 通过 ID 列表批量获取素材
* 优先使用批量接口,失败则回退为逐个获取
* 通过 ID 列表逐个获取素材(并发)
* 使用 Promise.allSettled 确保单个失败不影响整体
*/
async function fetchAssetsByIds(ids: string[]): Promise<AssetItem[]> {
if (!ids.length) return []
try {
// 尝试批量接口
const { default: apiClient } = await import("@/api/client")
const response = await apiClient.post(ASSETS_BATCH_URL, { ids })
const items: AssetItem[] = response.data?.items || response.data || []
if (items.length > 0) return items
} catch {
// 批量接口不存在,回退为逐个获取
}
// 回退:逐个获取
try {
const { default: apiClient } = await import("@/api/client")
const results = await Promise.allSettled(