diff --git a/lib/common/static/instance_theme.css b/lib/common/static/instance_theme.css index 5a62a78..36b4129 100644 --- a/lib/common/static/instance_theme.css +++ b/lib/common/static/instance_theme.css @@ -2197,12 +2197,48 @@ html[data-theme="light"] .journal-detail-img-thumb { .settings-side-col { display: flex; flex-direction: column; - gap: 8px; + gap: 0; align-self: stretch; height: 100%; min-height: 0; } +.settings-card--side-panel { + height: 100%; + min-height: 0; + display: flex; + flex-direction: column; + padding: 10px 12px; + overflow: hidden; +} + +.settings-side-subcards { + display: flex; + flex-direction: column; + gap: 8px; + flex: 1 1 auto; + min-height: 0; +} + +.settings-side-subcards > .settings-subcard { + flex: 1 1 0; + min-height: 0; + overflow-y: auto; + padding: 8px 10px; + margin: 0; +} + +.settings-side-subcards > .settings-subcard--export { + flex: 0 0 auto; + overflow: visible; +} + +.settings-subcard-desc { + font-size: 0.7rem; + margin: 0 0 6px; + line-height: 1.4; +} + .settings-card--risk { min-width: 0; height: 100%; @@ -2210,28 +2246,13 @@ html[data-theme="light"] .journal-detail-img-thumb { flex-direction: column; } -.settings-side-col > .settings-card { - flex: 1 1 0; - min-height: 0; - overflow-y: auto; - display: flex; - flex-direction: column; -} - -.settings-side-col > .settings-card--export { - flex: 0 0 auto; - min-height: 0; - overflow: visible; -} - -.settings-side-col .settings-card--export .settings-link-list { +.settings-link-list--export { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; - flex: 0 0 auto; } -.settings-side-col .settings-card--export .settings-export-link { +.settings-link-list--export .settings-export-link { display: flex; align-items: center; justify-content: center; @@ -2244,7 +2265,7 @@ html[data-theme="light"] .journal-detail-img-thumb { } @media (max-width: 520px) { - .settings-side-col .settings-card--export .settings-link-list { + .settings-link-list--export { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @@ -2842,10 +2863,89 @@ html[data-theme="light"] .settings-export-link { margin: 0 0 6px; line-height: 1.45; } +.options-transfer-compact { + display: flex; + flex-direction: column; + gap: 8px; +} + +.options-transfer-block { + display: flex; + flex-direction: column; + gap: 4px; +} + +.options-transfer-head { + font-size: 0.72rem; + font-weight: 600; + color: #a8b0cc; + line-height: 1.3; +} + +.options-transfer-line { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 5px; +} + +.options-transfer-acct { + font-size: 0.68rem; + color: #8892b0; + white-space: nowrap; + padding: 0 2px; +} + +.opt-set-chip-group { + display: inline-flex; + border: 1px solid var(--border-soft, #2a3150); + border-radius: 6px; + overflow: hidden; + flex-shrink: 0; +} + +.opt-set-chip { + border: none; + background: transparent; + color: #a8b0cc; + font-size: 0.68rem; + line-height: 1.2; + padding: 4px 7px; + cursor: pointer; + white-space: nowrap; +} + +.opt-set-chip:hover { + background: rgba(143, 200, 255, 0.08); + color: #cfd3ef; +} + +.opt-set-chip.active { + background: #1f3a5a; + color: #8fc8ff; +} + +.opt-set-amount { + width: 72px; + min-width: 64px; + font-size: 0.72rem; + padding: 4px 6px; + min-height: 26px; +} + +.options-swap-compact .options-settings-hint { + margin: 0 0 5px; +} + +.options-swap-compact .options-transfer-line { + margin-bottom: 0; +} + .options-settings-msg { - font-size: 0.7rem; - margin-top: 4px; + font-size: 0.68rem; + margin-top: 2px; min-height: 1em; + line-height: 1.35; } .pos-pnl-profit { color: #7ee787; diff --git a/lib/common/static/options_settings.js b/lib/common/static/options_settings.js index 4e7f27b..06c8b36 100644 --- a/lib/common/static/options_settings.js +++ b/lib/common/static/options_settings.js @@ -16,60 +16,99 @@ el.classList.toggle("opt-error", !!isErr); } - document.getElementById("opt-set-swap-btn").addEventListener("click", async function () { - const amount = parseFloat(document.getElementById("opt-set-swap-amount").value); - if (!amount || amount <= 0) { - setMsg("opt-set-swap-msg", "请输入有效数量", true); - return; - } - const d = await apiJson("/api/options/spot/swap", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - direction: document.getElementById("opt-set-swap-dir").value, - amount: amount, - }), + function wireChipGroup(id) { + const group = document.getElementById(id); + if (!group) return function () { + return null; + }; + const chips = group.querySelectorAll(".opt-set-chip"); + chips.forEach(function (chip) { + chip.addEventListener("click", function () { + chips.forEach(function (c) { + c.classList.remove("active"); + }); + chip.classList.add("active"); + }); }); - setMsg("opt-set-swap-msg", d.ok ? "兑换单已提交" : (d.msg || "失败"), !d.ok); - }); + return function () { + return group.querySelector(".opt-set-chip.active"); + }; + } - document.getElementById("opt-set-int-btn").addEventListener("click", async function () { - const amount = parseFloat(document.getElementById("opt-set-int-amount").value); - if (!amount || amount <= 0) { - setMsg("opt-set-int-msg", "请输入有效数量", true); - return; - } - const d = await apiJson("/api/options/transfer", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - ccy: document.getElementById("opt-set-int-ccy").value, - from: document.getElementById("opt-set-int-from").value, - to: document.getElementById("opt-set-int-to").value, - amount: amount, - }), - }); - setMsg("opt-set-int-msg", d.ok ? "划转成功" : (d.msg || "失败"), !d.ok); - }); + const activeSwapDir = wireChipGroup("opt-set-swap-dir"); + const activeIntDir = wireChipGroup("opt-set-int-dir"); + const activeIntCcy = wireChipGroup("opt-set-int-ccy"); + const activeCrossDir = wireChipGroup("opt-set-cross-dir"); + const activeCrossCcy = wireChipGroup("opt-set-cross-ccy"); - document.getElementById("opt-set-cross-btn").addEventListener("click", async function () { - const amount = parseFloat(document.getElementById("opt-set-cross-amount").value); - if (!amount || amount <= 0) { - setMsg("opt-set-cross-msg", "请输入有效数量", true); - return; - } - const d = await apiJson("/api/options/cross-transfer", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - ccy: document.getElementById("opt-set-cross-ccy").value, - amount: amount, - from_account: document.getElementById("opt-set-cross-from-acct").value, - to_account: document.getElementById("opt-set-cross-to-acct").value, - direction: document.getElementById("opt-set-cross-dir").value, - }), + const swapBtn = document.getElementById("opt-set-swap-btn"); + if (swapBtn) { + swapBtn.addEventListener("click", async function () { + const amount = parseFloat(document.getElementById("opt-set-swap-amount").value); + if (!amount || amount <= 0) { + setMsg("opt-set-swap-msg", "请输入有效数量", true); + return; + } + const dirChip = activeSwapDir(); + const d = await apiJson("/api/options/spot/swap", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + direction: (dirChip && dirChip.getAttribute("data-dir")) || "usdt_to_usdc", + amount: amount, + }), + }); + setMsg("opt-set-swap-msg", d.ok ? "兑换单已提交" : (d.msg || "失败"), !d.ok); }); - setMsg("opt-set-cross-msg", d.ok ? "划转成功" : (d.msg || "失败"), !d.ok); - if (d.ok && typeof refreshAccountSnapshot === "function") refreshAccountSnapshot(); - }); + } + + const intBtn = document.getElementById("opt-set-int-btn"); + if (intBtn) { + intBtn.addEventListener("click", async function () { + const amount = parseFloat(document.getElementById("opt-set-int-amount").value); + if (!amount || amount <= 0) { + setMsg("opt-set-int-msg", "请输入有效数量", true); + return; + } + const dirChip = activeIntDir(); + const ccyChip = activeIntCcy(); + const d = await apiJson("/api/options/transfer", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + ccy: (ccyChip && ccyChip.getAttribute("data-ccy")) || "USDC", + from: (dirChip && dirChip.getAttribute("data-from")) || "funding", + to: (dirChip && dirChip.getAttribute("data-to")) || "trading", + amount: amount, + }), + }); + setMsg("opt-set-int-msg", d.ok ? "划转成功" : (d.msg || "失败"), !d.ok); + }); + } + + const crossBtn = document.getElementById("opt-set-cross-btn"); + if (crossBtn) { + crossBtn.addEventListener("click", async function () { + const amount = parseFloat(document.getElementById("opt-set-cross-amount").value); + if (!amount || amount <= 0) { + setMsg("opt-set-cross-msg", "请输入有效数量", true); + return; + } + const dirChip = activeCrossDir(); + const ccyChip = activeCrossCcy(); + const d = await apiJson("/api/options/cross-transfer", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + ccy: (ccyChip && ccyChip.getAttribute("data-ccy")) || "USDT", + amount: amount, + from_account: "funding", + to_account: "funding", + direction: (dirChip && dirChip.getAttribute("data-dir")) || "sub_to_main", + }), + }); + setMsg("opt-set-cross-msg", d.ok ? "划转成功" : (d.msg || "失败"), !d.ok); + if (d.ok && typeof refreshAccountSnapshot === "function") refreshAccountSnapshot(); + }); + } })(); diff --git a/lib/instance/templates/embed_shell.html b/lib/instance/templates/embed_shell.html index 8196fbb..7b52524 100644 --- a/lib/instance/templates/embed_shell.html +++ b/lib/instance/templates/embed_shell.html @@ -7,7 +7,7 @@ - + {{ exchange_display }} · 加密货币 | 交易监控复盘系统 diff --git a/lib/instance/templates/index.html b/lib/instance/templates/index.html index 00cd738..9d4a7c6 100644 --- a/lib/instance/templates/index.html +++ b/lib/instance/templates/index.html @@ -17,7 +17,7 @@ {{ exchange_display }} · 加密货币 | 交易监控复盘系统 - +
- {% if instance_settings.options_settings_enabled %} -
-

币种兑换

- {% include 'options_settings_swap.html' %} -
-
-

资金划转

-

主账户期权资金:账户内划转、主账户与子账户之间划转。

- {% include 'options_settings_transfer.html' %} -
- {% include 'options_settings_panel.html' %} - {% endif %} - {% if instance_settings.show_transfer %} -
-

永续资金划转

-

子账户永续:资金账户与交易账户之间划转 USDT。

- {% include 'instance_transfer_panel.html' %} -
- {% endif %} +
+
+ {% if instance_settings.options_settings_enabled %} +
+

币种兑换

+ {% include 'options_settings_swap.html' %} +
+
+

期权资金划转

+ {% include 'options_settings_transfer.html' %} +
+ {% include 'options_settings_panel.html' %} + {% endif %} + {% if instance_settings.show_transfer %} +
+

永续资金划转

+

子账户永续:资金账户与交易账户之间划转 USDT。

+ {% include 'instance_transfer_panel.html' %} +
+ {% endif %} -
-

数据导出

-

- CSV · UTF-8 · v{{ instance_settings.data_export_version }}。 - 交易记录含开仓类型列;复盘单独导出。 -

-
diff --git a/lib/options/templates/options_settings_panel.html b/lib/options/templates/options_settings_panel.html index fe1cad9..fbdaeba 100644 --- a/lib/options/templates/options_settings_panel.html +++ b/lib/options/templates/options_settings_panel.html @@ -1,4 +1,4 @@ {# 期权设置脚本挂载点(卡片在 settings_panel 中拆分) #} - + diff --git a/lib/options/templates/options_settings_swap.html b/lib/options/templates/options_settings_swap.html index 3e659fa..2ceb91f 100644 --- a/lib/options/templates/options_settings_swap.html +++ b/lib/options/templates/options_settings_swap.html @@ -1,12 +1,12 @@ -
-

主账户资金账户:USDT ↔ USDC,走 USDC-USDT 现货市价单。

-
- - - +
+

主账户资金账户:USDT ↔ USDC 现货市价单。

+
+
+ + +
+ +
diff --git a/lib/options/templates/options_settings_transfer.html b/lib/options/templates/options_settings_transfer.html index bd13b60..aaaf5d6 100644 --- a/lib/options/templates/options_settings_transfer.html +++ b/lib/options/templates/options_settings_transfer.html @@ -1,47 +1,39 @@ -
-
主账户内
-
- - - - - - +
+
+
主账户内
+
+
+ + +
+
+ + +
+ + +
+
-
-
-
-
主账户 ↔ 子账户 ({{ instance_settings.options_sub_account or '未配置' }})
-
- - - - - - - +
+
+ 主子账户 + ({{ instance_settings.options_sub_account or '未配置' }}) +
+
+
+ + +
+
+ + +
+ 资金↔资金 + + +
+
-