总览名称旁增加条件单标签,无仓时持仓列显示触发短文案。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-04 19:00:47 +08:00
parent b9f76f4d53
commit bcd32a25c3
4 changed files with 112 additions and 5 deletions
+43
View File
@@ -719,6 +719,49 @@ button, .btn {
color: #6ee7b7;
background: rgba(52, 211, 153, 0.14);
}
.overview-table td strong {
display: inline-block;
margin-right: 8px;
vertical-align: middle;
}
.overview-cond-tag {
display: inline-block;
margin-top: 4px;
padding: 2px 8px;
border-radius: 999px;
font-size: 0.72rem;
font-weight: 700;
white-space: nowrap;
vertical-align: middle;
}
.overview-cond-tag.is-armed {
color: #7dd3fc;
background: rgba(56, 189, 248, 0.16);
}
.overview-cond-tag.is-trig {
color: #fbbf24;
background: rgba(251, 191, 36, 0.16);
}
.overview-cond-tag.is-open {
color: #6ee7b7;
background: rgba(52, 211, 153, 0.16);
}
.overview-cond-wait-line {
color: #9ec0ff;
font-size: 0.8rem;
font-weight: 600;
}
.overview-cond-src {
display: inline-block;
margin-left: 6px;
padding: 0 6px;
border-radius: 999px;
font-size: 0.68rem;
font-weight: 700;
color: #7dd3fc;
background: rgba(56, 189, 248, 0.14);
vertical-align: middle;
}
.pos-brief {
margin: 0;
padding-left: 0;
+67 -3
View File
@@ -46,12 +46,73 @@
return parts.length ? parts.join(" · ") : "未设出场";
}
function positionSummary(brief) {
function activeCondOrder(snap) {
const list = snap && snap.cond_orders_active;
if (Array.isArray(list) && list.length && list[0]) return list[0];
if (snap && snap.cond_order) return snap.cond_order;
if (snap && snap.cond_order_locked) return { status: "armed" };
return null;
}
function condStatusLabel(st) {
const map = { armed: "待命", triggering: "触发中", open: "持仓中" };
return map[st] || "占用";
}
function condStatusClass(st) {
if (st === "open") return "is-open";
if (st === "triggering") return "is-trig";
return "is-armed";
}
function condTagHtml(cond) {
if (!cond) return "";
const st = String(cond.status || "armed");
return (
'<span class="overview-cond-tag ' +
condStatusClass(st) +
'">条件单 · ' +
escapeHtml(condStatusLabel(st)) +
"</span>"
);
}
function condWaitLine(cond) {
if (!cond) return "条件单占用";
const put = String(cond.opt_type || "").toUpperCase() !== "C";
const uly = String(cond.underlying || "").trim();
const side =
String(cond.trigger_side || "").toLowerCase() === "lte"
? "下穿 ≤"
: put
? "上穿 ≥"
: "下穿 ≤";
const px = cond.trigger_px != null && cond.trigger_px !== "" ? String(cond.trigger_px) : "";
const bits = [];
if (uly) bits.push(uly + " " + (put ? "Put" : "Call"));
if (px) bits.push(side + " " + px);
return bits.length ? bits.join(" · ") : "条件单占用";
}
function positionSummary(brief, cond) {
const list = brief || [];
if (!list.length) return '<span class="muted">暂无持仓</span>';
if (!list.length) {
if (cond) {
return (
'<div class="overview-cond-wait">' +
'<div class="overview-cond-wait-line">' +
escapeHtml(condWaitLine(cond)) +
"</div></div>"
);
}
return '<span class="muted">暂无持仓</span>';
}
const opened = cond && String(cond.opened_inst_id || "").trim();
const tagOpen = !!(cond && String(cond.status || "") === "open");
const items = list.slice(0, 8).map(function (p) {
const id = p.inst_id || "";
const sheets = escapeHtml(String(p.sheets != null ? p.sheets : "—"));
const fromCond = tagOpen && (!opened || opened === id);
return (
"<li>" +
escapeHtml(id) +
@@ -59,6 +120,7 @@
sheets +
"张 · " +
fmtPnlHtml(p.pnl_usdt) +
(fromCond ? '<span class="overview-cond-src">条件单</span>' : "") +
"</li>"
);
});
@@ -237,6 +299,7 @@
? snap.pnl.unrealized_usdt
: snap.upl_total_usdc;
const brief = snap.positions_brief || snap.positions || [];
const cond = activeCondOrder(snap);
const online = !!row.online;
const status = online
? '<span class="status-on">在线</span>'
@@ -249,6 +312,7 @@
"<td><strong>" +
escapeHtml(row.name || "") +
"</strong>" +
condTagHtml(cond) +
err +
"</td>" +
"<td>" +
@@ -279,7 +343,7 @@
premiumRatioCell(snap) +
"</td>" +
"<td>" +
positionSummary(brief) +
positionSummary(brief, cond) +
"</td>" +
"<td>" +
exitSummary(brief) +
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}期权中控{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='hub.css') }}?v=20">
<link rel="stylesheet" href="{{ url_for('static', filename='hub.css') }}?v=21">
</head>
<body class="{% if request.path.startswith('/login') %}page-login{% elif request.path.startswith('/desk') %}page-desk{% elif request.path.startswith('/stats') %}page-stats{% elif request.path.startswith('/instances') %}page-instances{% elif request.path == '/' %}page-dashboard{% endif %}">
{% if session.get('logged_in') %}
+1 -1
View File
@@ -15,6 +15,6 @@
<div id="overview-grid"></div>
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='hub.js') }}?v=19"></script>
<script src="{{ url_for('static', filename='hub.js') }}?v=20"></script>
<script>HubOverview.boot();</script>
{% endblock %}