style: 优化api-stats布局

This commit is contained in:
shaw
2025-09-28 14:54:24 +08:00
parent b123cc35c1
commit 5e015e87e0
4 changed files with 402 additions and 389 deletions

View File

@@ -558,7 +558,6 @@ class ClaudeAccountService {
return { return {
id: accountData.id, id: accountData.id,
name: accountData.name,
accountType: accountData.accountType || 'shared', accountType: accountData.accountType || 'shared',
platform: accountData.platform || 'claude', platform: accountData.platform || 'claude',
isActive: accountData.isActive === 'true', isActive: accountData.isActive === 'true',

View File

@@ -833,7 +833,6 @@ async function getAccountOverview(accountId) {
return { return {
id: accountData.id, id: accountData.id,
name: accountData.name,
accountType: accountData.accountType || 'shared', accountType: accountData.accountType || 'shared',
platform: accountData.platform || 'openai', platform: accountData.platform || 'openai',
isActive: accountData.isActive === 'true', isActive: accountData.isActive === 'true',

View File

@@ -1,5 +1,6 @@
<template> <template>
<div class="mb-6 grid grid-cols-1 gap-4 md:mb-8 md:gap-6 lg:grid-cols-2"> <div class="space-y-6 md:space-y-8">
<div class="grid grid-cols-1 gap-4 md:gap-6 lg:grid-cols-2 lg:items-start">
<!-- API Key 基本信息 / 批量查询概要 --> <!-- API Key 基本信息 / 批量查询概要 -->
<div class="card p-4 md:p-6"> <div class="card p-4 md:p-6">
<h3 <h3
@@ -8,7 +9,9 @@
<i <i
class="mr-2 text-sm md:mr-3 md:text-base" class="mr-2 text-sm md:mr-3 md:text-base"
:class=" :class="
multiKeyMode ? 'fas fa-layer-group text-purple-500' : 'fas fa-info-circle text-blue-500' multiKeyMode
? 'fas fa-layer-group text-purple-500'
: 'fas fa-info-circle text-blue-500'
" "
/> />
{{ multiKeyMode ? '批量查询概要' : 'API Key 信息' }} {{ multiKeyMode ? '批量查询概要' : 'API Key 信息' }}
@@ -157,12 +160,61 @@
永不过期 永不过期
</div> </div>
</div> </div>
</div>
</div>
<div <!-- 使用统计概览 -->
v-if="boundAccountList.length > 0" <div class="card p-4 md:p-6">
class="mt-4 rounded-2xl border border-indigo-100/60 bg-indigo-50/60 p-4 dark:border-indigo-500/40 dark:bg-indigo-500/10" <h3
class="mb-3 flex flex-col text-lg font-bold text-gray-900 dark:text-gray-100 sm:flex-row sm:items-center md:mb-4 md:text-xl"
> >
<div class="mb-4 flex items-center justify-between"> <span class="flex items-center">
<i class="fas fa-chart-bar mr-2 text-sm text-green-500 md:mr-3 md:text-base" />
使用统计概览
</span>
<span class="text-xs font-normal text-gray-600 dark:text-gray-400 sm:ml-2 md:text-sm"
>({{ statsPeriod === 'daily' ? '今日' : '本月' }})</span
>
</h3>
<div class="grid grid-cols-2 gap-3 md:gap-4">
<div class="stat-card text-center">
<div class="text-lg font-bold text-green-600 md:text-3xl">
{{ formatNumber(currentPeriodData.requests) }}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400 md:text-sm">
{{ statsPeriod === 'daily' ? '今日' : '本月' }}请求数
</div>
</div>
<div class="stat-card text-center">
<div class="text-lg font-bold text-blue-600 md:text-3xl">
{{ formatNumber(currentPeriodData.allTokens) }}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400 md:text-sm">
{{ statsPeriod === 'daily' ? '今日' : '本月' }}Token数
</div>
</div>
<div class="stat-card text-center">
<div class="text-lg font-bold text-purple-600 md:text-3xl">
{{ currentPeriodData.formattedCost || '$0.000000' }}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400 md:text-sm">
{{ statsPeriod === 'daily' ? '今日' : '本月' }}费用
</div>
</div>
<div class="stat-card text-center">
<div class="text-lg font-bold text-yellow-600 md:text-3xl">
{{ formatNumber(currentPeriodData.inputTokens) }}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400 md:text-sm">
{{ statsPeriod === 'daily' ? '今日' : '本月' }}输入Token
</div>
</div>
</div>
</div>
</div>
<div v-if="boundAccountList.length > 0" class="card p-4 md:p-6">
<div class="mb-4 flex flex-wrap items-center justify-between gap-3">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<i class="fas fa-link text-sm text-indigo-500 md:text-base" /> <i class="fas fa-link text-sm text-indigo-500 md:text-base" />
<span class="text-sm font-semibold text-indigo-900 dark:text-indigo-200 md:text-base" <span class="text-sm font-semibold text-indigo-900 dark:text-indigo-200 md:text-base"
@@ -170,16 +222,15 @@
> >
</div> </div>
<span <span
class="rounded-full bg-white/70 px-2 py-0.5 text-xs font-medium text-indigo-500 shadow-sm dark:bg-slate-900/40 dark:text-indigo-200" class="rounded-full bg-indigo-100 px-2 py-0.5 text-xs font-semibold text-indigo-600 dark:bg-indigo-500/20 dark:text-indigo-200"
>实时速览</span >实时速览</span
> >
</div> </div>
<div class="grid grid-cols-1 gap-3 md:gap-4 lg:grid-cols-2">
<div class="space-y-3 md:space-y-4">
<div <div
v-for="account in boundAccountList" v-for="account in boundAccountList"
:key="account.id" :key="account.id || account.key"
class="rounded-xl bg-white/80 p-3 shadow-sm backdrop-blur dark:bg-slate-900/50 md:p-4" class="rounded-xl border border-white/60 bg-white/85 p-4 shadow-sm backdrop-blur dark:border-slate-700/70 dark:bg-slate-900/60"
> >
<div class="flex flex-wrap items-center justify-between gap-3"> <div class="flex flex-wrap items-center justify-between gap-3">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
@@ -193,20 +244,20 @@
> >
<i :class="account.platform === 'claude' ? 'fas fa-meteor' : 'fas fa-robot'" /> <i :class="account.platform === 'claude' ? 'fas fa-meteor' : 'fas fa-robot'" />
</div> </div>
<div> <div class="space-y-1">
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100"> <div class="text-sm font-semibold text-gray-900 dark:text-gray-100">
{{ account.name || '未命名账号' }} {{ getAccountTitle(account) }}
</div> </div>
<div class="mt-1 flex items-center gap-2 text-[11px]"> <div class="flex items-center gap-2 text-[11px]">
<span <span
v-if="account.platform === 'claude'" v-if="account.platform === 'claude'"
class="inline-flex items-center rounded-full bg-purple-100 px-2 py-0.5 font-medium text-purple-700 dark:bg-purple-500/20 dark:text-purple-200" class="inline-flex items-center rounded-full bg-purple-100 px-2 py-0.5 font-medium text-purple-700 dark:bg-purple-500/20 dark:text-purple-200"
>Claude </span >Claude </span
> >
<span <span
v-else v-else
class="inline-flex items-center rounded-full bg-blue-100 px-2 py-0.5 font-medium text-blue-700 dark:bg-blue-500/20 dark:text-blue-200" class="inline-flex items-center rounded-full bg-blue-100 px-2 py-0.5 font-medium text-blue-700 dark:bg-blue-500/20 dark:text-blue-200"
>OpenAI </span >OpenAI </span
> >
</div> </div>
</div> </div>
@@ -221,10 +272,10 @@
</div> </div>
</div> </div>
<div v-if="account.platform === 'claude'" class="mt-3 space-y-3"> <div v-if="account.platform === 'claude'" class="mt-4 space-y-2">
<div v-if="account.sessionWindow?.hasActiveWindow" class="space-y-2"> <div v-if="account.sessionWindow?.hasActiveWindow" class="space-y-2">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="h-2 w-32 rounded-full bg-gray-200 dark:bg-gray-700"> <div class="h-2 flex-1 rounded-full bg-gray-200 dark:bg-gray-700">
<div <div
:class="[ :class="[
'h-2 rounded-full transition-all duration-300', 'h-2 rounded-full transition-all duration-300',
@@ -234,19 +285,13 @@
) )
]" ]"
:style="{ :style="{
width: `${Math.min( width: `${Math.min(100, Math.max(0, account.sessionWindow?.progress || 0))}%`
100,
Math.max(0, account.sessionWindow?.progress || 0)
)}%`
}" }"
/> />
</div> </div>
<span class="text-xs font-semibold text-gray-700 dark:text-gray-200"> <span class="text-xs font-semibold text-gray-700 dark:text-gray-200">
{{ {{
Math.min( Math.min(100, Math.max(0, Math.round(account.sessionWindow?.progress || 0)))
100,
Math.max(0, Math.round(account.sessionWindow?.progress || 0))
)
}}% }}%
</span> </span>
</div> </div>
@@ -271,13 +316,13 @@
</div> </div>
<div <div
v-else v-else
class="rounded-lg bg-white/60 px-3 py-2 text-xs text-gray-500 dark:bg-slate-800/60 dark:text-gray-400" class="rounded-lg bg-white/70 px-3 py-2 text-xs text-gray-500 dark:bg-slate-800/60 dark:text-gray-400"
> >
暂无活跃会话窗口 暂无活跃会话窗口
</div> </div>
</div> </div>
<div v-else-if="account.platform === 'openai'" class="mt-3 space-y-3"> <div v-else-if="account.platform === 'openai'" class="mt-4 space-y-3">
<div v-if="account.codexUsage" class="space-y-3"> <div v-if="account.codexUsage" class="space-y-3">
<div class="rounded-lg bg-gray-50 p-3 dark:bg-gray-700/70"> <div class="rounded-lg bg-gray-50 p-3 dark:bg-gray-700/70">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
@@ -343,7 +388,7 @@
</div> </div>
<div <div
v-else v-else
class="rounded-lg bg-white/60 px-3 py-2 text-xs text-gray-500 dark:bg-slate-800/60 dark:text-gray-400" class="rounded-lg bg-white/70 px-3 py-2 text-xs text-gray-500 dark:bg-slate-800/60 dark:text-gray-400"
> >
暂无额度使用数据 暂无额度使用数据
</div> </div>
@@ -352,57 +397,6 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- 使用统计概览 -->
<div class="card p-4 md:p-6">
<h3
class="mb-3 flex flex-col text-lg font-bold text-gray-900 dark:text-gray-100 sm:flex-row sm:items-center md:mb-4 md:text-xl"
>
<span class="flex items-center">
<i class="fas fa-chart-bar mr-2 text-sm text-green-500 md:mr-3 md:text-base" />
使用统计概览
</span>
<span class="text-xs font-normal text-gray-600 dark:text-gray-400 sm:ml-2 md:text-sm"
>({{ statsPeriod === 'daily' ? '今日' : '本月' }})</span
>
</h3>
<div class="grid grid-cols-2 gap-3 md:gap-4">
<div class="stat-card text-center">
<div class="text-lg font-bold text-green-600 md:text-3xl">
{{ formatNumber(currentPeriodData.requests) }}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400 md:text-sm">
{{ statsPeriod === 'daily' ? '今日' : '本月' }}请求数
</div>
</div>
<div class="stat-card text-center">
<div class="text-lg font-bold text-blue-600 md:text-3xl">
{{ formatNumber(currentPeriodData.allTokens) }}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400 md:text-sm">
{{ statsPeriod === 'daily' ? '今日' : '本月' }}Token数
</div>
</div>
<div class="stat-card text-center">
<div class="text-lg font-bold text-purple-600 md:text-3xl">
{{ currentPeriodData.formattedCost || '$0.000000' }}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400 md:text-sm">
{{ statsPeriod === 'daily' ? '今日' : '本月' }}费用
</div>
</div>
<div class="stat-card text-center">
<div class="text-lg font-bold text-yellow-600 md:text-3xl">
{{ formatNumber(currentPeriodData.inputTokens) }}
</div>
<div class="text-xs text-gray-600 dark:text-gray-400 md:text-sm">
{{ statsPeriod === 'daily' ? '今日' : '本月' }}输入Token
</div>
</div>
</div>
</div>
</div>
</template> </template>
<script setup> <script setup>
@@ -528,7 +522,20 @@ const boundAccountList = computed(() => {
return result return result
}) })
// 将分钟格式化为易读文本 // 专属账号标题
const getAccountTitle = (account) => {
if (!account) {
return '专属账号'
}
if (account.platform === 'openai') {
return 'OpenAI 专属账号'
}
return 'Claude 专属账号'
}
// 格式化限流时间
const formatRateLimitTime = (minutes) => { const formatRateLimitTime = (minutes) => {
if (!minutes || minutes <= 0) { if (!minutes || minutes <= 0) {
return '' return ''

View File

@@ -123,12 +123,20 @@
<StatsOverview /> <StatsOverview />
<!-- Token 分布和限制配置 --> <!-- Token 分布和限制配置 -->
<div class="mb-6 grid grid-cols-1 gap-4 md:mb-8 md:gap-6 lg:grid-cols-2"> <div
class="mb-6 grid grid-cols-1 gap-4 md:mb-8 md:gap-6 lg:auto-rows-max lg:grid-cols-2 lg:items-start"
>
<div class="lg:col-span-1">
<TokenDistribution /> <TokenDistribution />
<!-- 单key模式下显示限制配置 --> </div>
<LimitConfig v-if="!multiKeyMode" /> <!-- 单key模式下显示限制配置使用整行避免出现大片空白 -->
<!-- 多key模式下显示聚合统计卡片填充右侧空白 --> <div v-if="!multiKeyMode" class="lg:col-span-2">
<AggregatedStatsCard v-if="multiKeyMode" /> <LimitConfig />
</div>
<!-- 多key模式下显示聚合统计卡片 TokenDistribution 并排 -->
<div v-if="multiKeyMode" class="lg:col-span-1">
<AggregatedStatsCard />
</div>
</div> </div>
<!-- 模型使用统计 --> <!-- 模型使用统计 -->