From a305e4013b10b9b0e002d8cdae41717fd9ad4746 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 30 Sep 2026 13:58:22 +0800 Subject: [PATCH 1/3] perf(ui): teleport overlays into #overlay-root instead of Every overlay (BaseDialog, Select, the accounts tools panel and row menu, tooltips, drawers, toasts: 31 in 25 files) inserted its content among 's own children, next to the anchors Vue appends at mount time. carries the positional (:first/:last-child) and sibling (space-y / divide-y ~) invalidation flags, so each open or close restyled the whole document: 130-290 ms event->paint on /admin/accounts. index.html now ends with an empty #overlay-root and every Teleport targets it, so opening an overlay only touches that container (~0.5 ms forced recalc instead of ~170 ms). The container has no styles and makes no stacking context: overlays keep their z-order. The login agreement dialog selectors (body > div.z-[140]) follow the overlay into #overlay-root; :where() keeps them at their old specificity. The test setup recreates #overlay-root before each test, since many specs reset document.body. Co-Authored-By: Claude Opus 5.5 --- frontend/index.html | 2 + frontend/src/__tests__/setup.ts | 13 ++++- .../components/account/AccountGroupsCell.vue | 2 +- .../components/account/AccountTestModal.vue | 2 +- .../admin/account-jobs/AccountTaskDrawer.vue | 2 +- .../admin/account/AccountActionMenu.vue | 2 +- .../admin/account/AccountDetailsDrawer.vue | 2 +- .../admin/account/AccountTestModal.vue | 2 +- .../src/components/admin/usage/UsageTable.vue | 4 +- .../admin/user/UserApiKeysModal.vue | 2 +- .../components/auth/LoginAgreementPrompt.vue | 2 +- .../channels/SupportedModelChip.vue | 2 +- .../components/common/AnnouncementBell.vue | 4 +- .../components/common/AnnouncementPopup.vue | 2 +- frontend/src/components/common/BaseDialog.vue | 2 +- .../src/components/common/HelpTooltip.vue | 2 +- .../src/components/common/InfoPopover.vue | 2 +- frontend/src/components/common/Select.vue | 2 +- frontend/src/components/common/Toast.vue | 2 +- .../channel-monitor-v2/FilterMultiSelect.vue | 2 +- .../channel-monitor-v2/RelayPulseMatrix.vue | 2 +- frontend/src/styles/console/controls.css | 2 +- frontend/src/styles/console/data.css | 18 +++--- .../console/pages/settings-ops-public.css | 56 +++++++++---------- frontend/src/views/admin/AccountsView.vue | 2 +- frontend/src/views/admin/RedeemView.vue | 6 +- frontend/src/views/admin/UsersView.vue | 2 +- .../src/views/user/BatchImageGuideView.vue | 4 +- frontend/src/views/user/KeysView.vue | 2 +- frontend/src/views/user/PaymentView.vue | 4 +- 30 files changed, 83 insertions(+), 70 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index ef5c8cca3316..6d55435f7989 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -9,6 +9,8 @@
+ +
diff --git a/frontend/src/__tests__/setup.ts b/frontend/src/__tests__/setup.ts index 9dad8c1f123b..2fee78ac0224 100644 --- a/frontend/src/__tests__/setup.ts +++ b/frontend/src/__tests__/setup.ts @@ -3,7 +3,7 @@ * 提供全局 mock 和测试工具 */ import { config } from '@vue/test-utils' -import { vi } from 'vitest' +import { beforeEach, vi } from 'vitest' function createMemoryStorage(): Storage { const values = new Map() @@ -89,6 +89,17 @@ class MockResizeObserver { globalThis.ResizeObserver = MockResizeObserver as unknown as typeof ResizeObserver +// Overlays teleport into #overlay-root (index.html); many specs reset document.body, so recreate it per test. +function ensureOverlayRoot() { + if (typeof document === 'undefined' || document.getElementById('overlay-root')) return + const overlayRoot = document.createElement('div') + overlayRoot.id = 'overlay-root' + document.body.appendChild(overlayRoot) +} + +ensureOverlayRoot() +beforeEach(ensureOverlayRoot) + // Vue Test Utils 全局配置 config.global.stubs = { // 可以在这里添加全局 stub diff --git a/frontend/src/components/account/AccountGroupsCell.vue b/frontend/src/components/account/AccountGroupsCell.vue index 37771275fafd..01c395fb16b3 100644 --- a/frontend/src/components/account/AccountGroupsCell.vue +++ b/frontend/src/components/account/AccountGroupsCell.vue @@ -24,7 +24,7 @@ - + - +
{{ t('admin.accountTasks.nextPage') }} - +