production runtime and mock removal

This commit is contained in:
inman committed 2026-08-17 23:44:14 +08:00
1 parent 2ef3da7af5
commit 6480e503eb
55 files changed
+581 -540

No files matched your search

+22 -9
View File
@@ -52,6 +52,7 @@ export function AssetManager({ initialView = "assets", initialTaskId }: AssetMan
}
return map;
}, [jobs]);
const outputAssetIds = useMemo(() => new Set(assets.map((asset) => asset.id)), [assets]);
const visibleAssets = pageItems(assets, assetPage, ASSET_PAGE_SIZE);
const visibleJobs = pageItems(jobs, jobPage, TASK_PAGE_SIZE);
@@ -262,10 +263,10 @@ export function AssetManager({ initialView = "assets", initialTaskId }: AssetMan
<div className="job-summary">
<h3>{job.prompt?.slice(0, 90) || capabilityLabel(job.capability)}</h3>
<p className="muted">{capabilityLabel(job.capability)} / {job.reqKey}</p>
<p className="muted compact-hint">{durationLabel(job, durationNow)} / 输入 {job.inputAssetIds.length || job.inputUrls.length} 个,输出 {job.outputAssetIds.length} 个 / {billingLabel(job)}</p>
<p className="muted compact-hint">{durationLabel(job, durationNow)} / 输入 {job.inputAssetIds.length || job.inputUrls.length} 个,输出 {resolvedOutputCount(job, outputAssetIds)} 个 / {billingLabel(job)}</p>
</div>
<div className="toolbar job-actions">
<span className={`status ${job.status}`}>{statusLabel(job.status)}</span>
<span className={`status ${taskStatusClass(job, outputAssetIds)}`}>{statusLabel(job.status, hasResolvedOutput(job, outputAssetIds))}</span>
<button className="button mini-button" type="button" aria-expanded={expandedJobId === job.id} onClick={() => setExpandedJobId(expandedJobId === job.id ? null : job.id)}>
<Info size={15} />
{expandedJobId === job.id ? "收起" : "详情"}
@@ -278,7 +279,7 @@ export function AssetManager({ initialView = "assets", initialTaskId }: AssetMan
</button>
</div>
</div>
{expandedJobId === job.id ? <JobDetails job={job} now={durationNow} /> : null}
{expandedJobId === job.id ? <JobDetails job={job} now={durationNow} outputAssetIds={outputAssetIds} /> : null}
</article>
))}
{!jobs.length ? <div className="callout">暂无生成任务。提交图片或视频生成后会保留任务历史。</div> : null}
@@ -314,13 +315,13 @@ export function AssetManager({ initialView = "assets", initialTaskId }: AssetMan
);
}
function JobDetails({ job, now }: { job: GenerationJob; now: number }) {
function JobDetails({ job, now, outputAssetIds }: { job: GenerationJob; now: number; outputAssetIds: Set<string> }) {
return (
<div className="job-detail-panel">
<dl className="job-detail-grid">
<div>
<dt>状态</dt>
<dd><span className={`status ${job.status}`}>{statusLabel(job.status)}</span></dd>
<dd><span className={`status ${taskStatusClass(job, outputAssetIds)}`}>{statusLabel(job.status, hasResolvedOutput(job, outputAssetIds))}</span></dd>
</div>
<div>
<dt>耗时</dt>
@@ -352,7 +353,7 @@ function JobDetails({ job, now }: { job: GenerationJob; now: number }) {
</div>
<div>
<dt>输入/输出</dt>
<dd>{job.inputAssetIds.length || job.inputUrls.length} / {job.outputAssetIds.length}</dd>
<dd>{job.inputAssetIds.length || job.inputUrls.length} / {resolvedOutputCount(job, outputAssetIds)}</dd>
</div>
<div>
<dt>扣费</dt>
@@ -456,10 +457,22 @@ function sourceLabel(source: Asset["source"]) {
return "外部";
}
function statusLabel(status: GenerationJob["status"]) {
function hasResolvedOutput(job: GenerationJob, outputAssetIds: Set<string>) {
return job.outputAssetIds.some((assetId) => outputAssetIds.has(assetId));
}
function resolvedOutputCount(job: GenerationJob, outputAssetIds: Set<string>) {
return job.outputAssetIds.filter((assetId) => outputAssetIds.has(assetId)).length;
}
function taskStatusClass(job: GenerationJob, outputAssetIds: Set<string>) {
return job.status === "succeeded" && !hasResolvedOutput(job, outputAssetIds) ? "syncing" : job.status;
}
function statusLabel(status: GenerationJob["status"], hasOutput = true) {
if (status === "queued") return "排队中";
if (status === "running") return "生成中";
if (status === "succeeded") return "已完成";
if (status === "succeeded") return hasOutput ? "已完成" : "结果同步中";
if (status === "failed") return "失败";
if (status === "expired") return "已过期";
if (status === "cancelled") return "已取消";
@@ -485,7 +498,7 @@ function capabilityLabel(capability?: GenerationJob["capability"]) {
}
function billingLabel(job: GenerationJob) {
if (!job.billing) return job.provider === "mock" ? "免计费" : "未计费";
if (!job.billing) return job.provider === "mock" ? "历史任务(未计费)" : "未计费";
if (job.billing.quotaExempt) return `超管费用 ${formatBillingAmount(job.billing.amountFen)}(不计额度)`;
if (job.billing.status === "refunded") return `已退款 ${formatBillingAmount(job.billing.amountFen)}`;
if (job.billing.status === "pending") return `预计 ${formatBillingAmount(job.billing.amountFen)}`;