feat(hub): settings toggles for funds and dashboard nav

Add show_nav_funds and show_nav_dashboard in hub_settings display prefs to hide top nav entries and redirect direct URL access.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-11 11:00:19 +08:00
parent 07e8604ea6
commit 007e089121
6 changed files with 89 additions and 14 deletions
+2
View File
@@ -737,6 +737,8 @@ def api_get_settings():
class SettingsDisplayBody(BaseModel): class SettingsDisplayBody(BaseModel):
show_account_pnl: bool = True show_account_pnl: bool = True
show_nav_funds: bool = True
show_nav_dashboard: bool = True
class SettingsBody(BaseModel): class SettingsBody(BaseModel):
+5 -2
View File
@@ -11,6 +11,8 @@ SETTINGS_PATH = DIR / "hub_settings.json"
DEFAULT_DISPLAY = { DEFAULT_DISPLAY = {
"show_account_pnl": True, "show_account_pnl": True,
"show_nav_funds": True,
"show_nav_dashboard": True,
} }
DEFAULT_EXCHANGES = [ DEFAULT_EXCHANGES = [
@@ -72,8 +74,9 @@ def env_force_disabled_ids() -> set[str]:
def normalize_display_prefs(raw: dict | None) -> dict: def normalize_display_prefs(raw: dict | None) -> dict:
out = dict(DEFAULT_DISPLAY) out = dict(DEFAULT_DISPLAY)
if isinstance(raw, dict): if isinstance(raw, dict):
if "show_account_pnl" in raw: for key in DEFAULT_DISPLAY:
out["show_account_pnl"] = bool(raw.get("show_account_pnl")) if key in raw:
out[key] = bool(raw.get(key))
return out return out
+11
View File
@@ -326,6 +326,10 @@ a:hover {
transition: background 0.15s, color 0.15s, box-shadow 0.15s; transition: background 0.15s, color 0.15s, box-shadow 0.15s;
} }
.top-nav a.nav-hidden {
display: none !important;
}
.top-nav a:hover { .top-nav a:hover {
color: var(--text); color: var(--text);
background: var(--panel-hover); background: var(--panel-hover);
@@ -2176,9 +2180,16 @@ button.btn-sm {
} }
.settings-display-chk { .settings-display-chk {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.88rem; font-size: 0.88rem;
} }
.settings-display-chk + .settings-display-chk {
margin-top: 8px;
}
.settings-display-hint { .settings-display-hint {
margin: 8px 0 0; margin: 8px 0 0;
font-size: 0.78rem; font-size: 0.78rem;
+51 -8
View File
@@ -3,17 +3,47 @@
let settingsCache = null; let settingsCache = null;
let authState = { required: false, logged_in: true }; let authState = { required: false, logged_in: true };
function showAccountPnlPref() { function displayPref(key, defaultOn) {
const d = settingsCache && settingsCache.display; const d = settingsCache && settingsCache.display;
if (!d || d.show_account_pnl === undefined) return true; if (!d || d[key] === undefined) return defaultOn !== false;
return !!d.show_account_pnl; return !!d[key];
}
function showAccountPnlPref() {
return displayPref("show_account_pnl", true);
}
function showNavFundsPref() {
return displayPref("show_nav_funds", true);
}
function showNavDashboardPref() {
return displayPref("show_nav_dashboard", true);
}
function syncNavVisibility(data) {
const d = (data && data.display) || {};
const navFunds = document.getElementById("nav-funds");
const navDash = document.getElementById("nav-dashboard");
if (navFunds) navFunds.classList.toggle("nav-hidden", d.show_nav_funds === false);
if (navDash) navDash.classList.toggle("nav-hidden", d.show_nav_dashboard === false);
}
function pageNavAllowed(page) {
if (page === "funds") return showNavFundsPref();
if (page === "dashboard") return showNavDashboardPref();
return true;
} }
function syncDisplayPrefsUI(data) { function syncDisplayPrefsUI(data) {
const cb = document.getElementById("pref-show-account-pnl"); const d = (data && data.display) || {};
if (!cb) return; const pnlCb = document.getElementById("pref-show-account-pnl");
const show = data && data.display ? data.display.show_account_pnl : true; const fundsCb = document.getElementById("pref-show-nav-funds");
cb.checked = show !== false; const dashCb = document.getElementById("pref-show-nav-dashboard");
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;
syncNavVisibility(data);
} }
function positionTableHeadHtml(compact) { function positionTableHeadHtml(compact) {
@@ -662,7 +692,11 @@
} }
function setActiveNav() { function setActiveNav() {
const page = currentPage(); let page = currentPage();
if (!pageNavAllowed(page)) {
history.replaceState({}, "", "/monitor");
page = "monitor";
}
const pageId = pageElementId(page); const pageId = pageElementId(page);
document.querySelectorAll(".top-nav a").forEach((a) => { document.querySelectorAll(".top-nav a").forEach((a) => {
const href = (a.getAttribute("href") || "").split("?")[0]; const href = (a.getAttribute("href") || "").split("?")[0];
@@ -857,6 +891,7 @@
async function loadSettings() { async function loadSettings() {
const r = await apiFetch("/api/settings"); const r = await apiFetch("/api/settings");
settingsCache = await r.json(); settingsCache = await r.json();
syncNavVisibility(settingsCache);
return settingsCache; return settingsCache;
} }
@@ -3055,10 +3090,14 @@
function collectSettingsFromUI() { function collectSettingsFromUI() {
const rows = [...document.querySelectorAll("#settings-list .settings-card")]; const rows = [...document.querySelectorAll("#settings-list .settings-card")];
const pnlCb = document.getElementById("pref-show-account-pnl"); const pnlCb = document.getElementById("pref-show-account-pnl");
const fundsCb = document.getElementById("pref-show-nav-funds");
const dashCb = document.getElementById("pref-show-nav-dashboard");
return { return {
version: 1, version: 1,
display: { display: {
show_account_pnl: pnlCb ? !!pnlCb.checked : true, show_account_pnl: pnlCb ? !!pnlCb.checked : true,
show_nav_funds: fundsCb ? !!fundsCb.checked : true,
show_nav_dashboard: dashCb ? !!dashCb.checked : true,
}, },
exchanges: rows.map((card) => { exchanges: rows.map((card) => {
const caps = []; const caps = [];
@@ -3100,6 +3139,10 @@
await loadSettingsUI(); await loadSettingsUI();
} }
if (lastMonitorRows.length) renderMonitorGrid(lastMonitorRows); if (lastMonitorRows.length) renderMonitorGrid(lastMonitorRows);
if (!pageNavAllowed(currentPage())) {
history.replaceState({}, "", "/monitor");
setActiveNav();
}
} else showToast("保存失败", true); } else showToast("保存失败", true);
} catch (e) { } catch (e) {
showToast(String(e), true); showToast(String(e), true);
+12 -4
View File
@@ -502,12 +502,20 @@
</details> </details>
<p id="settings-meta-line" class="settings-meta-line"></p> <p id="settings-meta-line" class="settings-meta-line"></p>
<div class="settings-display-panel card"> <div class="settings-display-panel card">
<h3 class="settings-display-title">监控区显示</h3> <h3 class="settings-display-title">显示与导航</h3>
<label class="chk-label settings-display-chk"> <label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-account-pnl" checked /> <input type="checkbox" id="pref-show-account-pnl" checked />
显示资金账户、交易账户与浮动盈亏 监控区显示资金账户、交易账户与浮动盈亏
</label> </label>
<p class="settings-display-hint">关闭后监控区不显示上述数值;保存至 hub_settings.json,换浏览器同样生效。</p> <label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-nav-funds" checked />
顶栏显示「资金概况」
</label>
<label class="chk-label settings-display-chk">
<input type="checkbox" id="pref-show-nav-dashboard" checked />
顶栏显示「数据看板」
</label>
<p class="settings-display-hint">保存至 hub_settings.json,换浏览器同样生效。关闭导航后对应页面将不可从顶栏进入。</p>
</div> </div>
<div class="toolbar"> <div class="toolbar">
<button type="button" id="btn-settings-save" class="primary">保存设置</button> <button type="button" id="btn-settings-save" class="primary">保存设置</button>
@@ -547,6 +555,6 @@
<script src="/assets/funds.js?v=20260609-hub-funds-fold"></script> <script src="/assets/funds.js?v=20260609-hub-funds-fold"></script>
<script src="/assets/dashboard.js?v=20260611-hub-dash-sse"></script> <script src="/assets/dashboard.js?v=20260611-hub-dash-sse"></script>
<script src="/assets/ai_review_render.js?v=2"></script> <script src="/assets/ai_review_render.js?v=2"></script>
<script src="/assets/app.js?v=20260611-hub-ai-chat"></script> <script src="/assets/app.js?v=20260611-hub-nav-prefs"></script>
</body> </body>
</html> </html>
+8
View File
@@ -236,6 +236,14 @@ Chrome **桌面快捷方式**图标来自站点 `favicon` / `manifest`(已配
**可用**:打开 http://127.0.0.1:5100/settings ,修改表格后点 **保存设置** 即写入 `hub_settings.json`;**重新加载** 从磁盘/默认再读(会重新套用 `HUB_DISABLED_IDS`)。保存后监控区立即使用新 URL/启用状态,**无需重启 hub**。 **可用**:打开 http://127.0.0.1:5100/settings ,修改表格后点 **保存设置** 即写入 `hub_settings.json`;**重新加载** 从磁盘/默认再读(会重新套用 `HUB_DISABLED_IDS`)。保存后监控区立即使用新 URL/启用状态,**无需重启 hub**。
**显示与导航**`hub_settings.json``display`):
| 开关 | 说明 |
|------|------|
| 监控区资金/浮盈 | 关闭后监控卡片不显示资金户、交易户、浮盈亏列 |
| 顶栏「资金概况」 | 关闭后隐藏导航;直接访问 `/funds` 会跳回监控区 |
| 顶栏「数据看板」 | 关闭后隐藏导航;直接访问 `/dashboard` 会跳回监控区 |
**下单、关键位、策略交易**:请在监控卡片点击 **「实例」** 或 **「策略交易」**SSO),进入各 `crypto_monitor_*` 网页(`/trade``/key_monitor``/strategy``/strategy/records` 等)。中控 **不** 提供下单区;**策略交易记录** 仅在实例顶栏查看(见 [策略交易说明.md](../策略交易说明.md) §五)。 **下单、关键位、策略交易**:请在监控卡片点击 **「实例」** 或 **「策略交易」**SSO),进入各 `crypto_monitor_*` 网页(`/trade``/key_monitor``/strategy``/strategy/records` 等)。中控 **不** 提供下单区;**策略交易记录** 仅在实例顶栏查看(见 [策略交易说明.md](../策略交易说明.md) §五)。
| 列 | 含义 | | 列 | 含义 |