Show hedge-plan scenario preview in a modal with start/cancel.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-19 08:28:54 +08:00
parent 1c155328b4
commit d5f3f315dc
3 changed files with 101 additions and 66 deletions
+56 -17
View File
@@ -35,6 +35,9 @@
fundingUsdc: null,
tradeBudgetUsdc: null,
budgetBuffer: 0.95,
previewOk: false,
canStart: false,
previewPlanType: null,
};
function $(id) {
@@ -169,13 +172,24 @@
];
if (gates.reasons && gates.reasons.length) parts.push(gates.reasons.join("; "));
el.textContent = parts.join(" · ");
const start = $("hp-start-btn");
const startOo = $("hp-start-btn-oo");
if ((gates.plan_type || state.mode) === "options_options") {
if (startOo) startOo.disabled = !gates.can_start;
} else {
if (start) start.disabled = !gates.can_start;
}
state.canStart = !!gates.can_start;
syncPreviewStartBtn();
}
function syncPreviewStartBtn() {
const start = $("hp-preview-start");
if (!start) return;
start.disabled = !(state.previewOk && state.canStart);
}
function openPreviewModal() {
const modal = $("hp-preview-modal");
if (modal) modal.hidden = false;
}
function closePreviewModal() {
const modal = $("hp-preview-modal");
if (modal) modal.hidden = true;
}
function setOptionsBalance(chain) {
@@ -851,8 +865,18 @@
async function runPreview() {
const isOo = state.mode === "options_options";
const tbody = $(isOo ? "hp-result-tbody-oo" : "hp-result-tbody");
const summary = $(isOo ? "hp-summary-oo" : "hp-summary");
const tbody = $("hp-result-tbody");
const summary = $("hp-preview-summary");
const midTh = $("hp-preview-mid-th");
const title = $("hp-preview-title");
state.previewOk = false;
state.previewPlanType = isOo ? "options_options" : "perp_options";
syncPreviewStartBtn();
if (midTh) midTh.textContent = isOo ? "腿盈亏" : "永续/腿盈亏";
if (title) title.textContent = isOo ? "情景测算 · 期期" : "情景测算 · 永期";
if (summary) summary.textContent = "";
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="muted">计算中…</td></tr>';
openPreviewModal();
try {
let body;
if (isOo) {
@@ -949,7 +973,11 @@
"</td>";
tbody.appendChild(tr);
});
state.previewOk = true;
syncPreviewStartBtn();
} catch (e) {
state.previewOk = false;
syncPreviewStartBtn();
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="err">' + (e.message || e) + "</td></tr>";
if (summary) summary.textContent = "";
}
@@ -1075,14 +1103,19 @@
state.mode = "options_options";
void runPreview();
});
if ($("hp-start-btn"))
$("hp-start-btn").addEventListener("click", function () {
void startPlan("perp_options");
if ($("hp-preview-cancel")) $("hp-preview-cancel").addEventListener("click", closePreviewModal);
if ($("hp-preview-cancel-x")) $("hp-preview-cancel-x").addEventListener("click", closePreviewModal);
if ($("hp-preview-start"))
$("hp-preview-start").addEventListener("click", function () {
const planType = state.previewPlanType || state.mode;
void startPlan(planType, true);
});
if ($("hp-start-btn-oo"))
$("hp-start-btn-oo").addEventListener("click", function () {
void startPlan("options_options");
const previewModal = $("hp-preview-modal");
if (previewModal) {
previewModal.addEventListener("click", function (ev) {
if (ev.target === previewModal) closePreviewModal();
});
}
if ($("hp-detail-close")) $("hp-detail-close").addEventListener("click", closeModal);
const modal = $("hp-detail-modal");
if (modal) {
@@ -1442,8 +1475,9 @@
}
}
async function startPlan(planType) {
async function startPlan(planType, fromPreviewModal) {
const isOo = planType === "options_options";
const startBtn = $("hp-preview-start");
try {
let body;
if (isOo) {
@@ -1487,17 +1521,22 @@
margin: state.market && state.market.full_margin_sizing && state.market.full_margin_sizing.margin_capital,
};
}
if (!window.confirm("确认启动对冲计划并真实下单?\n(将按期权账户/合约账户分别下单)")) return;
if (!fromPreviewModal) {
if (!window.confirm("确认启动对冲计划并真实下单?\n(将按期权账户/合约账户分别下单)")) return;
}
if (startBtn) startBtn.disabled = true;
const d = await apiJson("/api/hedge-plan/start", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
setGateLine(d.gates);
closePreviewModal();
alert("计划已启动 #" + (d.plan_id || "") + (d.dry_run ? " (dry_run)" : ""));
void loadGates();
} catch (e) {
alert(e.message || String(e));
syncPreviewStartBtn();
}
}
+13 -4
View File
@@ -3536,15 +3536,24 @@ html[data-theme="light"] .opt-be-dist-down {
display: flex;
flex-direction: column;
}
.hedge-plan-page-wrap .hp-preview-card {
margin-top: 0;
clear: both;
}
.hedge-plan-page-wrap .hp-action-row {
margin-top: 10px;
gap: 8px;
justify-content: flex-end;
}
.hedge-plan-page-wrap .hp-preview-modal {
width: min(96vw, 920px);
}
.hedge-plan-page-wrap .hp-preview-summary {
margin: 0 0 10px;
font-size: 0.84rem;
line-height: 1.45;
}
.hedge-plan-page-wrap .hp-preview-actions {
margin-top: 14px;
justify-content: flex-end;
gap: 10px;
}
.hedge-plan-page-wrap .hp-pick.active,
.hedge-plan-page-wrap .opt-row-selected td {
background: rgba(90, 140, 255, 0.18);