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:
@@ -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}
|
||||
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 };
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user