@wendongfly/myhi 1.0.52 → 1.0.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html CHANGED
@@ -415,6 +415,7 @@
415
415
  <div class="logo">my<span>hi</span></div>
416
416
  <div style="display:flex;align-items:center;gap:0.6rem">
417
417
  <span id="user-name" style="font-size:0.8rem;color:var(--muted)"></span>
418
+ <button id="usage-btn" onclick="showUsage()" style="background:none;border:1px solid var(--border);color:var(--muted);font-size:0.75rem;padding:0.3rem 0.6rem;border-radius:6px;cursor:pointer;width:auto">用量</button>
418
419
  <button id="logout-btn" onclick="doLogout()" style="display:none;background:none;border:1px solid var(--border);color:var(--muted);font-size:0.75rem;padding:0.3rem 0.6rem;border-radius:6px;cursor:pointer;width:auto">退出</button>
419
420
  <div id="conn-dot"></div>
420
421
  </div>
@@ -524,6 +525,85 @@
524
525
  }
525
526
  }).catch(() => {});
526
527
 
528
+ async function showUsage() {
529
+ try {
530
+ const res = await fetch('/api/usage');
531
+ const data = await res.json();
532
+ let html = '<div style="padding:1.25rem;max-width:500px">';
533
+ html += '<h3 style="margin:0 0 1rem;font-size:1rem">Claude 用量统计</h3>';
534
+
535
+ // 5小时限额
536
+ if (data.rateLimit) {
537
+ const rl = data.rateLimit;
538
+ const resetTime = new Date(rl.resetsAt * 1000);
539
+ const remaining = Math.max(0, Math.ceil((resetTime - Date.now()) / 60000));
540
+ html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
541
+ html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">5小时窗口</div>';
542
+ html += `<div style="font-size:0.8rem;color:var(--muted)">状态: ${rl.status === 'allowed' ? '✓ 正常' : '⚠ 受限'}</div>`;
543
+ html += `<div style="font-size:0.8rem;color:var(--muted)">重置时间: ${remaining} 分钟后</div>`;
544
+ html += '</div>';
545
+ } else {
546
+ html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
547
+ html += '<div style="font-size:0.85rem;color:var(--muted)">5小时窗口: 发送一条 Agent 消息后可查看</div></div>';
548
+ }
549
+
550
+ // 7天用量
551
+ if (data.sevenDay) {
552
+ const s = data.sevenDay;
553
+ html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
554
+ html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">近7天</div>';
555
+ html += `<div style="font-size:0.8rem;color:var(--muted)">消息: ${s.messageCount.toLocaleString()}</div>`;
556
+ html += `<div style="font-size:0.8rem;color:var(--muted)">会话: ${s.sessionCount}</div>`;
557
+ html += `<div style="font-size:0.8rem;color:var(--muted)">工具调用: ${s.toolCallCount.toLocaleString()}</div>`;
558
+ html += '</div>';
559
+ }
560
+
561
+ // 活跃会话用量
562
+ if (data.activeSessions?.length) {
563
+ html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
564
+ html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">当前会话</div>';
565
+ for (const s of data.activeSessions) {
566
+ if (!s.usage) continue;
567
+ const u = s.usage;
568
+ html += `<div style="font-size:0.8rem;color:var(--muted);margin-top:0.3rem">${s.title}: ${u.queryCount}次查询, $${u.totalCostUSD.toFixed(4)}</div>`;
569
+ }
570
+ html += '</div>';
571
+ }
572
+
573
+ // 累计总量
574
+ if (data.totalStats) {
575
+ const t = data.totalStats;
576
+ html += '<div style="padding:0.8rem;background:var(--bg);border-radius:8px">';
577
+ html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">累计(截至 ' + (t.lastComputedDate || '未知') + ')</div>';
578
+ html += `<div style="font-size:0.8rem;color:var(--muted)">总会话: ${t.totalSessions}</div>`;
579
+ html += `<div style="font-size:0.8rem;color:var(--muted)">总消息: ${t.totalMessages?.toLocaleString()}</div>`;
580
+ if (t.modelUsage) {
581
+ for (const [model, u] of Object.entries(t.modelUsage)) {
582
+ if (u.outputTokens > 0) {
583
+ const shortName = model.replace(/claude-/, '').replace(/-\d{8}$/, '');
584
+ html += `<div style="font-size:0.75rem;color:var(--muted);margin-top:0.2rem">${shortName}: 输入${(u.inputTokens/1000).toFixed(0)}K 输出${(u.outputTokens/1000).toFixed(0)}K</div>`;
585
+ }
586
+ }
587
+ }
588
+ html += '</div>';
589
+ }
590
+
591
+ html += '<button onclick="this.parentElement.parentElement.remove()" style="margin-top:1rem;width:100%;padding:0.6rem;background:var(--accent);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:0.85rem">关闭</button>';
592
+ html += '</div>';
593
+
594
+ const overlay = document.createElement('div');
595
+ overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:999;display:flex;align-items:center;justify-content:center';
596
+ overlay.onclick = (e) => { if (e.target === overlay) overlay.remove(); };
597
+ const box = document.createElement('div');
598
+ box.style.cssText = 'background:var(--surface);border-radius:16px;max-height:80vh;overflow-y:auto;width:90%;max-width:400px';
599
+ box.innerHTML = html;
600
+ overlay.appendChild(box);
601
+ document.body.appendChild(overlay);
602
+ } catch (err) {
603
+ alert('获取用量失败: ' + err.message);
604
+ }
605
+ }
606
+
527
607
  function doLogout() {
528
608
  if (!confirm('确定退出登录?当前所有会话将被关闭。')) return;
529
609
  fetch('/logout', { method: 'POST' }).then(() => { location.href = '/login'; });