Compare commits
2
Commits
8409a2c96e
...
3df6671ce3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3df6671ce3 | ||
|
|
e6d74059f2 |
@@ -73,6 +73,17 @@ function footerMarkup() {
|
||||
}
|
||||
|
||||
export function mountShell({ active, mode = 'public' }) {
|
||||
// ⚠️ 幂等保护:同一个页面被挂两次 shell,就会看到**两份一模一样的顶部导航与页脚**。
|
||||
//
|
||||
// 已知的触发方式只有一种:HTML 里引了两条入口 <script type="module">,且 `?v=` 不同。
|
||||
// 浏览器按**完整 URL** 去重,两条会被当成两个模块、**各执行一次** ——
|
||||
// 2026-09-14 的 `employee-console/workspace/index.html` 正是如此
|
||||
// (合并时把两个分支各自改的版本号都保留下来,成了两行)。
|
||||
//
|
||||
// 那次已经把那两行收敛成一行;这里再挡一道,理由是这个错误**从症状上很难联想到原因**
|
||||
// (页面看起来只是"多了一块"),而且以后别人加缓存版本号时很容易再犯一次。
|
||||
if (document.querySelector('.site-header')) return;
|
||||
|
||||
startAuthSync();
|
||||
document.body.classList.add(`portal-${mode}`);
|
||||
const context = getAuthContext();
|
||||
|
||||
@@ -45,7 +45,11 @@
|
||||
</main>
|
||||
<dialog class="operations-dialog" data-admin-detail><div class="operations-dialog__header"><h2 data-detail-title>详情</h2><button class="button icon-button" type="button" data-close-detail aria-label="关闭">×</button></div><div class="operations-dialog__body" data-detail-body></div><div class="operations-dialog__footer"><button class="button" type="button" data-close-detail>关闭</button></div></dialog>
|
||||
<dialog class="operations-dialog" data-admin-action><form data-admin-action-form><div class="operations-dialog__header"><h2 data-admin-action-title>确认操作</h2><button class="button icon-button" type="button" data-close-admin-action aria-label="关闭">×</button></div><div class="operations-dialog__body"><p class="admin-action-copy" data-admin-action-copy></p><label class="form-field" data-admin-comment-field hidden><span class="form-field__label">审核意见</span><textarea class="form-field__input admin-comment" name="comment" maxlength="1000"></textarea></label><div class="form-alert" data-admin-action-alert></div></div><div class="operations-dialog__footer"><button class="button" type="button" data-close-admin-action>取消</button><button class="button button--primary" type="submit">确认提交</button></div></form></dialog>
|
||||
<script type="module" src="/static/portal/employee-console/workspace/workspace.js?v=20260913-3"></script>
|
||||
<!-- ⚠️ 入口 JS 只能引一次。这里曾经同时引了两条,且 `?v=` 不同
|
||||
(20260913-3 与 20260914 —— 合并时两个分支各自改了版本号,都被保留下来):
|
||||
浏览器按**完整 URL** 去重,两条不同 query 会被当成两个模块、**各执行一次**,
|
||||
于是入口里的 `mountShell()` 跑两遍,页面上出现**两份顶部导航与页脚**。
|
||||
改版本号时是**替换**这一行,不是新增一行。 -->
|
||||
<script type="module" src="/static/portal/employee-console/workspace/workspace.js?v=20260914"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -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` 就这么写过:合并时
|
||||
两个分支各自把同一行的版本号换成新的,两边都被保留,成了一条重复的 `<script>`。
|
||||
"""
|
||||
pattern = re.compile(r"<script[^>]*\ssrc=[\"']([^\"']+)[\"']", re.IGNORECASE)
|
||||
duplicated: list[str] = []
|
||||
for page in sorted(PORTAL.rglob("*.html")):
|
||||
# 只比 `<script>`;站内绝对路径去掉 query 再归并
|
||||
sources = [
|
||||
url.split("?", 1)[0] if url.startswith("/") else url
|
||||
for url in pattern.findall(page.read_text(encoding="utf-8"))
|
||||
]
|
||||
repeated = sorted({src for src in sources if sources.count(src) > 1})
|
||||
if repeated:
|
||||
duplicated.append(f"{page.relative_to(PORTAL)}: {repeated}")
|
||||
assert not duplicated, f"同一入口脚本被引入多次:{duplicated}"
|
||||
|
||||
|
||||
def test_mount_shell_is_idempotent() -> None:
|
||||
"""`mountShell` 要自带「已经挂过就不再挂」的保护。
|
||||
|
||||
上一条测试守住 HTML,这一条守住代码 —— 两侧都挡一道,
|
||||
因为这个 bug 的症状很难反推原因(页面看起来只是"多了一块"),
|
||||
而以后加缓存版本号时很容易再犯。
|
||||
"""
|
||||
source = (PORTAL / "common" / "layout" / "app-shell.js").read_text(encoding="utf-8")
|
||||
assert "if (document.querySelector('.site-header')) return;" in source
|
||||
|
||||
|
||||
def test_portal_feature_modules_have_consistent_imports() -> None:
|
||||
"""拆分前端模块时最容易漏 import:定义搬走了,使用处却留在原文件。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user