diff --git a/web/src/components/table/channels/ChannelsColumnDefs.jsx b/web/src/components/table/channels/ChannelsColumnDefs.jsx
index 7fdd71b0..5d748c0f 100644
--- a/web/src/components/table/channels/ChannelsColumnDefs.jsx
+++ b/web/src/components/table/channels/ChannelsColumnDefs.jsx
@@ -538,19 +538,24 @@ export const getChannelsColumns = ({
updateChannelBalance(record)}
>
- {renderQuotaWithAmount(record.balance)}
+ {record.type === 57
+ ? t('帐号信息')
+ : renderQuotaWithAmount(record.balance)}
diff --git a/web/src/components/table/channels/modals/CodexUsageModal.jsx b/web/src/components/table/channels/modals/CodexUsageModal.jsx
index 76c84b90..1a42eafd 100644
--- a/web/src/components/table/channels/modals/CodexUsageModal.jsx
+++ b/web/src/components/table/channels/modals/CodexUsageModal.jsx
@@ -22,9 +22,11 @@ import {
Modal,
Button,
Progress,
- Tag,
Typography,
Spin,
+ Tag,
+ Descriptions,
+ Collapse,
} from '@douyinfe/semi-ui';
import { API, showError } from '../../../../helpers';
@@ -128,6 +130,87 @@ const formatUnixSeconds = (unixSeconds) => {
}
};
+const getDisplayText = (value) => {
+ if (value == null) return '';
+ return String(value).trim();
+};
+
+const formatAccountTypeLabel = (value, t) => {
+ const tt = typeof t === 'function' ? t : (v) => v;
+ const normalized = normalizePlanType(value);
+ switch (normalized) {
+ case 'free':
+ return 'Free';
+ case 'plus':
+ return 'Plus';
+ case 'pro':
+ return 'Pro';
+ case 'team':
+ return 'Team';
+ case 'enterprise':
+ return 'Enterprise';
+ default:
+ return getDisplayText(value) || tt('未识别');
+ }
+};
+
+const getAccountTypeTagColor = (value) => {
+ const normalized = normalizePlanType(value);
+ switch (normalized) {
+ case 'enterprise':
+ return 'green';
+ case 'team':
+ return 'cyan';
+ case 'pro':
+ return 'blue';
+ case 'plus':
+ return 'violet';
+ case 'free':
+ return 'amber';
+ default:
+ return 'grey';
+ }
+};
+
+const resolveUsageStatusTag = (t, rateLimit) => {
+ const tt = typeof t === 'function' ? t : (v) => v;
+ if (!rateLimit || Object.keys(rateLimit).length === 0) {
+ return {tt('待确认')};
+ }
+ if (rateLimit?.allowed && !rateLimit?.limit_reached) {
+ return {tt('可用')};
+ }
+ return {tt('受限')};
+};
+
+const AccountInfoValue = ({ t, value, onCopy, monospace = false }) => {
+ const tt = typeof t === 'function' ? t : (v) => v;
+ const text = getDisplayText(value);
+ const hasValue = text !== '';
+
+ return (
+
+
+ {hasValue ? text : '-'}
+
+
+
+ );
+};
+
const RateLimitWindowCard = ({ t, title, windowData }) => {
const tt = typeof t === 'function' ? t : (v) => v;
const hasWindowData =
@@ -181,50 +264,100 @@ const RateLimitWindowCard = ({ t, title, windowData }) => {
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 allowed = !!rateLimit?.allowed;
- const limitReached = !!rateLimit?.limit_reached;
const upstreamStatus = payload?.upstream_status;
-
- const statusTag =
- allowed && !limitReached ? (
- {tt('可用')}
- ) : (
- {tt('受限')}
- );
+ const accountType = data?.plan_type ?? rateLimit?.plan_type;
+ const accountTypeLabel = formatAccountTypeLabel(accountType, tt);
+ const accountTypeTagColor = getAccountTypeTagColor(accountType);
+ const statusTag = resolveUsageStatusTag(tt, rateLimit);
+ const userId = data?.user_id;
+ const email = data?.email;
+ const accountId = data?.account_id;
+ const errorMessage =
+ payload?.success === false ? getDisplayText(payload?.message) || tt('获取用量失败') : '';
const rawText =
typeof data === 'string' ? data : JSON.stringify(data ?? payload, null, 2);
return (
-
-
-
- {tt('渠道:')}
- {record?.name || '-'} ({tt('编号:')}
- {record?.id || '-'})
-
-
- {statusTag}
-