Redesign env config UI: tabs, 2-col form, remove per-field badges
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -65,13 +65,37 @@
|
|||||||
return document.getElementById("display-prefs-form");
|
return document.getElementById("display-prefs-form");
|
||||||
}
|
}
|
||||||
|
|
||||||
function envConfigGrid() {
|
function envConfigRoot() {
|
||||||
const pane = document.querySelector(".embed-tab-pane.is-active-pane");
|
const pane = document.querySelector(".embed-tab-pane.is-active-pane");
|
||||||
if (pane) {
|
if (pane) {
|
||||||
const inPane = pane.querySelector("#env-config-grid");
|
const inPane = pane.querySelector(".env-config-page");
|
||||||
if (inPane) return inPane;
|
if (inPane) return inPane;
|
||||||
}
|
}
|
||||||
return document.getElementById("env-config-grid");
|
return document.querySelector(".env-config-page");
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindEnvTabs(scope) {
|
||||||
|
const root = scope || envConfigRoot();
|
||||||
|
if (!root || root.getAttribute("data-env-tabs-bound") === "1") return;
|
||||||
|
const tabs = root.querySelectorAll(".env-tab-btn");
|
||||||
|
const panels = root.querySelectorAll(".env-panel");
|
||||||
|
if (!tabs.length) return;
|
||||||
|
root.setAttribute("data-env-tabs-bound", "1");
|
||||||
|
tabs.forEach((btn) => {
|
||||||
|
btn.addEventListener("click", () => {
|
||||||
|
const idx = btn.getAttribute("data-env-tab");
|
||||||
|
tabs.forEach((b) => {
|
||||||
|
const on = b.getAttribute("data-env-tab") === idx;
|
||||||
|
b.classList.toggle("is-active", on);
|
||||||
|
b.setAttribute("aria-selected", on ? "true" : "false");
|
||||||
|
});
|
||||||
|
panels.forEach((p) => {
|
||||||
|
const on = p.getAttribute("data-env-panel") === idx;
|
||||||
|
p.classList.toggle("is-active", on);
|
||||||
|
p.hidden = !on;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadDisplayPrefsForm(force) {
|
async function loadDisplayPrefsForm(force) {
|
||||||
@@ -140,26 +164,32 @@
|
|||||||
|
|
||||||
let envSchemaGroups = [];
|
let envSchemaGroups = [];
|
||||||
|
|
||||||
function renderEnvField(field) {
|
function renderEnvFieldRow(field) {
|
||||||
const card = document.createElement("div");
|
const row = document.createElement("div");
|
||||||
card.className = "env-field-card";
|
row.className = "env-field-row" + (field.restart_required ? " env-field-row--restart" : "");
|
||||||
const label = document.createElement("label");
|
const label = document.createElement("label");
|
||||||
label.className = "env-field-label";
|
label.className = "env-field-label";
|
||||||
|
label.htmlFor = "env-f-" + field.key;
|
||||||
label.textContent = field.label || field.key;
|
label.textContent = field.label || field.key;
|
||||||
card.appendChild(label);
|
if (field.restart_required) {
|
||||||
|
const mark = document.createElement("span");
|
||||||
|
mark.className = "env-restart-mark";
|
||||||
|
mark.title = "需重启";
|
||||||
|
mark.textContent = "*";
|
||||||
|
label.appendChild(mark);
|
||||||
|
}
|
||||||
|
row.appendChild(label);
|
||||||
if (field.note) {
|
if (field.note) {
|
||||||
const note = document.createElement("div");
|
const note = document.createElement("div");
|
||||||
note.className = "env-field-note muted";
|
note.className = "env-field-note muted";
|
||||||
note.textContent = field.note;
|
note.textContent = field.note;
|
||||||
card.appendChild(note);
|
row.appendChild(note);
|
||||||
}
|
}
|
||||||
let input;
|
let input;
|
||||||
if (field.type === "bool") {
|
if (field.type === "bool") {
|
||||||
input = document.createElement("select");
|
input = document.createElement("select");
|
||||||
[
|
input.id = "env-f-" + field.key;
|
||||||
["true", "开启"],
|
[["true", "开启"], ["false", "关闭"]].forEach(([v, text]) => {
|
||||||
["false", "关闭"],
|
|
||||||
].forEach(([v, text]) => {
|
|
||||||
const o = document.createElement("option");
|
const o = document.createElement("option");
|
||||||
o.value = v;
|
o.value = v;
|
||||||
o.textContent = text;
|
o.textContent = text;
|
||||||
@@ -169,6 +199,7 @@
|
|||||||
input.value = cur === "true" || cur === "1" ? "true" : "false";
|
input.value = cur === "true" || cur === "1" ? "true" : "false";
|
||||||
} else {
|
} else {
|
||||||
input = document.createElement("input");
|
input = document.createElement("input");
|
||||||
|
input.id = "env-f-" + field.key;
|
||||||
input.type = field.sensitive ? "password" : "text";
|
input.type = field.sensitive ? "password" : "text";
|
||||||
if (field.sensitive && field.has_value) {
|
if (field.sensitive && field.has_value) {
|
||||||
input.placeholder = field.masked || "留空不修改";
|
input.placeholder = field.masked || "留空不修改";
|
||||||
@@ -178,52 +209,88 @@
|
|||||||
}
|
}
|
||||||
input.dataset.envKey = field.key;
|
input.dataset.envKey = field.key;
|
||||||
input.className = "env-field-input";
|
input.className = "env-field-input";
|
||||||
card.appendChild(input);
|
row.appendChild(input);
|
||||||
const badge = document.createElement("span");
|
return row;
|
||||||
badge.className = "env-field-badge " + (field.restart_required ? "env-badge-restart" : "env-badge-hot");
|
}
|
||||||
badge.textContent = field.restart_required ? "需重启" : "保存即生效";
|
|
||||||
card.appendChild(badge);
|
function renderEnvConfigBody(groups) {
|
||||||
return card;
|
const body = document.createElement("div");
|
||||||
|
body.className = "env-config-body card";
|
||||||
|
body.id = "env-config-body";
|
||||||
|
body.setAttribute("data-env-ssr", "1");
|
||||||
|
const tabBar = document.createElement("div");
|
||||||
|
tabBar.className = "env-config-tabs";
|
||||||
|
tabBar.setAttribute("role", "tablist");
|
||||||
|
const panelsWrap = document.createElement("div");
|
||||||
|
panelsWrap.className = "env-config-panels";
|
||||||
|
panelsWrap.id = "env-config-grid";
|
||||||
|
groups.forEach((group, idx) => {
|
||||||
|
const tab = document.createElement("button");
|
||||||
|
tab.type = "button";
|
||||||
|
tab.className = "env-tab-btn" + (idx === 0 ? " is-active" : "");
|
||||||
|
tab.setAttribute("role", "tab");
|
||||||
|
tab.dataset.envTab = String(idx);
|
||||||
|
tab.setAttribute("aria-selected", idx === 0 ? "true" : "false");
|
||||||
|
tab.textContent = group.title || "其他";
|
||||||
|
tabBar.appendChild(tab);
|
||||||
|
const panel = document.createElement("section");
|
||||||
|
panel.className = "env-panel" + (idx === 0 ? " is-active" : "");
|
||||||
|
panel.setAttribute("role", "tabpanel");
|
||||||
|
panel.dataset.envPanel = String(idx);
|
||||||
|
if (idx !== 0) panel.hidden = true;
|
||||||
|
if (group.has_restart) {
|
||||||
|
const hint = document.createElement("p");
|
||||||
|
hint.className = "env-panel-hint";
|
||||||
|
hint.textContent = "本组含需重启项,修改后请点「保存并重启」。";
|
||||||
|
panel.appendChild(hint);
|
||||||
|
}
|
||||||
|
const grid = document.createElement("div");
|
||||||
|
grid.className = "env-form-grid";
|
||||||
|
(group.fields || []).forEach((field) => grid.appendChild(renderEnvFieldRow(field)));
|
||||||
|
panel.appendChild(grid);
|
||||||
|
panelsWrap.appendChild(panel);
|
||||||
|
});
|
||||||
|
body.appendChild(tabBar);
|
||||||
|
body.appendChild(panelsWrap);
|
||||||
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadEnvConfig(force) {
|
async function loadEnvConfig(force) {
|
||||||
const grid = envConfigGrid();
|
const root = envConfigRoot();
|
||||||
if (!grid) return;
|
const body = root && root.querySelector("#env-config-body");
|
||||||
if (!force && grid.getAttribute("data-env-ssr") === "1" && grid.querySelector("[data-env-key]")) {
|
if (!force && body && body.getAttribute("data-env-ssr") === "1" && body.querySelector("[data-env-key]")) {
|
||||||
|
bindEnvTabs(root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return loadEnvConfigIn(grid);
|
return loadEnvConfigIn(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadEnvConfigIn(grid) {
|
async function loadEnvConfigIn(root) {
|
||||||
grid.innerHTML = '<div class="env-config-loading muted">加载配置中…</div>';
|
const page = root || envConfigRoot() || document.querySelector(".env-config-page");
|
||||||
|
if (!page) return;
|
||||||
|
page.removeAttribute("data-env-tabs-bound");
|
||||||
|
const loading = document.createElement("div");
|
||||||
|
loading.className = "env-config-loading-wrap card";
|
||||||
|
loading.id = "env-config-body";
|
||||||
|
loading.innerHTML = '<div class="env-config-loading muted">加载配置中…</div>';
|
||||||
|
const oldBody = page.querySelector("#env-config-body");
|
||||||
|
const oldGrid = page.querySelector("#env-config-grid.env-config-loading-wrap");
|
||||||
|
if (oldBody) oldBody.replaceWith(loading);
|
||||||
|
else if (oldGrid) oldGrid.replaceWith(loading);
|
||||||
try {
|
try {
|
||||||
const data = await fetchJson("/api/settings/env");
|
const data = await fetchJson("/api/settings/env");
|
||||||
envSchemaGroups = data.groups || [];
|
envSchemaGroups = data.groups || [];
|
||||||
grid.innerHTML = "";
|
loading.replaceWith(renderEnvConfigBody(envSchemaGroups));
|
||||||
envSchemaGroups.forEach((group) => {
|
bindEnvTabs(page);
|
||||||
const card = document.createElement("div");
|
|
||||||
card.className = "card env-group-card";
|
|
||||||
const h = document.createElement("h3");
|
|
||||||
h.className = "env-group-title";
|
|
||||||
h.textContent = group.title || "其他";
|
|
||||||
card.appendChild(h);
|
|
||||||
const inner = document.createElement("div");
|
|
||||||
inner.className = "env-group-fields";
|
|
||||||
(group.fields || []).forEach((field) => inner.appendChild(renderEnvField(field)));
|
|
||||||
card.appendChild(inner);
|
|
||||||
grid.appendChild(card);
|
|
||||||
});
|
|
||||||
grid.setAttribute("data-env-ssr", "1");
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
grid.innerHTML = '<span class="err">' + (e.message || "加载失败") + "</span>";
|
loading.innerHTML = '<span class="err">' + (e.message || "加载失败") + "</span>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function collectEnvValues() {
|
function collectEnvValues() {
|
||||||
const grid = envConfigGrid();
|
const root = envConfigRoot();
|
||||||
const values = {};
|
const values = {};
|
||||||
const scope = grid || document;
|
const scope = root || document;
|
||||||
scope.querySelectorAll(".env-field-input[data-env-key]").forEach((el) => {
|
scope.querySelectorAll(".env-field-input[data-env-key]").forEach((el) => {
|
||||||
values[el.dataset.envKey] = el.value;
|
values[el.dataset.envKey] = el.value;
|
||||||
});
|
});
|
||||||
@@ -310,6 +377,7 @@
|
|||||||
bindEvents();
|
bindEvents();
|
||||||
loadDisplayPrefsForm(false);
|
loadDisplayPrefsForm(false);
|
||||||
loadEnvConfig(false);
|
loadEnvConfig(false);
|
||||||
|
bindEnvTabs();
|
||||||
if (global.__INSTANCE_DISPLAY__) applyDisplayToNav(global.__INSTANCE_DISPLAY__);
|
if (global.__INSTANCE_DISPLAY__) applyDisplayToNav(global.__INSTANCE_DISPLAY__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2185,85 +2185,172 @@ html[data-theme="light"] .journal-detail-img-thumb {
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── env 配置页(三列卡片) ── */
|
/* ── env 配置页(Tab + 双列表单) ── */
|
||||||
.env-config-page {
|
.env-config-page {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-config-head {
|
.env-config-head {
|
||||||
padding: 12px 14px;
|
padding: 14px 16px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.env-config-head-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-config-head h2 {
|
||||||
|
margin: 0 0 4px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-config-head-hint {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
max-width: 42rem;
|
||||||
|
}
|
||||||
|
|
||||||
.env-config-toolbar {
|
.env-config-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-top: 10px;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-config-grid {
|
.env-config-body {
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-config-tabs {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
gap: 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
padding: 0 8px;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-tab-btn {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted, #8892b0);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 10px 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: color 0.15s, border-color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-tab-btn:hover {
|
||||||
|
color: #c5cae0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-tab-btn.is-active {
|
||||||
|
color: #e8ecff;
|
||||||
|
border-bottom-color: var(--accent, #7c6cf0);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-config-panels {
|
||||||
|
padding: 14px 16px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-panel-hint {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: rgba(251, 191, 36, 0.08);
|
||||||
|
color: #e8c468;
|
||||||
|
border: 1px solid rgba(251, 191, 36, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-form-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
gap: 12px;
|
gap: 12px 20px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-group-card {
|
.env-field-row {
|
||||||
padding: 10px 12px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-group-title {
|
.env-field-row--restart .env-field-label {
|
||||||
margin: 0 0 8px;
|
color: #d4c4a0;
|
||||||
font-size: 0.88rem;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.env-group-fields {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.env-field-card {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-field-label {
|
.env-field-label {
|
||||||
font-size: 0.72rem;
|
font-size: 0.8rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #a8b0cc;
|
color: #c5cae0;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-restart-mark {
|
||||||
|
color: #fbbf24;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-field-note {
|
.env-field-note {
|
||||||
font-size: 0.68rem;
|
font-size: 0.72rem;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
|
margin-top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-field-input {
|
.env-field-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 0.78rem;
|
font-size: 0.82rem;
|
||||||
|
padding: 7px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-field-badge {
|
.env-config-loading-wrap {
|
||||||
font-size: 0.65rem;
|
padding: 24px;
|
||||||
align-self: flex-start;
|
text-align: center;
|
||||||
padding: 1px 6px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.env-badge-hot {
|
/* 兼容旧结构 */
|
||||||
background: rgba(56, 178, 120, 0.15);
|
.env-config-grid {
|
||||||
color: #6ee7a8;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.env-group-card,
|
||||||
|
.env-field-card,
|
||||||
|
.env-field-badge,
|
||||||
|
.env-badge-hot,
|
||||||
.env-badge-restart {
|
.env-badge-restart {
|
||||||
background: rgba(251, 191, 36, 0.12);
|
display: none;
|
||||||
color: #fbbf24;
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.env-form-grid {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.env-config-head-row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.env-config-toolbar {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.display-prefs-form {
|
.display-prefs-form {
|
||||||
@@ -2314,13 +2401,13 @@ html[data-theme="light"] .journal-detail-img-thumb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1100px) {
|
@media (max-width: 1100px) {
|
||||||
.env-config-grid {
|
.env-form-grid {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
.env-config-grid {
|
.env-form-grid {
|
||||||
grid-template-columns: minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
.settings-password-form {
|
.settings-password-form {
|
||||||
|
|||||||
Vendored
+5
-1
@@ -207,7 +207,11 @@ def build_env_ui_payload(
|
|||||||
_build_field(key, label, note, schema, values)
|
_build_field(key, label, note, schema, values)
|
||||||
for key, label, note in sec["fields"]
|
for key, label, note in sec["fields"]
|
||||||
]
|
]
|
||||||
groups.append({"title": sec["title"], "fields": fields})
|
groups.append({
|
||||||
|
"title": sec["title"],
|
||||||
|
"fields": fields,
|
||||||
|
"has_restart": any(f.get("restart_required") for f in fields),
|
||||||
|
})
|
||||||
return groups
|
return groups
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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=72">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=73">
|
||||||
<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,7 +103,7 @@ 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=6"></script>
|
<script src="/static/instance_settings_prefs.js?v=7"></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=19"></script>
|
<script src="/static/instance_embed.js?v=19"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,29 +1,45 @@
|
|||||||
{# env配置:白名单分组,仅中文标签 #}
|
{# env配置:Tab 分类 + 双列表单,顶部统一保存 #}
|
||||||
<div class="env-config-page">
|
<div class="env-config-page">
|
||||||
<div class="env-config-head card">
|
<div class="env-config-head card">
|
||||||
|
<div class="env-config-head-row">
|
||||||
|
<div>
|
||||||
<h2>env 配置</h2>
|
<h2>env 配置</h2>
|
||||||
<p class="settings-env-hint">仅展示运营相关配置。标注「保存即生效」的项会立即应用;标注「需重启」的项保存后请点「保存并重启」。完整说明见项目文档 <code>docs/env配置说明.md</code>。</p>
|
<p class="settings-env-hint env-config-head-hint">按分类修改,改完点保存。含「需重启」的项请用「保存并重启」。</p>
|
||||||
|
</div>
|
||||||
<div class="env-config-toolbar">
|
<div class="env-config-toolbar">
|
||||||
<button type="button" class="btn-primary btn-sm" id="env-config-save">保存</button>
|
<button type="button" class="btn-primary btn-sm" id="env-config-save">保存</button>
|
||||||
<button type="button" class="btn-secondary btn-sm" id="env-config-save-restart">保存并重启</button>
|
<button type="button" class="btn-secondary btn-sm" id="env-config-save-restart">保存并重启</button>
|
||||||
<button type="button" class="btn-secondary btn-sm" id="env-config-reload">重新加载</button>
|
<button type="button" class="btn-secondary btn-sm" id="env-config-reload">重新加载</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<span class="settings-status-line" id="env-config-status"></span>
|
<span class="settings-status-line" id="env-config-status"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div id="env-config-grid" class="env-config-grid"{% if env_config_groups %} data-env-ssr="1"{% endif %}>
|
|
||||||
{% if env_config_groups %}
|
{% if env_config_groups %}
|
||||||
|
<div class="env-config-body card" data-env-ssr="1" id="env-config-body">
|
||||||
|
<div class="env-config-tabs" role="tablist" aria-label="配置分类">
|
||||||
{% for group in env_config_groups %}
|
{% for group in env_config_groups %}
|
||||||
<div class="card env-group-card">
|
<button type="button" class="env-tab-btn{% if loop.first %} is-active{% endif %}" role="tab" data-env-tab="{{ loop.index0 }}" aria-selected="{{ 'true' if loop.first else 'false' }}">{{ group.title }}</button>
|
||||||
<h3 class="env-group-title">{{ group.title or '其他' }}</h3>
|
{% endfor %}
|
||||||
<div class="env-group-fields">
|
</div>
|
||||||
|
<div class="env-config-panels" id="env-config-grid">
|
||||||
|
{% for group in env_config_groups %}
|
||||||
|
<section class="env-panel{% if loop.first %} is-active{% endif %}" role="tabpanel" data-env-panel="{{ loop.index0 }}"{% if not loop.first %} hidden{% endif %}>
|
||||||
|
{% if group.has_restart %}
|
||||||
|
<p class="env-panel-hint">本组含需重启项,修改后请点「保存并重启」。</p>
|
||||||
|
{% endif %}
|
||||||
|
<div class="env-form-grid">
|
||||||
{% for field in group.fields %}
|
{% for field in group.fields %}
|
||||||
<div class="env-field-card">
|
<div class="env-field-row{% if field.restart_required %} env-field-row--restart{% endif %}">
|
||||||
<label class="env-field-label">{{ field.label or field.key }}</label>
|
<label class="env-field-label" for="env-f-{{ field.key }}">
|
||||||
|
{{ field.label or field.key }}
|
||||||
|
{% if field.restart_required %}<span class="env-restart-mark" title="需重启">*</span>{% endif %}
|
||||||
|
</label>
|
||||||
{% if field.note %}
|
{% if field.note %}
|
||||||
<div class="env-field-note muted">{{ field.note }}</div>
|
<div class="env-field-note muted">{{ field.note }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if field.type == 'bool' %}
|
{% if field.type == 'bool' %}
|
||||||
<select class="env-field-input" data-env-key="{{ field.key }}">
|
<select class="env-field-input" id="env-f-{{ field.key }}" data-env-key="{{ field.key }}">
|
||||||
{% set cur = (field.current or field.default or 'false')|lower %}
|
{% set cur = (field.current or field.default or 'false')|lower %}
|
||||||
<option value="true"{% if cur in ('true', '1', 'yes', 'on') %} selected{% endif %}>开启</option>
|
<option value="true"{% if cur in ('true', '1', 'yes', 'on') %} selected{% endif %}>开启</option>
|
||||||
<option value="false"{% if cur not in ('true', '1', 'yes', 'on') %} selected{% endif %}>关闭</option>
|
<option value="false"{% if cur not in ('true', '1', 'yes', 'on') %} selected{% endif %}>关闭</option>
|
||||||
@@ -31,6 +47,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<input
|
<input
|
||||||
class="env-field-input"
|
class="env-field-input"
|
||||||
|
id="env-f-{{ field.key }}"
|
||||||
type="{% if field.sensitive %}password{% else %}text{% endif %}"
|
type="{% if field.sensitive %}password{% else %}text{% endif %}"
|
||||||
data-env-key="{{ field.key }}"
|
data-env-key="{{ field.key }}"
|
||||||
{% if field.sensitive and field.has_value %}
|
{% if field.sensitive and field.has_value %}
|
||||||
@@ -40,16 +57,16 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
>
|
>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span class="env-field-badge {% if field.restart_required %}env-badge-restart{% else %}env-badge-hot{% endif %}">
|
|
||||||
{% if field.restart_required %}需重启{% else %}保存即生效{% endif %}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
<div id="env-config-grid" class="env-config-loading-wrap card">
|
||||||
<div class="env-config-loading muted">加载配置中…</div>
|
<div class="env-config-loading muted">加载配置中…</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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=72">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=73">
|
||||||
|
|
||||||
</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=6"></script>
|
<script src="/static/instance_settings_prefs.js?v=7"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user