/** * 中控 iframe 壳:顶栏/统计常驻,tab 内容走 /api/embed/page/。 */ (function (global) { const TAB_PATH = { key_monitor: "/key_monitor", trade: "/trade", strategy: "/strategy", strategy_records: "/strategy/records", records: "/records", stats: "/stats", }; let navToken = 0; let loadingTab = false; function isEmbedShell() { return document.body && document.body.getAttribute("data-embed-shell") === "1"; } function getTab() { try { const t = new URLSearchParams(location.search).get("tab"); if (t) return t; } catch (_) {} return document.body.getAttribute("data-page") || "trade"; } function listWindowQueryString() { if (typeof global.listWindowQueryString === "function") { return global.listWindowQueryString(); } return ""; } function setRootLoading(on) { const root = document.getElementById("embed-page-root"); if (root) root.classList.toggle("is-embed-tab-loading", !!on); } function setNavActive(tab) { document.querySelectorAll(".embed-top-nav [data-embed-tab]").forEach((a) => { a.classList.toggle("active", a.getAttribute("data-embed-tab") === tab); }); } function syncUrl(tab, replace) { const q = new URLSearchParams(location.search); q.set("tab", tab); q.set("embed", "1"); const qs = q.toString(); const url = "/embed?" + qs; if (replace) history.replaceState({ embedTab: tab }, "", url); else history.pushState({ embedTab: tab }, "", url); } function runPageInit(tab) { document.body.setAttribute("data-page", tab); if (typeof global.attachListWindowToExports === "function") { global.attachListWindowToExports(); } if (tab === "trade") { if (typeof global.refreshOrderDefaults === "function") global.refreshOrderDefaults(); } if (tab === "key_monitor" && global.KeyMonitorForm && typeof global.KeyMonitorForm.init === "function") { global.KeyMonitorForm.init(); } if (tab === "records") { if (typeof global.loadJournals === "function") global.loadJournals(); if (typeof global.loadReviews === "function") global.loadReviews(); if (typeof global.toggleReviewMode === "function") global.toggleReviewMode(); } if (typeof global.refreshPriceSnapshotConditional === "function") { global.refreshPriceSnapshotConditional(); } } function injectFragment(html) { const root = document.getElementById("embed-page-root"); if (!root) return; root.innerHTML = html; root.querySelectorAll("script").forEach((old) => { const s = document.createElement("script"); if (old.src) s.src = old.src; else s.textContent = old.textContent; old.replaceWith(s); }); } async function loadTab(tab, opts) { const options = opts || {}; if (!tab || loadingTab) return; const token = ++navToken; loadingTab = true; setRootLoading(true); try { const qs = listWindowQueryString(); const url = "/api/embed/page/" + encodeURIComponent(tab) + (qs ? "?" + qs : ""); const r = await fetch(url, { credentials: "same-origin" }); if (token !== navToken) return; const j = await r.json(); if (!j.ok || !j.html) throw new Error(j.msg || "加载失败"); injectFragment(j.html); setNavActive(tab); if (!options.skipUrl) syncUrl(tab, !!options.replace); runPageInit(tab); } catch (e) { if (token === navToken) { const flash = document.getElementById("embed-flash"); if (flash) { flash.style.display = ""; flash.textContent = String(e && e.message ? e.message : e); } } } finally { if (token === navToken) { loadingTab = false; setRootLoading(false); } } } function reloadCurrentTab() { return loadTab(getTab(), { replace: true, skipUrl: true }); } function patchApplyListWindow() { if (typeof global.applyListWindow !== "function") return; global.applyListWindow = function embedApplyListWindow() { void loadTab(getTab(), { replace: true }); }; } function patchHardNavigations() { const resubmitPaths = /^\/(del_|delete_|add_|stop_|strategy\/|trend_|roll_|cancel_|place_)/; document.addEventListener( "click", (ev) => { if (!isEmbedShell()) return; const a = ev.target.closest("a[href]"); if (!a || ev.defaultPrevented) return; if (a.closest(".embed-top-nav")) return; if (a.hasAttribute("download") || a.target === "_blank") return; const raw = a.getAttribute("href"); if (!raw || raw.startsWith("#") || raw.startsWith("javascript:")) return; let url; try { url = new URL(raw, location.href); } catch (_) { return; } if (url.origin !== location.origin) return; if (url.pathname.startsWith("/export/") || url.pathname.startsWith("/order_focus") || url.pathname.startsWith("/key_focus")) { return; } if (!resubmitPaths.test(url.pathname)) return; ev.preventDefault(); fetch(url.pathname + url.search, { credentials: "same-origin", redirect: "manual" }) .then(() => reloadCurrentTab()) .catch(() => reloadCurrentTab()); }, false ); document.addEventListener( "submit", (ev) => { if (!isEmbedShell()) return; const form = ev.target; if (!(form instanceof HTMLFormElement)) return; if (form.method && form.method.toUpperCase() === "GET") return; ev.preventDefault(); const fd = new FormData(form); fetch(form.action, { method: form.method || "POST", body: fd, credentials: "same-origin", redirect: "manual", }) .then(() => reloadCurrentTab()) .catch(() => reloadCurrentTab()); }, true ); } function bindNav() { document.querySelectorAll(".embed-top-nav [data-embed-tab]").forEach((a) => { a.addEventListener("click", (ev) => { ev.preventDefault(); const tab = a.getAttribute("data-embed-tab"); if (!tab || tab === getTab()) return; void loadTab(tab); }); }); window.addEventListener("popstate", () => { const tab = getTab(); void loadTab(tab, { replace: true, skipUrl: true }); }); } function boot() { if (!isEmbedShell()) return; patchApplyListWindow(); patchHardNavigations(); bindNav(); runPageInit(getTab()); try { window.parent.postMessage({ type: "instance-frame-ready" }, "*"); } catch (_) {} } global.InstanceEmbed = { loadTab, reloadCurrentTab, getTab, }; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", boot); } else { boot(); } })(typeof window !== "undefined" ? window : globalThis);