Add display toggles to hide monitor cards and strategy tabs.

Keep unused exchanges/docs out of the UI without disabling accounts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-24 00:24:00 +08:00
parent 29d59d6a53
commit 6f1ae14b3d
7 changed files with 367 additions and 200 deletions
+24 -5
View File
@@ -236,11 +236,30 @@ def load_strategy_payload(exchange_key: str) -> dict[str, Any]:
}
def strategy_meta_payload() -> dict[str, Any]:
tabs = [
{"key": k, "label": STRATEGY_META[k]["label"], "title": STRATEGY_META[k]["title"]}
for k in STRATEGY_EXCHANGES
]
_STRATEGY_TAB_DISPLAY_PREF: dict[str, str] = {
"playbook_v2": "show_strategy_playbook_v2",
"playbook": "show_strategy_playbook",
"behavior": "show_strategy_behavior",
"binance": "show_strategy_binance",
"okx": "show_strategy_okx",
"gate": "show_strategy_gate",
}
def strategy_meta_payload(display: dict[str, Any] | None = None) -> dict[str, Any]:
prefs = display if isinstance(display, dict) else {}
tabs = []
for k in STRATEGY_EXCHANGES:
pref_key = _STRATEGY_TAB_DISPLAY_PREF.get(k)
if pref_key and prefs.get(pref_key) is False:
continue
tabs.append(
{
"key": k,
"label": STRATEGY_META[k]["label"],
"title": STRATEGY_META[k]["title"],
}
)
return {"ok": True, "exchanges": tabs}
+12 -1
View File
@@ -1119,6 +1119,16 @@ class SettingsDisplayBody(BaseModel):
show_nav_amp_stats: bool = True
show_nav_help: bool = True
show_nav_logs: bool = True
show_monitor_binance: bool = True
show_monitor_okx_perp: bool = True
show_monitor_okx_options: bool = True
show_monitor_gate: bool = True
show_strategy_playbook_v2: bool = True
show_strategy_playbook: bool = True
show_strategy_behavior: bool = True
show_strategy_binance: bool = True
show_strategy_okx: bool = True
show_strategy_gate: bool = True
class SupervisorSettingsBody(BaseModel):
@@ -3348,7 +3358,8 @@ async def api_archive_sync():
@app.get("/api/strategy/meta")
def api_strategy_meta():
return strategy_meta_payload()
display = (load_settings() or {}).get("display") or {}
return strategy_meta_payload(display)
@app.get("/api/help/meta")
+12
View File
@@ -34,6 +34,18 @@ DEFAULT_DISPLAY = {
"show_nav_amp_stats": True,
"show_nav_help": True,
"show_nav_logs": True,
# 监控区卡片(仅隐藏界面,不关闭账户)
"show_monitor_binance": True,
"show_monitor_okx_perp": True,
"show_monitor_okx_options": True,
"show_monitor_gate": True,
# 策略说明页签
"show_strategy_playbook_v2": True,
"show_strategy_playbook": True,
"show_strategy_behavior": True,
"show_strategy_binance": True,
"show_strategy_okx": True,
"show_strategy_gate": True,
}
DEFAULT_EXCHANGES = [
+127 -115
View File
@@ -3501,6 +3501,18 @@ button.btn-sm {
margin-top: 8px;
}
.settings-display-subtitle {
margin: 16px 0 6px;
font-size: 0.82rem;
font-weight: 600;
color: var(--text);
}
.settings-display-subtitle + .settings-display-hint {
margin-top: 0;
margin-bottom: 8px;
}
.settings-display-hint {
margin: 8px 0 0;
font-size: 0.78rem;
@@ -11008,118 +11020,118 @@ html[data-theme="light"] .hub-logs-card-hint {
.amp-form { grid-template-columns: 1fr 1fr; }
.amp-actions { grid-column: 1 / -1; }
}
/* --- strategy compare --- */
#page-compare .toolbar {
padding: 12px 16px;
margin-bottom: 14px;
}
.cmp-form { display: flex; flex-direction: column; gap: 14px; margin-bottom: 16px; }
.cmp-form .card,
.cmp-common-card,
.cmp-sum-card,
.cmp-rec-card {
padding: 18px 20px;
}
.cmp-common-card h2,
.cmp-form .card h2 {
margin: 0 0 14px;
font-size: 15px;
}
.cmp-subhead {
margin: 16px 0 10px;
font-size: 13px;
color: var(--muted);
font-weight: 600;
}
.cmp-form-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px 16px;
}
.cmp-field {
display: flex;
flex-direction: column;
gap: 6px;
font-size: 12px;
color: var(--muted);
}
.cmp-field input,
.cmp-field select {
background: var(--inset-surface);
border: 1px solid var(--border-soft);
border-radius: 8px;
color: var(--text);
padding: 9px 12px;
font-size: 13px;
}
.cmp-input-cols {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.cmp-summary {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
margin-bottom: 16px;
}
.cmp-sum-card h3 { margin: 0 0 12px; font-size: 14px; }
.cmp-sum-row {
display: flex;
justify-content: space-between;
gap: 12px;
font-size: 12px;
margin: 6px 0;
color: var(--muted);
}
.cmp-sum-row strong { color: var(--text); font-weight: 600; }
.cmp-muted { color: var(--muted); font-size: 12px; margin: 0; }
.cmp-table-wrap { margin-bottom: 16px; }
.cmp-table-scroll { overflow-x: auto; }
.cmp-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
font-size: 13px;
background: var(--panel);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
.cmp-table th,
.cmp-table td {
border-bottom: 1px solid var(--border-soft);
padding: 14px 16px;
vertical-align: top;
text-align: left;
}
.cmp-table th:first-child,
.cmp-table td:first-child { width: 22%; }
.cmp-table tr:last-child td { border-bottom: none; }
.cmp-cell-note {
margin-top: 6px;
font-size: 11px;
color: var(--muted);
line-height: 1.4;
}
.cmp-pnl-pos { color: var(--green); font-weight: 600; }
.cmp-pnl-neg { color: var(--red); font-weight: 600; }
.cmp-rec-head { font-size: 16px; margin-bottom: 8px; }
.cmp-rec-reason { margin: 0 0 10px; color: var(--muted); font-size: 13px; }
.cmp-rec-list { margin: 0; padding-left: 20px; font-size: 13px; line-height: 1.55; }
.cmp-warn { margin-top: 12px; font-size: 12px; color: var(--warn, #e6a23c); }
.cmp-foot-note { margin: 12px 0 0; font-size: 11px; color: var(--muted); }
@media (max-width: 900px) {
.cmp-form .card,
.cmp-common-card,
.cmp-sum-card,
.cmp-rec-card {
padding: 16px;
}
.cmp-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cmp-input-cols,
.cmp-summary { grid-template-columns: 1fr; }
.cmp-table th,
.cmp-table td { padding: 12px 14px; }
}
/* --- strategy compare --- */
#page-compare .toolbar {
padding: 12px 16px;
margin-bottom: 14px;
}
.cmp-form { display: flex; flex-direction: column; gap: 14px; margin-bottom: 16px; }
.cmp-form .card,
.cmp-common-card,
.cmp-sum-card,
.cmp-rec-card {
padding: 18px 20px;
}
.cmp-common-card h2,
.cmp-form .card h2 {
margin: 0 0 14px;
font-size: 15px;
}
.cmp-subhead {
margin: 16px 0 10px;
font-size: 13px;
color: var(--muted);
font-weight: 600;
}
.cmp-form-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px 16px;
}
.cmp-field {
display: flex;
flex-direction: column;
gap: 6px;
font-size: 12px;
color: var(--muted);
}
.cmp-field input,
.cmp-field select {
background: var(--inset-surface);
border: 1px solid var(--border-soft);
border-radius: 8px;
color: var(--text);
padding: 9px 12px;
font-size: 13px;
}
.cmp-input-cols {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.cmp-summary {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
margin-bottom: 16px;
}
.cmp-sum-card h3 { margin: 0 0 12px; font-size: 14px; }
.cmp-sum-row {
display: flex;
justify-content: space-between;
gap: 12px;
font-size: 12px;
margin: 6px 0;
color: var(--muted);
}
.cmp-sum-row strong { color: var(--text); font-weight: 600; }
.cmp-muted { color: var(--muted); font-size: 12px; margin: 0; }
.cmp-table-wrap { margin-bottom: 16px; }
.cmp-table-scroll { overflow-x: auto; }
.cmp-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
font-size: 13px;
background: var(--panel);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
.cmp-table th,
.cmp-table td {
border-bottom: 1px solid var(--border-soft);
padding: 14px 16px;
vertical-align: top;
text-align: left;
}
.cmp-table th:first-child,
.cmp-table td:first-child { width: 22%; }
.cmp-table tr:last-child td { border-bottom: none; }
.cmp-cell-note {
margin-top: 6px;
font-size: 11px;
color: var(--muted);
line-height: 1.4;
}
.cmp-pnl-pos { color: var(--green); font-weight: 600; }
.cmp-pnl-neg { color: var(--red); font-weight: 600; }
.cmp-rec-head { font-size: 16px; margin-bottom: 8px; }
.cmp-rec-reason { margin: 0 0 10px; color: var(--muted); font-size: 13px; }
.cmp-rec-list { margin: 0; padding-left: 20px; font-size: 13px; line-height: 1.55; }
.cmp-warn { margin-top: 12px; font-size: 12px; color: var(--warn, #e6a23c); }
.cmp-foot-note { margin: 12px 0 0; font-size: 11px; color: var(--muted); }
@media (max-width: 900px) {
.cmp-form .card,
.cmp-common-card,
.cmp-sum-card,
.cmp-rec-card {
padding: 16px;
}
.cmp-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cmp-input-cols,
.cmp-summary { grid-template-columns: 1fr; }
.cmp-table th,
.cmp-table td { padding: 12px 14px; }
}
+125 -74
View File
@@ -9,12 +9,42 @@
return !!d[key];
}
window.hubDisplayPref = displayPref;
function showAccountPnlPref() {
return displayPref("show_account_pnl", true);
}
window.hubShowAccountPnlPref = showAccountPnlPref;
function showMonitorBinancePref() {
return displayPref("show_monitor_binance", true);
}
function showMonitorOkxPerpPref() {
return displayPref("show_monitor_okx_perp", true);
}
function showMonitorOkxOptionsPref() {
return displayPref("show_monitor_okx_options", true);
}
function showMonitorGatePref() {
return displayPref("show_monitor_gate", true);
}
function monitorExchangeKeyVisible(key) {
const k = String(key || "").toLowerCase();
if (k === "binance") return showMonitorBinancePref();
if (k === "gate") return showMonitorGatePref();
if (k === "okx") return showMonitorOkxPerpPref() || showMonitorOkxOptionsPref();
return true;
}
function filterVisibleMonitorRows(rows) {
return (rows || []).filter((r) => monitorExchangeKeyVisible(r && r.key));
}
function showNavFundsPref() {
return displayPref("show_nav_funds", true);
}
@@ -157,32 +187,33 @@
function syncDisplayPrefsUI(data) {
const d = (data && data.display) || {};
const pnlCb = document.getElementById("pref-show-account-pnl");
const fundsCb = document.getElementById("pref-show-nav-funds");
const dashCb = document.getElementById("pref-show-nav-dashboard");
const planCb = document.getElementById("pref-show-nav-plan");
const archiveCb = document.getElementById("pref-show-nav-archive");
const quotesCb = document.getElementById("pref-show-nav-quotes");
const aiCb = document.getElementById("pref-show-nav-ai");
const calcCb = document.getElementById("pref-show-nav-calculator");
const compareCb = document.getElementById("pref-show-nav-compare");
const strategyCb = document.getElementById("pref-show-nav-strategy");
const ampCb = document.getElementById("pref-show-nav-amp-stats");
const helpCb = document.getElementById("pref-show-nav-help");
const logsCb = document.getElementById("pref-show-nav-logs");
if (pnlCb) pnlCb.checked = d.show_account_pnl !== false;
if (fundsCb) fundsCb.checked = d.show_nav_funds !== false;
if (dashCb) dashCb.checked = d.show_nav_dashboard !== false;
if (planCb) planCb.checked = d.show_nav_plan !== false;
if (archiveCb) archiveCb.checked = d.show_nav_archive !== false;
if (quotesCb) quotesCb.checked = d.show_nav_quotes !== false;
if (aiCb) aiCb.checked = d.show_nav_ai !== false;
if (calcCb) calcCb.checked = d.show_nav_calculator !== false;
if (compareCb) compareCb.checked = d.show_nav_compare !== false;
if (strategyCb) strategyCb.checked = d.show_nav_strategy !== false;
if (ampCb) ampCb.checked = d.show_nav_amp_stats !== false;
if (helpCb) helpCb.checked = d.show_nav_help !== false;
if (logsCb) logsCb.checked = d.show_nav_logs !== false;
const setChk = (id, key) => {
const el = document.getElementById(id);
if (el) el.checked = d[key] !== false;
};
setChk("pref-show-account-pnl", "show_account_pnl");
setChk("pref-show-nav-funds", "show_nav_funds");
setChk("pref-show-nav-dashboard", "show_nav_dashboard");
setChk("pref-show-nav-plan", "show_nav_plan");
setChk("pref-show-nav-archive", "show_nav_archive");
setChk("pref-show-nav-quotes", "show_nav_quotes");
setChk("pref-show-nav-ai", "show_nav_ai");
setChk("pref-show-nav-calculator", "show_nav_calculator");
setChk("pref-show-nav-compare", "show_nav_compare");
setChk("pref-show-nav-strategy", "show_nav_strategy");
setChk("pref-show-nav-amp-stats", "show_nav_amp_stats");
setChk("pref-show-nav-help", "show_nav_help");
setChk("pref-show-nav-logs", "show_nav_logs");
setChk("pref-show-monitor-binance", "show_monitor_binance");
setChk("pref-show-monitor-okx-perp", "show_monitor_okx_perp");
setChk("pref-show-monitor-okx-options", "show_monitor_okx_options");
setChk("pref-show-monitor-gate", "show_monitor_gate");
setChk("pref-show-strategy-playbook-v2", "show_strategy_playbook_v2");
setChk("pref-show-strategy-playbook", "show_strategy_playbook");
setChk("pref-show-strategy-behavior", "show_strategy_behavior");
setChk("pref-show-strategy-binance", "show_strategy_binance");
setChk("pref-show-strategy-okx", "show_strategy_okx");
setChk("pref-show-strategy-gate", "show_strategy_gate");
syncNavVisibility(data);
}
@@ -1569,7 +1600,7 @@
if (upd) upd.textContent = txt;
if (updSum) updSum.textContent = txt;
}
updateMonitorAlertSummary(rows || []);
updateMonitorAlertSummary(filterVisibleMonitorRows(rows || []));
void refreshMacroRiskBanner(rows || []);
renderMonitorGrid(rows || []);
}
@@ -2080,19 +2111,20 @@
if (lastMonitorRows.length && nowMobile !== wasMobile) {
wasMobile = nowMobile;
renderMonitorGrid(lastMonitorRows);
updateMonitorAlertSummary(lastMonitorRows);
updateMonitorAlertSummary(filterVisibleMonitorRows(lastMonitorRows));
syncHubMobileTabActive(currentPage());
return;
}
wasMobile = nowMobile;
const box = document.getElementById("monitor-grid");
if (box && lastMonitorRows.length) {
const split = monitorOptionsSplitActive(lastMonitorRows);
syncMonitorGridColumns(box, lastMonitorRows.length + (lastMonitorTotals ? 1 : 0), {
const visible = filterVisibleMonitorRows(lastMonitorRows);
const split = monitorOptionsSplitActive(visible);
syncMonitorGridColumns(box, visible.length + (lastMonitorTotals ? 1 : 0), {
statsFirst: !!lastMonitorTotals && !split,
optionsSplit: split,
});
updateMonitorAlertSummary(lastMonitorRows);
updateMonitorAlertSummary(visible);
}
syncHubMobileTabActive(currentPage());
}, 120);
@@ -2486,11 +2518,12 @@
const fs = document.getElementById("exchange-fullscreen");
const fsInner = document.getElementById("exchange-fullscreen-inner");
if (!box) return;
if (expandedExchangeId && !rows.some((r) => String(r.id) === String(expandedExchangeId))) {
const visibleSource = filterVisibleMonitorRows(rows);
if (expandedExchangeId && !visibleSource.some((r) => String(r.id) === String(expandedExchangeId))) {
closeExchangeFullscreen();
}
const mobileTiles = isMobileLayout() && !expandedExchangeId;
const displayRows = mobileTiles ? sortRowsForMobileDashboard(rows) : rows;
const displayRows = mobileTiles ? sortRowsForMobileDashboard(visibleSource) : visibleSource;
const optionsSplit = monitorOptionsSplitActive(displayRows);
monitorGridOptionsSplit = optionsSplit;
const showStatsCard = !expandedExchangeId;
@@ -2503,20 +2536,33 @@
let cardsHtml = "";
if (optionsSplit) {
const okxRow = displayRows.find((r) => rowHasOptionsLayout(r));
const otherRows = displayRows.filter((r) => !rowHasOptionsLayout(r));
const ph =
'<div class="card card-monitor-split-side card-monitor-placeholder" aria-hidden="true"></div>';
/* 平铺 2×2 顺序:永续|币安 / 期权|Gate —— 同行左右同高,多仓时该行一起长高 */
const cells = [
okxRow ? renderMonitorCard(okxRow, { okxPart: "perp", splitSide: true }) : ph,
otherRows[0] ? renderMonitorCard(otherRows[0], { splitSide: true }) : ph,
okxRow ? renderMonitorCard(okxRow, { okxPart: "options", splitSide: true }) : ph,
otherRows[1] ? renderMonitorCard(otherRows[1], { splitSide: true }) : ph,
];
for (let i = 2; i < otherRows.length; i++) {
cells.push(renderMonitorCard(otherRows[i], { splitSide: true }));
const otherByKey = {};
displayRows
.filter((r) => !rowHasOptionsLayout(r))
.forEach((r) => {
otherByKey[String(r.key || "").toLowerCase()] = r;
});
/* 平铺顺序尽量保持:永续|币安 / 期权|Gate;隐藏项不占位 */
const cells = [];
if (okxRow && showMonitorOkxPerpPref()) {
cells.push(renderMonitorCard(okxRow, { okxPart: "perp", splitSide: true }));
}
cardsHtml = `<div class="monitor-split-body monitor-split-2x2">${cells.join("")}</div>`;
if (otherByKey.binance && showMonitorBinancePref()) {
cells.push(renderMonitorCard(otherByKey.binance, { splitSide: true }));
}
if (okxRow && showMonitorOkxOptionsPref()) {
cells.push(renderMonitorCard(okxRow, { okxPart: "options", splitSide: true }));
}
if (otherByKey.gate && showMonitorGatePref()) {
cells.push(renderMonitorCard(otherByKey.gate, { splitSide: true }));
}
Object.keys(otherByKey).forEach((k) => {
if (k === "binance" || k === "gate") return;
cells.push(renderMonitorCard(otherByKey[k], { splitSide: true }));
});
cardsHtml = cells.length
? `<div class="monitor-split-body monitor-split-2x2">${cells.join("")}</div>`
: "";
} else {
cardsHtml =
displayRows
@@ -2545,7 +2591,7 @@
}
if (expandedExchangeId && fs && fsInner) {
const row = rows.find((r) => String(r.id) === String(expandedExchangeId));
const row = visibleSource.find((r) => String(r.id) === String(expandedExchangeId));
if (row) {
try {
fsInner.innerHTML = renderFullscreenExchange(row);
@@ -3900,7 +3946,8 @@
function monitorOptionsSplitActive(rows) {
if (isMobileLayout() || expandedExchangeId) return false;
return (rows || []).some((r) => rowHasOptionsLayout(r));
if (!(rows || []).some((r) => rowHasOptionsLayout(r))) return false;
return showMonitorOkxPerpPref() || showMonitorOkxOptionsPref();
}
function renderPerpetualInnerCard(row, ag, pos, orders, trends, tickMap, intraday) {
@@ -5112,19 +5159,10 @@
function collectSettingsFromUI() {
const rows = [...document.querySelectorAll("#settings-list .settings-card")];
const pnlCb = document.getElementById("pref-show-account-pnl");
const fundsCb = document.getElementById("pref-show-nav-funds");
const dashCb = document.getElementById("pref-show-nav-dashboard");
const planCb = document.getElementById("pref-show-nav-plan");
const archiveCb = document.getElementById("pref-show-nav-archive");
const quotesCb = document.getElementById("pref-show-nav-quotes");
const aiCb = document.getElementById("pref-show-nav-ai");
const calcCb = document.getElementById("pref-show-nav-calculator");
const compareCb = document.getElementById("pref-show-nav-compare");
const strategyCb = document.getElementById("pref-show-nav-strategy");
const ampCb = document.getElementById("pref-show-nav-amp-stats");
const helpCb = document.getElementById("pref-show-nav-help");
const logsCb = document.getElementById("pref-show-nav-logs");
const chk = (id) => {
const el = document.getElementById(id);
return el ? !!el.checked : true;
};
const supEnabled = document.getElementById("supervisor-enabled");
const supProg = document.getElementById("supervisor-wechat-program");
const supWebhook = document.getElementById("supervisor-wechat-webhook");
@@ -5137,19 +5175,29 @@
return {
version: 1,
display: {
show_account_pnl: pnlCb ? !!pnlCb.checked : true,
show_nav_funds: fundsCb ? !!fundsCb.checked : true,
show_nav_dashboard: dashCb ? !!dashCb.checked : true,
show_nav_plan: planCb ? !!planCb.checked : true,
show_nav_archive: archiveCb ? !!archiveCb.checked : true,
show_nav_quotes: quotesCb ? !!quotesCb.checked : true,
show_nav_ai: aiCb ? !!aiCb.checked : true,
show_nav_calculator: calcCb ? !!calcCb.checked : true,
show_nav_compare: compareCb ? !!compareCb.checked : true,
show_nav_strategy: strategyCb ? !!strategyCb.checked : true,
show_nav_amp_stats: ampCb ? !!ampCb.checked : true,
show_nav_help: helpCb ? !!helpCb.checked : true,
show_nav_logs: logsCb ? !!logsCb.checked : true,
show_account_pnl: chk("pref-show-account-pnl"),
show_nav_funds: chk("pref-show-nav-funds"),
show_nav_dashboard: chk("pref-show-nav-dashboard"),
show_nav_plan: chk("pref-show-nav-plan"),
show_nav_archive: chk("pref-show-nav-archive"),
show_nav_quotes: chk("pref-show-nav-quotes"),
show_nav_ai: chk("pref-show-nav-ai"),
show_nav_calculator: chk("pref-show-nav-calculator"),
show_nav_compare: chk("pref-show-nav-compare"),
show_nav_strategy: chk("pref-show-nav-strategy"),
show_nav_amp_stats: chk("pref-show-nav-amp-stats"),
show_nav_help: chk("pref-show-nav-help"),
show_nav_logs: chk("pref-show-nav-logs"),
show_monitor_binance: chk("pref-show-monitor-binance"),
show_monitor_okx_perp: chk("pref-show-monitor-okx-perp"),
show_monitor_okx_options: chk("pref-show-monitor-okx-options"),
show_monitor_gate: chk("pref-show-monitor-gate"),
show_strategy_playbook_v2: chk("pref-show-strategy-playbook-v2"),
show_strategy_playbook: chk("pref-show-strategy-playbook"),
show_strategy_behavior: chk("pref-show-strategy-behavior"),
show_strategy_binance: chk("pref-show-strategy-binance"),
show_strategy_okx: chk("pref-show-strategy-okx"),
show_strategy_gate: chk("pref-show-strategy-gate"),
},
supervisor: {
enabled: supEnabled ? !!supEnabled.checked : true,
@@ -5210,6 +5258,9 @@
if (window.hubDashboardPage && window.hubDashboardPage.refresh) {
window.hubDashboardPage.refresh();
}
if (window.hubStrategyPage && typeof window.hubStrategyPage.reloadMeta === "function") {
window.hubStrategyPage.reloadMeta();
}
if (!pageNavAllowed(currentPage())) {
history.replaceState({}, "", "/monitor");
setActiveNav();
+47 -3
View File
@@ -16,7 +16,7 @@
<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'" />
<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=20260723-cmp-pad" />
<link rel="stylesheet" href="/assets/app.css?v=20260724-display-hide" />
<link rel="stylesheet" href="/assets/trade_stats_calendar.css?v=4" />
<link rel="stylesheet" href="/assets/account_risk_badge.css?v=4" />
<script src="/assets/account_risk_badge.js?v=4"></script>
@@ -1382,6 +1382,50 @@
<input type="checkbox" id="pref-show-nav-logs" checked />
顶栏显示「系统日志」
</label>
<p class="settings-display-subtitle">监控区卡片</p>
<p class="settings-display-hint">仅隐藏监控区界面卡片,不关闭账户与后台拉取.例:只做 OKX 期权与 Gate 时可关掉币安与 OKX 永续.</p>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-monitor-binance" checked />
监控区显示「币安」
</label>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-monitor-okx-perp" checked />
监控区显示「OKX 永续」
</label>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-monitor-okx-options" checked />
监控区显示「OKX 期权」
</label>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-monitor-gate" checked />
监控区显示「Gate」
</label>
<p class="settings-display-subtitle">策略说明页签</p>
<p class="settings-display-hint">关闭后该页签从策略说明中消失;顶栏「策略说明」入口仍由上方导航开关控制.</p>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-strategy-playbook-v2" checked />
策略说明显示「执行手册v2」
</label>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-strategy-playbook" checked />
策略说明显示「执行手册v1」
</label>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-strategy-behavior" checked />
策略说明显示「行为准则」
</label>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-strategy-binance" checked />
策略说明显示「币安」
</label>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-strategy-okx" checked />
策略说明显示「OKX」
</label>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-strategy-gate" checked />
策略说明显示「Gate」
</label>
<p class="settings-display-hint">保存至 hub_settings.json,换浏览器同样生效.关闭导航后对应页面将不可从顶栏进入,直接访问 URL 会跳回监控区.</p>
</section>
@@ -1633,7 +1677,7 @@
<script src="/assets/quotes.js?v=20260717-quotes-feed"></script>
<script src="/assets/funds.js?v=20260717-funds-scroll-fix"></script>
<script src="/assets/dashboard.js?v=20260723-hide-pnl"></script>
<script src="/assets/strategy.js?v=10"></script>
<script src="/assets/strategy.js?v=11"></script>
<script src="/assets/amp_stats.js?v=5"></script>
<script src="/assets/help.js?v=1"></script>
<script src="/assets/logs.js?v=1"></script>
@@ -1642,6 +1686,6 @@
<script src="/assets/options_expiry_countdown.js?v=1"></script>
<script src="/assets/options_position_cards.js?v=3"></script>
<script src="/assets/backup.js?v=1"></script>
<script src="/assets/app.js?v=20260723-compare"></script>
<script src="/assets/app.js?v=20260724-display-hide"></script>
</body>
</html>
+20 -2
View File
@@ -74,6 +74,14 @@
function renderExchangeTabs() {
if (!tabsEl) return;
if (!tabsMeta.length) {
tabsEl.innerHTML = "";
if (statusEl) statusEl.textContent = "当前无可显示的策略页签(可在系统设置·显示与导航中开启)";
if (docBody) docBody.innerHTML = "";
if (docToc) docToc.innerHTML = "";
if (checklistBody) checklistBody.innerHTML = "";
return;
}
tabsEl.innerHTML = tabsMeta
.map(
(t) =>
@@ -274,6 +282,15 @@
renderExchangeTabs();
}
async function reloadMeta() {
try {
await loadMeta();
if (tabsMeta.length) await loadExchange(activeKey);
} catch (e) {
if (statusEl) statusEl.textContent = String(e);
}
}
async function printSection(mode) {
const part = mode === "checklist" ? "checklist" : "doc";
const url = `/api/strategy/${encodeURIComponent(activeKey)}/print?part=${encodeURIComponent(part)}`;
@@ -334,7 +351,8 @@
setView(activeView);
try {
await loadMeta();
await loadExchange(activeKey);
if (tabsMeta.length) await loadExchange(activeKey);
else if (statusEl) statusEl.textContent = "当前无可显示的策略页签(可在系统设置·显示与导航中开启)";
} catch (e) {
if (statusEl) statusEl.textContent = String(e);
}
@@ -347,5 +365,5 @@
}
}
window.hubStrategyPage = { init, destroy };
window.hubStrategyPage = { init, destroy, reloadMeta };
})();