mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
Merge branch 'Wei-Shaw:main' into main
This commit is contained in:
@@ -537,6 +537,17 @@
|
||||
<span class="mx-1 h-4 w-px bg-teal-300 dark:bg-teal-600" />
|
||||
<span class="text-xs font-medium text-teal-700 dark:text-teal-300">Relay</span>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="account.platform === 'droid'"
|
||||
class="flex items-center gap-1.5 rounded-lg border border-cyan-200 bg-gradient-to-r from-cyan-100 to-sky-100 px-2.5 py-1 dark:border-cyan-700 dark:from-cyan-900/20 dark:to-sky-900/20"
|
||||
>
|
||||
<i class="fas fa-robot text-xs text-cyan-700 dark:text-cyan-400" />
|
||||
<span class="text-xs font-semibold text-cyan-800 dark:text-cyan-300"
|
||||
>Droid</span
|
||||
>
|
||||
<span class="mx-1 h-4 w-px bg-cyan-300 dark:bg-cyan-600" />
|
||||
<span class="text-xs font-medium text-cyan-700 dark:text-cyan-300">OAuth</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"
|
||||
@@ -656,7 +667,8 @@
|
||||
account.platform === 'openai' ||
|
||||
account.platform === 'openai-responses' ||
|
||||
account.platform === 'azure_openai' ||
|
||||
account.platform === 'ccr'
|
||||
account.platform === 'ccr' ||
|
||||
account.platform === 'droid'
|
||||
"
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
@@ -1108,7 +1120,9 @@
|
||||
? 'bg-gradient-to-br from-gray-600 to-gray-700'
|
||||
: account.platform === 'ccr'
|
||||
? 'bg-gradient-to-br from-teal-500 to-emerald-600'
|
||||
: 'bg-gradient-to-br from-blue-500 to-blue-600'
|
||||
: account.platform === 'droid'
|
||||
? 'bg-gradient-to-br from-cyan-500 to-sky-600'
|
||||
: 'bg-gradient-to-br from-blue-500 to-blue-600'
|
||||
]"
|
||||
>
|
||||
<i
|
||||
@@ -1124,7 +1138,9 @@
|
||||
? 'fas fa-openai'
|
||||
: account.platform === 'ccr'
|
||||
? 'fas fa-code-branch'
|
||||
: 'fas fa-robot'
|
||||
: account.platform === 'droid'
|
||||
? 'fas fa-robot'
|
||||
: 'fas fa-robot'
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
@@ -1696,7 +1712,14 @@ const accountUsageSummary = ref({})
|
||||
const accountUsageOverview = ref({})
|
||||
const accountUsageGeneratedAt = ref('')
|
||||
|
||||
const supportedUsagePlatforms = ['claude', 'claude-console', 'openai', 'openai-responses', 'gemini']
|
||||
const supportedUsagePlatforms = [
|
||||
'claude',
|
||||
'claude-console',
|
||||
'openai',
|
||||
'openai-responses',
|
||||
'gemini',
|
||||
'droid'
|
||||
]
|
||||
|
||||
// 缓存状态标志
|
||||
const apiKeysLoaded = ref(false)
|
||||
@@ -1722,7 +1745,8 @@ const platformOptions = ref([
|
||||
{ value: 'azure_openai', label: 'Azure OpenAI', icon: 'fab fa-microsoft' },
|
||||
{ value: 'bedrock', label: 'Bedrock', icon: 'fab fa-aws' },
|
||||
{ value: 'openai-responses', label: 'OpenAI-Responses', icon: 'fa-server' },
|
||||
{ value: 'ccr', label: 'CCR', icon: 'fa-code-branch' }
|
||||
{ value: 'ccr', label: 'CCR', icon: 'fa-code-branch' },
|
||||
{ value: 'droid', label: 'Droid', icon: 'fa-robot' }
|
||||
])
|
||||
|
||||
const groupOptions = computed(() => {
|
||||
@@ -1733,13 +1757,15 @@ const groupOptions = computed(() => {
|
||||
accountGroups.value.forEach((group) => {
|
||||
options.push({
|
||||
value: group.id,
|
||||
label: `${group.name} (${group.platform === 'claude' ? 'Claude' : group.platform === 'gemini' ? 'Gemini' : 'OpenAI'})`,
|
||||
label: `${group.name} (${group.platform === 'claude' ? 'Claude' : group.platform === 'gemini' ? 'Gemini' : group.platform === 'openai' ? 'OpenAI' : 'Droid'})`,
|
||||
icon:
|
||||
group.platform === 'claude'
|
||||
? 'fa-brain'
|
||||
: group.platform === 'gemini'
|
||||
? 'fa-robot'
|
||||
: 'fa-openai'
|
||||
: group.platform === 'openai'
|
||||
? 'fa-openai'
|
||||
: 'fa-robot'
|
||||
})
|
||||
})
|
||||
return options
|
||||
@@ -2044,7 +2070,8 @@ const loadAccounts = async (forceReload = false) => {
|
||||
apiClient.get('/admin/openai-accounts', { params }),
|
||||
apiClient.get('/admin/azure-openai-accounts', { params }),
|
||||
apiClient.get('/admin/openai-responses-accounts', { params }),
|
||||
apiClient.get('/admin/ccr-accounts', { params })
|
||||
apiClient.get('/admin/ccr-accounts', { params }),
|
||||
apiClient.get('/admin/droid-accounts', { params })
|
||||
)
|
||||
} else {
|
||||
// 只请求指定平台,其他平台设为null占位
|
||||
@@ -2057,7 +2084,9 @@ const loadAccounts = async (forceReload = false) => {
|
||||
Promise.resolve({ success: true, data: [] }), // gemini 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai 占位
|
||||
Promise.resolve({ success: true, data: [] }), // azure-openai 占位
|
||||
Promise.resolve({ success: true, data: [] }) // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // ccr 占位
|
||||
Promise.resolve({ success: true, data: [] }) // droid 占位
|
||||
)
|
||||
break
|
||||
case 'claude-console':
|
||||
@@ -2068,7 +2097,9 @@ const loadAccounts = async (forceReload = false) => {
|
||||
Promise.resolve({ success: true, data: [] }), // gemini 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai 占位
|
||||
Promise.resolve({ success: true, data: [] }), // azure-openai 占位
|
||||
Promise.resolve({ success: true, data: [] }) // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // ccr 占位
|
||||
Promise.resolve({ success: true, data: [] }) // droid 占位
|
||||
)
|
||||
break
|
||||
case 'bedrock':
|
||||
@@ -2079,7 +2110,9 @@ const loadAccounts = async (forceReload = false) => {
|
||||
Promise.resolve({ success: true, data: [] }), // gemini 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai 占位
|
||||
Promise.resolve({ success: true, data: [] }), // azure-openai 占位
|
||||
Promise.resolve({ success: true, data: [] }) // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // ccr 占位
|
||||
Promise.resolve({ success: true, data: [] }) // droid 占位
|
||||
)
|
||||
break
|
||||
case 'gemini':
|
||||
@@ -2090,7 +2123,9 @@ const loadAccounts = async (forceReload = false) => {
|
||||
apiClient.get('/admin/gemini-accounts', { params }),
|
||||
Promise.resolve({ success: true, data: [] }), // openai 占位
|
||||
Promise.resolve({ success: true, data: [] }), // azure-openai 占位
|
||||
Promise.resolve({ success: true, data: [] }) // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // ccr 占位
|
||||
Promise.resolve({ success: true, data: [] }) // droid 占位
|
||||
)
|
||||
break
|
||||
case 'openai':
|
||||
@@ -2101,7 +2136,9 @@ const loadAccounts = async (forceReload = false) => {
|
||||
Promise.resolve({ success: true, data: [] }), // gemini 占位
|
||||
apiClient.get('/admin/openai-accounts', { params }),
|
||||
Promise.resolve({ success: true, data: [] }), // azure-openai 占位
|
||||
Promise.resolve({ success: true, data: [] }) // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // ccr 占位
|
||||
Promise.resolve({ success: true, data: [] }) // droid 占位
|
||||
)
|
||||
break
|
||||
case 'azure_openai':
|
||||
@@ -2112,7 +2149,9 @@ const loadAccounts = async (forceReload = false) => {
|
||||
Promise.resolve({ success: true, data: [] }), // gemini 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai 占位
|
||||
apiClient.get('/admin/azure-openai-accounts', { params }),
|
||||
Promise.resolve({ success: true, data: [] }) // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // ccr 占位
|
||||
Promise.resolve({ success: true, data: [] }) // droid 占位
|
||||
)
|
||||
break
|
||||
case 'openai-responses':
|
||||
@@ -2123,7 +2162,9 @@ const loadAccounts = async (forceReload = false) => {
|
||||
Promise.resolve({ success: true, data: [] }), // gemini 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai 占位
|
||||
Promise.resolve({ success: true, data: [] }), // azure-openai 占位
|
||||
apiClient.get('/admin/openai-responses-accounts', { params })
|
||||
apiClient.get('/admin/openai-responses-accounts', { params }),
|
||||
Promise.resolve({ success: true, data: [] }), // ccr 占位
|
||||
Promise.resolve({ success: true, data: [] }) // droid 占位
|
||||
)
|
||||
break
|
||||
case 'ccr':
|
||||
@@ -2134,7 +2175,22 @@ const loadAccounts = async (forceReload = false) => {
|
||||
Promise.resolve({ success: true, data: [] }), // gemini 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai 占位
|
||||
Promise.resolve({ success: true, data: [] }), // azure 占位
|
||||
apiClient.get('/admin/ccr-accounts', { params })
|
||||
Promise.resolve({ success: true, data: [] }), // openai-responses 占位
|
||||
apiClient.get('/admin/ccr-accounts', { params }),
|
||||
Promise.resolve({ success: true, data: [] }) // droid 占位
|
||||
)
|
||||
break
|
||||
case 'droid':
|
||||
requests.push(
|
||||
Promise.resolve({ success: true, data: [] }), // claude 占位
|
||||
Promise.resolve({ success: true, data: [] }), // claude-console 占位
|
||||
Promise.resolve({ success: true, data: [] }), // bedrock 占位
|
||||
Promise.resolve({ success: true, data: [] }), // gemini 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai 占位
|
||||
Promise.resolve({ success: true, data: [] }), // azure 占位
|
||||
Promise.resolve({ success: true, data: [] }), // openai-responses 占位
|
||||
Promise.resolve({ success: true, data: [] }), // ccr 占位
|
||||
apiClient.get('/admin/droid-accounts', { params })
|
||||
)
|
||||
break
|
||||
default:
|
||||
@@ -2146,6 +2202,8 @@ const loadAccounts = async (forceReload = false) => {
|
||||
Promise.resolve({ success: true, data: [] }),
|
||||
Promise.resolve({ success: true, data: [] }),
|
||||
Promise.resolve({ success: true, data: [] }),
|
||||
Promise.resolve({ success: true, data: [] }),
|
||||
Promise.resolve({ success: true, data: [] }),
|
||||
Promise.resolve({ success: true, data: [] })
|
||||
)
|
||||
break
|
||||
@@ -2166,7 +2224,8 @@ const loadAccounts = async (forceReload = false) => {
|
||||
openaiData,
|
||||
azureOpenaiData,
|
||||
openaiResponsesData,
|
||||
ccrData
|
||||
ccrData,
|
||||
droidData
|
||||
] = await Promise.all(requests)
|
||||
|
||||
const allAccounts = []
|
||||
@@ -2260,6 +2319,18 @@ const loadAccounts = async (forceReload = false) => {
|
||||
allAccounts.push(...ccrAccounts)
|
||||
}
|
||||
|
||||
// Droid 账户
|
||||
if (droidData && droidData.success) {
|
||||
const droidAccounts = (droidData.data || []).map((acc) => {
|
||||
return {
|
||||
...acc,
|
||||
platform: 'droid',
|
||||
boundApiKeysCount: acc.boundApiKeysCount ?? 0
|
||||
}
|
||||
})
|
||||
allAccounts.push(...droidAccounts)
|
||||
}
|
||||
|
||||
// 根据分组筛选器过滤账户
|
||||
let filteredAccounts = allAccounts
|
||||
if (groupFilter.value !== 'all') {
|
||||
@@ -2600,6 +2671,8 @@ const resolveAccountDeleteEndpoint = (account) => {
|
||||
return `/admin/ccr-accounts/${account.id}`
|
||||
case 'gemini':
|
||||
return `/admin/gemini-accounts/${account.id}`
|
||||
case 'droid':
|
||||
return `/admin/droid-accounts/${account.id}`
|
||||
default:
|
||||
return null
|
||||
}
|
||||
@@ -2778,6 +2851,8 @@ const resetAccountStatus = async (account) => {
|
||||
endpoint = `/admin/claude-console-accounts/${account.id}/reset-status`
|
||||
} else if (account.platform === 'ccr') {
|
||||
endpoint = `/admin/ccr-accounts/${account.id}/reset-status`
|
||||
} else if (account.platform === 'droid') {
|
||||
endpoint = `/admin/droid-accounts/${account.id}/reset-status`
|
||||
} else {
|
||||
showToast('不支持的账户类型', 'error')
|
||||
account.isResetting = false
|
||||
@@ -2824,6 +2899,8 @@ const toggleSchedulable = async (account) => {
|
||||
endpoint = `/admin/openai-responses-accounts/${account.id}/toggle-schedulable`
|
||||
} else if (account.platform === 'ccr') {
|
||||
endpoint = `/admin/ccr-accounts/${account.id}/toggle-schedulable`
|
||||
} else if (account.platform === 'droid') {
|
||||
endpoint = `/admin/droid-accounts/${account.id}/toggle-schedulable`
|
||||
} else {
|
||||
showToast('该账户类型暂不支持调度控制', 'warning')
|
||||
return
|
||||
|
||||
@@ -511,6 +511,18 @@
|
||||
{{ getBedrockBindingInfo(key) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- Droid 绑定 -->
|
||||
<div v-if="key.droidAccountId" class="flex items-center gap-1 text-xs">
|
||||
<span
|
||||
class="inline-flex items-center rounded bg-cyan-100 px-1.5 py-0.5 text-cyan-700 dark:bg-cyan-900/30 dark:text-cyan-300"
|
||||
>
|
||||
<i class="fas fa-robot mr-1 text-[10px]" />
|
||||
Droid
|
||||
</span>
|
||||
<span class="truncate text-gray-600 dark:text-gray-400">
|
||||
{{ getDroidBindingInfo(key) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 共享池 -->
|
||||
<div
|
||||
v-if="
|
||||
@@ -518,7 +530,8 @@
|
||||
!key.claudeConsoleAccountId &&
|
||||
!key.geminiAccountId &&
|
||||
!key.openaiAccountId &&
|
||||
!key.bedrockAccountId
|
||||
!key.bedrockAccountId &&
|
||||
!key.droidAccountId
|
||||
"
|
||||
class="text-xs text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
@@ -594,6 +607,47 @@
|
||||
variant="compact"
|
||||
/>
|
||||
|
||||
<!-- 时间窗口费用限制(无每日和总费用限制时展示) -->
|
||||
<div
|
||||
v-else-if="
|
||||
key.rateLimitWindow > 0 &&
|
||||
key.rateLimitCost > 0 &&
|
||||
(!key.dailyCostLimit || key.dailyCostLimit === 0) &&
|
||||
(!key.totalCostLimit || key.totalCostLimit === 0)
|
||||
"
|
||||
class="space-y-1.5"
|
||||
>
|
||||
<!-- 费用进度条 -->
|
||||
<LimitProgressBar
|
||||
:current="key.currentWindowCost || 0"
|
||||
label="窗口费用"
|
||||
:limit="key.rateLimitCost"
|
||||
type="window"
|
||||
variant="compact"
|
||||
/>
|
||||
<!-- 重置倒计时 -->
|
||||
<div class="flex items-center justify-between text-[10px]">
|
||||
<div class="flex items-center gap-1 text-sky-600 dark:text-sky-300">
|
||||
<i class="fas fa-clock text-[10px]" />
|
||||
<span class="font-medium">{{ key.rateLimitWindow }}分钟窗口</span>
|
||||
</div>
|
||||
<span
|
||||
class="font-bold"
|
||||
:class="
|
||||
key.windowRemainingSeconds > 0
|
||||
? 'text-sky-700 dark:text-sky-300'
|
||||
: 'text-gray-400 dark:text-gray-500'
|
||||
"
|
||||
>
|
||||
{{
|
||||
key.windowRemainingSeconds > 0
|
||||
? formatWindowTime(key.windowRemainingSeconds)
|
||||
: '未激活'
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 如果没有任何限制 -->
|
||||
<div
|
||||
v-else
|
||||
@@ -1141,6 +1195,18 @@
|
||||
{{ getBedrockBindingInfo(key) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- Droid 绑定 -->
|
||||
<div v-if="key.droidAccountId" class="flex flex-wrap items-center gap-1 text-xs">
|
||||
<span
|
||||
class="inline-flex items-center rounded bg-cyan-100 px-2 py-0.5 text-cyan-700 dark:bg-cyan-900/30 dark:text-cyan-300"
|
||||
>
|
||||
<i class="fas fa-robot mr-1" />
|
||||
Droid
|
||||
</span>
|
||||
<span class="text-gray-600 dark:text-gray-400">
|
||||
{{ getDroidBindingInfo(key) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 无绑定时显示共享池 -->
|
||||
<div
|
||||
v-if="
|
||||
@@ -1148,7 +1214,8 @@
|
||||
!key.claudeConsoleAccountId &&
|
||||
!key.geminiAccountId &&
|
||||
!key.openaiAccountId &&
|
||||
!key.bedrockAccountId
|
||||
!key.bedrockAccountId &&
|
||||
!key.droidAccountId
|
||||
"
|
||||
class="text-xs text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
@@ -1221,6 +1288,47 @@
|
||||
variant="compact"
|
||||
/>
|
||||
|
||||
<!-- 时间窗口费用限制(无每日和总费用限制时展示) -->
|
||||
<div
|
||||
v-else-if="
|
||||
key.rateLimitWindow > 0 &&
|
||||
key.rateLimitCost > 0 &&
|
||||
(!key.dailyCostLimit || key.dailyCostLimit === 0) &&
|
||||
(!key.totalCostLimit || key.totalCostLimit === 0)
|
||||
"
|
||||
class="space-y-2"
|
||||
>
|
||||
<!-- 费用进度条 -->
|
||||
<LimitProgressBar
|
||||
:current="key.currentWindowCost || 0"
|
||||
label="窗口费用"
|
||||
:limit="key.rateLimitCost"
|
||||
type="window"
|
||||
variant="compact"
|
||||
/>
|
||||
<!-- 重置倒计时 -->
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<div class="flex items-center gap-1.5 text-sky-600 dark:text-sky-300">
|
||||
<i class="fas fa-clock text-xs" />
|
||||
<span class="font-medium">{{ key.rateLimitWindow }}分钟窗口</span>
|
||||
</div>
|
||||
<span
|
||||
class="font-bold"
|
||||
:class="
|
||||
key.windowRemainingSeconds > 0
|
||||
? 'text-sky-700 dark:text-sky-300'
|
||||
: 'text-gray-400 dark:text-gray-500'
|
||||
"
|
||||
>
|
||||
{{
|
||||
key.windowRemainingSeconds > 0
|
||||
? formatWindowTime(key.windowRemainingSeconds)
|
||||
: '未激活'
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 无限制显示 -->
|
||||
<div
|
||||
v-else
|
||||
@@ -1839,9 +1947,11 @@ const accounts = ref({
|
||||
openai: [],
|
||||
openaiResponses: [], // 添加 OpenAI-Responses 账号列表
|
||||
bedrock: [],
|
||||
droid: [],
|
||||
claudeGroups: [],
|
||||
geminiGroups: [],
|
||||
openaiGroups: []
|
||||
openaiGroups: [],
|
||||
droidGroups: []
|
||||
})
|
||||
const editingExpiryKey = ref(null)
|
||||
const expiryEditModalRef = ref(null)
|
||||
@@ -1949,12 +2059,17 @@ const getBindingDisplayStrings = (key) => {
|
||||
appendBindingRow('Bedrock', getBedrockBindingInfo(key))
|
||||
}
|
||||
|
||||
if (key.droidAccountId) {
|
||||
appendBindingRow('Droid', getDroidBindingInfo(key))
|
||||
}
|
||||
|
||||
if (
|
||||
!key.claudeAccountId &&
|
||||
!key.claudeConsoleAccountId &&
|
||||
!key.geminiAccountId &&
|
||||
!key.openaiAccountId &&
|
||||
!key.bedrockAccountId
|
||||
!key.bedrockAccountId &&
|
||||
!key.droidAccountId
|
||||
) {
|
||||
collect('共享池')
|
||||
}
|
||||
@@ -2114,6 +2229,7 @@ const loadAccounts = async () => {
|
||||
openaiData,
|
||||
openaiResponsesData,
|
||||
bedrockData,
|
||||
droidData,
|
||||
groupsData
|
||||
] = await Promise.all([
|
||||
apiClient.get('/admin/claude-accounts'),
|
||||
@@ -2122,6 +2238,7 @@ const loadAccounts = async () => {
|
||||
apiClient.get('/admin/openai-accounts'),
|
||||
apiClient.get('/admin/openai-responses-accounts'), // 加载 OpenAI-Responses 账号
|
||||
apiClient.get('/admin/bedrock-accounts'),
|
||||
apiClient.get('/admin/droid-accounts'),
|
||||
apiClient.get('/admin/account-groups')
|
||||
])
|
||||
|
||||
@@ -2178,12 +2295,21 @@ const loadAccounts = async () => {
|
||||
}))
|
||||
}
|
||||
|
||||
if (droidData.success) {
|
||||
accounts.value.droid = (droidData.data || []).map((account) => ({
|
||||
...account,
|
||||
platform: 'droid',
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
}))
|
||||
}
|
||||
|
||||
if (groupsData.success) {
|
||||
// 处理分组数据
|
||||
const allGroups = groupsData.data || []
|
||||
accounts.value.claudeGroups = allGroups.filter((g) => g.platform === 'claude')
|
||||
accounts.value.geminiGroups = allGroups.filter((g) => g.platform === 'gemini')
|
||||
accounts.value.openaiGroups = allGroups.filter((g) => g.platform === 'openai')
|
||||
accounts.value.droidGroups = allGroups.filter((g) => g.platform === 'droid')
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error('加载账户列表失败:', error)
|
||||
@@ -2299,6 +2425,11 @@ const getBoundAccountName = (accountId) => {
|
||||
return `分组-${openaiGroup.name}`
|
||||
}
|
||||
|
||||
const droidGroup = accounts.value.droidGroups.find((g) => g.id === groupId)
|
||||
if (droidGroup) {
|
||||
return `分组-${droidGroup.name}`
|
||||
}
|
||||
|
||||
// 如果找不到分组,返回分组ID的前8位
|
||||
return `分组-${groupId.substring(0, 8)}`
|
||||
}
|
||||
@@ -2346,6 +2477,11 @@ const getBoundAccountName = (accountId) => {
|
||||
return `${bedrockAccount.name}`
|
||||
}
|
||||
|
||||
const droidAccount = accounts.value.droid.find((acc) => acc.id === accountId)
|
||||
if (droidAccount) {
|
||||
return `${droidAccount.name}`
|
||||
}
|
||||
|
||||
// 如果找不到,返回账户ID的前8位
|
||||
return `${accountId.substring(0, 8)}`
|
||||
}
|
||||
@@ -2448,6 +2584,24 @@ const getBedrockBindingInfo = (key) => {
|
||||
return ''
|
||||
}
|
||||
|
||||
const getDroidBindingInfo = (key) => {
|
||||
if (key.droidAccountId) {
|
||||
const info = getBoundAccountName(key.droidAccountId)
|
||||
if (key.droidAccountId.startsWith('group:')) {
|
||||
return info
|
||||
}
|
||||
const account = accounts.value.droid.find((acc) => acc.id === key.droidAccountId)
|
||||
if (!account) {
|
||||
return `⚠️ ${info} (账户不存在)`
|
||||
}
|
||||
if (account.accountType === 'dedicated') {
|
||||
return `🔒 专属-${info}`
|
||||
}
|
||||
return info
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
// 检查API Key是否过期
|
||||
const isApiKeyExpired = (expiresAt) => {
|
||||
if (!expiresAt) return false
|
||||
@@ -3432,6 +3586,23 @@ const formatDate = (dateString) => {
|
||||
.replace(/\//g, '-')
|
||||
}
|
||||
|
||||
// 格式化时间窗口倒计时
|
||||
const formatWindowTime = (seconds) => {
|
||||
if (seconds === null || seconds === undefined) return '--:--'
|
||||
|
||||
const hours = Math.floor(seconds / 3600)
|
||||
const minutes = Math.floor((seconds % 3600) / 60)
|
||||
const secs = seconds % 60
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h${minutes}m`
|
||||
} else if (minutes > 0) {
|
||||
return `${minutes}m${secs}s`
|
||||
} else {
|
||||
return `${secs}s`
|
||||
}
|
||||
}
|
||||
|
||||
// 获取每日费用进度 - 已移到 LimitProgressBar 组件中
|
||||
// const getDailyCostProgress = (key) => {
|
||||
// if (!key.dailyCostLimit || key.dailyCostLimit === 0) return 0
|
||||
@@ -3555,7 +3726,9 @@ const exportToExcel = () => {
|
||||
? '仅Gemini'
|
||||
: key.permissions === 'openai'
|
||||
? '仅OpenAI'
|
||||
: key.permissions || '',
|
||||
: key.permissions === 'droid'
|
||||
? '仅Droid'
|
||||
: key.permissions || '',
|
||||
|
||||
// 限制配置
|
||||
令牌限制: key.tokenLimit === '0' || key.tokenLimit === 0 ? '无限制' : key.tokenLimit || '',
|
||||
@@ -3587,6 +3760,7 @@ const exportToExcel = () => {
|
||||
OpenAI专属账户: key.openaiAccountId || '',
|
||||
'Azure OpenAI专属账户': key.azureOpenaiAccountId || '',
|
||||
Bedrock专属账户: key.bedrockAccountId || '',
|
||||
Droid专属账户: key.droidAccountId || '',
|
||||
|
||||
// 模型和客户端限制
|
||||
启用模型限制: key.enableModelRestriction ? '是' : '否',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user