feat: integrate bricks.Router into shell
- shell_theme.js: call bricks.Router.init() with sage_main_content target - Remove standalone spa_router.js (now built into bricks) - Remove spa_router.js from load_path.py RBAC
This commit is contained in:
parent
0032e364b1
commit
61a1b2b2fa
@ -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"),
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(); }
|
||||
};
|
||||
|
||||
})();
|
||||
Loading…
x
Reference in New Issue
Block a user