Merge pull request #3316 from Honghurumeng/main
fix: 修正 Codex free 账号用量显示到每周窗口
This commit is contained in:
@@ -43,6 +43,68 @@ const pickStrokeColor = (percent) => {
|
||||
return '#3b82f6';
|
||||
};
|
||||
|
||||
const normalizePlanType = (value) => {
|
||||
if (value == null) return '';
|
||||
return String(value).trim().toLowerCase();
|
||||
};
|
||||
|
||||
const getWindowDurationSeconds = (windowData) => {
|
||||
const value = Number(windowData?.limit_window_seconds);
|
||||
if (!Number.isFinite(value) || value <= 0) return null;
|
||||
return value;
|
||||
};
|
||||
|
||||
const classifyWindowByDuration = (windowData) => {
|
||||
const seconds = getWindowDurationSeconds(windowData);
|
||||
if (seconds == null) return null;
|
||||
return seconds >= 24 * 60 * 60 ? 'weekly' : 'fiveHour';
|
||||
};
|
||||
|
||||
const resolveRateLimitWindows = (data) => {
|
||||
const rateLimit = data?.rate_limit ?? {};
|
||||
const primary = rateLimit?.primary_window ?? null;
|
||||
const secondary = rateLimit?.secondary_window ?? null;
|
||||
const windows = [primary, secondary].filter(Boolean);
|
||||
const planType = normalizePlanType(data?.plan_type ?? rateLimit?.plan_type);
|
||||
|
||||
let fiveHourWindow = null;
|
||||
let weeklyWindow = null;
|
||||
|
||||
for (const windowData of windows) {
|
||||
const bucket = classifyWindowByDuration(windowData);
|
||||
if (bucket === 'fiveHour' && !fiveHourWindow) {
|
||||
fiveHourWindow = windowData;
|
||||
continue;
|
||||
}
|
||||
if (bucket === 'weekly' && !weeklyWindow) {
|
||||
weeklyWindow = windowData;
|
||||
}
|
||||
}
|
||||
|
||||
if (planType === 'free') {
|
||||
if (!weeklyWindow) {
|
||||
weeklyWindow = primary ?? secondary ?? null;
|
||||
}
|
||||
return { fiveHourWindow: null, weeklyWindow };
|
||||
}
|
||||
|
||||
if (!fiveHourWindow && !weeklyWindow) {
|
||||
return {
|
||||
fiveHourWindow: primary ?? null,
|
||||
weeklyWindow: secondary ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
if (!fiveHourWindow) {
|
||||
fiveHourWindow = windows.find((windowData) => windowData !== weeklyWindow) ?? null;
|
||||
}
|
||||
if (!weeklyWindow) {
|
||||
weeklyWindow = windows.find((windowData) => windowData !== fiveHourWindow) ?? null;
|
||||
}
|
||||
|
||||
return { fiveHourWindow, weeklyWindow };
|
||||
};
|
||||
|
||||
const formatDurationSeconds = (seconds, t) => {
|
||||
const tt = typeof t === 'function' ? t : (v) => v;
|
||||
const s = Number(seconds);
|
||||
@@ -68,6 +130,10 @@ const formatUnixSeconds = (unixSeconds) => {
|
||||
|
||||
const RateLimitWindowCard = ({ t, title, windowData }) => {
|
||||
const tt = typeof t === 'function' ? t : (v) => v;
|
||||
const hasWindowData =
|
||||
!!windowData &&
|
||||
typeof windowData === 'object' &&
|
||||
Object.keys(windowData).length > 0;
|
||||
const percent = clampPercent(windowData?.used_percent ?? 0);
|
||||
const resetAt = windowData?.reset_at;
|
||||
const resetAfterSeconds = windowData?.reset_after_seconds;
|
||||
@@ -83,26 +149,30 @@ const RateLimitWindowCard = ({ t, title, windowData }) => {
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className='mt-2'>
|
||||
<Progress
|
||||
percent={percent}
|
||||
stroke={pickStrokeColor(percent)}
|
||||
showInfo={true}
|
||||
/>
|
||||
</div>
|
||||
{hasWindowData ? (
|
||||
<div className='mt-2'>
|
||||
<Progress
|
||||
percent={percent}
|
||||
stroke={pickStrokeColor(percent)}
|
||||
showInfo={true}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className='mt-3 text-sm text-semi-color-text-2'>-</div>
|
||||
)}
|
||||
|
||||
<div className='mt-1 flex flex-wrap items-center gap-2 text-xs text-semi-color-text-2'>
|
||||
<div>
|
||||
{tt('已使用:')}
|
||||
{percent}%
|
||||
{hasWindowData ? `${percent}%` : '-'}
|
||||
</div>
|
||||
<div>
|
||||
{tt('距离重置:')}
|
||||
{formatDurationSeconds(resetAfterSeconds, tt)}
|
||||
{hasWindowData ? formatDurationSeconds(resetAfterSeconds, tt) : '-'}
|
||||
</div>
|
||||
<div>
|
||||
{tt('窗口:')}
|
||||
{formatDurationSeconds(limitWindowSeconds, tt)}
|
||||
{hasWindowData ? formatDurationSeconds(limitWindowSeconds, tt) : '-'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -113,9 +183,7 @@ const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => {
|
||||
const tt = typeof t === 'function' ? t : (v) => v;
|
||||
const data = payload?.data ?? null;
|
||||
const rateLimit = data?.rate_limit ?? {};
|
||||
|
||||
const primary = rateLimit?.primary_window ?? null;
|
||||
const secondary = rateLimit?.secondary_window ?? null;
|
||||
const { fiveHourWindow, weeklyWindow } = resolveRateLimitWindows(data);
|
||||
|
||||
const allowed = !!rateLimit?.allowed;
|
||||
const limitReached = !!rateLimit?.limit_reached;
|
||||
@@ -163,12 +231,12 @@ const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => {
|
||||
<RateLimitWindowCard
|
||||
t={tt}
|
||||
title={tt('5小时窗口')}
|
||||
windowData={primary}
|
||||
windowData={fiveHourWindow}
|
||||
/>
|
||||
<RateLimitWindowCard
|
||||
t={tt}
|
||||
title={tt('每周窗口')}
|
||||
windowData={secondary}
|
||||
windowData={weeklyWindow}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user