Просмотр исходного кода

fix: 修正 Codex free 账号用量显示到每周窗口

reed 1 месяц назад
Родитель
Сommit
5bb8fe6af5
1 измененных файлов с 83 добавлено и 15 удалено
  1. 83 15
      web/src/components/table/channels/modals/CodexUsageModal.jsx

+ 83 - 15
web/src/components/table/channels/modals/CodexUsageModal.jsx

@@ -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'>
-        <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 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 primary = rateLimit?.primary_window ?? null;
-  const secondary = rateLimit?.secondary_window ?? null;
+  const { fiveHourWindow, weeklyWindow } = resolveRateLimitWindows(data);
 
 
   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>