/** * 四所实例共用 UI:复盘详情、盈亏着色等。 */ (function (global) { "use strict"; function escapeHtml(s) { return String(s == null ? "" : s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function pnlClassFromValue(val) { const n = Number(String(val == null ? "" : val).replace(/[^\d.-]/g, "")); if (!Number.isFinite(n) || n === 0) return ""; return n > 0 ? "pnl-profit" : "pnl-loss"; } function formatPnlSpan(val, suffix) { const sfx = suffix == null ? "U" : suffix; const cls = pnlClassFromValue(val); const text = escapeHtml(val == null || val === "" ? "-" : val) + sfx; return cls ? `${text}` : text; } function buildJournalDetailHtml(o, formatExitLine) { const moodTags = Array.isArray(o.mood_issues) && o.mood_issues.length ? o.mood_issues.join(",") : o.mood_issues || "无"; const exitText = typeof formatExitLine === "function" ? formatExitLine(o) : o.exit_reason || "无"; const lines = [ `币种/周期:${escapeHtml(o.coin || "-")} ${escapeHtml(o.tf || "-")}`, `开仓时间:${escapeHtml(o.open_datetime || "-")}`, `平仓时间:${escapeHtml(o.close_datetime || "-")}`, `持仓时长:${escapeHtml(o.hold_duration || "-")}`, `盈亏:${formatPnlSpan(o.pnl)}`, `开仓类型:${escapeHtml(o.entry_reason || "无")}`, `平仓/离场:${escapeHtml(exitText)}`, `预期RR:${escapeHtml(o.expect_rr || "-")}`, `实际RR:${escapeHtml(o.real_rr || "-")}`, `保本后盯盘:${escapeHtml(o.post_breakeven_stare || "-")}`, `占用时新开仓:${escapeHtml(o.new_trade_while_occupied || "-")}`, `心态标签:${escapeHtml(moodTags)}`, `备注:${escapeHtml(o.note || "无")}`, ]; return lines.join("
"); } function setJournalDetailBody(o, formatExitLine) { const body = document.getElementById("detailBody"); if (!body) return; body.classList.remove("md-review"); body.classList.add("journal-detail-meta"); body.innerHTML = buildJournalDetailHtml(o, formatExitLine); } function openJournalDetailModal(id, journalCache, formatExitLine) { const o = journalCache && journalCache[id]; if (!o) return; const titleEl = document.getElementById("detailTitle"); if (titleEl) { titleEl.innerText = `交易复盘详情|${o.coin || "-"} ${o.tf || "-"}`; } setJournalDetailBody(o, formatExitLine); const imgEl = document.getElementById("detailImage"); if (imgEl) { if (o.image) { imgEl.src = `/static/images/${o.image}`; imgEl.style.display = "block"; } else { imgEl.src = ""; imgEl.style.display = "none"; } } if (typeof setDetailModalFullscreen === "function") { setDetailModalFullscreen(false); } const modal = document.getElementById("detailModal"); if (modal) modal.style.display = "flex"; } global.InstanceUI = { escapeHtml: escapeHtml, pnlClassFromValue: pnlClassFromValue, formatPnlSpan: formatPnlSpan, buildJournalDetailHtml: buildJournalDetailHtml, setJournalDetailBody: setJournalDetailBody, openJournalDetailModal: openJournalDetailModal, }; })(typeof window !== "undefined" ? window : globalThis);