index.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // 全局 Loading 控制器
  2. window.GlobalLoading = (function() {
  3. let overlay = null;
  4. let loadingText = null;
  5. function init() {
  6. overlay = document.getElementById('globalLoadingOverlay');
  7. loadingText = overlay ? overlay.querySelector('.global-loading-text') : null;
  8. }
  9. function show(text = '正在处理...') {
  10. // console.log('[GlobalLoading] show() 被调用');
  11. // console.log('[GlobalLoading] 文本:', text);
  12. if (!overlay) {
  13. // console.log('[GlobalLoading] → 初始化overlay元素...');
  14. init();
  15. }
  16. if (!overlay) {
  17. // console.error('[GlobalLoading] ✗ overlay元素未找到!');
  18. return;
  19. }
  20. // console.log('[GlobalLoading] ✓ overlay元素存在');
  21. if (loadingText) {
  22. loadingText.textContent = text;
  23. // console.log('[GlobalLoading] ✓ 设置Loading文本:', text);
  24. }
  25. overlay.classList.add('is-visible');
  26. // console.log('[GlobalLoading] ✓ 添加is-visible类,Loading应该可见了');
  27. }
  28. function hide() {
  29. // console.log('[GlobalLoading] hide() 被调用');
  30. if (!overlay) {
  31. // console.error('[GlobalLoading] ✗ overlay元素不存在');
  32. return;
  33. }
  34. overlay.classList.remove('is-visible');
  35. // console.log('[GlobalLoading] ✓ 移除is-visible类,Loading已隐藏');
  36. }
  37. return {
  38. show,
  39. hide
  40. };
  41. })();
  42. // 全局 Alert 控制器
  43. window.GlobalAlert = (function() {
  44. let alertContainer = null;
  45. let alertMessage = null;
  46. let hideTimer = null;
  47. function init() {
  48. alertContainer = document.getElementById('globalAlert');
  49. alertMessage = alertContainer ? alertContainer.querySelector('#alertMessage') : null;
  50. }
  51. function show(text, duration = 1500) {
  52. console.log('[GlobalAlert] show() 被调用:', { text, duration });
  53. if (!alertContainer) {
  54. console.log('[GlobalAlert] 初始化 alertContainer');
  55. init();
  56. }
  57. if (!alertContainer) {
  58. console.error('[GlobalAlert] alertContainer 未找到!');
  59. return;
  60. }
  61. if (!alertMessage) {
  62. console.error('[GlobalAlert] alertMessage 未找到!');
  63. return;
  64. }
  65. console.log('[GlobalAlert] 设置消息:', text);
  66. // 清除之前的自动隐藏定时器
  67. if (hideTimer) {
  68. clearTimeout(hideTimer);
  69. hideTimer = null;
  70. }
  71. alertMessage.textContent = text;
  72. alertContainer.classList.add('show');
  73. console.log('[GlobalAlert] 已添加 show 类,alert 应该可见了');
  74. // 自动隐藏
  75. if (duration > 0) {
  76. hideTimer = setTimeout(() => {
  77. hide();
  78. }, duration);
  79. }
  80. }
  81. function hide() {
  82. if (!alertContainer) return;
  83. alertContainer.classList.remove('show');
  84. if (hideTimer) {
  85. clearTimeout(hideTimer);
  86. hideTimer = null;
  87. }
  88. }
  89. return {
  90. show,
  91. hide
  92. };
  93. })();
  94. // 页面管理:负责切换 iframe 中的子页面,并保持与导航栏状态同步
  95. (function () {
  96. console.log('[Index] index.js 已加载');
  97. const DEFAULT_PAGE = "store";
  98. function getPageFrame() {
  99. return document.getElementById("pageFrame");
  100. }
  101. function getNavigationFrame() {
  102. return document.getElementById("navigationFrame");
  103. }
  104. function switchPage(page) {
  105. const frame = getPageFrame();
  106. if (!frame) {
  107. return;
  108. }
  109. // 只处理实际的页面切换,不处理login/register
  110. if (page === "login" || page === "register") {
  111. return;
  112. }
  113. switch (page) {
  114. case "store":
  115. frame.src = "page/store/store.html";
  116. break;
  117. case "assets":
  118. default:
  119. frame.src = "page/assets/assets.html";
  120. break;
  121. }
  122. // 同步导航栏状态
  123. syncNavigationState(page);
  124. }
  125. // 同步导航栏状态
  126. function syncNavigationState(page) {
  127. const navigationFrame = getNavigationFrame();
  128. if (navigationFrame && navigationFrame.contentWindow) {
  129. // 使用setTimeout确保iframe已加载
  130. setTimeout(() => {
  131. navigationFrame.contentWindow.postMessage(
  132. { type: "navigation", page },
  133. "*"
  134. );
  135. }, 100);
  136. }
  137. }
  138. window.addEventListener("message", (event) => {
  139. // 调试:记录所有收到的消息
  140. console.log('[Index] 收到message事件:', {
  141. origin: event.origin,
  142. expectedOrigin: window.location.origin,
  143. data: event.data,
  144. source: event.source,
  145. type: event.data?.type
  146. });
  147. // 检查 origin(允许同源或 localhost,或者来自 iframe)
  148. const isSameOrigin = event.origin === window.location.origin;
  149. const isLocalhost = event.origin === 'http://localhost:3000' ||
  150. event.origin === 'http://127.0.0.1:3000' ||
  151. event.origin.startsWith('http://localhost:') ||
  152. event.origin.startsWith('http://127.0.0.1:');
  153. // 允许来自同源的 iframe(即使 origin 不完全匹配)
  154. const isFromIframe = event.source && event.source !== window;
  155. console.log('[Index] Origin 检查:', {
  156. eventOrigin: event.origin,
  157. windowOrigin: window.location.origin,
  158. isSameOrigin,
  159. isLocalhost,
  160. isFromIframe,
  161. willPass: isSameOrigin || isLocalhost || isFromIframe
  162. });
  163. // 对于 global-alert 消息,放宽 origin 检查(允许来自任何同源 iframe)
  164. if (event.data && event.data.type === 'global-alert') {
  165. console.log('[Index] 这是 global-alert 消息,放宽 origin 检查');
  166. // 允许来自任何 iframe 的消息(只要 source 存在且不是 window 本身)
  167. if (isFromIframe || isSameOrigin || isLocalhost) {
  168. console.log('[Index] global-alert 消息通过检查');
  169. } else {
  170. console.warn('[Index] global-alert 消息被 origin 检查过滤:', event.origin);
  171. // 即使 origin 不匹配,也允许 global-alert 消息通过(因为来自同源 iframe)
  172. console.log('[Index] 但允许通过(来自 iframe)');
  173. }
  174. } else if (!isSameOrigin && !isLocalhost && !isFromIframe) {
  175. console.log('[Index] 消息被 origin 检查过滤:', event.origin);
  176. return;
  177. }
  178. console.log('[Index] 消息通过 origin 检查,继续处理');
  179. const { data } = event;
  180. if (data && data.type === "navigation" && (data.page === "login" || data.page === "register")) {
  181. // console.log('[2-Index] 收到login/register消息');
  182. const loginFrame = document.getElementById('loginViewFrame');
  183. if (loginFrame) {
  184. const mode = data.page === "register" ? "register" : "login";
  185. loginFrame.style.display = 'block';
  186. // console.log('[3-Index] iframe已显示');
  187. const sendMode = () => {
  188. if (loginFrame.contentWindow) {
  189. loginFrame.contentWindow.postMessage({
  190. type: 'open-login-view',
  191. mode: mode
  192. }, '*');
  193. // console.log('[4-Index] 消息已发送到login iframe');
  194. } else {
  195. setTimeout(sendMode, 100);
  196. }
  197. };
  198. sendMode();
  199. const handleLoad = () => {
  200. setTimeout(() => {
  201. sendMode();
  202. }, 50);
  203. };
  204. if (loginFrame.contentDocument && loginFrame.contentDocument.readyState === 'complete') {
  205. handleLoad();
  206. } else {
  207. loginFrame.addEventListener('load', handleLoad, { once: true });
  208. }
  209. }
  210. } else if (data && data.type === "navigation" && data.page) {
  211. switchPage(data.page);
  212. }
  213. else if (data && data.type === "close-login-view") {
  214. const loginFrame = document.getElementById('loginViewFrame');
  215. if (loginFrame) {
  216. loginFrame.style.display = 'none';
  217. }
  218. } else if (data && data.type === "login-success" && data.user) {
  219. // 处理登录成功消息,转发给 navigation iframe 和 pageFrame
  220. const navigationFrame = getNavigationFrame();
  221. if (navigationFrame && navigationFrame.contentWindow) {
  222. navigationFrame.contentWindow.postMessage({
  223. type: 'login-success',
  224. user: data.user
  225. }, '*');
  226. }
  227. // 也转发给 pageFrame(store 页面)
  228. const pageFrame = getPageFrame();
  229. if (pageFrame && pageFrame.contentWindow) {
  230. pageFrame.contentWindow.postMessage({
  231. type: 'login-success',
  232. user: data.user
  233. }, '*');
  234. }
  235. // 转发给 assets iframe(如果存在),它会再转发给 disk iframe
  236. const assetsFrame = document.getElementById('assetsFrame');
  237. if (assetsFrame && assetsFrame.contentWindow) {
  238. assetsFrame.contentWindow.postMessage({
  239. type: 'login-success',
  240. user: data.user
  241. }, '*');
  242. }
  243. } else if (data && data.type === "logout") {
  244. // 处理登出消息,转发给所有 iframe
  245. const navigationFrame = getNavigationFrame();
  246. if (navigationFrame && navigationFrame.contentWindow) {
  247. navigationFrame.contentWindow.postMessage({
  248. type: 'logout'
  249. }, '*');
  250. }
  251. const pageFrame = getPageFrame();
  252. if (pageFrame && pageFrame.contentWindow) {
  253. pageFrame.contentWindow.postMessage({
  254. type: 'logout'
  255. }, '*');
  256. }
  257. }
  258. });
  259. window.addEventListener("DOMContentLoaded", () => {
  260. switchPage(DEFAULT_PAGE);
  261. syncNavigationState(DEFAULT_PAGE);
  262. });
  263. })();