feat(frontend): optimize gemini setup ui and usage visualization
- refactor: clarify gemini auth types (Built-in vs Custom) - feat: add setup guide with checklist and official links - feat: display simulated daily quota progress bar - style: apply brand-aligned colors (Blue/Gray) to gemini sections
This commit is contained in:
@@ -169,9 +169,44 @@
|
||||
<div v-else class="text-xs text-gray-400">-</div>
|
||||
</template>
|
||||
|
||||
<!-- Gemini platform: show quota info with AccountQuotaInfo component -->
|
||||
<!-- Gemini platform: show quota + local usage window -->
|
||||
<template v-else-if="account.platform === 'gemini'">
|
||||
<AccountQuotaInfo :account="account" />
|
||||
<div class="space-y-1">
|
||||
<AccountQuotaInfo :account="account" />
|
||||
<div v-if="loading" class="space-y-1">
|
||||
<div class="flex items-center gap-1">
|
||||
<div class="h-3 w-[32px] animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div>
|
||||
<div class="h-1.5 w-8 animate-pulse rounded-full bg-gray-200 dark:bg-gray-700"></div>
|
||||
<div class="h-3 w-[32px] animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="error" class="text-xs text-red-500">
|
||||
{{ error }}
|
||||
</div>
|
||||
<div v-else-if="geminiUsageAvailable" class="space-y-1">
|
||||
<UsageProgressBar
|
||||
v-if="usageInfo?.gemini_pro_daily"
|
||||
:label="t('admin.accounts.usageWindow.geminiProDaily')"
|
||||
:utilization="usageInfo.gemini_pro_daily.utilization"
|
||||
:resets-at="usageInfo.gemini_pro_daily.resets_at"
|
||||
:window-stats="usageInfo.gemini_pro_daily.window_stats"
|
||||
:stats-title="t('admin.accounts.usageWindow.statsTitleDaily')"
|
||||
color="indigo"
|
||||
/>
|
||||
<UsageProgressBar
|
||||
v-if="usageInfo?.gemini_flash_daily"
|
||||
:label="t('admin.accounts.usageWindow.geminiFlashDaily')"
|
||||
:utilization="usageInfo.gemini_flash_daily.utilization"
|
||||
:resets-at="usageInfo.gemini_flash_daily.resets_at"
|
||||
:window-stats="usageInfo.gemini_flash_daily.window_stats"
|
||||
:stats-title="t('admin.accounts.usageWindow.statsTitleDaily')"
|
||||
color="emerald"
|
||||
/>
|
||||
<p class="mt-1 text-[9px] leading-tight text-gray-400 dark:text-gray-500 italic">
|
||||
* {{ t('admin.accounts.gemini.quotaPolicy.simulatedNote') || 'Simulated quota' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Other accounts: no usage window -->
|
||||
@@ -211,6 +246,23 @@ const showUsageWindows = computed(
|
||||
() => props.account.type === 'oauth' || props.account.type === 'setup-token'
|
||||
)
|
||||
|
||||
const shouldFetchUsage = computed(() => {
|
||||
if (props.account.platform === 'anthropic') {
|
||||
return props.account.type === 'oauth' || props.account.type === 'setup-token'
|
||||
}
|
||||
if (props.account.platform === 'gemini') {
|
||||
return props.account.type === 'oauth'
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
const geminiUsageAvailable = computed(() => {
|
||||
return (
|
||||
!!usageInfo.value?.gemini_pro_daily ||
|
||||
!!usageInfo.value?.gemini_flash_daily
|
||||
)
|
||||
})
|
||||
|
||||
// OpenAI Codex usage computed properties
|
||||
const hasCodexUsage = computed(() => {
|
||||
const extra = props.account.extra
|
||||
@@ -498,10 +550,7 @@ const hasIneligibleTiers = computed(() => {
|
||||
})
|
||||
|
||||
const loadUsage = async () => {
|
||||
// Fetch usage for Anthropic OAuth and Setup Token accounts
|
||||
// OpenAI usage comes from account.extra field (updated during forwarding)
|
||||
if (props.account.platform !== 'anthropic') return
|
||||
if (props.account.type !== 'oauth' && props.account.type !== 'setup-token') return
|
||||
if (!shouldFetchUsage.value) return
|
||||
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
@@ -373,8 +373,12 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">OAuth</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{ t('admin.accounts.types.googleOauth') }}</span>
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.accountType.oauthTitle') }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.accountType.oauthDesc') }}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -411,12 +415,42 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">API Key</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">AI Studio API Key</span>
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.accountType.apiKeyTitle') }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.accountType.apiKeyDesc') }}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="accountCategory === 'apikey'"
|
||||
class="mt-3 rounded-lg border border-purple-200 bg-purple-50 px-3 py-2 text-xs text-purple-800 dark:border-purple-800/40 dark:bg-purple-900/20 dark:text-purple-200"
|
||||
>
|
||||
<p>{{ t('admin.accounts.gemini.accountType.apiKeyNote') }}</p>
|
||||
<div class="mt-2 flex flex-wrap gap-2">
|
||||
<a
|
||||
:href="geminiHelpLinks.apiKey"
|
||||
class="font-medium text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.accountType.apiKeyLink') }}
|
||||
</a>
|
||||
<span class="text-purple-400">·</span>
|
||||
<a
|
||||
:href="geminiHelpLinks.aiStudioPricing"
|
||||
class="font-medium text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.accountType.quotaLink') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- OAuth Type Selection (only show when oauth-based is selected) -->
|
||||
<div v-if="accountCategory === 'oauth-based'" class="mt-4">
|
||||
<label class="input-label">{{ t('admin.accounts.oauth.gemini.oauthTypeLabel') }}</label>
|
||||
@@ -443,10 +477,41 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15a4.5 4.5 0 004.5 4.5H18a3.75 3.75 0 001.332-7.257 3 3 0 00-3.758-3.848 5.25 5.25 0 00-10.233 2.33A4.502 4.502 0 002.25 15z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">{{ t('admin.accounts.types.codeAssist') }}</span>
|
||||
<span class="block text-xs font-medium text-blue-600 dark:text-blue-400">{{ t('admin.accounts.oauth.gemini.needsProjectId') }}</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{ t('admin.accounts.oauth.gemini.needsProjectIdDesc') }}</span>
|
||||
<div class="min-w-0">
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.oauthType.builtInTitle') }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.oauthType.builtInDesc') }}
|
||||
</span>
|
||||
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.oauthType.builtInRequirement') }}
|
||||
<a
|
||||
:href="geminiHelpLinks.gcpProject"
|
||||
class="ml-1 text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.oauthType.gcpProjectLink') }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="mt-2 flex flex-wrap gap-1">
|
||||
<span
|
||||
class="rounded bg-blue-100 px-2 py-0.5 text-[10px] font-semibold text-blue-700 dark:bg-blue-900/40 dark:text-blue-300"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.oauthType.badges.recommended') }}
|
||||
</span>
|
||||
<span
|
||||
class="rounded bg-emerald-100 px-2 py-0.5 text-[10px] font-semibold text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.oauthType.badges.highConcurrency') }}
|
||||
</span>
|
||||
<span
|
||||
class="rounded bg-gray-100 px-2 py-0.5 text-[10px] font-semibold text-gray-700 dark:bg-gray-800 dark:text-gray-300"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.oauthType.badges.noAdmin') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -486,13 +551,27 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">AI Studio</span>
|
||||
<span class="block text-xs font-medium text-purple-600 dark:text-purple-400">{{
|
||||
t('admin.accounts.oauth.gemini.noProjectIdNeeded')
|
||||
}}</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{
|
||||
t('admin.accounts.oauth.gemini.noProjectIdNeededDesc')
|
||||
}}</span>
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.oauthType.customTitle') }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.oauthType.customDesc') }}
|
||||
</span>
|
||||
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.oauthType.customRequirement') }}
|
||||
</div>
|
||||
<div class="mt-2 flex flex-wrap gap-1">
|
||||
<span
|
||||
class="rounded bg-purple-100 px-2 py-0.5 text-[10px] font-semibold text-purple-700 dark:bg-purple-900/40 dark:text-purple-300"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.oauthType.badges.orgManaged') }}
|
||||
</span>
|
||||
<span
|
||||
class="rounded bg-amber-100 px-2 py-0.5 text-[10px] font-semibold text-amber-700 dark:bg-amber-900/40 dark:text-amber-300"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.oauthType.badges.adminRequired') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
v-if="!geminiAIStudioOAuthEnabled"
|
||||
@@ -511,6 +590,79 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 rounded-lg border border-blue-200 bg-blue-50 p-4 text-xs text-blue-900 dark:border-blue-800/40 dark:bg-blue-900/20 dark:text-blue-200">
|
||||
<div class="flex items-start gap-3">
|
||||
<svg
|
||||
class="h-5 w-5 flex-shrink-0 text-blue-600 dark:text-blue-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-medium text-blue-800 dark:text-blue-300">
|
||||
{{ t('admin.accounts.gemini.setupGuide.title') }}
|
||||
</p>
|
||||
<div class="mt-2 space-y-2">
|
||||
<div>
|
||||
<p class="font-semibold text-blue-800 dark:text-blue-300">
|
||||
{{ t('admin.accounts.gemini.setupGuide.checklistTitle') }}
|
||||
</p>
|
||||
<ul class="mt-1 list-disc space-y-1 pl-4">
|
||||
<li>
|
||||
{{ t('admin.accounts.gemini.setupGuide.checklistItems.usIp') }}
|
||||
<a
|
||||
:href="geminiHelpLinks.countryCheck"
|
||||
class="ml-1 text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.setupGuide.links.countryCheck') }}
|
||||
</a>
|
||||
</li>
|
||||
<li>{{ t('admin.accounts.gemini.setupGuide.checklistItems.age') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-blue-800 dark:text-blue-300">
|
||||
{{ t('admin.accounts.gemini.setupGuide.activationTitle') }}
|
||||
</p>
|
||||
<ul class="mt-1 list-disc space-y-1 pl-4">
|
||||
<li>
|
||||
{{ t('admin.accounts.gemini.setupGuide.activationItems.geminiWeb') }}
|
||||
<a
|
||||
:href="geminiHelpLinks.geminiWebActivation"
|
||||
class="ml-1 text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.setupGuide.links.geminiWebActivation') }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{{ t('admin.accounts.gemini.setupGuide.activationItems.gcpProject') }}
|
||||
<a
|
||||
:href="geminiHelpLinks.gcpProject"
|
||||
class="ml-1 text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.setupGuide.links.gcpProject') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Account Type Selection (Antigravity - OAuth only) -->
|
||||
@@ -969,6 +1121,165 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gemini 配额与限流政策说明 -->
|
||||
<div v-if="form.platform === 'gemini'" class="border-t border-gray-200 pt-4 dark:border-dark-600">
|
||||
<div class="rounded-lg bg-gray-50 p-4 dark:bg-gray-800/40">
|
||||
<div class="flex items-start gap-3">
|
||||
<svg
|
||||
class="h-5 w-5 flex-shrink-0 text-gray-500 dark:text-gray-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
|
||||
/>
|
||||
</svg>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.title') }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-600 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.note') }}
|
||||
</p>
|
||||
<div class="mt-3 overflow-x-auto">
|
||||
<table class="min-w-full text-xs text-gray-700 dark:text-gray-300">
|
||||
<thead>
|
||||
<tr class="border-b border-gray-200 dark:border-gray-700">
|
||||
<th class="px-2 py-1.5 text-left font-semibold">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.channel') }}
|
||||
</th>
|
||||
<th class="px-2 py-1.5 text-left font-semibold">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.account') }}
|
||||
</th>
|
||||
<th class="px-2 py-1.5 text-left font-semibold">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.limits') }}
|
||||
</th>
|
||||
<th class="px-2 py-1.5 text-left font-semibold">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.columns.docs') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.channel') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.free') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.limitsFree') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
<a
|
||||
:href="geminiQuotaDocs.codeAssist"
|
||||
class="text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.codeAssist') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.premium') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.cli.limitsPremium') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5 align-top">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.gcloud.channel') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.gcloud.account') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.gcloud.limits') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5 align-top">
|
||||
<a
|
||||
:href="geminiQuotaDocs.codeAssist"
|
||||
class="text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.codeAssist') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.channel') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.free') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.limitsFree') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
<a
|
||||
:href="geminiQuotaDocs.aiStudio"
|
||||
class="text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.aiStudio') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100 dark:border-gray-800">
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.paid') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.aiStudio.limitsPaid') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.channel') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.free') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.limitsFree') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5 align-top" rowspan="2">
|
||||
<a
|
||||
:href="geminiQuotaDocs.vertex"
|
||||
class="text-blue-600 hover:underline dark:text-blue-400"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.docs.vertex') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.paid') }}
|
||||
</td>
|
||||
<td class="px-2 py-1.5">
|
||||
{{ t('admin.accounts.gemini.quotaPolicy.rows.customOAuth.limitsPaid') }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Intercept Warmup Requests (Anthropic only) -->
|
||||
@@ -1333,6 +1644,20 @@ const geminiModels = [
|
||||
{ value: 'gemini-1.5-flash', label: 'Gemini 1.5 Flash' }
|
||||
]
|
||||
|
||||
const geminiQuotaDocs = {
|
||||
codeAssist: 'https://developers.google.com/gemini-code-assist/resources/quotas',
|
||||
aiStudio: 'https://ai.google.dev/pricing',
|
||||
vertex: 'https://cloud.google.com/vertex-ai/generative-ai/docs/quotas'
|
||||
}
|
||||
|
||||
const geminiHelpLinks = {
|
||||
apiKey: 'https://aistudio.google.com/app/apikey',
|
||||
aiStudioPricing: 'https://ai.google.dev/pricing',
|
||||
gcpProject: 'https://console.cloud.google.com/welcome/new',
|
||||
geminiWebActivation: 'https://gemini.google.com/gems/create?hl=en-US',
|
||||
countryCheck: 'https://policies.google.com/country-association-form'
|
||||
}
|
||||
|
||||
// Computed: current models based on platform
|
||||
const commonModels = computed(() => {
|
||||
if (form.platform === 'openai') return openaiModels
|
||||
|
||||
@@ -121,16 +121,13 @@
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">{{
|
||||
t('admin.accounts.types.codeAssist')
|
||||
}}</span>
|
||||
<span class="block text-xs font-medium text-blue-600 dark:text-blue-400">{{
|
||||
t('admin.accounts.oauth.gemini.needsProjectId')
|
||||
}}</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{
|
||||
t('admin.accounts.oauth.gemini.needsProjectIdDesc')
|
||||
}}</span>
|
||||
<div class="min-w-0">
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.oauthType.builtInTitle') }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.oauthType.builtInDesc') }}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -168,14 +165,13 @@
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">AI Studio</span>
|
||||
<span class="block text-xs font-medium text-purple-600 dark:text-purple-400">{{
|
||||
t('admin.accounts.oauth.gemini.noProjectIdNeeded')
|
||||
}}</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{
|
||||
t('admin.accounts.oauth.gemini.noProjectIdNeededDesc')
|
||||
}}</span>
|
||||
<div class="min-w-0">
|
||||
<span class="block text-sm font-medium text-gray-900 dark:text-white">
|
||||
{{ t('admin.accounts.gemini.oauthType.customTitle') }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.gemini.oauthType.customDesc') }}
|
||||
</span>
|
||||
<div v-if="!geminiAIStudioOAuthEnabled" class="group relative mt-1 inline-block">
|
||||
<span
|
||||
class="rounded bg-amber-100 px-2 py-0.5 text-xs text-amber-700 dark:bg-amber-900/30 dark:text-amber-300"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div
|
||||
v-if="windowStats"
|
||||
class="mb-0.5 flex items-center justify-between"
|
||||
:title="t('admin.accounts.usageWindow.statsTitle')"
|
||||
:title="statsTitle || t('admin.accounts.usageWindow.statsTitle')"
|
||||
>
|
||||
<div
|
||||
class="flex cursor-help items-center gap-1.5 text-[9px] text-gray-500 dark:text-gray-400"
|
||||
@@ -60,6 +60,7 @@ const props = defineProps<{
|
||||
resetsAt?: string | null
|
||||
color: 'indigo' | 'emerald' | 'purple' | 'amber'
|
||||
windowStats?: WindowStats | null
|
||||
statsTitle?: string
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
Reference in New Issue
Block a user