mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-18 10:40:50 +08:00
fix: error display
This commit is contained in:
@@ -34,6 +34,8 @@
|
||||
"alias": "Alias",
|
||||
"failure": "Failure",
|
||||
"unknown_error": "Unknown error",
|
||||
"quota_update_required": "Please update the CPA version or check for updates",
|
||||
"quota_check_credential": "Please check the credential status",
|
||||
"copy": "Copy",
|
||||
"custom_headers_label": "Custom Headers",
|
||||
"custom_headers_hint": "Optional HTTP headers to send with the request. Leave blank to remove.",
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
"alias": "别名",
|
||||
"failure": "失败",
|
||||
"unknown_error": "未知错误",
|
||||
"quota_update_required": "请更新 CPA 版本或检查更新",
|
||||
"quota_check_credential": "请检查凭证状态",
|
||||
"copy": "复制",
|
||||
"custom_headers_label": "自定义请求头",
|
||||
"custom_headers_hint": "可选,设置需要附带到请求中的 HTTP 头,名称和值均不能为空。",
|
||||
|
||||
@@ -96,6 +96,7 @@ interface AntigravityQuotaState {
|
||||
status: 'idle' | 'loading' | 'success' | 'error';
|
||||
groups: AntigravityQuotaGroup[];
|
||||
error?: string;
|
||||
errorStatus?: number;
|
||||
}
|
||||
|
||||
interface AntigravityQuotaInfo {
|
||||
@@ -213,6 +214,7 @@ interface CodexQuotaState {
|
||||
windows: CodexQuotaWindow[];
|
||||
planType?: string | null;
|
||||
error?: string;
|
||||
errorStatus?: number;
|
||||
}
|
||||
|
||||
const CODEX_USAGE_URL = 'https://chatgpt.com/backend-api/wham/usage';
|
||||
@@ -223,6 +225,28 @@ const CODEX_REQUEST_HEADERS = {
|
||||
'User-Agent': 'codex_cli_rs/0.76.0 (Debian 13.0.0; x86_64) WindowsTerminal'
|
||||
};
|
||||
|
||||
const createStatusError = (message: string, status?: number) => {
|
||||
const error = new Error(message) as Error & { status?: number };
|
||||
if (status !== undefined) {
|
||||
error.status = status;
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
const getStatusFromError = (err: unknown): number | undefined => {
|
||||
if (typeof err === 'object' && err !== null && 'status' in err) {
|
||||
const rawStatus = (err as { status?: unknown }).status;
|
||||
if (typeof rawStatus === 'number' && Number.isFinite(rawStatus)) {
|
||||
return rawStatus;
|
||||
}
|
||||
const asNumber = Number(rawStatus);
|
||||
if (Number.isFinite(asNumber) && asNumber > 0) {
|
||||
return asNumber;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 标准化 auth_index 值(与 usage.ts 中的 normalizeAuthIndex 保持一致)
|
||||
@@ -780,6 +804,8 @@ export function AuthFilesPage() {
|
||||
const fetchAntigravityQuota = useCallback(
|
||||
async (authIndex: string): Promise<AntigravityQuotaGroup[]> => {
|
||||
let lastError = '';
|
||||
let lastStatus: number | undefined;
|
||||
let priorityStatus: number | undefined;
|
||||
let hadSuccess = false;
|
||||
|
||||
for (const url of ANTIGRAVITY_QUOTA_URLS) {
|
||||
@@ -794,6 +820,10 @@ export function AuthFilesPage() {
|
||||
|
||||
if (result.statusCode < 200 || result.statusCode >= 300) {
|
||||
lastError = getApiCallErrorMessage(result);
|
||||
lastStatus = result.statusCode;
|
||||
if (result.statusCode === 403 || result.statusCode === 404) {
|
||||
priorityStatus ??= result.statusCode;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -814,6 +844,13 @@ export function AuthFilesPage() {
|
||||
return groups;
|
||||
} catch (err: unknown) {
|
||||
lastError = err instanceof Error ? err.message : t('common.unknown_error');
|
||||
const status = getStatusFromError(err);
|
||||
if (status) {
|
||||
lastStatus = status;
|
||||
if (status === 403 || status === 404) {
|
||||
priorityStatus ??= status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,7 +858,7 @@ export function AuthFilesPage() {
|
||||
return [];
|
||||
}
|
||||
|
||||
throw new Error(lastError || t('common.unknown_error'));
|
||||
throw createStatusError(lastError || t('common.unknown_error'), priorityStatus ?? lastStatus);
|
||||
},
|
||||
[t]
|
||||
);
|
||||
@@ -862,7 +899,8 @@ export function AuthFilesPage() {
|
||||
return { name: file.name, status: 'success' as const, groups };
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : t('common.unknown_error');
|
||||
return { name: file.name, status: 'error' as const, error: message };
|
||||
const errorStatus = getStatusFromError(err);
|
||||
return { name: file.name, status: 'error' as const, error: message, errorStatus };
|
||||
}
|
||||
})
|
||||
);
|
||||
@@ -881,7 +919,8 @@ export function AuthFilesPage() {
|
||||
nextState[result.name] = {
|
||||
status: 'error',
|
||||
groups: [],
|
||||
error: result.error
|
||||
error: result.error,
|
||||
errorStatus: result.errorStatus
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -953,7 +992,7 @@ export function AuthFilesPage() {
|
||||
header: requestHeader
|
||||
});
|
||||
if (result.statusCode < 200 || result.statusCode >= 300) {
|
||||
throw new Error(getApiCallErrorMessage(result));
|
||||
throw createStatusError(getApiCallErrorMessage(result), result.statusCode);
|
||||
}
|
||||
const payload = parseCodexUsagePayload(result.body ?? result.bodyText);
|
||||
if (!payload) {
|
||||
@@ -1001,7 +1040,8 @@ export function AuthFilesPage() {
|
||||
return { name: file.name, status: 'success' as const, planType, windows };
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : t('common.unknown_error');
|
||||
return { name: file.name, status: 'error' as const, error: message };
|
||||
const errorStatus = getStatusFromError(err);
|
||||
return { name: file.name, status: 'error' as const, error: message, errorStatus };
|
||||
}
|
||||
})
|
||||
);
|
||||
@@ -1021,7 +1061,8 @@ export function AuthFilesPage() {
|
||||
nextState[result.name] = {
|
||||
status: 'error',
|
||||
windows: [],
|
||||
error: result.error
|
||||
error: result.error,
|
||||
errorStatus: result.errorStatus
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -1383,6 +1424,15 @@ export function AuthFilesPage() {
|
||||
if (normalized === 'free') return t('codex_quota.plan_free');
|
||||
return planType || normalized;
|
||||
};
|
||||
|
||||
const getQuotaErrorMessage = useCallback(
|
||||
(status: number | undefined, fallback: string) => {
|
||||
if (status === 404) return t('common.quota_update_required');
|
||||
if (status === 403) return t('common.quota_check_credential');
|
||||
return fallback;
|
||||
},
|
||||
[t]
|
||||
);
|
||||
|
||||
// OAuth 排除相关方法
|
||||
const openExcludedModal = (provider?: string) => {
|
||||
@@ -1627,6 +1677,10 @@ export function AuthFilesPage() {
|
||||
const quotaState = antigravityQuota[item.name];
|
||||
const quotaStatus = quotaState?.status ?? 'idle';
|
||||
const quotaGroups = quotaState?.groups ?? [];
|
||||
const quotaErrorMessage = getQuotaErrorMessage(
|
||||
quotaState?.errorStatus,
|
||||
quotaState?.error || t('common.unknown_error')
|
||||
);
|
||||
|
||||
return (
|
||||
<div key={item.name} className={`${styles.fileCard} ${styles.antigravityCard}`}>
|
||||
@@ -1652,7 +1706,7 @@ export function AuthFilesPage() {
|
||||
) : quotaStatus === 'error' ? (
|
||||
<div className={styles.quotaError}>
|
||||
{t('antigravity_quota.load_failed', {
|
||||
message: quotaState?.error || t('common.unknown_error')
|
||||
message: quotaErrorMessage
|
||||
})}
|
||||
</div>
|
||||
) : quotaGroups.length === 0 ? (
|
||||
@@ -1703,6 +1757,10 @@ export function AuthFilesPage() {
|
||||
const planType = quotaState?.planType ?? null;
|
||||
const planLabel = getCodexPlanLabel(planType);
|
||||
const isFreePlan = normalizePlanType(planType) === 'free';
|
||||
const quotaErrorMessage = getQuotaErrorMessage(
|
||||
quotaState?.errorStatus,
|
||||
quotaState?.error || t('common.unknown_error')
|
||||
);
|
||||
|
||||
return (
|
||||
<div key={item.name} className={`${styles.fileCard} ${styles.codexCard}`}>
|
||||
@@ -1728,7 +1786,7 @@ export function AuthFilesPage() {
|
||||
) : quotaStatus === 'error' ? (
|
||||
<div className={styles.quotaError}>
|
||||
{t('codex_quota.load_failed', {
|
||||
message: quotaState?.error || t('common.unknown_error')
|
||||
message: quotaErrorMessage
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user