fix期权复盘同步后无变化不重绘,避免进页闪动。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -32,11 +32,68 @@
|
||||
var tradesPages = 1;
|
||||
var reviewedPage = 0;
|
||||
var reviewedPages = 1;
|
||||
var tradesListFp = "";
|
||||
var reviewedListFp = "";
|
||||
var statsFp = "";
|
||||
|
||||
function $(id) {
|
||||
return document.getElementById(id);
|
||||
}
|
||||
|
||||
function listFingerprint(kind, data, rows) {
|
||||
var parts = [
|
||||
kind,
|
||||
activeSource,
|
||||
String((data && data.total) || 0),
|
||||
String((data && data.page) || 0),
|
||||
String((data && data.pages) || 0),
|
||||
];
|
||||
(rows || []).forEach(function (t) {
|
||||
var e = t.entry || {};
|
||||
parts.push(
|
||||
[
|
||||
t.id,
|
||||
t.realized_pnl_total,
|
||||
t.profit_rate,
|
||||
t.initial_premium_usdt,
|
||||
t.option_fee_usdt,
|
||||
t.status_raw,
|
||||
t.reviewed ? 1 : 0,
|
||||
t.opened_at,
|
||||
t.closed_at,
|
||||
t.hold_seconds,
|
||||
t.reviewed_at,
|
||||
t.strategy_tag || e.strategy_tag,
|
||||
t.result_tag || e.result_tag,
|
||||
t.direction_view || e.direction_view,
|
||||
t.entry_logic || e.entry_logic,
|
||||
t.source_label || t.source_type,
|
||||
t.inst_id,
|
||||
t.underlying,
|
||||
t.direction,
|
||||
t.plan_close_reason,
|
||||
].join("\u001f")
|
||||
);
|
||||
});
|
||||
return parts.join("\u001e");
|
||||
}
|
||||
|
||||
function statsFingerprint(data) {
|
||||
try {
|
||||
return JSON.stringify({
|
||||
kpi: data.kpi || {},
|
||||
by_source_type: data.by_source_type || [],
|
||||
by_underlying: data.by_underlying || [],
|
||||
by_strategy: data.by_strategy || [],
|
||||
by_close_reason: data.by_close_reason || [],
|
||||
by_hold_bucket: data.by_hold_bucket || [],
|
||||
by_opt_type: data.by_opt_type || [],
|
||||
});
|
||||
} catch (_) {
|
||||
return String(Date.now());
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s == null ? "" : s)
|
||||
.replace(/&/g, "&")
|
||||
@@ -203,7 +260,7 @@
|
||||
setSyncStatus("读取本地记录…");
|
||||
loadTrades({ sync: false });
|
||||
loadReviewed({ sync: false });
|
||||
loadStats();
|
||||
loadStats({ soft: false });
|
||||
backgroundSync();
|
||||
}
|
||||
|
||||
@@ -221,7 +278,7 @@
|
||||
setSyncStatus("本地记录已加载");
|
||||
loadTrades({ sync: false, soft: true });
|
||||
loadReviewed({ sync: false, soft: true });
|
||||
loadStats();
|
||||
loadStats({ soft: true });
|
||||
})
|
||||
.catch(function () {
|
||||
setSyncStatus("同步跳过,已显示本地缓存");
|
||||
@@ -379,12 +436,8 @@
|
||||
function beginListLoad(wrapId, soft) {
|
||||
var wrap = $(wrapId);
|
||||
if (!wrap) return null;
|
||||
if (soft) {
|
||||
if (!wrap.style.minHeight) {
|
||||
wrap.style.minHeight = Math.max(wrap.offsetHeight, 1) + "px";
|
||||
}
|
||||
wrap.classList.add("or-list-loading");
|
||||
} else {
|
||||
// soft 刷新不打半透明:无变化时也不应闪;有变化时静默换表
|
||||
if (!soft) {
|
||||
wrap.classList.remove("or-list-loading");
|
||||
wrap.style.minHeight = "";
|
||||
}
|
||||
@@ -405,6 +458,7 @@
|
||||
if (!tbody) return;
|
||||
var wrap = beginListLoad("or-trades-wrap", soft);
|
||||
if (!soft) {
|
||||
tradesListFp = "";
|
||||
tbody.innerHTML = '<tr><td colspan="10" class="muted">加载中…</td></tr>';
|
||||
}
|
||||
var p = baseQs();
|
||||
@@ -419,6 +473,7 @@
|
||||
.then(function (data) {
|
||||
if (doSync) setSyncStatus("本地记录已加载");
|
||||
if (!data.ok) {
|
||||
tradesListFp = "";
|
||||
tbody.innerHTML = '<tr><td colspan="10" class="muted">加载失败</td></tr>';
|
||||
endListLoad(wrap);
|
||||
return;
|
||||
@@ -428,6 +483,12 @@
|
||||
return;
|
||||
}
|
||||
var rows = data.trades || [];
|
||||
var fp = listFingerprint("trades", data, rows);
|
||||
if (soft && fp === tradesListFp) {
|
||||
endListLoad(wrap);
|
||||
return;
|
||||
}
|
||||
tradesListFp = fp;
|
||||
tradesCache = {};
|
||||
if (!rows.length) {
|
||||
tbody.innerHTML =
|
||||
@@ -546,6 +607,7 @@
|
||||
if (!tbody) return;
|
||||
var wrap = beginListLoad("or-reviewed-wrap", soft);
|
||||
if (!soft) {
|
||||
reviewedListFp = "";
|
||||
tbody.innerHTML = '<tr><td colspan="13" class="muted">加载中…</td></tr>';
|
||||
}
|
||||
var p = baseQs();
|
||||
@@ -559,6 +621,7 @@
|
||||
})
|
||||
.then(function (data) {
|
||||
if (!data.ok) {
|
||||
reviewedListFp = "";
|
||||
tbody.innerHTML = '<tr><td colspan="13" class="muted">加载失败</td></tr>';
|
||||
endListLoad(wrap);
|
||||
return;
|
||||
@@ -568,6 +631,12 @@
|
||||
return;
|
||||
}
|
||||
var rows = data.trades || [];
|
||||
var fp = listFingerprint("reviewed", data, rows);
|
||||
if (soft && fp === reviewedListFp) {
|
||||
endListLoad(wrap);
|
||||
return;
|
||||
}
|
||||
reviewedListFp = fp;
|
||||
reviewedCache = {};
|
||||
if (!rows.length) {
|
||||
tbody.innerHTML = '<tr><td colspan="13" class="muted">暂无复盘记录</td></tr>';
|
||||
@@ -1024,10 +1093,13 @@
|
||||
);
|
||||
}
|
||||
|
||||
function loadStats() {
|
||||
function loadStats(opts) {
|
||||
opts = opts || {};
|
||||
var soft = !!opts.soft;
|
||||
var kpi = $("or-kpi");
|
||||
var groups = $("or-stats-groups");
|
||||
if (!kpi || !groups) return;
|
||||
if (!soft) statsFp = "";
|
||||
// 与 trades?sync=1 并行时不再二次同步,避免 SQLite database is locked
|
||||
var qs = baseQs();
|
||||
qs.set("sync", "0");
|
||||
@@ -1037,6 +1109,9 @@
|
||||
})
|
||||
.then(function (data) {
|
||||
if (!data.ok) return;
|
||||
var fp = statsFingerprint(data);
|
||||
if (soft && fp === statsFp) return;
|
||||
statsFp = fp;
|
||||
var k = data.kpi || {};
|
||||
kpi.innerHTML = [
|
||||
["笔数", k.total],
|
||||
|
||||
Reference in New Issue
Block a user