mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-06-16 21:03:58 +08:00
Compare commits
1 Commits
@@ -87,7 +87,7 @@ const DEFAULT_ANTIGRAVITY_PROJECT_ID = 'bamboo-precept-lgxtn';
|
||||
const geminiCliSupplementaryRequestIds = new Map<string, number>();
|
||||
const geminiCliSupplementaryCache = new Map<
|
||||
string,
|
||||
{ requestId: number; tierLabel: string | null; creditBalance: number | null }
|
||||
{ requestId: number; tierLabel: string | null; tierId: string | null; creditBalance: number | null }
|
||||
>();
|
||||
|
||||
export interface QuotaStore {
|
||||
@@ -444,6 +444,8 @@ const GEMINI_CLI_TIER_LABELS: Record<string, string> = {
|
||||
'free-tier': 'tier_free',
|
||||
'legacy-tier': 'tier_legacy',
|
||||
'standard-tier': 'tier_standard',
|
||||
'g1-pro-tier': 'tier_pro',
|
||||
'g1-ultra-tier': 'tier_ultra',
|
||||
};
|
||||
|
||||
const resolveGeminiCliTierLabel = (
|
||||
@@ -455,10 +457,23 @@ const resolveGeminiCliTierLabel = (
|
||||
payload.currentTier ?? payload.current_tier;
|
||||
const paidTier: GeminiCliUserTier | null | undefined =
|
||||
payload.paidTier ?? payload.paid_tier;
|
||||
const tierId = normalizeStringValue(paidTier?.id) ?? normalizeStringValue(currentTier?.id);
|
||||
if (!tierId) return null;
|
||||
const rawId = normalizeStringValue(paidTier?.id) ?? normalizeStringValue(currentTier?.id);
|
||||
if (!rawId) return null;
|
||||
const tierId = rawId.toLowerCase();
|
||||
const labelKey = GEMINI_CLI_TIER_LABELS[tierId];
|
||||
return labelKey ? t(`gemini_cli_quota.${labelKey}`) : tierId;
|
||||
return labelKey ? t(`gemini_cli_quota.${labelKey}`) : rawId;
|
||||
};
|
||||
|
||||
const resolveGeminiCliTierId = (
|
||||
payload: GeminiCliCodeAssistPayload | null
|
||||
): string | null => {
|
||||
if (!payload) return null;
|
||||
const currentTier: GeminiCliUserTier | null | undefined =
|
||||
payload.currentTier ?? payload.current_tier;
|
||||
const paidTier: GeminiCliUserTier | null | undefined =
|
||||
payload.paidTier ?? payload.paid_tier;
|
||||
const rawId = normalizeStringValue(paidTier?.id) ?? normalizeStringValue(currentTier?.id);
|
||||
return rawId ? rawId.toLowerCase() : null;
|
||||
};
|
||||
|
||||
const resolveGeminiCliCreditBalance = (
|
||||
@@ -491,7 +506,7 @@ const fetchGeminiCliCodeAssist = async (
|
||||
authIndex: string,
|
||||
projectId: string,
|
||||
t: TFunction
|
||||
): Promise<{ tierLabel: string | null; creditBalance: number | null }> => {
|
||||
): Promise<{ tierLabel: string | null; tierId: string | null; creditBalance: number | null }> => {
|
||||
try {
|
||||
const result = await apiCallApi.request({
|
||||
authIndex,
|
||||
@@ -510,30 +525,32 @@ const fetchGeminiCliCodeAssist = async (
|
||||
});
|
||||
|
||||
if (result.statusCode < 200 || result.statusCode >= 300) {
|
||||
return { tierLabel: null, creditBalance: null };
|
||||
return { tierLabel: null, tierId: null, creditBalance: null };
|
||||
}
|
||||
|
||||
const payload = parseGeminiCliCodeAssistPayload(result.body ?? result.bodyText);
|
||||
return {
|
||||
tierLabel: resolveGeminiCliTierLabel(payload, t),
|
||||
tierId: resolveGeminiCliTierId(payload),
|
||||
creditBalance: resolveGeminiCliCreditBalance(payload),
|
||||
};
|
||||
} catch {
|
||||
return { tierLabel: null, creditBalance: null };
|
||||
return { tierLabel: null, tierId: null, creditBalance: null };
|
||||
}
|
||||
};
|
||||
|
||||
const readGeminiCliSupplementarySnapshot = (
|
||||
fileName: string,
|
||||
requestId: number
|
||||
): { tierLabel: string | null; creditBalance: number | null } => {
|
||||
): { tierLabel: string | null; tierId: string | null; creditBalance: number | null } => {
|
||||
const cached = geminiCliSupplementaryCache.get(fileName);
|
||||
if (!cached || cached.requestId !== requestId) {
|
||||
return { tierLabel: null, creditBalance: null };
|
||||
return { tierLabel: null, tierId: null, creditBalance: null };
|
||||
}
|
||||
|
||||
return {
|
||||
tierLabel: cached.tierLabel,
|
||||
tierId: cached.tierId,
|
||||
creditBalance: cached.creditBalance,
|
||||
};
|
||||
};
|
||||
@@ -564,6 +581,7 @@ const scheduleGeminiCliSupplementaryRefresh = (
|
||||
|
||||
if (
|
||||
current.tierLabel === supplementary.tierLabel &&
|
||||
current.tierId === supplementary.tierId &&
|
||||
current.creditBalance === supplementary.creditBalance
|
||||
) {
|
||||
return prev;
|
||||
@@ -574,6 +592,7 @@ const scheduleGeminiCliSupplementaryRefresh = (
|
||||
[fileName]: {
|
||||
...current,
|
||||
tierLabel: supplementary.tierLabel,
|
||||
tierId: supplementary.tierId,
|
||||
creditBalance: supplementary.creditBalance,
|
||||
},
|
||||
};
|
||||
@@ -591,6 +610,7 @@ const fetchGeminiCliQuota = async (
|
||||
supplementaryRequestId: number;
|
||||
buckets: GeminiCliQuotaBucketState[];
|
||||
tierLabel: string | null;
|
||||
tierId: string | null;
|
||||
creditBalance: number | null;
|
||||
}> => {
|
||||
const rawAuthIndex = file['auth_index'] ?? file.authIndex;
|
||||
@@ -664,6 +684,7 @@ const fetchGeminiCliQuota = async (
|
||||
supplementaryRequestId,
|
||||
buckets: builtBuckets,
|
||||
tierLabel: supplementarySnapshot.tierLabel,
|
||||
tierId: supplementarySnapshot.tierId,
|
||||
creditBalance: supplementarySnapshot.creditBalance,
|
||||
};
|
||||
};
|
||||
@@ -705,6 +726,8 @@ const renderAntigravityItems = (
|
||||
});
|
||||
};
|
||||
|
||||
const PREMIUM_GEMINI_CLI_TIER_IDS = new Set(['g1-ultra-tier']);
|
||||
|
||||
const renderCodexItems = (
|
||||
quota: CodexQuotaState,
|
||||
t: TFunction,
|
||||
@@ -718,6 +741,7 @@ const renderCodexItems = (
|
||||
const getPlanLabel = (pt?: string | null): string | null => {
|
||||
const normalized = normalizePlanType(pt);
|
||||
if (!normalized) return null;
|
||||
if (normalized === 'pro') return t('codex_quota.plan_pro');
|
||||
if (normalized === 'plus') return t('codex_quota.plan_plus');
|
||||
if (normalized === 'team') return t('codex_quota.plan_team');
|
||||
if (normalized === 'free') return t('codex_quota.plan_free');
|
||||
@@ -725,15 +749,17 @@ const renderCodexItems = (
|
||||
};
|
||||
|
||||
const planLabel = getPlanLabel(planType);
|
||||
const isPremiumPlan = normalizePlanType(planType) === 'pro';
|
||||
const nodes: ReactNode[] = [];
|
||||
|
||||
if (planLabel) {
|
||||
const valueClass = isPremiumPlan ? styleMap.premiumPlanValue : styleMap.codexPlanValue;
|
||||
nodes.push(
|
||||
h(
|
||||
'div',
|
||||
{ key: 'plan', className: styleMap.codexPlan },
|
||||
h('span', { className: styleMap.codexPlanLabel }, t('codex_quota.plan_label')),
|
||||
h('span', { className: styleMap.codexPlanValue }, planLabel)
|
||||
h('span', { className: valueClass }, planLabel)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -786,16 +812,19 @@ const renderGeminiCliItems = (
|
||||
const { createElement: h, Fragment } = React;
|
||||
const buckets = quota.buckets ?? [];
|
||||
const tierLabel = quota.tierLabel ?? null;
|
||||
const tierId = quota.tierId ?? null;
|
||||
const creditBalance = quota.creditBalance ?? null;
|
||||
const isPremiumTier = tierId !== null && PREMIUM_GEMINI_CLI_TIER_IDS.has(tierId);
|
||||
const nodes: ReactNode[] = [];
|
||||
|
||||
if (tierLabel) {
|
||||
const valueClass = isPremiumTier ? styleMap.premiumPlanValue : styleMap.codexPlanValue;
|
||||
nodes.push(
|
||||
h(
|
||||
'div',
|
||||
{ key: 'tier', className: styleMap.codexPlan },
|
||||
h('span', { className: styleMap.codexPlanLabel }, t('gemini_cli_quota.tier_label')),
|
||||
h('span', { className: styleMap.codexPlanValue }, tierLabel)
|
||||
h('span', { className: valueClass }, tierLabel)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1148,6 +1177,7 @@ export const GEMINI_CLI_CONFIG: QuotaConfig<
|
||||
supplementaryRequestId: number;
|
||||
buckets: GeminiCliQuotaBucketState[];
|
||||
tierLabel: string | null;
|
||||
tierId: string | null;
|
||||
creditBalance: number | null;
|
||||
}
|
||||
> = {
|
||||
@@ -1159,7 +1189,7 @@ export const GEMINI_CLI_CONFIG: QuotaConfig<
|
||||
fetchQuota: fetchGeminiCliQuota,
|
||||
storeSelector: (state) => state.geminiCliQuota,
|
||||
storeSetter: 'setGeminiCliQuota',
|
||||
buildLoadingState: () => ({ status: 'loading', buckets: [], tierLabel: null, creditBalance: null }),
|
||||
buildLoadingState: () => ({ status: 'loading', buckets: [], tierLabel: null, tierId: null, creditBalance: null }),
|
||||
buildSuccessState: (data) => {
|
||||
const supplementarySnapshot = readGeminiCliSupplementarySnapshot(
|
||||
data.fileName,
|
||||
@@ -1170,6 +1200,7 @@ export const GEMINI_CLI_CONFIG: QuotaConfig<
|
||||
status: 'success',
|
||||
buckets: data.buckets,
|
||||
tierLabel: supplementarySnapshot.tierLabel ?? data.tierLabel,
|
||||
tierId: supplementarySnapshot.tierId ?? data.tierId,
|
||||
creditBalance: supplementarySnapshot.creditBalance ?? data.creditBalance,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -639,7 +639,8 @@
|
||||
"plan_label": "Plan",
|
||||
"plan_plus": "Plus",
|
||||
"plan_team": "Team",
|
||||
"plan_free": "Free"
|
||||
"plan_free": "Free",
|
||||
"plan_pro": "Pro"
|
||||
},
|
||||
"gemini_cli_quota": {
|
||||
"title": "Gemini CLI Quota",
|
||||
@@ -658,6 +659,8 @@
|
||||
"tier_free": "Free",
|
||||
"tier_legacy": "Legacy",
|
||||
"tier_standard": "Standard",
|
||||
"tier_pro": "Pro",
|
||||
"tier_ultra": "Ultra",
|
||||
"credit_label": "Google One AI Credits",
|
||||
"credit_amount": "{{count}} credits"
|
||||
},
|
||||
|
||||
@@ -642,7 +642,8 @@
|
||||
"plan_label": "Тариф",
|
||||
"plan_plus": "Plus",
|
||||
"plan_team": "Team",
|
||||
"plan_free": "Free"
|
||||
"plan_free": "Free",
|
||||
"plan_pro": "Pro"
|
||||
},
|
||||
"gemini_cli_quota": {
|
||||
"title": "Квота Gemini CLI",
|
||||
@@ -661,6 +662,8 @@
|
||||
"tier_free": "Бесплатный",
|
||||
"tier_legacy": "Устаревший",
|
||||
"tier_standard": "Стандартный",
|
||||
"tier_pro": "Pro",
|
||||
"tier_ultra": "Ultra",
|
||||
"credit_label": "Google One AI кредиты",
|
||||
"credit_amount": "{{count}} кредитов"
|
||||
},
|
||||
|
||||
@@ -639,7 +639,8 @@
|
||||
"plan_label": "套餐",
|
||||
"plan_plus": "Plus",
|
||||
"plan_team": "Team",
|
||||
"plan_free": "Free"
|
||||
"plan_free": "Free",
|
||||
"plan_pro": "Pro"
|
||||
},
|
||||
"gemini_cli_quota": {
|
||||
"title": "Gemini CLI 额度",
|
||||
@@ -658,6 +659,8 @@
|
||||
"tier_free": "免费版",
|
||||
"tier_legacy": "旧版",
|
||||
"tier_standard": "标准版",
|
||||
"tier_pro": "Pro",
|
||||
"tier_ultra": "Ultra",
|
||||
"credit_label": "Google One AI 积分",
|
||||
"credit_amount": "{{count}} 积分"
|
||||
},
|
||||
|
||||
@@ -512,6 +512,45 @@
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.premiumPlanValue {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(135deg, #fdf3d7, #f0d060);
|
||||
border: 1px solid #e0b830;
|
||||
box-shadow: 0 1px 4px rgba(200, 160, 0, 0.18);
|
||||
color: #7a5c00;
|
||||
text-transform: capitalize;
|
||||
|
||||
@media (dynamic-range: high) {
|
||||
background: linear-gradient(135deg,
|
||||
color(display-p3 0.99 0.95 0.82),
|
||||
color(display-p3 0.97 0.82 0.28));
|
||||
border-color: color(display-p3 0.90 0.73 0.12);
|
||||
box-shadow: 0 1px 8px color(display-p3 1.0 0.84 0.0 / 0.25);
|
||||
color: color(display-p3 0.50 0.38 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
:global([data-theme='dark']) .premiumPlanValue {
|
||||
background: linear-gradient(135deg, #3d3210, #5a4a18);
|
||||
border-color: #8b7030;
|
||||
box-shadow: 0 1px 8px rgba(180, 140, 0, 0.2);
|
||||
color: #e8c84c;
|
||||
|
||||
@media (dynamic-range: high) {
|
||||
background: linear-gradient(135deg,
|
||||
color(display-p3 0.24 0.20 0.06),
|
||||
color(display-p3 0.38 0.30 0.08));
|
||||
border-color: color(display-p3 0.58 0.46 0.15);
|
||||
box-shadow: 0 1px 12px color(display-p3 0.80 0.65 0.0 / 0.2);
|
||||
color: color(display-p3 0.95 0.82 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
// 单个认证文件卡片
|
||||
.fileCard {
|
||||
background-color: var(--bg-primary);
|
||||
|
||||
@@ -318,6 +318,45 @@
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.premiumPlanValue {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(135deg, #fdf3d7, #f0d060);
|
||||
border: 1px solid #e0b830;
|
||||
box-shadow: 0 1px 4px rgba(200, 160, 0, 0.18);
|
||||
color: #7a5c00;
|
||||
text-transform: capitalize;
|
||||
|
||||
@media (dynamic-range: high) {
|
||||
background: linear-gradient(135deg,
|
||||
color(display-p3 0.99 0.95 0.82),
|
||||
color(display-p3 0.97 0.82 0.28));
|
||||
border-color: color(display-p3 0.90 0.73 0.12);
|
||||
box-shadow: 0 1px 8px color(display-p3 1.0 0.84 0.0 / 0.25);
|
||||
color: color(display-p3 0.50 0.38 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
:global([data-theme='dark']) .premiumPlanValue {
|
||||
background: linear-gradient(135deg, #3d3210, #5a4a18);
|
||||
border-color: #8b7030;
|
||||
box-shadow: 0 1px 8px rgba(180, 140, 0, 0.2);
|
||||
color: #e8c84c;
|
||||
|
||||
@media (dynamic-range: high) {
|
||||
background: linear-gradient(135deg,
|
||||
color(display-p3 0.24 0.20 0.06),
|
||||
color(display-p3 0.38 0.30 0.08));
|
||||
border-color: color(display-p3 0.58 0.46 0.15);
|
||||
box-shadow: 0 1px 12px color(display-p3 0.80 0.65 0.0 / 0.2);
|
||||
color: color(display-p3 0.95 0.82 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
.fileCard {
|
||||
background-color: var(--bg-primary);
|
||||
border: 1px solid var(--border-color);
|
||||
|
||||
@@ -223,6 +223,7 @@ export interface GeminiCliQuotaState {
|
||||
status: 'idle' | 'loading' | 'success' | 'error';
|
||||
buckets: GeminiCliQuotaBucketState[];
|
||||
tierLabel?: string | null;
|
||||
tierId?: string | null;
|
||||
creditBalance?: number | null;
|
||||
error?: string;
|
||||
errorStatus?: number;
|
||||
|
||||
Reference in New Issue
Block a user