Fix settings loading and use 2-column card layout.
Merge Flask GET/POST routes, refresh prefs on tab revisit after preload, and reorganize system settings into separate cards. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -117,6 +117,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (revisit && (tab === "settings" || tab === "env_config")) {
|
||||||
|
if (global.InstanceSettingsPrefs) {
|
||||||
|
if (tab === "settings" && typeof global.InstanceSettingsPrefs.loadDisplayPrefsForm === "function") {
|
||||||
|
global.InstanceSettingsPrefs.loadDisplayPrefsForm();
|
||||||
|
}
|
||||||
|
if (tab === "env_config" && typeof global.InstanceSettingsPrefs.loadEnvConfig === "function") {
|
||||||
|
global.InstanceSettingsPrefs.loadEnvConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!revisit) {
|
if (!revisit) {
|
||||||
if (typeof global.refreshAccountSnapshot === "function") {
|
if (typeof global.refreshAccountSnapshot === "function") {
|
||||||
global.refreshAccountSnapshot({ silent: true });
|
global.refreshAccountSnapshot({ silent: true });
|
||||||
@@ -296,6 +306,7 @@
|
|||||||
}
|
}
|
||||||
if (revisit) {
|
if (revisit) {
|
||||||
document.body.setAttribute("data-page", tab);
|
document.body.setAttribute("data-page", tab);
|
||||||
|
runPageInit(tab, { revisit: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
runPageInit(tab, { revisit: false });
|
runPageInit(tab, { revisit: false });
|
||||||
|
|||||||
@@ -57,8 +57,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadDisplayPrefsForm() {
|
async function loadDisplayPrefsForm() {
|
||||||
const root = document.getElementById("display-prefs-form");
|
const pane = document.querySelector('.embed-tab-pane.is-active-pane') || document;
|
||||||
if (!root) return;
|
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);
|
||||||
|
}
|
||||||
|
return loadDisplayPrefsFormIn(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadDisplayPrefsFormIn(root) {
|
||||||
try {
|
try {
|
||||||
const data = await fetchJson("/api/settings/display");
|
const data = await fetchJson("/api/settings/display");
|
||||||
const display = data.display || {};
|
const display = data.display || {};
|
||||||
@@ -157,8 +166,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadEnvConfig() {
|
async function loadEnvConfig() {
|
||||||
const grid = document.getElementById("env-config-grid");
|
const pane = document.querySelector('.embed-tab-pane.is-active-pane') || document;
|
||||||
if (!grid) return;
|
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 loadEnvConfigIn(grid) {
|
||||||
grid.innerHTML = '<div class="env-config-loading muted">加载配置中…</div>';
|
grid.innerHTML = '<div class="env-config-loading muted">加载配置中…</div>';
|
||||||
try {
|
try {
|
||||||
const data = await fetchJson("/api/settings/env");
|
const data = await fetchJson("/api/settings/env");
|
||||||
|
|||||||
@@ -2333,6 +2333,43 @@ html[data-theme="light"] .journal-detail-img-thumb {
|
|||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-page--grid {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-grid-2col {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-grid-cell {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-grid-cell--full {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-card--standalone {
|
||||||
|
padding: 12px 14px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-card--standalone h2 {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-card--export .settings-export-links-block {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.settings-page--ops {
|
.settings-page--ops {
|
||||||
max-width: 720px;
|
max-width: 720px;
|
||||||
}
|
}
|
||||||
@@ -2501,6 +2538,9 @@ html[data-theme="light"] .journal-detail-img-thumb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
|
.settings-grid-2col {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
}
|
||||||
.settings-cards-grid {
|
.settings-cards-grid {
|
||||||
grid-template-columns: minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,21 +65,18 @@ def register_instance_settings_routes(
|
|||||||
example_path = os.path.join(base_dir, ".env.example")
|
example_path = os.path.join(base_dir, ".env.example")
|
||||||
api_auth = _api_login_required()
|
api_auth = _api_login_required()
|
||||||
|
|
||||||
@app.route("/api/settings/display", methods=["GET"])
|
@app.route("/api/settings/display", methods=["GET", "POST"])
|
||||||
@api_auth
|
@api_auth
|
||||||
def api_get_display_prefs():
|
def api_settings_display():
|
||||||
prefs = get_display_prefs(get_db)
|
if request.method == "GET":
|
||||||
return jsonify(
|
prefs = get_display_prefs(get_db)
|
||||||
{
|
return jsonify(
|
||||||
"ok": True,
|
{
|
||||||
"display": prefs,
|
"ok": True,
|
||||||
"meta": display_meta_for_ui(),
|
"display": prefs,
|
||||||
}
|
"meta": display_meta_for_ui(),
|
||||||
)
|
}
|
||||||
|
)
|
||||||
@app.route("/api/settings/display", methods=["POST"])
|
|
||||||
@api_auth
|
|
||||||
def api_save_display_prefs():
|
|
||||||
body = request.get_json(silent=True) or {}
|
body = request.get_json(silent=True) or {}
|
||||||
raw = body.get("display") if isinstance(body.get("display"), dict) else body
|
raw = body.get("display") if isinstance(body.get("display"), dict) else body
|
||||||
saved = save_display_prefs(get_db, raw)
|
saved = save_display_prefs(get_db, raw)
|
||||||
@@ -91,15 +88,12 @@ def register_instance_settings_routes(
|
|||||||
payload = build_env_payload(example_path, env_path)
|
payload = build_env_payload(example_path, env_path)
|
||||||
return jsonify({"ok": True, **payload})
|
return jsonify({"ok": True, **payload})
|
||||||
|
|
||||||
@app.route("/api/settings/env", methods=["GET"])
|
@app.route("/api/settings/env", methods=["GET", "POST"])
|
||||||
@api_auth
|
@api_auth
|
||||||
def api_env_get():
|
def api_settings_env():
|
||||||
payload = build_env_payload(example_path, env_path)
|
if request.method == "GET":
|
||||||
return jsonify({"ok": True, **payload})
|
payload = build_env_payload(example_path, env_path)
|
||||||
|
return jsonify({"ok": True, **payload})
|
||||||
@app.route("/api/settings/env", methods=["POST"])
|
|
||||||
@api_auth
|
|
||||||
def api_env_post():
|
|
||||||
body = request.get_json(silent=True) or {}
|
body = request.get_json(silent=True) or {}
|
||||||
updates = body.get("values") if isinstance(body.get("values"), dict) else body
|
updates = body.get("values") if isinstance(body.get("values"), dict) else body
|
||||||
if not isinstance(updates, dict):
|
if not isinstance(updates, dict):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{# 系统设置 · 导航显示开关 #}
|
{# 系统设置 · 导航显示开关 #}
|
||||||
<div class="card settings-card settings-card--compact" id="display-prefs-card">
|
<div class="card settings-card settings-card--standalone" id="display-prefs-card">
|
||||||
<h2>导航显示</h2>
|
<h2>导航显示</h2>
|
||||||
<p class="settings-env-hint">以下开关控制顶栏导航与系统设置内区块是否显示,保存后立即生效。关键位监控、实盘下单、系统设置为固定项。</p>
|
<p class="settings-env-hint">以下开关控制顶栏导航与系统设置内区块是否显示,保存后立即生效。关键位监控、实盘下单、系统设置为固定项。</p>
|
||||||
<div id="display-prefs-form" class="display-prefs-form">
|
<div id="display-prefs-form" class="display-prefs-form">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
|
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
|
||||||
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
|
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
|
||||||
<link rel="stylesheet" href="/static/instance_page.css?v=4">
|
<link rel="stylesheet" href="/static/instance_page.css?v=4">
|
||||||
<link rel="stylesheet" href="/static/instance_theme.css?v=71">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=72">
|
||||||
<script src="/static/account_risk_badge.js?v=4"></script>
|
<script src="/static/account_risk_badge.js?v=4"></script>
|
||||||
<meta name="theme-color" content="#0b0d14">
|
<meta name="theme-color" content="#0b0d14">
|
||||||
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
||||||
@@ -103,8 +103,8 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj
|
|||||||
<script>
|
<script>
|
||||||
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
|
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/instance_settings_prefs.js?v=1"></script>
|
<script src="/static/instance_settings_prefs.js?v=2"></script>
|
||||||
<script src="/static/instance_live.js?v=4"></script>
|
<script src="/static/instance_live.js?v=4"></script>
|
||||||
<script src="/static/instance_embed.js?v=17"></script>
|
<script src="/static/instance_embed.js?v=18"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<link rel="manifest" href="/static/icons/manifest.webmanifest">
|
<link rel="manifest" href="/static/icons/manifest.webmanifest">
|
||||||
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
||||||
<link rel="stylesheet" href="/static/instance_page.css?v=1">
|
<link rel="stylesheet" href="/static/instance_page.css?v=1">
|
||||||
<link rel="stylesheet" href="/static/instance_theme.css?v=71">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=72">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body
|
<body
|
||||||
@@ -2038,6 +2038,6 @@ setInterval(refreshPriceSnapshotConditional, {{ price_refresh_seconds * 1000 }})
|
|||||||
<script>
|
<script>
|
||||||
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
|
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/instance_settings_prefs.js?v=1"></script>
|
<script src="/static/instance_settings_prefs.js?v=2"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
{# 系统设置 · 账户密码 #}
|
{# 系统设置 · 账户密码(外层 card 由 settings_panel 提供) #}
|
||||||
<div class="card settings-subcard settings-subcard--ops" id="password-settings-card" data-settings-section="password">
|
<h2>账户密码修改</h2>
|
||||||
<h3 class="settings-subcard-title">账户密码修改</h3>
|
<p class="settings-subcard-desc">修改网页登录账号密码,写入 <code>.env</code> 后需重启实例生效。</p>
|
||||||
<p class="settings-subcard-desc">修改网页登录账号密码,写入 <code>.env</code> 后需重启实例生效。</p>
|
<div class="settings-password-form">
|
||||||
<div class="settings-password-form">
|
<label>当前密码 <input type="password" id="pwd-old" autocomplete="current-password"></label>
|
||||||
<label>当前密码 <input type="password" id="pwd-old" autocomplete="current-password"></label>
|
<label>新用户名(可选) <input type="text" id="pwd-new-username" autocomplete="username"></label>
|
||||||
<label>新用户名(可选) <input type="text" id="pwd-new-username" autocomplete="username"></label>
|
<label>新密码 <input type="password" id="pwd-new" autocomplete="new-password"></label>
|
||||||
<label>新密码 <input type="password" id="pwd-new" autocomplete="new-password"></label>
|
<label>确认新密码 <input type="password" id="pwd-confirm" autocomplete="new-password"></label>
|
||||||
<label>确认新密码 <input type="password" id="pwd-confirm" autocomplete="new-password"></label>
|
</div>
|
||||||
</div>
|
<div class="settings-actions-row">
|
||||||
<div class="settings-actions-row">
|
<button type="button" class="btn-primary btn-sm" id="pwd-save-btn">保存密码</button>
|
||||||
<button type="button" class="btn-primary btn-sm" id="pwd-save-btn">保存密码</button>
|
<span class="settings-status-line" id="pwd-save-status"></span>
|
||||||
<span class="settings-status-line" id="pwd-save-status"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,50 +1,65 @@
|
|||||||
{# 系统设置:导航显示 + 账户密码 + 资金划转 + 数据导出 #}
|
{# 系统设置:2 列独立卡片 #}
|
||||||
<div class="settings-page settings-page--ops">
|
<div class="settings-page settings-page--grid">
|
||||||
{% include 'display_prefs_panel.html' %}
|
<div class="settings-grid-2col">
|
||||||
|
<div class="settings-grid-cell">
|
||||||
|
{% include 'display_prefs_panel.html' %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if display.show_settings_password %}
|
{% if display.show_settings_password %}
|
||||||
{% include 'password_settings_panel.html' %}
|
<div class="settings-grid-cell">
|
||||||
{% endif %}
|
<div class="card settings-card settings-card--standalone">
|
||||||
|
{% include 'password_settings_panel.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="card settings-card settings-card--side-panel">
|
{% if instance_settings.show_transfer and display.show_settings_transfer %}
|
||||||
<div class="settings-side-subcards">
|
<div class="settings-grid-cell">
|
||||||
{% if instance_settings.options_settings_enabled and display.show_settings_options_swap %}
|
<div class="card settings-card settings-card--standalone">
|
||||||
<div class="card settings-subcard settings-subcard--ops">
|
<h2>永续资金划转</h2>
|
||||||
<h3 class="settings-subcard-title">币种兑换</h3>
|
|
||||||
{% include 'options_settings_swap.html' %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if instance_settings.options_settings_enabled and display.show_settings_options_transfer %}
|
|
||||||
<div class="card settings-subcard settings-subcard--ops">
|
|
||||||
<h3 class="settings-subcard-title">期权资金划转</h3>
|
|
||||||
{% include 'options_settings_transfer.html' %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if instance_settings.options_settings_enabled %}
|
|
||||||
{% include 'options_settings_panel.html' %}
|
|
||||||
{% endif %}
|
|
||||||
{% if instance_settings.show_transfer and display.show_settings_transfer %}
|
|
||||||
<div class="card settings-subcard settings-subcard--ops">
|
|
||||||
<h3 class="settings-subcard-title">永续资金划转</h3>
|
|
||||||
<p class="settings-subcard-desc">子账户永续:资金账户与交易账户之间划转 USDT。</p>
|
<p class="settings-subcard-desc">子账户永续:资金账户与交易账户之间划转 USDT。</p>
|
||||||
{% include 'instance_transfer_panel.html' %}
|
{% include 'instance_transfer_panel.html' %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if display.show_settings_export %}
|
{% if display.show_settings_export %}
|
||||||
<div class="settings-side-export">
|
<div class="settings-grid-cell">
|
||||||
<div class="settings-side-export-head">
|
<div class="card settings-card settings-card--standalone settings-card--export">
|
||||||
<span class="settings-side-export-label">数据导出</span>
|
<h2>数据导出</h2>
|
||||||
<span class="settings-side-export-meta muted">CSV · v{{ instance_settings.data_export_version }}</span>
|
<p class="settings-subcard-desc muted">CSV · v{{ instance_settings.data_export_version }}</p>
|
||||||
</div>
|
<div class="settings-export-links-inline settings-export-links-block">
|
||||||
<div class="settings-export-links-inline">
|
|
||||||
<a href="/export/trade_records">交易记录</a>
|
<a href="/export/trade_records">交易记录</a>
|
||||||
<a href="/export/journal_entries">复盘记录</a>
|
<a href="/export/journal_entries">复盘记录</a>
|
||||||
<a href="/export/key_monitors">关键位(当前)</a>
|
<a href="/export/key_monitors">关键位(当前)</a>
|
||||||
<a href="/export/key_monitor_history">关键位历史</a>
|
<a href="/export/key_monitor_history">关键位历史</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if instance_settings.options_settings_enabled and display.show_settings_options_swap %}
|
||||||
|
<div class="settings-grid-cell">
|
||||||
|
<div class="card settings-card settings-card--standalone">
|
||||||
|
<h2>币种兑换</h2>
|
||||||
|
{% include 'options_settings_swap.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if instance_settings.options_settings_enabled and display.show_settings_options_transfer %}
|
||||||
|
<div class="settings-grid-cell">
|
||||||
|
<div class="card settings-card settings-card--standalone">
|
||||||
|
<h2>期权资金划转</h2>
|
||||||
|
{% include 'options_settings_transfer.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if instance_settings.options_settings_enabled %}
|
||||||
|
<div class="settings-grid-cell settings-grid-cell--full">
|
||||||
|
{% include 'options_settings_panel.html' %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user