diff --git a/app/static/portal/common/layout/app-shell.js b/app/static/portal/common/layout/app-shell.js index 1e4b31d..51d9677 100644 --- a/app/static/portal/common/layout/app-shell.js +++ b/app/static/portal/common/layout/app-shell.js @@ -73,6 +73,17 @@ function footerMarkup() { } export function mountShell({ active, mode = 'public' }) { + // ⚠️ 幂等保护:同一个页面被挂两次 shell,就会看到**两份一模一样的顶部导航与页脚**。 + // + // 已知的触发方式只有一种:HTML 里引了两条入口 + diff --git a/tests/unit/api/test_portal_frontend.py b/tests/unit/api/test_portal_frontend.py index b80bb8c..b4d8259 100644 --- a/tests/unit/api/test_portal_frontend.py +++ b/tests/unit/api/test_portal_frontend.py @@ -1,5 +1,6 @@ from __future__ import annotations +import re import subprocess import sys from pathlib import Path @@ -129,6 +130,39 @@ def test_advisor_dashboard_is_composed_from_feature_modules() -> None: assert "ACTION_LABELS" in config +def test_no_portal_page_includes_the_same_script_twice() -> None: + """同一个入口 JS 被引两次(哪怕 `?v=` 不同)会让页面出现两份顶部导航。 + + 浏览器按**完整 URL** 去重:`x.js?v=A` 与 `x.js?v=B` 是两个模块、**各执行一次**。 + 入口里的 `mountShell()` 于是跑两遍,插入两份 header / footer —— + 2026-09-14 `employee-console/workspace/index.html` 就这么写过:合并时 + 两个分支各自把同一行的版本号换成新的,两边都被保留,成了一条重复的 `