diff --git a/lib/common/static/hedge_plan.js b/lib/common/static/hedge_plan.js index 4c35a65..f296605 100644 --- a/lib/common/static/hedge_plan.js +++ b/lib/common/static/hedge_plan.js @@ -15,12 +15,13 @@ function pickDefaultTab() { if (showPerp) return "perp_options"; if (showOo) return "options_options"; - return "active"; + return "perp_options"; } const state = { tab: pickDefaultTab(), mode: showPerp ? "perp_options" : showOo ? "options_options" : "perp_options", + posTab: "live", underlying: root.getAttribute("data-default-underly") || "ETH", moneyFilter: root.getAttribute("data-option-primary") !== "0" ? "all" : "itm", ooMoneyFilter: "atm_otm", // 期期锁定:平值+虚值 @@ -29,6 +30,7 @@ poStrikeExpandAll: false, // 永期手动选约:默认平值+实3+虚3 chain: null, selected: null, + orderDialogOpen: false, legA: null, legB: null, market: null, @@ -72,7 +74,7 @@ if (isOptionPrimary()) { hint.textContent = (dir === "short" ? "买 Put + 永续多" : "买 Call + 永续空") + - " · 点「选择」填入右侧手动下单;比例默认 2(期权 1 → 永续 0.5)。"; + " · 点「选择」弹窗下单;比例默认 2(期权 1 → 永续 0.5)。"; } else { hint.textContent = dir === "short" ? "永续空 + 保险 Call" : "永续多 + 保险 Put"; } @@ -89,8 +91,11 @@ state.direction = next; syncPoDirUI(); if (!changed && !forceReload) return; - state.selected = null; - if ($("hp-sel-inst")) $("hp-sel-inst").textContent = "—"; + if (state.orderDialogOpen) closeOrderDialog(); + else { + state.selected = null; + if ($("hp-sel-inst")) $("hp-sel-inst").textContent = "—"; + } void loadMarket().then(function () { renderListStrikes(); }); @@ -681,7 +686,7 @@ if (!btn) return; if (isOptionPrimary()) { btn.textContent = "手动下单"; - btn.title = "按左侧已选合约卖一限价开仓(买期权+对冲永续);非交易所市价单、非条件盯盘"; + btn.title = "弹窗内确认:按已选合约卖一限价开仓(买期权+对冲永续);非交易所市价单"; } else { btn.textContent = "计算"; btn.title = "情景测算后再启动"; @@ -777,13 +782,110 @@ return (Math.round((1 / a) * 10) / 10).toFixed(1) + "×"; } - function clearPoSelection() { + const orderPanelHome = (function () { + const host = document.getElementById("hp-order-panel-host"); + return host ? host.parentElement : null; + })(); + + function orderPanel() { + return $("hp-order-panel"); + } + + function orderPanelHost() { + return $("hp-order-panel-host"); + } + + function parkOrderPanel() { + const panel = orderPanel(); + const host = orderPanelHost(); + if (panel && host && panel.parentElement !== host) host.appendChild(panel); + if (host) { + host.hidden = true; + host.setAttribute("aria-hidden", "true"); + if (orderPanelHome && host.parentElement !== orderPanelHome) { + orderPanelHome.appendChild(host); + } + } + if (panel) panel.style.display = "none"; + state.orderDialogOpen = false; + const tbody = $("hp-strike-tbody"); + if (tbody) { + tbody.querySelectorAll(".opt-strike-row").forEach(function (r) { + r.classList.remove("opt-row-selected"); + }); + tbody.querySelectorAll(".hp-pick").forEach(function (b) { + b.classList.remove("active"); + if (b.dataset.origText) b.textContent = b.dataset.origText; + }); + } + } + + function openOrderDialog(instId) { + const panel = orderPanel(); + const host = orderPanelHost(); + if (!panel || !host) return false; + if (panel.parentElement !== host) host.appendChild(panel); + if (host.parentElement !== document.body) document.body.appendChild(host); + host.hidden = false; + host.setAttribute("aria-hidden", "false"); + panel.style.display = ""; + state.orderDialogOpen = true; + const tbody = $("hp-strike-tbody"); + if (tbody && instId) { + tbody.querySelectorAll(".opt-strike-row").forEach(function (r) { + r.classList.toggle("opt-row-selected", r.getAttribute("data-inst") === instId); + }); + tbody.querySelectorAll(".hp-pick").forEach(function (b) { + if (!b.dataset.origText) b.dataset.origText = "选择"; + const on = b.getAttribute("data-inst") === instId; + b.classList.toggle("active", on); + b.textContent = on ? "已选" : b.dataset.origText; + }); + } + return true; + } + + function closeOrderDialog() { state.selected = null; + parkOrderPanel(); if ($("hp-sel-inst")) $("hp-sel-inst").textContent = "—"; updatePremiumLine(); updatePerpPnlHint(); } + function clearPoSelection() { + state.selected = null; + if ($("hp-sel-inst")) $("hp-sel-inst").textContent = "—"; + if (state.orderDialogOpen) parkOrderPanel(); + updatePremiumLine(); + updatePerpPnlHint(); + } + + function setHpPosTab(tab) { + const next = tab === "pending" || tab === "history" || tab === "stats" ? tab : "live"; + state.posTab = next; + document.querySelectorAll(".hp-pos-tab").forEach(function (btn) { + const on = btn.getAttribute("data-hp-pos-tab") === next; + btn.classList.toggle("active", on); + btn.setAttribute("aria-selected", on ? "true" : "false"); + }); + document.querySelectorAll("[data-hp-pos-pane]").forEach(function (pane) { + const on = pane.getAttribute("data-hp-pos-pane") === next; + pane.classList.toggle("is-active", on); + if (on) pane.removeAttribute("hidden"); + else pane.setAttribute("hidden", ""); + }); + if (next === "live" || next === "pending") void loadActivePlans(); + else if (next === "history") void loadHistory(); + else if (next === "stats") void loadStats(); + } + + function refreshHpPosPanel() { + void loadActivePlans(); + void loadHistory(); + if (state.posTab === "stats") void loadStats(); + } + /** 手动选约:不自动代选;仅在已选失效(换 Call/Put 或筛掉)时清空. */ function autoMatchPoOption(force) { if (!isOptionPrimary()) return; @@ -873,7 +975,7 @@ b.classList.toggle("active", on); b.setAttribute("aria-selected", on ? "true" : "false"); }); - ["perp_options", "options_options", "active", "history", "stats"].forEach(function (id) { + ["perp_options", "options_options"].forEach(function (id) { const panel = $("hp-tab-" + id); if (!panel) return; const on = id === tab; @@ -884,6 +986,9 @@ if (tab === "perp_options" || tab === "options_options") { state.mode = tab; } + if (tab === "perp_options") { + refreshHpPosPanel(); + } const hint = $("hp-acct-hint"); if (hint) { if (tab === "options_options") { @@ -1472,18 +1577,9 @@ state.selected = c; const el = $("hp-sel-inst"); if (el) el.textContent = c.inst_id; - const tbody = $("hp-strike-tbody"); - if (tbody) { - tbody.querySelectorAll(".opt-strike-row").forEach(function (r) { - r.classList.toggle("opt-row-selected", r.getAttribute("data-inst") === c.inst_id); - }); - tbody.querySelectorAll(".hp-pick").forEach(function (b) { - b.classList.toggle("active", b.getAttribute("data-inst") === c.inst_id); - }); - } updatePremiumLine(); if (isOptionPrimary()) { - // 手动下单以张数为主:选约后若未填张数则默认 1,并同步左右 + // 手动下单以张数为主:选约后若未填张数则默认 1 if (!(orderSheets() > 0)) { if ($("hp-sheets")) $("hp-sheets").value = "1"; if ($("hp-order-sheets")) $("hp-order-sheets").value = "1"; @@ -1491,10 +1587,11 @@ syncSheetsInputs("hp-order-sheets"); if (!(numInput("hp-order-sheets", 0) > 0)) syncSheetsInputs("hp-sheets"); } - void loadMarket(); updatePerpPnlHint(); updatePoOpenSummary(); } + openOrderDialog(c.inst_id); + void loadMarket(); } function renderListStrikes() { @@ -1608,11 +1705,11 @@ if (line) line.textContent = ""; return; } - const sheets = Number(($("hp-sheets") && $("hp-sheets").value) || 1); + const sheets = Math.max(1, orderSheets() || Number(($("hp-sheets") && $("hp-sheets").value) || 1)); const ct = Number(state.selected.ct_mult || 0.01); const ask = Number(state.selected.ask || 0); const prem = ask * sheets * ct; - line.textContent = "预估权利金 ≈ " + fmt(prem, 4) + " 币(币本位)"; + line.textContent = "预估权利金 ≈ " + fmt(prem, 4) + " 币(币本位) · 卖一 " + fmt(ask, 4); } function buildStraddleRows(contracts) { @@ -1881,7 +1978,8 @@ state.underlying = next; syncUnderlyingUI(); if (!changed && !forceReload) return; - state.selected = null; + if (state.orderDialogOpen) closeOrderDialog(); + else state.selected = null; state.legA = null; state.legB = null; state.ooRecommend = null; @@ -2133,18 +2231,36 @@ if (state.tab === "perp_options" || state.tab === "options_options") { void loadGates(); if (state.tab === "perp_options") void refreshPoStrategyStatus(); - } else if (state.tab === "active") { - void loadActivePlans(); - } else if (state.tab === "history") { - void loadHistory(); - } else if (state.tab === "stats") { - void loadStats(); } else { const el = $("hp-gate-line"); if (el) el.textContent = ""; } }); }); + document.querySelectorAll(".hp-pos-tab").forEach(function (btn) { + btn.addEventListener("click", function () { + setHpPosTab(btn.getAttribute("data-hp-pos-tab") || "live"); + }); + }); + if ($("hp-pos-refresh")) { + $("hp-pos-refresh").addEventListener("click", function () { + refreshHpPosPanel(); + }); + } + function onOrderDialogClose() { + closeOrderDialog(); + } + if ($("hp-order-close-btn")) $("hp-order-close-btn").addEventListener("click", onOrderDialogClose); + if ($("hp-order-cancel-btn")) $("hp-order-cancel-btn").addEventListener("click", onOrderDialogClose); + const orderHost = orderPanelHost(); + if (orderHost) { + orderHost.addEventListener("click", function (ev) { + if (ev.target === orderHost) closeOrderDialog(); + }); + } + document.addEventListener("keydown", function (ev) { + if (ev.key === "Escape" && state.orderDialogOpen) closeOrderDialog(); + }); document.querySelectorAll(".hp-uly-btn, .hp-uly-btn-oo").forEach(function (b) { b.addEventListener("click", function () { setUnderlying(b.getAttribute("data-uly") || "ETH", true); @@ -2617,65 +2733,92 @@ return map[st] || st || "—"; } - async function loadActivePlans() { - const tbody = $("hp-active-tbody"); + function bindActivePlanRowActions(tbody) { if (!tbody) return; + tbody.querySelectorAll(".hp-btn-detail").forEach(function (btn) { + btn.addEventListener("click", function () { + void showPlanDetail(Number(btn.getAttribute("data-id"))); + }); + }); + tbody.querySelectorAll(".hp-btn-complete").forEach(function (btn) { + btn.addEventListener("click", function () { + void completeMissingLeg(Number(btn.getAttribute("data-id"))); + }); + }); + tbody.querySelectorAll(".hp-btn-end").forEach(function (btn) { + btn.addEventListener("click", function () { + void endActivePlan(Number(btn.getAttribute("data-id"))); + }); + }); + } + + function isPendingPlan(p) { + const st = String((p && p.status) || "").toLowerCase(); + return st === "watching" || st === "pending"; + } + + function renderActivePlanRows(tbody, rows, emptyMsg, colMode) { + if (!tbody) return; + if (!rows.length) { + tbody.innerHTML = '
" +
+ contracts +
+ "" +
- contracts +
- "永续腿→合约账户 · 期权腿→期权账户
@@ -45,163 +42,220 @@