fix: 清理幽灵止盈止损监控并修正仓位上限冻结误触发

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-24 14:09:42 +08:00
parent 5af04ef661
commit 23d0f1d6fa
4 changed files with 176 additions and 30 deletions
+3
View File
@@ -43,6 +43,9 @@
.pos-pending-orders{margin-top:.55rem;padding-top:.55rem;border-top:1px dashed var(--table-border)}
.pos-pending-orders .pending-title{font-size:.68rem;color:var(--text-muted);margin-bottom:.35rem}
.pos-pending-item{display:flex;justify-content:space-between;align-items:center;gap:.5rem;font-size:.75rem;padding:.35rem .5rem;border-radius:6px;margin-bottom:.25rem;background:var(--list-item-bg)}
.pos-pending-right{display:flex;align-items:center;gap:.45rem;flex-shrink:0}
.pos-dismiss-btn{padding:.2rem .55rem;font-size:.68rem;border-radius:6px;border:1px solid var(--table-border);background:var(--card-inner);color:var(--text-muted);cursor:pointer;width:auto;min-height:auto;line-height:1.3}
.pos-dismiss-btn:disabled{opacity:.55;cursor:wait}
.pos-pending-item.sl{border-left:3px solid var(--loss)}
.pos-pending-item.tp{border-left:3px solid var(--profit)}
.pos-pending-item.ctp{border-left:3px solid var(--accent)}
+52 -2
View File
@@ -318,16 +318,56 @@
if (!items || !items.length) return '';
var rows = items.map(function (p) {
var cls = p.order_kind === 'stop_loss' ? 'sl' : (p.order_kind === 'take_profit' ? 'tp' : 'ctp');
var dismissBtn = p.monitor_id ?
'<button type="button" class="pos-dismiss-btn" data-monitor-id="' + p.monitor_id + '">取消</button>' : '';
return (
'<div class="pos-pending-item ' + cls + '">' +
'<span>' + (p.label || '挂单') + '</span>' +
'<span><strong>' + fmtNum(p.price) + '</strong> · ' + (p.lots || 1) + ' 手</span>' +
'<span class="pos-pending-right">' +
'<strong>' + fmtNum(p.price) + '</strong> · ' + (p.lots || 1) + ' 手' +
dismissBtn +
'</span>' +
'</div>'
);
}).join('');
return '<div class="pos-pending-orders"><div class="pending-title">止盈止损挂单</div>' + rows + '</div>';
}
function dismissMonitor(monitorId, btn) {
if (!monitorId) return;
if (!confirm('取消该本地止盈止损监控?(不影响柜台委托)')) return;
if (btn) {
btn.disabled = true;
btn.textContent = '取消中…';
}
fetch('/api/trading/monitor/dismiss', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ monitor_id: monitorId })
})
.then(function (r) { return r.json(); })
.then(function (d) {
if (!d.ok) throw new Error(d.error || '取消失败');
pollPositions();
})
.catch(function (e) {
alert(e.message || '取消失败');
if (btn) {
btn.disabled = false;
btn.textContent = '取消';
}
});
}
function bindPendingDismiss(root) {
if (!root) return;
root.querySelectorAll('[data-monitor-id]').forEach(function (btn) {
btn.addEventListener('click', function () {
dismissMonitor(parseInt(btn.getAttribute('data-monitor-id'), 10), btn);
});
});
}
function buildPosCard(row) {
var pnlClass = row.float_pnl > 0 ? 'pnl-pos' : (row.float_pnl < 0 ? 'pnl-neg' : '');
var pnlText = row.float_pnl != null ? ((row.float_pnl >= 0 ? '+' : '') + fmtNum(row.float_pnl) + ' 元') : '--';
@@ -405,6 +445,11 @@
var connected = data.ctp_status && data.ctp_status.connected;
var connecting = data.ctp_status && data.ctp_status.connecting;
updateCtpBadge(!!connected, !!connecting);
var riskBadge = document.getElementById('risk-badge');
if (riskBadge && data.risk_status) {
riskBadge.textContent = data.risk_status.status_label || '';
riskBadge.className = 'badge ' + (data.risk_status.can_trade ? 'profit' : 'loss');
}
var rows = data.rows || [];
if (!connected) {
if (connecting) {
@@ -420,19 +465,24 @@
if (pendingOnly.length) {
list.innerHTML = '<div class="empty-hint" style="margin-bottom:.75rem">柜台暂无持仓</div>' +
pendingOnly.map(function (p) {
var dismissBtn = p.monitor_id ?
'<button type="button" class="pos-dismiss-btn" data-monitor-id="' + p.monitor_id + '">取消</button>' : '';
return (
'<div class="pos-pending-item ' +
(p.order_kind === 'stop_loss' ? 'sl' : (p.order_kind === 'take_profit' ? 'tp' : 'ctp')) +
'"><span>' + (p.label || '挂单') + ' · ' + (p.symbol || p.symbol_code) + '</span>' +
'<span><strong>' + fmtNum(p.price) + '</strong> · ' + (p.lots || 1) + ' 手</span></div>'
'<span class="pos-pending-right"><strong>' + fmtNum(p.price) + '</strong> · ' +
(p.lots || 1) + ' 手' + dismissBtn + '</span></div>'
);
}).join('');
bindPendingDismiss(list);
} else {
list.innerHTML = '<div class="empty-hint">柜台暂无持仓。</div>';
}
return;
}
list.innerHTML = rows.map(buildPosCard).join('');
bindPendingDismiss(list);
list.querySelectorAll('[data-close]').forEach(function (btn) {
btn.addEventListener('click', function () {
closePosition(JSON.parse(decodeURIComponent(btn.getAttribute('data-close'))), btn);