fix: CTP连接改后台异步,避免多路重连互相阻塞

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-24 13:49:25 +08:00
parent 1d95950b5c
commit 049aaffdcf
4 changed files with 198 additions and 84 deletions
+93 -40
View File
@@ -69,18 +69,95 @@
if (marketHint) marketHint.hidden = priceType !== 'market';
}
function updateCtpBadge(connected) {
function updateCtpBadge(connected, connecting) {
var ctpBadge = document.getElementById('ctp-badge');
var btnConnect = document.getElementById('btn-ctp-connect');
if (ctpBadge) {
ctpBadge.textContent = connected ? 'CTP 已连接' : 'CTP 未连接';
ctpBadge.className = 'badge ' + (connected ? 'profit' : 'planned');
if (connecting) {
ctpBadge.textContent = 'CTP 连接中';
ctpBadge.className = 'badge planned';
} else {
ctpBadge.textContent = connected ? 'CTP 已连接' : 'CTP 未连接';
ctpBadge.className = 'badge ' + (connected ? 'profit' : 'planned');
}
}
if (btnConnect && connected) {
btnConnect.textContent = '重连 CTP';
if (btnConnect) {
if (connecting) {
btnConnect.textContent = '连接中…';
btnConnect.disabled = true;
} else {
btnConnect.disabled = false;
btnConnect.textContent = connected ? '重连 CTP' : '连接 CTP';
}
}
}
function waitForCtpConnected(maxMs) {
var deadline = Date.now() + (maxMs || 35000);
function tick() {
return fetch('/api/ctp/status')
.then(function (r) { return r.json(); })
.then(function (d) {
var st = d.status || {};
if (st.connected) {
updateCtpBadge(true, false);
if (d.account && d.account.available != null) {
var avail = document.getElementById('avail-display');
if (avail) avail.textContent = Number(d.account.available).toFixed(2);
}
pollPositions();
return true;
}
if (st.connecting && Date.now() < deadline) {
updateCtpBadge(false, true);
return new Promise(function (resolve) {
setTimeout(function () { resolve(tick()); }, 2000);
});
}
updateCtpBadge(false, false);
if (st.last_error) {
var hint = document.querySelector('.ctp-install-hint');
if (hint) hint.textContent = st.last_error;
}
return false;
})
.catch(function () { updateCtpBadge(false, false); return false; });
}
return tick();
}
function requestCtpConnect(force) {
updateCtpBadge(false, true);
return fetch('/api/ctp/connect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ force: !!force, auto: !force })
})
.then(function (r) { return r.json(); })
.then(function (d) {
if (d.status && d.status.connected) {
updateCtpBadge(true, false);
pollPositions();
return d;
}
if (d.connecting || (d.status && d.status.connecting)) {
return waitForCtpConnected(35000).then(function (ok) {
if (!ok && d.error) alert(d.error);
else if (!ok && d.status && d.status.last_error) alert(d.status.last_error);
return d;
});
}
if (!d.ok) {
updateCtpBadge(false, false);
alert(d.error || (d.status && d.status.last_error) || '连接失败');
}
return d;
})
.catch(function () {
updateCtpBadge(false, false);
});
}
function refreshQuote() {
var sym = selectedSymbol();
var lots = isRiskMode() ? (effectiveLots() || 1) : (lotsInput ? lotsInput.value : '1');
@@ -155,29 +232,12 @@
function tryAutoCtpReconnect() {
if (ctpReconnecting) return;
var now = Date.now();
if (now - lastCtpReconnectAt < 30000) return;
if (now - lastCtpReconnectAt < 60000) return;
lastCtpReconnectAt = now;
ctpReconnecting = true;
fetch('/api/ctp/connect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ auto: true })
})
.then(function (r) { return r.json(); })
.then(function (d) {
if (d.ok && d.status && d.status.connected) {
updateCtpBadge(true);
var avail = document.getElementById('avail-display');
if (avail && d.account && d.account.available != null) {
avail.textContent = Number(d.account.available).toFixed(2);
}
pollPositions();
}
})
.catch(function () { /* ignore */ })
.finally(function () {
ctpReconnecting = false;
});
requestCtpConnect(false).finally(function () {
ctpReconnecting = false;
});
}
function showOrderMsg(text, ok) {
@@ -342,9 +402,14 @@
var cap = document.getElementById('cap-display');
if (cap && data.capital != null) cap.textContent = Number(data.capital).toFixed(2);
var connected = data.ctp_status && data.ctp_status.connected;
updateCtpBadge(!!connected);
var connecting = data.ctp_status && data.ctp_status.connecting;
updateCtpBadge(!!connected, !!connecting);
var rows = data.rows || [];
if (!connected) {
if (connecting) {
list.innerHTML = '<div class="empty-hint">CTP 连接中,请稍候…</div>';
return;
}
list.innerHTML = '<div class="empty-hint">CTP 未连接,正在尝试自动重连…</div>';
tryAutoCtpReconnect();
return;
@@ -446,19 +511,7 @@
var btnConnect = document.getElementById('btn-ctp-connect');
if (btnConnect) {
btnConnect.addEventListener('click', function () {
btnConnect.disabled = true;
btnConnect.textContent = '连接中…';
fetch('/api/ctp/connect', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' })
.then(function (r) { return r.json(); })
.then(function (d) {
if (!d.ok) { alert(d.error || '连接失败'); return; }
updateCtpBadge(true);
pollPositions();
})
.finally(function () {
btnConnect.disabled = false;
btnConnect.textContent = '重连 CTP';
});
requestCtpConnect(true);
});
}