diff --git a/web/admin-spa/src/components/accounts/AccountForm.vue b/web/admin-spa/src/components/accounts/AccountForm.vue index eb252e55..10d469aa 100644 --- a/web/admin-spa/src/components/accounts/AccountForm.vue +++ b/web/admin-spa/src/components/accounts/AccountForm.vue @@ -870,7 +870,19 @@ const form = ref({ apiUrl: props.account?.apiUrl || '', apiKey: props.account?.apiKey || '', priority: props.account?.priority || 50, - supportedModels: props.account?.supportedModels?.join('\n') || '', + supportedModels: (() => { + const models = props.account?.supportedModels; + if (!models) return ''; + // 处理对象格式(Claude Console 的新格式) + if (typeof models === 'object' && !Array.isArray(models)) { + return Object.keys(models).join('\n'); + } + // 处理数组格式(向后兼容) + if (Array.isArray(models)) { + return models.join('\n'); + } + return ''; + })(), userAgent: props.account?.userAgent || '', rateLimitDuration: props.account?.rateLimitDuration || 60 }) @@ -1362,7 +1374,19 @@ watch(() => props.account, (newAccount) => { apiUrl: newAccount.apiUrl || '', apiKey: '', // 编辑模式不显示现有的 API Key priority: newAccount.priority || 50, - supportedModels: newAccount.supportedModels?.join('\n') || '', + supportedModels: (() => { + const models = newAccount.supportedModels; + if (!models) return ''; + // 处理对象格式(Claude Console 的新格式) + if (typeof models === 'object' && !Array.isArray(models)) { + return Object.keys(models).join('\n'); + } + // 处理数组格式(向后兼容) + if (Array.isArray(models)) { + return models.join('\n'); + } + return ''; + })(), userAgent: newAccount.userAgent || '', rateLimitDuration: newAccount.rateLimitDuration || 60 } diff --git a/web/admin-spa/src/components/apikeys/CreateApiKeyModal.vue b/web/admin-spa/src/components/apikeys/CreateApiKeyModal.vue index 4044b689..2020f74a 100644 --- a/web/admin-spa/src/components/apikeys/CreateApiKeyModal.vue +++ b/web/admin-spa/src/components/apikeys/CreateApiKeyModal.vue @@ -425,87 +425,27 @@
- + placeholder="请选择Claude账号" + default-option-text="使用共享账号池" + />
- + placeholder="请选择Gemini账号" + default-option-text="使用共享账号池" + />

@@ -665,6 +605,7 @@ import { showToast } from '@/utils/toast' import { useClientsStore } from '@/stores/clients' import { useApiKeysStore } from '@/stores/apiKeys' import { apiClient } from '@/config/api' +import AccountSelector from '@/components/common/AccountSelector.vue' const props = defineProps({ accounts: { diff --git a/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue b/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue index 87a42f6a..9b23dbb6 100644 --- a/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue +++ b/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue @@ -294,87 +294,27 @@

- + placeholder="请选择Claude账号" + default-option-text="使用共享账号池" + />
- + placeholder="请选择Gemini账号" + default-option-text="使用共享账号池" + />

@@ -538,6 +478,7 @@ import { useAuthStore } from '@/stores/auth' import { useClientsStore } from '@/stores/clients' import { useApiKeysStore } from '@/stores/apiKeys' import { apiClient } from '@/config/api' +import AccountSelector from '@/components/common/AccountSelector.vue' const props = defineProps({ apiKey: { @@ -638,11 +579,32 @@ const updateApiKey = async () => { concurrencyLimit: form.concurrencyLimit !== '' && form.concurrencyLimit !== null ? parseInt(form.concurrencyLimit) : 0, dailyCostLimit: form.dailyCostLimit !== '' && form.dailyCostLimit !== null ? parseFloat(form.dailyCostLimit) : 0, permissions: form.permissions, - claudeAccountId: form.claudeAccountId || null, - geminiAccountId: form.geminiAccountId || null, tags: form.tags } + // 处理Claude账户绑定(区分OAuth和Console) + if (form.claudeAccountId) { + if (form.claudeAccountId.startsWith('console:')) { + // Claude Console账户 + data.claudeConsoleAccountId = form.claudeAccountId.substring(8); + } else if (!form.claudeAccountId.startsWith('group:')) { + // Claude OAuth账户(非分组) + data.claudeAccountId = form.claudeAccountId; + } else { + // 分组 + data.claudeAccountId = form.claudeAccountId; + } + } else { + data.claudeAccountId = null; + } + + // Gemini账户绑定 + if (form.geminiAccountId) { + data.geminiAccountId = form.geminiAccountId; + } else { + data.geminiAccountId = null; + } + // 模型限制 - 始终提交这些字段 data.enableModelRestriction = form.enableModelRestriction data.restrictedModels = form.restrictedModels @@ -747,7 +709,12 @@ onMounted(async () => { form.concurrencyLimit = props.apiKey.concurrencyLimit || '' form.dailyCostLimit = props.apiKey.dailyCostLimit || '' form.permissions = props.apiKey.permissions || 'all' - form.claudeAccountId = props.apiKey.claudeAccountId || '' + // 处理 Claude 账号(区分 OAuth 和 Console) + if (props.apiKey.claudeConsoleAccountId) { + form.claudeAccountId = `console:${props.apiKey.claudeConsoleAccountId}` + } else { + form.claudeAccountId = props.apiKey.claudeAccountId || '' + } form.geminiAccountId = props.apiKey.geminiAccountId || '' form.restrictedModels = props.apiKey.restrictedModels || [] form.allowedClients = props.apiKey.allowedClients || [] diff --git a/web/admin-spa/src/components/common/AccountSelector.vue b/web/admin-spa/src/components/common/AccountSelector.vue new file mode 100644 index 00000000..da8ab6e8 --- /dev/null +++ b/web/admin-spa/src/components/common/AccountSelector.vue @@ -0,0 +1,468 @@ + + + + + \ No newline at end of file