admin-panel.html 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>DoTouch.AI 管理后台</title>
  7. <link rel="stylesheet" href="../web-v1.1.0/style.css">
  8. <style>
  9. .console { display:flex; min-height:100vh; }
  10. .sidebar { width:236px; flex-shrink:0; background:var(--card); border-right:1px solid var(--border); padding:20px 14px; position:sticky; top:0; height:100vh; display:flex; flex-direction:column; }
  11. .sidebar .logo { padding:0 10px 18px; border-bottom:1px solid var(--border); }
  12. .sidebar .logo svg { height:34px; }
  13. .side-nav { margin-top:14px; flex:1; }
  14. .side-nav a { display:flex; align-items:center; gap:10px; padding:11px 12px; border-radius:10px; color:var(--muted); font-size:14px; margin-bottom:4px; cursor:pointer; }
  15. .side-nav a:hover { color:var(--text); background:rgba(124,92,255,.08); }
  16. .side-nav a.active { color:var(--text); background:rgba(124,92,255,.15); font-weight:600; }
  17. .side-nav a .ico { width:20px; text-align:center; }
  18. .side-user { border-top:1px solid var(--border); padding:14px 12px 6px; }
  19. .side-user .name { font-size:13px; font-weight:700; }
  20. .side-user .role-tag { display:inline-block; font-size:10.5px; color:var(--gold); background:rgba(255,194,77,.1); border:1px solid rgba(255,194,77,.3); padding:1px 8px; border-radius:999px; margin-top:4px; }
  21. .main { flex:1; min-width:0; padding:26px 32px 60px; }
  22. .main-head { display:flex; justify-content:space-between; align-items:center; margin-bottom:24px; flex-wrap:wrap; gap:12px; }
  23. .main-head h1 { font-size:22px; font-weight:800; }
  24. .main-head .sub { color:var(--muted); font-size:13px; margin-top:3px; }
  25. .tab-panel { display:none; }
  26. .tab-panel.active { display:block; }
  27. .stat-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:16px; }
  28. .stat-card { background:var(--card); border:1px solid var(--border); border-radius:14px; padding:20px; }
  29. .stat-card .lbl { font-size:12px; color:var(--muted); }
  30. .stat-card .val { font-size:26px; font-weight:800; margin-top:6px; }
  31. .stat-card .val.green { color:var(--green-l); }
  32. .stat-card .val.purple { color:var(--purple-l); }
  33. .stat-card .val.gold { color:var(--gold); }
  34. .stat-card .sub2 { font-size:11.5px; color:var(--muted); margin-top:4px; }
  35. .bar-chart { display:flex; align-items:flex-end; gap:10px; height:130px; padding:14px 6px 0; }
  36. .bar-col { flex:1; display:flex; flex-direction:column; align-items:center; gap:6px; }
  37. .bar { width:70%; max-width:34px; border-radius:6px 6px 2px 2px; background:linear-gradient(180deg,var(--green),rgba(0,229,160,.25)); min-height:6px; }
  38. .bar-lbl { font-size:10.5px; color:var(--muted); }
  39. .sec-title { font-size:15px; font-weight:700; margin:26px 0 12px; display:flex; justify-content:space-between; align-items:center; }
  40. .sec-title a { font-size:12.5px; color:var(--purple-l); }
  41. .filter-bar { display:flex; gap:10px; flex-wrap:wrap; align-items:center; margin-bottom:16px; }
  42. .search-box { flex:1; min-width:200px; background:var(--card); border:1px solid var(--border); border-radius:10px; padding:10px 16px; color:var(--text); font-size:13.5px; font-family:inherit; outline:none; }
  43. .search-box:focus { border-color:var(--purple); }
  44. .filter-tag { border:1px solid var(--border); background:var(--card); color:var(--muted); border-radius:999px; padding:7px 15px; font-size:12.5px; cursor:pointer; font-family:inherit; }
  45. .filter-tag.active { border-color:var(--purple); color:#fff; background:rgba(124,92,255,.2); }
  46. .op-btn { font-size:12px; padding:4px 10px; border-radius:7px; border:1px solid var(--border); background:var(--card2); color:var(--muted); cursor:pointer; margin-right:6px; font-family:inherit; }
  47. .op-btn:hover { color:var(--text); border-color:var(--purple); }
  48. .op-btn.danger:hover { border-color:#FF6B6B; color:#FF8A8A; }
  49. .status-badge { font-size:11px; padding:2px 10px; border-radius:999px; white-space:nowrap; }
  50. .status-badge.active { color:var(--green-l); background:rgba(0,229,160,.1); border:1px solid rgba(0,229,160,.3); }
  51. .status-badge.disabled { color:var(--muted); background:rgba(154,163,192,.1); border:1px solid rgba(154,163,192,.3); }
  52. .status-badge.pending { color:var(--gold); background:rgba(255,194,77,.1); border:1px solid rgba(255,194,77,.3); }
  53. .pager { display:flex; justify-content:flex-end; gap:8px; margin-top:14px; align-items:center; font-size:12.5px; color:var(--muted); }
  54. .pager button { background:var(--card); border:1px solid var(--border); color:var(--text); padding:6px 12px; border-radius:8px; cursor:pointer; font-family:inherit; }
  55. .setting-row { display:flex; justify-content:space-between; align-items:center; padding:15px 18px; border-bottom:1px solid var(--border); font-size:13.5px; flex-wrap:wrap; gap:8px; }
  56. .setting-row:last-child { border-bottom:none; }
  57. .setting-row .desc { color:var(--muted); font-size:12px; margin-top:3px; }
  58. .setting-row input, .setting-row select { background:var(--card2); border:1px solid var(--border); border-radius:8px; padding:8px 12px; color:var(--text); font-family:inherit; font-size:13px; outline:none; }
  59. .switch { position:relative; width:42px; height:24px; flex-shrink:0; }
  60. .switch input { opacity:0; width:0; height:0; }
  61. .switch .sl { position:absolute; inset:0; background:var(--card2); border:1px solid var(--border); border-radius:999px; cursor:pointer; transition:.2s; }
  62. .switch .sl::before { content:""; position:absolute; width:18px; height:18px; border-radius:50%; background:var(--muted); top:2px; left:2px; transition:.2s; }
  63. .switch input:checked + .sl { background:var(--purple); border-color:var(--purple); }
  64. .switch input:checked + .sl::before { transform:translateX(18px); background:#fff; }
  65. .batch-bar { display:flex; gap:10px; align-items:center; background:rgba(124,92,255,.07); border:1px solid rgba(124,92,255,.25); border-radius:12px; padding:12px 16px; margin-bottom:16px; font-size:13px; }
  66. @media (max-width:860px){ .console{flex-direction:column;} .sidebar{width:100%;height:auto;position:static;} .main{padding:20px;} }
  67. </style>
  68. </head>
  69. <body>
  70. <div class="dev-note">v1.0.0 · 平台管理后台审阅稿 · 对接 /v1/admin/stats · /v1/admin/users · /v1/admin/models</div>
  71. <div class="console">
  72. <aside class="sidebar">
  73. <div class="logo">
  74. <svg viewBox="0 0 460 120" xmlns="http://www.w3.org/2000/svg">
  75. <defs><linearGradient id="ag" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#9B7BFF"/><stop offset="1" stop-color="#5C3DF0"/></linearGradient></defs>
  76. <g transform="translate(0,6) scale(0.92)"><circle cx="50" cy="50" r="33" stroke="rgba(124,92,255,.3)" stroke-width="1.5" stroke-dasharray="2 7" fill="none"/><g stroke="#00E5A0" stroke-width="1.8" opacity=".55"><line x1="50" y1="50" x2="76" y2="26"/><line x1="50" y1="50" x2="26" y2="76"/><line x1="50" y1="50" x2="78" y2="75"/></g><circle cx="50" cy="50" r="7.5" fill="url(#ag)"/><circle cx="76" cy="26" r="4" fill="#00E5A0"/><circle cx="26" cy="76" r="4" fill="#00E5A0"/><circle cx="78" cy="75" r="4" fill="#00E5A0"/></g>
  77. <text x="128" y="78" font-size="50" font-weight="700" fill="#E8ECF8" font-family="inherit">DoTouch</text><text x="348" y="78" font-size="50" font-weight="700" fill="url(#ag)" font-family="inherit">.AI</text>
  78. </svg>
  79. </div>
  80. <nav class="side-nav">
  81. <a class="active" data-tab="overview"><span class="ico">📊</span>运营概览</a>
  82. <a data-tab="users"><span class="ico">👥</span>用户管理</a>
  83. <a data-tab="models"><span class="ico">🧠</span>模型管理</a>
  84. <a data-tab="orders"><span class="ico">💸</span>交易流水</a>
  85. <a data-tab="quotas"><span class="ico">🚦</span>限额管理</a>
  86. <a data-tab="settings"><span class="ico">⚙️</span>系统设置</a>
  87. </nav>
  88. <div class="side-user">
  89. <div class="name">平台管理员</div>
  90. <span class="role-tag">ADMIN</span>
  91. </div>
  92. </aside>
  93. <main class="main">
  94. <div class="main-head">
  95. <div>
  96. <h1>运营概览</h1>
  97. <div class="sub">DoTouch.AI 平台数据 · 2026-08-08</div>
  98. </div>
  99. <a class="btn btn-primary btn-sm" href="../web-v1.1.0/index.html" style="font-size:12.5px;">← 返回官网</a>
  100. </div>
  101. <!-- ══ Tab 1: 概览 ══ -->
  102. <div class="tab-panel active" id="tab-overview">
  103. <div class="stat-grid">
  104. <div class="stat-card"><div class="lbl">注册用户</div><div class="val purple">1,284</div><div class="sub2">今日 +37</div></div>
  105. <div class="stat-card"><div class="lbl">总收入(累计充值)</div><div class="val green"><span class="price-usd" data-usd="8642.50">$8,642.50</span></div><div class="sub2">本月 <span class="price-usd" data-usd="1290">$1,290</span></div></div>
  106. <div class="stat-card"><div class="lbl">总 Token 消耗</div><div class="val">128.4M</div><div class="sub2">今日 4.2M</div></div>
  107. <div class="stat-card"><div class="lbl">今日请求</div><div class="val">32,118</div><div class="sub2">成功率 99.2%</div></div>
  108. </div>
  109. <div class="sec-title">收入趋势(近 30 天)</div>
  110. <div class="card">
  111. <div class="bar-chart">
  112. <div class="bar-col"><div class="bar" style="height:20%"></div><span class="bar-lbl">7/10</span></div>
  113. <div class="bar-col"><div class="bar" style="height:32%"></div><span class="bar-lbl">7/15</span></div>
  114. <div class="bar-col"><div class="bar" style="height:28%"></div><span class="bar-lbl">7/20</span></div>
  115. <div class="bar-col"><div class="bar" style="height:45%"></div><span class="bar-lbl">7/25</span></div>
  116. <div class="bar-col"><div class="bar" style="height:38%"></div><span class="bar-lbl">7/30</span></div>
  117. <div class="bar-col"><div class="bar" style="height:62%"></div><span class="bar-lbl">8/04</span></div>
  118. <div class="bar-col"><div class="bar" style="height:78%"></div><span class="bar-lbl">8/08</span></div>
  119. </div>
  120. </div>
  121. <div class="sec-title">最近注册</div>
  122. <div class="table-wrap">
  123. <table class="data">
  124. <thead><tr><th>邮箱</th><th>注册时间</th><th>充值</th><th>状态</th></tr></thead>
  125. <tbody>
  126. <tr><td class="price">tran.bao@example.com</td><td style="color:var(--muted);">2026-08-08 03:12</td><td class="price"><span class="price-usd" data-usd="5">$5.00</span></td><td><span class="status-badge active">active</span></td></tr>
  127. <tr><td class="price">le.minh@example.com</td><td style="color:var(--muted);">2026-08-08 02:58</td><td class="price">—</td><td><span class="status-badge active">active</span></td></tr>
  128. <tr><td class="price">phan.thu@example.com</td><td style="color:var(--muted);">2026-08-08 02:41</td><td class="price"><span class="price-usd" data-usd="10">$10.00</span></td><td><span class="status-badge active">active</span></td></tr>
  129. </tbody>
  130. </table>
  131. </div>
  132. <div class="sec-title">今日交易</div>
  133. <div class="table-wrap">
  134. <table class="data">
  135. <thead><tr><th>时间</th><th>用户</th><th>类型</th><th>金额</th><th>渠道</th></tr></thead>
  136. <tbody>
  137. <tr><td style="color:var(--muted);">03:12</td><td class="price">tran.bao@…</td><td><span class="tag tag-purple">deposit</span></td><td class="price">+<span class="price-usd" data-usd="5">$5.00</span></td><td>MoMo</td></tr>
  138. <tr><td style="color:var(--muted);">02:41</td><td class="price">phan.thu@…</td><td><span class="tag tag-purple">deposit</span></td><td class="price">+<span class="price-usd" data-usd="10">$10.00</span></td><td>ZaloPay</td></tr>
  139. <tr><td style="color:var(--muted);">02:30</td><td class="price">nguyen.anh@…</td><td><span class="tag tag-green">usage</span></td><td class="price">-<span class="price-usd" data-usd="0.0032">$0.0032</span></td><td>—</td></tr>
  140. </tbody>
  141. </table>
  142. </div>
  143. </div>
  144. <!-- ══ Tab 2: 用户管理 ══ -->
  145. <div class="tab-panel" id="tab-users">
  146. <div class="filter-bar">
  147. <input class="search-box" type="text" placeholder="搜索邮箱 / 用户 ID...">
  148. <button class="filter-tag active">全部</button>
  149. <button class="filter-tag">活跃</button>
  150. <button class="filter-tag">已封禁</button>
  151. <button class="filter-tag">管理员</button>
  152. </div>
  153. <div class="table-wrap">
  154. <table class="data">
  155. <thead><tr><th>ID</th><th>邮箱</th><th>角色</th><th>状态</th><th>余额</th><th>注册时间</th><th>操作</th></tr></thead>
  156. <tbody>
  157. <tr><td class="price">cmsjc9029</td><td class="price">test@example.com</td><td><span class="role-tag" style="color:var(--gold);">admin</span></td><td><span class="status-badge active">active</span></td><td class="price"><span class="price-usd" data-usd="23.5">$23.50</span></td><td style="color:var(--muted);">2026-08-08</td><td><button class="op-btn">封禁</button><button class="op-btn danger">降级</button></td></tr>
  158. <tr><td class="price">cmsjd1044</td><td class="price">tran.bao@example.com</td><td><span class="tag tag-gray">user</span></td><td><span class="status-badge active">active</span></td><td class="price"><span class="price-usd" data-usd="5">$5.00</span></td><td style="color:var(--muted);">2026-08-08</td><td><button class="op-btn">封禁</button><button class="op-btn">提权</button></td></tr>
  159. <tr><td class="price">cmsje2201</td><td class="price">le.minh@example.com</td><td><span class="tag tag-gray">user</span></td><td><span class="status-badge active">active</span></td><td class="price">$0.00</td><td style="color:var(--muted);">2026-08-08</td><td><button class="op-btn">封禁</button><button class="op-btn">提权</button></td></tr>
  160. <tr><td class="price">cmsjf5517</td><td class="price">spam@example.com</td><td><span class="tag tag-gray">user</span></td><td><span class="status-badge disabled">banned</span></td><td class="price">$0.00</td><td style="color:var(--muted);">2026-08-01</td><td><button class="op-btn">解封</button></td></tr>
  161. </tbody>
  162. </table>
  163. </div>
  164. <div class="pager"><span>第 1 / 257 页</span><button>‹</button><button>›</button></div>
  165. </div>
  166. <!-- ══ Tab 3: 模型管理 ══ -->
  167. <div class="tab-panel" id="tab-models">
  168. <div class="batch-bar">
  169. <b>批量工具:</b>
  170. <button class="op-btn" style="border-color:rgba(0,229,160,.4);color:var(--green-l);">按上游价 × 0.7 批量定价</button>
  171. <button class="op-btn" style="border-color:rgba(255,194,77,.4);color:var(--gold);">一键上架全部</button>
  172. <span style="color:var(--muted);font-size:12px;">共 236 个模型 · 推荐 11 · 待定价 225</span>
  173. </div>
  174. <div class="filter-bar">
  175. <input class="search-box" type="text" placeholder="搜索模型 ID / 供应商...">
  176. <button class="filter-tag active" data-cat="all">全部 (236)</button>
  177. <button class="filter-tag" data-cat="chat">对话 (153)</button>
  178. <button class="filter-tag" data-cat="vision">视觉 (21)</button>
  179. <button class="filter-tag" data-cat="image">图像 (19)</button>
  180. <button class="filter-tag" data-cat="speech">语音 (43)</button>
  181. </div>
  182. <div class="table-wrap">
  183. <table class="data">
  184. <thead><tr><th>模型 ID</th><th>供应商</th><th>分类</th><th>上下文</th><th>输入 / 1M</th><th>输出 / 1M</th><th>状态</th><th>推荐</th><th>操作</th></tr></thead>
  185. <tbody>
  186. <tr><td><b>glm-5.2</b></td><td>Zhipu</td><td><span class="tag tag-purple">对话</span></td><td class="price">1M</td><td class="price"><span class="price-usd" data-usd="0.98">$0.98</span></td><td class="price"><span class="price-usd" data-usd="3.08">$3.08</span></td><td><span class="status-badge active">active</span></td><td>⭐</td><td><button class="op-btn">定价</button><button class="op-btn danger">下架</button></td></tr>
  187. <tr><td><b>deepseek-v4-flash</b></td><td>DeepSeek</td><td><span class="tag tag-green">对话</span></td><td class="price">1M</td><td class="price"><span class="price-usd" data-usd="0.14">$0.14</span></td><td class="price"><span class="price-usd" data-usd="0.28">$0.28</span></td><td><span class="status-badge active">active</span></td><td>⭐</td><td><button class="op-btn">定价</button><button class="op-btn danger">下架</button></td></tr>
  188. <tr><td><b>deepseek-v4-pro</b></td><td>DeepSeek</td><td><span class="tag tag-gold">对话</span></td><td class="price">1M</td><td class="price"><span class="price-usd" data-usd="0.42">$0.42</span></td><td class="price"><span class="price-usd" data-usd="0.84">$0.84</span></td><td><span class="status-badge active">active</span></td><td>⭐</td><td><button class="op-btn">定价</button><button class="op-btn danger">下架</button></td></tr>
  189. <tr><td><b>qwen3-max</b></td><td>Alibaba</td><td><span class="tag tag-purple">对话</span></td><td class="price">256K</td><td class="price"><span class="price-usd" data-usd="2.10">$2.10</span></td><td class="price"><span class="price-usd" data-usd="8.40">$8.40</span></td><td><span class="status-badge active">active</span></td><td>⭐</td><td><button class="op-btn">定价</button><button class="op-btn danger">下架</button></td></tr>
  190. <tr><td><b>kimi-k2.7-code</b></td><td>Moonshot</td><td><span class="tag tag-green">对话</span></td><td class="price">256K</td><td class="price"><span class="price-usd" data-usd="0.70">$0.70</span></td><td class="price"><span class="price-usd" data-usd="2.80">$2.80</span></td><td><span class="status-badge active">active</span></td><td>⭐</td><td><button class="op-btn">定价</button><button class="op-btn danger">下架</button></td></tr>
  191. <tr><td><b>qwen-image-3.0</b></td><td>Alibaba</td><td><span class="tag tag-purple">图像</span></td><td class="price">—</td><td class="price"><span class="price-usd" data-usd="0.14">$0.14</span>/张</td><td class="price">—</td><td><span class="status-badge pending">pending</span></td><td>—</td><td><button class="op-btn">定价</button><button class="op-btn">上架</button></td></tr>
  192. <tr><td><b>qwen-tts-2025-05-22</b></td><td>Alibaba</td><td><span class="tag tag-gray">语音</span></td><td class="price">—</td><td class="price"><span class="price-usd" data-usd="0.0014">$0.0014</span>/字符</td><td class="price">—</td><td><span class="status-badge pending">pending</span></td><td>—</td><td><button class="op-btn">定价</button><button class="op-btn">上架</button></td></tr>
  193. <tr><td><b>… 共 236 个模型(全量已入库,seed 幂等)</b></td><td colspan="8" style="color:var(--muted);font-size:12.5px;">完整清单见 GET /v1/admin/models · 同步上游 POST /v1/admin/models/sync(待接百炼 Key)</td></tr>
  194. </tbody>
  195. </table>
  196. </div>
  197. <div class="pager"><span>第 1 / 24 页</span><button>‹</button><button>›</button></div>
  198. </div>
  199. <!-- ══ Tab 4: 交易流水 ══ -->
  200. <div class="tab-panel" id="tab-orders">
  201. <div class="filter-bar">
  202. <input class="search-box" type="text" placeholder="搜索用户 / 参考 ID...">
  203. <button class="filter-tag active">全部</button>
  204. <button class="filter-tag">充值</button>
  205. <button class="filter-tag">用量扣费</button>
  206. <button class="filter-tag">退款</button>
  207. </div>
  208. <div class="table-wrap">
  209. <table class="data">
  210. <thead><tr><th>时间</th><th>用户</th><th>类型</th><th>金额</th><th>参考</th><th>渠道</th></tr></thead>
  211. <tbody>
  212. <tr><td style="color:var(--muted);">2026-08-08 03:12</td><td class="price">tran.bao@…</td><td><span class="tag tag-purple">deposit</span></td><td class="price">+<span class="price-usd" data-usd="5">$5.00</span></td><td class="price">stripe_pi_8f3k…</td><td>MoMo</td></tr>
  213. <tr><td style="color:var(--muted);">2026-08-08 02:41</td><td class="price">phan.thu@…</td><td><span class="tag tag-purple">deposit</span></td><td class="price">+<span class="price-usd" data-usd="10">$10.00</span></td><td class="price">zalopay_9x2m…</td><td>ZaloPay</td></tr>
  214. <tr><td style="color:var(--muted);">2026-08-08 02:30</td><td class="price">nguyen.anh@…</td><td><span class="tag tag-green">usage</span></td><td class="price">-<span class="price-usd" data-usd="0.0032">$0.0032</span></td><td class="price">req_glm52_88a1</td><td>—</td></tr>
  215. <tr><td style="color:var(--muted);">2026-08-07 22:30</td><td class="price">nguyen.anh@…</td><td><span class="tag tag-purple">deposit</span></td><td class="price">+<span class="price-usd" data-usd="20">$20.00</span></td><td class="price">stripe_pi_7d2k…</td><td>Stripe</td></tr>
  216. <tr><td style="color:var(--muted);">2026-08-07 18:02</td><td class="price">nguyen.anh@…</td><td><span class="tag tag-green">usage</span></td><td class="price">-<span class="price-usd" data-usd="0.0084">$0.0084</span></td><td class="price">req_qwen3_41c9</td><td>—</td></tr>
  217. </tbody>
  218. </table>
  219. </div>
  220. <div class="pager"><span>第 1 / 89 页</span><button>‹</button><button>›</button></div>
  221. </div>
  222. <!-- ══ Tab 6: 限额管理 ══ -->
  223. <div class="tab-panel" id="tab-quotas">
  224. <div class="filter-bar">
  225. <input class="search-box" type="text" placeholder="搜索用户 / Key...">
  226. <button class="filter-tag active">全部</button>
  227. <button class="filter-tag" style="color:var(--gold);">超限</button>
  228. <button class="filter-tag" style="color:var(--green-l);">预警中</button>
  229. <button class="op-btn" style="border-color:rgba(124,92,255,.5);color:var(--purple-l);margin-left:auto;">+ 设置默认限额</button>
  230. </div>
  231. <div class="table-wrap">
  232. <table class="data">
  233. <thead><tr><th>对象</th><th>类型</th><th>每日限额 (请求/Token/费用)</th><th>当前用量</th><th>状态</th><th>操作</th></tr></thead>
  234. <tbody>
  235. <tr><td><b>test-e2e@dotouch.ai</b></td><td><span class="tag tag-purple">账号</span></td><td class="price">— / — / —</td><td class="price">1,284 req · 4.2M tokens · $3.85</td><td><span class="status-badge active">正常</span></td><td><button class="op-btn">配置</button></td></tr>
  236. <tr><td class="price">production (dt_8e75••••)</td><td><span class="tag tag-gray">API Key</span></td><td class="price">10,000 / 100M / $5</td><td class="price">6,420 req · 82M · $3.85</td><td><span class="status-badge pending">预警中 (82%)</span></td><td><button class="op-btn">配置</button></td></tr>
  237. <tr><td class="price">staging (dt_cb90••••)</td><td><span class="tag tag-gray">API Key</span></td><td class="price">10,000 / 100M / $5</td><td class="price">2,310 req · 30M · $1.10</td><td><span class="status-badge active">正常</span></td><td><button class="op-btn">配置</button></td></tr>
  238. <tr><td class="price">local-dev (dt_5f2a••••)</td><td><span class="tag tag-gray">API Key</span></td><td class="price">10,000 / 100M / $5</td><td class="price">10,000 req · 120M · $5.30</td><td><span class="status-badge disabled">超限 (429)</span></td><td><button class="op-btn">配置</button><button class="op-btn danger">解除</button></td></tr>
  239. </tbody>
  240. </table>
  241. </div>
  242. <div class="pager"><span>第 1 / 12 页</span><button>‹</button><button>›</button></div>
  243. <div class="sec-title">限额事件(QuotaEvent 审计)</div>
  244. <div class="table-wrap">
  245. <table class="data">
  246. <thead><tr><th>时间</th><th>对象</th><th>类型</th><th>维度</th><th>窗口</th><th>阈值/当前</th><th>动作</th></tr></thead>
  247. <tbody>
  248. <tr><td style="color:var(--muted);">2026-08-08 03:47</td><td class="price">local-dev (dt_5f2a••••)</td><td>Key</td><td>requests</td><td>daily</td><td class="price">10,000 / 10,000</td><td><span class="status-badge disabled">block</span></td></tr>
  249. <tr><td style="color:var(--muted);">2026-08-08 03:40</td><td class="price">production (dt_8e75••••)</td><td>Key</td><td>requests</td><td>daily</td><td class="price">10,000 / 8,000</td><td><span class="status-badge pending">alert</span></td></tr>
  250. <tr><td style="color:var(--muted);">2026-08-07 22:15</td><td class="price">staging (dt_cb90••••)</td><td>Key</td><td>cost</td><td>daily</td><td class="price">500¢ / 410¢</td><td><span class="status-badge pending">alert</span></td></tr>
  251. </tbody>
  252. </table>
  253. </div>
  254. <div class="notice" style="margin-top:14px;">💡 接口对接:GET /v1/admin/quotas(全局视图)· PUT /v1/admin/users/:id/limits / keys/:id/limits(覆盖)· GET /v1/admin/quota-events(审计)· 新用户默认不限(需求 v1.0)</div>
  255. </div>
  256. <!-- ══ Tab 5: 系统设置 ══ -->
  257. <div class="tab-panel" id="tab-settings">
  258. <div class="card" style="padding:0;overflow:hidden;margin-bottom:18px;">
  259. <div class="sec-title" style="padding:16px 18px 0;margin-top:0;">货币与汇率</div>
  260. <div class="setting-row"><div><b>美元 → 越南盾</b><div class="desc">充值结算汇率 · 接入实时汇率 API(TODO)</div></div><input type="text" value="25,400" style="width:110px;"></div>
  261. <div class="setting-row"><div><b>美元 → 人民币</b><div class="desc">展示汇率</div></div><input type="text" value="7.20" style="width:110px;"></div>
  262. <div class="setting-row"><div><b>实时汇率自动更新</b><div class="desc">接入第三方汇率 API 后启用</div></div><label class="switch"><input type="checkbox"><span class="sl"></span></label></div>
  263. </div>
  264. <div class="card" style="padding:0;overflow:hidden;margin-bottom:18px;">
  265. <div class="sec-title" style="padding:16px 18px 0;margin-top:0;">安全策略</div>
  266. <div class="setting-row"><div><b>邮箱验证码有效期</b><div class="desc">注册 / 重置密码验证码</div></div><input type="text" value="15 分钟" style="width:110px;"></div>
  267. <div class="setting-row"><div><b>验证码重发冷却</b></div><input type="text" value="60 秒" style="width:110px;"></div>
  268. <div class="setting-row"><div><b>登录失败锁定</b><div class="desc">5 次 / 15 分钟</div></div><input type="text" value="5 次" style="width:110px;"></div>
  269. <div class="setting-row"><div><b>API 限流</b><div class="desc">每 Key 每分钟请求数</div></div><input type="text" value="60" style="width:110px;"></div>
  270. <div class="setting-row"><div><b>JWT 过期时间</b></div><input type="text" value="7d" style="width:110px;"></div>
  271. </div>
  272. <div class="card" style="padding:0;overflow:hidden;margin-bottom:18px;">
  273. <div class="sec-title" style="padding:16px 18px 0;margin-top:0;">邮件服务(SMTP)</div>
  274. <div class="setting-row"><div><b>SMTP 主机</b><div class="desc">生产环境必填(当前为 stub,验证码打印到日志)</div></div><input type="text" placeholder="smtp.example.com" style="width:200px;"></div>
  275. <div class="setting-row"><div><b>发件人</b></div><input type="text" value="noreply@dotouch.ai" style="width:200px;"></div>
  276. <div class="setting-row"><div><b>SMTP 状态</b></div><span class="status-badge pending">未配置</span></div>
  277. </div>
  278. <div class="card" style="padding:0;overflow:hidden;margin-bottom:18px;">
  279. <div class="sec-title" style="padding:16px 18px 0;margin-top:0;">上游(阿里云百炼)</div>
  280. <div class="setting-row"><div><b>DASHSCOPE_API_KEY</b><div class="desc">当前为占位符,配置后启用 /admin/models/sync 自动同步</div></div><span class="status-badge pending">待配置</span></div>
  281. <div class="setting-row"><div><b>基础地址</b></div><input type="text" value="https://dashscope.aliyuncs.com/compatible-mode/v1" style="width:340px;"></div>
  282. </div>
  283. <div class="card" style="padding:0;overflow:hidden;">
  284. <div class="sec-title" style="padding:16px 18px 0;margin-top:0;">支付渠道</div>
  285. <div class="setting-row"><div><b>Stripe</b><div class="desc">国际卡 / PayPal</div></div><label class="switch"><input type="checkbox" checked><span class="sl"></span></label></div>
  286. <div class="setting-row"><div><b>MoMo</b><div class="desc">越南本地(需主体或聚合商)</div></div><label class="switch"><input type="checkbox" checked><span class="sl"></span></label></div>
  287. <div class="setting-row"><div><b>ZaloPay</b></div><label class="switch"><input type="checkbox" checked><span class="sl"></span></label></div>
  288. <div class="setting-row"><div><b>Alipay</b><div class="desc">国内用户</div></div><label class="switch"><input type="checkbox"><span class="sl"></span></label></div>
  289. </div>
  290. </div>
  291. </main>
  292. </div>
  293. <script src="../web-v1.1.0/i18n.js"></script>
  294. <script>
  295. document.querySelectorAll('.side-nav a').forEach(a => a.addEventListener('click', () => {
  296. document.querySelectorAll('.side-nav a').forEach(x => x.classList.remove('active'));
  297. document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
  298. a.classList.add('active');
  299. document.getElementById('tab-' + a.dataset.tab).classList.add('active');
  300. document.querySelector('.main-head h1').textContent = a.textContent.trim();
  301. }));
  302. document.querySelectorAll('.filter-tag').forEach(btn => btn.addEventListener('click', () => {
  303. btn.parentElement.querySelectorAll('.filter-tag').forEach(b => b.classList.remove('active'));
  304. btn.classList.add('active');
  305. }));
  306. </script>
  307. </body>
  308. </html>