大量修改UI

This commit is contained in:
Azmat@qq.com
2026-08-19 17:44:56 +08:00
parent 18b3927817
commit a343f47f0c
76 changed files with 11655 additions and 6104 deletions
@@ -10,6 +10,19 @@ function ratioStyle(ratio: string) {
return { aspectRatio: w && h ? `${w} / ${h}` : "16 / 9" };
}
function ratioCopy(ratio: string) {
const [w, h] = ratio.split(":").map(Number);
if (!w || !h) return ratio;
if (w === h) return `方形 ${ratio}`;
return `${w > h ? "横屏" : "竖屏"} ${ratio}`;
}
function statusTag(status: string) {
if (status === "succeeded") return { cls: "green", label: "已完成" };
if (status === "failed" || status === "cancelled") return { cls: "danger", label: status === "cancelled" ? "已取消" : "失败" };
return { cls: "blue", label: STATUS_LABELS[status] || "生成中" };
}
export function GenerationCard({ task, progress, onOpen, onRetry, onToggleFavorite, onDelete, onDownload }: {
task: FreeVideoTask;
progress: number;
@@ -23,12 +36,13 @@ export function GenerationCard({ task, progress, onOpen, onRetry, onToggleFavori
const inFlight = isInFlight(task.status);
const failed = task.status === "failed" || task.status === "cancelled";
const done = task.status === "succeeded" && !!task.video_url;
const tag = statusTag(task.status);
const errorText = isPublicGenerationError(task.error)
? (() => { const presentation = presentGenerationError(task.error); return `${presentation.title}:${presentation.description}`; })()
: task.error_message || "视频生成失败,请重试";
return (
<div className={`fc-card${done ? " done" : ""}`}>
<article className={`fc-card${done ? " done" : ""}`}>
<div
className="fc-card-media"
style={ratioStyle(task.aspect_ratio)}
@@ -43,18 +57,18 @@ export function GenerationCard({ task, progress, onOpen, onRetry, onToggleFavori
<div className="fc-card-generating">
<span className="spinner" />
<div className="fc-progress"><span style={{ width: `${Math.min(progress, 95)}%` }} /></div>
<span className="mono">{STATUS_LABELS[task.status] || "生成中"} · {Math.round(Math.min(progress, 95))}%</span>
<span>{STATUS_LABELS[task.status] || "生成中"} · {Math.round(Math.min(progress, 95))}%</span>
</div>
)}
{failed && (
<div className="fc-card-failed">
<span className="pill pill-l2 pill-err"><span className="dot" />失败</span>
<span className="fc-tag danger">失败</span>
<p>{errorText}</p>
<div className="hstack">
<button type="button" className="btn btn-sm" onClick={(event) => { event.stopPropagation(); onRetry(); }}>
<div className="fc-failed-actions">
<button type="button" className="fc-mini" onClick={(event) => { event.stopPropagation(); onRetry(); }}>
<RotateCcw size={13} /> 重试
</button>
<button type="button" className="btn btn-sm btn-ghost" title="删除" onClick={(event) => { event.stopPropagation(); onDelete(); }}>
<button type="button" className="fc-mini" title="删除" onClick={(event) => { event.stopPropagation(); onDelete(); }}>
<Trash2 size={13} /> 删除
</button>
</div>
@@ -71,6 +85,7 @@ export function GenerationCard({ task, progress, onOpen, onRetry, onToggleFavori
playsInline
preload="metadata"
/>
<span className="fc-dur">{task.duration}s</span>
<div className="fc-card-hover">
<button type="button" className="fc-hover-btn" title="下载" onClick={(event) => { event.stopPropagation(); onDownload(); }}>
<Download size={14} />
@@ -91,12 +106,16 @@ export function GenerationCard({ task, progress, onOpen, onRetry, onToggleFavori
)}
</div>
<div className="fc-card-meta">
<div className="fc-card-prompt" title={task.prompt}>{task.prompt}</div>
<div className="fc-card-sub mono">
// {MODE_LABELS[task.mode] || task.mode} · {modelLabel(task.model)} · {task.resolution.toUpperCase()} · {task.duration}s
{task.status === "succeeded" && ` · ${Number(task.actual_cost || 0)} 积分`}
<h3 title={task.prompt}>{task.prompt || "未命名视频"}</h3>
<p>{MODE_LABELS[task.mode] || task.mode} · {task.duration} 秒 · {ratioCopy(task.aspect_ratio)}</p>
<div className="fc-card-line">
<span className={`fc-tag ${tag.cls}`}>{tag.label}</span>
<span className="fc-tag">{modelLabel(task.model)}</span>
</div>
{inFlight && (
<div className="fc-progress-mini"><span style={{ width: `${Math.min(progress, 95)}%` }} /></div>
)}
</div>
</div>
</article>
);
}