From aa966114b1a3fa709fc58ba564d1ba7c58b07959 Mon Sep 17 00:00:00 2001 From: dekun Date: Wed, 8 Jul 2026 20:24:15 +0800 Subject: [PATCH] Fix settings and env config stuck on loading via SSR form render Co-authored-by: Cursor --- crypto_monitor_binance/app.py | 1 + crypto_monitor_gate/app.py | 1 + crypto_monitor_okx/app.py | 1 + lib/common/static/instance_settings_prefs.js | 58 +++++++++++++------ lib/instance/instance_display_prefs_lib.py | 2 +- lib/instance/instance_settings_lib.py | 11 +++- .../templates/display_prefs_panel.html | 20 ++++++- lib/instance/templates/embed_shell.html | 2 +- lib/instance/templates/env_config_panel.html | 43 +++++++++++++- lib/instance/templates/index.html | 2 +- 10 files changed, 114 insertions(+), 27 deletions(-) diff --git a/crypto_monitor_binance/app.py b/crypto_monitor_binance/app.py index 41fbbc3..f7f7202 100644 --- a/crypto_monitor_binance/app.py +++ b/crypto_monitor_binance/app.py @@ -7343,6 +7343,7 @@ def render_main_page(page="trade", embed_mode=None): **display_prefs_template_context(get_db), **settings_page_context( page, + instance_base_dir=BASE_DIR, exchange_key="binance", exchange_display=EXCHANGE_DISPLAY_NAME, risk_status=risk_status, diff --git a/crypto_monitor_gate/app.py b/crypto_monitor_gate/app.py index e246323..ac864a7 100644 --- a/crypto_monitor_gate/app.py +++ b/crypto_monitor_gate/app.py @@ -7146,6 +7146,7 @@ def render_main_page(page="trade", embed_mode=None): **display_prefs_template_context(get_db), **settings_page_context( page, + instance_base_dir=BASE_DIR, exchange_key="gate", exchange_display=EXCHANGE_DISPLAY_NAME, risk_status=risk_status, diff --git a/crypto_monitor_okx/app.py b/crypto_monitor_okx/app.py index 1bc0cfc..dded600 100644 --- a/crypto_monitor_okx/app.py +++ b/crypto_monitor_okx/app.py @@ -6747,6 +6747,7 @@ def render_main_page(page="trade", embed_mode=None): **display_prefs_template_context(get_db), **settings_page_context( page, + instance_base_dir=BASE_DIR, exchange_key="okx", exchange_display=EXCHANGE_DISPLAY_NAME, risk_status=risk_status, diff --git a/lib/common/static/instance_settings_prefs.js b/lib/common/static/instance_settings_prefs.js index 2e4c9cc..2bc300d 100644 --- a/lib/common/static/instance_settings_prefs.js +++ b/lib/common/static/instance_settings_prefs.js @@ -56,13 +56,29 @@ return d[key] !== false; } - async function loadDisplayPrefsForm() { - const pane = document.querySelector('.embed-tab-pane.is-active-pane') || document; - const root = pane.querySelector ? pane.querySelector("#display-prefs-form") : document.getElementById("display-prefs-form"); - if (!root) { - const fallback = document.getElementById("display-prefs-form"); - if (!fallback) return; - return loadDisplayPrefsFormIn(fallback); + function displayPrefsRoot() { + const pane = document.querySelector(".embed-tab-pane.is-active-pane"); + if (pane) { + const inPane = pane.querySelector("#display-prefs-form"); + if (inPane) return inPane; + } + return document.getElementById("display-prefs-form"); + } + + function envConfigGrid() { + const pane = document.querySelector(".embed-tab-pane.is-active-pane"); + if (pane) { + const inPane = pane.querySelector("#env-config-grid"); + if (inPane) return inPane; + } + return document.getElementById("env-config-grid"); + } + + async function loadDisplayPrefsForm(force) { + const root = displayPrefsRoot(); + if (!root) return; + if (!force && root.getAttribute("data-prefs-ssr") === "1" && root.querySelector("[data-pref-key]")) { + return; } return loadDisplayPrefsFormIn(root); } @@ -96,6 +112,7 @@ section.appendChild(grid); root.appendChild(section); }); + root.setAttribute("data-prefs-ssr", "1"); } catch (e) { root.innerHTML = '' + (e.message || "加载失败") + ""; } @@ -103,8 +120,9 @@ async function saveDisplayPrefs() { const status = document.getElementById("display-prefs-status"); + const root = displayPrefsRoot(); const display = {}; - document.querySelectorAll("#display-prefs-form input[data-pref-key]").forEach((cb) => { + (root ? root.querySelectorAll("input[data-pref-key]") : []).forEach((cb) => { display[cb.dataset.prefKey] = !!cb.checked; }); try { @@ -165,12 +183,13 @@ return card; } - async function loadEnvConfig() { - const pane = document.querySelector('.embed-tab-pane.is-active-pane') || document; - const grid = pane.querySelector ? pane.querySelector("#env-config-grid") : document.getElementById("env-config-grid"); - const target = grid || document.getElementById("env-config-grid"); - if (!target) return; - return loadEnvConfigIn(target); + async function loadEnvConfig(force) { + const grid = envConfigGrid(); + if (!grid) return; + if (!force && grid.getAttribute("data-env-ssr") === "1" && grid.querySelector("[data-env-key]")) { + return; + } + return loadEnvConfigIn(grid); } async function loadEnvConfigIn(grid) { @@ -192,14 +211,17 @@ card.appendChild(inner); grid.appendChild(card); }); + grid.setAttribute("data-env-ssr", "1"); } catch (e) { grid.innerHTML = '' + (e.message || "加载失败") + ""; } } function collectEnvValues() { + const grid = envConfigGrid(); const values = {}; - document.querySelectorAll(".env-field-input[data-env-key]").forEach((el) => { + const scope = grid || document; + scope.querySelectorAll(".env-field-input[data-env-key]").forEach((el) => { values[el.dataset.envKey] = el.value; }); return values; @@ -276,15 +298,15 @@ const eRestart = document.getElementById("env-config-save-restart"); if (eRestart) eRestart.addEventListener("click", () => saveEnvConfig(true)); const eReload = document.getElementById("env-config-reload"); - if (eReload) eReload.addEventListener("click", loadEnvConfig); + if (eReload) eReload.addEventListener("click", () => loadEnvConfig(true)); const pSave = document.getElementById("pwd-save-btn"); if (pSave) pSave.addEventListener("click", savePassword); } function initPage() { bindEvents(); - if (document.getElementById("display-prefs-form")) loadDisplayPrefsForm(); - if (document.getElementById("env-config-grid")) loadEnvConfig(); + loadDisplayPrefsForm(false); + loadEnvConfig(false); if (global.__INSTANCE_DISPLAY__) applyDisplayToNav(global.__INSTANCE_DISPLAY__); } diff --git a/lib/instance/instance_display_prefs_lib.py b/lib/instance/instance_display_prefs_lib.py index ca5b02e..e814641 100644 --- a/lib/instance/instance_display_prefs_lib.py +++ b/lib/instance/instance_display_prefs_lib.py @@ -84,7 +84,7 @@ def save_display_prefs(get_db: Callable, prefs: dict) -> dict[str, bool]: def display_prefs_template_context(get_db: Callable) -> dict[str, Any]: prefs = get_display_prefs(get_db) - return {"display": prefs} + return {"display": prefs, "display_meta": display_meta_for_ui()} def tab_allowed(tab: str, display: Optional[dict[str, bool]] = None) -> bool: diff --git a/lib/instance/instance_settings_lib.py b/lib/instance/instance_settings_lib.py index cacbd65..9024171 100644 --- a/lib/instance/instance_settings_lib.py +++ b/lib/instance/instance_settings_lib.py @@ -183,8 +183,15 @@ def build_instance_settings_view( } -def settings_page_context(page: str, **kwargs: Any) -> dict[str, Any]: +def settings_page_context(page: str, *, instance_base_dir: str | None = None, **kwargs: Any) -> dict[str, Any]: p = (page or "").strip() if p not in ("settings", "risk_policy", "env_config"): return {} - return {"instance_settings": build_instance_settings_view(**kwargs)} + ctx: dict[str, Any] = {"instance_settings": build_instance_settings_view(**kwargs)} + if p == "env_config" and instance_base_dir: + from lib.env.env_schema import build_env_payload + + env_path = os.path.join(instance_base_dir, ".env") + example_path = os.path.join(instance_base_dir, ".env.example") + ctx["env_config_groups"] = build_env_payload(example_path, env_path).get("groups") or [] + return ctx diff --git a/lib/instance/templates/display_prefs_panel.html b/lib/instance/templates/display_prefs_panel.html index 5fc8fb6..3177c7c 100644 --- a/lib/instance/templates/display_prefs_panel.html +++ b/lib/instance/templates/display_prefs_panel.html @@ -1,9 +1,25 @@ -{# 系统设置 · 导航显示开关 #} +{# 系统设置 · 导航显示开关(SSR 预渲染,保存仍走 API) #}

导航显示

以下开关控制顶栏导航与系统设置内区块是否显示,保存后立即生效。关键位监控、实盘下单、系统设置为固定项。

-
+
+ {% if display_meta %} + {% for group in display_meta %} +
+

{{ group.group }}

+
+ {% for item in group.keys %} + + {% endfor %} +
+
+ {% endfor %} + {% else %}
加载中…
+ {% endif %}
diff --git a/lib/instance/templates/embed_shell.html b/lib/instance/templates/embed_shell.html index 7e05bd7..a646ac3 100644 --- a/lib/instance/templates/embed_shell.html +++ b/lib/instance/templates/embed_shell.html @@ -103,7 +103,7 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj - + diff --git a/lib/instance/templates/env_config_panel.html b/lib/instance/templates/env_config_panel.html index adec2f9..0b7c017 100644 --- a/lib/instance/templates/env_config_panel.html +++ b/lib/instance/templates/env_config_panel.html @@ -1,4 +1,4 @@ -{# env配置:按功能分组,三列卡片布局 #} +{# env配置:按功能分组,三列卡片布局(SSR 预渲染) #}

env 配置

@@ -10,7 +10,46 @@
-
+
+ {% if env_config_groups %} + {% for group in env_config_groups %} +
+

{{ group.title or '其他' }}

+
+ {% for field in group.fields %} +
+ + {% if field.note %} +
{{ field.note }}
+ {% endif %} + {% if field.type == 'bool' %} + + {% else %} + + {% endif %} + + {% if field.restart_required %}需重启{% else %}保存即生效{% endif %} + +
+ {% endfor %} +
+
+ {% endfor %} + {% else %}
加载配置中…
+ {% endif %}
diff --git a/lib/instance/templates/index.html b/lib/instance/templates/index.html index f08d2c3..7567c1a 100644 --- a/lib/instance/templates/index.html +++ b/lib/instance/templates/index.html @@ -2038,6 +2038,6 @@ setInterval(refreshPriceSnapshotConditional, {{ price_refresh_seconds * 1000 }}) - + \ No newline at end of file