Split OKX monitor into perp and options cards.
Align four exchange cards in a 2x2 grid so 1080p layout stays balanced. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2434,7 +2434,11 @@
|
||||
if (optionsSplit) {
|
||||
const okxRow = displayRows.find((r) => rowHasOptionsLayout(r));
|
||||
const otherRows = displayRows.filter((r) => !rowHasOptionsLayout(r));
|
||||
const leftHtml = okxRow ? renderMonitorCard(okxRow, { okxSplit: true }) : "";
|
||||
/* OKX 拆成永续+期权两张独立卡,与右侧两所组成 2×2 对齐 */
|
||||
const leftHtml = okxRow
|
||||
? renderMonitorCard(okxRow, { okxPart: "perp", splitSide: true }) +
|
||||
renderMonitorCard(okxRow, { okxPart: "options", splitSide: true })
|
||||
: "";
|
||||
const rightHtml = otherRows.map((r) => renderMonitorCard(r, { splitSide: true })).join("");
|
||||
cardsHtml =
|
||||
`<div class="monitor-split-body">` +
|
||||
@@ -3852,12 +3856,26 @@
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderGridBody(row, ag, pos, hm, flaskOk, keys, orders, trends, rolls, kmap) {
|
||||
function renderGridBody(row, ag, pos, hm, flaskOk, keys, orders, trends, rolls, kmap, layoutOpts) {
|
||||
const layout = layoutOpts || {};
|
||||
const tickMap = buildPriceTickMap(row);
|
||||
const intraday = isIntradayDisciplineRow(row);
|
||||
let inner = "";
|
||||
if (layout.okxPart === "perp") {
|
||||
inner += renderAccountStatRow(row, ag);
|
||||
inner += renderPerpetualPositionsSection(row, ag, pos, orders, trends, tickMap, intraday);
|
||||
inner += renderCardStrategyStats(row, hm, flaskOk);
|
||||
inner += `<div class="card-expand-hint">点击标题栏进入全屏</div>`;
|
||||
return inner;
|
||||
}
|
||||
if (layout.okxPart === "options") {
|
||||
inner += renderOptionsSectionBody(row);
|
||||
inner += `<div class="card-expand-hint">点击标题栏进入全屏 · 期权专页可下单</div>`;
|
||||
return inner;
|
||||
}
|
||||
if (rowHasOptionsLayout(row)) {
|
||||
if (monitorGridOptionsSplit) {
|
||||
/* 兼容旧单卡内嵌;正常分栏已走 okxPart 双卡 */
|
||||
inner += '<div class="hub-inner-cards">';
|
||||
inner += renderPerpetualInnerCard(row, ag, pos, orders, trends, tickMap, intraday);
|
||||
inner += renderOptionsInnerCard(row);
|
||||
@@ -4266,41 +4284,49 @@
|
||||
inner = `<div class="err">${esc(agErr || "子代理返回失败")}</div>`;
|
||||
inner += `<div class="empty-hint">请检查 PM2 子代理与 <code>${esc(row.agent_url || "")}/status</code></div>`;
|
||||
} else {
|
||||
inner = renderGridBody(row, ag, pos, hm, flaskOk, keys, orders, trends, rolls, kmap);
|
||||
inner = renderGridBody(row, ag, pos, hm, flaskOk, keys, orders, trends, rolls, kmap, opts);
|
||||
}
|
||||
const online = row.http_ok && agOk;
|
||||
const cardCls = online ? "card-online" : "card-offline";
|
||||
const dotCls = online ? "ok" : "bad";
|
||||
const flaskOpen = row.flask_url_browser || row.flask_url;
|
||||
const okxPart = opts.okxPart || "";
|
||||
const isOkxOptionsCard = okxPart === "options";
|
||||
const isOkxPerpCard = okxPart === "perp";
|
||||
const titleSuffix = isOkxPerpCard ? " · 永续" : isOkxOptionsCard ? " · 期权" : "";
|
||||
const openFlask = flaskOpen
|
||||
? `<a class="btn-link btn-open-instance btn-open-trade" href="#" data-ex-id="${esc(row.id)}" data-next="/trade" data-new-tab="1">打开实例</a>`
|
||||
: "";
|
||||
const openTrade = flaskOpen
|
||||
? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/trade">下单</a>`
|
||||
: "";
|
||||
const openKey = flaskOpen
|
||||
? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/key_monitor">监控位</a>`
|
||||
: "";
|
||||
const openTrade =
|
||||
flaskOpen && !isOkxOptionsCard
|
||||
? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/trade">下单</a>`
|
||||
: "";
|
||||
const openKey =
|
||||
flaskOpen && !isOkxOptionsCard
|
||||
? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/key_monitor">监控位</a>`
|
||||
: "";
|
||||
const openReview = flaskOpen
|
||||
? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/records">复盘</a>`
|
||||
: "";
|
||||
const openOptions =
|
||||
flaskOpen && (row.capabilities || []).includes("options")
|
||||
flaskOpen && ((row.capabilities || []).includes("options") || isOkxOptionsCard)
|
||||
? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/options">期权</a>`
|
||||
: "";
|
||||
const intraday = isIntradayDisciplineRow(row);
|
||||
const fcHeadBadge = intraday ? forceCloseHeadBadgeHtml(row.force_close) : "";
|
||||
const fcHeadBadge = intraday && !isOkxOptionsCard ? forceCloseHeadBadgeHtml(row.force_close) : "";
|
||||
const showCloseAll = !intraday && !isOkxOptionsCard;
|
||||
const layoutCls = opts.okxSplit
|
||||
? " card-monitor-okx-split"
|
||||
: opts.splitSide
|
||||
: opts.splitSide || okxPart
|
||||
? " card-monitor-split-side"
|
||||
: "";
|
||||
return `<div class="card ${cardCls}${layoutCls}" data-ex-id="${esc(row.id)}">
|
||||
const partAttr = okxPart ? ` data-okx-part="${esc(okxPart)}"` : "";
|
||||
return `<div class="card ${cardCls}${layoutCls}" data-ex-id="${esc(row.id)}"${partAttr}>
|
||||
<div class="card-head card-expand-zone" title="点击放大全屏">
|
||||
<div>
|
||||
<div class="card-title-row">
|
||||
<span class="status-dot ${dotCls}" title="${online ? "在线" : "离线"}"></span>
|
||||
<div class="card-title"><span>${esc(row.name)}</span>${fcHeadBadge}${formatRiskStatusBadge(hm.risk_status)}</div>
|
||||
<div class="card-title"><span>${esc(row.name)}${esc(titleSuffix)}</span>${fcHeadBadge}${formatRiskStatusBadge(hm.risk_status)}</div>
|
||||
</div>
|
||||
<div class="card-sub">${esc(flaskOpen || "")}</div>
|
||||
</div>
|
||||
@@ -4310,7 +4336,7 @@
|
||||
${openKey}
|
||||
${openOptions}
|
||||
${openReview}
|
||||
${intraday ? "" : `<button type="button" class="danger btn-close-ex" data-id="${esc(row.id)}">全平</button>`}
|
||||
${showCloseAll ? `<button type="button" class="danger btn-close-ex" data-id="${esc(row.id)}">全平</button>` : ""}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">${inner}</div>
|
||||
|
||||
Reference in New Issue
Block a user