feat: add local auth billing and usage management
This commit is contained in:
1 parent
f642b5e71f
commit
196fdde83f
119 files changed
+15695
-2650
No files matched your search
@@ -4,6 +4,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Download, Eye, ImageIcon, Info, Loader2, Music, RefreshCw, Trash2, X } from "lucide-react";
|
||||
import { clampPage, pageItems, Pagination } from "@/components/pagination";
|
||||
import { modalEnter, modalExit, pulseFeedback, revealChildren, runScopedMotion } from "@/lib/ui/motion";
|
||||
import { formatBillingAmount } from "@/lib/billing";
|
||||
import type { Asset, GenerationJob } from "@/lib/types";
|
||||
|
||||
type AssetView = "assets" | "tasks";
|
||||
@@ -248,7 +249,7 @@ export function AssetManager({ initialView = "assets", initialTaskId }: AssetMan
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
{!assets.length ? <div className="callout">暂无生成结果。提交创作、局部重绘或超清后,结果会自动保留在这里。</div> : null}
|
||||
{!assets.length ? <div className="callout">暂无生成结果。提交图片或视频创作后,结果会自动保留在这里。</div> : null}
|
||||
</div>
|
||||
<Pagination page={assetPage} pageSize={ASSET_PAGE_SIZE} total={assets.length} label="资产分页" onPageChange={setAssetPage} />
|
||||
</>
|
||||
@@ -261,7 +262,7 @@ 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} 个</p>
|
||||
<p className="muted compact-hint">{durationLabel(job, durationNow)} / 输入 {job.inputAssetIds.length || job.inputUrls.length} 个,输出 {job.outputAssetIds.length} 个 / {billingLabel(job)}</p>
|
||||
</div>
|
||||
<div className="toolbar job-actions">
|
||||
<span className={`status ${job.status}`}>{statusLabel(job.status)}</span>
|
||||
@@ -353,6 +354,10 @@ function JobDetails({ job, now }: { job: GenerationJob; now: number }) {
|
||||
<dt>输入/输出</dt>
|
||||
<dd>{job.inputAssetIds.length || job.inputUrls.length} / {job.outputAssetIds.length}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>扣费</dt>
|
||||
<dd>{billingLabel(job)}</dd>
|
||||
</div>
|
||||
{job.error ? (
|
||||
<div>
|
||||
<dt>错误</dt>
|
||||
@@ -446,9 +451,8 @@ function kindLabel(asset: Asset) {
|
||||
function sourceLabel(source: Asset["source"]) {
|
||||
if (source === "upload") return "上传";
|
||||
if (source === "generated") return "生成";
|
||||
if (source === "edited") return "重绘";
|
||||
if (source === "upscaled") return "超清";
|
||||
if (source === "seed") return "示例";
|
||||
if (source === "edited" || source === "upscaled") return "历史结果";
|
||||
if (source === "seed") return "素材";
|
||||
return "外部";
|
||||
}
|
||||
|
||||
@@ -471,17 +475,24 @@ function providerLabel(provider: GenerationJob["provider"]) {
|
||||
if (provider === "evolink") return "EvoLink";
|
||||
if (provider === "seedance") return "Seedance";
|
||||
if (provider === "bailian") return "阿里云百炼";
|
||||
return "Mock";
|
||||
return "系统生成";
|
||||
}
|
||||
|
||||
function capabilityLabel(capability?: GenerationJob["capability"]) {
|
||||
if (capability === "image.generate") return "图片生成";
|
||||
if (capability === "image.inpaint") return "局部重绘";
|
||||
if (capability === "image.upscale") return "智能超清";
|
||||
if (capability === "video.generate") return "视频生成";
|
||||
return "生成任务";
|
||||
}
|
||||
|
||||
function billingLabel(job: GenerationJob) {
|
||||
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)}`;
|
||||
if (job.billing.status === "not_charged") return "未扣费";
|
||||
return `扣费 ${formatBillingAmount(job.billing.amountFen)}`;
|
||||
}
|
||||
|
||||
function jobPath(job: GenerationJob) {
|
||||
return job.capability === "video.generate" ? `/api/generations/video/${job.id}` : `/api/generations/image/${job.id}`;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user