refactor(*): 代码质量治理 - 收敛接口客户端、模型职责与异步计费巡检

This commit is contained in:
ddCat
2026-08-06 16:36:51 +08:00
parent 9ca9dd9df6
commit b3199c5e7e
42 changed files with 3051 additions and 2271 deletions

View File

@@ -29,23 +29,42 @@ export function CanvasUploadStatusToast({ status, theme }: { status: CanvasUploa
initial={{ opacity: 0, x: 22, scale: 0.94 }}
animate={{ opacity: 1, x: 0, scale: 1 }}
transition={aceternityMotion.spring.panel}
className="pointer-events-none absolute right-4 top-20 z-[var(--z-panel-floating)] w-[320px] overflow-hidden rounded-[22px] border px-4 py-4 backdrop-blur-2xl"
style={{ background: theme.spatial.elevated, borderColor: status.error ? `${theme.accent.danger}66` : status.done ? "rgba(34,197,94,.4)" : theme.spatial.glowStrong, color: theme.node.text, boxShadow: `0 24px 72px ${theme.spatial.shadow}, inset 0 1px 0 rgba(255,255,255,.14)` }}
className="pointer-events-none absolute right-4 top-20 z-[var(--z-panel-floating)] w-[var(--panel-width-compact)] overflow-hidden rounded-[var(--panel-radius-wide-tight)] border px-4 py-4 backdrop-blur-2xl"
style={{
background: theme.spatial.elevated,
borderColor: status.error ? `${theme.accent.danger}66` : status.done ? "rgba(34,197,94,.4)" : theme.spatial.glowStrong,
color: theme.node.text,
boxShadow: `0 24px 72px ${theme.spatial.shadow}, inset 0 1px 0 rgba(255,255,255,.14)`,
}}
>
<div className="absolute inset-x-0 top-0 h-px" style={{ background: `linear-gradient(90deg, transparent, ${accent}, transparent)` }} />
<div className="flex items-start gap-3">
<motion.span animate={status.done || status.error ? { scale: [0.8, 1.08, 1] } : { y: [0, -2, 0] }} transition={status.done || status.error ? { duration: aceternityMotion.duration.panel } : { duration: 1.5, repeat: Number.POSITIVE_INFINITY }} className="mt-0.5 grid size-9 shrink-0 place-items-center rounded-[var(--dock-radius)] border" style={{ background: theme.spatial.surface, borderColor: `${accent}44`, color: accent }}>
<motion.span
animate={status.done || status.error ? { scale: [0.8, 1.08, 1] } : { y: [0, -2, 0] }}
transition={status.done || status.error ? { duration: aceternityMotion.duration.panel } : { duration: 1.5, repeat: Number.POSITIVE_INFINITY }}
className="mt-0.5 grid size-9 shrink-0 place-items-center rounded-[var(--dock-radius)] border"
style={{ background: theme.spatial.surface, borderColor: `${accent}44`, color: accent }}
>
{status.error ? <TriangleAlert className="size-4" /> : status.done ? <CheckCircle2 className="size-4" /> : <CloudUpload className="size-4" />}
</motion.span>
<span className="min-w-0 flex-1">
<span className="block truncate text-sm font-semibold">{status.title}</span>
<span className="mt-1 block truncate text-[var(--fs-label)]" style={{ color: theme.node.muted }}>{status.detail}</span>
<span className="mt-1 block truncate text-[var(--fs-label)]" style={{ color: theme.node.muted }}>
{status.detail}
</span>
</span>
<span className="shrink-0 rounded-full border px-2 py-1 text-[var(--fs-tiny)] font-semibold tabular-nums" style={{ background: theme.spatial.surface, borderColor: theme.toolbar.border, color: theme.node.muted }}>
{status.step}/{status.total}
</span>
<span className="shrink-0 rounded-full border px-2 py-1 text-[var(--fs-tiny)] font-semibold tabular-nums" style={{ background: theme.spatial.surface, borderColor: theme.toolbar.border, color: theme.node.muted }}>{status.step}/{status.total}</span>
</div>
<div className="mt-4 flex items-center gap-1.5">
{Array.from({ length: status.total }, (_, index) => (
<motion.span key={index} animate={{ opacity: index < status.step ? 1 : 0.24, scaleX: index < status.step ? 1 : 0.88 }} className="h-1.5 min-w-0 flex-1 rounded-full" style={{ background: index < status.step ? accent : theme.toolbar.itemHover, transformOrigin: "left" }} />
<motion.span
key={index}
animate={{ opacity: index < status.step ? 1 : 0.24, scaleX: index < status.step ? 1 : 0.88 }}
className="h-1.5 min-w-0 flex-1 rounded-full"
style={{ background: index < status.step ? accent : theme.toolbar.itemHover, transformOrigin: "left" }}
/>
))}
</div>
<span className="sr-only">{progress}%</span>
@@ -54,23 +73,39 @@ export function CanvasUploadStatusToast({ status, theme }: { status: CanvasUploa
}
export function TaskDetailItem({ label, value }: { label: string; value: string }) {
return <div className="min-w-0"><div className="text-[var(--fs-tiny)] opacity-50">{label}</div><div className="mt-1 truncate text-xs font-medium" title={value}>{value}</div></div>;
return (
<div className="min-w-0">
<div className="text-[var(--fs-tiny)] opacity-50">{label}</div>
<div className="mt-1 truncate text-xs font-medium" title={value}>
{value}
</div>
</div>
);
}
export function CanvasMergeStatusToast({ progress, theme }: { progress: MergeVideoProgress; theme: CanvasTheme }) {
const detail = progress.phase === "loading" ? "加载视频工具" : progress.phase === "reading" ? "读取选中视频" : "正在编码合并成片";
const percent = Math.max(0, Math.min(100, Math.round(progress.progress)));
return (
<div data-canvas-no-zoom aria-live="polite" className="pointer-events-none absolute right-4 top-[164px] z-[var(--z-panel-floating)] w-[292px] overflow-hidden rounded-2xl border px-3 py-3 shadow-lg backdrop-blur-xl" style={{ background: theme.toolbar.panel, borderColor: theme.toolbar.border, color: theme.node.text }}>
<div
data-canvas-no-zoom
aria-live="polite"
className="pointer-events-none absolute right-4 top-[164px] z-[var(--z-panel-floating)] w-[292px] overflow-hidden rounded-2xl border px-3 py-3 shadow-lg backdrop-blur-xl"
style={{ background: theme.toolbar.panel, borderColor: theme.toolbar.border, color: theme.node.text }}
>
<div className="flex items-start gap-2.5">
<span className="mt-0.5 grid size-7 shrink-0 place-items-center rounded-xl" style={{ background: theme.toolbar.itemHover, color: theme.node.activeStroke }}>
<LoaderCircle className="size-4 animate-spin" />
</span>
<span className="min-w-0 flex-1">
<span className="block truncate text-xs font-semibold">合并成片</span>
<span className="mt-0.5 block truncate text-[var(--fs-label)]" style={{ color: theme.node.muted }}>{detail}</span>
<span className="mt-0.5 block truncate text-[var(--fs-label)]" style={{ color: theme.node.muted }}>
{detail}
</span>
</span>
<span className="shrink-0 text-[var(--fs-tiny)] tabular-nums" style={{ color: theme.node.faint }}>
{percent}%
</span>
<span className="shrink-0 text-[var(--fs-tiny)] tabular-nums" style={{ color: theme.node.faint }}>{percent}%</span>
</div>
<div className="mt-2 h-1 overflow-hidden rounded-full" style={{ background: theme.toolbar.itemHover }}>
<div className="h-full rounded-full transition-all duration-300" style={{ width: `${percent}%`, background: theme.node.activeStroke }} />
@@ -81,15 +116,37 @@ export function CanvasMergeStatusToast({ progress, theme }: { progress: MergeVid
export function CanvasAgentChangeToast({ change, theme, onView, onUndo, onClose }: { change: CanvasAgentChange; theme: CanvasTheme; onView: () => void; onUndo: () => void; onClose: () => void }) {
return (
<div data-canvas-no-zoom aria-live="polite" className="absolute bottom-20 right-4 z-[var(--z-panel-floating)] w-[320px] rounded-lg border p-3 shadow-lg backdrop-blur-xl" style={{ background: theme.toolbar.panel, borderColor: theme.toolbar.border, color: theme.node.text }}>
<div
data-canvas-no-zoom
aria-live="polite"
className="absolute bottom-20 right-4 z-[var(--z-panel-floating)] w-[var(--panel-width-compact)] rounded-lg border p-3 shadow-lg backdrop-blur-xl"
style={{ background: theme.toolbar.panel, borderColor: theme.toolbar.border, color: theme.node.text }}
>
<div className="flex items-start gap-2.5">
<span className="grid size-8 shrink-0 place-items-center rounded-md" style={{ background: theme.toolbar.itemHover, color: theme.node.activeStroke }}><span className="size-2 rounded-full bg-current" /></span>
<span className="min-w-0 flex-1"><span className="block text-xs font-semibold">Agent 已写回画布</span><span className="mt-0.5 block truncate text-[var(--fs-label)]" style={{ color: theme.node.muted }}>{change.summary} · 可撤销最近 {change.undoCount} 批</span></span>
<button type="button" className="grid size-7 place-items-center rounded-md opacity-55 transition hover:opacity-100" onClick={onClose} aria-label="关闭"><X className="size-3.5" /></button>
<span className="grid size-8 shrink-0 place-items-center rounded-md" style={{ background: theme.toolbar.itemHover, color: theme.node.activeStroke }}>
<span className="size-2 rounded-full bg-current" />
</span>
<span className="min-w-0 flex-1">
<span className="block text-xs font-semibold">Agent 已写回画布</span>
<span className="mt-0.5 block truncate text-[var(--fs-label)]" style={{ color: theme.node.muted }}>
{change.summary} · 可撤销最近 {change.undoCount} 批
</span>
</span>
<button type="button" className="grid size-7 place-items-center rounded-md opacity-55 transition hover:opacity-100" onClick={onClose} aria-label="关闭">
<X className="size-3.5" />
</button>
</div>
<div className="mt-3 flex items-center justify-end gap-1.5">
{change.nodeIds.length ? <button type="button" className="inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs font-medium transition hover:bg-black/5 dark:hover:bg-white/10" onClick={onView}><Eye className="size-3.5" />查看本次改动</button> : null}
<button type="button" className="inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs font-medium transition hover:bg-black/5 dark:hover:bg-white/10" onClick={onUndo}><RotateCcw className="size-3.5" />撤销本次操作</button>
{change.nodeIds.length ? (
<button type="button" className="inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs font-medium transition hover:bg-black/5 dark:hover:bg-white/10" onClick={onView}>
<Eye className="size-3.5" />
查看本次改动
</button>
) : null}
<button type="button" className="inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs font-medium transition hover:bg-black/5 dark:hover:bg-white/10" onClick={onUndo}>
<RotateCcw className="size-3.5" />
撤销本次操作
</button>
</div>
</div>
);

View File

@@ -0,0 +1,38 @@
export function CanvasRefreshShell() {
return (
<main className="relative h-full min-h-0 overflow-hidden bg-background text-foreground">
<div
className="absolute inset-0 opacity-60"
style={{
backgroundImage: "radial-gradient(circle, var(--border) 1px, transparent 1px)",
backgroundSize: "28px 28px",
}}
/>
<div
className="absolute bottom-5 left-1/2 z-[var(--z-toolbar)] flex h-14 -translate-x-1/2 items-center gap-1 rounded-xl border px-2 shadow-lg backdrop-blur"
style={{ background: "var(--background)", borderColor: "var(--border)" }}
aria-hidden="true"
>
{Array.from({ length: 7 }).map((_, index) => (
<div key={index} className="size-8 rounded-md bg-current opacity-10" />
))}
</div>
<div className="absolute bottom-24 left-6 z-[var(--z-toolbar)] h-40 w-[240px] rounded-lg border shadow-2xl backdrop-blur-sm" style={{ background: "var(--background)", borderColor: "var(--border)" }} aria-hidden="true">
<div className="absolute left-7 top-7 h-5 w-12 rounded-sm bg-current opacity-10" />
<div className="absolute left-28 top-16 h-6 w-16 rounded-sm bg-current opacity-10" />
<div className="absolute bottom-7 left-16 h-8 w-20 rounded-sm bg-current opacity-10" />
<div className="absolute inset-5 rounded border border-current opacity-15" />
</div>
<div className="absolute bottom-5 left-5 z-[var(--z-toolbar)] flex h-14 w-[260px] items-center gap-2 rounded-xl border px-2 shadow-lg backdrop-blur" style={{ background: "var(--background)", borderColor: "var(--border)" }} aria-hidden="true">
<div className="size-8 rounded-md bg-current opacity-10" />
<div className="size-8 rounded-md bg-current opacity-10" />
<div className="h-1 flex-1 rounded-full bg-current opacity-10" />
<div className="h-4 w-10 rounded bg-current opacity-10" />
<div className="size-8 rounded-md bg-current opacity-10" />
</div>
</main>
);
}

File diff suppressed because it is too large Load Diff