mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
Merge branch 'main' into um-5
This commit is contained in:
@@ -3,8 +3,12 @@
|
||||
<div class="card p-4 sm:p-6">
|
||||
<div class="mb-4 flex flex-col gap-4 sm:mb-6">
|
||||
<div>
|
||||
<h3 class="mb-1 text-lg font-bold text-gray-900 sm:mb-2 sm:text-xl">账户管理</h3>
|
||||
<p class="text-sm text-gray-600 sm:text-base">管理您的 Claude 和 Gemini 账户及代理配置</p>
|
||||
<h3 class="mb-1 text-lg font-bold text-gray-900 dark:text-gray-100 sm:mb-2 sm:text-xl">
|
||||
账户管理
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 sm:text-base">
|
||||
管理您的 Claude、Gemini、OpenAI 和 Azure OpenAI 账户及代理配置
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<!-- 筛选器组 -->
|
||||
@@ -62,7 +66,7 @@
|
||||
placement="bottom"
|
||||
>
|
||||
<button
|
||||
class="group relative flex items-center justify-center gap-2 rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition-all duration-200 hover:border-gray-300 hover:shadow-md disabled:cursor-not-allowed disabled:opacity-50 sm:w-auto"
|
||||
class="group relative flex items-center justify-center gap-2 rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition-all duration-200 hover:border-gray-300 hover:shadow-md disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:border-gray-500 sm:w-auto"
|
||||
:disabled="accountsLoading"
|
||||
@click.ctrl.exact="loadAccounts(true)"
|
||||
@click.exact="loadAccounts(false)"
|
||||
@@ -96,26 +100,26 @@
|
||||
|
||||
<div v-if="accountsLoading" class="py-12 text-center">
|
||||
<div class="loading-spinner mx-auto mb-4" />
|
||||
<p class="text-gray-500">正在加载账户...</p>
|
||||
<p class="text-gray-500 dark:text-gray-400">正在加载账户...</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="sortedAccounts.length === 0" class="py-12 text-center">
|
||||
<div
|
||||
class="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-gray-100"
|
||||
class="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-gray-100 dark:bg-gray-700"
|
||||
>
|
||||
<i class="fas fa-user-circle text-xl text-gray-400" />
|
||||
</div>
|
||||
<p class="text-lg text-gray-500">暂无账户</p>
|
||||
<p class="mt-2 text-sm text-gray-400">点击上方按钮添加您的第一个账户</p>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400">暂无账户</p>
|
||||
<p class="mt-2 text-sm text-gray-400 dark:text-gray-500">点击上方按钮添加您的第一个账户</p>
|
||||
</div>
|
||||
|
||||
<!-- 桌面端表格视图 -->
|
||||
<div v-else class="table-container hidden md:block">
|
||||
<table class="w-full table-fixed">
|
||||
<thead class="bg-gray-50/80 backdrop-blur-sm">
|
||||
<thead class="bg-gray-50/80 backdrop-blur-sm dark:bg-gray-700/80">
|
||||
<tr>
|
||||
<th
|
||||
class="w-[22%] min-w-[180px] cursor-pointer px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 hover:bg-gray-100"
|
||||
class="w-[22%] min-w-[180px] cursor-pointer px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600"
|
||||
@click="sortAccounts('name')"
|
||||
>
|
||||
名称
|
||||
@@ -130,7 +134,7 @@
|
||||
<i v-else class="fas fa-sort ml-1 text-gray-400" />
|
||||
</th>
|
||||
<th
|
||||
class="w-[15%] min-w-[120px] cursor-pointer px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 hover:bg-gray-100"
|
||||
class="w-[15%] min-w-[120px] cursor-pointer px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600"
|
||||
@click="sortAccounts('platform')"
|
||||
>
|
||||
平台/类型
|
||||
@@ -145,7 +149,7 @@
|
||||
<i v-else class="fas fa-sort ml-1 text-gray-400" />
|
||||
</th>
|
||||
<th
|
||||
class="w-[12%] min-w-[100px] cursor-pointer px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 hover:bg-gray-100"
|
||||
class="w-[12%] min-w-[100px] cursor-pointer px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600"
|
||||
@click="sortAccounts('status')"
|
||||
>
|
||||
状态
|
||||
@@ -160,7 +164,7 @@
|
||||
<i v-else class="fas fa-sort ml-1 text-gray-400" />
|
||||
</th>
|
||||
<th
|
||||
class="w-[8%] min-w-[80px] cursor-pointer px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 hover:bg-gray-100"
|
||||
class="w-[8%] min-w-[80px] cursor-pointer px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600"
|
||||
@click="sortAccounts('priority')"
|
||||
>
|
||||
优先级
|
||||
@@ -175,33 +179,33 @@
|
||||
<i v-else class="fas fa-sort ml-1 text-gray-400" />
|
||||
</th>
|
||||
<th
|
||||
class="w-[10%] min-w-[100px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700"
|
||||
class="w-[10%] min-w-[100px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
代理
|
||||
</th>
|
||||
<th
|
||||
class="w-[10%] min-w-[90px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700"
|
||||
class="w-[10%] min-w-[90px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
今日使用
|
||||
</th>
|
||||
<th
|
||||
class="w-[10%] min-w-[100px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700"
|
||||
class="w-[10%] min-w-[100px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
会话窗口
|
||||
</th>
|
||||
<th
|
||||
class="w-[8%] min-w-[80px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700"
|
||||
class="w-[8%] min-w-[80px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
最后使用
|
||||
</th>
|
||||
<th
|
||||
class="w-[15%] min-w-[180px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700"
|
||||
class="w-[15%] min-w-[180px] px-3 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
操作
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200/50">
|
||||
<tbody class="divide-y divide-gray-200/50 dark:divide-gray-600/50">
|
||||
<tr v-for="account in sortedAccounts" :key="account.id" class="table-row">
|
||||
<td class="px-3 py-4">
|
||||
<div class="flex items-center">
|
||||
@@ -213,7 +217,7 @@
|
||||
<div class="min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="truncate text-sm font-semibold text-gray-900"
|
||||
class="truncate text-sm font-semibold text-gray-900 dark:text-gray-100"
|
||||
:title="account.name"
|
||||
>
|
||||
{{ account.name }}
|
||||
@@ -238,13 +242,16 @@
|
||||
</span>
|
||||
<span
|
||||
v-if="account.groupInfo"
|
||||
class="ml-1 inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600"
|
||||
class="ml-1 inline-flex items-center rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600 dark:bg-gray-700 dark:text-gray-400"
|
||||
:title="`所属分组: ${account.groupInfo.name}`"
|
||||
>
|
||||
<i class="fas fa-folder mr-1" />{{ account.groupInfo.name }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="truncate text-xs text-gray-500" :title="account.id">
|
||||
<div
|
||||
class="truncate text-xs text-gray-500 dark:text-gray-400"
|
||||
:title="account.id"
|
||||
>
|
||||
{{ account.id }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -291,6 +298,19 @@
|
||||
<span class="mx-1 h-4 w-px bg-gray-400" />
|
||||
<span class="text-xs font-medium text-gray-950">{{ getOpenAIAuthType() }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="account.platform === 'azure_openai'"
|
||||
class="flex items-center gap-1.5 rounded-lg border border-blue-200 bg-gradient-to-r from-blue-100 to-cyan-100 px-2.5 py-1 dark:border-blue-700 dark:from-blue-900/20 dark:to-cyan-900/20"
|
||||
>
|
||||
<i class="fab fa-microsoft text-xs text-blue-700 dark:text-blue-400" />
|
||||
<span class="text-xs font-semibold text-blue-800 dark:text-blue-300"
|
||||
>Azure OpenAI</span
|
||||
>
|
||||
<span class="mx-1 h-4 w-px bg-blue-300 dark:bg-blue-600" />
|
||||
<span class="text-xs font-medium text-blue-700 dark:text-blue-400"
|
||||
>API Key</span
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
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"
|
||||
@@ -376,12 +396,15 @@
|
||||
</span>
|
||||
<span
|
||||
v-if="account.status === 'blocked' && account.errorMessage"
|
||||
class="mt-1 max-w-xs truncate text-xs text-gray-500"
|
||||
class="mt-1 max-w-xs truncate text-xs text-gray-500 dark:text-gray-400"
|
||||
:title="account.errorMessage"
|
||||
>
|
||||
{{ account.errorMessage }}
|
||||
</span>
|
||||
<span v-if="account.accountType === 'dedicated'" class="text-xs text-gray-500">
|
||||
<span
|
||||
v-if="account.accountType === 'dedicated'"
|
||||
class="text-xs text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
绑定: {{ account.boundApiKeysCount || 0 }} 个API Key
|
||||
</span>
|
||||
</div>
|
||||
@@ -403,7 +426,7 @@
|
||||
:style="{ width: 101 - (account.priority || 50) + '%' }"
|
||||
/>
|
||||
</div>
|
||||
<span class="min-w-[20px] text-xs font-medium text-gray-700">
|
||||
<span class="min-w-[20px] text-xs font-medium text-gray-700 dark:text-gray-200">
|
||||
{{ account.priority || 50 }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -425,19 +448,19 @@
|
||||
<div v-if="account.usage && account.usage.daily" class="space-y-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="h-2 w-2 rounded-full bg-green-500" />
|
||||
<span class="text-sm font-medium text-gray-900"
|
||||
<span class="text-sm font-medium text-gray-900 dark:text-gray-100"
|
||||
>{{ account.usage.daily.requests || 0 }} 次</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="h-2 w-2 rounded-full bg-blue-500" />
|
||||
<span class="text-xs text-gray-600"
|
||||
<span class="text-xs text-gray-600 dark:text-gray-300"
|
||||
>{{ formatNumber(account.usage.daily.allTokens || 0) }} tokens</span
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
v-if="account.usage.averages && account.usage.averages.rpm > 0"
|
||||
class="text-xs text-gray-500"
|
||||
class="text-xs text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
平均 {{ account.usage.averages.rpm.toFixed(2) }} RPM
|
||||
</div>
|
||||
@@ -460,11 +483,11 @@
|
||||
:style="{ width: account.sessionWindow.progress + '%' }"
|
||||
/>
|
||||
</div>
|
||||
<span class="min-w-[32px] text-xs font-medium text-gray-700">
|
||||
<span class="min-w-[32px] text-xs font-medium text-gray-700 dark:text-gray-200">
|
||||
{{ account.sessionWindow.progress }}%
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-600">
|
||||
<div class="text-xs text-gray-600 dark:text-gray-300">
|
||||
<div>
|
||||
{{
|
||||
formatSessionWindow(
|
||||
@@ -488,7 +511,7 @@
|
||||
<span class="text-xs">N/A</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-600">
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-600 dark:text-gray-300">
|
||||
{{ formatLastUsed(account.lastUsedAt) }}
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm font-medium">
|
||||
@@ -571,7 +594,11 @@
|
||||
? 'bg-gradient-to-br from-purple-500 to-purple-600'
|
||||
: account.platform === 'bedrock'
|
||||
? 'bg-gradient-to-br from-orange-500 to-red-600'
|
||||
: 'bg-gradient-to-br from-blue-500 to-blue-600'
|
||||
: account.platform === 'azure_openai'
|
||||
? 'bg-gradient-to-br from-blue-500 to-cyan-600'
|
||||
: account.platform === 'openai'
|
||||
? 'bg-gradient-to-br from-gray-600 to-gray-700'
|
||||
: 'bg-gradient-to-br from-blue-500 to-blue-600'
|
||||
]"
|
||||
>
|
||||
<i
|
||||
@@ -581,7 +608,11 @@
|
||||
? 'fas fa-brain'
|
||||
: account.platform === 'bedrock'
|
||||
? 'fab fa-aws'
|
||||
: 'fas fa-robot'
|
||||
: account.platform === 'azure_openai'
|
||||
? 'fab fa-microsoft'
|
||||
: account.platform === 'openai'
|
||||
? 'fas fa-openai'
|
||||
: 'fas fa-robot'
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
@@ -590,9 +621,11 @@
|
||||
{{ account.name || account.email }}
|
||||
</h4>
|
||||
<div class="mt-0.5 flex items-center gap-2">
|
||||
<span class="text-xs text-gray-500">{{ account.platform }}</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{
|
||||
account.platform
|
||||
}}</span>
|
||||
<span class="text-xs text-gray-400">|</span>
|
||||
<span class="text-xs text-gray-500">{{ account.type }}</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{ account.type }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -612,20 +645,20 @@
|
||||
<!-- 使用统计 -->
|
||||
<div class="mb-3 grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<p class="text-xs text-gray-500">今日使用</p>
|
||||
<p class="text-sm font-semibold text-gray-900">
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">今日使用</p>
|
||||
<p class="text-sm font-semibold text-gray-900 dark:text-gray-100">
|
||||
{{ formatNumber(account.usage?.daily?.requests || 0) }} 次
|
||||
</p>
|
||||
<p class="mt-0.5 text-xs text-gray-500">
|
||||
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ formatNumber(account.usage?.daily?.allTokens || 0) }} tokens
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500">总使用量</p>
|
||||
<p class="text-sm font-semibold text-gray-900">
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">总使用量</p>
|
||||
<p class="text-sm font-semibold text-gray-900 dark:text-gray-100">
|
||||
{{ formatNumber(account.usage?.total?.requests || 0) }} 次
|
||||
</p>
|
||||
<p class="mt-0.5 text-xs text-gray-500">
|
||||
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ formatNumber(account.usage?.total?.allTokens || 0) }} tokens
|
||||
</p>
|
||||
</div>
|
||||
@@ -640,22 +673,22 @@
|
||||
account.sessionWindow &&
|
||||
account.sessionWindow.hasActiveWindow
|
||||
"
|
||||
class="space-y-1.5 rounded-lg bg-gray-50 p-2"
|
||||
class="space-y-1.5 rounded-lg bg-gray-50 p-2 dark:bg-gray-700"
|
||||
>
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="font-medium text-gray-600">会话窗口</span>
|
||||
<span class="font-medium text-gray-700">
|
||||
<span class="font-medium text-gray-600 dark:text-gray-300">会话窗口</span>
|
||||
<span class="font-medium text-gray-700 dark:text-gray-200">
|
||||
{{ account.sessionWindow.progress }}%
|
||||
</span>
|
||||
</div>
|
||||
<div class="h-2 w-full overflow-hidden rounded-full bg-gray-200">
|
||||
<div class="h-2 w-full overflow-hidden rounded-full bg-gray-200 dark:bg-gray-600">
|
||||
<div
|
||||
class="h-full bg-gradient-to-r from-blue-500 to-indigo-600 transition-all duration-300"
|
||||
:style="{ width: account.sessionWindow.progress + '%' }"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="text-gray-500">
|
||||
<span class="text-gray-500 dark:text-gray-400">
|
||||
{{
|
||||
formatSessionWindow(
|
||||
account.sessionWindow.windowStart,
|
||||
@@ -675,8 +708,8 @@
|
||||
|
||||
<!-- 最后使用时间 -->
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="text-gray-500">最后使用</span>
|
||||
<span class="text-gray-700">
|
||||
<span class="text-gray-500 dark:text-gray-400">最后使用</span>
|
||||
<span class="text-gray-700 dark:text-gray-200">
|
||||
{{ account.lastUsedAt ? formatRelativeTime(account.lastUsedAt) : '从未使用' }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -686,16 +719,16 @@
|
||||
v-if="account.proxyConfig && account.proxyConfig.type !== 'none'"
|
||||
class="flex items-center justify-between text-xs"
|
||||
>
|
||||
<span class="text-gray-500">代理</span>
|
||||
<span class="text-gray-700">
|
||||
<span class="text-gray-500 dark:text-gray-400">代理</span>
|
||||
<span class="text-gray-700 dark:text-gray-200">
|
||||
{{ account.proxyConfig.type.toUpperCase() }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 调度优先级 -->
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="text-gray-500">优先级</span>
|
||||
<span class="font-medium text-gray-700">
|
||||
<span class="text-gray-500 dark:text-gray-400">优先级</span>
|
||||
<span class="font-medium text-gray-700 dark:text-gray-200">
|
||||
{{ account.priority || 50 }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -808,6 +841,7 @@ const platformOptions = ref([
|
||||
{ value: 'claude-console', label: 'Claude Console', icon: 'fa-terminal' },
|
||||
{ value: 'gemini', label: 'Gemini', icon: 'fa-google' },
|
||||
{ value: 'openai', label: 'OpenAi', icon: 'fa-openai' },
|
||||
{ value: 'azure_openai', label: 'Azure OpenAI', icon: 'fab fa-microsoft' },
|
||||
{ value: 'bedrock', label: 'Bedrock', icon: 'fab fa-aws' }
|
||||
])
|
||||
|
||||
@@ -900,7 +934,8 @@ const loadAccounts = async (forceReload = false) => {
|
||||
apiClient.get('/admin/claude-console-accounts', { params }),
|
||||
apiClient.get('/admin/bedrock-accounts', { params }),
|
||||
apiClient.get('/admin/gemini-accounts', { params }),
|
||||
apiClient.get('/admin/openai-accounts', { params })
|
||||
apiClient.get('/admin/openai-accounts', { params }),
|
||||
apiClient.get('/admin/azure-openai-accounts', { params })
|
||||
)
|
||||
} else {
|
||||
// 只请求指定平台,其他平台设为null占位
|
||||
@@ -946,7 +981,7 @@ const loadAccounts = async (forceReload = false) => {
|
||||
// 加载分组成员关系(需要在分组数据加载完成后)
|
||||
await loadGroupMembers(forceReload)
|
||||
|
||||
const [claudeData, claudeConsoleData, bedrockData, geminiData, openaiData] =
|
||||
const [claudeData, claudeConsoleData, bedrockData, geminiData, openaiData, azureOpenaiData] =
|
||||
await Promise.all(requests)
|
||||
|
||||
const allAccounts = []
|
||||
@@ -1004,6 +1039,17 @@ const loadAccounts = async (forceReload = false) => {
|
||||
})
|
||||
allAccounts.push(...openaiAccounts)
|
||||
}
|
||||
if (azureOpenaiData && azureOpenaiData.success) {
|
||||
const azureOpenaiAccounts = (azureOpenaiData.data || []).map((acc) => {
|
||||
// 计算每个Azure OpenAI账户绑定的API Key数量
|
||||
const boundApiKeysCount = apiKeys.value.filter(
|
||||
(key) => key.azureOpenaiAccountId === acc.id
|
||||
).length
|
||||
const groupInfo = accountGroupMap.value.get(acc.id) || null
|
||||
return { ...acc, platform: 'azure_openai', boundApiKeysCount, groupInfo }
|
||||
})
|
||||
allAccounts.push(...azureOpenaiAccounts)
|
||||
}
|
||||
|
||||
accounts.value = allAccounts
|
||||
} catch (error) {
|
||||
@@ -1232,6 +1278,8 @@ const deleteAccount = async (account) => {
|
||||
endpoint = `/admin/bedrock-accounts/${account.id}`
|
||||
} else if (account.platform === 'openai') {
|
||||
endpoint = `/admin/openai-accounts/${account.id}`
|
||||
} else if (account.platform === 'azure_openai') {
|
||||
endpoint = `/admin/azure-openai-accounts/${account.id}`
|
||||
} else {
|
||||
endpoint = `/admin/gemini-accounts/${account.id}`
|
||||
}
|
||||
@@ -1304,6 +1352,8 @@ const toggleSchedulable = async (account) => {
|
||||
endpoint = `/admin/gemini-accounts/${account.id}/toggle-schedulable`
|
||||
} else if (account.platform === 'openai') {
|
||||
endpoint = `/admin/openai-accounts/${account.id}/toggle-schedulable`
|
||||
} else if (account.platform === 'azure_openai') {
|
||||
endpoint = `/admin/azure-openai-accounts/${account.id}/toggle-schedulable`
|
||||
} else {
|
||||
showToast('该账户类型暂不支持调度控制', 'warning')
|
||||
return
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="gradient-bg min-h-screen p-4 md:p-6">
|
||||
<div class="min-h-screen p-4 md:p-6" :class="isDarkMode ? 'gradient-bg-dark' : 'gradient-bg'">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="glass-strong mb-6 rounded-3xl p-4 shadow-xl md:mb-8 md:p-6">
|
||||
<div class="flex flex-col items-center justify-between gap-4 md:flex-row">
|
||||
@@ -9,7 +9,18 @@
|
||||
:subtitle="currentTab === 'stats' ? 'API Key 使用统计' : '使用教程'"
|
||||
:title="oemSettings.siteName"
|
||||
/>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-2 md:gap-4">
|
||||
<!-- 主题切换按钮 -->
|
||||
<div class="flex items-center">
|
||||
<ThemeToggle mode="dropdown" />
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div
|
||||
class="h-8 w-px bg-gradient-to-b from-transparent via-gray-300 to-transparent opacity-50 dark:via-gray-600"
|
||||
/>
|
||||
|
||||
<!-- 管理后台按钮 -->
|
||||
<router-link
|
||||
class="user-login-button flex items-center gap-2 rounded-xl px-3 py-2 text-white transition-all duration-300 md:px-4 md:py-2"
|
||||
to="/user-login"
|
||||
@@ -18,11 +29,11 @@
|
||||
<span class="text-xs font-medium md:text-sm">用户登录</span>
|
||||
</router-link>
|
||||
<router-link
|
||||
class="admin-button flex items-center gap-2 rounded-xl px-3 py-2 text-white transition-all duration-300 md:px-4 md:py-2"
|
||||
class="admin-button-refined flex items-center gap-2 rounded-2xl px-4 py-2 transition-all duration-300 md:px-5 md:py-2.5"
|
||||
to="/dashboard"
|
||||
>
|
||||
<i class="fas fa-cog text-sm" />
|
||||
<span class="text-xs font-medium md:text-sm">管理后台</span>
|
||||
<i class="fas fa-shield-alt text-sm md:text-base" />
|
||||
<span class="text-xs font-semibold tracking-wide md:text-sm">管理后台</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,7 +71,7 @@
|
||||
<!-- 错误提示 -->
|
||||
<div v-if="error" class="mb-6 md:mb-8">
|
||||
<div
|
||||
class="rounded-xl border border-red-500/30 bg-red-500/20 p-3 text-sm text-red-800 backdrop-blur-sm md:p-4 md:text-base"
|
||||
class="rounded-xl border border-red-500/30 bg-red-500/20 p-3 text-sm text-red-800 backdrop-blur-sm dark:border-red-500/20 dark:bg-red-500/10 dark:text-red-200 md:p-4 md:text-base"
|
||||
>
|
||||
<i class="fas fa-exclamation-triangle mr-2" />
|
||||
{{ error }}
|
||||
@@ -71,13 +82,15 @@
|
||||
<div v-if="statsData" class="fade-in">
|
||||
<div class="glass-strong rounded-3xl p-4 shadow-xl md:p-6">
|
||||
<!-- 时间范围选择器 -->
|
||||
<div class="mb-4 border-b border-gray-200 pb-4 md:mb-6 md:pb-6">
|
||||
<div class="mb-4 border-b border-gray-200 pb-4 dark:border-gray-700 md:mb-6 md:pb-6">
|
||||
<div
|
||||
class="flex flex-col items-start justify-between gap-3 md:flex-row md:items-center md:gap-4"
|
||||
>
|
||||
<div class="flex items-center gap-2 md:gap-3">
|
||||
<i class="fas fa-clock text-base text-blue-500 md:text-lg" />
|
||||
<span class="text-base font-medium text-gray-700 md:text-lg">统计时间范围</span>
|
||||
<span class="text-base font-medium text-gray-700 dark:text-gray-200 md:text-lg"
|
||||
>统计时间范围</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex w-full gap-2 md:w-auto">
|
||||
<button
|
||||
@@ -127,11 +140,13 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { ref, onMounted, onUnmounted, watch, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useApiStatsStore } from '@/stores/apistats'
|
||||
import { useThemeStore } from '@/stores/theme'
|
||||
import LogoTitle from '@/components/common/LogoTitle.vue'
|
||||
import ThemeToggle from '@/components/common/ThemeToggle.vue'
|
||||
import ApiKeyInput from '@/components/apistats/ApiKeyInput.vue'
|
||||
import StatsOverview from '@/components/apistats/StatsOverview.vue'
|
||||
import TokenDistribution from '@/components/apistats/TokenDistribution.vue'
|
||||
@@ -141,10 +156,14 @@ import TutorialView from './TutorialView.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const apiStatsStore = useApiStatsStore()
|
||||
const themeStore = useThemeStore()
|
||||
|
||||
// 当前标签页
|
||||
const currentTab = ref('stats')
|
||||
|
||||
// 主题相关
|
||||
const isDarkMode = computed(() => themeStore.isDarkMode)
|
||||
|
||||
const {
|
||||
apiKey,
|
||||
apiId,
|
||||
@@ -179,6 +198,9 @@ const handleKeyDown = (event) => {
|
||||
onMounted(() => {
|
||||
console.log('API Stats Page loaded')
|
||||
|
||||
// 初始化主题(因为该页面不在 MainLayout 内)
|
||||
themeStore.initTheme()
|
||||
|
||||
// 加载 OEM 设置
|
||||
loadOemSettings()
|
||||
|
||||
@@ -224,6 +246,14 @@ watch(apiKey, (newValue) => {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 暗色模式的渐变背景 */
|
||||
.gradient-bg-dark {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #334155 50%, #475569 100%);
|
||||
background-attachment: fixed;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gradient-bg::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
@@ -239,11 +269,27 @@ watch(apiKey, (newValue) => {
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* 玻璃态效果 */
|
||||
/* 暗色模式的背景覆盖 */
|
||||
.gradient-bg-dark::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background:
|
||||
radial-gradient(circle at 20% 80%, rgba(100, 116, 139, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 20%, rgba(71, 85, 105, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 40% 40%, rgba(30, 41, 59, 0.1) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* 玻璃态效果 - 使用CSS变量 */
|
||||
.glass-strong {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
background: var(--glass-strong-color);
|
||||
backdrop-filter: blur(25px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow:
|
||||
0 25px 50px -12px rgba(0, 0, 0, 0.25),
|
||||
0 0 0 1px rgba(255, 255, 255, 0.05),
|
||||
@@ -252,6 +298,14 @@ watch(apiKey, (newValue) => {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 暗色模式的玻璃态效果 */
|
||||
:global(.dark) .glass-strong {
|
||||
box-shadow:
|
||||
0 25px 50px -12px rgba(0, 0, 0, 0.7),
|
||||
0 0 0 1px rgba(55, 65, 81, 0.3),
|
||||
inset 0 1px 0 rgba(75, 85, 99, 0.2);
|
||||
}
|
||||
|
||||
/* 标题渐变 */
|
||||
.header-title {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
@@ -296,38 +350,76 @@ watch(apiKey, (newValue) => {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
/* 管理后台按钮 */
|
||||
.admin-button {
|
||||
/* 管理后台按钮 - 精致版本 */
|
||||
.admin-button-refined {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
box-shadow:
|
||||
0 4px 6px -1px rgba(102, 126, 234, 0.3),
|
||||
0 2px 4px -1px rgba(102, 126, 234, 0.1);
|
||||
0 4px 12px rgba(102, 126, 234, 0.25),
|
||||
inset 0 1px 1px rgba(255, 255, 255, 0.2);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.admin-button::before {
|
||||
/* 暗色模式下的管理后台按钮 */
|
||||
:global(.dark) .admin-button-refined {
|
||||
background: rgba(55, 65, 81, 0.8);
|
||||
border: 1px solid rgba(107, 114, 128, 0.4);
|
||||
color: #f3f4f6;
|
||||
box-shadow:
|
||||
0 4px 12px rgba(0, 0, 0, 0.3),
|
||||
inset 0 1px 1px rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.admin-button-refined::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: left 0.5s;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.admin-button:hover {
|
||||
transform: translateY(-2px);
|
||||
.admin-button-refined:hover {
|
||||
transform: translateY(-2px) scale(1.02);
|
||||
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
|
||||
box-shadow:
|
||||
0 10px 15px -3px rgba(102, 126, 234, 0.4),
|
||||
0 4px 6px -2px rgba(102, 126, 234, 0.15);
|
||||
0 8px 20px rgba(118, 75, 162, 0.35),
|
||||
inset 0 1px 1px rgba(255, 255, 255, 0.3);
|
||||
border-color: rgba(255, 255, 255, 0.4);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.admin-button:hover::before {
|
||||
left: 100%;
|
||||
.admin-button-refined:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 暗色模式下的悬停效果 */
|
||||
:global(.dark) .admin-button-refined:hover {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-color: rgba(147, 51, 234, 0.4);
|
||||
box-shadow:
|
||||
0 8px 20px rgba(102, 126, 234, 0.3),
|
||||
inset 0 1px 1px rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.admin-button-refined:active {
|
||||
transform: translateY(-1px) scale(1);
|
||||
}
|
||||
|
||||
/* 确保图标和文字在所有模式下都清晰可见 */
|
||||
.admin-button-refined i,
|
||||
.admin-button-refined span {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 时间范围按钮 */
|
||||
@@ -353,12 +445,26 @@ watch(apiKey, (newValue) => {
|
||||
|
||||
.period-btn:not(.active) {
|
||||
color: #374151;
|
||||
background: transparent;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border: 1px solid rgba(229, 231, 235, 0.5);
|
||||
}
|
||||
|
||||
:global(html.dark) .period-btn:not(.active) {
|
||||
color: #e5e7eb;
|
||||
background: rgba(55, 65, 81, 0.4);
|
||||
border: 1px solid rgba(75, 85, 99, 0.5);
|
||||
}
|
||||
|
||||
.period-btn:not(.active):hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
color: #1f2937;
|
||||
border-color: rgba(209, 213, 219, 0.8);
|
||||
}
|
||||
|
||||
:global(html.dark) .period-btn:not(.active):hover {
|
||||
background: rgba(75, 85, 99, 0.6);
|
||||
color: #ffffff;
|
||||
border-color: rgba(107, 114, 128, 0.8);
|
||||
}
|
||||
|
||||
/* Tab 胶囊按钮样式 */
|
||||
@@ -380,6 +486,11 @@ watch(apiKey, (newValue) => {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 暗夜模式下的Tab按钮基础样式 */
|
||||
:global(html.dark) .tab-pill-button {
|
||||
color: rgba(209, 213, 219, 0.8);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.tab-pill-button {
|
||||
padding: 0.625rem 1.25rem;
|
||||
@@ -392,6 +503,11 @@ watch(apiKey, (newValue) => {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
:global(html.dark) .tab-pill-button:hover {
|
||||
color: #f3f4f6;
|
||||
background: rgba(100, 116, 139, 0.2);
|
||||
}
|
||||
|
||||
.tab-pill-button.active {
|
||||
background: white;
|
||||
color: #764ba2;
|
||||
@@ -400,6 +516,14 @@ watch(apiKey, (newValue) => {
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
:global(html.dark) .tab-pill-button.active {
|
||||
background: rgba(71, 85, 105, 0.9);
|
||||
color: #f3f4f6;
|
||||
box-shadow:
|
||||
0 4px 6px -1px rgba(0, 0, 0, 0.3),
|
||||
0 2px 4px -1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.tab-pill-button i {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,15 @@
|
||||
<div class="stat-card">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 sm:text-sm">总API Keys</p>
|
||||
<p class="text-2xl font-bold text-gray-900 sm:text-3xl">
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
总API Keys
|
||||
</p>
|
||||
<p class="text-2xl font-bold text-gray-900 dark:text-gray-100 sm:text-3xl">
|
||||
{{ dashboardData.totalApiKeys }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-500">活跃: {{ dashboardData.activeApiKeys || 0 }}</p>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
活跃: {{ dashboardData.activeApiKeys || 0 }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="stat-icon flex-shrink-0 bg-gradient-to-br from-blue-500 to-blue-600">
|
||||
<i class="fas fa-key" />
|
||||
@@ -22,9 +26,11 @@
|
||||
<div class="stat-card">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex-1">
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 sm:text-sm">服务账户</p>
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
服务账户
|
||||
</p>
|
||||
<div class="flex flex-wrap items-baseline gap-x-2">
|
||||
<p class="text-2xl font-bold text-gray-900 sm:text-3xl">
|
||||
<p class="text-2xl font-bold text-gray-900 dark:text-gray-100 sm:text-3xl">
|
||||
{{ dashboardData.totalAccounts }}
|
||||
</p>
|
||||
<!-- 各平台账户数量展示 -->
|
||||
@@ -39,7 +45,7 @@
|
||||
:title="`Claude: ${dashboardData.accountsByPlatform.claude.total} 个 (正常: ${dashboardData.accountsByPlatform.claude.normal})`"
|
||||
>
|
||||
<i class="fas fa-brain text-xs text-indigo-600" />
|
||||
<span class="text-xs font-medium text-gray-700">{{
|
||||
<span class="text-xs font-medium text-gray-700 dark:text-gray-300">{{
|
||||
dashboardData.accountsByPlatform.claude.total
|
||||
}}</span>
|
||||
</div>
|
||||
@@ -53,7 +59,7 @@
|
||||
:title="`Console: ${dashboardData.accountsByPlatform['claude-console'].total} 个 (正常: ${dashboardData.accountsByPlatform['claude-console'].normal})`"
|
||||
>
|
||||
<i class="fas fa-terminal text-xs text-purple-600" />
|
||||
<span class="text-xs font-medium text-gray-700">{{
|
||||
<span class="text-xs font-medium text-gray-700 dark:text-gray-300">{{
|
||||
dashboardData.accountsByPlatform['claude-console'].total
|
||||
}}</span>
|
||||
</div>
|
||||
@@ -67,7 +73,7 @@
|
||||
:title="`Gemini: ${dashboardData.accountsByPlatform.gemini.total} 个 (正常: ${dashboardData.accountsByPlatform.gemini.normal})`"
|
||||
>
|
||||
<i class="fas fa-robot text-xs text-yellow-600" />
|
||||
<span class="text-xs font-medium text-gray-700">{{
|
||||
<span class="text-xs font-medium text-gray-700 dark:text-gray-300">{{
|
||||
dashboardData.accountsByPlatform.gemini.total
|
||||
}}</span>
|
||||
</div>
|
||||
@@ -81,7 +87,7 @@
|
||||
:title="`Bedrock: ${dashboardData.accountsByPlatform.bedrock.total} 个 (正常: ${dashboardData.accountsByPlatform.bedrock.normal})`"
|
||||
>
|
||||
<i class="fab fa-aws text-xs text-orange-600" />
|
||||
<span class="text-xs font-medium text-gray-700">{{
|
||||
<span class="text-xs font-medium text-gray-700 dark:text-gray-300">{{
|
||||
dashboardData.accountsByPlatform.bedrock.total
|
||||
}}</span>
|
||||
</div>
|
||||
@@ -95,18 +101,35 @@
|
||||
:title="`OpenAI: ${dashboardData.accountsByPlatform.openai.total} 个 (正常: ${dashboardData.accountsByPlatform.openai.normal})`"
|
||||
>
|
||||
<i class="fas fa-openai text-xs text-gray-100" />
|
||||
<span class="text-xs font-medium text-gray-700">{{
|
||||
<span class="text-xs font-medium text-gray-700 dark:text-gray-300">{{
|
||||
dashboardData.accountsByPlatform.openai.total
|
||||
}}</span>
|
||||
</div>
|
||||
<!-- Azure OpenAI账户 -->
|
||||
<div
|
||||
v-if="
|
||||
dashboardData.accountsByPlatform.azure_openai &&
|
||||
dashboardData.accountsByPlatform.azure_openai.total > 0
|
||||
"
|
||||
class="inline-flex items-center gap-0.5"
|
||||
:title="`Azure OpenAI: ${dashboardData.accountsByPlatform.azure_openai.total} 个 (正常: ${dashboardData.accountsByPlatform.azure_openai.normal})`"
|
||||
>
|
||||
<i class="fab fa-microsoft text-xs text-blue-600" />
|
||||
<span class="text-xs font-medium text-gray-700 dark:text-gray-300">{{
|
||||
dashboardData.accountsByPlatform.azure_openai.total
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-gray-500">
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
正常: {{ dashboardData.normalAccounts || 0 }}
|
||||
<span v-if="dashboardData.abnormalAccounts > 0" class="text-red-600">
|
||||
| 异常: {{ dashboardData.abnormalAccounts }}
|
||||
</span>
|
||||
<span v-if="dashboardData.pausedAccounts > 0" class="text-gray-600">
|
||||
<span
|
||||
v-if="dashboardData.pausedAccounts > 0"
|
||||
class="text-gray-600 dark:text-gray-400"
|
||||
>
|
||||
| 停止调度: {{ dashboardData.pausedAccounts }}
|
||||
</span>
|
||||
<span v-if="dashboardData.rateLimitedAccounts > 0" class="text-yellow-600">
|
||||
@@ -123,11 +146,13 @@
|
||||
<div class="stat-card">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 sm:text-sm">今日请求</p>
|
||||
<p class="text-2xl font-bold text-gray-900 sm:text-3xl">
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
今日请求
|
||||
</p>
|
||||
<p class="text-2xl font-bold text-gray-900 dark:text-gray-100 sm:text-3xl">
|
||||
{{ dashboardData.todayRequests }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-500">
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
总请求: {{ formatNumber(dashboardData.totalRequests || 0) }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -140,11 +165,15 @@
|
||||
<div class="stat-card">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 sm:text-sm">系统状态</p>
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
系统状态
|
||||
</p>
|
||||
<p class="text-2xl font-bold text-green-600 sm:text-3xl">
|
||||
{{ dashboardData.systemStatus }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-500">运行时间: {{ formattedUptime }}</p>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
运行时间: {{ formattedUptime }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="stat-icon flex-shrink-0 bg-gradient-to-br from-yellow-500 to-orange-500">
|
||||
<i class="fas fa-heartbeat" />
|
||||
@@ -160,7 +189,9 @@
|
||||
<div class="stat-card">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="mr-8 flex-1">
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 sm:text-sm">今日Token</p>
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
今日Token
|
||||
</p>
|
||||
<div class="mb-2 flex flex-wrap items-baseline gap-2">
|
||||
<p class="text-xl font-bold text-blue-600 sm:text-2xl md:text-3xl">
|
||||
{{
|
||||
@@ -176,7 +207,7 @@
|
||||
>/ {{ costsData.todayCosts.formatted.totalCost }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="text-xs text-gray-500">
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400">
|
||||
<div class="flex flex-wrap items-center justify-between gap-x-4">
|
||||
<span
|
||||
>输入:
|
||||
@@ -214,7 +245,9 @@
|
||||
<div class="stat-card">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="mr-8 flex-1">
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 sm:text-sm">总Token消耗</p>
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
总Token消耗
|
||||
</p>
|
||||
<div class="mb-2 flex flex-wrap items-baseline gap-2">
|
||||
<p class="text-xl font-bold text-emerald-600 sm:text-2xl md:text-3xl">
|
||||
{{
|
||||
@@ -230,7 +263,7 @@
|
||||
>/ {{ costsData.totalCosts.formatted.totalCost }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="text-xs text-gray-500">
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400">
|
||||
<div class="flex flex-wrap items-center justify-between gap-x-4">
|
||||
<span
|
||||
>输入:
|
||||
@@ -268,14 +301,14 @@
|
||||
<div class="stat-card">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 sm:text-sm">
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
实时RPM
|
||||
<span class="text-xs text-gray-400">({{ dashboardData.metricsWindow }}分钟)</span>
|
||||
</p>
|
||||
<p class="text-2xl font-bold text-orange-600 sm:text-3xl">
|
||||
{{ dashboardData.realtimeRPM || 0 }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-500">
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
每分钟请求数
|
||||
<span v-if="dashboardData.isHistoricalMetrics" class="text-yellow-600">
|
||||
<i class="fas fa-exclamation-circle" /> 历史数据
|
||||
@@ -291,14 +324,14 @@
|
||||
<div class="stat-card">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 sm:text-sm">
|
||||
<p class="mb-1 text-xs font-semibold text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
实时TPM
|
||||
<span class="text-xs text-gray-400">({{ dashboardData.metricsWindow }}分钟)</span>
|
||||
</p>
|
||||
<p class="text-2xl font-bold text-rose-600 sm:text-3xl">
|
||||
{{ formatNumber(dashboardData.realtimeTPM || 0) }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-500">
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
每分钟Token数
|
||||
<span v-if="dashboardData.isHistoricalMetrics" class="text-yellow-600">
|
||||
<i class="fas fa-exclamation-circle" /> 历史数据
|
||||
@@ -315,18 +348,22 @@
|
||||
<!-- 模型消费统计 -->
|
||||
<div class="mb-8">
|
||||
<div class="mb-4 flex flex-col gap-4 sm:mb-6">
|
||||
<h3 class="text-lg font-bold text-gray-900 sm:text-xl">模型使用分布与Token使用趋势</h3>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 sm:text-xl">
|
||||
模型使用分布与Token使用趋势
|
||||
</h3>
|
||||
<div class="flex flex-col gap-2 lg:flex-row lg:items-center lg:justify-end">
|
||||
<!-- 快捷日期选择 -->
|
||||
<div class="flex flex-shrink-0 gap-1 overflow-x-auto rounded-lg bg-gray-100 p-1">
|
||||
<div
|
||||
class="flex flex-shrink-0 gap-1 overflow-x-auto rounded-lg bg-gray-100 p-1 dark:bg-gray-700"
|
||||
>
|
||||
<button
|
||||
v-for="option in dateFilter.presetOptions"
|
||||
:key="option.value"
|
||||
:class="[
|
||||
'rounded-md px-3 py-1 text-sm font-medium transition-colors',
|
||||
dateFilter.preset === option.value && dateFilter.type === 'preset'
|
||||
? 'bg-white text-blue-600 shadow-sm'
|
||||
: 'text-gray-600 hover:text-gray-900'
|
||||
? 'bg-white text-blue-600 shadow-sm dark:bg-gray-800'
|
||||
: 'text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100'
|
||||
]"
|
||||
@click="setDateFilterPreset(option.value)"
|
||||
>
|
||||
@@ -335,13 +372,13 @@
|
||||
</div>
|
||||
|
||||
<!-- 粒度切换按钮 -->
|
||||
<div class="flex gap-1 rounded-lg bg-gray-100 p-1">
|
||||
<div class="flex gap-1 rounded-lg bg-gray-100 p-1 dark:bg-gray-700">
|
||||
<button
|
||||
:class="[
|
||||
'rounded-md px-3 py-1 text-sm font-medium transition-colors',
|
||||
trendGranularity === 'day'
|
||||
? 'bg-white text-blue-600 shadow-sm'
|
||||
: 'text-gray-600 hover:text-gray-900'
|
||||
? 'bg-white text-blue-600 shadow-sm dark:bg-gray-800'
|
||||
: 'text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100'
|
||||
]"
|
||||
@click="setTrendGranularity('day')"
|
||||
>
|
||||
@@ -351,8 +388,8 @@
|
||||
:class="[
|
||||
'rounded-md px-3 py-1 text-sm font-medium transition-colors',
|
||||
trendGranularity === 'hour'
|
||||
? 'bg-white text-blue-600 shadow-sm'
|
||||
: 'text-gray-600 hover:text-gray-900'
|
||||
? 'bg-white text-blue-600 shadow-sm dark:bg-gray-800'
|
||||
: 'text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100'
|
||||
]"
|
||||
@click="setTrendGranularity('hour')"
|
||||
>
|
||||
@@ -385,17 +422,17 @@
|
||||
<!-- 刷新控制 -->
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- 自动刷新控制 -->
|
||||
<div class="flex items-center rounded-lg bg-gray-100 px-3 py-1">
|
||||
<div class="flex items-center rounded-lg bg-gray-100 px-3 py-1 dark:bg-gray-700">
|
||||
<label class="relative inline-flex cursor-pointer items-center">
|
||||
<input v-model="autoRefreshEnabled" class="peer sr-only" type="checkbox" />
|
||||
<!-- 更小的开关 -->
|
||||
<div
|
||||
class="peer relative h-5 w-9 rounded-full bg-gray-300 transition-all duration-200 after:absolute after:left-[2px] after:top-0.5 after:h-4 after:w-4 after:rounded-full after:bg-white after:shadow-sm after:transition-transform after:duration-200 after:content-[''] peer-checked:bg-blue-500 peer-checked:after:translate-x-4 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue-300"
|
||||
class="peer relative h-5 w-9 rounded-full bg-gray-300 transition-all duration-200 after:absolute after:left-[2px] after:top-0.5 after:h-4 after:w-4 after:rounded-full after:bg-white after:shadow-sm after:transition-transform after:duration-200 after:content-[''] peer-checked:bg-blue-500 peer-checked:after:translate-x-4 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue-300 dark:bg-gray-600 dark:after:bg-gray-300 dark:peer-focus:ring-blue-600"
|
||||
/>
|
||||
<span
|
||||
class="ml-2.5 flex select-none items-center gap-1 text-sm font-medium text-gray-600"
|
||||
class="ml-2.5 flex select-none items-center gap-1 text-sm font-medium text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
<i class="fas fa-redo-alt text-xs text-gray-500" />
|
||||
<i class="fas fa-redo-alt text-xs text-gray-500 dark:text-gray-400" />
|
||||
<span>自动刷新</span>
|
||||
<span
|
||||
v-if="autoRefreshEnabled"
|
||||
@@ -410,7 +447,7 @@
|
||||
|
||||
<!-- 刷新按钮 -->
|
||||
<button
|
||||
class="flex items-center gap-1 rounded-md border border-gray-300 bg-white px-3 py-1 text-sm font-medium text-blue-600 shadow-sm transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 sm:gap-2"
|
||||
class="flex items-center gap-1 rounded-md border border-gray-300 bg-white px-3 py-1 text-sm font-medium text-blue-600 shadow-sm transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:hover:bg-gray-700 sm:gap-2"
|
||||
:disabled="isRefreshing"
|
||||
title="立即刷新数据"
|
||||
@click="refreshAllData()"
|
||||
@@ -425,7 +462,9 @@
|
||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
||||
<!-- 饼图 -->
|
||||
<div class="card p-4 sm:p-6">
|
||||
<h4 class="mb-4 text-base font-semibold text-gray-800 sm:text-lg">Token使用分布</h4>
|
||||
<h4 class="mb-4 text-base font-semibold text-gray-800 dark:text-gray-200 sm:text-lg">
|
||||
Token使用分布
|
||||
</h4>
|
||||
<div class="relative" style="height: 250px">
|
||||
<canvas ref="modelUsageChart" />
|
||||
</div>
|
||||
@@ -433,48 +472,62 @@
|
||||
|
||||
<!-- 详细数据表格 -->
|
||||
<div class="card p-4 sm:p-6">
|
||||
<h4 class="mb-4 text-base font-semibold text-gray-800 sm:text-lg">详细统计数据</h4>
|
||||
<h4 class="mb-4 text-base font-semibold text-gray-800 dark:text-gray-200 sm:text-lg">
|
||||
详细统计数据
|
||||
</h4>
|
||||
<div v-if="dashboardModelStats.length === 0" class="py-8 text-center">
|
||||
<p class="text-sm text-gray-500 sm:text-base">暂无模型使用数据</p>
|
||||
</div>
|
||||
<div v-else class="max-h-[250px] overflow-auto sm:max-h-[300px]">
|
||||
<table class="min-w-full">
|
||||
<thead class="sticky top-0 bg-gray-50">
|
||||
<thead class="sticky top-0 bg-gray-50 dark:bg-gray-700">
|
||||
<tr>
|
||||
<th class="px-2 py-2 text-left text-xs font-medium text-gray-700 sm:px-4">
|
||||
<th
|
||||
class="px-2 py-2 text-left text-xs font-medium text-gray-700 dark:text-gray-300 sm:px-4"
|
||||
>
|
||||
模型
|
||||
</th>
|
||||
<th
|
||||
class="hidden px-2 py-2 text-right text-xs font-medium text-gray-700 sm:table-cell sm:px-4"
|
||||
class="hidden px-2 py-2 text-right text-xs font-medium text-gray-700 dark:text-gray-300 sm:table-cell sm:px-4"
|
||||
>
|
||||
请求数
|
||||
</th>
|
||||
<th class="px-2 py-2 text-right text-xs font-medium text-gray-700 sm:px-4">
|
||||
<th
|
||||
class="px-2 py-2 text-right text-xs font-medium text-gray-700 dark:text-gray-300 sm:px-4"
|
||||
>
|
||||
总Token
|
||||
</th>
|
||||
<th class="px-2 py-2 text-right text-xs font-medium text-gray-700 sm:px-4">
|
||||
<th
|
||||
class="px-2 py-2 text-right text-xs font-medium text-gray-700 dark:text-gray-300 sm:px-4"
|
||||
>
|
||||
费用
|
||||
</th>
|
||||
<th
|
||||
class="hidden px-2 py-2 text-right text-xs font-medium text-gray-700 sm:table-cell sm:px-4"
|
||||
class="hidden px-2 py-2 text-right text-xs font-medium text-gray-700 dark:text-gray-300 sm:table-cell sm:px-4"
|
||||
>
|
||||
占比
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200">
|
||||
<tr v-for="stat in dashboardModelStats" :key="stat.model" class="hover:bg-gray-50">
|
||||
<td class="px-2 py-2 text-xs text-gray-900 sm:px-4 sm:text-sm">
|
||||
<tbody class="divide-y divide-gray-200 dark:divide-gray-600">
|
||||
<tr
|
||||
v-for="stat in dashboardModelStats"
|
||||
:key="stat.model"
|
||||
class="hover:bg-gray-50 dark:hover:bg-gray-700"
|
||||
>
|
||||
<td class="px-2 py-2 text-xs text-gray-900 dark:text-gray-100 sm:px-4 sm:text-sm">
|
||||
<span class="block max-w-[100px] truncate sm:max-w-none" :title="stat.model">
|
||||
{{ stat.model }}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="hidden px-2 py-2 text-right text-xs text-gray-600 sm:table-cell sm:px-4 sm:text-sm"
|
||||
class="hidden px-2 py-2 text-right text-xs text-gray-600 dark:text-gray-400 sm:table-cell sm:px-4 sm:text-sm"
|
||||
>
|
||||
{{ formatNumber(stat.requests) }}
|
||||
</td>
|
||||
<td class="px-2 py-2 text-right text-xs text-gray-600 sm:px-4 sm:text-sm">
|
||||
<td
|
||||
class="px-2 py-2 text-right text-xs text-gray-600 dark:text-gray-400 sm:px-4 sm:text-sm"
|
||||
>
|
||||
{{ formatNumber(stat.allTokens) }}
|
||||
</td>
|
||||
<td
|
||||
@@ -486,7 +539,7 @@
|
||||
class="hidden px-2 py-2 text-right text-xs font-medium sm:table-cell sm:px-4 sm:text-sm"
|
||||
>
|
||||
<span
|
||||
class="inline-flex items-center rounded-full bg-blue-100 px-2 py-1 text-xs font-medium text-blue-800"
|
||||
class="inline-flex items-center rounded-full bg-blue-100 px-2 py-1 text-xs font-medium text-blue-800 dark:bg-blue-900/30 dark:text-blue-300"
|
||||
>
|
||||
{{ calculatePercentage(stat.allTokens, dashboardModelStats) }}%
|
||||
</span>
|
||||
@@ -512,15 +565,17 @@
|
||||
<div class="mb-4 sm:mb-6 md:mb-8">
|
||||
<div class="card p-4 sm:p-6">
|
||||
<div class="mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<h3 class="text-base font-semibold text-gray-900 sm:text-lg">API Keys 使用趋势</h3>
|
||||
<h3 class="text-base font-semibold text-gray-900 dark:text-gray-100 sm:text-lg">
|
||||
API Keys 使用趋势
|
||||
</h3>
|
||||
<!-- 维度切换按钮 -->
|
||||
<div class="flex gap-1 rounded-lg bg-gray-100 p-1">
|
||||
<div class="flex gap-1 rounded-lg bg-gray-100 p-1 dark:bg-gray-700">
|
||||
<button
|
||||
:class="[
|
||||
'rounded-md px-2 py-1 text-xs font-medium transition-colors sm:px-3 sm:text-sm',
|
||||
apiKeysTrendMetric === 'requests'
|
||||
? 'bg-white text-blue-600 shadow-sm'
|
||||
: 'text-gray-600 hover:text-gray-900'
|
||||
? 'bg-white text-blue-600 shadow-sm dark:bg-gray-800'
|
||||
: 'text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100'
|
||||
]"
|
||||
@click="((apiKeysTrendMetric = 'requests'), updateApiKeysUsageTrendChart())"
|
||||
>
|
||||
@@ -531,8 +586,8 @@
|
||||
:class="[
|
||||
'rounded-md px-2 py-1 text-xs font-medium transition-colors sm:px-3 sm:text-sm',
|
||||
apiKeysTrendMetric === 'tokens'
|
||||
? 'bg-white text-blue-600 shadow-sm'
|
||||
: 'text-gray-600 hover:text-gray-900'
|
||||
? 'bg-white text-blue-600 shadow-sm dark:bg-gray-800'
|
||||
: 'text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100'
|
||||
]"
|
||||
@click="((apiKeysTrendMetric = 'tokens'), updateApiKeysUsageTrendChart())"
|
||||
>
|
||||
@@ -541,7 +596,7 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-4 text-xs text-gray-600 sm:text-sm">
|
||||
<div class="mb-4 text-xs text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
<span v-if="apiKeysTrendData.totalApiKeys > 10">
|
||||
共 {{ apiKeysTrendData.totalApiKeys }} 个 API Key,显示使用量前 10 个
|
||||
</span>
|
||||
@@ -556,12 +611,16 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
||||
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useDashboardStore } from '@/stores/dashboard'
|
||||
import { useThemeStore } from '@/stores/theme'
|
||||
import Chart from 'chart.js/auto'
|
||||
|
||||
const dashboardStore = useDashboardStore()
|
||||
const themeStore = useThemeStore()
|
||||
const { isDarkMode } = storeToRefs(themeStore)
|
||||
|
||||
const {
|
||||
dashboardData,
|
||||
costsData,
|
||||
@@ -607,6 +666,13 @@ const isRefreshing = ref(false)
|
||||
// return `${refreshCountdown.value}秒后刷新`
|
||||
// })
|
||||
|
||||
// 图表颜色配置(根据主题动态调整)
|
||||
const chartColors = computed(() => ({
|
||||
text: isDarkMode.value ? '#e5e7eb' : '#374151',
|
||||
grid: isDarkMode.value ? 'rgba(75, 85, 99, 0.3)' : 'rgba(0, 0, 0, 0.1)',
|
||||
legend: isDarkMode.value ? '#e5e7eb' : '#374151'
|
||||
}))
|
||||
|
||||
// 格式化数字
|
||||
function formatNumber(num) {
|
||||
if (num >= 1000000) {
|
||||
@@ -670,7 +736,8 @@ function createModelUsageChart() {
|
||||
usePointStyle: true,
|
||||
font: {
|
||||
size: 12
|
||||
}
|
||||
},
|
||||
color: chartColors.value.legend
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
@@ -800,10 +867,14 @@ function createUsageTrendChart() {
|
||||
font: {
|
||||
size: 16,
|
||||
weight: 'bold'
|
||||
}
|
||||
},
|
||||
color: chartColors.value.text
|
||||
},
|
||||
legend: {
|
||||
position: 'top'
|
||||
position: 'top',
|
||||
labels: {
|
||||
color: chartColors.value.legend
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
mode: 'index',
|
||||
@@ -858,7 +929,14 @@ function createUsageTrendChart() {
|
||||
display: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: trendGranularity.value === 'hour' ? '时间' : '日期'
|
||||
text: trendGranularity === 'hour' ? '时间' : '日期',
|
||||
color: chartColors.value.text
|
||||
},
|
||||
ticks: {
|
||||
color: chartColors.value.text
|
||||
},
|
||||
grid: {
|
||||
color: chartColors.value.grid
|
||||
}
|
||||
},
|
||||
y: {
|
||||
@@ -867,12 +945,17 @@ function createUsageTrendChart() {
|
||||
position: 'left',
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Token数量'
|
||||
text: 'Token数量',
|
||||
color: chartColors.value.text
|
||||
},
|
||||
ticks: {
|
||||
callback: function (value) {
|
||||
return formatNumber(value)
|
||||
}
|
||||
},
|
||||
color: chartColors.value.text
|
||||
},
|
||||
grid: {
|
||||
color: chartColors.value.grid
|
||||
}
|
||||
},
|
||||
y1: {
|
||||
@@ -881,7 +964,8 @@ function createUsageTrendChart() {
|
||||
position: 'right',
|
||||
title: {
|
||||
display: true,
|
||||
text: '请求数'
|
||||
text: '请求数',
|
||||
color: chartColors.value.text
|
||||
},
|
||||
grid: {
|
||||
drawOnChartArea: false
|
||||
@@ -889,7 +973,8 @@ function createUsageTrendChart() {
|
||||
ticks: {
|
||||
callback: function (value) {
|
||||
return value.toLocaleString()
|
||||
}
|
||||
},
|
||||
color: chartColors.value.text
|
||||
}
|
||||
},
|
||||
y2: {
|
||||
@@ -998,7 +1083,8 @@ function createApiKeysUsageTrendChart() {
|
||||
usePointStyle: true,
|
||||
font: {
|
||||
size: 12
|
||||
}
|
||||
},
|
||||
color: chartColors.value.legend
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
@@ -1062,19 +1148,31 @@ function createApiKeysUsageTrendChart() {
|
||||
display: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: trendGranularity.value === 'hour' ? '时间' : '日期'
|
||||
text: trendGranularity === 'hour' ? '时间' : '日期',
|
||||
color: chartColors.value.text
|
||||
},
|
||||
ticks: {
|
||||
color: chartColors.value.text
|
||||
},
|
||||
grid: {
|
||||
color: chartColors.value.grid
|
||||
}
|
||||
},
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: apiKeysTrendMetric.value === 'tokens' ? 'Token 数量' : '请求次数'
|
||||
text: apiKeysTrendMetric.value === 'tokens' ? 'Token 数量' : '请求次数',
|
||||
color: chartColors.value.text
|
||||
},
|
||||
ticks: {
|
||||
callback: function (value) {
|
||||
return formatNumber(value)
|
||||
}
|
||||
},
|
||||
color: chartColors.value.text
|
||||
},
|
||||
grid: {
|
||||
color: chartColors.value.grid
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1179,6 +1277,15 @@ watch(autoRefreshEnabled, (newVal) => {
|
||||
}
|
||||
})
|
||||
|
||||
// 监听主题变化,重新创建图表
|
||||
watch(isDarkMode, () => {
|
||||
nextTick(() => {
|
||||
createModelUsageChart()
|
||||
createUsageTrendChart()
|
||||
createApiKeysUsageTrendChart()
|
||||
})
|
||||
})
|
||||
|
||||
// 初始化
|
||||
onMounted(async () => {
|
||||
// 加载所有数据
|
||||
@@ -1208,19 +1315,8 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 自定义日期选择器样式 */
|
||||
.custom-date-picker :deep(.el-input__inner) {
|
||||
@apply border-gray-300 bg-white focus:border-blue-500 focus:ring-blue-500;
|
||||
font-size: 13px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.custom-date-picker :deep(.el-range-separator) {
|
||||
@apply text-gray-500;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.custom-date-picker :deep(.el-range-input) {
|
||||
/* 日期选择器基本样式调整 - 让Element Plus官方暗黑模式生效 */
|
||||
.custom-date-picker {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<div class="flex min-h-screen items-center justify-center p-4 sm:p-6">
|
||||
<!-- 主题切换按钮 - 固定在右上角 -->
|
||||
<div class="fixed right-4 top-4 z-50">
|
||||
<ThemeToggle mode="dropdown" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="glass-strong w-full max-w-md rounded-xl p-6 shadow-2xl sm:rounded-2xl sm:p-8 md:rounded-3xl md:p-10"
|
||||
>
|
||||
@@ -29,12 +34,14 @@
|
||||
v-else-if="oemLoading"
|
||||
class="mx-auto mb-2 h-8 w-48 animate-pulse rounded bg-gray-300/50 sm:h-9 sm:w-64"
|
||||
/>
|
||||
<p class="text-base text-gray-600 sm:text-lg">管理后台</p>
|
||||
<p class="text-base text-gray-600 dark:text-gray-400 sm:text-lg">管理后台</p>
|
||||
</div>
|
||||
|
||||
<form class="space-y-4 sm:space-y-6" @submit.prevent="handleLogin">
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-semibold text-gray-900 sm:mb-3">用户名</label>
|
||||
<label class="mb-2 block text-sm font-semibold text-gray-900 dark:text-gray-100 sm:mb-3"
|
||||
>用户名</label
|
||||
>
|
||||
<input
|
||||
v-model="loginForm.username"
|
||||
class="form-input w-full"
|
||||
@@ -45,7 +52,9 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-semibold text-gray-900 sm:mb-3">密码</label>
|
||||
<label class="mb-2 block text-sm font-semibold text-gray-900 dark:text-gray-100 sm:mb-3"
|
||||
>密码</label
|
||||
>
|
||||
<input
|
||||
v-model="loginForm.password"
|
||||
class="form-input w-full"
|
||||
@@ -68,7 +77,7 @@
|
||||
|
||||
<div
|
||||
v-if="authStore.loginError"
|
||||
class="mt-4 rounded-lg border border-red-500/30 bg-red-500/20 p-3 text-center text-xs text-red-800 backdrop-blur-sm sm:mt-6 sm:rounded-xl sm:p-4 sm:text-sm"
|
||||
class="mt-4 rounded-lg border border-red-500/30 bg-red-500/20 p-3 text-center text-xs text-red-800 backdrop-blur-sm dark:text-red-400 sm:mt-6 sm:rounded-xl sm:p-4 sm:text-sm"
|
||||
>
|
||||
<i class="fas fa-exclamation-triangle mr-2" />{{ authStore.loginError }}
|
||||
</div>
|
||||
@@ -79,8 +88,11 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useThemeStore } from '@/stores/theme'
|
||||
import ThemeToggle from '@/components/common/ThemeToggle.vue'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const themeStore = useThemeStore()
|
||||
const oemLoading = computed(() => authStore.oemLoading)
|
||||
|
||||
const loginForm = ref({
|
||||
@@ -89,6 +101,8 @@ const loginForm = ref({
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 初始化主题
|
||||
themeStore.initTheme()
|
||||
// 加载OEM设置
|
||||
authStore.loadOemSettings()
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +1,28 @@
|
||||
<template>
|
||||
<div class="card p-3 sm:p-6">
|
||||
<div class="mb-4 sm:mb-8">
|
||||
<h3 class="mb-3 flex items-center text-xl font-bold text-gray-900 sm:mb-4 sm:text-2xl">
|
||||
<h3
|
||||
class="mb-3 flex items-center text-xl font-bold text-gray-900 dark:text-gray-100 sm:mb-4 sm:text-2xl"
|
||||
>
|
||||
<i class="fas fa-graduation-cap mr-2 text-blue-600 sm:mr-3" />
|
||||
Claude Code 使用教程
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 sm:text-lg">
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 sm:text-lg">
|
||||
跟着这个教程,你可以轻松在自己的电脑上安装并使用 Claude Code。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 系统选择标签 -->
|
||||
<div class="mb-4 sm:mb-8">
|
||||
<div class="flex flex-wrap gap-1 rounded-xl bg-gray-100 p-1 sm:gap-2 sm:p-2">
|
||||
<div class="flex flex-wrap gap-1 rounded-xl bg-gray-100 p-1 dark:bg-gray-700 sm:gap-2 sm:p-2">
|
||||
<button
|
||||
v-for="system in tutorialSystems"
|
||||
:key="system.key"
|
||||
:class="[
|
||||
'flex flex-1 items-center justify-center gap-1 rounded-lg px-3 py-2 text-xs font-semibold transition-all duration-300 sm:gap-2 sm:px-6 sm:py-3 sm:text-sm',
|
||||
activeTutorialSystem === system.key
|
||||
? 'bg-white text-blue-600 shadow-sm'
|
||||
: 'text-gray-600 hover:bg-white/50 hover:text-gray-900'
|
||||
? 'bg-white text-blue-600 shadow-sm dark:bg-gray-800'
|
||||
: 'text-gray-600 hover:bg-white/50 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200'
|
||||
]"
|
||||
@click="activeTutorialSystem = system.key"
|
||||
>
|
||||
@@ -34,14 +36,16 @@
|
||||
<div v-if="activeTutorialSystem === 'windows'" class="tutorial-content">
|
||||
<!-- 第一步:安装 Node.js -->
|
||||
<div class="mb-4 sm:mb-10 sm:mb-6">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-blue-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>1</span
|
||||
>
|
||||
安装 Node.js 环境
|
||||
</h4>
|
||||
<p class="mb-4 text-sm text-gray-600 sm:mb-4 sm:mb-6 sm:text-base">
|
||||
<p class="mb-4 text-sm text-gray-600 dark:text-gray-400 sm:mb-4 sm:mb-6 sm:text-base">
|
||||
Claude Code 需要 Node.js 环境才能运行。
|
||||
</p>
|
||||
|
||||
@@ -49,34 +53,42 @@
|
||||
class="mb-4 rounded-xl border border-blue-100 bg-gradient-to-r from-blue-50 to-indigo-50 p-4 sm:mb-4 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fab fa-windows mr-2 text-blue-600" />
|
||||
Windows 安装方法
|
||||
</h5>
|
||||
<div class="mb-3 sm:mb-4">
|
||||
<p class="mb-2 text-sm text-gray-700 sm:mb-3 sm:text-base">方法一:官网下载(推荐)</p>
|
||||
<p class="mb-2 text-sm text-gray-700 dark:text-gray-600 sm:mb-3 sm:text-base">
|
||||
方法一:官网下载(推荐)
|
||||
</p>
|
||||
<ol
|
||||
class="ml-2 list-inside list-decimal space-y-1 text-xs text-gray-600 sm:ml-4 sm:space-y-2 sm:text-sm"
|
||||
class="ml-2 list-inside list-decimal space-y-1 text-xs text-gray-600 dark:text-gray-600 sm:ml-4 sm:space-y-2 sm:text-sm"
|
||||
>
|
||||
<li>
|
||||
打开浏览器访问
|
||||
<code class="rounded bg-gray-100 px-1 py-1 text-xs sm:px-2 sm:text-sm"
|
||||
<code
|
||||
class="rounded bg-gray-100 px-1 py-1 text-xs dark:bg-gray-700 sm:px-2 sm:text-sm"
|
||||
>https://nodejs.org/</code
|
||||
>
|
||||
</li>
|
||||
<li>点击 "LTS" 版本进行下载(推荐长期支持版本)</li>
|
||||
<li>
|
||||
下载完成后双击
|
||||
<code class="rounded bg-gray-100 px-1 py-1 text-xs sm:px-2 sm:text-sm">.msi</code>
|
||||
<code
|
||||
class="rounded bg-gray-100 px-1 py-1 text-xs dark:bg-gray-700 sm:px-2 sm:text-sm"
|
||||
>.msi</code
|
||||
>
|
||||
文件
|
||||
</li>
|
||||
<li>按照安装向导完成安装,保持默认设置即可</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="mb-3 sm:mb-4">
|
||||
<p class="mb-2 text-sm text-gray-700 sm:mb-3 sm:text-base">方法二:使用包管理器</p>
|
||||
<p class="mb-2 text-xs text-gray-600 sm:text-sm">
|
||||
<p class="mb-2 text-sm text-gray-700 dark:text-gray-600 sm:mb-3 sm:text-base">
|
||||
方法二:使用包管理器
|
||||
</p>
|
||||
<p class="mb-2 text-xs text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
如果你安装了 Chocolatey 或 Scoop,可以使用命令行安装:
|
||||
</p>
|
||||
<div
|
||||
@@ -116,7 +128,9 @@
|
||||
|
||||
<!-- 第二步:安装 Claude Code -->
|
||||
<div class="mb-4 sm:mb-10 sm:mb-6">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-green-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>2</span
|
||||
@@ -128,12 +142,12 @@
|
||||
class="mb-4 rounded-xl border border-green-100 bg-gradient-to-r from-green-50 to-emerald-50 p-4 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-download mr-2 text-green-600" />
|
||||
安装 Claude Code
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
打开 PowerShell 或 CMD,运行以下命令:
|
||||
</p>
|
||||
<div
|
||||
@@ -144,7 +158,7 @@
|
||||
npm install -g @anthropic-ai/claude-code
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600">
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
这个命令会从 npm 官方仓库下载并安装最新版本的 Claude Code。
|
||||
</p>
|
||||
|
||||
@@ -159,7 +173,7 @@
|
||||
|
||||
<!-- 验证安装 -->
|
||||
<div class="rounded-lg border border-green-200 bg-green-50 p-3 sm:p-4">
|
||||
<h6 class="mb-2 font-medium text-green-800">验证 Claude Code 安装</h6>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">验证 Claude Code 安装</h6>
|
||||
<p class="mb-3 text-sm text-green-700">安装完成后,输入以下命令检查是否安装成功:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -174,7 +188,9 @@
|
||||
|
||||
<!-- 第三步:设置环境变量 -->
|
||||
<div class="mb-6 sm:mb-10">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-purple-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>3</span
|
||||
@@ -186,18 +202,20 @@
|
||||
class="mb-4 rounded-xl border border-purple-100 bg-gradient-to-r from-purple-50 to-pink-50 p-4 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-cog mr-2 text-purple-600" />
|
||||
配置 Claude Code 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="rounded-lg border border-purple-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">
|
||||
<div
|
||||
class="rounded-lg border border-purple-200 bg-white p-3 dark:border-purple-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
方法一:PowerShell 临时设置(当前会话)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在 PowerShell 中运行以下命令:</p>
|
||||
@@ -216,8 +234,10 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-purple-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">
|
||||
<div
|
||||
class="rounded-lg border border-purple-200 bg-white p-3 dark:border-purple-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
方法二:PowerShell 永久设置(用户级)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">
|
||||
@@ -260,14 +280,14 @@
|
||||
|
||||
<!-- 验证环境变量设置 -->
|
||||
<div class="mt-6 rounded-lg border border-blue-200 bg-blue-50 p-3 sm:p-4">
|
||||
<h6 class="mb-2 font-medium text-blue-800">验证环境变量设置</h6>
|
||||
<h6 class="mb-2 font-medium text-blue-800 dark:text-blue-300">验证环境变量设置</h6>
|
||||
<p class="mb-3 text-sm text-blue-700">
|
||||
设置完环境变量后,可以通过以下命令验证是否设置成功:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
在 PowerShell 中验证:
|
||||
</h6>
|
||||
<div
|
||||
@@ -279,7 +299,9 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">在 CMD 中验证:</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
在 CMD 中验证:
|
||||
</h6>
|
||||
<div
|
||||
class="space-y-1 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
@@ -293,7 +315,7 @@
|
||||
<p class="text-sm text-blue-700">
|
||||
<strong>预期输出示例:</strong>
|
||||
</p>
|
||||
<div class="rounded bg-gray-100 p-2 font-mono text-sm">
|
||||
<div class="rounded bg-gray-100 p-2 font-mono text-sm dark:bg-gray-700">
|
||||
<div>{{ currentBaseUrl }}</div>
|
||||
<div>cr_xxxxxxxxxxxxxxxxxx</div>
|
||||
</div>
|
||||
@@ -306,18 +328,18 @@
|
||||
<!-- Gemini CLI 环境变量设置 -->
|
||||
<div class="mt-8">
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-robot mr-2 text-green-600" />
|
||||
配置 Gemini CLI 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
如果你使用 Gemini CLI,需要设置以下环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="rounded-lg border border-green-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
PowerShell 设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在 PowerShell 中运行以下命令:</p>
|
||||
@@ -340,7 +362,7 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-green-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
PowerShell 永久设置(用户级)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在 PowerShell 中运行以下命令:</p>
|
||||
@@ -368,7 +390,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-green-200 bg-green-50 p-3 sm:p-4">
|
||||
<h6 class="mb-2 font-medium text-green-800">验证 Gemini CLI 环境变量</h6>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">
|
||||
验证 Gemini CLI 环境变量
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-green-700">在 PowerShell 中验证:</p>
|
||||
<div
|
||||
class="space-y-1 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -386,18 +410,18 @@
|
||||
<!-- Codex 环境变量设置 -->
|
||||
<div class="mt-8">
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-code mr-2 text-indigo-600" />
|
||||
配置 Codex 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
如果你使用支持 OpenAI API 的工具(如 Codex),需要设置以下环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="rounded-lg border border-indigo-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
PowerShell 设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在 PowerShell 中运行以下命令:</p>
|
||||
@@ -417,7 +441,7 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-indigo-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
PowerShell 永久设置(用户级)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在 PowerShell 中运行以下命令:</p>
|
||||
@@ -456,7 +480,9 @@
|
||||
|
||||
<!-- 第四步:开始使用 -->
|
||||
<div class="mb-6 sm:mb-8">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-orange-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>4</span
|
||||
@@ -466,13 +492,15 @@
|
||||
<div
|
||||
class="rounded-xl border border-orange-100 bg-gradient-to-r from-orange-50 to-yellow-50 p-4 sm:p-6"
|
||||
>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
现在你可以开始使用 Claude Code 了!
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">启动 Claude Code</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
启动 Claude Code
|
||||
</h6>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
@@ -481,7 +509,9 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">在特定项目中使用</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
在特定项目中使用
|
||||
</h6>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
@@ -497,7 +527,9 @@
|
||||
|
||||
<!-- Windows 故障排除 -->
|
||||
<div class="mb-8">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<i class="fas fa-wrench mr-2 text-red-600 sm:mr-3" />
|
||||
Windows 常见问题解决
|
||||
</h4>
|
||||
@@ -567,7 +599,9 @@
|
||||
<div v-else-if="activeTutorialSystem === 'macos'" class="tutorial-content">
|
||||
<!-- 第一步:安装 Node.js -->
|
||||
<div class="mb-6 sm:mb-10">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-blue-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>1</span
|
||||
@@ -580,14 +614,14 @@
|
||||
class="mb-4 rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fab fa-apple mr-2 text-gray-700" />
|
||||
macOS 安装方法
|
||||
</h5>
|
||||
<div class="mb-4">
|
||||
<p class="mb-3 text-gray-700">方法一:使用 Homebrew(推荐)</p>
|
||||
<p class="mb-2 text-xs text-gray-600 sm:text-sm">
|
||||
<p class="mb-2 text-xs text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
如果你已经安装了 Homebrew,使用它安装 Node.js 会更方便:
|
||||
</p>
|
||||
<div
|
||||
@@ -602,18 +636,22 @@
|
||||
<div class="mb-4">
|
||||
<p class="mb-3 text-gray-700">方法二:官网下载</p>
|
||||
<ol
|
||||
class="ml-2 list-inside list-decimal space-y-1 text-xs text-gray-600 sm:ml-4 sm:space-y-2 sm:text-sm"
|
||||
class="ml-2 list-inside list-decimal space-y-1 text-xs text-gray-600 dark:text-gray-400 sm:ml-4 sm:space-y-2 sm:text-sm"
|
||||
>
|
||||
<li>
|
||||
访问
|
||||
<code class="rounded bg-gray-100 px-1 py-1 text-xs sm:px-2 sm:text-sm"
|
||||
<code
|
||||
class="rounded bg-gray-100 px-1 py-1 text-xs dark:bg-gray-700 sm:px-2 sm:text-sm"
|
||||
>https://nodejs.org/</code
|
||||
>
|
||||
</li>
|
||||
<li>下载适合 macOS 的 LTS 版本</li>
|
||||
<li>
|
||||
打开下载的
|
||||
<code class="rounded bg-gray-100 px-1 py-1 text-xs sm:px-2 sm:text-sm">.pkg</code>
|
||||
<code
|
||||
class="rounded bg-gray-100 px-1 py-1 text-xs dark:bg-gray-700 sm:px-2 sm:text-sm"
|
||||
>.pkg</code
|
||||
>
|
||||
文件
|
||||
</li>
|
||||
<li>按照安装程序指引完成安装</li>
|
||||
@@ -634,7 +672,7 @@
|
||||
|
||||
<!-- 验证安装 -->
|
||||
<div class="rounded-lg border border-green-200 bg-green-50 p-3 sm:p-4">
|
||||
<h6 class="mb-2 font-medium text-green-800">验证安装是否成功</h6>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">验证安装是否成功</h6>
|
||||
<p class="mb-3 text-sm text-green-700">安装完成后,打开 Terminal,输入以下命令:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -648,7 +686,9 @@
|
||||
|
||||
<!-- 第二步:安装 Claude Code -->
|
||||
<div class="mb-6 sm:mb-10">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-green-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>2</span
|
||||
@@ -660,12 +700,12 @@
|
||||
class="mb-4 rounded-xl border border-purple-100 bg-gradient-to-r from-purple-50 to-pink-50 p-4 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-download mr-2 text-purple-600" />
|
||||
安装 Claude Code
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
打开 Terminal,运行以下命令:
|
||||
</p>
|
||||
<div
|
||||
@@ -688,7 +728,7 @@
|
||||
|
||||
<!-- 验证安装 -->
|
||||
<div class="rounded-lg border border-green-200 bg-green-50 p-3 sm:p-4">
|
||||
<h6 class="mb-2 font-medium text-green-800">验证 Claude Code 安装</h6>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">验证 Claude Code 安装</h6>
|
||||
<p class="mb-3 text-sm text-green-700">安装完成后,输入以下命令检查是否安装成功:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -703,7 +743,9 @@
|
||||
|
||||
<!-- 第三步:设置环境变量 -->
|
||||
<div class="mb-6 sm:mb-10">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-orange-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>3</span
|
||||
@@ -715,18 +757,18 @@
|
||||
class="mb-4 rounded-xl border border-orange-100 bg-gradient-to-r from-orange-50 to-yellow-50 p-4 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-cog mr-2 text-orange-600" />
|
||||
配置 Claude Code 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="rounded-lg border border-orange-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
方法一:临时设置(当前会话)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在 Terminal 中运行以下命令:</p>
|
||||
@@ -746,7 +788,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-orange-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">方法二:永久设置</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
方法二:永久设置
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">
|
||||
编辑你的 shell 配置文件(根据你使用的 shell):
|
||||
</p>
|
||||
@@ -781,18 +825,20 @@
|
||||
<!-- Gemini CLI 环境变量设置 -->
|
||||
<div class="mt-8">
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-robot mr-2 text-green-600" />
|
||||
配置 Gemini CLI 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
如果你使用 Gemini CLI,需要设置以下环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="rounded-lg border border-green-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">Terminal 设置方法</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
Terminal 设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在 Terminal 中运行以下命令:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -813,7 +859,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-green-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">永久设置方法</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
永久设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">添加到你的 shell 配置文件:</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -848,7 +896,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-green-200 bg-green-50 p-3 sm:p-4">
|
||||
<h6 class="mb-2 font-medium text-green-800">验证 Gemini CLI 环境变量</h6>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">
|
||||
验证 Gemini CLI 环境变量
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-green-700">在 Terminal 中验证:</p>
|
||||
<div
|
||||
class="space-y-1 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -864,18 +914,20 @@
|
||||
<!-- Codex 环境变量设置 -->
|
||||
<div class="mt-8">
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-code mr-2 text-indigo-600" />
|
||||
配置 Codex 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
如果你使用支持 OpenAI API 的工具(如 Codex),需要设置以下环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="rounded-lg border border-indigo-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">Terminal 设置方法</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
Terminal 设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在 Terminal 中运行以下命令:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -893,7 +945,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-indigo-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">永久设置方法</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
永久设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">添加到你的 shell 配置文件:</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -937,7 +991,9 @@
|
||||
|
||||
<!-- 第四步:开始使用 -->
|
||||
<div class="mb-8">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-yellow-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>4</span
|
||||
@@ -947,13 +1003,15 @@
|
||||
<div
|
||||
class="rounded-xl border border-yellow-100 bg-gradient-to-r from-yellow-50 to-amber-50 p-4 sm:p-6"
|
||||
>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
现在你可以开始使用 Claude Code 了!
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">启动 Claude Code</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
启动 Claude Code
|
||||
</h6>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
@@ -962,7 +1020,9 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">在特定项目中使用</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
在特定项目中使用
|
||||
</h6>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
@@ -978,7 +1038,9 @@
|
||||
|
||||
<!-- macOS 故障排除 -->
|
||||
<div class="mb-8">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<i class="fas fa-wrench mr-2 text-red-600 sm:mr-3" />
|
||||
macOS 常见问题解决
|
||||
</h4>
|
||||
@@ -1054,7 +1116,9 @@
|
||||
<div v-else-if="activeTutorialSystem === 'linux'" class="tutorial-content">
|
||||
<!-- 第一步:安装 Node.js -->
|
||||
<div class="mb-6 sm:mb-10">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-blue-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>1</span
|
||||
@@ -1067,7 +1131,7 @@
|
||||
class="mb-4 rounded-xl border border-orange-100 bg-gradient-to-r from-orange-50 to-red-50 p-4 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fab fa-ubuntu mr-2 text-orange-600" />
|
||||
Linux 安装方法
|
||||
@@ -1087,7 +1151,7 @@
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<p class="mb-3 text-gray-700">方法二:使用系统包管理器</p>
|
||||
<p class="mb-2 text-xs text-gray-600 sm:text-sm">
|
||||
<p class="mb-2 text-xs text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
虽然版本可能不是最新的,但对于基本使用已经足够:
|
||||
</p>
|
||||
<div
|
||||
@@ -1112,7 +1176,7 @@
|
||||
|
||||
<!-- 验证安装 -->
|
||||
<div class="rounded-lg border border-green-200 bg-green-50 p-3 sm:p-4">
|
||||
<h6 class="mb-2 font-medium text-green-800">验证安装是否成功</h6>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">验证安装是否成功</h6>
|
||||
<p class="mb-3 text-sm text-green-700">安装完成后,打开终端,输入以下命令:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -1126,7 +1190,9 @@
|
||||
|
||||
<!-- 第二步:安装 Claude Code -->
|
||||
<div class="mb-6 sm:mb-10">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-green-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>2</span
|
||||
@@ -1138,12 +1204,14 @@
|
||||
class="mb-4 rounded-xl border border-purple-100 bg-gradient-to-r from-purple-50 to-pink-50 p-4 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-download mr-2 text-purple-600" />
|
||||
安装 Claude Code
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">打开终端,运行以下命令:</p>
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
打开终端,运行以下命令:
|
||||
</p>
|
||||
<div
|
||||
class="mb-4 overflow-x-auto rounded-lg bg-gray-900 p-3 font-mono text-xs text-green-400 sm:p-4 sm:text-sm"
|
||||
>
|
||||
@@ -1164,7 +1232,7 @@
|
||||
|
||||
<!-- 验证安装 -->
|
||||
<div class="rounded-lg border border-green-200 bg-green-50 p-3 sm:p-4">
|
||||
<h6 class="mb-2 font-medium text-green-800">验证 Claude Code 安装</h6>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">验证 Claude Code 安装</h6>
|
||||
<p class="mb-3 text-sm text-green-700">安装完成后,输入以下命令检查是否安装成功:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -1179,7 +1247,9 @@
|
||||
|
||||
<!-- 第三步:设置环境变量 -->
|
||||
<div class="mb-6 sm:mb-10">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-orange-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>3</span
|
||||
@@ -1191,18 +1261,18 @@
|
||||
class="mb-4 rounded-xl border border-orange-100 bg-gradient-to-r from-orange-50 to-yellow-50 p-4 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-cog mr-2 text-orange-600" />
|
||||
配置 Claude Code 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="rounded-lg border border-orange-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
方法一:临时设置(当前会话)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在终端中运行以下命令:</p>
|
||||
@@ -1222,7 +1292,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-orange-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">方法二:永久设置</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
方法二:永久设置
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">编辑你的 shell 配置文件:</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -1255,18 +1327,20 @@
|
||||
<!-- Gemini CLI 环境变量设置 -->
|
||||
<div class="mt-8">
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-robot mr-2 text-green-600" />
|
||||
配置 Gemini CLI 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
如果你使用 Gemini CLI,需要设置以下环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="rounded-lg border border-green-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">终端设置方法</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
终端设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在终端中运行以下命令:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -1287,7 +1361,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-green-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">永久设置方法</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
永久设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">添加到你的 shell 配置文件:</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -1322,7 +1398,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-green-200 bg-green-50 p-3 sm:p-4">
|
||||
<h6 class="mb-2 font-medium text-green-800">验证 Gemini CLI 环境变量</h6>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">
|
||||
验证 Gemini CLI 环境变量
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-green-700">在终端中验证:</p>
|
||||
<div
|
||||
class="space-y-1 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -1338,18 +1416,20 @@
|
||||
<!-- Codex 环境变量设置 -->
|
||||
<div class="mt-8">
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 sm:mb-3 sm:text-lg"
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-600 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-code mr-2 text-indigo-600" />
|
||||
配置 Codex 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
如果你使用支持 OpenAI API 的工具(如 Codex),需要设置以下环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="rounded-lg border border-indigo-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">终端设置方法</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
终端设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">在终端中运行以下命令:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -1367,7 +1447,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-indigo-200 bg-white p-3 sm:p-4">
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">永久设置方法</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
永久设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600">添加到你的 shell 配置文件:</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
@@ -1411,7 +1493,9 @@
|
||||
|
||||
<!-- 第四步:开始使用 -->
|
||||
<div class="mb-8">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-yellow-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>4</span
|
||||
@@ -1421,13 +1505,15 @@
|
||||
<div
|
||||
class="rounded-xl border border-yellow-100 bg-gradient-to-r from-yellow-50 to-amber-50 p-4 sm:p-6"
|
||||
>
|
||||
<p class="mb-3 text-sm text-gray-700 sm:mb-4 sm:text-base">
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
现在你可以开始使用 Claude Code 了!
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">启动 Claude Code</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
启动 Claude Code
|
||||
</h6>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
@@ -1436,7 +1522,9 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 sm:text-base">在特定项目中使用</h6>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-600 sm:text-base">
|
||||
在特定项目中使用
|
||||
</h6>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
@@ -1452,7 +1540,9 @@
|
||||
|
||||
<!-- Linux 故障排除 -->
|
||||
<div class="mb-8">
|
||||
<h4 class="mb-3 flex items-center text-lg font-semibold text-gray-800 sm:mb-4 sm:text-xl">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<i class="fas fa-wrench mr-2 text-red-600 sm:mr-3" />
|
||||
Linux 常见问题解决
|
||||
</h4>
|
||||
|
||||
Reference in New Issue
Block a user