条件单页美化,看跌/看涨自动绑定上穿/下穿。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-03 02:23:07 +08:00
parent 1546bc49f0
commit 69fa7f50f1
4 changed files with 246 additions and 68 deletions
+54 -12
View File
@@ -7,6 +7,28 @@
.replace(/"/g, "&quot;");
}
function leftTriggerSide(optType) {
return String(optType || "P").toUpperCase() === "C" ? "lte" : "gte";
}
function triggerHintText(optType, px) {
const put = String(optType || "P").toUpperCase() !== "C";
const price = px && String(px).trim() !== "" ? String(px) : "触发价";
if (put) {
return "看跌左侧单:指数上穿 " + price + " 后,在偏离区内开最近实值 Put。";
}
return "看涨左侧单:指数下穿 " + price + " 后,在偏离区内开最近实值 Call。";
}
function syncTriggerHint() {
const hint = document.getElementById("cf-trigger-hint");
const typeEl = document.getElementById("cf-opt-type");
const pxEl = document.getElementById("cf-trigger-px");
if (!hint || !typeEl) return;
hint.textContent = triggerHintText(typeEl.value, pxEl && pxEl.value);
hint.className = "cond-trigger-hint " + (typeEl.value === "C" ? "is-call" : "is-put");
}
function statusLabel(o) {
const st = o.status || "";
const reason = o.end_reason || "";
@@ -23,6 +45,14 @@
return map2[st] || st || "—";
}
function statusClass(o) {
const st = o.status || "";
if (st === "open") return "st-open";
if (st === "triggering") return "st-trig";
if (st === "armed") return "st-armed";
return "st-done";
}
async function loadCandidates() {
const box = document.getElementById("cf-instances");
if (!box) return;
@@ -46,18 +76,22 @@
: "离线"
: "可选";
return (
'<label class="check" title="' +
'<label class="cond-inst' +
(disabled ? " is-off" : "") +
'" title="' +
escapeHtml(tip) +
'">' +
'<input type="checkbox" name="cf-inst" value="' +
encodeURIComponent(String(it.id)) +
'"' +
(disabled ? " disabled" : "") +
"> " +
">" +
'<span class="cond-inst-name">' +
escapeHtml(it.name || "") +
' <span class="muted">(' +
"</span>" +
'<span class="cond-inst-tag">' +
escapeHtml(tip) +
")</span></label>"
"</span></label>"
);
})
.join("");
@@ -70,16 +104,16 @@
const d = await r.json();
const list = d.orders || [];
if (!list.length) {
box.innerHTML = '<span class="muted">暂无条件单</span>';
box.innerHTML = '<div class="cond-empty">暂无条件单</div>';
return;
}
box.innerHTML =
'<div class="overview-table-wrap"><table class="overview-table"><thead><tr>' +
'<div class="overview-table-wrap cond-table-wrap"><table class="overview-table"><thead><tr>' +
"<th>客户端</th><th>状态</th><th>标的</th><th>触发</th><th>偏离</th><th>到期h</th><th>出场</th><th>说明</th><th>操作</th>" +
"</tr></thead><tbody>" +
list
.map(function (o) {
const side = o.trigger_side === "lte" ? "≤" : "≥";
const side = o.trigger_side === "lte" ? "下穿 ≤" : "上穿 ≥";
const exit =
(o.profit_exit_enabled ? "翻倍×" + (o.profit_exit_mult || "") : "") +
(o.target_index != null ? " 目标" + o.target_index : "");
@@ -113,9 +147,11 @@
"<td>" +
escapeHtml(o.instance_name || "") +
"</td>" +
"<td>" +
'<td><span class="cond-st ' +
statusClass(o) +
'">' +
escapeHtml(statusLabel(o)) +
"</td>" +
"</span></td>" +
"<td>" +
escapeHtml((o.underlying || "") + " " + (o.opt_type || "")) +
"</td>" +
@@ -131,7 +167,7 @@
"<td>" +
escapeHtml(exit || "—") +
"</td>" +
"<td class=\"muted\">" +
'<td class="muted">' +
escapeHtml(o.message || "") +
"</td>" +
'<td><div class="overview-actions">' +
@@ -202,11 +238,12 @@
alert("请选择至少一台可选客户端");
return;
}
const optType = document.getElementById("cf-opt-type").value;
const body = {
instance_ids: ids,
underlying: document.getElementById("cf-underlying").value,
opt_type: document.getElementById("cf-opt-type").value,
trigger_side: document.getElementById("cf-trigger-side").value,
opt_type: optType,
trigger_side: leftTriggerSide(optType),
trigger_px: document.getElementById("cf-trigger-px").value,
deviation_pct: document.getElementById("cf-deviation").value,
min_expiry_hours: document.getElementById("cf-expiry-h").value,
@@ -235,6 +272,11 @@
if (btn) btn.addEventListener("click", refresh);
const create = document.getElementById("btn-cond-create");
if (create) create.addEventListener("click", createOrder);
const typeEl = document.getElementById("cf-opt-type");
const pxEl = document.getElementById("cf-trigger-px");
if (typeEl) typeEl.addEventListener("change", syncTriggerHint);
if (pxEl) pxEl.addEventListener("input", syncTriggerHint);
syncTriggerHint();
refresh();
setInterval(refresh, 10000);
}
+113 -1
View File
@@ -175,7 +175,7 @@ body.page-login .main {
}
.stack label, .form-grid label { display: block; margin: 8px 0; }
input[type="text"], input[type="password"], input:not([type]) {
input[type="text"], input[type="password"], input[type="number"], input:not([type]), select {
width: 100%;
padding: 8px 10px;
border-radius: 8px;
@@ -431,3 +431,115 @@ input.readonly {
padding-right: clamp(32px, 6vw, 96px);
}
}
.cond-head { justify-content: space-between; align-items: flex-start; }
.cond-lead { margin: 6px 0 0; max-width: 720px; line-height: 1.5; }
.cond-layout { display: grid; gap: 16px; }
.cond-card { padding: 18px 18px 16px; }
.cond-card-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-bottom: 14px;
}
.cond-card-head h2 {
margin: 0;
font-size: 1.02rem;
letter-spacing: 0.03em;
}
.cond-chip {
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.06em;
color: #041018;
background: linear-gradient(90deg, var(--accent-deep), var(--accent));
border-radius: 999px;
padding: 3px 10px;
}
.cond-section {
border-top: 1px solid rgba(56, 189, 248, 0.12);
padding: 14px 0 4px;
}
.cond-section:first-of-type { border-top: 0; padding-top: 0; }
.cond-section-title {
font-size: 0.78rem;
color: var(--accent-2);
letter-spacing: 0.08em;
margin-bottom: 10px;
font-weight: 600;
}
.cond-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 12px 14px;
align-items: end;
}
.cond-grid label {
margin: 0;
font-size: 0.8rem;
color: #b6c7da;
}
.cond-grid input,
.cond-grid select {
margin-top: 6px;
}
.cond-trigger-hint {
grid-column: 1 / -1;
padding: 9px 12px;
border-radius: 10px;
font-size: 0.82rem;
line-height: 1.45;
border: 1px solid var(--line);
background: rgba(8, 16, 30, 0.7);
color: var(--text);
}
.cond-trigger-hint.is-put { border-color: rgba(251, 113, 133, 0.35); }
.cond-trigger-hint.is-call { border-color: rgba(52, 211, 153, 0.35); }
.cond-switch {
display: flex !important;
align-items: center;
gap: 8px;
min-height: 62px;
}
.cond-switch input { width: auto; margin: 0; }
.cond-inst-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 10px;
}
.cond-inst {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 10px 12px;
border-radius: 10px;
border: 1px solid var(--line);
background: rgba(8, 16, 30, 0.72);
cursor: pointer;
}
.cond-inst input { width: auto; margin: 0; }
.cond-inst-name { flex: 1; font-weight: 600; }
.cond-inst-tag { color: var(--muted); font-size: 0.75rem; }
.cond-inst.is-off { opacity: 0.5; cursor: not-allowed; }
.cond-actions {
display: flex;
align-items: center;
gap: 12px;
margin-top: 14px;
}
.cond-empty { padding: 28px 8px; text-align: center; }
.cond-st {
display: inline-block;
min-width: 64px;
padding: 2px 8px;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 600;
}
.cond-st.st-armed { color: var(--accent-2); background: rgba(56, 189, 248, 0.12); }
.cond-st.st-trig { color: #fbbf24; background: rgba(251, 191, 36, 0.12); }
.cond-st.st-open { color: var(--ok); background: rgba(52, 211, 153, 0.12); }
.cond-st.st-done { color: var(--muted); background: rgba(138, 160, 184, 0.12); }
.cond-table-wrap { margin-top: 0; }