Download app/template/admin.html from JXJBing/grok2api: direct link, hf CLI and curl.
- Browser
- Download file 114 kB
-
https://huggingface.co/spaces/JXJBing/grok2api/resolve/main/app/template/admin.html
- Command line
-
hf download hf://spaces/JXJBing/grok2api/app/template/admin.html
-
curl -L -o admin.html https://huggingface.co/spaces/JXJBing/grok2api/resolve/main/app/template/admin.html
114 kB
| <html lang="zh-CN" class="h-full"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>管理控制台 - Grok2API</title> | |
| <link rel="icon" type="image/png" href="/static/favicon.png"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <style> | |
| @keyframes slide-up { | |
| from { | |
| transform: translateY(100%); | |
| opacity: 0 | |
| } | |
| to { | |
| transform: translateY(0); | |
| opacity: 1 | |
| } | |
| } | |
| .animate-slide-up { | |
| animation: slide-up .3s ease-out | |
| } | |
| .tab-btn { | |
| transition: all .2s ease | |
| } | |
| .hover-card { | |
| position: relative; | |
| display: inline-block | |
| } | |
| .hover-card-trigger { | |
| cursor: pointer | |
| } | |
| .hover-card-content { | |
| position: absolute; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| background: hsl(0 0% 3.9%); | |
| color: hsl(0 0% 98%); | |
| padding: 8px 12px; | |
| border-radius: 6px; | |
| font-size: 12px; | |
| font-weight: 500; | |
| white-space: nowrap; | |
| z-index: 9999; | |
| pointer-events: none; | |
| opacity: 0; | |
| visibility: hidden; | |
| transition: opacity .2s ease, transform .2s ease; | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, .25); | |
| border: 1px solid hsl(0 0% 14.9%) | |
| } | |
| .hover-card:hover .hover-card-content { | |
| opacity: 1; | |
| visibility: visible | |
| } | |
| .hover-card-content.top { | |
| bottom: 100%; | |
| transform: translateX(-50%) translateY(-8px) | |
| } | |
| .hover-card-content.bottom { | |
| top: 100%; | |
| transform: translateX(-50%) translateY(8px) | |
| } | |
| .hover-card-content::after { | |
| content: ''; | |
| position: absolute; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| border: 6px solid transparent; | |
| z-index: 1000 | |
| } | |
| .hover-card-content.top::after { | |
| top: 100%; | |
| border-top-color: hsl(0 0% 3.9%) | |
| } | |
| .hover-card-content.bottom::after { | |
| bottom: 100%; | |
| border-bottom-color: hsl(0 0% 3.9%) | |
| } | |
| .hover-card-trigger:hover+.hover-card-content { | |
| opacity: 1; | |
| visibility: visible | |
| } | |
| .btn-icon { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| border-radius: 0.375rem; | |
| transition: color .2s, background-color .2s; | |
| height: 2rem; | |
| width: 2rem | |
| } | |
| .btn-icon:focus-visible { | |
| outline: 2px solid transparent; | |
| outline-offset: 2px; | |
| box-shadow: 0 0 0 1px hsl(0 0% 3.9%) | |
| } | |
| .btn-icon:hover { | |
| background-color: hsl(0 0% 96.1%); | |
| color: hsl(0 0% 9%) | |
| } | |
| .sticky-right { | |
| position: sticky; | |
| right: 0; | |
| background-color: hsl(0 0% 100%); | |
| z-index: 10; | |
| border-left: 1px solid hsl(0 0% 89%) | |
| } | |
| .cfg-label { | |
| font-size: 0.875rem; | |
| font-weight: 500; | |
| color: hsl(0 0% 45.1%); | |
| margin-bottom: 0.5rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.25rem | |
| } | |
| .cfg-input { | |
| display: flex; | |
| height: 2.25rem; | |
| width: 100%; | |
| border-radius: 0.375rem; | |
| border: 1px solid hsl(0 0% 89%); | |
| background-color: hsl(0 0% 100%); | |
| padding: 0.5rem 0.75rem; | |
| font-size: 0.875rem | |
| } | |
| .help-icon { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| width: 0.875rem; | |
| height: 0.875rem; | |
| border-radius: 9999px; | |
| border: 1px solid hsl(0 0% 45.1%); | |
| color: hsl(0 0% 45.1%); | |
| cursor: help; | |
| font-size: 10px; | |
| line-height: 1 | |
| } | |
| [title] { | |
| position: relative | |
| } | |
| [title]:hover::after { | |
| content: attr(title); | |
| position: absolute; | |
| bottom: 100%; | |
| left: 50%; | |
| transform: translateX(-50%) translateY(-8px); | |
| background: hsl(0 0% 11%); | |
| color: hsl(0 0% 98%); | |
| padding: 8px 12px; | |
| border-radius: 6px; | |
| font-size: 12px; | |
| font-weight: 500; | |
| line-height: 1.4; | |
| white-space: pre-line; | |
| max-width: 350px; | |
| width: max-content; | |
| word-wrap: break-word; | |
| z-index: 1000; | |
| pointer-events: none; | |
| box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15), 0 2px 8px rgba(0, 0, 0, 0.1); | |
| opacity: 0; | |
| visibility: hidden; | |
| transition: all 0.2s ease; | |
| animation: tooltipFadeIn 0.2s ease forwards | |
| } | |
| [title]:hover::before { | |
| content: ''; | |
| position: absolute; | |
| bottom: 100%; | |
| left: 50%; | |
| transform: translateX(-50%) translateY(-4px); | |
| border: 6px solid transparent; | |
| border-top-color: hsl(0 0% 11%); | |
| z-index: 1000; | |
| opacity: 0; | |
| visibility: hidden; | |
| transition: opacity 0.2s ease, visibility 0.2s ease | |
| } | |
| [title]:hover::after, | |
| [title]:hover::before { | |
| opacity: 1; | |
| visibility: visible | |
| } | |
| @keyframes tooltipFadeIn { | |
| from { | |
| opacity: 0; | |
| transform: translateX(-50%) translateY(-4px) | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateX(-50%) translateY(-8px) | |
| } | |
| } | |
| </style> | |
| <script> | |
| tailwind.config = { theme: { extend: { colors: { border: "hsl(0 0% 89%)", input: "hsl(0 0% 89%)", ring: "hsl(0 0% 3.9%)", background: "hsl(0 0% 100%)", foreground: "hsl(0 0% 3.9%)", primary: { DEFAULT: "hsl(0 0% 9%)", foreground: "hsl(0 0% 98%)" }, secondary: { DEFAULT: "hsl(0 0% 96.1%)", foreground: "hsl(0 0% 9%)" }, muted: { DEFAULT: "hsl(0 0% 96.1%)", foreground: "hsl(0 0% 45.1%)" }, accent: { DEFAULT: "hsl(0 0% 96.1%)", foreground: "hsl(0 0% 9%)" }, destructive: { DEFAULT: "hsl(0 84.2% 60.2%)", foreground: "hsl(0 0% 98%)" } } } } } | |
| </script> | |
| </head> | |
| <body class="h-full bg-background text-foreground antialiased"> | |
| <!-- 导航栏 --> | |
| <header | |
| class="sticky top-0 z-50 w-full border-b border-border/40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60"> | |
| <div class="mx-auto flex h-14 max-w-7xl items-center px-6"> | |
| <div class="mr-4 flex items-baseline gap-3"> | |
| <span class="font-bold text-xl">Grok2API</span> | |
| <span class="text-xs text-gray-400">by @Chenyme & @Tomiya233</span> | |
| </div> | |
| <div class="flex flex-1 items-center justify-end"> | |
| <div class="flex items-center gap-2"> | |
| <div class="hover-card"> | |
| <span id="storageMode" | |
| class="hover-card-trigger inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium bg-muted text-muted-foreground border"> | |
| <svg class="h-3 w-3 mr-1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <ellipse cx="12" cy="5" rx="9" ry="3" /> | |
| <path d="m21 12c0 1.66-4 3-9 3s-9-1.34-9-3" /> | |
| <path d="m3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" /> | |
| </svg> | |
| <span id="storageModeText">FILE</span> | |
| </span> | |
| <div id="storageModeTooltip" class="hover-card-content top"> | |
| 加载中... | |
| </div> | |
| </div> | |
| <nav class="flex items-center gap-1"> | |
| <button onclick="logout()" | |
| class="inline-flex items-center justify-center text-xs transition-colors hover:bg-accent hover:text-accent-foreground h-7 px-2.5 gap-1"> | |
| <svg class="h-3.5 w-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" /> | |
| <polyline points="16 17 21 12 16 7" /> | |
| <line x1="21" y1="12" x2="9" y2="12" /> | |
| </svg> | |
| 退出 | |
| </button> | |
| </nav> | |
| </div> | |
| </div> | |
| </header> | |
| <main class="mx-auto max-w-7xl px-6 py-6"> | |
| <!-- Tab 导航 --> | |
| <div class="border-b border-border mb-6"> | |
| <nav class="flex space-x-8"> | |
| <button onclick="switchTab('tokens')" id="tabTokens" | |
| class="tab-btn border-b-2 border-primary text-sm font-medium py-3 px-1">Token 管理</button> | |
| <button onclick="switchTab('statistics')" id="tabStatistics" | |
| class="tab-btn border-b-2 border-transparent text-sm font-medium py-3 px-1">请求统计</button> | |
| <button onclick="switchTab('keys')" id="tabKeys" | |
| class="tab-btn border-b-2 border-transparent text-sm font-medium py-3 px-1">Key 管理</button> | |
| <button onclick="switchTab('logs')" id="tabLogs" | |
| class="tab-btn border-b-2 border-transparent text-sm font-medium py-3 px-1">日志审计</button> | |
| <button onclick="switchTab('cache')" id="tabCache" | |
| class="tab-btn border-b-2 border-transparent text-sm font-medium py-3 px-1">缓存预览</button> | |
| <button onclick="switchTab('settings')" id="tabSettings" | |
| class="tab-btn border-b-2 border-transparent text-sm font-medium py-3 px-1">Setting 配置</button> | |
| </nav> | |
| </div> | |
| <!-- Token 管理面板 --> | |
| <div id="panelTokens"> | |
| <!-- 统计卡片 --> | |
| <div class="grid gap-4 grid-cols-2 md:grid-cols-4 mb-6"> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">Token 总数</p> | |
| <h3 class="text-xl font-bold" id="statTotal">-</h3> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">Token 正常</p> | |
| <h3 class="text-xl font-bold text-green-600" id="statActive">-</h3> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">Token 未使用</p> | |
| <h3 class="text-xl font-bold text-gray-500" id="statUnused">-</h3> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">Token 限流中</p> | |
| <h3 class="text-xl font-bold text-orange-600" id="statLimited">-</h3> | |
| <p class="text-xs text-muted-foreground mt-2"> | |
| 冷却 <span id="statCooldown">-</span> · 耗尽 <span id="statExhausted">-</span> | |
| </p> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">Token 失效</p> | |
| <h3 class="text-xl font-bold text-destructive" id="statExpired">-</h3> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">Chat 总剩余</p> | |
| <h3 class="text-xl font-bold" id="statChatRemaining">-</h3> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">Image 总剩余</p> | |
| <h3 class="text-xl font-bold text-blue-600" id="statImageRemaining">-</h3> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">Video 总剩余</p> | |
| <h3 class="text-xl font-bold text-purple-600" id="statVideoRemaining">无法统计</h3> | |
| </div> | |
| </div> | |
| <!-- Token 列表 --> | |
| <div class="rounded-lg border border-border bg-background"> | |
| <!-- 工具栏 --> | |
| <div class="flex items-center justify-between gap-4 p-4 border-b border-border"> | |
| <div class="flex items-center gap-3 flex-1"> | |
| <div class="flex items-center gap-2"> | |
| <select id="filterType" onchange="filterTokens()" | |
| class="h-8 px-1 text-sm rounded-md bg-background focus:outline-none focus:ring-1 focus:ring-ring w-[90px]"> | |
| <option value="all">全部类型</option> | |
| <option value="sso">SSO</option> | |
| <option value="ssoSuper">SuperSSO</option> | |
| </select> | |
| <select id="filterStatus" onchange="filterTokens()" | |
| class="h-8 px-1 text-sm rounded-md bg-background focus:outline-none focus:ring-1 focus:ring-ring w-[90px]"> | |
| <option value="all">全部状态</option> | |
| <option value="未使用">未使用</option> | |
| <option value="冷却中">冷却中</option> | |
| <option value="额度耗尽">额度耗尽</option> | |
| <option value="失效">失效</option> | |
| <option value="正常">正常</option> | |
| </select> | |
| <select id="filterTag" onchange="filterTokens()" | |
| class="h-8 px-1 text-sm rounded-md bg-background focus:outline-none focus:ring-1 focus:ring-ring w-[90px]"> | |
| <option value="all">全部标签</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="flex items-center gap-2"> | |
| <button onclick="refreshTokens()" class="btn-icon" title="刷新列表"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <polyline points="23 4 23 10 17 10" /> | |
| <polyline points="1 20 1 14 7 14" /> | |
| <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" /> | |
| </svg> | |
| </button> | |
| <button onclick="refreshAllTokens()" class="btn-icon" title="刷新所有Token剩余次数"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" /> | |
| <path d="M3 3v5h5" /> | |
| <path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" /> | |
| <path d="M16 21h5v-5" /> | |
| </svg> | |
| </button> | |
| <div id="batchActions" class="hidden items-center gap-2"> | |
| <button onclick="exportSelected()" class="btn-icon" title="导出选中项"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> | |
| <polyline points="7 10 12 15 17 10" /> | |
| <line x1="12" y1="15" x2="12" y2="3" /> | |
| </svg> | |
| </button> | |
| <button onclick="batchDelete()" class="btn-icon hover:bg-destructive/10 hover:text-destructive" | |
| title="批量删除"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <polyline points="3 6 5 6 21 6" /> | |
| <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /> | |
| <line x1="10" y1="11" x2="10" y2="17" /> | |
| <line x1="14" y1="11" x2="14" y2="17" /> | |
| </svg> | |
| </button> | |
| </div> | |
| <button onclick="openAddModal()" | |
| class="inline-flex items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring bg-primary text-primary-foreground hover:bg-primary/90 h-8 px-3" | |
| title="添加 Token"> | |
| <svg class="h-4 w-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <line x1="12" y1="5" x2="12" y2="19" /> | |
| <line x1="5" y1="12" x2="19" y2="12" /> | |
| </svg> | |
| <span class="text-sm font-medium">新增</span> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- 表格 --> | |
| <div class="relative w-full overflow-auto"> | |
| <table class="w-full text-sm table-fixed"> | |
| <thead> | |
| <tr class="border-b border-border"> | |
| <th class="h-10 px-3 text-left align-middle font-medium w-12"> | |
| <input type="checkbox" id="selectAll" onchange="toggleSelectAll()" | |
| class="h-3.5 w-3.5 rounded border border-input focus:ring-1 focus:ring-ring"> | |
| </th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-72">Token</th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-20">类型</th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-20">状态</th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-20">普通</th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-20">高级</th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-40">限流信息</th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-48">最近失败</th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-32">标签</th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-40">备注</th> | |
| <th class="h-10 px-3 text-left align-middle text-sm font-medium text-muted-foreground w-32">创建时间</th> | |
| <th | |
| class="h-10 px-3 text-center align-middle text-sm font-medium text-muted-foreground w-28 sticky-right"> | |
| 操作</th> | |
| </tr> | |
| </thead> | |
| <tbody id="tokenTableBody" class="divide-y divide-border"> | |
| <!-- 动态填充 --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div id="emptyState" class="hidden flex flex-col items-center justify-center py-12"> | |
| <svg class="h-10 w-10 text-muted-foreground/50 mb-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" | |
| fill="none" stroke="currentColor" stroke-width="2"> | |
| <rect x="3" y="3" width="18" height="18" rx="2" /> | |
| <path d="M9 9h6v6H9z" /> | |
| </svg> | |
| <p class="text-sm text-muted-foreground">暂无数据</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Key 管理面板 --> | |
| <div id="panelKeys" class="hidden"> | |
| <!-- 工具栏 --> | |
| <div class="flex items-center justify-between gap-4 mb-6"> | |
| <h2 class="text-xl font-bold">Key Management</h2> | |
| <div class="flex items-center gap-2"> | |
| <button onclick="loadKeys()" class="btn-icon" title="刷新列表"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" /> | |
| <path d="M3 3v5h5" /> | |
| <path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" /> | |
| <path d="M16 21h5v-5" /> | |
| </svg> | |
| </button> | |
| <button onclick="openBatchAddModal()" | |
| class="inline-flex items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring border border-input bg-background hover:bg-accent hover:text-accent-foreground h-8 px-3"> | |
| <svg class="h-4 w-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <rect x="3" y="3" width="18" height="18" rx="2" /> | |
| <line x1="12" y1="8" x2="12" y2="16" /> | |
| <line x1="8" y1="12" x2="16" y2="12" /> | |
| </svg> | |
| <span class="text-sm font-medium">批量创建</span> | |
| </button> | |
| <button onclick="openAddKeyModal()" | |
| class="inline-flex items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring bg-primary text-primary-foreground hover:bg-primary/90 h-8 px-3"> | |
| <svg class="h-4 w-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <line x1="12" y1="5" x2="12" y2="19" /> | |
| <line x1="5" y1="12" x2="19" y2="12" /> | |
| </svg> | |
| <span class="text-sm font-medium">新增 Key</span> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- 批量操作栏 --> | |
| <div id="batchActionBar" | |
| class="hidden mb-4 p-3 rounded-lg bg-primary/5 border border-primary/20 flex items-center justify-between"> | |
| <div class="flex items-center gap-3"> | |
| <span class="text-sm font-medium text-primary"><span id="selectedCount">0</span> 个项目被选中</span> | |
| </div> | |
| <div class="flex items-center gap-2"> | |
| <button onclick="batchUpdateStatus(true)" | |
| class="text-xs px-2 py-1 rounded bg-background border border-border hover:bg-accent transition-colors">批量启用</button> | |
| <button onclick="batchUpdateStatus(false)" | |
| class="text-xs px-2 py-1 rounded bg-background border border-border hover:bg-accent transition-colors">批量禁用</button> | |
| <button onclick="batchDeleteKeys()" | |
| class="text-xs px-2 py-1 rounded bg-destructive text-destructive-foreground hover:bg-destructive/90 transition-colors">批量删除</button> | |
| </div> | |
| </div> | |
| <!-- Key 表格 --> | |
| <div class="rounded-lg border border-border bg-background"> | |
| <div class="relative w-full overflow-auto"> | |
| <table class="w-full text-sm"> | |
| <thead> | |
| <tr class="border-b border-border"> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-12"> | |
| <input type="checkbox" id="selectAllKeys" onchange="toggleSelectAllKeys(this)" | |
| class="rounded border-border text-primary focus:ring-primary h-4 w-4"> | |
| </th> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-48">备注</th> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-64">Key</th> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-32">创建时间</th> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-24">状态</th> | |
| <th class="h-10 px-4 text-right align-middle font-medium w-48">操作</th> | |
| </tr> | |
| </thead> | |
| <tbody id="keyTableBody" class="divide-y divide-border"> | |
| <!-- JS填充 --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div id="keyEmptyState" class="hidden flex flex-col items-center justify-center py-12"> | |
| <p class="text-sm text-muted-foreground">暂无 API Key</p> | |
| </div> | |
| </div> | |
| <div id="globalKeyAlert" class="mt-4 p-4 rounded-lg bg-orange-50 border border-orange-200 hidden"> | |
| <div class="flex items-start gap-3"> | |
| <svg class="h-5 w-5 text-orange-600 mt-0.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" /> | |
| <line x1="12" y1="9" x2="12" y2="13" /> | |
| <line x1="12" y1="17" x2="12.01" y2="17" /> | |
| </svg> | |
| <div> | |
| <h4 class="text-sm font-bold text-orange-800">存在全局 Key</h4> | |
| <p class="text-sm text-orange-700 mt-1"> | |
| 系统检测到 `setting.toml` 中配置了旧的全局 `api_key`。 | |
| 它被视为 "默认管理员" Key,此处无法修改或删除。如果希望完全使用多 Key 管理,请清空配置文件中的 api_key。 | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 日志审计面板 --> | |
| <div id="panelLogs" class="hidden"> | |
| <div class="flex items-center justify-between mb-6"> | |
| <h2 class="text-xl font-bold">日志审计</h2> | |
| <div class="flex items-center gap-2"> | |
| <button onclick="loadLogs()" class="btn-icon" title="刷新日志"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" /> | |
| <path d="M3 3v5h5" /> | |
| <path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" /> | |
| <path d="M16 21h5v-5" /> | |
| </svg> | |
| </button> | |
| <button onclick="clearLogs()" | |
| class="inline-flex items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring bg-destructive text-destructive-foreground hover:bg-destructive/90 h-8 px-3"> | |
| <span class="text-sm font-medium">清空日志</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background"> | |
| <div class="relative w-full overflow-auto" style="max-height: 800px;"> | |
| <table class="w-full text-sm"> | |
| <thead> | |
| <tr class="border-b border-border sticky top-0 bg-background z-10"> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-40">时间</th> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-32">Key 名称</th> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-40">模型</th> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-32">IP</th> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-24">耗时</th> | |
| <th class="h-10 px-4 text-left align-middle font-medium w-24">状态</th> | |
| <th class="h-10 px-4 text-left align-middle font-medium">详情</th> | |
| </tr> | |
| </thead> | |
| <tbody id="logTableBody" class="divide-y divide-border"> | |
| <!-- JS填充 --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div id="logEmptyState" class="hidden flex flex-col items-center justify-center py-12"> | |
| <p class="text-sm text-muted-foreground">暂无日志</p> | |
| </div> | |
| <!-- 分页控制 --> | |
| <div id="logPagination" class="flex items-center justify-between px-4 py-3 border-t border-border bg-muted/20"> | |
| <div class="text-xs text-muted-foreground"> | |
| 共 <span id="logTotalCount">0</span> 条日志 | |
| </div> | |
| <div class="flex items-center gap-2"> | |
| <button onclick="changeLogPage(-1)" id="logPrevBtn" | |
| class="inline-flex items-center justify-center rounded-md text-xs font-medium h-8 w-8 border border-input bg-background hover:bg-accent disabled:opacity-50 transition-colors"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <polyline points="15 18 9 12 15 6" /> | |
| </svg> | |
| </button> | |
| <span class="text-xs font-medium px-2">第 <span id="logCurrentPage">1</span> / <span id="logMaxPage">1</span> | |
| 页</span> | |
| <button onclick="changeLogPage(1)" id="logNextBtn" | |
| class="inline-flex items-center justify-center rounded-md text-xs font-medium h-8 w-8 border border-input bg-background hover:bg-accent disabled:opacity-50 transition-colors"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <polyline points="9 18 15 12 9 6" /> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 缓存预览面板 --> | |
| <div id="panelCache" class="hidden"> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h3 class="text-sm font-semibold">缓存预览</h3> | |
| <div class="flex items-center gap-2"> | |
| <div class="inline-flex rounded-md border border-input overflow-hidden"> | |
| <button id="cacheTabImage" onclick="switchCachePreviewType('image')" | |
| class="px-3 h-8 text-xs font-medium bg-primary text-primary-foreground">图片</button> | |
| <button id="cacheTabVideo" onclick="switchCachePreviewType('video')" | |
| class="px-3 h-8 text-xs font-medium bg-muted text-muted-foreground">视频</button> | |
| </div> | |
| <button onclick="refreshCachePreview()" | |
| class="inline-flex items-center justify-center rounded-md text-xs font-medium border border-input bg-background hover:bg-accent h-8 px-3 transition-colors">刷新</button> | |
| </div> | |
| </div> | |
| <div id="cachePreviewMeta" class="text-xs text-muted-foreground mb-3">图片缓存:0 个</div> | |
| <div id="cachePreviewGrid" class="grid grid-cols-2 sm:grid-cols-3 xl:grid-cols-4 gap-3"> | |
| <div class="col-span-full text-sm text-muted-foreground text-center py-6">暂无缓存文件</div> | |
| </div> | |
| <div class="mt-3 flex items-center justify-center"> | |
| <button id="cacheLoadMoreBtn" onclick="loadMoreCachePreview()" | |
| class="inline-flex items-center justify-center rounded-md text-xs font-medium border border-input bg-background hover:bg-accent h-8 px-4 transition-colors">加载更多</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 全局设置面板 --> | |
| <div id="panelSettings" class="hidden"> | |
| <!-- 全局配置区域 --> | |
| <div class="mb-8"> | |
| <div class="flex items-center justify-between mb-6"> | |
| <h2 class="text-xl font-bold">全局配置</h2> | |
| <button onclick="saveGlobalSettings()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium bg-secondary text-secondary-foreground hover:bg-black hover:text-white h-9 px-4 transition-colors">保存配置</button> | |
| </div> | |
| <div class="grid gap-4 lg:grid-cols-3"> | |
| <!-- 系统设置 --> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <h3 class="text-sm font-semibold mb-4">系统设置</h3> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="cfg-label">登陆账户<span class="help-icon" title="登录管理后台的用户名">?</span></label> | |
| <input id="cfgAdminUser" class="cfg-input" placeholder="admin"> | |
| </div> | |
| <div> | |
| <label class="cfg-label">登陆密码<span class="help-icon" title="登录管理后台的密码,留空表示不修改当前密码">?</span></label> | |
| <input id="cfgAdminPass" type="password" class="cfg-input" placeholder="留空则不修改"> | |
| </div> | |
| <div> | |
| <label class="cfg-label">日志级别<span class="help-icon" | |
| title="日志详细程度。DEBUG:最详细 | INFO:一般信息 | WARNING:警告 | ERROR:仅错误">?</span></label> | |
| <select id="cfgLogLevel" class="cfg-input"> | |
| <option>DEBUG</option> | |
| <option>INFO</option> | |
| <option>WARNING</option> | |
| <option>ERROR</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 媒体设置 --> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <h3 class="text-sm font-semibold mb-4">媒体设置</h3> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="cfg-label"> | |
| 图片模式 | |
| <span class="help-icon" title="返回图片的方式。URL:图片链接,支持图片缓存 | Base64:base64编码,不支持缓存">?</span> | |
| </label> | |
| <select id="cfgImageMode" class="cfg-input"> | |
| <option value="url">URL链接</option> | |
| <option value="base64">Base64</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| 服务网址 | |
| <span class="help-icon" title="服务器的公网访问地址,用于构建图片URL链接(仅在图片模式为URL时需要)">?</span> | |
| </label> | |
| <input id="cfgBaseUrl" class="cfg-input" placeholder="http://localhost:8000"> | |
| </div> | |
| <div class="grid grid-cols-2 gap-3"> | |
| <div> | |
| <label class="cfg-label"> | |
| 图片缓存 (MB) | |
| <span class="help-icon" title="图片缓存的最大容量(MB),超过后会自动清理旧缓存">?</span> | |
| </label> | |
| <input id="cfgImageCacheMaxSize" type="number" class="cfg-input" placeholder="500"> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| 视频缓存 (MB) | |
| <span class="help-icon" title="视频缓存的最大容量(MB),超过后会自动清理旧缓存">?</span> | |
| </label> | |
| <input id="cfgVideoCacheMaxSize" type="number" class="cfg-input" placeholder="1000"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 缓存管理 --> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <h3 class="text-sm font-semibold mb-4">缓存管理</h3> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="text-sm font-medium text-muted-foreground mb-2 block">图片缓存</label> | |
| <div class="flex gap-2"> | |
| <input id="imageCacheSize" readonly | |
| class="flex h-9 flex-1 rounded-md border border-input bg-muted px-3 py-2 text-sm" | |
| placeholder="0 MB"> | |
| <button onclick="clearImageCache()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium bg-secondary text-secondary-foreground hover:bg-red-600 hover:text-white h-9 w-9 p-0 transition-colors"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <path | |
| d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2M10 11v6M14 11v6" /> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="text-sm font-medium text-muted-foreground mb-2 block">视频缓存</label> | |
| <div class="flex gap-2"> | |
| <input id="videoCacheSize" readonly | |
| class="flex h-9 flex-1 rounded-md border border-input bg-muted px-3 py-2 text-sm" | |
| placeholder="0 MB"> | |
| <button onclick="clearVideoCache()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium bg-secondary text-secondary-foreground hover:bg-red-600 hover:text-white h-9 w-9 p-0 transition-colors"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <path | |
| d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2M10 11v6M14 11v6" /> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="text-sm font-medium text-muted-foreground mb-2 block">所有缓存</label> | |
| <div class="flex gap-2"> | |
| <input id="totalCacheSize" readonly | |
| class="flex h-9 flex-1 rounded-md border border-input bg-muted px-3 py-2 text-sm font-medium" | |
| placeholder="0 MB"> | |
| <button onclick="clearCache()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium bg-secondary text-secondary-foreground hover:bg-red-600 hover:text-white h-9 w-9 p-0 transition-colors"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <path | |
| d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2M10 11v6M14 11v6" /> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Grok 配置区域 --> | |
| <div> | |
| <div class="flex items-center justify-between mb-6"> | |
| <h2 class="text-xl font-bold">Grok 配置</h2> | |
| <button onclick="saveGrokSettings()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium bg-secondary text-secondary-foreground hover:bg-black hover:text-white h-9 px-4 transition-colors">保存配置</button> | |
| </div> | |
| <div class="grid gap-4 lg:grid-cols-3"> | |
| <!-- 基础设置 --> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <h3 class="text-sm font-semibold mb-4">基础设置</h3> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="cfg-label"> | |
| API Key | |
| <span class="help-icon" title="接口调用的身份验证密钥,用于保护API访问安全">?</span> | |
| </label> | |
| <input id="cfgApiKey" class="cfg-input" placeholder=""> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| X Statsig ID | |
| <span class="help-icon" title="Statsig统计ID,用于功能实验和统计分析">?</span> | |
| </label> | |
| <div class="flex items-center gap-3"> | |
| <input id="cfgStatsigId" | |
| class="flex h-9 flex-1 rounded-md border border-input bg-background px-3 py-2 text-sm" | |
| placeholder=""> | |
| <label class="inline-flex items-center gap-2 cursor-pointer" title="开启后每次请求自动生成新的 x-statsig-id"> | |
| <span class="text-xs text-muted-foreground whitespace-nowrap">动态</span> | |
| <div class="relative"> | |
| <input type="checkbox" id="cfgDynamicStatsig" class="sr-only peer"> | |
| <div | |
| class="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-ring rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-primary"> | |
| </div> | |
| </div> | |
| </label> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| 过滤标签 | |
| <span class="help-icon" title="需要过滤的响应标签,多个标签用逗号分隔。如:xaiartifact,xai:tool_usage_card">?</span> | |
| </label> | |
| <input id="cfgFilteredTags" class="cfg-input" placeholder="xaiartifact,xai:tool_usage_card"> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| 显示思考 | |
| <span class="help-icon" title="开启后会显示模型的思考过程(<think>标签内容);关闭后仅返回最终结果">?</span> | |
| </label> | |
| <select id="cfgShowThinking" class="cfg-input"> | |
| <option value="true">开启</option> | |
| <option value="false">关闭</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| 临时会话 | |
| <span class="help-icon" title="开启后每次对话都创建新会话,不保留历史;关闭后可以继续之前的对话">?</span> | |
| </label> | |
| <select id="cfgTemporary" class="cfg-input"> | |
| <option value="false">关闭</option> | |
| <option value="true">开启</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 代理设置 --> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <h3 class="text-sm font-semibold mb-4">代理设置</h3> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="cfg-label"> | |
| CF Clearance | |
| <span class="help-icon" | |
| title="Cloudflare验证cookie的值部分,用于绕过Cloudflare人机验证。只需输入cf_clearance=后面的值。">?</span> | |
| </label> | |
| <input id="cfgCfClearance" class="cfg-input" placeholder=""> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| Proxy Url (服务代理) | |
| <span class="help-icon" | |
| title="API请求和上传使用的代理。支持 http、https、socks5。格式:socks5://user:pass@host:port">?</span> | |
| </label> | |
| <input id="cfgProxyUrl" class="cfg-input" placeholder="socks5://username:password@127.0.0.1:7890"> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| Proxy Pool URL (代理池API) | |
| <span class="help-icon" | |
| title="代理池API地址,返回单个代理URL。留空则使用上方的固定代理。 返回格式:纯文本,单行代理地址 示例返回:socks5h://1.2.3.4:1080 支持协议:http://, https://, socks5://, socks5h:// API示例:http://your-api.com/get">?</span> | |
| </label> | |
| <input id="cfgProxyPoolUrl" class="cfg-input" placeholder="http://your-proxy-api.com/get"> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| Proxy Pool Interval (刷新间隔秒) | |
| <span class="help-icon" title="代理池自动刷新间隔,单位秒。建议300-600秒(5-10分钟)">?</span> | |
| </label> | |
| <input id="cfgProxyPoolInterval" type="number" class="cfg-input" placeholder="300"> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| Cache Proxy Url (缓存代理) | |
| <span class="help-icon" title="图片/视频缓存下载专用代理,不设置则使用服务代理。Grok的图片/视频获取接口对IP风控要求不高,可使用便宜的大流量节点">?</span> | |
| </label> | |
| <input id="cfgCacheProxyUrl" class="cfg-input" placeholder="socks5://username:password@127.0.0.1:7890"> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 超时设置 --> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <h3 class="text-sm font-semibold mb-4">超时设置</h3> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="cfg-label"> | |
| 首次响应超时 (秒) | |
| <span class="help-icon" title="等待API首次返回数据的最大时间(秒)。超时后会报错,建议30-60秒">?</span> | |
| </label> | |
| <input id="cfgStreamFirstResponseTimeout" type="number" class="cfg-input" placeholder="30"> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| 流式间隔超时 (秒) | |
| <span class="help-icon" title="两次数据块之间的最大间隔时间(秒)。如果超过此时间没有收到新数据则断开,建议60-180秒">?</span> | |
| </label> | |
| <input id="cfgStreamChunkTimeout" type="number" class="cfg-input" placeholder="120"> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| 生成总过程超时 (秒) | |
| <span class="help-icon" title="整个对话生成的最大总时长(秒)。适用于超长对话,建议300-900秒">?</span> | |
| </label> | |
| <input id="cfgStreamTotalTimeout" type="number" class="cfg-input" placeholder="600"> | |
| </div> | |
| <div> | |
| <label class="cfg-label"> | |
| 可重试状态码 | |
| <span class="help-icon" | |
| title="遇到这些HTTP状态码时会自动换token重试。多个状态码用逗号分隔。默认:401,429 常见状态码:401(未授权), 429(速率限制), 500(服务器错误), 502(网关错误), 503(服务不可用)">?</span> | |
| </label> | |
| <input id="cfgRetryStatusCodes" class="cfg-input" placeholder="401,429"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 配置提示 --> | |
| <div class="mt-8 rounded border border-blue-300 bg-blue-50 px-4 py-3"> | |
| <div class="text-xs text-gray-800 leading-relaxed"> | |
| <div class="text-base font-medium text-gray-900 mb-2.5">部分说明</div> | |
| <div class="space-y-1.5"> | |
| <div><span class="font-medium">X Statsig ID:</span>反机器人验证参数。开启"动态 Statsig ID"后会自动生成,固定值将被忽略;关闭则使用上方设置的固定值 | |
| </div> | |
| <div><span class="font-medium">动态 Statsig:</span>开启后每次请求自动生成新的 x-statsig-id,增强请求多样性,推荐开启</div> | |
| <div><span class="font-medium">服务网址:</span>图片/视频链接返回时需要拼接您的服务网址(如 | |
| https://yourdomain.com),若您不使用视频功能且图片使用Base64模式则可留空</div> | |
| <div><span class="font-medium">代理设置:</span>服务代理用于访问Grok | |
| API和上传图片;缓存代理专门用于下载图片和视频缓存。若仅设置服务代理,缓存将使用相同的代理;若都设置,则分别使用不同的代理</div> | |
| <div><span class="font-medium">请求 403:</span>通常是被 CF 拦截了,可采用以下办法之一:1. 更换服务器IP | 2. 配置代理IP | 3.在服务器中访问 | |
| grok.com 通过 CF 验证后 F12 获取 cf_clearance</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 统计面板 --> | |
| <div id="panelStatistics" class="hidden"> | |
| <!-- 概览卡片 --> | |
| <div class="grid gap-4 grid-cols-2 md:grid-cols-4 mb-6"> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">总请求数</p> | |
| <h3 class="text-xl font-bold" id="reqStatTotal">-</h3> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">成功请求</p> | |
| <h3 class="text-xl font-bold text-green-600" id="reqStatSuccess">-</h3> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">失败请求</p> | |
| <h3 class="text-xl font-bold text-destructive" id="reqStatFailed">-</h3> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-4"> | |
| <p class="text-sm font-medium text-muted-foreground mb-2">成功率</p> | |
| <h3 class="text-xl font-bold text-blue-600" id="reqStatRate">-</h3> | |
| </div> | |
| </div> | |
| <!-- 图表容器 --> | |
| <div class="grid gap-6 lg:grid-cols-2 mb-6"> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <h3 class="text-sm font-semibold mb-4">24小时请求趋势</h3> | |
| <canvas id="hourlyChart" height="200"></canvas> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <h3 class="text-sm font-semibold mb-4">7天请求统计</h3> | |
| <canvas id="dailyChart" height="200"></canvas> | |
| </div> | |
| <div class="rounded-lg border border-border bg-background p-6"> | |
| <h3 class="text-sm font-semibold mb-4">模型调用分布</h3> | |
| <canvas id="modelsChart" height="200"></canvas> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- 编辑信息模态框 --> | |
| <div id="editTagsModal" class="hidden fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4"> | |
| <div class="bg-background rounded-lg border border-border w-full max-w-md shadow-xl"> | |
| <div class="flex items-center justify-between p-5 border-b border-border"> | |
| <h3 class="text-lg font-semibold">编辑信息</h3> | |
| <button onclick="closeEditModal()" class="text-muted-foreground hover:text-foreground transition-colors"> | |
| <svg class="h-3.5 w-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <line x1="18" y1="6" x2="6" y2="18" /> | |
| <line x1="6" y1="6" x2="18" y2="18" /> | |
| </svg> | |
| </button> | |
| </div> | |
| <div class="p-5 space-y-4"> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-muted-foreground">Token</label> | |
| <input id="editTokenInput" readonly | |
| class="flex h-9 w-full rounded-md border border-input bg-muted px-3 py-2 text-xs font-mono" placeholder=""> | |
| </div> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-muted-foreground">标签 <span | |
| class="text-muted-foreground">(多个标签用逗号分隔)</span></label> | |
| <input id="editTagsInput" placeholder="例如: 生产环境, 测试用" | |
| class="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring" /> | |
| <div id="suggestedTags" class="flex flex-wrap gap-2 mt-2"></div> | |
| </div> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-muted-foreground">备注</label> | |
| <textarea id="editNoteInput" rows="3" placeholder="添加备注信息..." | |
| class="flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring resize-none"></textarea> | |
| </div> | |
| </div> | |
| <div class="flex items-center justify-end gap-3 p-5 border-t border-border bg-muted/30"> | |
| <button onclick="closeEditModal()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent h-9 px-5"> | |
| 取消 | |
| </button> | |
| <button onclick="submitEditInfo()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-5"> | |
| 保存 | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 添加 Token 模态框 --> | |
| <div id="addModal" class="hidden fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4"> | |
| <div class="bg-background rounded-lg border border-border w-full max-w-2xl max-h-[90vh] overflow-y-auto shadow-xl"> | |
| <div class="flex items-center justify-between p-5 border-b border-border"> | |
| <h3 class="text-lg font-semibold">添加 Token</h3> | |
| <button onclick="closeAddModal()" class="text-muted-foreground hover:text-foreground transition-colors"> | |
| <svg class="h-3.5 w-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <line x1="18" y1="6" x2="6" y2="18" /> | |
| <line x1="6" y1="6" x2="18" y2="18" /> | |
| </svg> | |
| </button> | |
| </div> | |
| <div class="p-5 space-y-4"> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-muted-foreground">Token 类型</label> | |
| <select id="addTokenType" | |
| class="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring"> | |
| <option value="sso">SSO</option> | |
| <option value="ssoSuper">SuperSSO</option> | |
| </select> | |
| </div> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-muted-foreground">Token 列表 <span | |
| class="text-muted-foreground">(每行一个)</span></label> | |
| <textarea id="addTokenList" rows="12" placeholder="请输入 Token,每行一个" | |
| class="flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring font-mono resize-none"></textarea> | |
| </div> | |
| </div> | |
| <div class="flex items-center justify-end gap-3 p-5 border-t border-border bg-muted/30"> | |
| <button onclick="closeAddModal()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent h-9 px-5"> | |
| 取消 | |
| </button> | |
| <button onclick="submitAddTokens()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-5"> | |
| 添加 | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 新增 Key 模态框 --> | |
| <div id="modalAddKey" class="hidden fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4"> | |
| <div class="bg-background rounded-lg border border-border w-full max-w-md shadow-xl"> | |
| <div class="flex items-center justify-between p-5 border-b border-border"> | |
| <h3 class="text-lg font-semibold">新增 API Key</h3> | |
| <button onclick="closeAddKeyModal()" class="text-muted-foreground hover:text-foreground transition-colors"> | |
| <svg class="h-3.5 w-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <line x1="18" y1="6" x2="6" y2="18" /> | |
| <line x1="6" y1="6" x2="18" y2="18" /> | |
| </svg> | |
| </button> | |
| </div> | |
| <div class="p-5 space-y-4"> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-muted-foreground">备注名称</label> | |
| <input type="text" id="newKeyName" placeholder="例如: 某某应用使用" | |
| class="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring"> | |
| </div> | |
| </div> | |
| <div class="flex items-center justify-end gap-3 p-5 border-t border-border bg-muted/30"> | |
| <button onclick="closeAddKeyModal()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors border border-input bg-background hover:bg-accent h-9 px-5">取消</button> | |
| <button onclick="doAddKey()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-5">确认</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 批量创建 Key 模态框 --> | |
| <div id="modalBatchAddKey" class="hidden fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4"> | |
| <div class="bg-background rounded-lg border border-border w-full max-w-md shadow-xl"> | |
| <div class="flex items-center justify-between p-5 border-b border-border"> | |
| <h3 class="text-lg font-semibold">批量创建 API Key</h3> | |
| <button onclick="closeBatchAddModal()" class="text-muted-foreground hover:text-foreground transition-colors"> | |
| <svg class="h-3.5 w-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <line x1="18" y1="6" x2="6" y2="18" /> | |
| <line x1="6" y1="6" x2="18" y2="18" /> | |
| </svg> | |
| </button> | |
| </div> | |
| <div class="p-5 space-y-4"> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-muted-foreground">名称前缀</label> | |
| <input type="text" id="batchKeyPrefix" placeholder="例如: 测试用户" | |
| class="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring"> | |
| </div> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-muted-foreground">创建数量 (1-50)</label> | |
| <input type="number" id="batchKeyCount" value="10" min="1" max="50" | |
| class="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring"> | |
| </div> | |
| </div> | |
| <div class="flex items-center justify-end gap-3 p-5 border-t border-border bg-muted/30"> | |
| <button onclick="closeBatchAddModal()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors border border-input bg-background hover:bg-accent h-9 px-5">取消</button> | |
| <button onclick="doBatchAddKeys()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-5">确认创建</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 批量创建结果模态框 --> | |
| <div id="modalBatchResult" class="hidden fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4"> | |
| <div class="bg-background rounded-lg border border-border w-full max-w-2xl shadow-xl"> | |
| <div class="flex items-center justify-between p-5 border-b border-border"> | |
| <h3 class="text-lg font-semibold">创建成功</h3> | |
| <button onclick="copyBatchResults()" class="text-sm text-primary hover:underline font-medium">点击复制全部</button> | |
| </div> | |
| <div class="p-5"> | |
| <div class="bg-muted p-4 rounded-md border border-border"> | |
| <textarea id="batchResultContent" readonly | |
| class="w-full h-80 bg-transparent border-none focus:ring-0 text-xs font-mono resize-none"></textarea> | |
| </div> | |
| </div> | |
| <div class="flex items-center justify-end p-5 border-t border-border bg-muted/30"> | |
| <button onclick="closeBatchResultModal()" | |
| class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-5">关闭</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 缓存预览模态框 --> | |
| <div id="cacheViewerModal" class="hidden fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4"> | |
| <div class="bg-background rounded-lg border border-border w-full max-w-5xl shadow-xl overflow-hidden"> | |
| <div class="flex items-center justify-between p-4 border-b border-border"> | |
| <div class="min-w-0"> | |
| <h3 id="cacheViewerTitle" class="text-sm font-semibold truncate">缓存预览</h3> | |
| <div id="cacheViewerMeta" class="text-xs text-muted-foreground"></div> | |
| </div> | |
| <button onclick="closeCacheViewer()" | |
| class="inline-flex items-center justify-center rounded-md text-xs font-medium border border-input bg-background hover:bg-accent h-8 px-3 transition-colors">关闭</button> | |
| </div> | |
| <div id="cacheViewerBody" class="bg-black flex items-center justify-center p-4"></div> | |
| </div> | |
| </div> | |
| <script> | |
| </script> | |
| </body> | |
| </html> | |