Show hub fullscreen options positions as cards matching instance data.

Enrich hub options snapshot with close preview and render read-only option position cards in exchange fullscreen view.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-11 09:40:35 +08:00
parent baf94b4feb
commit 843d87422d
8 changed files with 292 additions and 23 deletions
+11
View File
@@ -773,6 +773,7 @@ _TRADE_STATS_CALENDAR_JS = _REPO_STATIC / "trade_stats_calendar.js"
_ACCOUNT_RISK_BADGE_CSS = _REPO_STATIC / "account_risk_badge.css"
_ACCOUNT_RISK_BADGE_JS = _REPO_STATIC / "account_risk_badge.js"
_OPTIONS_EXPIRY_COUNTDOWN_JS = _REPO_STATIC / "options_expiry_countdown.js"
_OPTIONS_POSITION_CARDS_JS = _REPO_STATIC / "options_position_cards.js"
@app.get("/assets/account_risk_badge.css")
@@ -807,6 +808,16 @@ def hub_options_expiry_countdown_js():
)
@app.get("/assets/options_position_cards.js")
def hub_options_position_cards_js():
if not _OPTIONS_POSITION_CARDS_JS.is_file():
raise HTTPException(status_code=404, detail="options_position_cards.js not found")
return FileResponse(
str(_OPTIONS_POSITION_CARDS_JS),
media_type="application/javascript; charset=utf-8",
)
@app.get("/assets/ai_review_render.js")
def hub_ai_review_render_js():
"""与三所实例共用仓库根 static/ai_review_render.js(须在 /assets mount 之前注册)."""
+29
View File
@@ -1970,6 +1970,35 @@ body.market-chart-fs-open {
margin-bottom: 12px;
}
.exchange-fullscreen .hub-opt-pos-list {
margin-bottom: 14px;
}
.hub-opt-pos-card .pos-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.hub-opt-pos-card .opt-pos-cell--depth {
grid-column: span 2;
}
.hub-opt-pos-card .opt-bid-plain {
color: #dbe6ff;
font-variant-numeric: tabular-nums;
line-height: 1.35;
white-space: normal;
}
.hub-opt-pos-card .opt-close-value {
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.hub-opt-pos-card .pos-card-symbol strong {
font-size: 0.72rem;
word-break: break-all;
}
.hub-pos-card .pos-cell {
display: flex;
flex-direction: column;
+21 -5
View File
@@ -3569,7 +3569,23 @@
return html;
}
function renderOptionsSectionBody(row) {
function renderOptionsPositionsCards(pos) {
if (!pos.length) return '<div class="empty-hint">暂无期权持仓</div>';
if (!globalThis.OptionsPositionCards || !OptionsPositionCards.renderCard) {
return renderOptionsPositionsTable(pos);
}
const cls = hubPosListCountClass(pos.length);
let html = `<div class="hub-pos-list hub-opt-pos-list ${cls}" data-pos-count="${pos.length}">`;
pos.forEach((p) => {
html += OptionsPositionCards.renderCard(p, { readOnly: true, hub: true });
});
html += "</div>";
return html;
}
function renderOptionsSectionBody(row, opts) {
const options = opts || {};
const layout = options.layout || "table";
const opt = row.options || {};
let html = "";
if (opt.enabled === false) {
@@ -3585,7 +3601,7 @@
const bal = optionsBalanceFields(opt);
html += renderStatRow(bal.funding, bal.trading, bal.upl);
html += `<div class="section-title hub-options-title">期权持仓 · ${pos.length} 仓</div>`;
html += renderOptionsPositionsTable(pos);
html += layout === "cards" ? renderOptionsPositionsCards(pos) : renderOptionsPositionsTable(pos);
if (row.flask_url_browser || row.flask_url) {
html += `<div class="hub-options-actions"><a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/options">打开期权页</a></div>`;
}
@@ -3602,11 +3618,11 @@
return html;
}
function renderOptionsMonitorSection(row) {
function renderOptionsMonitorSection(row, opts) {
if (!rowHasOptionsLayout(row)) return "";
let html = '<div class="hub-monitor-block hub-monitor-options">';
html += '<div class="hub-monitor-block-label">期权账户</div>';
html += renderOptionsSectionBody(row);
html += renderOptionsSectionBody(row, opts);
html += "</div>";
return html;
}
@@ -3723,7 +3739,7 @@
if (rowHasOptionsLayout(row)) {
html += "</div>";
}
html += renderOptionsMonitorSection(row);
html += renderOptionsMonitorSection(row, { layout: "cards" });
html += '<div class="hub-fs-sections-grid">';
if ((row.capabilities || []).includes("key")) {
if (!flaskOk) {
+3 -2
View File
@@ -15,7 +15,7 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" media="print" onload="this.media='all'" />
<noscript><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" /></noscript>
<link rel="stylesheet" href="/assets/app.css?v=20260710-logs-cal" />
<link rel="stylesheet" href="/assets/app.css?v=20260711-hub-opt-cards" />
<link rel="stylesheet" href="/assets/trade_stats_calendar.css?v=4" />
<link rel="stylesheet" href="/assets/account_risk_badge.css?v=4" />
<script src="/assets/account_risk_badge.js?v=4"></script>
@@ -1237,7 +1237,8 @@
<script src="/assets/ai_review_render.js?v=3"></script>
<script src="/assets/time_close_ui.js?v=3"></script>
<script src="/assets/options_expiry_countdown.js?v=1"></script>
<script src="/assets/options_position_cards.js?v=1"></script>
<script src="/assets/backup.js?v=1"></script>
<script src="/assets/app.js?v=20260708-hub-ai-save"></script>
<script src="/assets/app.js?v=20260711-hub-opt-cards"></script>
</body>
</html>