mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
- 添加 OEM 设置管理功能,支持自定义网站名称和图标 - 支持图标文件上传和 Base64 编码存储 - 实现动态更新网站标题和 favicon - 统一 API 统计页面与管理页面的样式和布局 - 修复文本颜色显示问题,提升可读性 - 优化错误处理和默认值回退机制 - 移除测试文件和冗余代码 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
497 lines
30 KiB
HTML
497 lines
30 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>API Key 统计</title>
|
|
|
|
<!-- 🎨 样式 -->
|
|
<link rel="stylesheet" href="/apiStats/style.css">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
|
|
<style>
|
|
[v-cloak] {
|
|
display: none;
|
|
}
|
|
|
|
/* 调整间距使其与管理页面一致 */
|
|
.stat-card {
|
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0.8) 100%);
|
|
border-radius: 20px;
|
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
padding: 24px;
|
|
position: relative;
|
|
overflow: hidden;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.stat-card:hover {
|
|
transform: translateY(-4px);
|
|
box-shadow:
|
|
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
|
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
}
|
|
|
|
/* 与管理页面一致的按钮样式 */
|
|
.glass-button {
|
|
background: var(--glass-color, rgba(255, 255, 255, 0.1));
|
|
backdrop-filter: blur(20px);
|
|
border: 1px solid var(--border-color, rgba(255, 255, 255, 0.2));
|
|
}
|
|
|
|
/* 调整卡片样式 */
|
|
.card {
|
|
background: var(--surface-color, rgba(255, 255, 255, 0.95));
|
|
border-radius: 16px;
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
box-shadow:
|
|
0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
|
0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
</style>
|
|
|
|
<!-- 🔧 Vue 3 -->
|
|
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
|
|
|
<!-- 📊 Charts -->
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
|
|
<!-- 🧮 工具库 -->
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.9/dayjs.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.9/plugin/relativeTime.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.9/plugin/timezone.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.9/plugin/utc.min.js"></script>
|
|
</head>
|
|
<body class="min-h-screen">
|
|
<div id="app" v-cloak class="min-h-screen p-6">
|
|
<!-- 🎯 顶部导航 -->
|
|
<div class="glass-strong rounded-3xl p-6 mb-8 shadow-xl">
|
|
<div class="flex flex-col md:flex-row justify-between items-center gap-4">
|
|
<div class="flex items-center gap-4">
|
|
<div class="w-12 h-12 bg-gradient-to-br from-blue-500/20 to-purple-500/20 border border-gray-300/30 rounded-xl flex items-center justify-center backdrop-blur-sm flex-shrink-0 overflow-hidden">
|
|
<img v-if="oemSettings.siteIconData || oemSettings.siteIcon"
|
|
:src="oemSettings.siteIconData || oemSettings.siteIcon"
|
|
alt="Logo"
|
|
class="w-8 h-8 object-contain"
|
|
@error="(e) => e.target.style.display = 'none'">
|
|
<i v-else class="fas fa-cloud text-xl text-gray-700"></i>
|
|
</div>
|
|
<div class="flex flex-col justify-center min-h-[48px]">
|
|
<div class="flex items-center gap-3">
|
|
<h1 class="text-2xl font-bold text-white header-title leading-tight">{{ oemSettings.siteName || 'Claude Relay Service' }}</h1>
|
|
</div>
|
|
<p class="text-gray-600 text-sm leading-tight mt-0.5">API Key 使用统计</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-3">
|
|
<a href="/web" class="glass-button rounded-xl px-4 py-2 text-gray-700 hover:bg-white/20 transition-colors flex items-center gap-2">
|
|
<i class="fas fa-cog text-sm"></i>
|
|
<span class="text-sm font-medium">管理后台</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 🔑 API Key 输入区域 -->
|
|
<div class="api-input-wide-card glass-strong rounded-3xl p-6 mb-8 shadow-xl">
|
|
<!-- 📊 标题区域 -->
|
|
<div class="wide-card-title text-center mb-6">
|
|
<h2 class="text-2xl font-bold mb-2">
|
|
<i class="fas fa-chart-line mr-3"></i>
|
|
使用统计查询
|
|
</h2>
|
|
<p class="text-base text-gray-600">查询您的 API Key 使用情况和统计数据</p>
|
|
</div>
|
|
|
|
<!-- 🔍 输入区域 -->
|
|
<div class="max-w-4xl mx-auto">
|
|
<div class="api-input-grid grid grid-cols-1 lg:grid-cols-4">
|
|
<!-- API Key 输入 -->
|
|
<div class="lg:col-span-3">
|
|
<label class="block text-sm font-medium mb-2 text-gray-700">
|
|
<i class="fas fa-key mr-2"></i>
|
|
输入您的 API Key
|
|
</label>
|
|
<input
|
|
v-model="apiKey"
|
|
type="password"
|
|
placeholder="请输入您的 API Key (cr_...)"
|
|
class="wide-card-input w-full"
|
|
@keyup.enter="queryStats"
|
|
:disabled="loading"
|
|
>
|
|
</div>
|
|
|
|
<!-- 查询按钮 -->
|
|
<div class="lg:col-span-1">
|
|
<button
|
|
@click="queryStats"
|
|
:disabled="loading || !apiKey.trim()"
|
|
class="btn btn-primary w-full px-6 py-3 flex items-center justify-center gap-2"
|
|
>
|
|
<i v-if="loading" class="fas fa-spinner loading-spinner"></i>
|
|
<i v-else class="fas fa-search"></i>
|
|
{{ loading ? '查询中...' : '查询统计' }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 安全提示 -->
|
|
<div class="security-notice mt-4">
|
|
<i class="fas fa-shield-alt mr-2"></i>
|
|
您的 API Key 仅用于查询自己的统计数据,不会被存储或用于其他用途
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ❌ 错误提示 -->
|
|
<div v-if="error" class="mb-8">
|
|
<div class="bg-red-500/20 border border-red-500/30 rounded-xl p-4 text-red-800 backdrop-blur-sm">
|
|
<i class="fas fa-exclamation-triangle mr-2"></i>
|
|
{{ error }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 📊 统计数据展示区域 -->
|
|
<div v-if="statsData" class="fade-in">
|
|
<!-- 主要内容卡片 -->
|
|
<div class="glass-strong rounded-3xl p-6 shadow-xl">
|
|
<!-- 📅 时间范围选择器 -->
|
|
<div class="mb-6 pb-6 border-b border-gray-200">
|
|
<div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
|
|
<div class="flex items-center gap-3">
|
|
<i class="fas fa-clock text-blue-500 text-lg"></i>
|
|
<span class="text-lg font-medium text-gray-700">统计时间范围</span>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<button
|
|
@click="switchPeriod('daily')"
|
|
:class="['period-btn', { 'active': statsPeriod === 'daily' }]"
|
|
class="px-6 py-2 text-sm font-medium flex items-center gap-2"
|
|
:disabled="loading || modelStatsLoading"
|
|
>
|
|
<i class="fas fa-calendar-day"></i>
|
|
今日
|
|
</button>
|
|
<button
|
|
@click="switchPeriod('monthly')"
|
|
:class="['period-btn', { 'active': statsPeriod === 'monthly' }]"
|
|
class="px-6 py-2 text-sm font-medium flex items-center gap-2"
|
|
:disabled="loading || modelStatsLoading"
|
|
>
|
|
<i class="fas fa-calendar-alt"></i>
|
|
本月
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- 📈 基本信息卡片 -->
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
|
<!-- API Key 基本信息 -->
|
|
<div class="card p-6">
|
|
<h3 class="text-xl font-bold mb-4 flex items-center text-gray-900">
|
|
<i class="fas fa-info-circle mr-3 text-blue-500"></i>
|
|
API Key 信息
|
|
</h3>
|
|
<div class="space-y-3">
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">名称</span>
|
|
<span class="font-medium text-gray-900">{{ statsData.name }}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">状态</span>
|
|
<span :class="statsData.isActive ? 'text-green-600' : 'text-red-600'" class="font-medium">
|
|
<i :class="statsData.isActive ? 'fas fa-check-circle' : 'fas fa-times-circle'" class="mr-1"></i>
|
|
{{ statsData.isActive ? '活跃' : '已停用' }}
|
|
</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">权限</span>
|
|
<span class="font-medium text-gray-900">{{ formatPermissions(statsData.permissions) }}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">创建时间</span>
|
|
<span class="font-medium text-gray-900">{{ formatDate(statsData.createdAt) }}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">过期时间</span>
|
|
<div v-if="statsData.expiresAt">
|
|
<div v-if="isApiKeyExpired(statsData.expiresAt)" class="text-red-600 font-medium">
|
|
<i class="fas fa-exclamation-circle mr-1"></i>
|
|
已过期
|
|
</div>
|
|
<div v-else-if="isApiKeyExpiringSoon(statsData.expiresAt)" class="text-orange-600 font-medium">
|
|
<i class="fas fa-clock mr-1"></i>
|
|
{{ formatExpireDate(statsData.expiresAt) }}
|
|
</div>
|
|
<div v-else class="text-gray-900 font-medium">
|
|
{{ formatExpireDate(statsData.expiresAt) }}
|
|
</div>
|
|
</div>
|
|
<div v-else class="text-gray-400 font-medium">
|
|
<i class="fas fa-infinity mr-1"></i>
|
|
永不过期
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 使用统计概览 -->
|
|
<div class="card p-6">
|
|
<h3 class="text-xl font-bold mb-4 flex items-center text-gray-900">
|
|
<i class="fas fa-chart-bar mr-3 text-green-500"></i>
|
|
使用统计概览 <span class="text-sm font-normal text-gray-600 ml-2">({{ statsPeriod === 'daily' ? '今日' : '本月' }})</span>
|
|
</h3>
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div class="stat-card text-center">
|
|
<div class="text-3xl font-bold text-green-600">{{ formatNumber(currentPeriodData.requests) }}</div>
|
|
<div class="text-sm text-gray-600">{{ statsPeriod === 'daily' ? '今日' : '本月' }}请求数</div>
|
|
</div>
|
|
<div class="stat-card text-center">
|
|
<div class="text-3xl font-bold text-blue-600">{{ formatNumber(currentPeriodData.allTokens) }}</div>
|
|
<div class="text-sm text-gray-600">{{ statsPeriod === 'daily' ? '今日' : '本月' }}Token数</div>
|
|
</div>
|
|
<div class="stat-card text-center">
|
|
<div class="text-3xl font-bold text-purple-600">{{ currentPeriodData.formattedCost || '$0.000000' }}</div>
|
|
<div class="text-sm text-gray-600">{{ statsPeriod === 'daily' ? '今日' : '本月' }}费用</div>
|
|
</div>
|
|
<div class="stat-card text-center">
|
|
<div class="text-3xl font-bold text-yellow-600">{{ formatNumber(currentPeriodData.inputTokens) }}</div>
|
|
<div class="text-sm text-gray-600">{{ statsPeriod === 'daily' ? '今日' : '本月' }}输入Token</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 📋 详细使用数据 -->
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
|
<!-- Token 分类统计 -->
|
|
<div class="card p-6">
|
|
<h3 class="text-xl font-bold mb-4 flex items-center text-gray-900">
|
|
<i class="fas fa-coins mr-3 text-yellow-500"></i>
|
|
Token 使用分布 <span class="text-sm font-normal text-gray-600 ml-2">({{ statsPeriod === 'daily' ? '今日' : '本月' }})</span>
|
|
</h3>
|
|
<div class="space-y-3">
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600 flex items-center">
|
|
<i class="fas fa-arrow-right mr-2 text-green-500"></i>
|
|
输入 Token
|
|
</span>
|
|
<span class="font-medium text-gray-900">{{ formatNumber(currentPeriodData.inputTokens) }}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600 flex items-center">
|
|
<i class="fas fa-arrow-left mr-2 text-blue-500"></i>
|
|
输出 Token
|
|
</span>
|
|
<span class="font-medium text-gray-900">{{ formatNumber(currentPeriodData.outputTokens) }}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600 flex items-center">
|
|
<i class="fas fa-save mr-2 text-purple-500"></i>
|
|
缓存创建 Token
|
|
</span>
|
|
<span class="font-medium text-gray-900">{{ formatNumber(currentPeriodData.cacheCreateTokens) }}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600 flex items-center">
|
|
<i class="fas fa-download mr-2 text-orange-500"></i>
|
|
缓存读取 Token
|
|
</span>
|
|
<span class="font-medium text-gray-900">{{ formatNumber(currentPeriodData.cacheReadTokens) }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="mt-4 pt-4 border-t border-gray-200">
|
|
<div class="flex justify-between items-center font-bold text-gray-900">
|
|
<span>{{ statsPeriod === 'daily' ? '今日' : '本月' }}总计</span>
|
|
<span class="text-xl">{{ formatNumber(currentPeriodData.allTokens) }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 限制设置 -->
|
|
<div class="card p-6">
|
|
<h3 class="text-xl font-bold mb-4 flex items-center text-gray-900">
|
|
<i class="fas fa-shield-alt mr-3 text-red-500"></i>
|
|
限制配置
|
|
</h3>
|
|
<div class="space-y-3">
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">Token 限制</span>
|
|
<span class="font-medium text-gray-900">{{ statsData.limits.tokenLimit > 0 ? formatNumber(statsData.limits.tokenLimit) : '无限制' }}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">并发限制</span>
|
|
<span class="font-medium text-gray-900">{{ statsData.limits.concurrencyLimit > 0 ? statsData.limits.concurrencyLimit : '无限制' }}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">速率限制</span>
|
|
<span class="font-medium text-gray-900">
|
|
{{ statsData.limits.rateLimitRequests > 0 && statsData.limits.rateLimitWindow > 0
|
|
? `${statsData.limits.rateLimitRequests}次/${statsData.limits.rateLimitWindow}分钟`
|
|
: '无限制' }}
|
|
</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">每日费用限制</span>
|
|
<span class="font-medium text-gray-900">{{ statsData.limits.dailyCostLimit > 0 ? '$' + statsData.limits.dailyCostLimit : '无限制' }}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">模型限制</span>
|
|
<span class="font-medium text-gray-900">
|
|
<span v-if="statsData.restrictions.enableModelRestriction && statsData.restrictions.restrictedModels.length > 0"
|
|
class="text-orange-600">
|
|
<i class="fas fa-exclamation-triangle mr-1"></i>
|
|
限制 {{ statsData.restrictions.restrictedModels.length }} 个模型
|
|
</span>
|
|
<span v-else class="text-green-600">
|
|
<i class="fas fa-check-circle mr-1"></i>
|
|
允许所有模型
|
|
</span>
|
|
</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-gray-600">客户端限制</span>
|
|
<span class="font-medium text-gray-900">
|
|
<span v-if="statsData.restrictions.enableClientRestriction && statsData.restrictions.allowedClients.length > 0"
|
|
class="text-orange-600">
|
|
<i class="fas fa-exclamation-triangle mr-1"></i>
|
|
限制 {{ statsData.restrictions.allowedClients.length }} 个客户端
|
|
</span>
|
|
<span v-else class="text-green-600">
|
|
<i class="fas fa-check-circle mr-1"></i>
|
|
允许所有客户端
|
|
</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 📋 详细限制信息 -->
|
|
<div v-if="(statsData.restrictions.enableModelRestriction && statsData.restrictions.restrictedModels.length > 0) ||
|
|
(statsData.restrictions.enableClientRestriction && statsData.restrictions.allowedClients.length > 0)"
|
|
class="card p-6 mb-8">
|
|
<h3 class="text-xl font-bold mb-4 flex items-center text-gray-900">
|
|
<i class="fas fa-list-alt mr-3 text-amber-500"></i>
|
|
详细限制信息
|
|
</h3>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
<!-- 模型限制详情 -->
|
|
<div v-if="statsData.restrictions.enableModelRestriction && statsData.restrictions.restrictedModels.length > 0"
|
|
class="bg-amber-50 border border-amber-200 rounded-lg p-4">
|
|
<h4 class="font-bold text-amber-800 mb-3 flex items-center">
|
|
<i class="fas fa-robot mr-2"></i>
|
|
受限模型列表
|
|
</h4>
|
|
<div class="space-y-2">
|
|
<div v-for="model in statsData.restrictions.restrictedModels"
|
|
:key="model"
|
|
class="bg-white rounded px-3 py-2 text-sm border border-amber-200">
|
|
<i class="fas fa-ban mr-2 text-red-500"></i>
|
|
<span class="text-gray-800">{{ model }}</span>
|
|
</div>
|
|
</div>
|
|
<p class="text-xs text-amber-700 mt-3">
|
|
<i class="fas fa-info-circle mr-1"></i>
|
|
此 API Key 不能访问以上列出的模型
|
|
</p>
|
|
</div>
|
|
|
|
<!-- 客户端限制详情 -->
|
|
<div v-if="statsData.restrictions.enableClientRestriction && statsData.restrictions.allowedClients.length > 0"
|
|
class="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
|
<h4 class="font-bold text-blue-800 mb-3 flex items-center">
|
|
<i class="fas fa-desktop mr-2"></i>
|
|
允许的客户端
|
|
</h4>
|
|
<div class="space-y-2">
|
|
<div v-for="client in statsData.restrictions.allowedClients"
|
|
:key="client"
|
|
class="bg-white rounded px-3 py-2 text-sm border border-blue-200">
|
|
<i class="fas fa-check mr-2 text-green-500"></i>
|
|
<span class="text-gray-800">{{ client }}</span>
|
|
</div>
|
|
</div>
|
|
<p class="text-xs text-blue-700 mt-3">
|
|
<i class="fas fa-info-circle mr-1"></i>
|
|
此 API Key 只能被以上列出的客户端使用
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 📊 模型使用统计 -->
|
|
<div class="card p-6 mb-8">
|
|
<div class="mb-6">
|
|
<h3 class="text-xl font-bold flex items-center text-gray-900">
|
|
<i class="fas fa-robot mr-3 text-indigo-500"></i>
|
|
模型使用统计 <span class="text-sm font-normal text-gray-600 ml-2">({{ statsPeriod === 'daily' ? '今日' : '本月' }})</span>
|
|
</h3>
|
|
</div>
|
|
|
|
<!-- 模型统计加载状态 -->
|
|
<div v-if="modelStatsLoading" class="text-center py-8">
|
|
<i class="fas fa-spinner loading-spinner text-2xl mb-2 text-gray-600"></i>
|
|
<p class="text-gray-600">加载模型统计数据中...</p>
|
|
</div>
|
|
|
|
<!-- 模型统计数据 -->
|
|
<div v-else-if="modelStats.length > 0" class="space-y-4">
|
|
<div
|
|
v-for="(model, index) in modelStats"
|
|
:key="index"
|
|
class="model-usage-item"
|
|
>
|
|
<div class="flex justify-between items-start mb-3">
|
|
<div>
|
|
<h4 class="font-bold text-lg text-gray-900">{{ model.model }}</h4>
|
|
<p class="text-gray-600 text-sm">{{ model.requests }} 次请求</p>
|
|
</div>
|
|
<div class="text-right">
|
|
<div class="text-lg font-bold text-green-600">{{ model.formatted?.total || '$0.000000' }}</div>
|
|
<div class="text-sm text-gray-600">总费用</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-3 text-sm">
|
|
<div class="bg-gray-50 rounded p-2">
|
|
<div class="text-gray-600">输入 Token</div>
|
|
<div class="font-medium text-gray-900">{{ formatNumber(model.inputTokens) }}</div>
|
|
</div>
|
|
<div class="bg-gray-50 rounded p-2">
|
|
<div class="text-gray-600">输出 Token</div>
|
|
<div class="font-medium text-gray-900">{{ formatNumber(model.outputTokens) }}</div>
|
|
</div>
|
|
<div class="bg-gray-50 rounded p-2">
|
|
<div class="text-gray-600">缓存创建</div>
|
|
<div class="font-medium text-gray-900">{{ formatNumber(model.cacheCreateTokens) }}</div>
|
|
</div>
|
|
<div class="bg-gray-50 rounded p-2">
|
|
<div class="text-gray-600">缓存读取</div>
|
|
<div class="font-medium text-gray-900">{{ formatNumber(model.cacheReadTokens) }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 无模型数据 -->
|
|
<div v-else class="text-center py-8 text-gray-500">
|
|
<i class="fas fa-chart-pie text-3xl mb-3"></i>
|
|
<p>暂无{{ statsPeriod === 'daily' ? '今日' : '本月' }}模型使用数据</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 📱 JavaScript -->
|
|
<script src="/apiStats/app.js"></script>
|
|
</body>
|
|
</html> |