Revert "feat: 完整国际化支持 - Web 管理界面多语言实现"

This commit is contained in:
Wesley Liddick
2025-09-12 11:09:52 +08:00
committed by GitHub
parent 1d915d8327
commit 96f213e3e2
80 changed files with 7026 additions and 19087 deletions

View File

@@ -12,7 +12,7 @@
<i class="fas fa-edit text-sm text-white sm:text-base" />
</div>
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 sm:text-xl">
{{ t('apiKeys.editApiKeyModal.title') }}
编辑 API Key
</h3>
</div>
<button
@@ -30,18 +30,20 @@
<div>
<label
class="mb-1.5 block text-xs font-semibold text-gray-700 dark:text-gray-300 sm:mb-3 sm:text-sm"
>{{ t('apiKeys.editApiKeyModal.name') }}</label
>名称</label
>
<input
v-model="form.name"
class="form-input w-full border-gray-300 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
maxlength="100"
:placeholder="t('apiKeys.editApiKeyModal.namePlaceholder')"
required
type="text"
/>
<div>
<input
v-model="form.name"
class="form-input flex-1 border-gray-300 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
maxlength="100"
placeholder="请输入API Key名称"
required
type="text"
/>
</div>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400 sm:mt-2">
{{ t('apiKeys.editApiKeyModal.nameHint') }}
用于识别此 API Key 的用途
</p>
</div>
@@ -49,7 +51,7 @@
<div>
<label
class="mb-1.5 block text-xs font-semibold text-gray-700 dark:text-gray-300 sm:mb-3 sm:text-sm"
>{{ t('apiKeys.editApiKeyModal.owner') }}</label
>所有者</label
>
<select
v-model="form.ownerId"
@@ -57,13 +59,11 @@
>
<option v-for="user in availableUsers" :key="user.id" :value="user.id">
{{ user.displayName }} ({{ user.username }})
<span v-if="user.role === 'admin'" class="text-gray-500">{{
t('apiKeys.editApiKeyModal.adminLabel')
}}</span>
<span v-if="user.role === 'admin'" class="text-gray-500">- 管理员</span>
</option>
</select>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400 sm:mt-2">
{{ t('apiKeys.editApiKeyModal.ownerHint') }}
分配此 API Key 给指定用户或管理员管理员分配时不受用户 API Key 数量限制
</p>
</div>
@@ -71,13 +71,13 @@
<div>
<label
class="mb-1.5 block text-xs font-semibold text-gray-700 dark:text-gray-300 sm:mb-3 sm:text-sm"
>{{ t('apiKeys.editApiKeyModal.tags') }}</label
>标签</label
>
<div class="space-y-4">
<!-- 已选择的标签 -->
<div v-if="form.tags.length > 0">
<div class="mb-2 text-xs font-medium text-gray-600 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.selectedTags') }}
已选择的标签:
</div>
<div class="flex flex-wrap gap-2">
<span
@@ -100,7 +100,7 @@
<!-- 可选择的已有标签 -->
<div v-if="unselectedTags.length > 0">
<div class="mb-2 text-xs font-medium text-gray-600 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.clickToSelectTags') }}
点击选择已有标签:
</div>
<div class="flex flex-wrap gap-2">
<button
@@ -119,13 +119,13 @@
<!-- 创建新标签 -->
<div>
<div class="mb-2 text-xs font-medium text-gray-600 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.createNewTag') }}
创建新标签:
</div>
<div class="flex gap-2">
<input
v-model="newTag"
class="form-input flex-1 border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
:placeholder="t('apiKeys.editApiKeyModal.newTagPlaceholder')"
placeholder="输入新标签名称"
type="text"
@keypress.enter.prevent="addTag"
/>
@@ -140,7 +140,7 @@
</div>
<p class="text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.tagsHint') }}
用于标记不同团队或用途方便筛选管理
</p>
</div>
</div>
@@ -156,76 +156,68 @@
<i class="fas fa-tachometer-alt text-xs text-white" />
</div>
<h4 class="text-sm font-semibold text-gray-800 dark:text-gray-200">
{{ t('apiKeys.editApiKeyModal.rateLimitTitle') }}
速率限制设置 (可选)
</h4>
</div>
<div class="space-y-2">
<div class="grid grid-cols-1 gap-2 lg:grid-cols-3">
<div>
<label class="mb-1 block text-xs font-medium text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.rateLimitWindow')
}}</label>
<label class="mb-1 block text-xs font-medium text-gray-700 dark:text-gray-300"
>时间窗口 (分钟)</label
>
<input
v-model="form.rateLimitWindow"
class="form-input w-full border-gray-300 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
min="1"
:placeholder="t('apiKeys.editApiKeyModal.noLimit')"
placeholder="无限制"
type="number"
/>
<p class="ml-2 mt-0.5 text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.rateLimitWindowHint') }}
</p>
<p class="ml-2 mt-0.5 text-xs text-gray-500 dark:text-gray-400">时间段单位</p>
</div>
<div>
<label class="mb-1 block text-xs font-medium text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.rateLimitRequests')
}}</label>
<label class="mb-1 block text-xs font-medium text-gray-700 dark:text-gray-300"
>请求次数限制</label
>
<input
v-model="form.rateLimitRequests"
class="form-input w-full border-gray-300 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
min="1"
:placeholder="t('apiKeys.editApiKeyModal.noLimit')"
placeholder="无限制"
type="number"
/>
<p class="ml-2 mt-0.5 text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.rateLimitRequestsHint') }}
</p>
<p class="ml-2 mt-0.5 text-xs text-gray-500 dark:text-gray-400">窗口内最大请求</p>
</div>
<div>
<label class="mb-1 block text-xs font-medium text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.rateLimitCost')
}}</label>
<label class="mb-1 block text-xs font-medium text-gray-700 dark:text-gray-300"
>费用限制 (美元)</label
>
<input
v-model="form.rateLimitCost"
class="form-input w-full border-gray-300 text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
min="0"
:placeholder="t('apiKeys.editApiKeyModal.noLimit')"
placeholder="无限制"
step="0.01"
type="number"
/>
<p class="ml-2 mt-0.5 text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.rateLimitCostHint') }}
</p>
<p class="ml-2 mt-0.5 text-xs text-gray-500 dark:text-gray-400">窗口内最大费用</p>
</div>
</div>
<!-- 示例说明 -->
<div class="rounded-lg bg-blue-100 p-2 dark:bg-blue-900/30">
<h5 class="mb-1 text-xs font-semibold text-blue-800 dark:text-blue-400">
{{ t('apiKeys.editApiKeyModal.usageExamples') }}
💡 使用示例
</h5>
<div class="space-y-0.5 text-xs text-blue-700 dark:text-blue-300">
<div>
<strong>{{ t('apiKeys.editApiKeyModal.example1') }}</strong>
<strong>示例1:</strong> 时间窗口=60请求次数=1000 每60分钟最多1000次请求
</div>
<div><strong>示例2:</strong> 时间窗口=1费用=0.1 每分钟最多$0.1费用</div>
<div>
<strong>{{ t('apiKeys.editApiKeyModal.example2') }}</strong>
</div>
<div>
<strong>{{ t('apiKeys.editApiKeyModal.example3') }}</strong>
<strong>示例3:</strong> 窗口=30请求=50费用=5 每30分钟50次请求且不超$5费用
</div>
</div>
</div>
@@ -233,9 +225,9 @@
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.dailyCostLimit')
}}</label>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>每日费用限制 (美元)</label
>
<div class="space-y-3">
<div class="flex gap-2">
<button
@@ -264,27 +256,27 @@
type="button"
@click="form.dailyCostLimit = ''"
>
{{ t('apiKeys.editApiKeyModal.custom') }}
自定义
</button>
</div>
<input
v-model="form.dailyCostLimit"
class="form-input w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
min="0"
:placeholder="t('apiKeys.editApiKeyModal.dailyCostLimitPlaceholder')"
placeholder="0 表示无限制"
step="0.01"
type="number"
/>
<p class="text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.dailyCostHint') }}
设置此 API Key 每日的费用限制超过限制将拒绝请求0 或留空表示无限制
</p>
</div>
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.weeklyOpusCostLimit')
}}</label>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>Opus 模型周费用限制 (美元)</label
>
<div class="space-y-3">
<div class="flex gap-2">
<button
@@ -313,36 +305,36 @@
type="button"
@click="form.weeklyOpusCostLimit = ''"
>
{{ t('apiKeys.editApiKeyModal.custom') }}
自定义
</button>
</div>
<input
v-model="form.weeklyOpusCostLimit"
class="form-input w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
min="0"
:placeholder="t('apiKeys.editApiKeyModal.weeklyOpusCostLimitPlaceholder')"
placeholder="0 表示无限制"
step="0.01"
type="number"
/>
<p class="text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.weeklyOpusHint') }}
设置 Opus 模型的周费用限制周一到周日仅限 Claude 官方账户0 或留空表示无限制
</p>
</div>
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.concurrencyLimit')
}}</label>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>并发限制</label
>
<input
v-model="form.concurrencyLimit"
class="form-input w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
min="0"
:placeholder="t('apiKeys.editApiKeyModal.concurrencyLimitPlaceholder')"
placeholder="0 表示无限制"
type="number"
/>
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.concurrencyHint') }}
设置此 API Key 可同时处理的最大请求数
</p>
</div>
@@ -359,18 +351,18 @@
class="ml-2 cursor-pointer text-sm font-semibold text-gray-700 dark:text-gray-300"
for="editIsActive"
>
{{ t('apiKeys.editApiKeyModal.activeStatus') }}
激活账号
</label>
</div>
<p class="mb-4 text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.activeStatusHint') }}
取消勾选将禁用此 API Key暂停所有请求客户端返回 401 错误
</p>
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.servicePermissions')
}}</label>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>服务权限</label
>
<div class="flex gap-4">
<label class="flex cursor-pointer items-center">
<input
@@ -379,9 +371,7 @@
type="radio"
value="all"
/>
<span class="text-sm text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.allServices')
}}</span>
<span class="text-sm text-gray-700 dark:text-gray-300">全部服务</span>
</label>
<label class="flex cursor-pointer items-center">
<input
@@ -390,9 +380,7 @@
type="radio"
value="claude"
/>
<span class="text-sm text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.claudeOnly')
}}</span>
<span class="text-sm text-gray-700 dark:text-gray-300"> Claude</span>
</label>
<label class="flex cursor-pointer items-center">
<input
@@ -401,9 +389,7 @@
type="radio"
value="gemini"
/>
<span class="text-sm text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.geminiOnly')
}}</span>
<span class="text-sm text-gray-700 dark:text-gray-300"> Gemini</span>
</label>
<label class="flex cursor-pointer items-center">
<input
@@ -412,25 +398,23 @@
type="radio"
value="openai"
/>
<span class="text-sm text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.openaiOnly')
}}</span>
<span class="text-sm text-gray-700 dark:text-gray-300"> OpenAI</span>
</label>
</div>
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.permissionsHint') }}
控制此 API Key 可以访问哪些服务
</p>
</div>
<div>
<div class="mb-3 flex items-center justify-between">
<label class="text-sm font-semibold text-gray-700 dark:text-gray-300">{{
t('apiKeys.editApiKeyModal.accountBinding')
}}</label>
<label class="text-sm font-semibold text-gray-700 dark:text-gray-300"
>专属账号绑定</label
>
<button
class="flex items-center gap-1 text-sm text-blue-600 transition-colors hover:text-blue-800 disabled:cursor-not-allowed disabled:opacity-50 dark:text-blue-400 dark:hover:text-blue-300"
:disabled="accountsLoading"
:title="t('apiKeys.editApiKeyModal.refreshAccounts')"
title="刷新账号列表"
type="button"
@click="refreshAccounts"
>
@@ -441,73 +425,69 @@
'text-xs'
]"
/>
<span>{{
accountsLoading
? t('apiKeys.editApiKeyModal.refreshing')
: t('apiKeys.editApiKeyModal.refreshAccounts')
}}</span>
<span>{{ accountsLoading ? '刷新中...' : '刷新账号' }}</span>
</button>
</div>
<div class="grid grid-cols-1 gap-3">
<div>
<label class="mb-1 block text-sm font-medium text-gray-600 dark:text-gray-400">{{
t('apiKeys.editApiKeyModal.claudeAccount')
}}</label>
<label class="mb-1 block text-sm font-medium text-gray-600 dark:text-gray-400"
>Claude 专属账号</label
>
<AccountSelector
v-model="form.claudeAccountId"
:accounts="localAccounts.claude"
:default-option-text="t('apiKeys.editApiKeyModal.useSharedPool')"
default-option-text="使用共享账号池"
:disabled="form.permissions === 'gemini' || form.permissions === 'openai'"
:groups="localAccounts.claudeGroups"
:placeholder="t('apiKeys.editApiKeyModal.selectClaudeAccount')"
placeholder="请选择Claude账号"
platform="claude"
/>
</div>
<div>
<label class="mb-1 block text-sm font-medium text-gray-600 dark:text-gray-400">{{
t('apiKeys.editApiKeyModal.geminiAccount')
}}</label>
<label class="mb-1 block text-sm font-medium text-gray-600 dark:text-gray-400"
>Gemini 专属账号</label
>
<AccountSelector
v-model="form.geminiAccountId"
:accounts="localAccounts.gemini"
:default-option-text="t('apiKeys.editApiKeyModal.useSharedPool')"
default-option-text="使用共享账号池"
:disabled="form.permissions === 'claude' || form.permissions === 'openai'"
:groups="localAccounts.geminiGroups"
:placeholder="t('apiKeys.editApiKeyModal.selectGeminiAccount')"
placeholder="请选择Gemini账号"
platform="gemini"
/>
</div>
<div>
<label class="mb-1 block text-sm font-medium text-gray-600 dark:text-gray-400">{{
t('apiKeys.editApiKeyModal.openaiAccount')
}}</label>
<label class="mb-1 block text-sm font-medium text-gray-600 dark:text-gray-400"
>OpenAI 专属账号</label
>
<AccountSelector
v-model="form.openaiAccountId"
:accounts="localAccounts.openai"
:default-option-text="t('apiKeys.editApiKeyModal.useSharedPool')"
default-option-text="使用共享账号池"
:disabled="form.permissions === 'claude' || form.permissions === 'gemini'"
:groups="localAccounts.openaiGroups"
:placeholder="t('apiKeys.editApiKeyModal.selectOpenaiAccount')"
placeholder="请选择OpenAI账号"
platform="openai"
/>
</div>
<div>
<label class="mb-1 block text-sm font-medium text-gray-600 dark:text-gray-400">{{
t('apiKeys.editApiKeyModal.bedrockAccount')
}}</label>
<label class="mb-1 block text-sm font-medium text-gray-600 dark:text-gray-400"
>Bedrock 专属账号</label
>
<AccountSelector
v-model="form.bedrockAccountId"
:accounts="localAccounts.bedrock"
:default-option-text="t('apiKeys.editApiKeyModal.useSharedPool')"
default-option-text="使用共享账号池"
:disabled="form.permissions === 'gemini' || form.permissions === 'openai'"
:groups="[]"
:placeholder="t('apiKeys.editApiKeyModal.selectBedrockAccount')"
placeholder="请选择Bedrock账号"
platform="bedrock"
/>
</div>
</div>
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.accountBindingHint') }}
修改绑定账号将影响此API Key的请求路由
</p>
</div>
@@ -523,15 +503,15 @@
class="ml-2 cursor-pointer text-sm font-semibold text-gray-700 dark:text-gray-300"
for="editEnableModelRestriction"
>
{{ t('apiKeys.editApiKeyModal.enableModelRestriction') }}
启用模型限制
</label>
</div>
<div v-if="form.enableModelRestriction" class="space-y-3">
<div>
<label class="mb-2 block text-sm font-medium text-gray-600 dark:text-gray-400">{{
t('apiKeys.editApiKeyModal.restrictedModels')
}}</label>
<label class="mb-2 block text-sm font-medium text-gray-600 dark:text-gray-400"
>限制的模型列表</label
>
<div
class="mb-3 flex min-h-[32px] flex-wrap gap-2 rounded-lg border border-gray-200 bg-gray-50 p-2 dark:border-gray-600 dark:bg-gray-700"
>
@@ -553,7 +533,7 @@
v-if="form.restrictedModels.length === 0"
class="text-sm text-gray-400 dark:text-gray-500"
>
{{ t('apiKeys.editApiKeyModal.noRestrictedModels') }}
暂无限制的模型
</span>
</div>
<div class="space-y-3">
@@ -572,7 +552,7 @@
v-if="availableQuickModels.length === 0"
class="text-sm italic text-gray-400 dark:text-gray-500"
>
{{ t('apiKeys.editApiKeyModal.allCommonModelsRestricted') }}
所有常用模型已在限制列表中
</span>
</div>
@@ -581,7 +561,7 @@
<input
v-model="form.modelInput"
class="form-input flex-1 border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
:placeholder="t('apiKeys.editApiKeyModal.addRestrictedModelPlaceholder')"
placeholder="输入模型名称,按回车添加"
type="text"
@keydown.enter.prevent="addRestrictedModel"
/>
@@ -595,7 +575,7 @@
</div>
</div>
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.modelRestrictionHint') }}
设置此API Key无法访问的模型例如claude-opus-4-20250514
</p>
</div>
</div>
@@ -614,17 +594,17 @@
class="ml-2 cursor-pointer text-sm font-semibold text-gray-700 dark:text-gray-300"
for="editEnableClientRestriction"
>
{{ t('apiKeys.editApiKeyModal.enableClientRestriction') }}
启用客户端限制
</label>
</div>
<div v-if="form.enableClientRestriction" class="space-y-3">
<div>
<label class="mb-2 block text-sm font-medium text-gray-600 dark:text-gray-400">{{
t('apiKeys.editApiKeyModal.allowedClients')
}}</label>
<label class="mb-2 block text-sm font-medium text-gray-600 dark:text-gray-400"
>允许的客户端</label
>
<p class="mb-3 text-xs text-gray-500 dark:text-gray-400">
{{ t('apiKeys.editApiKeyModal.clientRestrictionHint') }}
勾选允许使用此API Key的客户端
</p>
<div class="space-y-2">
<div v-for="client in supportedClients" :key="client.id" class="flex items-start">
@@ -655,7 +635,7 @@
type="button"
@click="$emit('close')"
>
{{ t('apiKeys.editApiKeyModal.cancel') }}
取消
</button>
<button
class="btn btn-primary flex-1 px-6 py-3 font-semibold"
@@ -664,9 +644,7 @@
>
<div v-if="loading" class="loading-spinner mr-2" />
<i v-else class="fas fa-save mr-2" />
{{
loading ? t('apiKeys.editApiKeyModal.saving') : t('apiKeys.editApiKeyModal.save')
}}
{{ loading ? '保存中...' : '保存修改' }}
</button>
</div>
</form>
@@ -677,7 +655,6 @@
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { showToast } from '@/utils/toast'
import { useClientsStore } from '@/stores/clients'
import { useApiKeysStore } from '@/stores/apiKeys'
@@ -697,9 +674,6 @@ const props = defineProps({
const emit = defineEmits(['close', 'success'])
// 国际化
const { t } = useI18n()
// const authStore = useAuthStore()
const clientsStore = useClientsStore()
const apiKeysStore = useApiKeysStore()
@@ -811,14 +785,14 @@ const updateApiKey = async () => {
let confirmed = false
if (window.showConfirm) {
confirmed = await window.showConfirm(
t('apiKeys.editApiKeyModal.costLimitConfirmTitle'),
t('apiKeys.editApiKeyModal.costLimitConfirmMessage'),
t('apiKeys.editApiKeyModal.costLimitConfirmContinue'),
t('apiKeys.editApiKeyModal.costLimitConfirmBack')
'费用限制提醒',
'您设置了时间窗口但费用限制为0这意味着不会有费用限制。\n\n是否继续',
'继续保存',
'返回修改'
)
} else {
// 降级方案
confirmed = confirm(t('apiKeys.editApiKeyModal.costLimitConfirmMessage'))
confirmed = confirm('您设置了时间窗口但费用限制为0这意味着不会有费用限制。\n是否继续')
}
if (!confirmed) {
return
@@ -924,10 +898,10 @@ const updateApiKey = async () => {
emit('success')
emit('close')
} else {
showToast(result.message || t('apiKeys.editApiKeyModal.updateFailed'), 'error')
showToast(result.message || '更新失败', 'error')
}
} catch (error) {
showToast(t('apiKeys.editApiKeyModal.updateFailed'), 'error')
showToast('更新失败', 'error')
} finally {
loading.value = false
}
@@ -937,15 +911,23 @@ const updateApiKey = async () => {
const refreshAccounts = async () => {
accountsLoading.value = true
try {
const [claudeData, claudeConsoleData, geminiData, openaiData, bedrockData, groupsData] =
await Promise.all([
apiClient.get('/admin/claude-accounts'),
apiClient.get('/admin/claude-console-accounts'),
apiClient.get('/admin/gemini-accounts'),
apiClient.get('/admin/openai-accounts'),
apiClient.get('/admin/bedrock-accounts'), // 添加 Bedrock 账号获取
apiClient.get('/admin/account-groups')
])
const [
claudeData,
claudeConsoleData,
geminiData,
openaiData,
openaiResponsesData,
bedrockData,
groupsData
] = await Promise.all([
apiClient.get('/admin/claude-accounts'),
apiClient.get('/admin/claude-console-accounts'),
apiClient.get('/admin/gemini-accounts'),
apiClient.get('/admin/openai-accounts'),
apiClient.get('/admin/openai-responses-accounts'), // 获取 OpenAI-Responses 账号
apiClient.get('/admin/bedrock-accounts'), // 添加 Bedrock 账号获取
apiClient.get('/admin/account-groups')
])
// 合并Claude OAuth账户和Claude Console账户
const claudeAccounts = []
@@ -979,13 +961,31 @@ const refreshAccounts = async () => {
}))
}
// 合并 OpenAI 和 OpenAI-Responses 账号
const openaiAccounts = []
if (openaiData.success) {
localAccounts.value.openai = (openaiData.data || []).map((account) => ({
...account,
isDedicated: account.accountType === 'dedicated'
}))
;(openaiData.data || []).forEach((account) => {
openaiAccounts.push({
...account,
platform: 'openai',
isDedicated: account.accountType === 'dedicated'
})
})
}
if (openaiResponsesData.success) {
;(openaiResponsesData.data || []).forEach((account) => {
openaiAccounts.push({
...account,
platform: 'openai-responses',
isDedicated: account.accountType === 'dedicated'
})
})
}
localAccounts.value.openai = openaiAccounts
if (bedrockData.success) {
localAccounts.value.bedrock = (bedrockData.data || []).map((account) => ({
...account,
@@ -1001,9 +1001,9 @@ const refreshAccounts = async () => {
localAccounts.value.openaiGroups = allGroups.filter((g) => g.platform === 'openai')
}
showToast(t('apiKeys.editApiKeyModal.refreshAccountsSuccess'), 'success')
showToast('账号列表已刷新', 'success')
} catch (error) {
showToast(t('apiKeys.editApiKeyModal.refreshAccountsFailed'), 'error')
showToast('刷新账号列表失败', 'error')
} finally {
accountsLoading.value = false
}
@@ -1017,7 +1017,7 @@ const loadUsers = async () => {
availableUsers.value = response.data || []
}
} catch (error) {
console.error('Failed to load users:', error)
// console.error('Failed to load users:', error)
availableUsers.value = [
{
id: 'admin',
@@ -1043,7 +1043,7 @@ onMounted(async () => {
supportedClients.value = clients || []
availableTags.value = tags || []
} catch (error) {
console.error('Error loading initial data:', error)
// console.error('Error loading initial data:', error)
// Fallback to empty arrays if loading fails
supportedClients.value = []
availableTags.value = []
@@ -1051,10 +1051,29 @@ onMounted(async () => {
// 初始化账号数据
if (props.accounts) {
// 合并 OpenAI 和 OpenAI-Responses 账号
const openaiAccounts = []
if (props.accounts.openai) {
props.accounts.openai.forEach((account) => {
openaiAccounts.push({
...account,
platform: 'openai'
})
})
}
if (props.accounts.openaiResponses) {
props.accounts.openaiResponses.forEach((account) => {
openaiAccounts.push({
...account,
platform: 'openai-responses'
})
})
}
localAccounts.value = {
claude: props.accounts.claude || [],
gemini: props.accounts.gemini || [],
openai: props.accounts.openai || [],
openai: openaiAccounts,
bedrock: props.accounts.bedrock || [], // 添加 Bedrock 账号
claudeGroups: props.accounts.claudeGroups || [],
geminiGroups: props.accounts.geminiGroups || [],
@@ -1062,6 +1081,9 @@ onMounted(async () => {
}
}
// 自动加载账号数据
await refreshAccounts()
form.name = props.apiKey.name
// 处理速率限制迁移如果有tokenLimit且没有rateLimitCost提示用户
@@ -1071,7 +1093,7 @@ onMounted(async () => {
// 如果有历史tokenLimit但没有rateLimitCost提示用户需要重新设置
if (props.apiKey.tokenLimit > 0 && !props.apiKey.rateLimitCost) {
// 可以根据需要添加提示,或者自动迁移(这里选择让用户手动设置)
console.log('Token limit migration detected, consider setting cost limit')
// console.log('检测到历史Token限制请考虑设置费用限制')
}
form.rateLimitWindow = props.apiKey.rateLimitWindow || ''
@@ -1087,7 +1109,10 @@ onMounted(async () => {
form.claudeAccountId = props.apiKey.claudeAccountId || ''
}
form.geminiAccountId = props.apiKey.geminiAccountId || ''
// 处理 OpenAI 账号 - 直接使用后端传来的值(已包含 responses: 前缀)
form.openaiAccountId = props.apiKey.openaiAccountId || ''
form.bedrockAccountId = props.apiKey.bedrockAccountId || '' // 添加 Bedrock 账号ID初始化
form.restrictedModels = props.apiKey.restrictedModels || []
form.allowedClients = props.apiKey.allowedClients || []