fix(hub): merge strategy snapshots into archive for gate_bot

Include strategy_trade_snapshots when trade_records is empty, harden SQL for older schemas, and show per-exchange sync errors in the archive UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-07 23:02:46 +08:00
parent 6a56928d59
commit 3052607280
6 changed files with 396 additions and 34 deletions
+21 -4
View File
@@ -410,6 +410,9 @@
const r = await apiFetch("/api/archive/meta");
meta = await r.json();
timeframe = (meta && meta.default_timeframe) || "15m";
if (meta && meta.last_sync && elStatus && !elStatus.textContent) {
setStatus(formatSyncSummary(meta.last_sync));
}
renderExchangeOptions();
if (elTfTabs) {
elTfTabs.querySelectorAll(".archive-tf-btn").forEach(function (btn) {
@@ -418,16 +421,30 @@
}
}
function formatSyncSummary(j) {
const results = j.results || [];
const okN = results.filter(function (x) {
return x.ok !== false;
}).length;
const parts = ["同步完成 · " + okN + "/" + (j.exchanges || 0) + " 所"];
results.forEach(function (row) {
const label = row.exchange_key || row.name || "?";
if (row.ok === false) {
parts.push(label + " 失败: " + (row.msg || "未知错误"));
} else {
parts.push(label + " " + (row.trade_count != null ? row.trade_count : row.trades || 0) + " 笔");
}
});
return parts.join(" · ");
}
async function syncAll() {
setStatus("同步中(可能需数分钟)…");
elBtnSync && (elBtnSync.disabled = true);
try {
const r = await apiFetch("/api/archive/sync", { method: "POST" });
const j = await r.json();
const okN = (j.results || []).filter(function (x) {
return x.ok !== false;
}).length;
setStatus("同步完成 · " + okN + "/" + (j.exchanges || 0) + " 所");
setStatus(formatSyncSummary(j));
await loadList();
if (selected) await openDetail(selected.exchange_key, selected.symbol);
} catch (e) {