fix: hide hub close/entrust controls for intraday discipline profile

Expose intraday_discipline via hub meta and block manual close/tpsl APIs; Gate instance card no longer shows 全平/平仓/委托.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-06 02:26:22 +08:00
parent a268a93027
commit 4904a86e03
8 changed files with 119 additions and 22 deletions
+57 -20
View File
@@ -2804,6 +2804,24 @@
);
}
function isIntradayDisciplineRow(row) {
const m = row && row.meta;
if (!m || typeof m !== "object") return false;
if (m.intraday_discipline === true) return true;
return m.order_entry_profile === "intraday";
}
function forceCloseHeadBadgeHtml(state) {
if (!state || !state.enabled) return "";
return forceCloseSymbolBadgeHtml({
force_close_enabled: true,
force_close_label: state.label || "强制清仓",
force_close_countdown: state.countdown || "--:--:--",
force_close_at_ms: state.next_at_ms,
force_close_active: state.active,
});
}
function renderTrendDcaTable(t, tickMap) {
const levels = resolveTrendDcaLevels(t);
if (!levels.length) return "";
@@ -2979,7 +2997,7 @@
</div>`;
}
function renderLivePositionCard(exchangeId, exchangeKey, pos, monitorOrder, trendPlan, tickMap) {
function renderLivePositionCard(exchangeId, exchangeKey, pos, monitorOrder, trendPlan, tickMap, intradayDiscipline) {
const symbol = pos.symbol || "";
const exKeyAttr = esc(exchangeKey || exchangeId || "").replace(/"/g, "&quot;");
const side = (pos.side || "long").toLowerCase();
@@ -2999,6 +3017,7 @@
const tp = tpsl.tp;
const tpMonitored = tpsl.tp_monitored;
const isTrend = isTrendContext(mo, trendPlan);
const intraday = !!intradayDiscipline;
const rr = resolveSnapshotRr(mo, side, entry, sl, tp, tpMonitored, trendPlan);
const beSecured = isBreakevenSecured(side, entry, mo, cond, pos);
const upnl = resolveTrendFloatingPnl(pos, trendPlan);
@@ -3044,29 +3063,34 @@
if (riskLine) meta.push(riskLine);
const latestRiskLine = formatLatestRiskMeta(mo, trendPlan, pos, tpsl);
if (latestRiskLine) meta.push(latestRiskLine);
const beOn = mo.breakeven_enabled === 1 || mo.breakeven_enabled === true;
meta.push(
`<span class="${beOn ? "pos-meta-on" : "pos-meta-off"}">移动保本:${beOn ? "开" : "关"}</span>`
);
if (!intraday) {
const beOn = mo.breakeven_enabled === 1 || mo.breakeven_enabled === true;
meta.push(
`<span class="${beOn ? "pos-meta-on" : "pos-meta-off"}">移动保本:${beOn ? "开" : "关"}</span>`
);
}
} else {
meta.push("来源: 交易所持仓");
meta.push("风格: —");
meta.push(`<span class="pos-meta-off">移动保本:关</span>`);
if (!intraday) meta.push(`<span class="pos-meta-off">移动保本:关</span>`);
}
const symBeBadge = beSecured ? ` ${breakevenBadgeHtml()}` : "";
const tcSymBadge = !isTrend && mo.time_close_enabled ? timeCloseSymbolBadgeHtml(mo) : "";
const fcSymBadge = !isTrend && mo.force_close_enabled ? forceCloseSymbolBadgeHtml(mo) : "";
const mktAttrs = marketOpenBtnAttrs(exchangeId, exchangeKey, symbol, pos, monitorOrder, trendPlan);
const headActions = intraday
? ""
: `<div class="pos-head-actions">
<button type="button" class="pos-entrust-btn btn-place-tpsl" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}" data-contracts="${contractsAttr}" data-sl="${slAttr}" data-tp="${tpAttr}">委托</button>
<button type="button" class="pos-close-btn btn-close-pos" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}">平仓</button>
</div>`;
return `<div class="pos-card hub-pos-card">
<div class="pos-card-head">
<div class="pos-card-symbol">
<button type="button" class="btn-open-market sym-link pos-symbol-link" ${mktAttrs} title="打开行情区(含入场/止盈止损)"><strong>${esc(symbol)}</strong></button>${tcSymBadge}${fcSymBadge}${symBeBadge}
<span class="pos-side-badge ${sideCls}">${sideCn}</span>
</div>
<div class="pos-head-actions">
<button type="button" class="pos-entrust-btn btn-place-tpsl" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}" data-contracts="${contractsAttr}" data-sl="${slAttr}" data-tp="${tpAttr}">委托</button>
<button type="button" class="pos-close-btn btn-close-pos" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}">平仓</button>
</div>
${headActions}
</div>
<div class="pos-meta">${meta.map((m) => `<span class="pos-meta-item">${m}</span>`).join("")}</div>
<div class="pos-grid">
@@ -3218,7 +3242,10 @@
!isTrendContext(mo, trendPlan) && mo.time_close_enabled ? timeCloseSymbolBadgeHtml(mo) : "";
const fcBadge =
!isTrendContext(mo, trendPlan) && mo.force_close_enabled ? forceCloseSymbolBadgeHtml(mo) : "";
const actionCell = `<div class="pos-action-group">
const intraday = !!options.intradayDiscipline;
const actionCell = intraday
? ""
: `<div class="pos-action-group">
<button type="button" class="btn-place-tpsl btn-sm ghost" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}" data-contracts="${contractsAttr}" data-sl="${slAttr}" data-tp="${tpAttr}">委托</button>
<button type="button" class="btn-close-pos btn-sm danger" data-ex-id="${esc(exchangeId)}" data-symbol="${symAttr}" data-side="${sideAttr}">平仓</button>
</div>`;
@@ -3329,7 +3356,8 @@
.join("")}</div>`;
}
function renderGridPositionsTable(exchangeId, exchangeKey, positions, orders, trends, tickMap) {
function renderGridPositionsTable(exchangeId, exchangeKey, positions, orders, trends, tickMap, intradayDiscipline) {
const intraday = !!intradayDiscipline;
const rows = positions
.map((p) =>
renderPositionTableRow(
@@ -3339,7 +3367,7 @@
findMonitorOrder(orders, p.symbol, p.side),
findTrendPlan(trends, p.symbol, p.side),
tickMap,
{ compact: true }
{ compact: true, intradayDiscipline: intraday }
)
)
.join("");
@@ -3362,6 +3390,7 @@
function renderGridBody(row, ag, pos, hm, flaskOk, keys, orders, trends, rolls, kmap) {
const tickMap = buildPriceTickMap(row);
const intraday = isIntradayDisciplineRow(row);
let inner = renderAccountStatRow(row, ag);
inner += `<div class="section-title">交易所持仓 · ${pos.length} 仓</div>`;
if (pos.length) {
@@ -3371,13 +3400,16 @@
pos,
orders,
trends,
tickMap
tickMap,
intraday
);
} else {
inner += '<div class="empty-hint">无持仓</div>';
}
inner += renderCardStrategyStats(row, hm, flaskOk);
inner += `<div class="card-expand-hint">点击标题栏进入全屏 · 委托 / 关键位 / 下单监控 / 趋势回调 / 顺势加仓</div>`;
inner += intraday
? `<div class="card-expand-hint">日内纪律:禁手动平仓/改委托 · 整点强制清仓${row.force_close && row.force_close.enabled ? " · " + esc(row.force_close.label || "强制清仓") : ""}</div>`
: `<div class="card-expand-hint">点击标题栏进入全屏 · 委托 / 关键位 / 下单监控 / 趋势回调 / 顺势加仓</div>`;
return inner;
}
@@ -3396,9 +3428,11 @@
kmap[k.id] = k;
});
const flaskOpen = row.flask_url_browser || row.flask_url;
const intraday = isIntradayDisciplineRow(row);
const fcHeadBadge = intraday ? forceCloseHeadBadgeHtml(row.force_close) : "";
let html = `<div class="fs-head">
<div>
<h2 class="fs-title">${esc(row.name)}</h2>
<h2 class="fs-title">${esc(row.name)}${fcHeadBadge ? " " + fcHeadBadge : ""}</h2>
<div class="fs-sub">${esc(flaskOpen || "")}</div>
</div>
<div class="fs-head-actions">
@@ -3407,7 +3441,7 @@
${flaskOpen ? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/trade">下单</a>` : ""}
${flaskOpen ? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/key_monitor">监控位</a>` : ""}
${flaskOpen ? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/records">复盘</a>` : ""}
<button type="button" class="danger btn-close-ex" data-id="${esc(row.id)}">全平</button>
${intraday ? "" : `<button type="button" class="danger btn-close-ex" data-id="${esc(row.id)}">全平</button>`}
</div>
</div>`;
if (!row.http_ok || ag.ok === false) {
@@ -3427,7 +3461,8 @@
p,
findMonitorOrder(orders, p.symbol, p.side),
findTrendPlan(trends, p.symbol, p.side),
tickMap
tickMap,
intraday
);
});
} else {
@@ -3740,12 +3775,14 @@
const openReview = flaskOpen
? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/records">复盘</a>`
: "";
const intraday = isIntradayDisciplineRow(row);
const fcHeadBadge = intraday ? forceCloseHeadBadgeHtml(row.force_close) : "";
return `<div class="card ${cardCls}" data-ex-id="${esc(row.id)}">
<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>${formatRiskStatusBadge(hm.risk_status)}</div>
<div class="card-title"><span>${esc(row.name)}</span>${fcHeadBadge}${formatRiskStatusBadge(hm.risk_status)}</div>
</div>
<div class="card-sub">${esc(flaskOpen || "")}</div>
</div>
@@ -3754,7 +3791,7 @@
${openTrade}
${openKey}
${openReview}
<button type="button" class="danger btn-close-ex" data-id="${esc(row.id)}">全平</button>
${intraday ? "" : `<button type="button" class="danger btn-close-ex" data-id="${esc(row.id)}">全平</button>`}
</div>
</div>
<div class="card-body">${inner}</div>