feat: redesign quota summary for v0.3.0
This commit is contained in:
+67
-17
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user