feat(media): 作品保存恢复 - 按原任务重试交付并避免重复生成计费

This commit is contained in:
ddCat
2026-09-22 15:47:24 +08:00
parent acbb354e97
commit 48a82ded74
49 changed files with 1710 additions and 50 deletions

View File

@@ -321,6 +321,8 @@ function completedTaskMetadata(task: GenerationTask): CanvasNodeMetadata {
taskStatus: task.status,
taskProgress: typeof task.progress === "number" && Number.isFinite(task.progress) ? Math.max(0, Math.min(100, Math.round(task.progress))) : 100,
taskStage: task.stage,
taskMediaStage: task.mediaStage,
taskCanRecoverMedia: task.canRecoverMedia,
taskStartedAt: task.startedAt,
taskCompletedAt: task.completedAt,
taskDurationMs: task.startedAt && task.completedAt ? Math.max(0, Date.parse(task.completedAt) - Date.parse(task.startedAt)) : undefined,

View File

@@ -158,6 +158,8 @@ export function generationTaskMetadata(task: GenerationTask): CanvasNodeMetadata
taskStatus: task.status,
taskProgress: progress,
taskStage: task.stage,
taskMediaStage: task.mediaStage,
taskCanRecoverMedia: task.canRecoverMedia,
taskProvider: task.provider,
taskStartedAt: task.startedAt,
taskCompletedAt: task.completedAt,

View File

@@ -23,6 +23,8 @@ export function resetGenerationTaskMetadata(metadata: CanvasNodeMetadata | undef
delete next.taskStatus;
delete next.taskProgress;
delete next.taskStage;
delete next.taskMediaStage;
delete next.taskCanRecoverMedia;
delete next.taskProvider;
delete next.taskStartedAt;
delete next.taskCompletedAt;

View File

@@ -8,13 +8,23 @@ export const statusLabel: Record<TaskStatus, string> = {
cancelled: "已取消",
};
type GenerationTaskDisplayTarget = Pick<GenerationTask, "status" | "stage">;
type GenerationTaskDisplayTarget = Pick<GenerationTask, "status" | "stage" | "mediaStage">;
export function mediaDeliverySummary(status: TaskStatus | undefined, stage: GenerationTask["mediaStage"]) {
if (!stage) return "";
if (stage === "completed") return "生成成功 · 文件保存成功 · 素材登记成功";
const prefix = stage === "download" || stage === "checkpoint" ? "生成成功" : stage === "register" ? "生成成功 · 文件保存成功" : "生成成功 · 下载成功";
const action = { download: "下载", upload: "上传 OSS", local_save: "保存文件", register: "登记素材", checkpoint: "记录恢复信息" }[stage];
return `${prefix} · ${action}${status === "failed" ? "失败" : status === "cancelled" ? "已停止" : "待完成"}`;
}
export function isGenerationTaskSubmissionUncertain(task: GenerationTaskDisplayTarget) {
return task.stage === "submission_unknown";
}
export function generationTaskStatusLabel(task: GenerationTaskDisplayTarget) {
if (task.mediaStage && task.status === "failed") return "作品保存未完成";
if (task.mediaStage && (task.status === "queued" || task.status === "running")) return "作品已生成,正在保存";
if (isGenerationTaskSubmissionUncertain(task)) return "提交结果待确认";
return statusLabel[task.status];
}
@@ -27,6 +37,7 @@ export function generationTaskStageLabel(task: GenerationTaskDisplayTarget) {
}
export function generationTaskShowsProgress(task: GenerationTaskDisplayTarget) {
if (task.mediaStage && task.mediaStage !== "completed") return false;
if (isGenerationTaskSubmissionUncertain(task)) return false;
// 排队、后端接管和连接供应商都没有真实百分比。只有上游状态响应
// 已经写回任务后才显示进度,避免所有图片/视频长期停在同一个假数值。