From 9728fa40fe670d79a69d1336be02f5945bb84c04 Mon Sep 17 00:00:00 2001 From: bot_dev1 Date: Thu, 6 Aug 2026 11:37:40 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E3=80=8C=E7=94=A8=E6=88=B7=E4=B8=8E?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E3=80=8D=E6=A8=A1=E5=9D=97=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E5=88=B0=20FBA=20UI=20=E6=89=BF=E8=BD=BD=EF=BC=88Epic=20#159?= =?UTF-8?q?=20=E9=81=97=E6=BC=8F=E6=94=B6=E5=B0=BE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/auth/users.html | 14 ++++++++++++++ web/shared/pro-header.js | 11 ++++++++--- web/shared/session.js | 16 +++++++++++++--- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/web/auth/users.html b/web/auth/users.html index f7c306e..2cf5fe2 100644 --- a/web/auth/users.html +++ b/web/auth/users.html @@ -102,6 +102,20 @@ + diff --git a/web/shared/pro-header.js b/web/shared/pro-header.js index 356d14d..32c2916 100644 --- a/web/shared/pro-header.js +++ b/web/shared/pro-header.js @@ -182,14 +182,18 @@ } /* ---- 菜单渲染(需要登录角色,异步) ----------------------------------- */ - function addLeafItem(key, icon, text, href) { + function addLeafItem(key, icon, text, href, external) { var a = el("a", "pro-menu-item" + (key === active ? " active" : "")); a.href = href; a.title = text; a.setAttribute("data-module", key); a.appendChild(el("span", "pro-menu-icon", icon)); a.appendChild(el("span", "pro-menu-text", text)); - if (SHELL) { + if (external) { + // 外部承载模块(FBA UI 等):新标签打开,不进 iframe 外壳 + a.target = "_blank"; + a.rel = "noopener"; + } else if (SHELL) { a.addEventListener("click", function (e) { e.preventDefault(); go(href); @@ -250,7 +254,8 @@ // 输出(FBA 服务端按角色授权过滤,本地角色过滤兜底) (mods || []).forEach(function (m) { if (m.children && m.children.length) addSubMenu(m); - else addLeafItem(m.key, m.icon, m.title, prefix + m.url); + else addLeafItem(m.key, m.icon, m.title, + m.external ? m.url : prefix + m.url, !!m.external); }); if (!SHELL) syncSubHighlight(); // 菜单(重)渲染完成事件:shell.js 据此重放当前高亮, diff --git a/web/shared/session.js b/web/shared/session.js index c8f8680..27756c6 100644 --- a/web/shared/session.js +++ b/web/shared/session.js @@ -62,8 +62,11 @@ var IAOP_SESSION = (function () { { key: "audit", title: "审计查询", hash: "#audit" } ] }, { key: "users", title: "用户与角色", icon: "👤", url: "auth/users.html", - desc: "用户管理、角色分配(readonly / engineer / admin)、审计(PRD 8.2)", - roles: ["admin"], tag: "管理员", tagColor: "gold" }, + desc: "用户管理、角色分配、菜单授权(Epic #159 起由 FBA UI 承载)", + roles: ["admin"], tag: "管理员", tagColor: "gold", + /* FBA 模式下该模块由 FBA UI(/fba-admin/)承载,新标签打开; + * fbaUrl 由 menuTree() 在 FBA 轨道生效时注入 */ + fbaUrl: "/fba-admin/" }, { key: "mobile", title: "移动端驾驶舱", icon: "📱", url: "mobile/", desc: "移动端只读驾驶舱与交接班摘要(iOS14+ / Android 10+)", roles: ["readonly", "engineer", "admin"], tag: "移动端", tagColor: "default" } @@ -441,7 +444,14 @@ var IAOP_SESSION = (function () { return copy; }); // 服务端树里没有任何 iAOP 模块(未播种)→ 本地角色过滤兜底 - return mods.length ? mods : modulesFor(user.role); + if (!mods.length) return modulesFor(user.role); + // FBA 轨道生效:带 fbaUrl 的模块(用户与角色)指向 FBA UI,新标签打开 + return mods.map(function (m) { + if (m.fbaUrl) { + return Object.assign({}, m, { url: m.fbaUrl, external: true }); + } + return m; + }); }) .catch(function () { return modulesFor(user.role); }); }