134 lines
12 KiB
HTML
134 lines
12 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<base href="/v0/resource/plugins/billing/">
|
||
<title>CPA</title>
|
||
<link rel="stylesheet" href="./styles/base.css">
|
||
<link rel="stylesheet" href="./styles/layout.css">
|
||
<link rel="stylesheet" href="./styles/keys.css">
|
||
<link rel="stylesheet" href="./styles/usage.css">
|
||
<link rel="stylesheet" href="./styles/pricing.css">
|
||
<link rel="stylesheet" href="./styles/responsive.css">
|
||
</head>
|
||
<body class="read-only">
|
||
<div class="app-shell">
|
||
<header class="workspace-bar">
|
||
<nav class="workspace-nav" aria-label="工作区">
|
||
<button class="nav-button active" type="button" data-view="stats">统计</button>
|
||
<button class="nav-button" type="button" data-view="usage">请求</button>
|
||
<button class="nav-button" type="button" data-view="pricing">模型</button>
|
||
<button class="nav-button" type="button" data-view="logs">日志</button>
|
||
<button class="nav-button admin-only" type="button" data-view="users">用户</button>
|
||
</nav>
|
||
<div class="topbar-actions">
|
||
<div id="demo-perspective" class="demo-perspective hidden" aria-label="演示视角">
|
||
<button type="button" data-perspective="admin">管理员示教</button>
|
||
<button type="button" data-perspective="user">普通用户视角</button>
|
||
</div>
|
||
<div class="auth-box"><input id="key" type="password" autocomplete="off" aria-label="管理密钥"></div>
|
||
</div>
|
||
</header>
|
||
<main>
|
||
<section id="view-stats" class="view active">
|
||
<div class="chart-grid">
|
||
<article class="chart-card"><div id="user-usage" class="user-usage"></div></article>
|
||
<article class="chart-card"><div id="quota-chart" class="quota-matrix-wrap"></div></article>
|
||
</div>
|
||
<div class="stats-insight-grid">
|
||
<article class="chart-card insight-card"><header><h2>额度健康</h2></header><div id="quota-health"></div></article>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="view-users" class="view admin-only">
|
||
<div id="key-management" class="user-management">
|
||
<div class="user-management-header">
|
||
<p id="key-status" class="status"></p>
|
||
<div class="user-management-actions">
|
||
<button id="reset-all-billing" type="button">重置所有</button>
|
||
<button id="create-key" class="primary" type="button">创建 Key</button>
|
||
</div>
|
||
</div>
|
||
<div id="key-rows" class="user-card-grid"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="view-usage" class="view">
|
||
<div class="section-heading"><div><div id="page-buttons" class="page-buttons admin-only"></div><span id="status" class="status"></span></div><div class="tools">
|
||
<details id="usage-filter-panel" class="usage-filter-panel admin-only"><summary>查询过滤</summary><div class="surface usage-filters">
|
||
<label class="usage-filter">开始时间<input id="usage-from" type="datetime-local" step="1"></label>
|
||
<label class="usage-filter">结束时间<input id="usage-to" type="datetime-local" step="1"></label>
|
||
<label class="usage-filter">用户<select id="usage-key"><option value="">全部用户</option></select></label>
|
||
<label class="usage-filter">模型<input id="usage-model" list="usage-model-options" placeholder="全部模型"><datalist id="usage-model-options"></datalist></label>
|
||
<label class="usage-filter">结果<select id="usage-result"><option value="">全部结果</option><option value="succeeded">成功</option><option value="failed">失败</option><option value="rejected">已拒绝</option><option value="canceled">已取消</option></select></label>
|
||
<label class="usage-filter">上游<select id="usage-auth"><option value="">全部上游</option></select></label>
|
||
<label class="usage-filter">端点<select id="usage-endpoint"><option value="">全部端点</option><option value="responses">responses</option><option value="compact">compact</option><option value="chat">chat</option></select></label>
|
||
<label class="usage-filter request-filter">请求 ID<input id="usage-request-id" placeholder="粘贴完整 Request ID"></label>
|
||
<div class="usage-filter-actions"><button id="clear-usage-filters" type="button">清空</button><button id="apply-usage-filters" class="primary" type="button">查询</button></div>
|
||
</div></details>
|
||
<details class="admin-only"><summary>列</summary><div id="column-options" class="column-options"></div></details><button id="refresh" class="admin-only" type="button">刷新</button>
|
||
</div></div>
|
||
<div class="surface"><div class="table-wrap"><table><thead><tr id="headers"></tr></thead><tbody id="rows"></tbody></table></div></div>
|
||
</section>
|
||
|
||
<section id="view-pricing" class="view">
|
||
<div class="surface price-panel price-layout">
|
||
<aside class="price-sidebar"><div class="price-sidebar-header admin-only"><div><h2>已配置模型</h2><div id="price-status" class="status"></div></div><button id="new-price" class="small" type="button">新增</button></div><div id="price-list" class="price-list"></div></aside>
|
||
<section class="price-editor">
|
||
<div id="price-editor-content" class="hidden">
|
||
<div class="price-editor-header"><h2>模型价格</h2></div>
|
||
<div class="price-section"><label class="field price-model-field">模型名称<input id="price-model" placeholder="gpt-5.6-sol"></label><div id="price-source" class="price-source">手动配置</div></div>
|
||
<div class="price-section admin-only"><div class="price-section-header"><h3>models.dev 参考价格</h3><button id="refresh-catalog" class="small" type="button">更新目录</button></div><div id="catalog-summary" class="catalog-summary"></div><div class="catalog-toolbar"><input id="catalog-query" placeholder="搜索模型或供应商"><button id="search-catalog" class="small" type="button">搜索</button></div><div id="catalog-results" class="catalog-results"></div></div>
|
||
<div class="price-section"><div class="price-section-header"><h3>基础价格 · $ / 1M Token</h3></div><div class="price-grid">
|
||
<label>输入<input id="price-input" inputmode="decimal"></label><label>缓存读取<input id="price-cache-read" inputmode="decimal"></label><label>缓存写入<input id="price-cache-write" inputmode="decimal"></label><label>输出<input id="price-output" inputmode="decimal"></label>
|
||
</div></div>
|
||
<div id="long-price-section" class="price-section hidden"><div class="price-section-header"><h3>长上下文价格</h3><label class="inline-check"><input id="long-enabled" type="checkbox">启用</label></div><div class="price-grid long-grid">
|
||
<label class="long-field hidden">输入门槛<input id="long-threshold" type="number" min="0" step="1"></label><label class="long-field hidden">门槛比较<select id="long-comparison"><option value="gt">大于</option><option value="gte">大于等于</option></select></label><label class="long-field hidden">输入<input id="long-input" inputmode="decimal"></label><label class="long-field hidden">缓存读取<input id="long-cache-read" inputmode="decimal"></label><label class="long-field hidden">缓存写入<input id="long-cache-write" inputmode="decimal"></label><label class="long-field hidden">输出<input id="long-output" inputmode="decimal"></label>
|
||
</div></div>
|
||
<div class="price-section"><div class="price-section-header"><h3>Fast 价格</h3></div><div class="fast-row"><label class="inline-check"><input id="fast-pricing-enabled" type="checkbox">使用倍率计价</label><label class="field">倍率<input id="fast-multiplier" inputmode="decimal" value="2.5"></label></div></div>
|
||
<div class="price-actions admin-only"><button id="delete-price" class="danger hidden" type="button">删除</button><button id="clear-price" type="button">清空</button><button id="save-price" class="primary" type="button">保存价格</button></div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="view-logs" class="view">
|
||
<div class="surface"><div class="table-wrap"><table class="event-table"><thead><tr><th class="left">时间</th><th class="left">事件</th><th class="left">状态</th></tr></thead><tbody id="event-rows"></tbody></table></div></div>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
|
||
<div id="drawer-overlay" class="drawer-overlay hidden"></div>
|
||
<aside id="key-drawer" class="drawer hidden" aria-hidden="true">
|
||
<div class="drawer-header"><div><h2 id="drawer-title">管理 Key</h2><p id="drawer-subtitle">修改用户状态、路由和模型权限</p></div><button id="close-drawer" class="icon-button" type="button" aria-label="关闭">×</button></div>
|
||
<div class="drawer-body">
|
||
<div id="key-editor" class="drawer-form">
|
||
<div class="drawer-section"><h3>用户</h3><label class="field">名称<input id="editor-name" placeholder="例如 alice"></label>
|
||
<label class="field">完整 Key<input id="editor-secret" class="secret" minlength="6" maxlength="256" placeholder="留空自动生成"></label>
|
||
<label class="inline-check"><input id="editor-show-stats" type="checkbox" checked>在统计页显示该用户</label></div>
|
||
<div id="managed-fields" class="drawer-form">
|
||
<div class="drawer-section"><h3>访问与路由</h3>
|
||
<div class="field-row"><label class="field">状态<select id="editor-status"><option value="active">启用</option><option value="disabled">禁用</option><option value="archived">已归档</option></select></label><label class="field">路由<select id="editor-route"><option value="auto">自由选择</option><option value="strict">指定账号</option></select></label></div>
|
||
<label class="field">上游账号<select id="editor-upstream"></select></label>
|
||
<label class="inline-check"><input id="editor-all-models" type="checkbox">允许全部模型</label>
|
||
<label class="field">允许模型规则<input id="editor-models" placeholder="deepseek-*,gpt-5.6-sol"></label><p class="field-hint">多个规则用逗号分隔;* 匹配任意字符,未匹配的模型会被拒绝。</p></div>
|
||
<div class="drawer-section"><h3>额度与周期</h3>
|
||
<div id="billing-preview" class="billing-preview"><div><span>额度</span><strong id="billing-quota-view">$0.0000</strong></div><div><span>已用</span><strong id="billing-spent-view">$0.0000</strong></div><div><span>余额</span><strong id="billing-balance-view">$0.0000</strong></div></div>
|
||
<div class="field-row"><label class="field">本周期额度(USD)<input id="editor-quota" inputmode="decimal" value="0"></label><label class="field">并发上限<input id="editor-concurrency" type="number" min="1" max="64" step="1" value="4"></label></div>
|
||
<div class="field-row"><label class="field">自动重置<select id="editor-reset-period"><option value="none">不重置</option><option value="daily">每天</option><option value="weekly">每周</option><option value="monthly">每月</option></select></label><label class="field">下次重置时间<input id="editor-next-reset" type="datetime-local" step="1"></label></div>
|
||
<p class="field-hint">请求结束后按实际费用扣款;最后一个并发请求可能产生负余额。</p>
|
||
<div class="billing-tools"><span id="billing-status" class="status"></span><button id="reset-billing" class="small" type="button">立即重置额度</button></div>
|
||
</div>
|
||
<div id="ledger-section" class="drawer-section"><h3>最近账目</h3><div id="billing-ledger" class="ledger-list"></div></div>
|
||
</div>
|
||
</div>
|
||
<div id="key-stats" class="hidden"><div id="stats-grid" class="stats-grid"></div><h3>最近请求</h3><div id="stats-recent" class="recent-list"></div></div>
|
||
</div>
|
||
<div id="editor-footer" class="drawer-footer"><button id="archive-key" class="danger hidden" type="button">永久归档</button><div><button id="cancel-editor" type="button">取消</button><button id="save-key" class="primary" type="button">保存</button></div></div>
|
||
</aside>
|
||
<script src="./ui-config.js"></script>
|
||
<script type="module" src="./app/main.js"></script>
|
||
</body>
|
||
</html>
|