dsh-dock 0.11.0 → 0.11.2
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 -2
- package/client.js +44 -36
- package/features/tokenlog/host.js +2 -1
- package/features/tokenlog/view.jsx +38 -25
- package/package.json +1 -1
- package/src/client.jsx +8 -5
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ dsh plugin --profile web remove dsh-dock # 卸载
|
|
|
95
95
|
- **⛁ 会话用量**:显示当前会话的 Token 数与估算费用(10 秒自动刷新)
|
|
96
96
|
- **余额**:显示当前选中模型的 Provider 账户余额(跟随模型切换实时更新)
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
点击芯片直接跳转功能坞对应页(「会话用量」打开后即按当前会话筛选出结果,无需再点查询)。每个功能可在面板页脚或设置页单独设置「会话页显示 / 隐藏」。
|
|
99
99
|
|
|
100
100
|
### 各功能使用
|
|
101
101
|
|
|
@@ -252,7 +252,7 @@ dsh plugin --profile web remove dsh-dock # 卸载
|
|
|
252
252
|
- **⛁ 会话用量**:显示当前会话的 Token 数与估算费用(10 秒自动刷新)
|
|
253
253
|
- **余额**:显示当前选中模型的 Provider 账户余额(跟随模型切换实时更新)
|
|
254
254
|
|
|
255
|
-
|
|
255
|
+
点击芯片直接跳转功能坞对应页(「会话用量」打开后即按当前会话筛选出结果,无需再点查询)。每个功能可在面板页脚或设置页单独设置「会话页显示 / 隐藏」。
|
|
256
256
|
|
|
257
257
|
### 各功能使用
|
|
258
258
|
|
package/client.js
CHANGED
|
@@ -2470,9 +2470,9 @@ function Detail({ rec, onClose, rate }) {
|
|
|
2470
2470
|
["\u9519\u8BEF\u4FE1\u606F", rec.errorMsg || "\u2014"],
|
|
2471
2471
|
["\u9519\u8BEF\u7801", rec.errorCode || "\u2014"],
|
|
2472
2472
|
["Request ID", rec.requestId || "\u2014"],
|
|
2473
|
-
["\u8F93\u5165 Token(\
|
|
2473
|
+
["\u8F93\u5165 Token(\u7F13\u5B58\u547D\u4E2D)", fmtNum(rec.cacheReadTokens)],
|
|
2474
|
+
["\u8F93\u5165 Token(\u7F13\u5B58\u672A\u547D\u4E2D)", fmtNum(rec.inputTokens)],
|
|
2474
2475
|
["\u8F93\u51FA Token", fmtNum(rec.outputTokens)],
|
|
2475
|
-
["\u7F13\u5B58\u547D\u4E2D Token", fmtNum(rec.cacheReadTokens)],
|
|
2476
2476
|
["\u7F13\u5B58\u5199\u5165 Token", fmtNum(rec.cacheWriteTokens)],
|
|
2477
2477
|
["\u63A8\u7406 Token", fmtNum(rec.reasoningTokens)],
|
|
2478
2478
|
["\u8BA1\u8D39\u8F93\u5165", fmtNum(rec.billedInput)],
|
|
@@ -2721,22 +2721,23 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
2721
2721
|
] }),
|
|
2722
2722
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-grid", children: [
|
|
2723
2723
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2724
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u57FA\u51C6\u8F93\u5165" }),
|
|
2724
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u57FA\u51C6\u8F93\u5165\uFF08\u7F13\u5B58\u547D\u4E2D\uFF09" }),
|
|
2725
|
+
num(r.cacheRead, (v) => patchRow(i, { cacheRead: v }))
|
|
2726
|
+
] }),
|
|
2727
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2728
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u57FA\u51C6\u8F93\u5165\uFF08\u7F13\u5B58\u672A\u547D\u4E2D\uFF09" }),
|
|
2725
2729
|
num(r.input, (v) => patchRow(i, { input: v }))
|
|
2726
2730
|
] }),
|
|
2727
2731
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2728
2732
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u57FA\u51C6\u8F93\u51FA" }),
|
|
2729
2733
|
num(r.output, (v) => patchRow(i, { output: v }))
|
|
2730
2734
|
] }),
|
|
2731
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2732
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u57FA\u51C6\u7F13\u5B58\u547D\u4E2D" }),
|
|
2733
|
-
num(r.cacheRead, (v) => patchRow(i, { cacheRead: v }))
|
|
2734
|
-
] }),
|
|
2735
2735
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2736
2736
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u57FA\u51C6\u7F13\u5B58\u5199\u5165" }),
|
|
2737
2737
|
num(r.cacheWrite, (v) => patchRow(i, { cacheWrite: v }))
|
|
2738
2738
|
] })
|
|
2739
2739
|
] }),
|
|
2740
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtok-price-hint", style: { marginTop: 2 }, children: "\u7F13\u5B58\u5199\u5165\uFF1D\u672A\u547D\u4E2D\u7F13\u5B58\u3001\u672C\u6B21\u65B0\u5EFA\u7F13\u5B58\u7684\u90A3\u90E8\u5206\u8F93\u5165\uFF08Claude \u7B49\u6309\u6EA2\u4EF7\u5355\u72EC\u6536\u5EFA\u7F13\u5B58\u8D39\uFF09\uFF1BDeepSeek \u4E0D\u6536\u6B64\u9879\uFF0C\u586B 0 \u5373\u53EF\u3002" }),
|
|
2740
2741
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtok-price-hint", style: { marginTop: 2 }, children: "\u5206\u65F6\u6BB5\u4EF7\uFF08\u53EF\u591A\u6BB5\uFF0C\u547D\u4E2D\u54EA\u6BB5\u7528\u54EA\u6BB5\uFF1B\u65F6\u6BB5\u5916\u56DE\u843D\u5230\u57FA\u51C6\u4EF7\u3002start>end \u8868\u793A\u8DE8\u96F6\u70B9\uFF0C\u5982 23~7\uFF1Bstart=end \u8868\u793A\u5168\u5929\uFF09" }),
|
|
2741
2742
|
r.peaks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtok-price-hint", children: "\uFF08\u672A\u8BBE\u7F6E\u5206\u65F6\u6BB5\uFF0C\u6309\u57FA\u51C6\u4EF7\u8BA1\u8D39\uFF09" }) : null,
|
|
2742
2743
|
r.peaks.map((s, k) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-pseg", children: [
|
|
@@ -2745,13 +2746,13 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
2745
2746
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtok-pseg-tilde", children: "~" }),
|
|
2746
2747
|
num(s.end, (v) => patchSeg(i, k, { end: v }), { width: 56 }),
|
|
2747
2748
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dtok-pseg-tilde", children: "\u65F6" }),
|
|
2748
|
-
segNum(s.input, (v) => patchSeg(i, k, { input: v }), "\u8F93\u5165"),
|
|
2749
|
-
segNum(s.output, (v) => patchSeg(i, k, { output: v }), "\u8F93\u51FA"),
|
|
2750
2749
|
segNum(s.cacheRead, (v) => patchSeg(i, k, { cacheRead: v }), "\u7F13\u5B58\u547D\u4E2D"),
|
|
2751
|
-
segNum(s.
|
|
2750
|
+
segNum(s.input, (v) => patchSeg(i, k, { input: v }), "\u672A\u547D\u4E2D"),
|
|
2751
|
+
segNum(s.output, (v) => patchSeg(i, k, { output: v }), "\u8F93\u51FA"),
|
|
2752
|
+
segNum(s.cacheWrite, (v) => patchSeg(i, k, { cacheWrite: v }), "\u5199\u5165"),
|
|
2752
2753
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "dtok-btn tiny", onClick: () => delSeg(i, k), children: "\u5220\u9664\u65F6\u6BB5" })
|
|
2753
2754
|
] }, k)),
|
|
2754
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtok-price-hint", style: { opacity: 0.85 }, children: "\u65F6\u6BB5\u4EF7\u4ECE\u5DE6\u5230\u53F3\uFF1A\u8F93\u5165
|
|
2755
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtok-price-hint", style: { opacity: 0.85 }, children: "\u65F6\u6BB5\u4EF7\u4ECE\u5DE6\u5230\u53F3\uFF1A\u8F93\u5165\uFF08\u547D\u4E2D\uFF09/ \u8F93\u5165\uFF08\u672A\u547D\u4E2D\uFF09/ \u8F93\u51FA / \u7F13\u5B58\u5199\u5165" }),
|
|
2755
2756
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "dtok-btn tiny", onClick: () => addSeg(i), children: "+ \u6DFB\u52A0\u65F6\u6BB5" })
|
|
2756
2757
|
] }, i)),
|
|
2757
2758
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-grid", style: { marginTop: 6 }, children: [
|
|
@@ -2772,17 +2773,17 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
2772
2773
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtok-section-title", style: { margin: "0 0 4px" }, children: "\u515C\u5E95\u5355\u4EF7\uFF08\u672A\u5339\u914D\u4EFB\u4F55\u6761\u76EE\u65F6\u4F7F\u7528\uFF09" }),
|
|
2773
2774
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-grid", children: [
|
|
2774
2775
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2775
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u8F93\u5165" }),
|
|
2776
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u8F93\u5165\uFF08\u7F13\u5B58\u547D\u4E2D\uFF09" }),
|
|
2777
|
+
num(fb.cacheRead, (v) => setFb((s) => Object.assign({}, s, { cacheRead: v })))
|
|
2778
|
+
] }),
|
|
2779
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2780
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u8F93\u5165\uFF08\u7F13\u5B58\u672A\u547D\u4E2D\uFF09" }),
|
|
2776
2781
|
num(fb.input, (v) => setFb((s) => Object.assign({}, s, { input: v })))
|
|
2777
2782
|
] }),
|
|
2778
2783
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2779
2784
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u8F93\u51FA" }),
|
|
2780
2785
|
num(fb.output, (v) => setFb((s) => Object.assign({}, s, { output: v })))
|
|
2781
2786
|
] }),
|
|
2782
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2783
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u7F13\u5B58\u547D\u4E2D" }),
|
|
2784
|
-
num(fb.cacheRead, (v) => setFb((s) => Object.assign({}, s, { cacheRead: v })))
|
|
2785
|
-
] }),
|
|
2786
2787
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dtok-price-field", children: [
|
|
2787
2788
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u7F13\u5B58\u5199\u5165" }),
|
|
2788
2789
|
num(fb.cacheWrite, (v) => setFb((s) => Object.assign({}, s, { cacheWrite: v })))
|
|
@@ -2798,17 +2799,17 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
2798
2799
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtok-table-wrap", style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "dtok-table", children: [
|
|
2799
2800
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
2800
2801
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u5339\u914D" }),
|
|
2801
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8F93\u5165" }),
|
|
2802
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8F93\u5165(\u547D\u4E2D)" }),
|
|
2803
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8F93\u5165(\u672A\u547D\u4E2D)" }),
|
|
2802
2804
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8F93\u51FA" }),
|
|
2803
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u7F13\u5B58\u547D\u4E2D" }),
|
|
2804
2805
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u7F13\u5B58\u5199\u5165" }),
|
|
2805
2806
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u5206\u65F6\u6BB5" })
|
|
2806
2807
|
] }) }),
|
|
2807
2808
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: cfg.builtin.map((b) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
2808
2809
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: b.match }),
|
|
2810
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: b.cacheRead }),
|
|
2809
2811
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: b.input }),
|
|
2810
2812
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: b.output }),
|
|
2811
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: b.cacheRead }),
|
|
2812
2813
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: b.cacheWrite }),
|
|
2813
2814
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: b.peaks && b.peaks.length ? b.peaks.map((s) => s.start + "~" + s.end).join("\u3001") + "\u65F6" : "\u2014" })
|
|
2814
2815
|
] }, b.match)) })
|
|
@@ -2822,6 +2823,7 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
2822
2823
|
}
|
|
2823
2824
|
function TokenLogView(props) {
|
|
2824
2825
|
const navSession = props && props.params && props.params.sessionId ? props.params.sessionId : null;
|
|
2826
|
+
const navAt = props && props.params && props.params.navAt ? props.params.navAt : 0;
|
|
2825
2827
|
const [savedFilters] = (0, import_react2.useState)(loadSavedFilters);
|
|
2826
2828
|
const [fromStr, setFromStr] = (0, import_react2.useState)(() => savedFilters && savedFilters.fromStr || "");
|
|
2827
2829
|
const [toStr, setToStr] = (0, import_react2.useState)(() => savedFilters && savedFilters.toStr || "");
|
|
@@ -2829,7 +2831,7 @@ function TokenLogView(props) {
|
|
|
2829
2831
|
const [model, setModel] = (0, import_react2.useState)(() => savedFilters && savedFilters.model || "");
|
|
2830
2832
|
const [status, setStatus] = (0, import_react2.useState)(() => savedFilters && savedFilters.status || "");
|
|
2831
2833
|
const [effort, setEffort] = (0, import_react2.useState)(() => savedFilters && savedFilters.effort || "");
|
|
2832
|
-
const [sessionId, setSessionId] = (0, import_react2.useState)(() => savedFilters && savedFilters.sessionId || "");
|
|
2834
|
+
const [sessionId, setSessionId] = (0, import_react2.useState)(() => navSession || savedFilters && savedFilters.sessionId || "");
|
|
2833
2835
|
const [dim, setDim] = (0, import_react2.useState)(() => savedFilters && savedFilters.dim || "");
|
|
2834
2836
|
const [sortKey, setSortKey] = (0, import_react2.useState)("time");
|
|
2835
2837
|
const [sortDir, setSortDir] = (0, import_react2.useState)("desc");
|
|
@@ -2858,6 +2860,7 @@ function TokenLogView(props) {
|
|
|
2858
2860
|
if (savedFilters.sessionId) q.sessionId = savedFilters.sessionId;
|
|
2859
2861
|
if (savedFilters.dim) q.dim = savedFilters.dim;
|
|
2860
2862
|
}
|
|
2863
|
+
if (navSession) q.sessionId = navSession;
|
|
2861
2864
|
rpcCall("scan", {}).then(() => cancel ? null : rpcCall("query", q)).then((d) => {
|
|
2862
2865
|
if (cancel) return;
|
|
2863
2866
|
setData(d);
|
|
@@ -2891,8 +2894,10 @@ function TokenLogView(props) {
|
|
|
2891
2894
|
setPage(0);
|
|
2892
2895
|
}).catch((e) => setErr(String(e && e.message || e))).finally(() => setLoading(false));
|
|
2893
2896
|
}, [buildQ]);
|
|
2897
|
+
const navAppliedRef = (0, import_react2.useRef)(navAt);
|
|
2894
2898
|
(0, import_react2.useEffect)(() => {
|
|
2895
|
-
if (!navSession) return;
|
|
2899
|
+
if (!navSession || navAppliedRef.current === navAt) return;
|
|
2900
|
+
navAppliedRef.current = navAt;
|
|
2896
2901
|
setSessionId(navSession);
|
|
2897
2902
|
setLoading(true);
|
|
2898
2903
|
setErr("");
|
|
@@ -2900,7 +2905,7 @@ function TokenLogView(props) {
|
|
|
2900
2905
|
setData(d);
|
|
2901
2906
|
setPage(0);
|
|
2902
2907
|
}).catch((e) => setErr(String(e && e.message || e))).finally(() => setLoading(false));
|
|
2903
|
-
}, [
|
|
2908
|
+
}, [navAt]);
|
|
2904
2909
|
const resetFilters = (0, import_react2.useCallback)(() => {
|
|
2905
2910
|
setFromStr("");
|
|
2906
2911
|
setToStr("");
|
|
@@ -2969,8 +2974,8 @@ function TokenLogView(props) {
|
|
|
2969
2974
|
const cards = totals ? [
|
|
2970
2975
|
{ v: fmtNum(totals.calls), l: "\u8C03\u7528\u6B21\u6570" },
|
|
2971
2976
|
{ v: fmtCompact(totals.totalTokens), l: "\u603B Token" },
|
|
2972
|
-
{ v: fmtCompact(totals.
|
|
2973
|
-
{ v: fmtCompact(totals.
|
|
2977
|
+
{ v: fmtCompact(totals.cacheReadTokens), l: "\u8F93\u5165(\u547D\u4E2D)" },
|
|
2978
|
+
{ v: fmtCompact(totals.inputTokens), l: "\u8F93\u5165(\u672A\u547D\u4E2D)" },
|
|
2974
2979
|
{ v: totals.cacheHitPct + "%", l: "\u7F13\u5B58\u547D\u4E2D\u7387" },
|
|
2975
2980
|
{ v: fmtCompact(totals.outputTokens), l: "\u8F93\u51FA" },
|
|
2976
2981
|
{ v: fmtCostCny(totals.cost, rateCny), l: "\u6D88\u8017\u91D1\u989D(\u4F30\u7B97\xB7\u4EBA\u6C11\u5E01)" },
|
|
@@ -2981,8 +2986,8 @@ function TokenLogView(props) {
|
|
|
2981
2986
|
const summaryRows = (data && data.summary || []).map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
2982
2987
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: r.key }),
|
|
2983
2988
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtNum(r.calls) }),
|
|
2984
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtCompact(r.inputTokens) }),
|
|
2985
2989
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtCompact(r.cacheReadTokens) }),
|
|
2990
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtCompact(r.inputTokens) }),
|
|
2986
2991
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: r.cacheHitPct + "%" }),
|
|
2987
2992
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtCompact(r.outputTokens) }),
|
|
2988
2993
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtCompact(r.totalTokens) }),
|
|
@@ -3003,8 +3008,8 @@ function TokenLogView(props) {
|
|
|
3003
3008
|
}, children: shortId(r.sessionId) }) }),
|
|
3004
3009
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: r.provider || "\u2014" }),
|
|
3005
3010
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: r.model || "\u2014" }),
|
|
3006
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtNum(r.inputTokens) }),
|
|
3007
3011
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtNum(r.cacheReadTokens) }),
|
|
3012
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtNum(r.inputTokens) }),
|
|
3008
3013
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: r.cacheHitPercent + "%" }),
|
|
3009
3014
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtNum(r.outputTokens) }),
|
|
3010
3015
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: fmtNum(r.reasoningTokens) }),
|
|
@@ -3047,8 +3052,8 @@ function TokenLogView(props) {
|
|
|
3047
3052
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
3048
3053
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u7EF4\u5EA6" }),
|
|
3049
3054
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8C03\u7528" }),
|
|
3050
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8F93\u5165" }),
|
|
3051
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\
|
|
3055
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8F93\u5165(\u547D\u4E2D)" }),
|
|
3056
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8F93\u5165(\u672A\u547D\u4E2D)" }),
|
|
3052
3057
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u547D\u4E2D\u7387" }),
|
|
3053
3058
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8F93\u51FA" }),
|
|
3054
3059
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u603BToken" }),
|
|
@@ -3090,8 +3095,8 @@ function TokenLogView(props) {
|
|
|
3090
3095
|
sortTh("\u4F1A\u8BDDID", "sessionId"),
|
|
3091
3096
|
sortTh("\u63D0\u4F9B\u5546", "provider"),
|
|
3092
3097
|
sortTh("\u6A21\u578B", "model"),
|
|
3093
|
-
sortTh("\u8F93\u5165", "
|
|
3094
|
-
sortTh("\
|
|
3098
|
+
sortTh("\u8F93\u5165(\u547D\u4E2D)", "cacheReadTokens"),
|
|
3099
|
+
sortTh("\u8F93\u5165(\u672A\u547D\u4E2D)", "inputTokens"),
|
|
3095
3100
|
sortTh("\u547D\u4E2D%", "cacheHitPercent"),
|
|
3096
3101
|
sortTh("\u8F93\u51FA", "outputTokens"),
|
|
3097
3102
|
sortTh("\u63A8\u7406", "reasoningTokens"),
|
|
@@ -3221,7 +3226,7 @@ function TokenLogChip(props) {
|
|
|
3221
3226
|
className: "dockchip" + (snap.err && !t ? " err" : ""),
|
|
3222
3227
|
title,
|
|
3223
3228
|
"aria-label": "\u4F1A\u8BDD\u7528\u91CF",
|
|
3224
|
-
onClick: () => openPanel("tokenlog", { sessionId: sid }),
|
|
3229
|
+
onClick: () => openPanel("tokenlog", { sessionId: sid, navAt: Date.now() }),
|
|
3225
3230
|
children: [
|
|
3226
3231
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dockchip-dot", style: { background: "var(--dk-warn)" } }),
|
|
3227
3232
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label })
|
|
@@ -10878,7 +10883,7 @@ var feature10 = {
|
|
|
10878
10883
|
};
|
|
10879
10884
|
|
|
10880
10885
|
// src/client.jsx
|
|
10881
|
-
var DOCK_VERSION = "0.11.
|
|
10886
|
+
var DOCK_VERSION = "0.11.2";
|
|
10882
10887
|
var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6, feature7, feature8, feature9, feature10];
|
|
10883
10888
|
var PLANNED_FEATURES = [];
|
|
10884
10889
|
var PLANNED_NOTES = {};
|
|
@@ -11038,11 +11043,14 @@ var SHELL_CSS = [
|
|
|
11038
11043
|
// 注意:旧上限 min(280px,36cqw) 仍偏宽——标准 780px 输入卡下(.row 内容约 762px),
|
|
11039
11044
|
// add 钮(28)+工作区选择器(~214)+chips(280) 已与右侧模型选择器+发送键(~345px)合计超宽,
|
|
11040
11045
|
// 即便 chips 未截断 .row 也会换行把模型选择器/发送键挤到第二行。实测把上限收到 189px
|
|
11041
|
-
// (≈25cqw)并使 chips 内距收紧(padding 2px 6px、gap 2px
|
|
11042
|
-
// 两 chip
|
|
11046
|
+
// (≈25cqw)并使 chips 内距收紧(padding 2px 6px、gap 2px)后,「4~6M 用量 + 余额」
|
|
11047
|
+
// 两 chip 可完整显示且不再换行。v0.11.2:配置单价后费用段「· ¥0.03」让两 chip 合计
|
|
11048
|
+
// 约需 204px,189px 恰好截掉约 2 个数字(费用/余额小数位看不到)——按用户反馈放宽到
|
|
11049
|
+
// 216px(≈28cqw),标准卡下实测完整显示;若再出现把模型选择器挤换行,优先压缩用量
|
|
11050
|
+
// chip 的 ⛁ 前缀换空间,别再收这个上限。超限仍省略号截断,完整值在 title 悬浮提示里。
|
|
11043
11051
|
// 2) 截断:超限部分用省略号截断(完整数值在 title 悬浮提示里),防 chips 凸出输入卡圆角(悬空)。
|
|
11044
|
-
".dockchip-row{display:inline-flex;align-items:center;gap:2px;min-width:0;flex:0 1 auto;overflow:hidden;max-width:
|
|
11045
|
-
"@supports (width:1cqw){.dockchip-row{max-width:min(
|
|
11052
|
+
".dockchip-row{display:inline-flex;align-items:center;gap:2px;min-width:0;flex:0 1 auto;overflow:hidden;max-width:216px;}",
|
|
11053
|
+
"@supports (width:1cqw){.dockchip-row{max-width:min(216px,28cqw);}}",
|
|
11046
11054
|
".dockchip{display:inline-flex;align-items:center;gap:5px;cursor:pointer;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);border-radius:8px;padding:2px 6px;font-family:inherit;font-size:11px;line-height:18px;white-space:nowrap;min-width:0;overflow:hidden;transition:background .15s var(--ds-ease-in-out),color .15s var(--ds-ease-in-out);}",
|
|
11047
11055
|
".dockchip > span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}",
|
|
11048
11056
|
".dockchip:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
|
|
@@ -851,7 +851,8 @@ export const feature = {
|
|
|
851
851
|
if (method === 'export') {
|
|
852
852
|
loadPricingConfig()
|
|
853
853
|
const list = buildQuery(payload || {}).map(withCost)
|
|
854
|
-
|
|
854
|
+
// 列序对齐界面习惯(缓存命中在前):… 命中 → 未命中 → 输出 → 写入
|
|
855
|
+
const header = ['time', 'provider', 'model', 'apiKey', 'cacheReadTokens', 'inputTokens', 'outputTokens', 'cacheWriteTokens', 'reasoningTokens', 'billedInput', 'cacheHitPercent', 'totalTokens', 'costCny', 'effort', 'status', 'statusCode', 'errorCode', 'errorMsg', 'llmMs', 'sessionId', 'turn', 'step']
|
|
855
856
|
const esc = (v) => {
|
|
856
857
|
const s = String(v === undefined || v === null ? '' : v)
|
|
857
858
|
return /[,"\n]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s
|
|
@@ -189,9 +189,9 @@ function Detail({ rec, onClose, rate }) {
|
|
|
189
189
|
["错误信息", rec.errorMsg || "—"],
|
|
190
190
|
["错误码", rec.errorCode || "—"],
|
|
191
191
|
["Request ID", rec.requestId || "—"],
|
|
192
|
-
["输入 Token(
|
|
192
|
+
["输入 Token(缓存命中)", fmtNum(rec.cacheReadTokens)],
|
|
193
|
+
["输入 Token(缓存未命中)", fmtNum(rec.inputTokens)],
|
|
193
194
|
["输出 Token", fmtNum(rec.outputTokens)],
|
|
194
|
-
["缓存命中 Token", fmtNum(rec.cacheReadTokens)],
|
|
195
195
|
["缓存写入 Token", fmtNum(rec.cacheWriteTokens)],
|
|
196
196
|
["推理 Token", fmtNum(rec.reasoningTokens)],
|
|
197
197
|
["计费输入", fmtNum(rec.billedInput)],
|
|
@@ -451,11 +451,14 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
451
451
|
<button className="dtok-btn tiny" onClick={() => delRow(i)}>删除模型</button>
|
|
452
452
|
</div>
|
|
453
453
|
<div className="dtok-price-grid">
|
|
454
|
-
<div className="dtok-price-field"><label
|
|
454
|
+
<div className="dtok-price-field"><label>基准输入(缓存命中)</label>{num(r.cacheRead, (v) => patchRow(i, { cacheRead: v }))}</div>
|
|
455
|
+
<div className="dtok-price-field"><label>基准输入(缓存未命中)</label>{num(r.input, (v) => patchRow(i, { input: v }))}</div>
|
|
455
456
|
<div className="dtok-price-field"><label>基准输出</label>{num(r.output, (v) => patchRow(i, { output: v }))}</div>
|
|
456
|
-
<div className="dtok-price-field"><label>基准缓存命中</label>{num(r.cacheRead, (v) => patchRow(i, { cacheRead: v }))}</div>
|
|
457
457
|
<div className="dtok-price-field"><label>基准缓存写入</label>{num(r.cacheWrite, (v) => patchRow(i, { cacheWrite: v }))}</div>
|
|
458
458
|
</div>
|
|
459
|
+
<div className="dtok-price-hint" style={{ marginTop: 2 }}>
|
|
460
|
+
缓存写入=未命中缓存、本次新建缓存的那部分输入(Claude 等按溢价单独收建缓存费);DeepSeek 不收此项,填 0 即可。
|
|
461
|
+
</div>
|
|
459
462
|
<div className="dtok-price-hint" style={{ marginTop: 2 }}>
|
|
460
463
|
分时段价(可多段,命中哪段用哪段;时段外回落到基准价。start>end 表示跨零点,如 23~7;start=end 表示全天)
|
|
461
464
|
</div>
|
|
@@ -467,14 +470,14 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
467
470
|
<span className="dtok-pseg-tilde">~</span>
|
|
468
471
|
{num(s.end, (v) => patchSeg(i, k, { end: v }), { width: 56 })}
|
|
469
472
|
<span className="dtok-pseg-tilde">时</span>
|
|
470
|
-
{segNum(s.input, (v) => patchSeg(i, k, { input: v }), "输入")}
|
|
471
|
-
{segNum(s.output, (v) => patchSeg(i, k, { output: v }), "输出")}
|
|
472
473
|
{segNum(s.cacheRead, (v) => patchSeg(i, k, { cacheRead: v }), "缓存命中")}
|
|
473
|
-
{segNum(s.
|
|
474
|
+
{segNum(s.input, (v) => patchSeg(i, k, { input: v }), "未命中")}
|
|
475
|
+
{segNum(s.output, (v) => patchSeg(i, k, { output: v }), "输出")}
|
|
476
|
+
{segNum(s.cacheWrite, (v) => patchSeg(i, k, { cacheWrite: v }), "写入")}
|
|
474
477
|
<button className="dtok-btn tiny" onClick={() => delSeg(i, k)}>删除时段</button>
|
|
475
478
|
</div>
|
|
476
479
|
))}
|
|
477
|
-
<div className="dtok-price-hint" style={{ opacity: .85 }}
|
|
480
|
+
<div className="dtok-price-hint" style={{ opacity: .85 }}>时段价从左到右:输入(命中)/ 输入(未命中)/ 输出 / 缓存写入</div>
|
|
478
481
|
<button className="dtok-btn tiny" onClick={() => addSeg(i)}>+ 添加时段</button>
|
|
479
482
|
</div>
|
|
480
483
|
))}
|
|
@@ -492,9 +495,9 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
492
495
|
<div>
|
|
493
496
|
<div className="dtok-section-title" style={{ margin: "0 0 4px" }}>兜底单价(未匹配任何条目时使用)</div>
|
|
494
497
|
<div className="dtok-price-grid">
|
|
495
|
-
<div className="dtok-price-field"><label
|
|
498
|
+
<div className="dtok-price-field"><label>输入(缓存命中)</label>{num(fb.cacheRead, (v) => setFb((s) => Object.assign({}, s, { cacheRead: v })))}</div>
|
|
499
|
+
<div className="dtok-price-field"><label>输入(缓存未命中)</label>{num(fb.input, (v) => setFb((s) => Object.assign({}, s, { input: v })))}</div>
|
|
496
500
|
<div className="dtok-price-field"><label>输出</label>{num(fb.output, (v) => setFb((s) => Object.assign({}, s, { output: v })))}</div>
|
|
497
|
-
<div className="dtok-price-field"><label>缓存命中</label>{num(fb.cacheRead, (v) => setFb((s) => Object.assign({}, s, { cacheRead: v })))}</div>
|
|
498
501
|
<div className="dtok-price-field"><label>缓存写入</label>{num(fb.cacheWrite, (v) => setFb((s) => Object.assign({}, s, { cacheWrite: v })))}</div>
|
|
499
502
|
</div>
|
|
500
503
|
</div>
|
|
@@ -504,11 +507,11 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
504
507
|
<summary className="dtok-price-hint" style={{ cursor: "pointer" }}>查看内置默认单价({cfg.builtin.length} 条,自定义配置未命中时按此兜底)</summary>
|
|
505
508
|
<div className="dtok-table-wrap" style={{ marginTop: 6 }}>
|
|
506
509
|
<table className="dtok-table">
|
|
507
|
-
<thead><tr><th>匹配</th><th
|
|
510
|
+
<thead><tr><th>匹配</th><th>输入(命中)</th><th>输入(未命中)</th><th>输出</th><th>缓存写入</th><th>分时段</th></tr></thead>
|
|
508
511
|
<tbody>
|
|
509
512
|
{cfg.builtin.map((b) => (
|
|
510
513
|
<tr key={b.match}>
|
|
511
|
-
<td>{b.match}</td><td>{b.
|
|
514
|
+
<td>{b.match}</td><td>{b.cacheRead}</td><td>{b.input}</td><td>{b.output}</td><td>{b.cacheWrite}</td>
|
|
512
515
|
<td>{b.peaks && b.peaks.length ? b.peaks.map((s) => s.start + "~" + s.end).join("、") + "时" : "—"}</td>
|
|
513
516
|
</tr>
|
|
514
517
|
))}
|
|
@@ -528,8 +531,10 @@ function PricingEditor({ onClose, onSaved, embedded }) {
|
|
|
528
531
|
|
|
529
532
|
// ---------- 主视图(嵌入 dock 面板内容区) ----------
|
|
530
533
|
export function TokenLogView(props) {
|
|
531
|
-
// props.params.sessionId(chips
|
|
534
|
+
// props.params.sessionId(chips 点击带入):立即按该会话筛选并查询。
|
|
535
|
+
// navAt:每次 chip 点击的时间戳——面板已打开时再次点击(即便同一会话)也触发重查。
|
|
532
536
|
const navSession = props && props.params && props.params.sessionId ? props.params.sessionId : null;
|
|
537
|
+
const navAt = props && props.params && props.params.navAt ? props.params.navAt : 0;
|
|
533
538
|
// 挂载即视为「打开」:恢复上次暂存的条件(时间不选=显示全部记录); savedFilters 稳定快照, 仅初始化时读取一次
|
|
534
539
|
const [savedFilters] = useState(loadSavedFilters);
|
|
535
540
|
const [fromStr, setFromStr] = useState(() => (savedFilters && savedFilters.fromStr) || "");
|
|
@@ -538,7 +543,8 @@ export function TokenLogView(props) {
|
|
|
538
543
|
const [model, setModel] = useState(() => (savedFilters && savedFilters.model) || "");
|
|
539
544
|
const [status, setStatus] = useState(() => (savedFilters && savedFilters.status) || "");
|
|
540
545
|
const [effort, setEffort] = useState(() => (savedFilters && savedFilters.effort) || "");
|
|
541
|
-
|
|
546
|
+
// 会话入口(chip/深链)带入的 sessionId 优先于暂存条件:下拉框初值即选中该会话
|
|
547
|
+
const [sessionId, setSessionId] = useState(() => navSession || (savedFilters && savedFilters.sessionId) || "");
|
|
542
548
|
const [dim, setDim] = useState(() => (savedFilters && savedFilters.dim) || "");
|
|
543
549
|
const [sortKey, setSortKey] = useState("time");
|
|
544
550
|
const [sortDir, setSortDir] = useState("desc");
|
|
@@ -572,6 +578,9 @@ export function TokenLogView(props) {
|
|
|
572
578
|
if (savedFilters.sessionId) q.sessionId = savedFilters.sessionId;
|
|
573
579
|
if (savedFilters.dim) q.dim = savedFilters.dim;
|
|
574
580
|
}
|
|
581
|
+
// 从会话入口点入时按带入的会话查(优先于暂存条件):打开即出当前会话结果,
|
|
582
|
+
// 不再需要手动点「查询」。只保留这一条初始查询,避免并发的会话查询被本链路覆盖。
|
|
583
|
+
if (navSession) q.sessionId = navSession;
|
|
575
584
|
rpcCall("scan", {})
|
|
576
585
|
.then(() => (cancel ? null : rpcCall("query", q)))
|
|
577
586
|
.then((d) => {
|
|
@@ -606,16 +615,20 @@ export function TokenLogView(props) {
|
|
|
606
615
|
.finally(() => setLoading(false));
|
|
607
616
|
}, [buildQ]);
|
|
608
617
|
|
|
609
|
-
// chips
|
|
618
|
+
// chips 定位:面板已打开时再次从会话入口点击 → 立即按该会话筛选查询。
|
|
619
|
+
// 挂载时的首次带入已并入初始查询(sessionId 初值 + 挂载 effect),以 navAt 判同跳过,
|
|
620
|
+
// 避免打开面板时同一条件跑两遍、且挂载查询链路较慢把会话结果覆盖回全量。
|
|
621
|
+
const navAppliedRef = useRef(navAt);
|
|
610
622
|
useEffect(() => {
|
|
611
|
-
if (!navSession) return;
|
|
623
|
+
if (!navSession || navAppliedRef.current === navAt) return;
|
|
624
|
+
navAppliedRef.current = navAt;
|
|
612
625
|
setSessionId(navSession);
|
|
613
626
|
setLoading(true); setErr("");
|
|
614
627
|
rpcCall("query", Object.assign({}, buildQ(true), { sessionId: navSession }))
|
|
615
628
|
.then((d) => { setData(d); setPage(0); })
|
|
616
629
|
.catch((e) => setErr(String((e && e.message) || e)))
|
|
617
630
|
.finally(() => setLoading(false));
|
|
618
|
-
}, [
|
|
631
|
+
}, [navAt]);
|
|
619
632
|
|
|
620
633
|
// 重置: 清空所有筛选(时间不选=显示全部记录), 并立即查询
|
|
621
634
|
const resetFilters = useCallback(() => { setFromStr(""); setToStr("");
|
|
@@ -684,8 +697,8 @@ export function TokenLogView(props) {
|
|
|
684
697
|
const cards = totals ? [
|
|
685
698
|
{ v: fmtNum(totals.calls), l: "调用次数" },
|
|
686
699
|
{ v: fmtCompact(totals.totalTokens), l: "总 Token" },
|
|
687
|
-
{ v: fmtCompact(totals.
|
|
688
|
-
{ v: fmtCompact(totals.
|
|
700
|
+
{ v: fmtCompact(totals.cacheReadTokens), l: "输入(命中)" },
|
|
701
|
+
{ v: fmtCompact(totals.inputTokens), l: "输入(未命中)" },
|
|
689
702
|
{ v: totals.cacheHitPct + "%", l: "缓存命中率" },
|
|
690
703
|
{ v: fmtCompact(totals.outputTokens), l: "输出" },
|
|
691
704
|
{ v: fmtCostCny(totals.cost, rateCny), l: "消耗金额(估算·人民币)" },
|
|
@@ -702,8 +715,8 @@ export function TokenLogView(props) {
|
|
|
702
715
|
|
|
703
716
|
const summaryRows = (data && data.summary || []).map((r) => (
|
|
704
717
|
<tr key={r.key}>
|
|
705
|
-
<td>{r.key}</td><td>{fmtNum(r.calls)}</td><td>{fmtCompact(r.
|
|
706
|
-
<td>{fmtCompact(r.
|
|
718
|
+
<td>{r.key}</td><td>{fmtNum(r.calls)}</td><td>{fmtCompact(r.cacheReadTokens)}</td>
|
|
719
|
+
<td>{fmtCompact(r.inputTokens)}</td><td>{r.cacheHitPct + "%"}</td><td>{fmtCompact(r.outputTokens)}</td>
|
|
707
720
|
<td>{fmtCompact(r.totalTokens)}</td>
|
|
708
721
|
<td>{fmtCostCny(r.cost, rateCny)}</td>
|
|
709
722
|
<td>{fmtDuration(r.llmMs)}</td>
|
|
@@ -724,8 +737,8 @@ export function TokenLogView(props) {
|
|
|
724
737
|
<td><span className="dtok-sid" title="点击按此会话筛选" onClick={() => { setSessionId(r.sessionId); runQuery(); }}>{shortId(r.sessionId)}</span></td>
|
|
725
738
|
<td>{r.provider || "—"}</td>
|
|
726
739
|
<td>{r.model || "—"}</td>
|
|
727
|
-
<td>{fmtNum(r.inputTokens)}</td>
|
|
728
740
|
<td>{fmtNum(r.cacheReadTokens)}</td>
|
|
741
|
+
<td>{fmtNum(r.inputTokens)}</td>
|
|
729
742
|
<td>{r.cacheHitPercent + "%"}</td>
|
|
730
743
|
<td>{fmtNum(r.outputTokens)}</td>
|
|
731
744
|
<td>{fmtNum(r.reasoningTokens)}</td>
|
|
@@ -756,7 +769,7 @@ export function TokenLogView(props) {
|
|
|
756
769
|
<div key="sumtab" className="dtok-table-wrap">
|
|
757
770
|
<table className="dtok-table">
|
|
758
771
|
<thead><tr>
|
|
759
|
-
<th>维度</th><th>调用</th><th
|
|
772
|
+
<th>维度</th><th>调用</th><th>输入(命中)</th><th>输入(未命中)</th><th>命中率</th><th>输出</th><th>总Token</th><th>金额(人民币)</th><th>耗时</th>
|
|
760
773
|
</tr></thead>
|
|
761
774
|
<tbody>{summaryRows}</tbody>
|
|
762
775
|
</table>
|
|
@@ -788,7 +801,7 @@ export function TokenLogView(props) {
|
|
|
788
801
|
<table className="dtok-table">
|
|
789
802
|
<thead><tr>
|
|
790
803
|
{sortTh("时间", "time")}{sortTh("会话ID", "sessionId")}{sortTh("提供商", "provider")}{sortTh("模型", "model")}
|
|
791
|
-
{sortTh("输入", "
|
|
804
|
+
{sortTh("输入(命中)", "cacheReadTokens")}{sortTh("输入(未命中)", "inputTokens")}{sortTh("命中%", "cacheHitPercent")}{sortTh("输出", "outputTokens")}
|
|
792
805
|
{sortTh("推理", "reasoningTokens")}{sortTh("总额", "totalTokens")}{sortTh("金额(人民币)", "cost")}{sortTh("强度", "effort")}
|
|
793
806
|
{sortTh("状态", "status")}{sortTh("耗时", "llmMs")}
|
|
794
807
|
</tr></thead>
|
|
@@ -899,7 +912,7 @@ export function TokenLogChip(props) {
|
|
|
899
912
|
: (snap.err ? snap.err + "\n" : "") + "点击在功能坞查看用量记录";
|
|
900
913
|
return (
|
|
901
914
|
<button type="button" className={"dockchip" + (snap.err && !t ? " err" : "")} title={title} aria-label="会话用量"
|
|
902
|
-
onClick={() => openPanel("tokenlog", { sessionId: sid })}>
|
|
915
|
+
onClick={() => openPanel("tokenlog", { sessionId: sid, navAt: Date.now() })}>
|
|
903
916
|
<span className="dockchip-dot" style={{ background: "var(--dk-warn)" }} />
|
|
904
917
|
<span>{label}</span>
|
|
905
918
|
</button>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-dock",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "DeepSeek Harness 功能坞插件(dsh-dock):模块化功能中枢——每个功能一个 features/ 模块(可单独提取成包发布,又可经 dockBridge 装回面板)。含用量记录(LLM 调用记账/费用统计,支持各模型自定义单价与多段分时价)、模型设置、图片理解代理、模型余额、任务动画(19 种运行动画 + 桌面伙伴 3D 场景)、任务通知(完成/异常/需确认通知、提示音、系统通知、钉钉/飞书推送)、运行状态(进行中任务与最近完成一览);侧栏入口 + 可拖拽弹窗(最大化/最小化/缩放)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
package/src/client.jsx
CHANGED
|
@@ -30,7 +30,7 @@ import { feature as fGames } from "../features/games/view.jsx";
|
|
|
30
30
|
import { feature as fMobileRelay } from "../features/mobile-relay/view.jsx";
|
|
31
31
|
|
|
32
32
|
const name = "dsh-dock";
|
|
33
|
-
const DOCK_VERSION = "0.11.
|
|
33
|
+
const DOCK_VERSION = "0.11.2";
|
|
34
34
|
|
|
35
35
|
// ---- 内置功能注册表:新功能 = features/<id>/ 加模块 + 这里 import 一行 ----
|
|
36
36
|
const BUILTIN_FEATURES = [fTokenlog, fModelconfig, fHeartbeat, fTheme, fBalance, fAnimation, fNotify, fRunState, fGames, fMobileRelay];
|
|
@@ -206,11 +206,14 @@ const SHELL_CSS = [
|
|
|
206
206
|
// 注意:旧上限 min(280px,36cqw) 仍偏宽——标准 780px 输入卡下(.row 内容约 762px),
|
|
207
207
|
// add 钮(28)+工作区选择器(~214)+chips(280) 已与右侧模型选择器+发送键(~345px)合计超宽,
|
|
208
208
|
// 即便 chips 未截断 .row 也会换行把模型选择器/发送键挤到第二行。实测把上限收到 189px
|
|
209
|
-
// (≈25cqw)并使 chips 内距收紧(padding 2px 6px、gap 2px
|
|
210
|
-
// 两 chip
|
|
209
|
+
// (≈25cqw)并使 chips 内距收紧(padding 2px 6px、gap 2px)后,「4~6M 用量 + 余额」
|
|
210
|
+
// 两 chip 可完整显示且不再换行。v0.11.2:配置单价后费用段「· ¥0.03」让两 chip 合计
|
|
211
|
+
// 约需 204px,189px 恰好截掉约 2 个数字(费用/余额小数位看不到)——按用户反馈放宽到
|
|
212
|
+
// 216px(≈28cqw),标准卡下实测完整显示;若再出现把模型选择器挤换行,优先压缩用量
|
|
213
|
+
// chip 的 ⛁ 前缀换空间,别再收这个上限。超限仍省略号截断,完整值在 title 悬浮提示里。
|
|
211
214
|
// 2) 截断:超限部分用省略号截断(完整数值在 title 悬浮提示里),防 chips 凸出输入卡圆角(悬空)。
|
|
212
|
-
".dockchip-row{display:inline-flex;align-items:center;gap:2px;min-width:0;flex:0 1 auto;overflow:hidden;max-width:
|
|
213
|
-
"@supports (width:1cqw){.dockchip-row{max-width:min(
|
|
215
|
+
".dockchip-row{display:inline-flex;align-items:center;gap:2px;min-width:0;flex:0 1 auto;overflow:hidden;max-width:216px;}",
|
|
216
|
+
"@supports (width:1cqw){.dockchip-row{max-width:min(216px,28cqw);}}",
|
|
214
217
|
".dockchip{display:inline-flex;align-items:center;gap:5px;cursor:pointer;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);border-radius:8px;padding:2px 6px;font-family:inherit;font-size:11px;line-height:18px;white-space:nowrap;min-width:0;overflow:hidden;transition:background .15s var(--ds-ease-in-out),color .15s var(--ds-ease-in-out);}",
|
|
215
218
|
".dockchip > span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}",
|
|
216
219
|
".dockchip:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
|