From a244850b2587d8038df31c19c4e00e1f29fa43d6 Mon Sep 17 00:00:00 2001 From: dekun Date: Sat, 18 Jul 2026 15:23:48 +0800 Subject: [PATCH] Fix journal AJAX save in embed so trades stay loaded. Delegate submit handling for late-mounted #journal-form across OKX/Binance/Gate, avoid full reload fallback, and soft-refresh trade rows after save. Co-authored-by: Cursor --- lib/common/static/instance_embed.js | 3 + lib/common/static/journal_form_save.js | 151 ++++++++++++++--------- lib/common/static/records_review_page.js | 3 + lib/instance/templates/embed_shell.html | 6 +- lib/instance/templates/index.html | 4 +- 5 files changed, 102 insertions(+), 65 deletions(-) diff --git a/lib/common/static/instance_embed.js b/lib/common/static/instance_embed.js index cc3bef0..7253dfa 100644 --- a/lib/common/static/instance_embed.js +++ b/lib/common/static/instance_embed.js @@ -155,6 +155,9 @@ const root = pageRoot() || document; global.JournalUploadSlots.init(root); } + if (global.JournalFormSave && typeof global.JournalFormSave.init === "function") { + global.JournalFormSave.init(); + } } } diff --git a/lib/common/static/journal_form_save.js b/lib/common/static/journal_form_save.js index 822ec09..873aade 100644 --- a/lib/common/static/journal_form_save.js +++ b/lib/common/static/journal_form_save.js @@ -1,5 +1,6 @@ /** * 复盘表单 AJAX 保存:避免整页刷新卡顿;配合 FormSubmitGuard 即时反馈. + * 使用 document 委托,兼容中控 embed 后插入的 #journal-form. */ (function (global) { "use strict"; @@ -22,13 +23,23 @@ } function refreshLists() { - if (typeof global.loadJournals === "function") { + if (global.RecordsReviewPage && typeof RecordsReviewPage.loadJournals === "function") { + try { + RecordsReviewPage.loadJournals(); + } catch (_) {} + } else if (typeof global.loadJournals === "function") { try { global.loadJournals(); } catch (_) {} - } else if (global.RecordsReviewPage && typeof RecordsReviewPage.loadJournals === "function") { + } + // 交易记录保持可见:soft 刷新,勿「加载中…」占位 + if (global.RecordsReviewPage && typeof RecordsReviewPage.loadTradeRecords === "function") { try { - RecordsReviewPage.loadJournals(); + RecordsReviewPage.loadTradeRecords({ soft: true }); + } catch (_) {} + } else if (typeof global.loadTradeRecords === "function") { + try { + global.loadTradeRecords({ soft: true }); } catch (_) {} } } @@ -63,72 +74,92 @@ resetJournalForm(form); refreshLists(); if (data && data.chart_pending) { - // K 线后台生成,数秒后再刷一次列表拿缩略图 setTimeout(refreshLists, 4000); setTimeout(refreshLists, 12000); } } - function bind(form) { - if (!form || form.dataset.journalAjaxBound === "1") return; - form.dataset.journalAjaxBound = "1"; - form.addEventListener("submit", function (ev) { - if (typeof global.validateJournalEntryReason === "function") { - if (!global.validateJournalEntryReason()) { - ev.preventDefault(); - return; - } - } - ev.preventDefault(); - if (global.FormSubmitGuard && FormSubmitGuard.isLocked(form)) return; - if (global.FormSubmitGuard) FormSubmitGuard.lock(form, "保存中…"); - - var fd = new FormData(form); - fd.set("ajax", "1"); - var action = form.getAttribute("action") || "/add_journal"; - - fetch(action, { - method: "POST", - body: fd, - credentials: "same-origin", - headers: { - "X-Requested-With": "XMLHttpRequest", - Accept: "application/json", - }, - }) - .then(function (res) { - var ct = (res.headers.get("content-type") || "").toLowerCase(); - if (ct.indexOf("application/json") >= 0) { - return res.json().then(function (data) { - return { ok: res.ok, data: data, redirected: false }; - }); - } - // 旧后端未返回 JSON 时走整页逻辑 - if (res.redirected || res.ok) { - global.location.reload(); - return { ok: true, data: null, redirected: true }; - } - throw new Error("save failed"); - }) - .then(function (result) { - if (result.redirected) return; - if (!result.ok || !result.data || result.data.ok === false) { - var err = - (result.data && (result.data.msg || result.data.error)) || "保存失败"; - throw new Error(err); - } - onSuccess(form, result.data); - }) - .catch(function (err) { - toast((err && err.message) || "保存失败,请稍后重试"); - }) - .finally(function () { - if (global.FormSubmitGuard) FormSubmitGuard.unlock(form); - }); + function parseJsonSafe(res) { + var ct = (res.headers.get("content-type") || "").toLowerCase(); + if (ct.indexOf("application/json") >= 0) { + return res.json().then(function (data) { + return { kind: "json", ok: res.ok, data: data }; + }); + } + return res.text().then(function (text) { + return { kind: "html", ok: res.ok, redirected: !!res.redirected, text: text }; }); } + function submitAjax(form) { + if (global.FormSubmitGuard && FormSubmitGuard.isLocked(form)) return; + if (global.FormSubmitGuard) FormSubmitGuard.lock(form, "保存中…"); + + var fd = new FormData(form); + fd.set("ajax", "1"); + var action = form.getAttribute("action") || "/add_journal"; + + fetch(action, { + method: "POST", + body: fd, + credentials: "same-origin", + redirect: "manual", + headers: { + "X-Requested-With": "XMLHttpRequest", + Accept: "application/json", + }, + }) + .then(function (res) { + // opaque redirect:后端未认 AJAX,仍走了 302 + if (res.type === "opaqueredirect" || (res.status >= 300 && res.status < 400)) { + throw new Error("保存接口未返回 JSON,请硬刷新页面后重试"); + } + return parseJsonSafe(res); + }) + .then(function (result) { + if (result.kind !== "json") { + throw new Error("保存接口未返回 JSON,请硬刷新页面后重试"); + } + if (!result.ok || !result.data || result.data.ok === false) { + var err = + (result.data && (result.data.msg || result.data.error)) || "保存失败"; + throw new Error(err); + } + onSuccess(form, result.data); + }) + .catch(function (err) { + toast((err && err.message) || "保存失败,请稍后重试"); + }) + .finally(function () { + if (global.FormSubmitGuard) FormSubmitGuard.unlock(form); + }); + } + + function onSubmit(ev) { + var form = ev.target; + if (!form || form.id !== "journal-form") return; + if (typeof global.validateJournalEntryReason === "function") { + if (!global.validateJournalEntryReason()) { + ev.preventDefault(); + return; + } + } + ev.preventDefault(); + submitAjax(form); + } + + function bind(form) { + // 保留显式 bind 入口(embed 切 tab 时可再调);真正拦截靠 document 委托 + if (form) form.dataset.journalAjaxBound = "1"; + } + function init() { + if (document.documentElement.dataset.journalFormSaveDelegated === "1") { + bind($("journal-form")); + return; + } + document.documentElement.dataset.journalFormSaveDelegated = "1"; + document.addEventListener("submit", onSubmit, true); bind($("journal-form")); } diff --git a/lib/common/static/records_review_page.js b/lib/common/static/records_review_page.js index d4f7a13..76e8e36 100644 --- a/lib/common/static/records_review_page.js +++ b/lib/common/static/records_review_page.js @@ -589,6 +589,9 @@ updatePager("trades"); updatePager("journals"); updatePager("reviews"); + if (global.JournalFormSave && typeof global.JournalFormSave.init === "function") { + global.JournalFormSave.init(); + } loadTradeRecords({ soft: false }); loadJournalsPaged(); loadReviewsPaged(); diff --git a/lib/instance/templates/embed_shell.html b/lib/instance/templates/embed_shell.html index c0c2152..2deea46 100644 --- a/lib/instance/templates/embed_shell.html +++ b/lib/instance/templates/embed_shell.html @@ -97,7 +97,7 @@ - + {% include 'embed_boot_scripts.html' %} - + - + diff --git a/lib/instance/templates/index.html b/lib/instance/templates/index.html index f2e1b47..2750fe7 100644 --- a/lib/instance/templates/index.html +++ b/lib/instance/templates/index.html @@ -456,7 +456,7 @@ - + - +