diff --git a/scripts/load_path.py b/scripts/load_path.py index 1c10377..1d71437 100644 --- a/scripts/load_path.py +++ b/scripts/load_path.py @@ -35,7 +35,6 @@ paths = [ ("/dashboard_for_sage/shell.ui", "logined"), ("/dashboard_for_sage/shell_theme.css", "any"), ("/dashboard_for_sage/shell_theme.js", "any"), - ("/dashboard_for_sage/spa_router.js", "any"), # Global menu ("/dashboard_for_sage/global_menu.ui", "logined"), diff --git a/wwwroot/shell_theme.js b/wwwroot/shell_theme.js index 3116075..a921acd 100644 --- a/wwwroot/shell_theme.js +++ b/wwwroot/shell_theme.js @@ -67,15 +67,30 @@ } } + // Initialize SPA Router + function initRouter() { + if (typeof bricks === 'undefined' || !bricks.Router) { + console.log('[Shell] Router not available'); + return; + } + bricks.Router.init({ + targets: [ + { id: 'sage_main_content', param: 'page' } + ] + }); + } + // Run on DOM ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { initTheme(); initSidebar(); + initRouter(); }); } else { initTheme(); initSidebar(); + initRouter(); } // Expose global functions for bricks bind access diff --git a/wwwroot/spa_router.js b/wwwroot/spa_router.js deleted file mode 100644 index 70b84b1..0000000 --- a/wwwroot/spa_router.js +++ /dev/null @@ -1,223 +0,0 @@ -/** - * Bricks SPA Router - * - * 为bricks单页应用提供路由支持: - * 1. urlwidget加载内容到sage_main_content时更新浏览器URL - * 2. 浏览器刷新时根据URL恢复当前页面 - * 3. 支持浏览器前进/后退按钮 - * 4. 支持直接URL访问(深链接) - * - * URL格式: /?page=/module/index.ui - * - * 工作原理: - * - 拦截bricks.buildUrlwidgetHandler,当target是sage_main_content时记录路由 - * - 使用History API (pushState/replaceState)更新URL - * - 监听popstate事件处理前进/后退 - * - 页面加载时检查URL参数并恢复状态 - */ - -(function() { - 'use strict'; - - // 路由配置 - var ROUTE_PARAM = 'page'; - var MAIN_CONTENT_ID = 'sage_main_content'; - - // 路由状态 - var currentRoute = null; - var isPopState = false; - var routerReady = false; - - // ── URL 操作 ── - - function getRouteFromURL() { - var params = new URLSearchParams(window.location.search); - return params.get(ROUTE_PARAM) || null; - } - - function pushRoute(route) { - var url = new URL(window.location); - url.searchParams.set(ROUTE_PARAM, route); - history.pushState({ route: route }, '', url.toString()); - currentRoute = route; - } - - function replaceRoute(route) { - var url = new URL(window.location); - if (route) { - url.searchParams.set(ROUTE_PARAM, route); - } else { - url.searchParams.delete(ROUTE_PARAM); - } - history.replaceState({ route: route }, '', url.toString()); - currentRoute = route; - } - - // ── 路由加载 ── - - function waitForApp(maxWait) { - return new Promise(function(resolve) { - if (bricks && bricks.app) { - resolve(true); - return; - } - var waited = 0; - var interval = setInterval(function() { - waited += 100; - if ((bricks && bricks.app) || waited >= maxWait) { - clearInterval(interval); - resolve(!!(bricks && bricks.app)); - } - }, 100); - }); - } - - function getMainContent() { - if (!bricks || !bricks.app) return null; - return bricks.getWidgetById(MAIN_CONTENT_ID, bricks.app); - } - - /** - * 程序化加载路由:构建urlwidget并放入sage_main_content - */ - async function loadRoute(route, pushHistory) { - if (!route) return; - - var ready = await waitForApp(5000); - if (!ready) { - console.error('[SPA Router] bricks.app not ready'); - return; - } - - var mainContent = getMainContent(); - if (!mainContent) { - console.error('[SPA Router] #' + MAIN_CONTENT_ID + ' not found'); - return; - } - - // 避免重复加载 - if (currentRoute === route && !isPopState) return; - - console.log('[SPA Router] Loading:', route); - - var desc = { - widgettype: 'urlwidget', - options: { url: route } - }; - - try { - var widget = await bricks.widgetBuild(desc, bricks.app); - if (widget && !(widget instanceof bricks.Popup) && !(widget instanceof bricks.NewWindow)) { - mainContent.clear_widgets(); - mainContent.add_widget(widget); - currentRoute = route; - - if (pushHistory && !isPopState) { - pushRoute(route); - } - } - } catch (e) { - console.error('[SPA Router] Load failed:', route, e); - } - - isPopState = false; - } - - // ── 拦截 buildUrlwidgetHandler ── - - function installInterceptor() { - var _orig = bricks.buildUrlwidgetHandler; - - bricks.buildUrlwidgetHandler = function(w, target, rtdata, desc) { - var url = desc && desc.options ? desc.options.url : null; - var targetId = target ? target.id : null; - - // 只拦截目标是sage_main_content的urlwidget - if (targetId === MAIN_CONTENT_ID && url && routerReady) { - // 获取原始handler - var handler = _orig(w, target, rtdata, desc); - - if (typeof handler === 'function') { - // 包装:执行原始handler后更新URL - return async function() { - await handler(); - // 跳过已经是当前路由的情况 - if (currentRoute !== url && !isPopState) { - console.log('[SPA Router] Route changed:', url); - pushRoute(url); - } - }; - } - } - - return _orig(w, target, rtdata, desc); - }; - - console.log('[SPA Router] Interceptor installed'); - } - - // ── popstate 处理 ── - - function onPopState(event) { - var route = (event.state && event.state.route) || getRouteFromURL(); - console.log('[SPA Router] popstate →', route); - isPopState = true; - if (route) { - loadRoute(route, false); - } - } - - // ── 初始化 ── - - async function init() { - console.log('[SPA Router] Initializing...'); - - // 等bricks.js加载完 - if (typeof bricks === 'undefined') { - await waitForApp(10000); - } - - if (!bricks) { - console.error('[SPA Router] bricks not found, aborting'); - return; - } - - installInterceptor(); - window.addEventListener('popstate', onPopState); - - // 检查URL是否有初始路由 - var initialRoute = getRouteFromURL(); - - if (initialRoute) { - console.log('[SPA Router] Deep link:', initialRoute); - // 等shell加载完再恢复 - await waitForApp(5000); - await new Promise(function(r) { setTimeout(r, 300); }); - await loadRoute(initialRoute, false); - // 用replaceState标记初始状态 - replaceRoute(initialRoute); - } else { - // 记录初始状态 - replaceRoute(null); - } - - routerReady = true; - console.log('[SPA Router] Ready'); - } - - // 启动 - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', init); - } else { - init(); - } - - // 调试API - window.BricksRouter = { - loadRoute: function(route) { return loadRoute(route, true); }, - current: function() { return currentRoute; }, - back: function() { history.back(); }, - forward: function() { history.forward(); } - }; - -})();