fix(hub): inner-light-mind chart, exchange column and layout

Preserve exchange_key from archive cache, fix chart resize in details panel, move filters above quotes, align panel heights, and style sick trades with red/cyan.
This commit is contained in:
dekun
2026-06-11 17:53:25 +08:00
parent bb800b876b
commit 2388ecc882
4 changed files with 138 additions and 45 deletions
+71 -12
View File
@@ -211,12 +211,50 @@
if (elStatus) elStatus.textContent = text || "";
}
function tradeRowExchange(tr) {
if (!tr) return "—";
const exKey = tr.exchange_key || tr.account_exchange_key || "";
if (exKey) return exchangeLabel(exKey);
const name = tr.account_name || tr.exchange_name || "";
return name || "—";
}
function exchangeLabel(exKey) {
const key = String(exKey || "").toLowerCase();
if (!key) return "—";
const hit = (meta && meta.exchanges || []).find(function (ex) {
return String(ex.key || "").toLowerCase() === key;
});
return hit ? hit.name || hit.key : exKey || "—";
return hit ? hit.name || hit.key : exKey;
}
function scheduleChartResize() {
requestAnimationFrame(function () {
if (chart && elChartHost) {
const w = elChartHost.clientWidth;
const h = elChartHost.clientHeight;
if (w > 0 && h > 0) chart.applyOptions({ width: w, height: h });
}
requestAnimationFrame(function () {
if (chart && elChartHost) {
const w = elChartHost.clientWidth;
const h = elChartHost.clientHeight;
if (w > 0 && h > 0) chart.applyOptions({ width: w, height: h });
}
});
});
}
async function ensureChartSelection() {
if (selected && selected.exchange_key && selected.symbol) return;
if (!dailyTrades.length) return;
const tr = dailyTrades.find(function (t) {
return t.exchange_key && t.symbol;
});
if (!tr) return;
selected = { exchange_key: tr.exchange_key, symbol: tr.symbol };
selectedTradeId = String(tr.trade_id || tr.id);
await loadSymbolTradesForChart(tr.exchange_key, tr.symbol);
}
function isChartOpen() {
@@ -229,7 +267,11 @@
if (elBtnChartToggle) {
elBtnChartToggle.classList.toggle("is-active", !!on);
}
if (!on) destroyChart();
if (!on) {
destroyChart();
return;
}
scheduleChartResize();
}
function updateChartTitle() {
@@ -718,7 +760,11 @@
setStatus(j.detail || "K 线加载失败");
return;
}
if (chart) {
destroyChart();
}
ensureChart();
scheduleChartResize();
const candles = j.candles || [];
lastCandles = candles;
candleSeries.setData(
@@ -742,14 +788,18 @@
chart.timeScale().setVisibleLogicalRange({ from: candles.length - 120, to: candles.length + 5 });
}
updateChartTitle();
scheduleChartResize();
setStatus("K 线 " + candles.length + " 根 · " + timeframe);
}
async function openTradeChart(tr) {
if (!tr) return;
const exKey = tr.exchange_key;
const sym = tr.symbol;
if (!exKey || !sym) return;
const exKey = tr.exchange_key || tr.account_exchange_key || "";
const sym = tr.symbol || "";
if (!exKey || !sym) {
setStatus("该笔交易缺少交易所或合约,无法加载图表");
return;
}
selected = { exchange_key: exKey, symbol: sym };
selectedTradeId = String(tr.trade_id || tr.id);
setChartOpen(true);
@@ -772,7 +822,7 @@
dailyTrades
.map(function (t) {
const tid = t.trade_id || t.id;
const exKey = t.exchange_key || "";
const exKey = t.exchange_key || t.account_exchange_key || "";
const tag = t.behavior_tag || "";
const sick = tag === "sick";
const active = String(tid) === String(selectedTradeId) ? " is-active" : "";
@@ -785,9 +835,11 @@
tid +
'" data-ex="' +
esc(exKey) +
'" data-sym="' +
esc(t.symbol || "") +
'">' +
"<td>" +
esc(exchangeLabel(exKey)) +
esc(tradeRowExchange(t)) +
"</td>" +
"<td>" +
(rev ? '<span class="archive-review-mark">' + rev + "</span>" : "") +
@@ -1015,17 +1067,24 @@
});
}
if (elBtnChartToggle) {
elBtnChartToggle.addEventListener("click", function () {
elBtnChartToggle.addEventListener("click", async function () {
const next = !isChartOpen();
setChartOpen(next);
if (next && selected) void loadChart();
if (next) {
await ensureChartSelection();
void loadChart();
}
});
}
if (elChartSection) {
elChartSection.addEventListener("toggle", function () {
elChartSection.addEventListener("toggle", async function () {
if (elBtnChartToggle) elBtnChartToggle.classList.toggle("is-active", elChartSection.open);
if (elChartSection.open && selected) void loadChart();
else if (!elChartSection.open) destroyChart();
if (elChartSection.open) {
await ensureChartSelection();
void loadChart();
} else {
destroyChart();
}
});
}
if (elQuoteForm) elQuoteForm.addEventListener("submit", addQuote);