feat: redesign quota summary for v0.3.0

This commit is contained in:
2026-08-30 17:50:15 +08:00
parent 54e20f7b8c
commit 0a639c1f68
8 changed files with 161 additions and 28 deletions
+67 -17
View File
@@ -632,24 +632,44 @@ function AccountQuickSummary({
: "等待数据"}
</span>
);
const remaining = dashboard.limits.length
? Math.min(...dashboard.limits.map((limit) => remainingPercent(limit)))
: null;
const reset = dashboard.limits
.map((limit) => limit.resetsAt)
.filter((value) => value > 0)
.sort((a, b) => a - b)[0];
const limits = quickSummaryLimits(dashboard.limits);
if (!limits.length)
return <span className="account-summary-metrics">限额暂无</span>;
return (
<span className="account-summary-metrics">
<span>
{remaining == null ? "限额暂无" : `最低 ${Math.round(remaining)}% 剩余`}
</span>
<span>
{dashboard.currentCycle == null
? "本周期 Token 暂无"
: `本周期 ${num(dashboard.currentCycle.totalTokens)} Tokens`}
</span>
<span>{reset ? `最近重置 ${relative(reset)}` : "暂无重置时间"}</span>
<span
className={`account-summary-metrics account-summary-limits${limits.length === 1 ? " single" : ""}`}
>
{limits.map(({ kind, limit }) => {
const remaining = Math.round(remainingPercent(limit));
return (
<span
className="account-summary-limit"
data-window-kind={kind}
key={`${kind}-${limit.limitId}-${limit.windowType}`}
aria-label={`${quickLimitLabel(kind, limit)},剩余 ${remaining}%,${limit.resetsAt ? `${relative(limit.resetsAt)}重置` : "重置时间暂无"}`}
>
<span className="account-summary-limit-name">
{quickLimitLabel(kind, limit)}
</span>
<strong style={{ color: `hsl(${remaining * 1.2} 70% 45%)` }}>
{remaining}%
</strong>
<span className="account-summary-limit-remaining">剩余</span>
<span
className="account-summary-limit-reset"
title={
limit.resetsAt
? new Date(limit.resetsAt * 1000).toLocaleString()
: undefined
}
>
{limit.resetsAt
? `${relative(limit.resetsAt)}重置`
: "重置时间暂无"}
</span>
</span>
);
})}
</span>
);
}
@@ -1670,6 +1690,36 @@ const cycleDuration = (minutes: number) =>
: `${minutes} 分钟窗口`;
const remainingPercent = (limit: Limit) =>
100 - Math.min(100, Math.max(0, limit.usedPercent));
type QuickLimitKind = "hour" | "week" | "other";
const quickSummaryLimits = (
limits: Limit[],
): Array<{ kind: QuickLimitKind; limit: Limit }> => {
const sorted = [...limits].sort(
(a, b) => a.windowDurationMinutes - b.windowDurationMinutes,
);
const hour = sorted.find(
(limit) =>
limit.windowDurationMinutes > 0 && limit.windowDurationMinutes < 24 * 60,
);
const week = sorted.find(
(limit) =>
limit.windowDurationMinutes >= 6 * 24 * 60 &&
limit.windowDurationMinutes <= 8 * 24 * 60,
);
const selected: Array<{ kind: QuickLimitKind; limit: Limit }> = [];
if (hour) selected.push({ kind: "hour", limit: hour });
if (week && week !== hour) selected.push({ kind: "week", limit: week });
if (selected.length) return selected;
return sorted.slice(0, 2).map((limit) => ({ kind: "other", limit }));
};
const quickLimitLabel = (kind: QuickLimitKind, limit: Limit) => {
if (kind === "week") return "周额度";
if (kind === "hour") {
const hours = limit.windowDurationMinutes / 60;
return `${Number.isInteger(hours) ? hours : hours.toFixed(1)} 小时额度`;
}
return limitLabel(limit).replace(/限额$/, "额度");
};
const limitLabel = (limit: Limit) => {
if (limit.limitName) return limit.limitName;
if (limit.windowDurationMinutes >= 60) {