Files
xiaoxia-saas/apps/web/src/pages/generate/components/BatchGenerationGrid.tsx
T
xiaoxia a4c008e829
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check push changed paths (push) Successful in 3s
CI/CD Pipeline / Build Staging API Image (push) Successful in 27s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 26s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m31s
CI/CD Pipeline / Integration Tests (push) Successful in 1m44s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 2m15s
CI/CD Pipeline / Validate - Style (push) Successful in 2m19s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m9s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m2s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m28s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m36s
CI/CD Pipeline / Unit Tests (push) Failing after 6m25s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m27s
CI/CD Pipeline / Validate - Security (push) Successful in 9m9s
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Failing after 191h47m29s
CI/CD Pipeline / Deploy Production (push) Failing after 191h47m29s
CI/CD Pipeline / CI Gate (push) Failing after 191h47m33s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 191h47m33s
CI/CD Pipeline / Build Production Web Image (push) Failing after 191h47m33s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 191h55m0s
CI/CD Pipeline / Build Production API Image (push) Failing after 191h47m33s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 191h55m3s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 191h55m4s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 191h56m40s
CI/CD Pipeline / Frontend Lint (push) Failing after 191h56m40s
CI/CD Pipeline / PR Build Web Image (push) Failing after 191h56m40s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 191h56m45s
CI/CD Pipeline / PR Build API Image (push) Failing after 192h31m24s
fix: #1799 批量生成进度卡片 grid 列宽过窄导致标题和进度条重叠
2026-09-08 15:27:21 +08:00

135 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 第5步「确认生成」— 批量渲染进度网格(Issue #1677)
*
* N 个正式生成任务各自独立卡片:进度条 / 成功成片播放 / 失败原因 + 单独重试。
* 数据来自 useGenerateVideo 的 batchTasks(useGenerationPolling 实时回传)。
*/
import React from "react"
import { LoadingOutlined, CheckCircleFilled, CloseCircleOutlined } from "@ant-design/icons"
import type { BatchTaskState } from "../hooks/generate-video/useGenerationPolling"
import type { GeneratedVideo } from "@/api/template-editor"
interface BatchGenerationGridProps {
tasks: BatchTaskState[]
/** 变体标题(按变体序号取) */
titles: string[]
/** 失败任务重试 */
onRetryTask: (taskId: string) => void
}
const BatchGenerationGrid: React.FC<BatchGenerationGridProps> = ({
tasks,
titles,
onRetryTask,
}) => {
const sorted = [...tasks].sort(
(a, b) => Number(a.variantIndex || 0) - Number(b.variantIndex || 0),
)
return (
<div className="xx-form-section">
<div className="xx-preview-header">
<h3>🎬 正在生成 {tasks.length} 个视频</h3>
<span style={{ fontSize: 13, color: "var(--text-secondary, #666)" }}>
完成 {tasks.filter((t) => t.status === "completed").length} / {tasks.length}
</span>
</div>
<div
className="xx-batch-gen-grid"
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 320px))",
justifyContent: "center",
justifyItems: "center",
gap: 14,
width: "100%",
}}
>
{sorted.map((task) => {
const title = titles[task.variantIndex] || `视频 ${task.variantIndex + 1}`
const video = (task.videos?.[0] || null) as GeneratedVideo | null
return (
<div
key={task.taskId}
className={`xx-batch-gen-card status-${task.status}`}
style={{ maxWidth: 320 }}
>
<div className="xx-batch-gen-card-head">
<span className="xx-batch-gen-card-title" title={title}>
{task.status === "completed" ? (
<CheckCircleFilled style={{ color: "#52c41a", marginRight: 6 }} />
) : task.status === "failed" ? (
<CloseCircleOutlined style={{ color: "#ef4444", marginRight: 6 }} />
) : (
<LoadingOutlined style={{ color: "#1677ff", marginRight: 6 }} />
)}
视频 {task.variantIndex + 1}:{title}
</span>
</div>
<div className="xx-batch-gen-card-body">
{task.status === "running" && (
<>
<div className="xx-gen-progress-bar">
<div
className="xx-gen-progress-bar-fill"
style={{ width: `${Math.min(task.progress, 100)}%` }}
/>
</div>
<div className="xx-batch-gen-card-pct">{Math.round(task.progress)}%</div>
</>
)}
{task.status === "completed" && video && (
// 竖屏自适应容器(#1750):成片固定 1080×1920(9:16),
// 视频按真实宽高比 contain 显示,黑底居中,杜绝横屏播放器左右大黑边
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
background: "transparent",
borderRadius: 8,
padding: 0,
}}
>
<video
src={video.download_url || video.file_url}
controls
style={{
width: "100%",
maxHeight: "70vh",
aspectRatio: "9 / 16",
objectFit: "cover",
borderRadius: 4,
background: "transparent",
}}
poster={video.thumbnail_url}
/>
</div>
)}
{task.status === "completed" && !video && (
<div className="xx-batch-gen-card-done">✅ 已完成(成片可在下一步选择封面)</div>
)}
{task.status === "failed" && (
<div className="xx-batch-gen-card-failed">
<div className="xx-batch-gen-card-err">{task.error || "生成失败"}</div>
<button
type="button"
className="xx-btn xx-btn-primary xx-btn-sm"
onClick={() => onRetryTask(task.taskId)}
>
🔄 重试此视频
</button>
</div>
)}
</div>
</div>
)
})}
</div>
</div>
)
}
export default BatchGenerationGrid