204 lines
11 KiB
HTML
204 lines
11 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}监控面板 - Gemini Balancer{% endblock %}
|
|
|
|
{% block head_extra %}
|
|
<link rel="stylesheet" href="/static/css/status-grid.css">
|
|
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
|
|
<!-- [核心] 页面顶栏:标题与全局控制器 -->
|
|
<div class="flex items-center justify-between mb-6">
|
|
<h2 class="text-3xl font-bold tracking-tight">数据总览</h2>
|
|
<div class="flex items-center space-x-3">
|
|
<!-- [最终形态] 完全自定义的下拉选择器组件 -->
|
|
<div class="relative w-full" data-custom-select-container>
|
|
|
|
<!-- 1. 隐藏的真实 <select>,用于表单提交 -->
|
|
<select name="group-filter" id="globalGroupFilter" class="hidden">
|
|
<option value="">所有分组</option>
|
|
<!-- JS将会动态填充更多选项 -->
|
|
</select>
|
|
|
|
<!-- 2. "诱饵" - 我们看到的、可以完全自定义的按钮 -->
|
|
<button type="button" class="custom-select-trigger h-9 w-full rounded-md border border-zinc-300 bg-zinc-50 py-1 pl-4 pr-8 text-left text-sm shadow-sm transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-inset dark:border-zinc-700 dark:bg-zinc-900">
|
|
<span class="block truncate">所有分组</span>
|
|
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
|
<svg class="h-4 w-4 text-zinc-700 dark:text-zinc-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
|
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m6 8 4 4 4-4"/>
|
|
</svg>
|
|
</span>
|
|
</button>
|
|
|
|
<!-- 3. "真正的菜单" - 可以被我们完全样式化的下拉面板 -->
|
|
<div class="custom-select-panel absolute z-10 mt-1 w-full rounded-lg bg-zinc-50 dark:bg-zinc-900 shadow-xl p-1 hidden">
|
|
<!-- 选项将会由 JS 动态生成并插入此处 -->
|
|
<!-- 示例选项 -->
|
|
<div class="custom-select-option" data-value="">所有分组</div>
|
|
<div class="custom-select-option" data-value="group1">分组一</div>
|
|
<div class="custom-select-option" data-value="group2">分组二</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- [核心] 快速处置按钮 (触发模态框) -->
|
|
<button id="quick-action-btn" class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors h-9 px-4 py-2 bg-blue-500 text-white shadow hover:bg-blue-500/90">
|
|
<i class="fas fa-bolt"></i>
|
|
<span class="hidden lg:inline">快速处置</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- [组件蓝图] 任何页面都可以复制此结构来创建一个新的滑动标签实例 -->
|
|
<div class="py-2">
|
|
<div class="w-full overflow-x-auto scrollbar-hide">
|
|
<!-- 1. 容器: 必须有 `data-sliding-tabs-container` 属性 -->
|
|
<div role="tablist" class="relative inline-flex h-10 items-center justify-center inset-shadow-sm/25 rounded-lg bg-zinc-800/50 dark:bg-zinc-950 p-1" data-sliding-tabs-container>
|
|
|
|
<!-- 2. 指示器: 必须有 `data-tab-indicator` 属性 -->
|
|
<div class="absolute left-0 h-[calc(100%-0.5rem)] rounded-md bg-white dark:bg-zinc-700 shadow-sm" data-tab-indicator style="transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);"></div>
|
|
<!-- 3. 标签项: 必须有 `data-tab-item` 属性。激活项应有 `tab-active` class -->
|
|
<a href="#" role="tab" class="tab-item tab-active" data-tab-item>数据总览</a>
|
|
<a href="#" role="tab" class="tab-item" data-tab-item>密钥管理</a>
|
|
<a href="#" role="tab" class="tab-item" data-tab-item>性能分析</a>
|
|
<a href="#" role="tab" class="tab-item" data-tab-item>请求日志</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- [核心] 标签页内容区域 -->
|
|
<div class="mt-8">
|
|
<!-- 标签A: 数据总览 (默认显示) -->
|
|
<div id="tab-content-overview" class="space-y-6">
|
|
|
|
<!-- 第一行: 四核心指标卡片 -->
|
|
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
|
|
<!-- 卡片1: 密钥统计 -->
|
|
<div class="ds-stats-card bg-card text-card-foreground">
|
|
<div class="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<div class="text-sm font-medium">密钥统计</div>
|
|
<i class="h-4 w-4 text-zinc-500 fas fa-key"></i>
|
|
</div>
|
|
<div>
|
|
<div class="text-2xl font-bold">
|
|
<span id="stat-valid-keys">0</span> / <span id="stat-total-keys">0</span>
|
|
</div>
|
|
<p class="text-xs text-zinc-500 dark:text-zinc-400">有效密钥 / 总密钥数</p>
|
|
</div>
|
|
</div>
|
|
<!-- 卡片2: 请求总览 -->
|
|
<div class="ds-stats-card bg-card text-card-foreground">
|
|
<div class="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<div class="text-sm font-medium">请求总览</div>
|
|
<i class="h-4 w-4 text-zinc-500 fas fa-exchange-alt"></i>
|
|
</div>
|
|
<div>
|
|
<!-- [ID保留] 沿用旧ID: stat-calls-24h -->
|
|
<div class="text-2xl font-bold" id="stat-calls-24h">0</div>
|
|
<p class="text-xs text-zinc-500 dark:text-zinc-400">24小时请求数</p>
|
|
</div>
|
|
</div>
|
|
<!-- 卡片3: Token消耗 -->
|
|
<div class="ds-stats-card bg-card text-card-foreground">
|
|
<div class="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<div class="text-sm font-medium">Token 消耗</div>
|
|
<i class="h-4 w-4 text-zinc-500 fas fa-coins"></i>
|
|
</div>
|
|
<div>
|
|
<!-- [ID新增] 新增ID: stat-tokens-24h -->
|
|
<div class="text-2xl font-bold" id="stat-tokens-24h">0</div>
|
|
<p class="text-xs text-zinc-500 dark:text-zinc-400">24小时消耗</p>
|
|
</div>
|
|
</div>
|
|
<!-- 卡片4: 请求成功率 -->
|
|
<div class="ds-stats-card bg-card text-card-foreground">
|
|
<div class="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<div class="text-sm font-medium">请求成功率</div>
|
|
<i class="h-4 w-4 text-zinc-500 fas fa-check-circle"></i>
|
|
</div>
|
|
<div>
|
|
<!-- [ID新增] 新增ID: stat-success-rate-24h -->
|
|
<div class="text-2xl font-bold" id="stat-success-rate-24h">0%</div>
|
|
<p class="text-xs text-zinc-500 dark:text-zinc-400">24小时成功率</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 第二行: API 状态分布 (通栏) -->
|
|
<div class="ds-stats-card bg-card text-card-foreground">
|
|
<h3 class="font-semibold leading-none tracking-tight mb-4">API 状态分布</h3>
|
|
<!-- [容器保留] 沿用旧ID, JS可无缝对接 -->
|
|
<div id="poolGridContainer" class="relative p-2 canvas-placeholder" style="height: 60px;">
|
|
<canvas id="poolGridCanvas" class="absolute top-0 left-0 w-full h-full"></canvas>
|
|
</div>
|
|
<!-- [图例保留] 沿用旧ID -->
|
|
<div id="poolStatusLegend" class="flex flex-wrap justify-center gap-x-4 gap-y-2 text-xs mt-4">
|
|
<span class="legend-item" data-status-hover="ACTIVE"><i class="fas fa-square text-green-500"></i> ACTIVE (<span id="legend-active">0</span>)</span>
|
|
<span class="legend-item" data-status-hover="PENDING"><i class="fas fa-square text-gray-400"></i> PENDING (<span id="legend-pending">0</span>)</span>
|
|
<span class="legend-item" data-status-hover="COOLDOWN"><i class="fas fa-square text-yellow-500"></i> COOLDOWN (<span id="legend-cooldown">0</span>)</span>
|
|
<span class="legend-item" data-status-hover="DISABLED"><i class="fas fa-square text-orange-500"></i> DISABLED (<span id="legend-disabled">0</span>)</span>
|
|
<span class="legend-item" data-status-hover="BANNED"><i class="fas fa-square text-red-500"></i> BANNED (<span id="legend-banned">0</span>)</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 第三行: 左侧图表 + 右侧排行 -->
|
|
<div class="grid gap-6 lg:grid-cols-5">
|
|
<!-- 左侧大卡片: 请求趋势图 (占位) -->
|
|
<div class="ds-stats-card bg-card text-card-foreground lg:col-span-3">
|
|
<h3 class="font-semibold leading-none tracking-tight">请求趋势</h3>
|
|
<p class="text-sm text-zinc-500 dark:text-zinc-400 mb-4">成功与失败请求数</p>
|
|
<!-- [容器新增] 新增一个清晰的ID给新图表 -->
|
|
<div class="h-[350px] flex items-center justify-center text-zinc-400">
|
|
<canvas id="successFailChart"></canvas>
|
|
<span>图表加载中...</span>
|
|
</div>
|
|
</div>
|
|
<!-- 右侧小卡片: 模型排行 (占位) -->
|
|
<div class="ds-stats-card bg-card text-card-foreground lg:col-span-2">
|
|
<h3 class="font-semibold leading-none tracking-tight">模型排行</h3>
|
|
<p class="text-sm text-zinc-500 dark:text-zinc-400 mb-4">24小时内调用次数</p>
|
|
<!-- [容器新增] 新增一个列表容器ID -->
|
|
<div id="model-ranking-list" class="space-y-4 h-[350px] overflow-y-auto pr-2">
|
|
<!-- JS将在此处动态填充排行列表 -->
|
|
<div class="flex items-center text-sm text-zinc-500">排行数据加载中...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- 其他标签页的内容区域 (暂时留空) -->
|
|
<div id="tab-content-keys" class="hidden">密钥管理内容</div>
|
|
<div id="tab-content-performance" class="hidden">性能分析内容</div>
|
|
<div id="tab-content-requests" class="hidden">请求日志内容</div>
|
|
|
|
</div>
|
|
|
|
<!-- [占位符] 快速处置模态框 -->
|
|
<div id="quick-action-modal" class="fixed inset-0 bg-black/50 z-50 hidden items-center justify-center">
|
|
<div class="bg-white dark:bg-zinc-800 rounded-lg shadow-xl w-full max-w-md p-6">
|
|
<h3 class="text-lg font-medium">快速处置</h3>
|
|
<p class="text-sm text-zinc-500 mt-2">模态框内容占位符,未来将在此处实现具体功能。</p>
|
|
<div class="mt-4 flex justify-end">
|
|
<button id="close-modal-btn" class="px-4 py-2 text-sm rounded-md bg-zinc-200 dark:bg-zinc-700">关闭</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %}
|
|
|
|
|
|
{% block page_scripts %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
});
|
|
</script>
|
|
<!-- [保留] 核心UI依赖 -->
|
|
<script src="/static/js/status-grid.js" defer></script>
|
|
<!-- [保留] 核心UI主程序 (需要进行适配) -->
|
|
<script src="/static/js/dashboard.js" defer></script>
|
|
{% endblock %}
|