@wendongfly/myhi 1.0.55 → 1.0.57

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.
Files changed (2) hide show
  1. package/dist/chat.html +48 -2
  2. package/package.json +1 -1
package/dist/chat.html CHANGED
@@ -215,6 +215,7 @@
215
215
  <button class="top-btn" onclick="goBack()" title="返回">
216
216
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
217
217
  </button>
218
+ <button class="top-btn" onclick="showUsage()" title="用量" style="font-size:0.7rem;color:var(--muted)">用量</button>
218
219
  <button class="top-btn" id="logout-btn" onclick="doLogout()" title="退出" style="display:none;color:#f0883e">
219
220
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
220
221
  </button>
@@ -335,6 +336,45 @@
335
336
  fetch('/api/me').then(r => r.json()).then(data => {
336
337
  if (data.exclusive || data.hasUsers) document.getElementById('logout-btn').style.display = '';
337
338
  }).catch(() => {});
339
+ window.showUsage = async () => {
340
+ try {
341
+ const res = await fetch('/api/usage');
342
+ const data = await res.json();
343
+ let html = '<div style="padding:1.25rem;max-width:500px">';
344
+ html += '<h3 style="margin:0 0 1rem;font-size:1rem">Claude 用量统计</h3>';
345
+ if (data.rateLimit) {
346
+ const rl = data.rateLimit;
347
+ const remaining = Math.max(0, Math.ceil((new Date(rl.resetsAt * 1000) - Date.now()) / 60000));
348
+ html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
349
+ html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">5小时窗口</div>';
350
+ html += `<div style="font-size:0.8rem;color:var(--muted)">状态: ${rl.status === 'allowed' ? '✓ 正常' : '⚠ 受限'} 重置: ${remaining}分钟后</div></div>`;
351
+ }
352
+ if (data.sevenDay) {
353
+ const s = data.sevenDay;
354
+ html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
355
+ html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">近7天</div>';
356
+ html += `<div style="font-size:0.8rem;color:var(--muted)">消息: ${s.messageCount.toLocaleString()} 会话: ${s.sessionCount} 工具: ${s.toolCallCount.toLocaleString()}</div></div>`;
357
+ }
358
+ if (data.activeSessions?.length) {
359
+ html += '<div style="margin-bottom:1rem;padding:0.8rem;background:var(--bg);border-radius:8px">';
360
+ html += '<div style="font-size:0.85rem;font-weight:600;margin-bottom:0.4rem">当前会话</div>';
361
+ for (const s of data.activeSessions) {
362
+ if (!s.usage) continue;
363
+ html += `<div style="font-size:0.8rem;color:var(--muted)">${s.title}: ${s.usage.queryCount}次, $${s.usage.totalCostUSD.toFixed(4)}</div>`;
364
+ }
365
+ html += '</div>';
366
+ }
367
+ html += '<button onclick="this.parentElement.parentElement.remove()" style="margin-top:0.5rem;width:100%;padding:0.6rem;background:var(--accent);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:0.85rem">关闭</button></div>';
368
+ const overlay = document.createElement('div');
369
+ 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';
370
+ overlay.onclick = (e) => { if (e.target === overlay) overlay.remove(); };
371
+ const box = document.createElement('div');
372
+ box.style.cssText = 'background:var(--surface);border-radius:16px;max-height:80vh;overflow-y:auto;width:90%;max-width:400px';
373
+ box.innerHTML = html;
374
+ overlay.appendChild(box);
375
+ document.body.appendChild(overlay);
376
+ } catch (err) { alert('获取用量失败: ' + err.message); }
377
+ };
338
378
  window.doLogout = () => {
339
379
  if (!confirm('确定退出登录?当前所有会话将被关闭。')) return;
340
380
  fetch('/logout', { method: 'POST' }).then(() => { location.href = '/login'; });
@@ -355,7 +395,10 @@
355
395
  cmdInput.style.height = 'auto';
356
396
  cmdInput.style.height = Math.min(cmdInput.scrollHeight, 120) + 'px';
357
397
  });
358
- cmdInput.addEventListener('focus', () => inputBox.classList.add('focused'));
398
+ cmdInput.addEventListener('focus', () => {
399
+ inputBox.classList.add('focused');
400
+ if (!isController && canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID });
401
+ });
359
402
  cmdInput.addEventListener('blur', () => inputBox.classList.remove('focused'));
360
403
 
361
404
  let currentSession = null;
@@ -1165,7 +1208,10 @@
1165
1208
  return;
1166
1209
  }
1167
1210
 
1168
- if (!isController) { addStatusMessage('请先获取控制权'); return; }
1211
+ if (!isController) {
1212
+ if (canTakeControl()) { socket.emit('take-control', { sessionId: SESSION_ID }); }
1213
+ else { addStatusMessage('其他用户控制中,无法发送'); return; }
1214
+ }
1169
1215
  endStream();
1170
1216
 
1171
1217
  const imgPath = _pendingImage?.path || null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wendongfly/myhi",
3
- "version": "1.0.55",
3
+ "version": "1.0.57",
4
4
  "description": "Web-based terminal sharing with chat UI — control your terminal from phone via LAN/Tailscale",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",