修复全仓复利关闭后仍无法开仓:前端不再残留选中全仓,后端强制改指定张数。

审计:开关关闭时隐藏全仓芯片并自动勾选指定张数;报价/余额热同步 compound_full_enabled;API 将 compound_full 归一为 sheets(缺张数默认1);单测覆盖开关开关两种归一路径。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-12 16:14:53 +08:00
parent 9c19afc8d4
commit 271865fa3d
8 changed files with 168 additions and 28 deletions
+3
View File
@@ -4424,6 +4424,9 @@ html[data-theme="light"] .opt-pending-item {
.opt-size-mode-chip {
position: relative;
}
.opt-size-mode-chip[hidden] {
display: none !important;
}
.opt-size-mode-chip input[type="radio"] {
position: absolute;
opacity: 0;
+67 -15
View File
@@ -271,13 +271,32 @@
}
}
function currentSizeMode() {
const el = document.querySelector('input[name="opt-size-mode"]:checked');
return el ? el.value : "sheets";
function compoundFullEnabled() {
// 缺省按关闭,避免热更关闭后仍误用全仓复利
return !!(root && String(root.dataset.compoundFullEnabled || "0") === "1");
}
function compoundFullEnabled() {
return !!(root && String(root.dataset.compoundFullEnabled || "1") === "1");
function currentSizeMode() {
const el = document.querySelector('input[name="opt-size-mode"]:checked:not(:disabled)');
if (el) return el.value;
const any = document.querySelector('input[name="opt-size-mode"]:checked');
if (any && any.value === "compound_full" && !compoundFullEnabled()) return "sheets";
if (any && any.value === "budget_full" && compoundFullEnabled()) return "compound_full";
return "sheets";
}
function applyCompoundModeUi(compoundOn) {
if (root) root.dataset.compoundFullEnabled = compoundOn ? "1" : "0";
updateSizeInputs();
}
function syncCompoundFlagsFromPayload(d) {
if (!d || typeof d !== "object") return;
if (d.compound_full_enabled != null) {
applyCompoundModeUi(!!d.compound_full_enabled);
} else if (d.cfg && d.cfg.compound_full_enabled != null) {
applyCompoundModeUi(!!d.cfg.compound_full_enabled);
}
}
function updateSizeInputs() {
@@ -292,21 +311,38 @@
const compoundCapLine = document.getElementById("opt-compound-cap-line");
const compoundOn = compoundFullEnabled();
if (budgetWrap) {
budgetWrap.hidden = compoundOn;
budgetWrap.hidden = !!compoundOn;
budgetWrap.style.display = compoundOn ? "none" : "";
const radio = budgetWrap.querySelector('input[name="opt-size-mode"]');
if (radio) radio.disabled = compoundOn;
if (radio) radio.disabled = !!compoundOn;
}
if (compoundWrap) {
compoundWrap.hidden = !compoundOn;
compoundWrap.style.display = compoundOn ? "" : "none";
const radio = compoundWrap.querySelector('input[name="opt-size-mode"]');
if (radio) radio.disabled = !compoundOn;
}
if (compoundOn && mode === "budget_full") {
if (compoundOn && (mode === "budget_full" || mode === "compound_full")) {
const compoundRadio = document.querySelector('input[name="opt-size-mode"][value="compound_full"]');
if (compoundRadio) compoundRadio.checked = true;
} else if (!compoundOn && mode === "compound_full") {
const sheetsRadio = document.querySelector('input[name="opt-size-mode"][value="sheets"]');
if (sheetsRadio) sheetsRadio.checked = true;
if (compoundRadio) {
compoundRadio.disabled = false;
compoundRadio.checked = true;
}
} else if (!compoundOn) {
const compoundRadio = document.querySelector('input[name="opt-size-mode"][value="compound_full"]');
if (compoundRadio) {
compoundRadio.checked = false;
compoundRadio.disabled = true;
}
// currentSizeMode 会把残留 compound 映射成 sheets,须实际勾选,避免无选中无法开仓
const checkedOk = document.querySelector('input[name="opt-size-mode"]:checked:not(:disabled)');
if (!checkedOk) {
const sheetsRadio = document.querySelector('input[name="opt-size-mode"][value="sheets"]');
if (sheetsRadio) {
sheetsRadio.disabled = false;
sheetsRadio.checked = true;
}
}
}
const modeNow = currentSizeMode();
if (sheetsEl) sheetsEl.style.display = modeNow === "sheets" ? "" : "none";
@@ -328,8 +364,9 @@
}
document.querySelectorAll(".opt-size-mode-chip").forEach(function (chip) {
const radio = chip.querySelector('input[name="opt-size-mode"]');
chip.classList.toggle("is-selected", !!(radio && radio.checked));
chip.classList.toggle("active", !!(radio && radio.checked));
const selected = !!(radio && radio.checked && !radio.disabled);
chip.classList.toggle("is-selected", selected);
chip.classList.toggle("active", selected);
});
}
@@ -365,6 +402,7 @@
}
function quoteUrl(instId) {
updateSizeInputs();
const mode = currentSizeMode();
let url = "/api/options/quote?inst_id=" + encodeURIComponent(instId) + "&mode=" + mode;
if (mode === "eth_amount") {
@@ -1186,6 +1224,7 @@
}
function fillOrderPanel(d) {
syncCompoundFlagsFromPayload(d);
state.orderQuote = d && d.ok ? d : null;
const sz = d.sizing || {};
const canOpen = !!(d && d.ok && d.can_open);
@@ -1386,6 +1425,7 @@
const btn = document.getElementById("opt-open-btn");
btn.disabled = true;
try {
updateSizeInputs();
const mode = currentSizeMode();
const body = {
inst_id: state.selectedInst,
@@ -1395,7 +1435,10 @@
if (mode === "eth_amount") {
body.eth_amount = parseFloat(document.getElementById("opt-eth-amount").value);
} else if (mode === "sheets") {
body.sheets = parseInt(document.getElementById("opt-sheets-amount").value, 10);
body.sheets = parseInt(document.getElementById("opt-sheets-amount").value, 10) || 1;
} else if (mode === "compound_full" && !compoundFullEnabled()) {
body.mode = "sheets";
body.sheets = parseInt(document.getElementById("opt-sheets-amount").value, 10) || 1;
}
const tgtRaw = (document.getElementById("opt-target-idx").value || "").trim();
if (tgtRaw !== "") {
@@ -2369,6 +2412,15 @@
function bootOptionsPanel() {
applyBudgetBuffer(state.budgetBuffer);
updateSizeInputs();
void (async function syncLiveCompoundFlag() {
try {
const d = await apiJson("/api/options/balances");
syncCompoundFlagsFromPayload(d);
if (d && d.trade_budget != null && root) {
root.dataset.tradeBudget = String(d.trade_budget);
}
} catch (_) {}
})();
syncMoneyFilterButtons();
syncChainViewUI();
updateUnderlyingLabel();