(function () { "use strict"; function syncRollFormMode(form, mode) { if (!form) return; const m = mode || "market"; form.setAttribute("data-add-mode", m); const showFib = m === "fib_618" || m === "fib_786"; const showBreakout = m === "breakout"; const fibWrap = form.querySelector(".roll-field-fib"); const breakoutWrap = form.querySelector(".roll-field-breakout"); const fibUpper = form.querySelector("#roll-fib-upper"); const fibLower = form.querySelector("#roll-fib-lower"); const breakoutInput = form.querySelector("#roll-breakout"); function tuneInput(inp, active, required) { if (!inp) return; inp.disabled = !active; inp.required = !!required && active; inp.tabIndex = active ? 0 : -1; if (!active) inp.value = ""; } if (fibWrap) fibWrap.setAttribute("aria-hidden", showFib ? "false" : "true"); if (breakoutWrap) breakoutWrap.setAttribute("aria-hidden", showBreakout ? "false" : "true"); tuneInput(fibUpper, showFib, showFib); tuneInput(fibLower, showFib, showFib); tuneInput(breakoutInput, showBreakout, showBreakout); } window.syncRollFormMode = syncRollFormMode; const form = document.getElementById("roll-form"); if (!form) return; const symbolSel = document.getElementById("roll-symbol"); const dirInput = document.getElementById("roll-direction"); const modeSel = document.getElementById("roll-add-mode"); const riskBanner = document.getElementById("roll-risk-banner"); const previewBtn = document.getElementById("roll-preview-btn"); const submitBtn = document.getElementById("roll-submit-btn"); const previewBox = document.getElementById("roll-preview-box"); const previewText = document.getElementById("roll-preview-text"); const countdownEl = document.getElementById("roll-countdown"); const trendLocked = submitBtn && submitBtn.getAttribute("data-trend-locked") === "1"; let countdownTimer = null; let previewOk = false; let lastPreviewMode = ""; let allowMonitorSubmit = false; function isMarketMode() { return (modeSel.value || "market") === "market"; } function isMonitorMode() { const m = modeSel.value || "market"; return m === "fib_618" || m === "fib_786" || m === "breakout"; } function selectedOption() { return symbolSel.options[symbolSel.selectedIndex]; } function syncDirectionLock() { const opt = selectedOption(); if (!opt || !opt.value) { riskBanner.textContent = "当前风险:请选择持仓币种"; return; } const dir = opt.getAttribute("data-direction") || "long"; const rp = opt.getAttribute("data-risk-percent") || "—"; dirInput.value = dir; riskBanner.textContent = "当前风险:" + rp + "%(来自监控单 #" + (opt.getAttribute("data-monitor-id") || "?") + ")"; } function syncSubmitButton() { if (!submitBtn || trendLocked) return; if (isMonitorMode()) { submitBtn.disabled = false; return; } submitBtn.disabled = !previewOk || !!countdownTimer; } function clearMessageBox() { if (!previewBox) return; previewBox.style.display = "none"; previewBox.classList.remove("is-error", "is-preview"); if (previewText) previewText.textContent = ""; if (countdownEl) countdownEl.style.display = "none"; } function showReject(msg) { if (!previewBox || !previewText) return; previewBox.style.display = "block"; previewBox.classList.remove("is-preview"); previewBox.classList.add("is-error"); previewText.textContent = msg || "无法执行"; if (countdownEl) countdownEl.style.display = "none"; } function showPreviewResult(p) { if (!previewBox || !previewText) return; previewBox.style.display = "block"; previewBox.classList.remove("is-error"); previewBox.classList.add("is-preview"); previewText.innerHTML = "" + (p.add_mode_label || "") + " · 约 " + (p.add_amount_display != null ? p.add_amount_display : p.add_amount_raw) + "
" + "加仓参考价 " + (p.add_price_display != null ? p.add_price_display : p.add_price) + " · 新止损 " + (p.new_sl_display != null ? p.new_sl_display : p.new_stop_loss) + "
" + "合并均价 " + p.avg_entry_after + " · 打到止损约 " + p.loss_at_sl_usdt + "U(风险预算 " + (p.risk_budget_usdt != null ? p.risk_budget_usdt : "—") + "U)"; } function syncFieldVisibility() { syncRollFormMode(form, modeSel.value || "market"); resetPreview(); } function resetPreview() { previewOk = false; allowMonitorSubmit = false; clearMessageBox(); if (countdownTimer) { clearInterval(countdownTimer); countdownTimer = null; } syncSubmitButton(); } function formPayload() { const fd = new FormData(form); const obj = {}; fd.forEach(function (v, k) { if (v !== "") obj[k] = v; }); return obj; } function requestPreview() { return fetch("/strategy/roll/preview", { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json" }, body: JSON.stringify(formPayload()), credentials: "same-origin", }).then(function (r) { return r.json(); }); } function runPreview() { resetPreview(); if (!symbolSel.value) { showReject("请先选择持仓币种"); return; } if (previewBtn) previewBtn.disabled = true; requestPreview() .then(function (data) { if (previewBtn) previewBtn.disabled = false; if (!data.ok) { showReject(data.msg || "预览失败"); return; } const p = data.preview || {}; lastPreviewMode = p.add_mode || modeSel.value; showPreviewResult(p); previewOk = true; if (lastPreviewMode === "market") { startCountdown(10); } else { syncSubmitButton(); } }) .catch(function () { if (previewBtn) previewBtn.disabled = false; showReject("预览请求失败,请稍后重试"); }); } function runMonitorSubmit() { if (!symbolSel.value) { showReject("请先选择持仓币种"); return; } if (submitBtn) submitBtn.disabled = true; requestPreview() .then(function (data) { if (submitBtn && !trendLocked) submitBtn.disabled = false; if (!data.ok) { showReject(data.msg || "无法提交监控"); return; } const p = data.preview || {}; const modeLabel = modeSel.options[modeSel.selectedIndex].text; const summary = "约 " + (p.add_amount_display != null ? p.add_amount_display : p.add_amount_raw) + " 张 · 触发参考价 " + (p.add_price_display != null ? p.add_price_display : p.add_price) + " · 新止损 " + (p.new_sl_display != null ? p.new_sl_display : p.new_stop_loss); if (!confirm("确认提交「" + modeLabel + "」?\n" + summary)) { return; } allowMonitorSubmit = true; form.requestSubmit(); }) .catch(function () { if (submitBtn && !trendLocked) submitBtn.disabled = false; showReject("校验请求失败,请稍后重试"); }); } function startCountdown(sec) { let left = sec; if (submitBtn) submitBtn.disabled = true; if (countdownEl) { countdownEl.style.display = "block"; countdownEl.textContent = "市价加仓:" + left + " 秒后可执行(修改表单将取消预览)"; } countdownTimer = setInterval(function () { left -= 1; if (left <= 0) { clearInterval(countdownTimer); countdownTimer = null; if (countdownEl) countdownEl.textContent = "可以执行市价加仓"; syncSubmitButton(); return; } if (countdownEl) countdownEl.textContent = "市价加仓:" + left + " 秒后可执行"; }, 1000); } symbolSel.addEventListener("change", function () { syncDirectionLock(); resetPreview(); }); modeSel.addEventListener("change", syncFieldVisibility); form.addEventListener("input", resetPreview); form.addEventListener("change", function (e) { if (e.target !== previewBtn) resetPreview(); }); if (previewBtn) previewBtn.addEventListener("click", runPreview); form.addEventListener("submit", function (e) { if (isMonitorMode()) { if (allowMonitorSubmit) { allowMonitorSubmit = false; return; } e.preventDefault(); runMonitorSubmit(); return; } if (!previewOk) { e.preventDefault(); showReject("请先点击「预览」并通过校验"); return; } if (submitBtn && submitBtn.disabled) { e.preventDefault(); showReject("请等待 10 秒确认倒计时结束后再执行市价加仓"); return; } const modeLabel = modeSel.options[modeSel.selectedIndex].text; if (!confirm("确认提交「" + modeLabel + "」?")) { e.preventDefault(); } }); syncDirectionLock(); syncFieldVisibility(); })();