dsh-commandcode-usage 1.0.1 → 1.1.0
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/README.md +2 -0
- package/client.js +264 -131
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,9 @@ A CommandCode usage & balance panel for DeepSeek Harness — shows API usage, cr
|
|
|
10
10
|
|
|
11
11
|
- **CommandCode 用量**:请求次数、成功率、Token 消耗、总花费
|
|
12
12
|
- **信用额度**:月额度、5小时窗口、每周窗口,进度条可视化
|
|
13
|
+
- **⏱ 重置时间显示**:每个周期下方标明截止/重置时刻(「重置 今天/明天/N天后 HH:mm」),一眼知道额度何时刷新
|
|
13
14
|
- **余额与订阅**:套餐信息、订阅状态、计费周期
|
|
15
|
+
- **精致卡片 UI**:渐变 header + 套餐徽章、统计三卡、图标渐变动画进度条、彩色百分比胶囊(≥85% 红 / ≥60% 黄 / 其余绿)
|
|
14
16
|
- **主题自适应**:跟随 DSH 的浅色/深色主题自动切换
|
|
15
17
|
- **侧边栏入口**:在 codex-ui 侧边栏底部提供"⚡ 用量"按钮,点击弹出面板
|
|
16
18
|
|
package/client.js
CHANGED
|
@@ -1,103 +1,124 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* usage-panel 客户端半:在 codex-ui 侧边栏底部注入"⚡ 用量"按钮,
|
|
3
|
-
* 点击弹出 CommandCode
|
|
3
|
+
* 点击弹出 CommandCode 用量面板(精致卡片 UI)。
|
|
4
4
|
*
|
|
5
5
|
* 主题自适应:复用 codex-ui 的 body[data-ds-dark-theme] 机制 —— 面板自带
|
|
6
6
|
* 主题变量,浅色/深色自动切换。
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* 数据获取:/dsh-usage/report RPC(同源 HTTP POST,client-request 协议)
|
|
9
9
|
*/
|
|
10
10
|
window.__ModuleLoader__.load({
|
|
11
|
-
id: "
|
|
11
|
+
id: "@deepseek-ai/usage-panel",
|
|
12
12
|
factory: function (require) {
|
|
13
13
|
var module = { exports: {} };
|
|
14
14
|
var exports = module.exports;
|
|
15
15
|
|
|
16
|
-
var POLL_MS = 5 * 60 * 1000;
|
|
16
|
+
var POLL_MS = 5 * 60 * 1000;
|
|
17
17
|
var PANEL_CLS = "dsh-usage-panel";
|
|
18
18
|
var BTN_CLS = "dsh-usage-btn";
|
|
19
19
|
|
|
20
|
-
//
|
|
20
|
+
// ================= 主题样式 =================
|
|
21
21
|
var STYLE_ID = "dsh-usage-panel-style";
|
|
22
22
|
function injectStyles() {
|
|
23
23
|
if (document.getElementById(STYLE_ID)) return;
|
|
24
24
|
var css = [
|
|
25
|
-
// 主题变量
|
|
25
|
+
// ---------- 主题变量 ----------
|
|
26
26
|
"." + PANEL_CLS + "{",
|
|
27
|
-
" --up-bg:#ffffff;--up-fg:#
|
|
28
|
-
" --up-border:rgba(
|
|
29
|
-
" --up-
|
|
30
|
-
" --up-
|
|
31
|
-
" --up-
|
|
27
|
+
" --up-bg:#ffffff;--up-fg:#1d2421;--up-fg2:#5b6662;--up-fg3:#8fa09a;",
|
|
28
|
+
" --up-border:rgba(25,65,50,.10);--up-border2:rgba(25,65,50,.18);",
|
|
29
|
+
" --up-hover:#eef6f3;--up-card:#f6faf8;--up-card2:#ffffff;",
|
|
30
|
+
" --up-shadow:0 1px 2px rgba(16,50,40,.05),0 14px 36px rgba(16,50,40,.16);",
|
|
31
|
+
" --up-grad1:#0ea97a;--up-grad2:#14b8a6;--up-grad3:#0d9488;",
|
|
32
|
+
" --up-accent:#0d9f77;--up-accent-soft:rgba(13,159,119,.10);",
|
|
33
|
+
" --up-bar-bg:#e9f1ee;--up-warn:#eab308;--up-danger:#e5484d;",
|
|
32
34
|
"}",
|
|
33
35
|
"body[data-ds-dark-theme] ." + PANEL_CLS + "{",
|
|
34
|
-
" --up-bg:#
|
|
35
|
-
" --up-border:rgba(255,255,255,.08);--up-
|
|
36
|
-
" --up-
|
|
37
|
-
" --up-
|
|
38
|
-
" --up-
|
|
36
|
+
" --up-bg:#202724;--up-fg:#e9efec;--up-fg2:#aab6b1;--up-fg3:#72807b;",
|
|
37
|
+
" --up-border:rgba(255,255,255,.08);--up-border2:rgba(255,255,255,.16);",
|
|
38
|
+
" --up-hover:#2a332f;--up-card:#252e2a;--up-card2:#29332f;",
|
|
39
|
+
" --up-shadow:0 1px 2px rgba(0,0,0,.25),0 16px 44px rgba(0,0,0,.52);",
|
|
40
|
+
" --up-grad1:#34d399;--up-grad2:#2dd4bf;--up-grad3:#14b8a6;",
|
|
41
|
+
" --up-accent:#34d399;--up-accent-soft:rgba(52,211,153,.15);",
|
|
42
|
+
" --up-bar-bg:#2f3a35;--up-warn:#fbbf24;--up-danger:#f2555a;",
|
|
39
43
|
"}",
|
|
40
|
-
//
|
|
44
|
+
// ---------- 面板外壳 ----------
|
|
41
45
|
"." + PANEL_CLS + "{",
|
|
42
|
-
" position:fixed;z-index:9999;right:12px;top:49px;width:
|
|
43
|
-
" max-height:
|
|
44
|
-
" background:var(--up-bg);",
|
|
45
|
-
" border:
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
" padding:0;font-family:var(--dcu-font,Inter,system-ui);",
|
|
49
|
-
" color:var(--up-fg);",
|
|
50
|
-
" display:none;",
|
|
51
|
-
" scrollbar-width:thin;scrollbar-color:var(--up-fg3) transparent;",
|
|
46
|
+
" position:fixed;z-index:9999;right:12px;top:49px;width:332px;",
|
|
47
|
+
" max-height:calc(100vh - 62px);overflow-y:auto;overflow-x:hidden;",
|
|
48
|
+
" background:var(--up-bg);border:1px solid var(--up-border);",
|
|
49
|
+
" border-radius:18px;box-shadow:var(--up-shadow);",
|
|
50
|
+
" padding:0;font-family:var(--dcu-font,Inter,system-ui);color:var(--up-fg);",
|
|
51
|
+
" display:none;scrollbar-width:thin;scrollbar-color:var(--up-fg3) transparent;",
|
|
52
52
|
"}",
|
|
53
53
|
"." + PANEL_CLS + "::-webkit-scrollbar{width:6px}",
|
|
54
54
|
"." + PANEL_CLS + "::-webkit-scrollbar-thumb{background:var(--up-fg3);border-radius:3px}",
|
|
55
|
-
|
|
56
|
-
"." + PANEL_CLS + "
|
|
57
|
-
|
|
58
|
-
"." + PANEL_CLS + " .up-head
|
|
59
|
-
"." + PANEL_CLS + " .up-head-
|
|
60
|
-
"." + PANEL_CLS + " .up-
|
|
61
|
-
"." + PANEL_CLS + " .up-
|
|
62
|
-
|
|
63
|
-
"." + PANEL_CLS + " .up-
|
|
64
|
-
"." + PANEL_CLS + " .up-
|
|
65
|
-
"." + PANEL_CLS + " .up-
|
|
66
|
-
"." + PANEL_CLS + " .up-
|
|
67
|
-
|
|
68
|
-
"." + PANEL_CLS + " .up-
|
|
69
|
-
"
|
|
55
|
+
"@keyframes up-in{from{opacity:0;transform:translateY(-10px) scale(.97)}to{opacity:1;transform:none}}",
|
|
56
|
+
"." + PANEL_CLS + ".up-open{display:block;animation:up-in .24s cubic-bezier(.2,.9,.3,1.15)}",
|
|
57
|
+
// ---------- Header 渐变横幅 ----------
|
|
58
|
+
"." + PANEL_CLS + " .up-head{position:relative;padding:16px 16px 13px;overflow:hidden}",
|
|
59
|
+
"." + PANEL_CLS + " .up-head-bg{position:absolute;inset:0;background:linear-gradient(118deg,var(--up-grad1),var(--up-grad3) 62%,var(--up-grad2))}",
|
|
60
|
+
"." + PANEL_CLS + " .up-head-bg::after{content:\"\";position:absolute;inset:0;background:radial-gradient(130% 100% at 100% 0,rgba(255,255,255,.28),transparent 55%)}",
|
|
61
|
+
"." + PANEL_CLS + " .up-head-in{position:relative;display:flex;align-items:flex-start;gap:10px}",
|
|
62
|
+
"." + PANEL_CLS + " .up-head-logo{width:34px;height:34px;border-radius:11px;background:rgba(255,255,255,.22);border:1px solid rgba(255,255,255,.4);display:grid;place-items:center;font-size:17px;box-shadow:0 2px 10px rgba(0,0,0,.16);flex:none}",
|
|
63
|
+
"." + PANEL_CLS + " .up-head-title{font-size:15px;font-weight:800;letter-spacing:.2px;flex:1;min-width:0;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.15)}",
|
|
64
|
+
"." + PANEL_CLS + " .up-head-sub{font-size:10.5px;color:rgba(255,255,255,.82);font-weight:500;margin-top:2px;text-shadow:0 1px 2px rgba(0,0,0,.12)}",
|
|
65
|
+
"." + PANEL_CLS + " .up-icon-btn{appearance:none;border:0;background:rgba(255,255,255,.16);cursor:pointer;width:28px;height:28px;border-radius:9px;display:grid;place-items:center;color:#fff;font-size:15px;transition:background .18s,transform .25s}",
|
|
66
|
+
"." + PANEL_CLS + " .up-icon-btn:hover{background:rgba(255,255,255,.3);transform:rotate(140deg)}",
|
|
67
|
+
"." + PANEL_CLS + " .up-plan-chip{position:relative;display:inline-flex;align-items:center;gap:6px;margin-top:10px;padding:3px 10px;border-radius:99px;background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.34);font-size:10px;font-weight:700;letter-spacing:.5px;color:#fff;text-transform:uppercase;max-width:100%;box-sizing:border-box}",
|
|
68
|
+
"." + PANEL_CLS + " .up-plan-chip .up-dot{width:5px;height:5px;border-radius:50%;background:#c9f7e4;box-shadow:0 0 0 2px rgba(201,247,228,.25);animation:up-pulse 2.2s ease-in-out infinite;flex:none}",
|
|
69
|
+
"@keyframes up-pulse{0%,100%{opacity:1}50%{opacity:.4}}",
|
|
70
|
+
// ---------- 主体 ----------
|
|
71
|
+
"." + PANEL_CLS + " .up-body{padding:13px 13px 11px}",
|
|
72
|
+
// 统计三卡
|
|
73
|
+
"." + PANEL_CLS + " .up-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:12px}",
|
|
74
|
+
"." + PANEL_CLS + " .up-stat{position:relative;background:var(--up-card);border:1px solid var(--up-border);border-radius:12px;padding:10px 4px 8px;text-align:center;transition:border-color .18s,transform .18s,box-shadow .18s;overflow:hidden}",
|
|
75
|
+
"." + PANEL_CLS + " .up-stat::before{content:\"\";position:absolute;top:0;left:16%;right:16%;height:2px;border-radius:2px;background:linear-gradient(90deg,transparent,var(--up-accent),transparent);opacity:.75}",
|
|
76
|
+
"." + PANEL_CLS + " .up-stat:hover{border-color:var(--up-border2);transform:translateY(-1px);box-shadow:0 3px 10px rgba(16,50,40,.06)}",
|
|
77
|
+
"." + PANEL_CLS + " .up-stat-num{font-size:16.5px;font-weight:800;color:var(--up-fg);line-height:1.15;font-variant-numeric:tabular-nums;letter-spacing:-.3px}",
|
|
78
|
+
"." + PANEL_CLS + " .up-stat-lbl{font-size:9px;color:var(--up-fg3);margin-top:4px;letter-spacing:.6px;font-weight:700;text-transform:uppercase}",
|
|
79
|
+
// 分区卡片
|
|
80
|
+
"." + PANEL_CLS + " .up-section{background:var(--up-card);border:1px solid var(--up-border);border-radius:14px;padding:11px 12px 10px;margin-bottom:9px;transition:border-color .18s}",
|
|
81
|
+
"." + PANEL_CLS + " .up-section:hover{border-color:var(--up-border2)}",
|
|
82
|
+
"." + PANEL_CLS + " .up-section-title{display:flex;align-items:center;gap:7px;font-size:9.5px;font-weight:800;color:var(--up-fg3);text-transform:uppercase;letter-spacing:1.2px;margin-bottom:7px}",
|
|
83
|
+
"." + PANEL_CLS + " .up-section-title::before{content:\"\";width:3px;height:11px;border-radius:2px;background:linear-gradient(180deg,var(--up-grad1),var(--up-grad3))}",
|
|
70
84
|
// 进度行
|
|
71
|
-
"." + PANEL_CLS + " .up-progress{margin:
|
|
72
|
-
"." + PANEL_CLS + " .up-progress-top{display:flex;align-items:
|
|
73
|
-
"." + PANEL_CLS + " .up-progress-label{font-size:12px;color:var(--up-
|
|
74
|
-
"." + PANEL_CLS + " .up-progress-
|
|
75
|
-
"." + PANEL_CLS + " .up-progress-
|
|
76
|
-
"." + PANEL_CLS + " .up-progress-
|
|
77
|
-
"." + PANEL_CLS + " .up-progress-
|
|
85
|
+
"." + PANEL_CLS + " .up-progress{margin:8px 0}",
|
|
86
|
+
"." + PANEL_CLS + " .up-progress-top{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:5px;gap:8px}",
|
|
87
|
+
"." + PANEL_CLS + " .up-progress-label{font-size:12px;color:var(--up-fg);font-weight:650;display:flex;align-items:center;gap:5px}",
|
|
88
|
+
"." + PANEL_CLS + " .up-progress-label .up-lbl-ic{font-size:12px;width:16px;text-align:center;color:var(--up-accent);flex:none}",
|
|
89
|
+
"." + PANEL_CLS + " .up-progress-val{font-size:10.5px;color:var(--up-fg2);font-variant-numeric:tabular-nums;font-weight:500}",
|
|
90
|
+
"." + PANEL_CLS + " .up-progress-val b{color:var(--up-fg);font-weight:700}",
|
|
91
|
+
"." + PANEL_CLS + " .up-progress-track{height:9px;border-radius:99px;background:var(--up-bar-bg);overflow:hidden;box-shadow:inset 0 1px 2px rgba(0,0,0,.06)}",
|
|
92
|
+
"." + PANEL_CLS + " .up-progress-fill{height:100%;border-radius:99px;transition:width .8s cubic-bezier(.3,.7,.3,1);position:relative;box-shadow:0 1px 3px rgba(0,0,0,.14)}",
|
|
93
|
+
"." + PANEL_CLS + " .up-progress-fill::after{content:\"\";position:absolute;inset:0;border-radius:99px;background:linear-gradient(90deg,rgba(255,255,255,.32),transparent 42%)}",
|
|
94
|
+
"." + PANEL_CLS + " .up-progress-bottom{display:flex;align-items:center;justify-content:space-between;margin-top:5px;gap:8px;min-height:15px}",
|
|
95
|
+
"." + PANEL_CLS + " .up-progress-deadline{font-size:10px;color:var(--up-fg3);font-weight:500;display:inline-flex;align-items:center;gap:3px;letter-spacing:.2px;font-variant-numeric:tabular-nums}",
|
|
96
|
+
"." + PANEL_CLS + " .up-progress-deadline .up-cal{font-size:9.5px;opacity:.9}",
|
|
97
|
+
"." + PANEL_CLS + " .up-pct-chip{font-size:9.5px;font-weight:800;padding:2px 8px;border-radius:99px;letter-spacing:.3px;font-variant-numeric:tabular-nums}",
|
|
78
98
|
// 页脚
|
|
79
|
-
"." + PANEL_CLS + " .up-foot{padding:10px 16px 12px;border-top:1px solid var(--up-border);display:flex;align-items:center;justify-content:space-between}",
|
|
80
|
-
"." + PANEL_CLS + " .up-foot-left{font-size:10px;color:var(--up-fg3)}",
|
|
81
|
-
"." + PANEL_CLS + " .up-foot-
|
|
82
|
-
//
|
|
83
|
-
"." + PANEL_CLS + " .up-loading{padding:
|
|
84
|
-
"." + PANEL_CLS + " .up-spinner{width:
|
|
99
|
+
"." + PANEL_CLS + " .up-foot{padding:10px 16px 12px;border-top:1px solid var(--up-border);display:flex;align-items:center;justify-content:space-between;gap:8px;background:linear-gradient(0deg,var(--up-accent-soft),transparent 85%)}",
|
|
100
|
+
"." + PANEL_CLS + " .up-foot-left{font-size:10px;color:var(--up-fg3);display:flex;align-items:center;gap:6px;font-variant-numeric:tabular-nums}",
|
|
101
|
+
"." + PANEL_CLS + " .up-foot-user{font-weight:700;color:var(--up-fg2);max-width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
102
|
+
// 加载 / 错误
|
|
103
|
+
"." + PANEL_CLS + " .up-loading{padding:36px 16px;text-align:center;font-size:12px;color:var(--up-fg3)}",
|
|
104
|
+
"." + PANEL_CLS + " .up-spinner{width:26px;height:26px;border:3px solid var(--up-bar-bg);border-top-color:var(--up-accent);border-radius:50%;margin:0 auto 10px;animation:up-spin .7s linear infinite}",
|
|
85
105
|
"@keyframes up-spin{to{transform:rotate(360deg)}}",
|
|
86
|
-
"." + PANEL_CLS + " .up-error{padding:
|
|
87
|
-
"." + PANEL_CLS + " .up-retry{margin-top:
|
|
88
|
-
|
|
106
|
+
"." + PANEL_CLS + " .up-error{padding:32px 16px;text-align:center;font-size:12px;color:var(--up-danger)}",
|
|
107
|
+
"." + PANEL_CLS + " .up-retry{margin-top:12px;padding:6px 18px;border-radius:99px;border:0;background:var(--up-accent);cursor:pointer;font-size:12px;font-weight:600;color:#fff}",
|
|
108
|
+
"." + PANEL_CLS + " .up-retry:hover{filter:brightness(1.1)}",
|
|
109
|
+
// ---------- 侧栏按钮 ----------
|
|
89
110
|
"." + BTN_CLS + "{",
|
|
90
111
|
" --up-fg2:#4e5253;--up-hover:#dfe8e5;",
|
|
91
112
|
" display:flex;align-items:center;gap:8px;width:100%;min-height:36px;",
|
|
92
113
|
" padding:0 4px;border-radius:8px;background:transparent;border:0;",
|
|
93
|
-
" cursor:pointer;color:var(--up-fg2);",
|
|
94
|
-
" font-
|
|
114
|
+
" cursor:pointer;color:var(--up-fg2);font-size:14px;text-align:left;",
|
|
115
|
+
" font-family:var(--dcu-font,Inter,system-ui);transition:background .15s;",
|
|
95
116
|
"}",
|
|
96
|
-
"body[data-ds-dark-theme] ." + BTN_CLS + "{",
|
|
97
|
-
"
|
|
98
|
-
"}",
|
|
99
|
-
"." + BTN_CLS + "
|
|
100
|
-
"." + BTN_CLS + "
|
|
117
|
+
"body[data-ds-dark-theme] ." + BTN_CLS + "{--up-fg2:#b9bab9;--up-hover:#303432}",
|
|
118
|
+
"." + BTN_CLS + ":hover{background:var(--up-hover)}",
|
|
119
|
+
"." + BTN_CLS + " .up-btn-icon{width:20px;height:20px;display:grid;place-items:center;font-size:14px}",
|
|
120
|
+
"." + BTN_CLS + ".up-active{background:var(--up-accent-soft,#e6f4ef);color:var(--up-accent,#0d9f77);font-weight:600}",
|
|
121
|
+
"body[data-ds-dark-theme] ." + BTN_CLS + ".up-active{color:#34d399;background:rgba(52,211,153,.12)}",
|
|
101
122
|
].join("\n");
|
|
102
123
|
var style = document.createElement("style");
|
|
103
124
|
style.id = STYLE_ID;
|
|
@@ -107,64 +128,82 @@ window.__ModuleLoader__.load({
|
|
|
107
128
|
|
|
108
129
|
// ---------- 格式化 ----------
|
|
109
130
|
function fmtMoney(v) { return "$" + (typeof v === "number" ? v.toFixed(2) : "—"); }
|
|
110
|
-
function fmtNum(v) { return typeof v === "number" ? v.toLocaleString() : "—"; }
|
|
111
131
|
function fmtCompact(v) {
|
|
112
132
|
if (typeof v !== "number") return "—";
|
|
113
|
-
if (v >=
|
|
114
|
-
if (v >= 1e6) return (v / 1e6).toFixed(1) + "M";
|
|
133
|
+
if (v >= 1e6) return (v / 1e6).toFixed(2) + "M";
|
|
115
134
|
if (v >= 1e3) return (v / 1e3).toFixed(1) + "K";
|
|
116
|
-
return String(v);
|
|
135
|
+
return String(Math.round(v));
|
|
117
136
|
}
|
|
118
137
|
function pct(used, cap) { return cap > 0 ? Math.min(100, Math.round(used / cap * 100)) : 0; }
|
|
119
|
-
function
|
|
138
|
+
function pad2(n) { return (n < 10 ? "0" : "") + n; }
|
|
139
|
+
// 周期截止 → {text:"M/D HH:mm", days} 或 ""
|
|
140
|
+
function fmtDeadline(t) {
|
|
141
|
+
if (t === undefined || t === null || t === "") return "";
|
|
142
|
+
var d = new Date(t);
|
|
143
|
+
if (isNaN(d.getTime())) return "";
|
|
144
|
+
var now = new Date();
|
|
145
|
+
var days = Math.ceil((d - now) / 86400000);
|
|
146
|
+
var text = (d.getMonth() + 1) + "/" + d.getDate() + " " + pad2(d.getHours()) + ":" + pad2(d.getMinutes());
|
|
147
|
+
return { text: text, days: days };
|
|
148
|
+
}
|
|
149
|
+
function fmtCountdown(dl) {
|
|
150
|
+
if (!dl) return "";
|
|
151
|
+
var hm = dl.text.split(" ")[1];
|
|
152
|
+
if (dl.days <= 0) return "今日 " + hm;
|
|
153
|
+
if (dl.days === 1) return "明天 " + hm;
|
|
154
|
+
return dl.days + "天后 " + hm;
|
|
155
|
+
}
|
|
156
|
+
function barColor(p) { return p >= 85 ? "var(--up-danger)" : p >= 60 ? "var(--up-warn)" : "linear-gradient(90deg,var(--up-grad1),var(--up-grad2))"; }
|
|
120
157
|
|
|
121
|
-
// ---------- RPC
|
|
122
|
-
function callUsage(
|
|
158
|
+
// ---------- RPC ----------
|
|
159
|
+
function callUsage() {
|
|
123
160
|
return new Promise(function (resolve) {
|
|
124
161
|
try {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
162
|
+
fetch("/dsh-usage/report", {
|
|
163
|
+
method: "POST",
|
|
164
|
+
headers: { "Content-Type": "application/json" },
|
|
165
|
+
body: JSON.stringify({ type: "client-request", rpcId: "usage-" + Date.now(), method: "report", payload: {} })
|
|
166
|
+
}).then(function (res) { return res.ok ? res.json() : Promise.reject(new Error("HTTP " + res.status)); })
|
|
167
|
+
.then(function (msg) {
|
|
168
|
+
if (msg && msg.type === "server-response" && msg.result) {
|
|
169
|
+
var r = msg.result;
|
|
170
|
+
if (r.ok && r.value) resolve(r.value);
|
|
171
|
+
else resolve({ error: (r.error && (r.error.message || JSON.stringify(r.error))) || "RPC 返回异常" });
|
|
172
|
+
} else resolve({ error: "RPC 响应格式异常" });
|
|
173
|
+
})
|
|
174
|
+
.catch(function (e) { resolve({ error: String(e && e.message || e) }); });
|
|
134
175
|
} catch (e) { resolve({ error: String(e && e.message || e) }); }
|
|
135
176
|
});
|
|
136
177
|
}
|
|
137
178
|
|
|
138
|
-
//
|
|
139
|
-
function buildPanel(
|
|
179
|
+
// ================= 面板 =================
|
|
180
|
+
function buildPanel() {
|
|
140
181
|
var wrap = document.createElement("div");
|
|
141
182
|
wrap.className = PANEL_CLS;
|
|
142
183
|
var state = { data: null, error: null, loading: false };
|
|
143
184
|
|
|
144
|
-
//
|
|
185
|
+
// ---- 头部 ----
|
|
145
186
|
var head = document.createElement("div");
|
|
146
187
|
head.className = "up-head";
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
var
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
headTitle
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
headSub.textContent = "用量 · 余额";
|
|
157
|
-
headTitles.appendChild(headTitle); headTitles.appendChild(headSub);
|
|
158
|
-
var refreshBtn = document.createElement("button");
|
|
159
|
-
refreshBtn.className = "up-icon-btn";
|
|
160
|
-
refreshBtn.textContent = "↻";
|
|
188
|
+
head.appendChild(el("div", "up-head-bg"));
|
|
189
|
+
var headIn = el("div", "up-head-in");
|
|
190
|
+
var logo = el("div", "up-head-logo", "⚡");
|
|
191
|
+
var titles = el("div");
|
|
192
|
+
titles.style.cssText = "flex:1;min-width:0";
|
|
193
|
+
var headTitle = el("div", "up-head-title", "CommandCode");
|
|
194
|
+
var headSub = el("div", "up-head-sub", "用量 · 余额");
|
|
195
|
+
titles.appendChild(headTitle); titles.appendChild(headSub);
|
|
196
|
+
var refreshBtn = el("button", "up-icon-btn", "↻");
|
|
161
197
|
refreshBtn.title = "刷新";
|
|
162
|
-
refreshBtn.onclick = load;
|
|
163
|
-
|
|
198
|
+
refreshBtn.onclick = function () { load(); };
|
|
199
|
+
headIn.appendChild(logo); headIn.appendChild(titles); headIn.appendChild(refreshBtn);
|
|
200
|
+
head.appendChild(headIn);
|
|
201
|
+
var planChip = el("div", "up-plan-chip"); planChip.style.display = "none";
|
|
202
|
+
head.appendChild(planChip);
|
|
164
203
|
wrap.appendChild(head);
|
|
165
204
|
|
|
166
|
-
//
|
|
167
|
-
var body =
|
|
205
|
+
// ---- 主体 ----
|
|
206
|
+
var body = el("div", "up-body");
|
|
168
207
|
wrap.appendChild(body);
|
|
169
208
|
|
|
170
209
|
function el(tag, cls, text) {
|
|
@@ -179,19 +218,45 @@ window.__ModuleLoader__.load({
|
|
|
179
218
|
s.appendChild(el("div", "up-stat-lbl", label));
|
|
180
219
|
return s;
|
|
181
220
|
}
|
|
182
|
-
function progressRow(label, used, cap) {
|
|
221
|
+
function progressRow(label, icon, used, cap, deadlineT) {
|
|
183
222
|
var p = pct(used, cap);
|
|
184
223
|
var pr = el("div", "up-progress");
|
|
224
|
+
// 顶行
|
|
185
225
|
var top = el("div", "up-progress-top");
|
|
186
|
-
|
|
187
|
-
|
|
226
|
+
var lbl = el("span", "up-progress-label");
|
|
227
|
+
if (icon) lbl.appendChild(el("span", "up-lbl-ic", icon));
|
|
228
|
+
lbl.appendChild(el("span", "", label));
|
|
229
|
+
top.appendChild(lbl);
|
|
230
|
+
var val = el("span", "up-progress-val");
|
|
231
|
+
var usedB = document.createElement("b");
|
|
232
|
+
usedB.textContent = fmtMoney(used);
|
|
233
|
+
val.appendChild(usedB);
|
|
234
|
+
val.appendChild(document.createTextNode(" / " + fmtMoney(cap)));
|
|
235
|
+
top.appendChild(val);
|
|
188
236
|
pr.appendChild(top);
|
|
237
|
+
// 进度条(动画)
|
|
189
238
|
var track = el("div", "up-progress-track");
|
|
190
239
|
var fill = el("div", "up-progress-fill");
|
|
191
|
-
fill.style.width =
|
|
240
|
+
fill.style.width = "0%";
|
|
192
241
|
fill.style.background = barColor(p);
|
|
193
242
|
track.appendChild(fill);
|
|
194
243
|
pr.appendChild(track);
|
|
244
|
+
setTimeout(function () { fill.style.width = p + "%"; }, 40);
|
|
245
|
+
// 底行:重置倒计时 + 百分比胶囊
|
|
246
|
+
var bottom = el("div", "up-progress-bottom");
|
|
247
|
+
if (deadlineT && deadlineT.text) {
|
|
248
|
+
var dl = el("span", "up-progress-deadline");
|
|
249
|
+
dl.appendChild(el("span", "up-cal", "🕒"));
|
|
250
|
+
dl.appendChild(document.createTextNode("重置 " + fmtCountdown(deadlineT) + " · " + deadlineT.text));
|
|
251
|
+
bottom.appendChild(dl);
|
|
252
|
+
} else {
|
|
253
|
+
bottom.appendChild(el("span", "", ""));
|
|
254
|
+
}
|
|
255
|
+
var chip = el("span", "up-pct-chip", p + "%");
|
|
256
|
+
chip.style.color = p >= 85 ? "var(--up-danger)" : p >= 60 ? "var(--up-warn)" : "var(--up-accent)";
|
|
257
|
+
chip.style.background = p >= 85 ? "rgba(229,72,77,.12)" : p >= 60 ? "rgba(234,179,8,.13)" : "var(--up-accent-soft)";
|
|
258
|
+
bottom.appendChild(chip);
|
|
259
|
+
pr.appendChild(bottom);
|
|
195
260
|
return pr;
|
|
196
261
|
}
|
|
197
262
|
|
|
@@ -221,45 +286,75 @@ window.__ModuleLoader__.load({
|
|
|
221
286
|
var win = d.credits && d.credits.windowLimits || {};
|
|
222
287
|
var sub = d.subscription && d.subscription.data || {};
|
|
223
288
|
|
|
224
|
-
//
|
|
289
|
+
// 头部:账号 + 套餐 chip
|
|
290
|
+
if (account.userName) headSub.textContent = account.userName + (sub.planId ? " · " + sub.planId : "");
|
|
291
|
+
planChip.textContent = ""; planChip.style.display = sub.planId ? "inline-flex" : "none";
|
|
292
|
+
if (sub.planId) {
|
|
293
|
+
planChip.appendChild(el("span", "up-dot"));
|
|
294
|
+
planChip.appendChild(document.createTextNode(sub.status === "active" ? "Active · " + sub.planId : sub.planId));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// 统计三卡
|
|
225
298
|
if (usage.totalCount !== undefined) {
|
|
226
299
|
var stats = el("div", "up-stats");
|
|
227
300
|
stats.appendChild(statRow(fmtCompact(usage.totalCount), "请求"));
|
|
228
|
-
stats.appendChild(statRow(
|
|
229
|
-
stats.appendChild(statRow(fmtMoney(usage.totalCost), "
|
|
301
|
+
stats.appendChild(statRow(usage.successRate !== undefined ? usage.successRate + "%" : "—", "成功率"));
|
|
302
|
+
stats.appendChild(statRow(fmtMoney(usage.totalCost), "总花费"));
|
|
230
303
|
body.appendChild(stats);
|
|
231
304
|
}
|
|
232
305
|
|
|
233
|
-
//
|
|
306
|
+
// 窗口用量
|
|
234
307
|
var secWin = el("div", "up-section");
|
|
235
308
|
secWin.appendChild(el("div", "up-section-title", "窗口用量"));
|
|
236
|
-
if (win.fiveHour) secWin.appendChild(progressRow("5
|
|
237
|
-
if (win.weekly) secWin.appendChild(progressRow("
|
|
309
|
+
if (win.fiveHour) secWin.appendChild(progressRow("5小时滚动窗口", "⏱", win.fiveHour.used, win.fiveHour.cap, fmtDeadline(win.fiveHour.resetAt)));
|
|
310
|
+
if (win.weekly) secWin.appendChild(progressRow("每周用量", "📅", win.weekly.used, win.weekly.cap, fmtDeadline(win.weekly.resetAt)));
|
|
311
|
+
if (win.limited === false && !win.fiveHour && !win.weekly) secWin.appendChild(el("div", "up-progress-deadline", "无限额度 · 无窗口限制"));
|
|
238
312
|
body.appendChild(secWin);
|
|
239
313
|
|
|
240
|
-
//
|
|
314
|
+
// 信用 / 月额度
|
|
241
315
|
if (credits.monthlyCredits !== undefined) {
|
|
242
316
|
var secCred = el("div", "up-section");
|
|
243
317
|
secCred.appendChild(el("div", "up-section-title", "月额度"));
|
|
244
318
|
var usedMonthly = win.weekly ? win.weekly.used : (usage.totalCredits || 0);
|
|
245
319
|
var capMonthly = usedMonthly + credits.monthlyCredits;
|
|
246
|
-
secCred.appendChild(progressRow("
|
|
320
|
+
secCred.appendChild(progressRow("剩余额度", "💳", credits.monthlyCredits, capMonthly, fmtDeadline(sub.currentPeriodEnd)));
|
|
321
|
+
// 明细
|
|
322
|
+
var det = el("div", "up-progress-bottom");
|
|
323
|
+
det.style.cssText = "justify-content:flex-start;gap:14px;margin-top:6px;padding-top:7px;border-top:1px dashed var(--up-border);min-height:0";
|
|
324
|
+
var detItem = function (k, v) {
|
|
325
|
+
var it = el("span", "up-progress-deadline");
|
|
326
|
+
it.appendChild(document.createTextNode(k + " "));
|
|
327
|
+
var vv = document.createElement("b");
|
|
328
|
+
vv.textContent = v;
|
|
329
|
+
vv.style.cssText = "color:var(--up-fg2);font-weight:700";
|
|
330
|
+
it.appendChild(vv);
|
|
331
|
+
return it;
|
|
332
|
+
};
|
|
333
|
+
if (usage.totalMonthlyCredits !== undefined) det.appendChild(detItem("当月已用", fmtMoney(usage.totalMonthlyCredits)));
|
|
334
|
+
det.appendChild(detItem("已购买", fmtMoney(credits.purchasedCredits)));
|
|
335
|
+
if (credits.freeCredits !== undefined) det.appendChild(detItem("免费", fmtMoney(credits.freeCredits)));
|
|
336
|
+
secCred.appendChild(det);
|
|
247
337
|
body.appendChild(secCred);
|
|
248
338
|
}
|
|
249
339
|
|
|
250
|
-
//
|
|
340
|
+
// 页脚
|
|
251
341
|
var foot = el("div", "up-foot");
|
|
252
342
|
var footL = el("div", "up-foot-left");
|
|
253
|
-
|
|
343
|
+
var fu = el("span", "up-foot-user", account.userName || "—");
|
|
344
|
+
footL.appendChild(fu);
|
|
345
|
+
footL.appendChild(document.createTextNode("·"));
|
|
346
|
+
footL.appendChild(document.createTextNode(d.fetchedAt ? new Date(d.fetchedAt).toLocaleTimeString() : ""));
|
|
254
347
|
foot.appendChild(footL);
|
|
255
|
-
|
|
348
|
+
var footR = el("span", "up-foot-left");
|
|
349
|
+
footR.textContent = "5分钟自动刷新";
|
|
350
|
+
foot.appendChild(footR);
|
|
256
351
|
body.appendChild(foot);
|
|
257
352
|
}
|
|
258
353
|
|
|
259
354
|
function load() {
|
|
260
355
|
state.loading = true; state.error = null;
|
|
261
356
|
render();
|
|
262
|
-
callUsage(
|
|
357
|
+
callUsage().then(function (res) {
|
|
263
358
|
state.loading = false;
|
|
264
359
|
if (res && res.error) state.error = res.error;
|
|
265
360
|
else {
|
|
@@ -270,21 +365,47 @@ window.__ModuleLoader__.load({
|
|
|
270
365
|
});
|
|
271
366
|
}
|
|
272
367
|
|
|
273
|
-
|
|
274
|
-
function onDocClick(ev) {
|
|
275
|
-
|
|
368
|
+
var open = false; var panelBtn = null;
|
|
369
|
+
function onDocClick(ev) { if (!wrap.contains(ev.target) && !(panelBtn && panelBtn.contains(ev.target))) hide(); }
|
|
370
|
+
function onKey(ev) { if (ev.key === "Escape") hide(); }
|
|
371
|
+
function show() {
|
|
372
|
+
open = true;
|
|
373
|
+
load();
|
|
374
|
+
wrap.style.display = "block";
|
|
375
|
+
wrap.classList.add("up-open");
|
|
376
|
+
if (panelBtn) panelBtn.classList.add("up-active");
|
|
377
|
+
document.addEventListener("click", onDocClick, true);
|
|
378
|
+
document.addEventListener("keydown", onKey, true);
|
|
379
|
+
}
|
|
380
|
+
function hide() {
|
|
381
|
+
open = false;
|
|
382
|
+
wrap.style.display = "none";
|
|
383
|
+
wrap.classList.remove("up-open");
|
|
384
|
+
if (panelBtn) panelBtn.classList.remove("up-active");
|
|
385
|
+
document.removeEventListener("click", onDocClick, true);
|
|
386
|
+
document.removeEventListener("keydown", onKey, true);
|
|
276
387
|
}
|
|
277
|
-
function
|
|
278
|
-
function hide() { wrap.style.display = "none"; document.removeEventListener("click", onDocClick); }
|
|
279
|
-
function toggle() { if (wrap.style.display === "none") show(); else hide(); }
|
|
388
|
+
function toggle() { if (open) hide(); else show(); }
|
|
280
389
|
|
|
281
|
-
|
|
282
|
-
var timer = setInterval(function () { if (wrap.style.display !== "none") load(); }, POLL_MS);
|
|
390
|
+
var timer = setInterval(function () { if (open) load(); }, POLL_MS);
|
|
283
391
|
|
|
284
|
-
|
|
392
|
+
var api = {
|
|
393
|
+
wrap: wrap,
|
|
394
|
+
setButton: function (b) { panelBtn = b; },
|
|
395
|
+
toggle: toggle,
|
|
396
|
+
hide: hide,
|
|
397
|
+
dispose: function () {
|
|
398
|
+
clearInterval(timer);
|
|
399
|
+
document.removeEventListener("click", onDocClick, true);
|
|
400
|
+
document.removeEventListener("keydown", onKey, true);
|
|
401
|
+
if (wrap.parentNode) wrap.parentNode.removeChild(wrap);
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
wrap.__dshDispose = api.dispose;
|
|
405
|
+
return api;
|
|
285
406
|
}
|
|
286
407
|
|
|
287
|
-
// ----------
|
|
408
|
+
// ---------- 侧栏按钮 ----------
|
|
288
409
|
function buildButton(panel) {
|
|
289
410
|
var btn = document.createElement("button");
|
|
290
411
|
btn.type = "button";
|
|
@@ -300,16 +421,28 @@ window.__ModuleLoader__.load({
|
|
|
300
421
|
}
|
|
301
422
|
|
|
302
423
|
// ---------- apply ----------
|
|
424
|
+
var _instance = null;
|
|
303
425
|
exports.apply = function apply(ctx) {
|
|
304
426
|
if (typeof document === "undefined") return;
|
|
305
|
-
|
|
306
|
-
|
|
427
|
+
|
|
428
|
+
if (_instance) {
|
|
429
|
+
try { if (typeof _instance.dispose === "function") _instance.dispose(); } catch (e) {}
|
|
430
|
+
_instance = null;
|
|
431
|
+
}
|
|
432
|
+
var oldWrap = document.querySelector("." + PANEL_CLS);
|
|
433
|
+
if (oldWrap && oldWrap.__dshDispose) { try { oldWrap.__dshDispose(); } catch (e) {} }
|
|
434
|
+
var oldBtns = document.querySelectorAll("." + BTN_CLS);
|
|
435
|
+
for (var i = 0; i < oldBtns.length; i++) {
|
|
436
|
+
if (oldBtns[i].parentNode) oldBtns[i].parentNode.removeChild(oldBtns[i]);
|
|
437
|
+
}
|
|
307
438
|
|
|
308
439
|
injectStyles();
|
|
309
440
|
|
|
310
|
-
var panel = buildPanel(
|
|
441
|
+
var panel = buildPanel();
|
|
311
442
|
var btn = buildButton(panel);
|
|
443
|
+
if (panel && typeof panel.setButton === 'function') panel.setButton(btn);
|
|
312
444
|
document.body.appendChild(panel.wrap);
|
|
445
|
+
_instance = panel;
|
|
313
446
|
|
|
314
447
|
function tryAttach() {
|
|
315
448
|
var foot = document.querySelector(".dcu-footer-actions");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-commandcode-usage",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "CommandCode 用量与余额面板 — 在 codex-ui 侧边栏底部显示 CommandCode API 用量、信用额度、5小时/每周窗口。 · CommandCode usage & balance panel for DeepSeek Harness: shows API usage, credit balance, 5-hour/weekly windows from the sidebar footer.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"exports": {
|