From 0ccbaa3a3527d50ab5bb0457467a889f7b55fe86 Mon Sep 17 00:00:00 2001 From: Gloridust Date: Sun, 14 Jun 2026 15:15:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=E5=AE=9E=E4=BE=8B=E3=80=8C?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E3=80=8D=E8=8F=9C=E5=8D=95=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E6=82=AC=E6=B5=AE=E5=9B=BE=E5=B1=82=E5=B1=95=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 绝对定位悬浮层(从按钮下方浮出),不再撑高卡片/顶走下方内容;展开时卡片 overflow:visible + z-index:5(盖住下方/同列卡片,仍低于弹窗);加点击外部 / 点击菜单项自动关闭。 Co-Authored-By: Claude Opus 4.8 --- panel/web/src/pages/Admin.tsx | 30 +++++++++++++++++++++--------- panel/web/src/styles.css | 21 +++++++++++++++++++-- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/panel/web/src/pages/Admin.tsx b/panel/web/src/pages/Admin.tsx index bd18371..f59e9fb 100644 --- a/panel/web/src/pages/Admin.tsx +++ b/panel/web/src/pages/Admin.tsx @@ -887,7 +887,17 @@ function InstanceAdminCard({ const installed = wx.installed && wx.phase !== 'downloading'; const offline = inst.runtime !== 'running'; const working = !!acting || busy; // 生命周期操作中 或 微信下载/更新中 → 锁住卡片 - const [menuOpen, setMenuOpen] = useState(false); // 「管理」折叠菜单是否展开 + const [menuOpen, setMenuOpen] = useState(false); // 「管理」菜单是否展开(悬浮层,不占文档流) + const menuRef = useRef(null); + // 悬浮下拉:点击菜单外部时关闭 + useEffect(() => { + if (!menuOpen) return; + const onDocDown = (e: MouseEvent) => { + if (menuRef.current && !menuRef.current.contains(e.target as Node)) setMenuOpen(false); + }; + document.addEventListener('mousedown', onDocDown); + return () => document.removeEventListener('mousedown', onDocDown); + }, [menuOpen]); let badge: { text: string; cls: string }; if (acting) badge = { text: '处理中', cls: 'tag-busy' }; @@ -905,7 +915,7 @@ function InstanceAdminCard({ else sub = '微信尚未安装'; return ( -
+
{inst.name} {badge.text} @@ -939,13 +949,14 @@ function InstanceAdminCard({ )}
- +
+ - {menuOpen && ( -
+ {menuOpen && ( +
setMenuOpen(false)}>
运维
@@ -997,7 +1008,8 @@ function InstanceAdminCard({
- )} + )} +
)}
diff --git a/panel/web/src/styles.css b/panel/web/src/styles.css index 35aad48..7a05465 100644 --- a/panel/web/src/styles.css +++ b/panel/web/src/styles.css @@ -307,7 +307,6 @@ button { /* 实例卡片操作:「管理」分类折叠菜单(默认收起,点开按运维/设置/危险分组展开文字操作) */ .inst-menu-toggle { - margin-top: 10px; width: 100%; height: 38px; display: flex; @@ -335,11 +334,24 @@ button { .inst-menu-toggle.open .inst-menu-caret { transform: rotate(180deg); } +/* 「管理」菜单:绝对定位悬浮层,浮在下方内容之上,不把卡片撑高、不顶走后面的内容 */ +.inst-menu-wrap { + position: relative; + margin-top: 10px; +} .inst-menu { - margin-top: 8px; + position: absolute; + top: calc(100% + 6px); + left: 0; + right: 0; + z-index: 2; display: flex; flex-direction: column; gap: 6px; + padding: 10px; + background: var(--surface); + border-radius: var(--r-small); + box-shadow: 0 6px 22px rgba(var(--shadow) / 0.26), 0 2px 6px rgba(var(--shadow) / 0.18); animation: inst-menu-in 0.16s ease; } @keyframes inst-menu-in { @@ -928,6 +940,11 @@ button { .inst-card > * { position: relative; } +/* 菜单展开时:放开裁剪让悬浮层露出,并抬升层级盖住下方/同列卡片(仍低于弹窗 z-index 20) */ +.inst-card.open-menu { + overflow: visible; + z-index: 5; +} .inst-head { display: flex; align-items: center;