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:
@@ -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;
|
||||
|
||||
@@ -584,7 +584,7 @@
|
||||
<script src="https://unpkg.com/lightweight-charts@4.2.0/dist/lightweight-charts.standalone.production.js"></script>
|
||||
<script src="/assets/chart_draw.js?v=20260609-market-day-split"></script>
|
||||
<script src="/assets/chart.js?v=20260609-market-day-split"></script>
|
||||
<script src="/assets/archive.js?v=20260612-archive-chart-row"></script>
|
||||
<script src="/assets/archive.js?v=20260612-trade-row-key"></script>
|
||||
<script src="/assets/funds.js?v=20260609-hub-funds-fold"></script>
|
||||
<script src="/assets/dashboard.js?v=20260612-dash-monitor-count"></script>
|
||||
<script src="/assets/ai_review_render.js?v=3"></script>
|
||||
|
||||
Reference in New Issue
Block a user