chore: refine codex usage modal layout (#4386)

* chore: refine codex usage modal layout

* fix: polish codex usage modal responsiveness
This commit is contained in:
Seefs
2026-04-22 22:54:28 +08:00
committed by GitHub
parent 6afaa58d28
commit d586a567e4
@@ -29,6 +29,7 @@ import {
Collapse,
} from '@douyinfe/semi-ui';
import { API, showError } from '../../../../helpers';
import { MOBILE_BREAKPOINT } from '../../../../hooks/common/useIsMobile';
const { Text } = Typography;
@@ -98,10 +99,12 @@ const resolveRateLimitWindows = (data) => {
}
if (!fiveHourWindow) {
fiveHourWindow = windows.find((windowData) => windowData !== weeklyWindow) ?? null;
fiveHourWindow =
windows.find((windowData) => windowData !== weeklyWindow) ?? null;
}
if (!weeklyWindow) {
weeklyWindow = windows.find((windowData) => windowData !== fiveHourWindow) ?? null;
weeklyWindow =
windows.find((windowData) => windowData !== fiveHourWindow) ?? null;
}
return { fiveHourWindow, weeklyWindow };
@@ -135,6 +138,40 @@ const getDisplayText = (value) => {
return String(value).trim();
};
const isMobileViewport = () =>
typeof window !== 'undefined' && window.innerWidth < MOBILE_BREAKPOINT;
const getCodexUsageModalLayout = () => {
if (isMobileViewport()) {
return {
width: 'calc(100vw - 16px)',
style: {
top: 8,
maxWidth: 'calc(100vw - 16px)',
margin: '0 auto',
},
bodyStyle: {
maxHeight: 'calc(100vh - 148px)',
overflowY: 'auto',
padding: '16px 16px 12px',
},
};
}
return {
width: 900,
style: {
top: 24,
maxWidth: 'min(900px, 92vw)',
},
bodyStyle: {
maxHeight: 'calc(100vh - 172px)',
overflowY: 'auto',
padding: '20px 24px 16px',
},
};
};
const formatAccountTypeLabel = (value, t) => {
const tt = typeof t === 'function' ? t : (v) => v;
const normalized = normalizePlanType(value);
@@ -224,7 +261,7 @@ const RateLimitWindowCard = ({ t, title, windowData }) => {
return (
<div className='rounded-lg border border-semi-color-border bg-semi-color-bg-0 p-3'>
<div className='flex items-center justify-between gap-2'>
<div className='flex flex-wrap items-start justify-between gap-x-3 gap-y-1'>
<div className='font-medium'>{title}</div>
<Text type='tertiary' size='small'>
{tt('重置时间:')}
@@ -262,12 +299,86 @@ const RateLimitWindowCard = ({ t, title, windowData }) => {
);
};
const RateLimitWindowGrid = ({ t, fiveHourWindow, weeklyWindow }) => {
const tt = typeof t === 'function' ? t : (v) => v;
return (
<div className='grid grid-cols-1 gap-3 md:grid-cols-2'>
<RateLimitWindowCard
t={tt}
title={tt('5小时窗口')}
windowData={fiveHourWindow}
/>
<RateLimitWindowCard
t={tt}
title={tt('每周窗口')}
windowData={weeklyWindow}
/>
</div>
);
};
const RateLimitGroupSection = ({
t,
title,
description,
rateLimitSource,
statusTag,
meteredFeature,
}) => {
const tt = typeof t === 'function' ? t : (v) => v;
const { fiveHourWindow, weeklyWindow } =
resolveRateLimitWindows(rateLimitSource);
const featureText = getDisplayText(meteredFeature);
return (
<section className='space-y-3'>
<div className='flex flex-wrap items-start justify-between gap-3'>
<div className='min-w-0 space-y-2'>
<div className='flex flex-wrap items-center gap-2'>
<div className='text-sm font-semibold text-semi-color-text-0'>
{title}
</div>
{statusTag}
</div>
{(description || featureText) && (
<div className='flex flex-wrap items-center gap-2 text-xs text-semi-color-text-2'>
{description ? <span>{description}</span> : null}
{featureText ? (
<div className='inline-flex max-w-full items-center gap-2 rounded-full bg-semi-color-fill-0 px-2 py-1'>
<span className='text-[11px] text-semi-color-text-2'>
metered_feature
</span>
<span className='min-w-0 break-all font-mono text-xs text-semi-color-text-0'>
{featureText}
</span>
</div>
) : null}
</div>
)}
</div>
</div>
<RateLimitWindowGrid
t={tt}
fiveHourWindow={fiveHourWindow}
weeklyWindow={weeklyWindow}
/>
</section>
);
};
const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => {
const tt = typeof t === 'function' ? t : (v) => v;
const [showRawJson, setShowRawJson] = useState(false);
const data = payload?.data ?? null;
const rateLimit = data?.rate_limit ?? {};
const { fiveHourWindow, weeklyWindow } = resolveRateLimitWindows(data);
const additionalRateLimits = Array.isArray(data?.additional_rate_limits)
? data.additional_rate_limits.filter(
(item) =>
item && typeof item === 'object' && Object.keys(item).length > 0,
)
: [];
const upstreamStatus = payload?.upstream_status;
const accountType = data?.plan_type ?? rateLimit?.plan_type;
const accountTypeLabel = formatAccountTypeLabel(accountType, tt);
@@ -277,7 +388,9 @@ const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => {
const email = data?.email;
const accountId = data?.account_id;
const errorMessage =
payload?.success === false ? getDisplayText(payload?.message) || tt('获取用量失败') : '';
payload?.success === false
? getDisplayText(payload?.message) || tt('获取用量失败')
: '';
const rawText =
typeof data === 'string' ? data : JSON.stringify(data ?? payload, null, 2);
@@ -313,7 +426,12 @@ const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => {
</Tag>
</div>
</div>
<Button size='small' type='tertiary' theme='outline' onClick={onRefresh}>
<Button
size='small'
type='tertiary'
theme='outline'
onClick={onRefresh}
>
{tt('刷新')}
</Button>
</div>
@@ -355,22 +473,61 @@ const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => {
{tt('额度窗口')}
</div>
<Text type='tertiary' size='small'>
{tt('用于观察当前帐号在 Codex 上游的限额使用情况')}
{tt(
'用于观察当前帐号在 Codex 上游的基础限额与附加计费能力使用情况',
)}
</Text>
</div>
</div>
<div className='grid grid-cols-1 gap-3 md:grid-cols-2'>
<RateLimitWindowCard
<div className='space-y-5'>
<RateLimitGroupSection
t={tt}
title={tt('5小时窗口')}
windowData={fiveHourWindow}
/>
<RateLimitWindowCard
t={tt}
title={tt('每周窗口')}
windowData={weeklyWindow}
title={tt('基础额度')}
description={tt('当前帐号的基础额度窗口')}
rateLimitSource={data}
statusTag={statusTag}
/>
{additionalRateLimits.length > 0 ? (
<div className='space-y-4 border-t border-semi-color-border pt-4'>
<div>
<div className='text-sm font-semibold text-semi-color-text-0'>
{tt('附加额度')}
</div>
<Text type='tertiary' size='small'>
{tt('按模型或能力拆分的附加计费能力窗口')}
</Text>
</div>
<div className='space-y-4'>
{additionalRateLimits.map((item, index) => {
const limitName =
getDisplayText(item?.limit_name) ||
getDisplayText(item?.metered_feature) ||
`${tt('附加额度')} ${index + 1}`;
return (
<div
key={`${limitName}-${getDisplayText(item?.metered_feature)}-${index}`}
className={
index > 0 ? 'border-t border-semi-color-border pt-4' : ''
}
>
<RateLimitGroupSection
t={tt}
title={limitName}
description={tt('附加计费能力')}
rateLimitSource={item}
statusTag={resolveUsageStatusTag(tt, item?.rate_limit)}
meteredFeature={item?.metered_feature}
/>
</div>
);
})}
</div>
</div>
) : null}
</div>
<Collapse
@@ -489,12 +646,14 @@ const CodexUsageLoader = ({ t, record, initialPayload, onCopy }) => {
export const openCodexUsageModal = ({ t, record, payload, onCopy }) => {
const tt = typeof t === 'function' ? t : (v) => v;
const layout = getCodexUsageModalLayout();
Modal.info({
title: tt('Codex 帐号与用量'),
centered: true,
width: 900,
style: { maxWidth: '95vw' },
centered: false,
width: layout.width,
style: layout.style,
bodyStyle: layout.bodyStyle,
content: (
<CodexUsageLoader
t={tt}