Collapse daily stats by default.

Show only total floating PnL until expanded; enlarge details and lower exchange headers.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-16 14:31:00 +08:00
parent 35b23836e3
commit 4e86595f2a
4 changed files with 134 additions and 33 deletions
+26
View File
@@ -4,6 +4,32 @@
--- ---
## 2026-07-16 · 今日统计默认折叠 + 交易所标题行下移
### 修改原因
今日统计常占一行挤空间;默认只需看总浮盈亏。交易所卡标题/打开实例贴顶过紧。
### 修改的地方
| 文件 | 改动摘要 |
|------|----------|
| `manual_trading_hub/static/app.js` | 今日统计默认折叠只露总浮盈亏;展开显示明细;状态写入 localStorage |
| `manual_trading_hub/static/app.css` | 折叠/展开样式;展开后明细字号加大;分栏卡 `card-head` 上内边距加大 |
| `manual_trading_hub/static/index.html` | 缓存 `20260716-hub-stats-fold` |
### 达成的目标
监控区默认更省高;需要时一键展开更大明细;交易所标识行不再贴顶。
### 交付之后的验收
1. 默认只见「今日统计 + 总浮盈亏」与「展开明细」。
2. 点展开后六项明细可见且数字更大。
3. OKX/币安等卡标题与按钮相对顶边有更明显间距。
---
## 2026-07-16 · 监控芯片还原 + 底栏贴底 + 1080p 留白 ## 2026-07-16 · 监控芯片还原 + 底栏贴底 + 1080p 留白
### 修改原因 ### 修改原因
+62 -20
View File
@@ -1205,20 +1205,62 @@ html[data-theme="light"] .host-metric-bar {
.grid-monitor.grid-monitor-options-split .monitor-stats-card { .grid-monitor.grid-monitor-options-split .monitor-stats-card {
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: row; flex-direction: column;
align-items: center; align-items: stretch;
gap: 14px 18px; gap: 0;
padding: 8px 14px; padding: 8px 14px;
} }
.grid-monitor.grid-monitor-options-split .monitor-stats-card .card-head { .grid-monitor.grid-monitor-options-split .monitor-stats-card .card-head,
.monitor-stats-card .monitor-stats-head {
padding: 0; padding: 0;
border-bottom: none; border-bottom: none;
flex: 0 0 auto; flex: 0 0 auto;
width: 100%;
align-items: center;
}
.monitor-stats-head-main {
min-width: 0;
flex: 1 1 auto;
}
.monitor-stats-float-summary {
flex: 0 0 auto;
text-align: right;
padding: 2px 4px 2px 12px;
}
.monitor-stats-float-summary .monitor-stat-label {
margin-bottom: 0;
font-size: 11px;
}
.monitor-stats-float-value {
font-size: 18px;
font-weight: 700;
line-height: 1.2;
}
.btn-monitor-stats-toggle {
font-size: 11px;
padding: 2px 8px;
min-height: 0;
line-height: 1.3;
color: var(--accent);
border-color: var(--border-soft);
}
.monitor-stats-card.is-collapsed .monitor-stats-detail {
display: none;
}
.monitor-stats-card:not(.is-collapsed) .monitor-stats-float-summary {
display: none;
} }
.grid-monitor.grid-monitor-options-split .monitor-stats-card .card-body { .grid-monitor.grid-monitor-options-split .monitor-stats-card .card-body {
padding: 0; padding: 8px 0 0;
flex: 1; flex: 1;
min-width: 0; min-width: 0;
} }
@@ -1236,31 +1278,32 @@ html[data-theme="light"] .host-metric-bar {
.grid-monitor.grid-monitor-options-split .monitor-stats-grid { .grid-monitor.grid-monitor-options-split .monitor-stats-grid {
display: grid; display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr)); grid-template-columns: repeat(6, minmax(0, 1fr));
gap: 8px; gap: 10px;
width: 100%; width: 100%;
} }
.grid-monitor.grid-monitor-options-split .monitor-stat-cell { .grid-monitor.grid-monitor-options-split .monitor-stat-cell {
padding: 5px 6px 4px; padding: 10px 8px 8px;
border-radius: 8px; border-radius: 8px;
min-width: 0; min-width: 0;
text-align: center; text-align: center;
} }
.grid-monitor.grid-monitor-options-split .monitor-stat-label { .grid-monitor.grid-monitor-options-split .monitor-stat-label {
font-size: 10px; font-size: 11px;
margin-bottom: 2px; margin-bottom: 4px;
} }
.grid-monitor.grid-monitor-options-split .monitor-stat-value { .grid-monitor.grid-monitor-options-split .monitor-stat-value {
font-size: 14px; font-size: 18px;
line-height: 1.2; line-height: 1.25;
font-weight: 700;
} }
.grid-monitor.grid-monitor-options-split .monitor-stat-sub { .grid-monitor.grid-monitor-options-split .monitor-stat-sub {
margin-top: 1px; margin-top: 3px;
font-size: 10px; font-size: 11px;
line-height: 1.2; line-height: 1.25;
} }
.monitor-split-body { .monitor-split-body {
@@ -9940,20 +9983,19 @@ html[data-theme="light"] .hub-logs-card-hint {
body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-stats-card { body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-stats-card {
flex: 0 0 auto; flex: 0 0 auto;
padding: 5px 10px; padding: 8px 14px;
gap: 10px 14px;
} }
body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-stats-grid { body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-stats-grid {
gap: 6px; gap: 10px;
} }
body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-stat-cell { body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-stat-cell {
padding: 3px 4px; padding: 10px 8px 8px;
} }
body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-stat-value { body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-stat-value {
font-size: 13px; font-size: 18px;
} }
body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-split-body { body.hub-page-monitor:not(.hub-phone) .grid-monitor-options-split .monitor-split-body {
@@ -9991,7 +10033,7 @@ html[data-theme="light"] .hub-logs-card-hint {
body.hub-page-monitor:not(.hub-phone) .card-monitor-okx-split .card-head, body.hub-page-monitor:not(.hub-phone) .card-monitor-okx-split .card-head,
body.hub-page-monitor:not(.hub-phone) .card-monitor-split-side .card-head { body.hub-page-monitor:not(.hub-phone) .card-monitor-split-side .card-head {
padding: 6px 10px; padding: 12px 14px 10px;
} }
body.hub-page-monitor:not(.hub-phone) .card-monitor-okx-split .card-body, body.hub-page-monitor:not(.hub-phone) .card-monitor-okx-split .card-body,
+44 -11
View File
@@ -2346,12 +2346,34 @@
return (n > 0 ? "+" : "-") + abs; return (n > 0 ? "+" : "-") + abs;
} }
const MONITOR_STATS_FOLD_KEY = "hub_monitor_stats_collapsed";
function isMonitorStatsCollapsed() {
try {
const v = localStorage.getItem(MONITOR_STATS_FOLD_KEY);
if (v === null || v === "") return true;
return v === "1";
} catch (_e) {
return true;
}
}
function setMonitorStatsCollapsed(collapsed) {
try {
localStorage.setItem(MONITOR_STATS_FOLD_KEY, collapsed ? "1" : "0");
} catch (_e) {
/* ignore */
}
}
function renderMonitorStatsCard(totals) { function renderMonitorStatsCard(totals) {
const t = totals || {}; const t = totals || {};
const day = t.trading_day || "—"; const day = t.trading_day || "—";
const resetH = t.reset_hour != null ? t.reset_hour : 8; const resetH = t.reset_hour != null ? t.reset_hour : 8;
const winN = Number(t.win_count) || 0; const winN = Number(t.win_count) || 0;
const lossN = Number(t.loss_count) || 0; const lossN = Number(t.loss_count) || 0;
const floatVal = Number(t.float_pnl_u);
const collapsed = isMonitorStatsCollapsed();
function cell(label, main, sub, valCls) { function cell(label, main, sub, valCls) {
return `<div class="monitor-stat-cell"> return `<div class="monitor-stat-cell">
<div class="monitor-stat-label">${esc(label)}</div> <div class="monitor-stat-label">${esc(label)}</div>
@@ -2367,29 +2389,31 @@
lossN > 0 && Number.isFinite(Number(t.loss_pnl_u)) lossN > 0 && Number.isFinite(Number(t.loss_pnl_u))
? `<span class="${pnlCls(t.loss_pnl_u)}">${esc(pnlSigned(t.loss_pnl_u, 2))}U</span>` ? `<span class="${pnlCls(t.loss_pnl_u)}">${esc(pnlSigned(t.loss_pnl_u, 2))}U</span>`
: "—"; : "—";
const floatVal = Number(t.float_pnl_u); const floatMain = esc(pnlSigned(floatVal, 2)) + "U";
return `<div class="card card-online monitor-stats-card" data-monitor-stats="1"> const floatCls = Math.abs(floatVal) > 1e-9 ? pnlCls(floatVal) : "";
<div class="card-head"> const foldLabel = collapsed ? "展开明细" : "收起";
<div> return `<div class="card card-online monitor-stats-card${collapsed ? " is-collapsed" : ""}" data-monitor-stats="1">
<div class="card-head monitor-stats-head">
<div class="monitor-stats-head-main">
<div class="card-title-row"> <div class="card-title-row">
<div class="card-title">今日统计</div> <div class="card-title">今日统计</div>
<button type="button" class="ghost btn-monitor-stats-toggle" aria-expanded="${collapsed ? "false" : "true"}">${foldLabel}</button>
</div> </div>
<div class="card-sub">交易日 ${esc(day)} · 北京时间 ${esc(String(resetH))}:00 切日</div> <div class="card-sub">交易日 ${esc(day)} · 北京时间 ${esc(String(resetH))}:00 切日</div>
</div> </div>
<div class="monitor-stats-float-summary">
<div class="monitor-stat-label">总浮盈亏</div>
<div class="monitor-stat-value monitor-stats-float-value ${floatCls}">${floatMain}</div>
</div>
</div> </div>
<div class="card-body"> <div class="card-body monitor-stats-detail">
<div class="monitor-stats-grid"> <div class="monitor-stats-grid">
${cell("今日开仓", String(Number(t.open_count) || 0), "含未平", "")} ${cell("今日开仓", String(Number(t.open_count) || 0), "含未平", "")}
${cell("今日平仓", String(Number(t.closed_count) || 0), "", "")} ${cell("今日平仓", String(Number(t.closed_count) || 0), "", "")}
${cell("持有仓位", String(Number(t.open_position_count) || 0), "", "")} ${cell("持有仓位", String(Number(t.open_position_count) || 0), "", "")}
${cell("盈利", String(winN), winSub, winN > 0 ? "pnl-pos" : "")} ${cell("盈利", String(winN), winSub, winN > 0 ? "pnl-pos" : "")}
${cell("亏损", String(lossN), lossSub, lossN > 0 ? "pnl-neg" : "")} ${cell("亏损", String(lossN), lossSub, lossN > 0 ? "pnl-neg" : "")}
${cell( ${cell("总浮盈亏", floatMain, "", floatCls)}
"总浮盈亏",
esc(pnlSigned(floatVal, 2)) + "U",
"",
Math.abs(floatVal) > 1e-9 ? pnlCls(floatVal) : ""
)}
</div> </div>
</div> </div>
</div>`; </div>`;
@@ -2809,6 +2833,15 @@
} }
function bindMonitorInteractions(box) { function bindMonitorInteractions(box) {
box.querySelectorAll(".btn-monitor-stats-toggle").forEach((btn) => {
btn.onclick = (ev) => {
ev.preventDefault();
ev.stopPropagation();
const next = !isMonitorStatsCollapsed();
setMonitorStatsCollapsed(next);
if (lastMonitorRows) renderMonitorGrid(lastMonitorRows);
};
});
box.querySelectorAll(".btn-open-market").forEach((btn) => { box.querySelectorAll(".btn-open-market").forEach((btn) => {
btn.onclick = (ev) => { btn.onclick = (ev) => {
ev.preventDefault(); ev.preventDefault();
+2 -2
View File
@@ -15,7 +15,7 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" media="print" onload="this.media='all'" /> <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" media="print" onload="this.media='all'" />
<noscript><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" /></noscript> <noscript><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" /></noscript>
<link rel="stylesheet" href="/assets/app.css?v=20260716-hub-chips-margin" /> <link rel="stylesheet" href="/assets/app.css?v=20260716-hub-stats-fold" />
<link rel="stylesheet" href="/assets/trade_stats_calendar.css?v=4" /> <link rel="stylesheet" href="/assets/trade_stats_calendar.css?v=4" />
<link rel="stylesheet" href="/assets/account_risk_badge.css?v=4" /> <link rel="stylesheet" href="/assets/account_risk_badge.css?v=4" />
<script src="/assets/account_risk_badge.js?v=4"></script> <script src="/assets/account_risk_badge.js?v=4"></script>
@@ -1327,6 +1327,6 @@
<script src="/assets/options_expiry_countdown.js?v=1"></script> <script src="/assets/options_expiry_countdown.js?v=1"></script>
<script src="/assets/options_position_cards.js?v=1"></script> <script src="/assets/options_position_cards.js?v=1"></script>
<script src="/assets/backup.js?v=1"></script> <script src="/assets/backup.js?v=1"></script>
<script src="/assets/app.js?v=20260716-hub-chips-margin"></script> <script src="/assets/app.js?v=20260716-hub-stats-fold"></script>
</body> </body>
</html> </html>