From 557dab3cafc74224fd77a8fe0a3ff4c6b50562db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Wed, 30 Sep 2026 12:21:31 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=8C=82=E4=BB=B6=E9=9D=A2=E6=9D=BF?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E8=81=94=E5=8A=A8=E2=80=94=E2=80=94bottom-le?= =?UTF-8?q?ft=E6=BA=A2=E5=87=BA=E5=B1=8F=E5=B9=95/top=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E5=90=91=E4=B8=8A=E6=BA=A2=E5=87=BA(=E7=BA=BF=E4=B8=8A?= =?UTF-8?q?=E5=AE=9E=E6=B5=8Bx=3D-183.78=E6=A0=B9=E5=9B=A0:=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E7=A1=AC=E7=BC=96=E7=A0=81right:0=E6=9C=AA=E9=9A=8Fpo?= =?UTF-8?q?sition=E7=BF=BB=E8=BD=AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 容器挂pos-类+CSS联动规则,无效position归一化;静态测试锁定。 Co-Authored-By: Claude Code --- static/widget.js | 10 +++++++++- tests/test_invite_static.py | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/static/widget.js b/static/widget.js index 6d60dc9..773a209 100644 --- a/static/widget.js +++ b/static/widget.js @@ -138,6 +138,9 @@ }; var c = colors[theme] || colors.light; + // 无效 position 归一化(防 "pos-垃圾" class 与查表错位) + if (!positionStyles[position]) position = "bottom-right"; + var pos = (isMobile ? positionStylesMobile : positionStyles)[position] || (isMobile ? positionStylesMobile : positionStyles)["bottom-right"]; @@ -176,6 +179,11 @@ // Chat panel ".chat-panel { position:absolute; bottom:80px; right:0; width:400px; height:540px; background:" + c.bg + "; border-radius:16px; box-shadow:0 10px 40px rgba(0,0,0,0.15); display:none; flex-direction:column; overflow:hidden; }", ".chat-panel.open { display:flex; }", + // 位置联动(2026-09-30 修复): 面板对齐随 data-position 翻转,默认 right:0 + // 只适配 bottom-right——左侧模式溢出屏幕、顶部模式向上溢出 + ".widget-container.pos-bottom-left .chat-panel { left:0; right:auto; }", + ".widget-container.pos-top-right .chat-panel { top:0; bottom:auto; }", + ".widget-container.pos-top-left .chat-panel { left:0; right:auto; top:0; bottom:auto; }", // Panel header ".panel-header { display:flex; align-items:center; gap:12px; padding:14px 18px; background:var(--w-primary); color:white; }", @@ -286,7 +294,7 @@ // Build DOM var container = document.createElement("div"); - container.className = "widget-container" + (isMobile ? " mobile-host" : ""); + container.className = "widget-container pos-" + position + (isMobile ? " mobile-host" : ""); var panel = document.createElement("div"); panel.className = "chat-panel"; diff --git a/tests/test_invite_static.py b/tests/test_invite_static.py index a4af56b..c68be57 100644 --- a/tests/test_invite_static.py +++ b/tests/test_invite_static.py @@ -78,3 +78,24 @@ def test_gdpr_privacy_notice_present(): assert 'target="_blank" rel="noopener"' in wjs chat = _read("chat.html") assert "privacy policy" in chat and "privacy-policy/" in chat + + +def test_position_class_panel_alignment(): + """位置联动(2026-09-30 线上bug): 面板对齐必须随 data-position 翻转。 + 根因: .chat-panel 硬编码 right:0(为 bottom-right 设计), positionStyles + 只应用到按钮容器——bottom-left 时 400px 面板右缘贴 196px 容器右缘, + 向左溢出屏幕 184px(线上实测 x=-183.78); top-* 模式面板 bottom:80px + 同理向上溢出。修法: 容器挂 pos- class + CSS 联动规则。""" + src = _read("widget.js") + # 1) 无效 position 归一化(防 "pos-垃圾" class 与查表错位) + assert "if (!positionStyles[position])" in src, "position 需归一化为合法值" + # 2) 容器挂载位置 class + assert '"widget-container pos-" + position' in src, "container 需挂 pos- class" + # 3) CSS 联动规则: 左侧模式面板左对齐, 顶部模式面板从顶部向下弹 + assert ".widget-container.pos-bottom-left .chat-panel { left:0; right:auto; }" in src + assert ".widget-container.pos-top-right .chat-panel { top:0; bottom:auto; }" in src + assert ".widget-container.pos-top-left .chat-panel { left:0; right:auto; top:0; bottom:auto; }" in src + # 4) pos 规则须在 mobile-host 规则之后注入(同特异性靠顺序决胜, 不得被 bottom:84px 覆盖打断) + mobile_rule = ".widget-container.mobile-host .chat-panel { bottom:84px; }" + pos_rule = ".widget-container.pos-bottom-left .chat-panel" + assert src.index(mobile_rule) < src.index(pos_rule), "pos 规则须在 mobile 规则之后"