fix(hub): archive trade row selection by exchange+id

Use composite trade key so Gate accounts with duplicate trade IDs no longer highlight two rows at once.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-11 20:01:20 +08:00
parent a87234f627
commit 3ef0750ea9
2 changed files with 42 additions and 18 deletions
+41 -17
View File
@@ -58,7 +58,7 @@
let tradingDay = "";
let selected = null;
let trades = [];
let selectedTradeId = null;
let selectedTradeKey = null;
let timeframe = "15m";
let chart = null;
let candleSeries = null;
@@ -229,6 +229,23 @@
return exKey ? exchangeLabel(exKey) : "—";
}
function tradeRowKey(tr) {
if (!tr) return "";
const exKey = String(tr.exchange_key || "").toLowerCase();
const tid = tr.trade_id != null ? tr.trade_id : tr.id;
if (!exKey || tid == null || tid === "") return "";
return exKey + ":" + String(tid);
}
function findTradeByKey(key) {
if (!key) return null;
return (
dailyTrades.find(function (t) {
return tradeRowKey(t) === String(key);
}) || null
);
}
function applyTagSelectStyle(sel) {
if (!sel) return;
const v = sel.value || "";
@@ -272,7 +289,7 @@
});
if (!tr) return;
selected = { exchange_key: tr.exchange_key, symbol: tr.symbol };
selectedTradeId = String(tr.trade_id || tr.id);
selectedTradeKey = tradeRowKey(tr);
await loadSymbolTradesForChart(tr.exchange_key, tr.symbol);
}
@@ -589,9 +606,9 @@
function pickAnchorTrade() {
if (!trades.length) return null;
if (selectedTradeId != null) {
if (selectedTradeKey) {
const hit = trades.find(function (t) {
return String(t.trade_id || t.id) === String(selectedTradeId);
return tradeRowKey(t) === selectedTradeKey;
});
if (hit) return hit;
}
@@ -721,10 +738,10 @@
const multi = sorted.length > 1;
const out = [];
sorted.forEach(function (row, idx) {
const tid = String(row.trade_id || row.id);
const rowKey = tradeRowKey(row);
const parts = buildTradeMarkers(row, candles, tf, {
labelSuffix: multi ? String(idx + 1) : "",
highlight: tid === String(selectedTradeId),
highlight: rowKey === selectedTradeKey,
});
out.push.apply(out, parts);
});
@@ -937,7 +954,7 @@
return;
}
selected = { exchange_key: exKey, symbol: sym };
selectedTradeId = String(tr.trade_id || tr.id);
selectedTradeKey = tradeRowKey(tr);
renderTrades();
setChartOpen(true);
await loadSymbolTradesForChart(exKey, sym);
@@ -960,14 +977,17 @@
.map(function (t) {
const tid = t.trade_id || t.id;
const exKey = String(t.exchange_key || "").toLowerCase();
const rowKey = tradeRowKey(t);
const tag = t.behavior_tag || "";
const sick = tag === "sick";
const active = String(tid) === String(selectedTradeId) ? " is-active" : "";
const active = rowKey && rowKey === selectedTradeKey ? " is-active" : "";
const rev = reviewMark(t);
return (
'<tr class="archive-trade-row' +
active +
(sick ? " archive-trade-sick" : "") +
'" data-key="' +
esc(rowKey) +
'" data-id="' +
tid +
'" data-ex="' +
@@ -1051,13 +1071,11 @@
btn.addEventListener("click", function (ev) {
ev.stopPropagation();
const row = btn.closest(".archive-trade-row");
const tid = btn.getAttribute("data-id");
const tr = dailyTrades.find(function (t) {
return String(t.trade_id || t.id) === String(tid);
});
const rowKey = row && row.getAttribute("data-key");
const tr = findTradeByKey(rowKey);
if (tr) void openTradeChart(tr);
else if (row) {
selectedTradeId = tid;
else if (rowKey) {
selectedTradeKey = rowKey;
renderTrades();
}
});
@@ -1096,7 +1114,8 @@
setStatus(j.detail || j.msg || "删除失败");
return;
}
if (String(selectedTradeId) === String(tradeId)) selectedTradeId = null;
const deletedKey = String(exchangeKey || "").toLowerCase() + ":" + String(tradeId);
if (selectedTradeKey === deletedKey) selectedTradeKey = null;
await loadDailyTrades();
setStatus("已移除 1 笔档案记录");
}
@@ -1106,7 +1125,9 @@
if (!exKey) return;
const body = { behavior_tag: tag || "", note: note != null ? note : undefined };
if (note == null) {
const row = elTrades.querySelector('.archive-trade-row[data-id="' + tradeId + '"]');
const row = elTrades.querySelector(
'.archive-trade-row[data-id="' + tradeId + '"][data-ex="' + exKey + '"]'
);
const inp = row && row.querySelector(".archive-note-input");
body.note = inp ? inp.value : "";
}
@@ -1116,7 +1137,10 @@
body: JSON.stringify(body),
});
const tr = dailyTrades.find(function (t) {
return String(t.trade_id || t.id) === String(tradeId);
return (
String(t.trade_id || t.id) === String(tradeId) &&
String(t.exchange_key || "").toLowerCase() === String(exKey).toLowerCase()
);
});
if (tr) {
tr.behavior_tag = body.behavior_tag;