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

@@ -4,6 +4,7 @@ import { AdminEmpty } from "@/pages/admin/components/admin-ui";
import { RefreshCw } from "lucide-react";
import { formatCredits } from "@/constant/credits";
import { mediaDeliverySummary } from "@/lib/generation-task-display";
import { getAdminApiLog, queryAdminApiLogTask, type ApiCallLog } from "@/services/api/auth";
import { AdminStatusBadge } from "./admin-ui";
@@ -80,6 +81,7 @@ function LogDetail({ log, querying, onQueryProviderTask }: { log: ApiCallLog; qu
],
["能力", capabilityText(log.capability)],
["请求阶段", requestKindText(log.requestKind)],
["作品交付", mediaDeliverySummary(log.taskStatus, log.mediaStage) || "未记录保存阶段"],
["计费属性", log.billable ? "计费调用" : "不计费"],
["总耗时", <span className="tabular-nums">{formatDuration(log.durationMs)}</span>],
["视频轮询", log.capability === "video" ? <span className="tabular-nums">{log.pollCount || 0} 次</span> : <span className="text-foreground/35">--</span>],
@@ -125,7 +127,7 @@ function LogDetail({ log, querying, onQueryProviderTask }: { log: ApiCallLog; qu
["上游地址", log.upstreamUrl ? <code className="break-all text-sm text-foreground/70">{log.upstreamUrl}</code> : <span className="text-foreground/35">--</span>],
].map(([label, children], index) => ({ key: String(index), label, children }));
const canQueryProviderTask = log.capability === "video" && log.taskStatus === "failed" && Boolean(log.taskId && log.providerRequestId);
const canQueryProviderTask = !log.mediaStage && log.capability === "video" && log.taskStatus === "failed" && Boolean(log.taskId && log.providerRequestId);
return (
<div className="space-y-6">
@@ -159,7 +161,7 @@ function billingText(log: ApiCallLog) {
}
function requestKindText(value: ApiCallLog["requestKind"]) {
const labels: Partial<Record<ApiCallLog["requestKind"], string>> = { create: "模型生成", poll: "状态查询", download: "结果下载", repair: "结果修复" };
const labels: Partial<Record<ApiCallLog["requestKind"], string>> = { create: "模型生成", poll: "状态查询", download: "结果下载", upload: "上传 OSS", local_save: "保存文件", register: "登记素材", repair: "结果修复" };
return labels[value] || "上游请求";
}

View File

@@ -10,6 +10,7 @@ import { PaginationBar } from "@/pages/admin/components/admin-ui";
import { MediaPreview } from "@/components/media-preview";
import { formatCredits } from "@/constant/credits";
import { useDebouncedValue } from "@/hooks/use-debounced-value";
import { mediaDeliverySummary } from "@/lib/generation-task-display";
import { exportAdminApiLogs, listAdminApiLogs, type ApiCallLog } from "@/services/api/auth";
import { ApiLogDetailDrawer } from "../components/api-log-detail-drawer";
import { AdminPageFrame } from "../components/admin-shell";
@@ -361,12 +362,13 @@ function CallStatus({ log }: { log: ApiCallLog }) {
<div>
<div className="mb-1 text-xs font-medium text-foreground/70">{requestKindText(log.requestKind)}</div>
<AdminStatusBadge {...logStatus(log)} />
{log.mediaStage ? <div className="mt-1 text-xs text-foreground/60">{mediaDeliverySummary(log.taskStatus, log.mediaStage)}</div> : null}
{log.capability === "video" ? <div className="mt-1 text-xs tabular-nums text-foreground/45">已轮询 {log.pollCount || 0} 次</div> : null}
</div>
);
}
function requestKindText(value: ApiCallLog["requestKind"]) {
const labels: Partial<Record<ApiCallLog["requestKind"], string>> = { create: "模型生成", poll: "状态查询", download: "结果下载", repair: "结果修复" };
const labels: Partial<Record<ApiCallLog["requestKind"], string>> = { create: "模型生成", poll: "状态查询", download: "结果下载", upload: "上传 OSS", local_save: "保存文件", register: "登记素材", repair: "结果修复" };
return labels[value] || "上游请求";
}