mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-06-16 21:03:58 +08:00
fix(quota): localize kimi quota fallback labels and reset hint
This commit is contained in:
@@ -915,9 +915,17 @@ const renderKimiItems = (
|
||||
return rows.map((row) => {
|
||||
const limit = row.limit;
|
||||
const used = row.used;
|
||||
const remaining = limit > 0 ? Math.max(0, Math.min(100, Math.round(((limit - used) / limit) * 100))) : (used > 0 ? 0 : null);
|
||||
const remaining =
|
||||
limit > 0
|
||||
? Math.max(0, Math.min(100, Math.round(((limit - used) / limit) * 100)))
|
||||
: used > 0
|
||||
? 0
|
||||
: null;
|
||||
const percentLabel = remaining === null ? '--' : `${remaining}%`;
|
||||
const resetLabel = formatKimiResetHint(row.resetHint);
|
||||
const rowLabel = row.labelKey
|
||||
? t(row.labelKey, (row.labelParams ?? {}) as Record<string, string | number>)
|
||||
: row.label ?? '';
|
||||
const resetLabel = formatKimiResetHint(t, row.resetHint);
|
||||
|
||||
return h(
|
||||
'div',
|
||||
@@ -925,7 +933,7 @@ const renderKimiItems = (
|
||||
h(
|
||||
'div',
|
||||
{ className: styleMap.quotaRowHeader },
|
||||
h('span', { className: styleMap.quotaModel }, row.label),
|
||||
h('span', { className: styleMap.quotaModel }, rowLabel),
|
||||
h(
|
||||
'div',
|
||||
{ className: styleMap.quotaMeta },
|
||||
|
||||
@@ -629,7 +629,11 @@
|
||||
"missing_auth_index": "Auth file missing auth_index",
|
||||
"empty_data": "No quota data available",
|
||||
"refresh_button": "Refresh Quota",
|
||||
"fetch_all": "Fetch All"
|
||||
"fetch_all": "Fetch All",
|
||||
"weekly_limit": "Weekly limit",
|
||||
"limit_window": "{{duration}} limit",
|
||||
"limit_index": "Limit #{{index}}",
|
||||
"reset_hint": "resets in {{hint}}"
|
||||
},
|
||||
"vertex_import": {
|
||||
"title": "Vertex JSON Login",
|
||||
|
||||
@@ -632,7 +632,11 @@
|
||||
"missing_auth_index": "В файле авторизации отсутствует auth_index",
|
||||
"empty_data": "Данные по квоте отсутствуют",
|
||||
"refresh_button": "Обновить квоту",
|
||||
"fetch_all": "Получить все"
|
||||
"fetch_all": "Получить все",
|
||||
"weekly_limit": "Недельный лимит",
|
||||
"limit_window": "Лимит {{duration}}",
|
||||
"limit_index": "Лимит #{{index}}",
|
||||
"reset_hint": "сброс через {{hint}}"
|
||||
},
|
||||
"vertex_import": {
|
||||
"title": "Вход с Vertex JSON",
|
||||
|
||||
@@ -629,7 +629,11 @@
|
||||
"missing_auth_index": "认证文件缺少 auth_index",
|
||||
"empty_data": "暂无额度数据",
|
||||
"refresh_button": "刷新额度",
|
||||
"fetch_all": "获取全部"
|
||||
"fetch_all": "获取全部",
|
||||
"weekly_limit": "周限额",
|
||||
"limit_window": "{{duration}} 限额",
|
||||
"limit_index": "限额 #{{index}}",
|
||||
"reset_hint": "{{hint}} 后重置"
|
||||
},
|
||||
"vertex_import": {
|
||||
"title": "Vertex JSON 登录",
|
||||
|
||||
+3
-1
@@ -244,7 +244,9 @@ export interface KimiUsagePayload {
|
||||
|
||||
export interface KimiQuotaRow {
|
||||
id: string;
|
||||
label: string;
|
||||
label?: string;
|
||||
labelKey?: string;
|
||||
labelParams?: Record<string, string | number>;
|
||||
used: number;
|
||||
limit: number;
|
||||
resetHint?: string;
|
||||
|
||||
+43
-21
@@ -275,6 +275,8 @@ function toInt(value: unknown): number | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
type KimiRowLabel = Pick<KimiQuotaRow, 'label' | 'labelKey' | 'labelParams'>;
|
||||
|
||||
function kimiResetHint(data: Record<string, unknown>): string | undefined {
|
||||
const absoluteKeys = ['reset_at', 'resetAt', 'reset_time', 'resetTime'];
|
||||
for (const key of absoluteKeys) {
|
||||
@@ -316,39 +318,57 @@ function kimiResetHint(data: Record<string, unknown>): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function kimiDurationToken(duration: number, rawTimeUnit: unknown): string {
|
||||
const unit = typeof rawTimeUnit === 'string' ? rawTimeUnit.trim().toUpperCase() : '';
|
||||
if (unit === 'MINUTES') {
|
||||
return duration % 60 === 0 ? `${duration / 60}h` : `${duration}m`;
|
||||
}
|
||||
if (unit === 'HOURS') return `${duration}h`;
|
||||
if (unit === 'DAYS') return `${duration}d`;
|
||||
return `${duration}s`;
|
||||
}
|
||||
|
||||
function kimiLimitLabel(
|
||||
item: KimiLimitItem,
|
||||
detail: KimiUsageDetail | KimiLimitItem,
|
||||
window: KimiLimitWindow,
|
||||
index: number
|
||||
): string {
|
||||
): KimiRowLabel {
|
||||
for (const key of ['name', 'title', 'scope'] as const) {
|
||||
const val = (item as Record<string, unknown>)[key] ?? (detail as Record<string, unknown>)[key];
|
||||
if (typeof val === 'string' && val.trim()) return val.trim();
|
||||
if (typeof val === 'string' && val.trim()) return { label: val.trim() };
|
||||
}
|
||||
|
||||
const duration =
|
||||
toInt(window.duration) ?? toInt((item as Record<string, unknown>).duration) ?? toInt((detail as Record<string, unknown>).duration);
|
||||
toInt(window.duration) ??
|
||||
toInt((item as Record<string, unknown>).duration) ??
|
||||
toInt((detail as Record<string, unknown>).duration);
|
||||
const timeUnit =
|
||||
(window.timeUnit as string) ?? (item as Record<string, unknown>).timeUnit ?? (detail as Record<string, unknown>).timeUnit;
|
||||
(window as Record<string, unknown>).timeUnit ??
|
||||
(item as Record<string, unknown>).timeUnit ??
|
||||
(detail as Record<string, unknown>).timeUnit;
|
||||
|
||||
if (duration !== null && duration > 0) {
|
||||
const unit = typeof timeUnit === 'string' ? timeUnit.toUpperCase() : '';
|
||||
if (unit === 'MINUTES') {
|
||||
return duration % 60 === 0 ? `${duration / 60}h limit` : `${duration}m limit`;
|
||||
}
|
||||
if (unit === 'HOURS') return `${duration}h limit`;
|
||||
if (unit === 'DAYS') return `${duration}d limit`;
|
||||
return `${duration}s limit`;
|
||||
return {
|
||||
labelKey: 'kimi_quota.limit_window',
|
||||
labelParams: {
|
||||
duration: kimiDurationToken(duration, timeUnit),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return `Limit #${index + 1}`;
|
||||
return {
|
||||
labelKey: 'kimi_quota.limit_index',
|
||||
labelParams: {
|
||||
index: index + 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function toKimiUsageRow(
|
||||
data: Record<string, unknown>,
|
||||
defaultLabel: string
|
||||
): { label: string; used: number; limit: number; resetHint?: string } | null {
|
||||
fallbackLabel: KimiRowLabel
|
||||
): (KimiRowLabel & { used: number; limit: number; resetHint?: string }) | null {
|
||||
const limit = toInt(data.limit);
|
||||
let used = toInt(data.used);
|
||||
if (used === null) {
|
||||
@@ -358,12 +378,12 @@ function toKimiUsageRow(
|
||||
}
|
||||
}
|
||||
if (used === null && limit === null) return null;
|
||||
const label =
|
||||
const explicitLabel =
|
||||
(typeof data.name === 'string' && data.name.trim()) ||
|
||||
(typeof data.title === 'string' && data.title.trim()) ||
|
||||
defaultLabel;
|
||||
(typeof data.title === 'string' && data.title.trim());
|
||||
const label = explicitLabel ? { label: explicitLabel } : fallbackLabel;
|
||||
return {
|
||||
label,
|
||||
...label,
|
||||
used: used ?? 0,
|
||||
limit: limit ?? 0,
|
||||
resetHint: kimiResetHint(data),
|
||||
@@ -375,7 +395,9 @@ export function buildKimiQuotaRows(payload: KimiUsagePayload): KimiQuotaRow[] {
|
||||
|
||||
const usage = payload.usage;
|
||||
if (usage && typeof usage === 'object') {
|
||||
const summary = toKimiUsageRow(usage as Record<string, unknown>, 'Weekly limit');
|
||||
const summary = toKimiUsageRow(usage as Record<string, unknown>, {
|
||||
labelKey: 'kimi_quota.weekly_limit',
|
||||
});
|
||||
if (summary) {
|
||||
rows.push({ id: 'summary', ...summary });
|
||||
}
|
||||
@@ -386,8 +408,8 @@ export function buildKimiQuotaRows(payload: KimiUsagePayload): KimiQuotaRow[] {
|
||||
limits.forEach((item, idx) => {
|
||||
const detail = (item.detail && typeof item.detail === 'object' ? item.detail : item) as KimiUsageDetail | KimiLimitItem;
|
||||
const window = (item.window && typeof item.window === 'object' ? item.window : {}) as KimiLimitWindow;
|
||||
const label = kimiLimitLabel(item, detail, window, idx);
|
||||
const row = toKimiUsageRow(detail as Record<string, unknown>, label);
|
||||
const fallbackLabel = kimiLimitLabel(item, detail, window, idx);
|
||||
const row = toKimiUsageRow(detail as Record<string, unknown>, fallbackLabel);
|
||||
if (row) {
|
||||
rows.push({ id: `limit-${idx}`, ...row });
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Formatting functions for quota display.
|
||||
*/
|
||||
|
||||
import type { TFunction } from 'i18next';
|
||||
import type { CodexUsageWindow } from '@/types';
|
||||
import { normalizeNumberValue } from './parsers';
|
||||
|
||||
@@ -67,7 +68,7 @@ export function getStatusFromError(err: unknown): number | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function formatKimiResetHint(hint?: string): string {
|
||||
export function formatKimiResetHint(t: TFunction, hint?: string): string {
|
||||
if (!hint) return '';
|
||||
return `resets in ${hint}`;
|
||||
return t('kimi_quota.reset_hint', { hint });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user