mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
Merge remote-tracking branch 'f3n9/main' into user-management-new
This commit is contained in:
@@ -555,14 +555,37 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Claude、Claude Console和Bedrock的优先级设置 -->
|
||||
<div
|
||||
v-if="
|
||||
form.platform === 'claude' ||
|
||||
form.platform === 'claude-console' ||
|
||||
form.platform === 'bedrock'
|
||||
"
|
||||
>
|
||||
<!-- Claude 订阅类型选择 -->
|
||||
<div v-if="form.platform === 'claude'">
|
||||
<label class="mb-3 block text-sm font-semibold text-gray-700">订阅类型</label>
|
||||
<div class="flex gap-4">
|
||||
<label class="flex cursor-pointer items-center">
|
||||
<input
|
||||
v-model="form.subscriptionType"
|
||||
class="mr-2"
|
||||
type="radio"
|
||||
value="claude_max"
|
||||
/>
|
||||
<span class="text-sm text-gray-700">Claude Max</span>
|
||||
</label>
|
||||
<label class="flex cursor-pointer items-center">
|
||||
<input
|
||||
v-model="form.subscriptionType"
|
||||
class="mr-2"
|
||||
type="radio"
|
||||
value="claude_pro"
|
||||
/>
|
||||
<span class="text-sm text-gray-700">Claude Pro</span>
|
||||
</label>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-gray-500">
|
||||
<i class="fas fa-info-circle mr-1" />
|
||||
Pro 账号不支持 Claude Opus 4 模型
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 所有平台的优先级设置 -->
|
||||
<div>
|
||||
<label class="mb-3 block text-sm font-semibold text-gray-700"
|
||||
>调度优先级 (1-100)</label
|
||||
>
|
||||
@@ -961,14 +984,37 @@
|
||||
<p class="mt-2 text-xs text-gray-500">Google Cloud/Workspace 账号可能需要提供项目 ID</p>
|
||||
</div>
|
||||
|
||||
<!-- Claude、Claude Console和Bedrock的优先级设置(编辑模式) -->
|
||||
<div
|
||||
v-if="
|
||||
form.platform === 'claude' ||
|
||||
form.platform === 'claude-console' ||
|
||||
form.platform === 'bedrock'
|
||||
"
|
||||
>
|
||||
<!-- Claude 订阅类型选择(编辑模式) -->
|
||||
<div v-if="form.platform === 'claude'">
|
||||
<label class="mb-3 block text-sm font-semibold text-gray-700">订阅类型</label>
|
||||
<div class="flex gap-4">
|
||||
<label class="flex cursor-pointer items-center">
|
||||
<input
|
||||
v-model="form.subscriptionType"
|
||||
class="mr-2"
|
||||
type="radio"
|
||||
value="claude_max"
|
||||
/>
|
||||
<span class="text-sm text-gray-700">Claude Max</span>
|
||||
</label>
|
||||
<label class="flex cursor-pointer items-center">
|
||||
<input
|
||||
v-model="form.subscriptionType"
|
||||
class="mr-2"
|
||||
type="radio"
|
||||
value="claude_pro"
|
||||
/>
|
||||
<span class="text-sm text-gray-700">Claude Pro</span>
|
||||
</label>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-gray-500">
|
||||
<i class="fas fa-info-circle mr-1" />
|
||||
Pro 账号不支持 Claude Opus 4 模型
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 所有平台的优先级设置(编辑模式) -->
|
||||
<div>
|
||||
<label class="mb-3 block text-sm font-semibold text-gray-700">调度优先级 (1-100)</label>
|
||||
<input
|
||||
v-model.number="form.priority"
|
||||
@@ -1419,6 +1465,7 @@ const form = ref({
|
||||
name: props.account?.name || '',
|
||||
description: props.account?.description || '',
|
||||
accountType: props.account?.accountType || 'shared',
|
||||
subscriptionType: 'claude_max', // 默认为 Claude Max,兼容旧数据
|
||||
groupId: '',
|
||||
projectId: props.account?.projectId || '',
|
||||
idToken: '',
|
||||
@@ -1678,12 +1725,21 @@ const handleOAuthSuccess = async (tokenInfo) => {
|
||||
// Claude使用claudeAiOauth字段
|
||||
data.claudeAiOauth = tokenInfo.claudeAiOauth || tokenInfo
|
||||
data.priority = form.value.priority || 50
|
||||
// 添加订阅类型信息
|
||||
data.subscriptionInfo = {
|
||||
accountType: form.value.subscriptionType || 'claude_max',
|
||||
hasClaudeMax: form.value.subscriptionType === 'claude_max',
|
||||
hasClaudePro: form.value.subscriptionType === 'claude_pro',
|
||||
manuallySet: true // 标记为手动设置
|
||||
}
|
||||
} else if (form.value.platform === 'gemini') {
|
||||
// Gemini使用geminiOauth字段
|
||||
data.geminiOauth = tokenInfo.tokens || tokenInfo
|
||||
if (form.value.projectId) {
|
||||
data.projectId = form.value.projectId
|
||||
}
|
||||
// 添加 Gemini 优先级
|
||||
data.priority = form.value.priority || 50
|
||||
} else if (form.value.platform === 'openai') {
|
||||
data.openaiOauth = tokenInfo.tokens || tokenInfo
|
||||
data.accountInfo = tokenInfo.accountInfo
|
||||
@@ -1803,9 +1859,16 @@ const createAccount = async () => {
|
||||
accessToken: form.value.accessToken,
|
||||
refreshToken: form.value.refreshToken || '',
|
||||
expiresAt: Date.now() + expiresInMs,
|
||||
scopes: ['user:inference']
|
||||
scopes: [] // 手动添加没有 scopes
|
||||
}
|
||||
data.priority = form.value.priority || 50
|
||||
// 添加订阅类型信息
|
||||
data.subscriptionInfo = {
|
||||
accountType: form.value.subscriptionType || 'claude_max',
|
||||
hasClaudeMax: form.value.subscriptionType === 'claude_max',
|
||||
hasClaudePro: form.value.subscriptionType === 'claude_pro',
|
||||
manuallySet: true // 标记为手动设置
|
||||
}
|
||||
} else if (form.value.platform === 'gemini') {
|
||||
// Gemini手动模式需要构建geminiOauth对象
|
||||
const expiresInMs = form.value.refreshToken
|
||||
@@ -1823,6 +1886,9 @@ const createAccount = async () => {
|
||||
if (form.value.projectId) {
|
||||
data.projectId = form.value.projectId
|
||||
}
|
||||
|
||||
// 添加 Gemini 优先级
|
||||
data.priority = form.value.priority || 50
|
||||
} else if (form.value.platform === 'openai') {
|
||||
// OpenAI手动模式需要构建openaiOauth对象
|
||||
const expiresInMs = form.value.refreshToken
|
||||
@@ -1985,7 +2051,7 @@ const updateAccount = async () => {
|
||||
accessToken: form.value.accessToken || '',
|
||||
refreshToken: form.value.refreshToken || '',
|
||||
expiresAt: Date.now() + expiresInMs,
|
||||
scopes: ['user:inference']
|
||||
scopes: props.account.scopes || [] // 保持原有的 scopes,如果没有则为空数组
|
||||
}
|
||||
} else if (props.account.platform === 'gemini') {
|
||||
// Gemini需要构建geminiOauth对象
|
||||
@@ -2019,9 +2085,16 @@ const updateAccount = async () => {
|
||||
data.projectId = form.value.projectId
|
||||
}
|
||||
|
||||
// Claude 官方账号优先级更新
|
||||
// Claude 官方账号优先级和订阅类型更新
|
||||
if (props.account.platform === 'claude') {
|
||||
data.priority = form.value.priority || 50
|
||||
// 更新订阅类型信息
|
||||
data.subscriptionInfo = {
|
||||
accountType: form.value.subscriptionType || 'claude_max',
|
||||
hasClaudeMax: form.value.subscriptionType === 'claude_max',
|
||||
hasClaudePro: form.value.subscriptionType === 'claude_pro',
|
||||
manuallySet: true // 标记为手动设置
|
||||
}
|
||||
}
|
||||
|
||||
// OpenAI 账号优先级更新
|
||||
@@ -2029,6 +2102,11 @@ const updateAccount = async () => {
|
||||
data.priority = form.value.priority || 50
|
||||
}
|
||||
|
||||
// Gemini 账号优先级更新
|
||||
if (props.account.platform === 'gemini') {
|
||||
data.priority = form.value.priority || 50
|
||||
}
|
||||
|
||||
// Claude Console 特定更新
|
||||
if (props.account.platform === 'claude-console') {
|
||||
data.apiUrl = form.value.apiUrl
|
||||
@@ -2319,12 +2397,32 @@ watch(
|
||||
groupId = newAccount.groupId || (newAccount.groupInfo && newAccount.groupInfo.id) || ''
|
||||
}
|
||||
|
||||
// 初始化订阅类型(从 subscriptionInfo 中提取,兼容旧数据默认为 claude_max)
|
||||
let subscriptionType = 'claude_max'
|
||||
if (newAccount.subscriptionInfo) {
|
||||
const info =
|
||||
typeof newAccount.subscriptionInfo === 'string'
|
||||
? JSON.parse(newAccount.subscriptionInfo)
|
||||
: newAccount.subscriptionInfo
|
||||
|
||||
if (info.accountType) {
|
||||
subscriptionType = info.accountType
|
||||
} else if (info.hasClaudeMax) {
|
||||
subscriptionType = 'claude_max'
|
||||
} else if (info.hasClaudePro) {
|
||||
subscriptionType = 'claude_pro'
|
||||
} else {
|
||||
subscriptionType = 'claude_free'
|
||||
}
|
||||
}
|
||||
|
||||
form.value = {
|
||||
platform: newAccount.platform,
|
||||
addType: 'oauth',
|
||||
name: newAccount.name,
|
||||
description: newAccount.description || '',
|
||||
accountType: newAccount.accountType || 'shared',
|
||||
subscriptionType: subscriptionType,
|
||||
groupId: groupId,
|
||||
projectId: newAccount.projectId || '',
|
||||
accessToken: '',
|
||||
|
||||
@@ -436,6 +436,18 @@
|
||||
platform="openai"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-gray-600">Bedrock 专属账号</label>
|
||||
<AccountSelector
|
||||
v-model="form.bedrockAccountId"
|
||||
:accounts="localAccounts.bedrock"
|
||||
default-option-text="使用共享账号池"
|
||||
:disabled="form.permissions === 'gemini' || form.permissions === 'openai'"
|
||||
:groups="[]"
|
||||
placeholder="请选择Bedrock账号"
|
||||
platform="bedrock"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-gray-500">
|
||||
选择专属账号后,此API Key将只使用该账号,不选择则使用共享账号池
|
||||
@@ -618,6 +630,7 @@ const localAccounts = ref({
|
||||
claude: [],
|
||||
gemini: [],
|
||||
openai: [],
|
||||
bedrock: [], // 添加 Bedrock 账号列表
|
||||
claudeGroups: [],
|
||||
geminiGroups: [],
|
||||
openaiGroups: []
|
||||
@@ -658,6 +671,7 @@ const form = reactive({
|
||||
claudeAccountId: '',
|
||||
geminiAccountId: '',
|
||||
openaiAccountId: '',
|
||||
bedrockAccountId: '', // 添加 Bedrock 账号ID
|
||||
enableModelRestriction: false,
|
||||
restrictedModels: [],
|
||||
modelInput: '',
|
||||
@@ -676,6 +690,7 @@ onMounted(async () => {
|
||||
claude: props.accounts.claude || [],
|
||||
gemini: props.accounts.gemini || [],
|
||||
openai: props.accounts.openai || [],
|
||||
bedrock: props.accounts.bedrock || [], // 添加 Bedrock 账号
|
||||
claudeGroups: props.accounts.claudeGroups || [],
|
||||
geminiGroups: props.accounts.geminiGroups || [],
|
||||
openaiGroups: props.accounts.openaiGroups || []
|
||||
@@ -687,13 +702,15 @@ onMounted(async () => {
|
||||
const refreshAccounts = async () => {
|
||||
accountsLoading.value = true
|
||||
try {
|
||||
const [claudeData, claudeConsoleData, geminiData, openaiData, 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/account-groups')
|
||||
])
|
||||
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')
|
||||
])
|
||||
|
||||
// 合并Claude OAuth账户和Claude Console账户
|
||||
const claudeAccounts = []
|
||||
@@ -734,6 +751,13 @@ const refreshAccounts = async () => {
|
||||
}))
|
||||
}
|
||||
|
||||
if (bedrockData.success) {
|
||||
localAccounts.value.bedrock = (bedrockData.data || []).map((account) => ({
|
||||
...account,
|
||||
isDedicated: account.accountType === 'dedicated' // 保留以便向后兼容
|
||||
}))
|
||||
}
|
||||
|
||||
// 处理分组数据
|
||||
if (groupsData.success) {
|
||||
const allGroups = groupsData.data || []
|
||||
@@ -939,6 +963,11 @@ const createApiKey = async () => {
|
||||
baseData.openaiAccountId = form.openaiAccountId
|
||||
}
|
||||
|
||||
// Bedrock账户绑定
|
||||
if (form.bedrockAccountId) {
|
||||
baseData.bedrockAccountId = form.bedrockAccountId
|
||||
}
|
||||
|
||||
if (form.createType === 'single') {
|
||||
// 单个创建
|
||||
const data = {
|
||||
|
||||
@@ -339,6 +339,18 @@
|
||||
platform="openai"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="mb-1 block text-sm font-medium text-gray-600">Bedrock 专属账号</label>
|
||||
<AccountSelector
|
||||
v-model="form.bedrockAccountId"
|
||||
:accounts="localAccounts.bedrock"
|
||||
default-option-text="使用共享账号池"
|
||||
:disabled="form.permissions === 'gemini' || form.permissions === 'openai'"
|
||||
:groups="[]"
|
||||
placeholder="请选择Bedrock账号"
|
||||
platform="bedrock"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-gray-500">修改绑定账号将影响此API Key的请求路由</p>
|
||||
</div>
|
||||
@@ -522,6 +534,7 @@ const localAccounts = ref({
|
||||
claude: [],
|
||||
gemini: [],
|
||||
openai: [],
|
||||
bedrock: [], // 添加 Bedrock 账号列表
|
||||
claudeGroups: [],
|
||||
geminiGroups: [],
|
||||
openaiGroups: []
|
||||
@@ -551,6 +564,7 @@ const form = reactive({
|
||||
claudeAccountId: '',
|
||||
geminiAccountId: '',
|
||||
openaiAccountId: '',
|
||||
bedrockAccountId: '', // 添加 Bedrock 账号ID
|
||||
enableModelRestriction: false,
|
||||
restrictedModels: [],
|
||||
modelInput: '',
|
||||
@@ -673,6 +687,13 @@ const updateApiKey = async () => {
|
||||
data.openaiAccountId = null
|
||||
}
|
||||
|
||||
// Bedrock账户绑定
|
||||
if (form.bedrockAccountId) {
|
||||
data.bedrockAccountId = form.bedrockAccountId
|
||||
} else {
|
||||
data.bedrockAccountId = null
|
||||
}
|
||||
|
||||
// 模型限制 - 始终提交这些字段
|
||||
data.enableModelRestriction = form.enableModelRestriction
|
||||
data.restrictedModels = form.restrictedModels
|
||||
@@ -703,13 +724,15 @@ const updateApiKey = async () => {
|
||||
const refreshAccounts = async () => {
|
||||
accountsLoading.value = true
|
||||
try {
|
||||
const [claudeData, claudeConsoleData, geminiData, openaiData, 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/account-groups')
|
||||
])
|
||||
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')
|
||||
])
|
||||
|
||||
// 合并Claude OAuth账户和Claude Console账户
|
||||
const claudeAccounts = []
|
||||
@@ -750,6 +773,13 @@ const refreshAccounts = async () => {
|
||||
}))
|
||||
}
|
||||
|
||||
if (bedrockData.success) {
|
||||
localAccounts.value.bedrock = (bedrockData.data || []).map((account) => ({
|
||||
...account,
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
}))
|
||||
}
|
||||
|
||||
// 处理分组数据
|
||||
if (groupsData.success) {
|
||||
const allGroups = groupsData.data || []
|
||||
@@ -778,6 +808,7 @@ onMounted(async () => {
|
||||
claude: props.accounts.claude || [],
|
||||
gemini: props.accounts.gemini || [],
|
||||
openai: props.accounts.openai || [],
|
||||
bedrock: props.accounts.bedrock || [], // 添加 Bedrock 账号
|
||||
claudeGroups: props.accounts.claudeGroups || [],
|
||||
geminiGroups: props.accounts.geminiGroups || [],
|
||||
openaiGroups: props.accounts.openaiGroups || []
|
||||
@@ -799,6 +830,7 @@ onMounted(async () => {
|
||||
}
|
||||
form.geminiAccountId = props.apiKey.geminiAccountId || ''
|
||||
form.openaiAccountId = props.apiKey.openaiAccountId || ''
|
||||
form.bedrockAccountId = props.apiKey.bedrockAccountId || '' // 添加 Bedrock 账号ID初始化
|
||||
form.restrictedModels = props.apiKey.restrictedModels || []
|
||||
form.allowedClients = props.apiKey.allowedClients || []
|
||||
form.tags = props.apiKey.tags || []
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
<span class="text-xs font-semibold text-yellow-800">Gemini</span>
|
||||
<span class="mx-1 h-4 w-px bg-yellow-300" />
|
||||
<span class="text-xs font-medium text-yellow-700">
|
||||
{{ account.scopes && account.scopes.length > 0 ? 'OAuth' : '传统' }}
|
||||
{{ getGeminiAuthType() }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -289,19 +289,28 @@
|
||||
<div class="fa-openai" />
|
||||
<span class="text-xs font-semibold text-gray-950">OpenAi</span>
|
||||
<span class="mx-1 h-4 w-px bg-gray-400" />
|
||||
<span class="text-xs font-medium text-gray-950">Oauth</span>
|
||||
<span class="text-xs font-medium text-gray-950">{{ getOpenAIAuthType() }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
v-else-if="account.platform === 'claude' || account.platform === 'claude-oauth'"
|
||||
class="flex items-center gap-1.5 rounded-lg border border-indigo-200 bg-gradient-to-r from-indigo-100 to-blue-100 px-2.5 py-1"
|
||||
>
|
||||
<i class="fas fa-brain text-xs text-indigo-700" />
|
||||
<span class="text-xs font-semibold text-indigo-800">Claude</span>
|
||||
<span class="text-xs font-semibold text-indigo-800">{{
|
||||
getClaudeAccountType(account)
|
||||
}}</span>
|
||||
<span class="mx-1 h-4 w-px bg-indigo-300" />
|
||||
<span class="text-xs font-medium text-indigo-700">
|
||||
{{ account.scopes && account.scopes.length > 0 ? 'OAuth' : '传统' }}
|
||||
{{ getClaudeAuthType(account) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="flex items-center gap-1.5 rounded-lg border border-gray-200 bg-gradient-to-r from-gray-100 to-gray-200 px-2.5 py-1"
|
||||
>
|
||||
<i class="fas fa-question text-xs text-gray-700" />
|
||||
<span class="text-xs font-semibold text-gray-800">未知</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-3 py-4">
|
||||
@@ -382,7 +391,9 @@
|
||||
v-if="
|
||||
account.platform === 'claude' ||
|
||||
account.platform === 'claude-console' ||
|
||||
account.platform === 'bedrock'
|
||||
account.platform === 'bedrock' ||
|
||||
account.platform === 'gemini' ||
|
||||
account.platform === 'openai'
|
||||
"
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
@@ -482,21 +493,6 @@
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm font-medium">
|
||||
<div class="flex flex-wrap items-center gap-1">
|
||||
<button
|
||||
v-if="account.platform === 'claude' && account.scopes"
|
||||
:class="[
|
||||
'rounded px-2.5 py-1 text-xs font-medium transition-colors',
|
||||
account.isRefreshing
|
||||
? 'cursor-not-allowed bg-gray-100 text-gray-400'
|
||||
: 'bg-blue-100 text-blue-700 hover:bg-blue-200'
|
||||
]"
|
||||
:disabled="account.isRefreshing"
|
||||
:title="account.isRefreshing ? '刷新中...' : '刷新Token'"
|
||||
@click="refreshToken(account)"
|
||||
>
|
||||
<i :class="['fas fa-sync-alt', account.isRefreshing ? 'animate-spin' : '']" />
|
||||
<span class="ml-1">刷新</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="
|
||||
account.platform === 'claude' &&
|
||||
@@ -700,23 +696,13 @@
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="text-gray-500">优先级</span>
|
||||
<span class="font-medium text-gray-700">
|
||||
{{ account.priority || 0 }}
|
||||
{{ account.priority || 50 }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="mt-3 flex gap-2 border-t border-gray-100 pt-3">
|
||||
<button
|
||||
v-if="account.platform === 'claude' && account.type === 'oauth'"
|
||||
class="flex flex-1 items-center justify-center gap-1 rounded-lg bg-blue-50 px-3 py-2 text-xs text-blue-600 transition-colors hover:bg-blue-100"
|
||||
:disabled="refreshingTokens[account.id]"
|
||||
@click="refreshAccountToken(account)"
|
||||
>
|
||||
<i :class="['fas fa-sync-alt', { 'animate-spin': refreshingTokens[account.id] }]" />
|
||||
{{ refreshingTokens[account.id] ? '刷新中' : '刷新' }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex flex-1 items-center justify-center gap-1 rounded-lg px-3 py-2 text-xs transition-colors"
|
||||
:class="
|
||||
@@ -797,7 +783,6 @@ const accountSortBy = ref('name')
|
||||
const accountsSortBy = ref('')
|
||||
const accountsSortOrder = ref('asc')
|
||||
const apiKeys = ref([])
|
||||
const refreshingTokens = ref({})
|
||||
const accountGroups = ref([])
|
||||
const groupFilter = ref('all')
|
||||
const platformFilter = ref('all')
|
||||
@@ -821,7 +806,7 @@ const platformOptions = ref([
|
||||
{ value: 'all', label: '所有平台', icon: 'fa-globe' },
|
||||
{ value: 'claude', label: 'Claude', icon: 'fa-brain' },
|
||||
{ value: 'claude-console', label: 'Claude Console', icon: 'fa-terminal' },
|
||||
{ value: 'gemini', label: 'Gemini', icon: 'fa-robot' },
|
||||
{ value: 'gemini', label: 'Gemini', icon: 'fa-google' },
|
||||
{ value: 'openai', label: 'OpenAi', icon: 'fa-openai' },
|
||||
{ value: 'bedrock', label: 'Bedrock', icon: 'fab fa-aws' }
|
||||
])
|
||||
@@ -1266,27 +1251,6 @@ const deleteAccount = async (account) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新Token
|
||||
const refreshToken = async (account) => {
|
||||
if (account.isRefreshing) return
|
||||
|
||||
try {
|
||||
account.isRefreshing = true
|
||||
const data = await apiClient.post(`/admin/claude-accounts/${account.id}/refresh`)
|
||||
|
||||
if (data.success) {
|
||||
showToast('Token刷新成功', 'success')
|
||||
loadAccounts()
|
||||
} else {
|
||||
showToast(data.message || 'Token刷新失败', 'error')
|
||||
}
|
||||
} catch (error) {
|
||||
showToast('Token刷新失败', 'error')
|
||||
} finally {
|
||||
account.isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置账户状态
|
||||
const resetAccountStatus = async (account) => {
|
||||
if (account.isResetting) return
|
||||
@@ -1378,6 +1342,66 @@ const handleEditSuccess = () => {
|
||||
loadAccounts()
|
||||
}
|
||||
|
||||
// 获取 Claude 账号的添加方式
|
||||
const getClaudeAuthType = (account) => {
|
||||
// 基于 lastRefreshAt 判断:如果为空说明是 Setup Token(不能刷新),否则是 OAuth
|
||||
if (!account.lastRefreshAt || account.lastRefreshAt === '') {
|
||||
return 'Setup' // 缩短显示文本
|
||||
}
|
||||
return 'OAuth'
|
||||
}
|
||||
|
||||
// 获取 Gemini 账号的添加方式
|
||||
const getGeminiAuthType = () => {
|
||||
// Gemini 统一显示 OAuth
|
||||
return 'OAuth'
|
||||
}
|
||||
|
||||
// 获取 OpenAI 账号的添加方式
|
||||
const getOpenAIAuthType = () => {
|
||||
// OpenAI 统一显示 OAuth
|
||||
return 'OAuth'
|
||||
}
|
||||
|
||||
// 获取 Claude 账号类型显示
|
||||
const getClaudeAccountType = (account) => {
|
||||
// 如果有订阅信息
|
||||
if (account.subscriptionInfo) {
|
||||
try {
|
||||
// 如果 subscriptionInfo 是字符串,尝试解析
|
||||
const info =
|
||||
typeof account.subscriptionInfo === 'string'
|
||||
? JSON.parse(account.subscriptionInfo)
|
||||
: account.subscriptionInfo
|
||||
|
||||
// 添加调试日志
|
||||
console.log('Account subscription info:', {
|
||||
accountName: account.name,
|
||||
subscriptionInfo: info,
|
||||
hasClaudeMax: info.hasClaudeMax,
|
||||
hasClaudePro: info.hasClaudePro
|
||||
})
|
||||
|
||||
// 根据 has_claude_max 和 has_claude_pro 判断
|
||||
if (info.hasClaudeMax === true) {
|
||||
return 'Claude Max'
|
||||
} else if (info.hasClaudePro === true) {
|
||||
return 'Claude Pro'
|
||||
} else {
|
||||
return 'Claude Free'
|
||||
}
|
||||
} catch (e) {
|
||||
// 解析失败,返回默认值
|
||||
console.error('Failed to parse subscription info:', e)
|
||||
return 'Claude'
|
||||
}
|
||||
}
|
||||
|
||||
// 没有订阅信息,保持原有显示
|
||||
console.log('No subscription info for account:', account.name)
|
||||
return 'Claude'
|
||||
}
|
||||
|
||||
// 获取账户状态文本
|
||||
const getAccountStatusText = (account) => {
|
||||
// 检查是否被封锁
|
||||
@@ -1463,27 +1487,6 @@ const formatRelativeTime = (dateString) => {
|
||||
return formatLastUsed(dateString)
|
||||
}
|
||||
|
||||
// 刷新账户Token
|
||||
const refreshAccountToken = async (account) => {
|
||||
if (refreshingTokens.value[account.id]) return
|
||||
|
||||
try {
|
||||
refreshingTokens.value[account.id] = true
|
||||
const data = await apiClient.post(`/admin/claude-accounts/${account.id}/refresh`)
|
||||
|
||||
if (data.success) {
|
||||
showToast('Token刷新成功', 'success')
|
||||
loadAccounts()
|
||||
} else {
|
||||
showToast(data.message || 'Token刷新失败', 'error')
|
||||
}
|
||||
} catch (error) {
|
||||
showToast('Token刷新失败', 'error')
|
||||
} finally {
|
||||
refreshingTokens.value[account.id] = false
|
||||
}
|
||||
}
|
||||
|
||||
// 切换调度状态
|
||||
// const toggleDispatch = async (account) => {
|
||||
// await toggleSchedulable(account)
|
||||
|
||||
Reference in New Issue
Block a user