mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
fix: 修复账户管理和API Key管理的多个问题
- 修复 Claude Console 账号 supportedModels 导致的 be.join 错误 - 添加专属账号选择器组件,支持搜索和按创建时间倒序排序 - 修复搜索框图标与placeholder文字重叠的问题 - 修复选择共享账号池后显示文字不正确的问题 - 优化下拉框定位逻辑,解决超出视窗无法滚动的问题 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -425,87 +425,27 @@
|
||||
<div class="grid grid-cols-1 gap-3">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">Claude 专属账号</label>
|
||||
<select
|
||||
v-model="form.claudeAccountId"
|
||||
class="form-input w-full"
|
||||
<AccountSelector
|
||||
v-model="form.claudeAccountId"
|
||||
platform="claude"
|
||||
:accounts="localAccounts.claude"
|
||||
:groups="localAccounts.claudeGroups"
|
||||
:disabled="form.permissions === 'gemini'"
|
||||
>
|
||||
<option value="">
|
||||
使用共享账号池
|
||||
</option>
|
||||
<optgroup
|
||||
v-if="localAccounts.claudeGroups && localAccounts.claudeGroups.length > 0"
|
||||
label="调度分组"
|
||||
>
|
||||
<option
|
||||
v-for="group in localAccounts.claudeGroups"
|
||||
:key="`group:${group.id}`"
|
||||
:value="`group:${group.id}`"
|
||||
>
|
||||
{{ group.name }} ({{ group.memberCount || 0 }} 个成员)
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-oauth').length > 0"
|
||||
label="Claude OAuth 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-oauth')"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
>
|
||||
{{ account.name }} ({{ account.status === 'active' ? '正常' : '异常' }})
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-console').length > 0"
|
||||
label="Claude Console 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-console')"
|
||||
:key="account.id"
|
||||
:value="`console:${account.id}`"
|
||||
>
|
||||
{{ account.name }} ({{ account.status === 'active' ? '正常' : '异常' }})
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
placeholder="请选择Claude账号"
|
||||
default-option-text="使用共享账号池"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">Gemini 专属账号</label>
|
||||
<select
|
||||
v-model="form.geminiAccountId"
|
||||
class="form-input w-full"
|
||||
<AccountSelector
|
||||
v-model="form.geminiAccountId"
|
||||
platform="gemini"
|
||||
:accounts="localAccounts.gemini"
|
||||
:groups="localAccounts.geminiGroups"
|
||||
:disabled="form.permissions === 'claude'"
|
||||
>
|
||||
<option value="">
|
||||
使用共享账号池
|
||||
</option>
|
||||
<optgroup
|
||||
v-if="localAccounts.geminiGroups && localAccounts.geminiGroups.length > 0"
|
||||
label="调度分组"
|
||||
>
|
||||
<option
|
||||
v-for="group in localAccounts.geminiGroups"
|
||||
:key="`group:${group.id}`"
|
||||
:value="`group:${group.id}`"
|
||||
>
|
||||
{{ group.name }} ({{ group.memberCount || 0 }} 个成员)
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.gemini.filter(a => a.accountType === 'dedicated').length > 0"
|
||||
label="Gemini 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.gemini.filter(a => a.accountType === 'dedicated')"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
>
|
||||
{{ account.name }} ({{ account.status === 'active' ? '正常' : '异常' }})
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
placeholder="请选择Gemini账号"
|
||||
default-option-text="使用共享账号池"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 mt-2">
|
||||
@@ -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: {
|
||||
|
||||
@@ -294,87 +294,27 @@
|
||||
<div class="grid grid-cols-1 gap-3">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">Claude 专属账号</label>
|
||||
<select
|
||||
v-model="form.claudeAccountId"
|
||||
class="form-input w-full"
|
||||
<AccountSelector
|
||||
v-model="form.claudeAccountId"
|
||||
platform="claude"
|
||||
:accounts="localAccounts.claude"
|
||||
:groups="localAccounts.claudeGroups"
|
||||
:disabled="form.permissions === 'gemini'"
|
||||
>
|
||||
<option value="">
|
||||
使用共享账号池
|
||||
</option>
|
||||
<optgroup
|
||||
v-if="localAccounts.claudeGroups && localAccounts.claudeGroups.length > 0"
|
||||
label="调度分组"
|
||||
>
|
||||
<option
|
||||
v-for="group in localAccounts.claudeGroups"
|
||||
:key="`group:${group.id}`"
|
||||
:value="`group:${group.id}`"
|
||||
>
|
||||
{{ group.name }} ({{ group.memberCount || 0 }} 个成员)
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-oauth').length > 0"
|
||||
label="Claude OAuth 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-oauth')"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
>
|
||||
{{ account.name }} ({{ account.status === 'active' ? '正常' : '异常' }})
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-console').length > 0"
|
||||
label="Claude Console 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-console')"
|
||||
:key="account.id"
|
||||
:value="`console:${account.id}`"
|
||||
>
|
||||
{{ account.name }} ({{ account.status === 'active' ? '正常' : '异常' }})
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
placeholder="请选择Claude账号"
|
||||
default-option-text="使用共享账号池"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-600 mb-1">Gemini 专属账号</label>
|
||||
<select
|
||||
v-model="form.geminiAccountId"
|
||||
class="form-input w-full"
|
||||
<AccountSelector
|
||||
v-model="form.geminiAccountId"
|
||||
platform="gemini"
|
||||
:accounts="localAccounts.gemini"
|
||||
:groups="localAccounts.geminiGroups"
|
||||
:disabled="form.permissions === 'claude'"
|
||||
>
|
||||
<option value="">
|
||||
使用共享账号池
|
||||
</option>
|
||||
<optgroup
|
||||
v-if="localAccounts.geminiGroups && localAccounts.geminiGroups.length > 0"
|
||||
label="调度分组"
|
||||
>
|
||||
<option
|
||||
v-for="group in localAccounts.geminiGroups"
|
||||
:key="`group:${group.id}`"
|
||||
:value="`group:${group.id}`"
|
||||
>
|
||||
{{ group.name }} ({{ group.memberCount || 0 }} 个成员)
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.gemini.filter(a => a.accountType === 'dedicated').length > 0"
|
||||
label="Gemini 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.gemini.filter(a => a.accountType === 'dedicated')"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
>
|
||||
{{ account.name }} ({{ account.status === 'active' ? '正常' : '异常' }})
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
placeholder="请选择Gemini账号"
|
||||
default-option-text="使用共享账号池"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 mt-2">
|
||||
@@ -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 || []
|
||||
|
||||
Reference in New Issue
Block a user