实例期权页增加中控条件单卡片,接单后显示状态与触发参数。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-04 18:39:47 +08:00
parent 8b584a0870
commit e11651d729
6 changed files with 164 additions and 12 deletions
+73
View File
@@ -5540,6 +5540,79 @@ html[data-theme="light"] .opt-source-badge--oo {
flex-wrap: wrap; flex-wrap: wrap;
justify-content: flex-end; justify-content: flex-end;
} }
.opt-cond-order-card {
margin-bottom: 12px;
padding: 12px 14px;
border-radius: 10px;
border: 1px solid rgba(56, 189, 248, 0.35);
background: rgba(14, 42, 68, 0.72);
}
.opt-cond-order-card[hidden] {
display: none !important;
}
.opt-cond-order-head {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
margin-bottom: 8px;
}
.opt-cond-order-head strong {
font-size: 0.9rem;
}
.opt-cond-lock-note {
margin-left: auto;
font-size: 0.72rem;
color: #9ec0ff;
}
.opt-cond-st {
display: inline-block;
padding: 2px 8px;
border-radius: 999px;
font-size: 0.72rem;
font-weight: 700;
}
.opt-cond-st.is-armed {
color: #7dd3fc;
background: rgba(56, 189, 248, 0.16);
}
.opt-cond-st.is-trig {
color: #fbbf24;
background: rgba(251, 191, 36, 0.16);
}
.opt-cond-st.is-open {
color: #6ee7b7;
background: rgba(52, 211, 153, 0.16);
}
.opt-cond-order-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 8px 12px;
}
.opt-cond-kv .k {
display: block;
font-size: 0.68rem;
color: #8ea0c0;
}
.opt-cond-kv .v {
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.opt-cond-order-msg {
margin-top: 8px;
font-size: 0.72rem;
color: #c9d6f5;
}
html[data-theme="light"] .opt-cond-order-card {
border-color: rgba(14, 116, 144, 0.28);
background: rgba(224, 242, 254, 0.7);
}
html[data-theme="light"] .opt-cond-lock-note,
html[data-theme="light"] .opt-cond-kv .k,
html[data-theme="light"] .opt-cond-order-msg {
color: #35506e;
}
.opt-spot-sell-head { .opt-spot-sell-head {
display: flex; display: flex;
align-items: center; align-items: center;
+76 -8
View File
@@ -2308,16 +2308,84 @@
head.hidden = false; head.hidden = false;
} }
function escHtml(s) {
return String(s)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;");
}
function condStatusLabel(st) {
const map = { armed: "待命", triggering: "触发中", open: "持仓中" };
return map[st] || st || "已接收";
}
function condStatusClass(st) {
if (st === "open") return "is-open";
if (st === "triggering") return "is-trig";
return "is-armed";
}
function paintCondOrderLock(d) { function paintCondOrderLock(d) {
const el = document.getElementById("opt-cond-lock-banner"); const card = document.getElementById("opt-cond-order-card");
if (!el) return; if (!card) return;
if (d && d.cond_order_locked) { const order = d && d.cond_order;
const extra = d.cond_order_msg ? " · " + d.cond_order_msg : ""; const locked = !!(d && d.cond_order_locked);
el.textContent = "中控条件单占用中,禁止手动开仓" + extra; if (!order && !locked) {
el.style.display = ""; card.hidden = true;
} else { return;
el.style.display = "none";
} }
const st = order ? String(order.status || "") : "";
const stEl = document.getElementById("opt-cond-order-st");
if (stEl) {
stEl.textContent = condStatusLabel(st);
stEl.className = "opt-cond-st " + condStatusClass(st);
}
const grid = document.getElementById("opt-cond-order-grid");
if (grid) {
if (!order) {
grid.innerHTML = "";
} else {
const put = String(order.opt_type || "").toUpperCase() !== "C";
const side = put ? "上穿 ≥" : "下穿 ≤";
const exitParts = [];
if (order.profit_exit_enabled) {
exitParts.push("翻倍×" + (order.profit_exit_mult != null ? order.profit_exit_mult : ""));
}
if (order.target_index != null && order.target_index !== "") {
exitParts.push("目标 " + order.target_index);
}
const items = [
["标的", (order.underlying || "") + " " + (put ? "Put" : "Call")],
["触发", side + " " + (order.trigger_px != null ? order.trigger_px : "—")],
["偏离", order.deviation_pct != null ? order.deviation_pct + "%" : "—"],
["最短到期", order.min_expiry_hours != null ? order.min_expiry_hours + "h" : "—"],
["出场", exitParts.join(" · ") || "—"],
["当前指数", order.last_index != null && order.last_index !== "" ? String(order.last_index) : "—"],
];
if (order.opened_inst_id) {
items.push(["已开合约", String(order.opened_inst_id)]);
}
grid.innerHTML = items
.map(function (it) {
return (
'<div class="opt-cond-kv"><span class="k">' +
escHtml(it[0]) +
'</span><span class="v">' +
escHtml(it[1]) +
"</span></div>"
);
})
.join("");
}
}
const msgEl = document.getElementById("opt-cond-order-msg");
if (msgEl) {
const msg = (order && order.message) || (d && d.cond_order_msg) || "";
msgEl.textContent = msg ? String(msg) : "";
}
card.hidden = false;
} }
async function retrySpotSell() { async function retrySpotSell() {
+1 -1
View File
@@ -9,7 +9,7 @@
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4"> <link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4"> <link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
<link rel="stylesheet" href="/static/instance_page.css?v=25"> <link rel="stylesheet" href="/static/instance_page.css?v=25">
<link rel="stylesheet" href="/static/instance_theme.css?v=126"> <link rel="stylesheet" href="/static/instance_theme.css?v=127">
<script src="/static/account_risk_badge.js?v=4"></script> <script src="/static/account_risk_badge.js?v=4"></script>
<script src="/static/open_submit_gate.js?v=1"></script> <script src="/static/open_submit_gate.js?v=1"></script>
<meta name="theme-color" content="#0b0d14"> <meta name="theme-color" content="#0b0d14">
+1 -1
View File
@@ -19,7 +19,7 @@
<link rel="manifest" href="/static/icons/manifest.webmanifest"> <link rel="manifest" href="/static/icons/manifest.webmanifest">
<title>{{ pwa_app_name }}</title> <title>{{ pwa_app_name }}</title>
<link rel="stylesheet" href="/static/instance_page.css?v=25"> <link rel="stylesheet" href="/static/instance_page.css?v=25">
<link rel="stylesheet" href="/static/instance_theme.css?v=126"> <link rel="stylesheet" href="/static/instance_theme.css?v=127">
</head> </head>
<body <body
+3
View File
@@ -1505,6 +1505,7 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
spot_sell_hint = None spot_sell_hint = None
cond_locked = False cond_locked = False
cond_msg = "" cond_msg = ""
cond_order = None
try: try:
from lib.options.options_cond_order_lib import has_active_cond_order, list_cond_orders from lib.options.options_cond_order_lib import has_active_cond_order, list_cond_orders
@@ -1515,6 +1516,7 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
if cond_locked: if cond_locked:
act = list_cond_orders(conn_c, active_only=True) act = list_cond_orders(conn_c, active_only=True)
if act: if act:
cond_order = act[0]
cond_msg = str(act[0].get("message") or act[0].get("status") or "") cond_msg = str(act[0].get("message") or act[0].get("status") or "")
finally: finally:
conn_c.close() conn_c.close()
@@ -1527,6 +1529,7 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
"spot_sell": spot_sell_hint, "spot_sell": spot_sell_hint,
"cond_order_locked": cond_locked, "cond_order_locked": cond_locked,
"cond_order_msg": cond_msg, "cond_order_msg": cond_msg,
"cond_order": cond_order,
} }
) )
+10 -2
View File
@@ -13,7 +13,15 @@
{% if options_enabled and options_open_allowed is defined and not options_open_allowed %} {% if options_enabled and options_open_allowed is defined and not options_open_allowed %}
<div class="flash" style="margin-bottom:12px">当前交易模式为对冲(永期/期期),不可单独开期权;持仓可在此查看/平仓.切换请到 env「交易模式」.</div> <div class="flash" style="margin-bottom:12px">当前交易模式为对冲(永期/期期),不可单独开期权;持仓可在此查看/平仓.切换请到 env「交易模式」.</div>
{% endif %} {% endif %}
<div class="flash" id="opt-cond-lock-banner" style="margin-bottom:12px;display:none">中控条件单占用中,禁止手动开仓.</div> <div class="opt-cond-order-card" id="opt-cond-order-card" hidden>
<div class="opt-cond-order-head">
<strong>中控条件单</strong>
<span class="opt-cond-st" id="opt-cond-order-st"></span>
<span class="opt-cond-lock-note">已接收 · 禁止手动开仓</span>
</div>
<div class="opt-cond-order-grid" id="opt-cond-order-grid"></div>
<div class="opt-cond-order-msg" id="opt-cond-order-msg"></div>
</div>
<div class="options-dual-grid"> <div class="options-dual-grid">
<div class="card options-order-card"{% if options_open_allowed is defined and not options_open_allowed %} style="opacity:.72"{% endif %}> <div class="card options-order-card"{% if options_open_allowed is defined and not options_open_allowed %} style="opacity:.72"{% endif %}>
@@ -356,4 +364,4 @@
</div> </div>
</div> </div>
<script src="/static/options_expiry_countdown.js?v=1"></script> <script src="/static/options_expiry_countdown.js?v=1"></script>
<script src="/static/options_panel.js?v=68"></script> <script src="/static/options_panel.js?v=69"></script>