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