Files
2026-06-26 23:25:27 +08:00

290 lines
9.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(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;
if (form.dataset.rollJsInit === "1") return;
form.dataset.rollJsInit = "1";
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 monitorSubmitting = 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";
previewBox.scrollIntoView({ behavior: "smooth", block: "nearest" });
}
function showPreviewResult(p) {
if (!previewBox || !previewText) return;
previewBox.style.display = "block";
previewBox.classList.remove("is-error");
previewBox.classList.add("is-preview");
previewText.innerHTML =
"<strong>" +
(p.add_mode_label || "") +
"</strong> · 约 <strong>" +
(p.add_amount_display != null ? p.add_amount_display : p.add_amount_raw) +
"</strong> 张<br>" +
"加仓参考价 " +
(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) +
"<br>" +
"合并均价 " +
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;
monitorSubmitting = 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 (monitorSubmitting) return;
if (!symbolSel.value) {
showReject("请先选择持仓币种");
return;
}
monitorSubmitting = true;
if (submitBtn) submitBtn.disabled = true;
requestPreview()
.then(function (data) {
monitorSubmitting = false;
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;
}
form.submit();
})
.catch(function () {
monitorSubmitting = false;
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()) {
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();
})();