Files
thebet365/docs/admin-page-switch-performance.md
Mars 929352bc62 perf(admin): 优化管理端页面切换性能与包体积 (同步自 main)
- 阶段 A: 增加 KeepAlive 缓存高频列表页,改用 onActivated 进行后台静默刷新,优化 tab 切换与 HomeEntry 闪屏

- 阶段 B: beforeEach 守卫在 TTL 内走同步快速路径,api 请求拦截器缓存 token 避免重复解析 JWT

- 阶段 C: 引入 unplugin 插件启用 Element Plus 组件按需加载,清理 App.vue 中 960+ 行冗余暗色主题 CSS

- i18n 拆包: 将三语文案包提取为独立懒加载 chunks,主包体积从 209KB 减少至 99KB (降低 53%)
2026-06-18 15:32:16 +08:00

9.1 KiB
Raw Blame History

管理端页面切换性能分析与优化任务

分析日期2026-06-18
范围:apps/admin 侧边栏切换路由时的响应速度(非玩家端)。


任务清单

  • measure-baseline:用 DevTools Network/Performance 记录慢路径基线(/users/bets、充值 tab 切换)
  • keepalive-layoutManageLayoutRouterView 增加 KeepAlive + 列表页 defineOptions({ name })2026-06-18
  • list-stale-cache:高频列表页改 onActivated + stale-while-revalidate避免 remount 全量 refetch2026-06-18
  • fix-deposit-tabsDepositManagev-ifv-show2026-06-18
  • lighten-agent-managerAgentManager 挂载 API 合并或按 tab 延迟加载onActivated 部分已做,拆分 SFC 待后续)
  • guard-sessionbeforeEach 去阻塞式 ensureStaffSessionTTL 内同步快速路径);api 拦截器减少 per-request reconcile2026-06-18
  • bundle-i18n-epElement Plus 按需引入 + 落地 split-i18n + App.vue CSS 瘦身2026-06-18

现象定义

用户感知的「切换慢」通常包含三段延迟叠加:

sequenceDiagram
  participant User
  participant RouterGuard
  participant ChunkLoader
  participant PageView
  participant API

  User->>RouterGuard: 点击侧边栏
  RouterGuard->>RouterGuard: ensureStaffSession (可能 HTTP)
  RouterGuard->>ChunkLoader: 动态 import 页面 chunk
  ChunkLoader->>PageView: mount 组件
  PageView->>API: onMounted 并发拉列表
  API-->>PageView: 渲染表格
  PageView-->>User: 页面可交互

一、架构结论

层级 现状 对切页的影响
路由 全部 lazy loadapps/admin/src/router/index.ts 首次进入某页需下载 chunk
布局 ManageLayout.vue 常驻 壳层不重载,合理
页面缓存 全项目无 <KeepAlive> 切走即销毁,回来必 remount + 重拉数据
数据层 无 Pinia仅少数 composable 有模块级缓存 绝大多数列表页无跨访问缓存
首屏 bundle Element Plus 全量 + 三语 i18n 打进主包 影响首访/冷启动,对已登录切页影响次之

最大根因:没有 KeepAlive + 页面 onMounted 全量 refetch。


二、切页时实际发生什么

2.1 路由守卫(每条鉴权路由)

apps/admin/src/router/index.tsbeforeEach

  • 有 token 时 await ensureStaffSession()
  • apps/admin/src/utils/session-hydrate.ts 有 60s TTL过期后会 GET /manage/auth/me阻塞导航完成
  • 访问 smoke-tests 路由时额外 await ensureLoaded()

2.2 页面生命周期(无缓存)

ManageLayout.vue 内为裸 <RouterView />

  • 旧页面 unmount
  • 新页面 chunk 动态 importmount
  • 典型模式:onMounted(load) / 顶层 void load()

Dashboard 子页 体验较好:useAdminDashboard.ts 模块级 stats 缓存,同 session 内切 //dashboard/players 可跳过 APIHomeEntry 仍可能闪 boot 屏)。

2.3 布局层常驻副作用

ManageLayout.vue onMounted

  • useDepositPendingCount:立即请求 + 每 30s 轮询 pending-count
  • useSmokeTestsAllowed:一次性权限探测

不直接阻塞切页,但增加后台并发请求。

2.4 每个 API 请求的同步开销

apps/admin/src/api.ts 请求拦截器对每个请求调用 reconcileStaffSessionFromToken()JWT decode + localStorage。列表页 mount 时常 并发 310 个请求,同步开销被放大。


三、按影响排序的瓶颈清单

P0 — 切换体验(每次切页都痛)

1. 无 KeepAlive列表页反复 remount + refetch

受影响页面(模式相同):

  • Bets.vueCashback.vue
  • Matches.vueMatchesOutrights.vue
  • DepositOrders.vueStaffManage.vue
  • Contents.vueFinanceLogs.vue

2. 重型页面挂载 API burst

AgentManager.vue/users)— 约 2900 行 SFConMounted 并行:

  • GET /admin/users/page-init
  • GET /admin/users(全量玩家)
  • GET /admin/agents?level=1
  • page-init 后再按层级 N+1 拉子代理

每次从其他页回到 /users 都会重复上述 burst。

3. Tab 用 v-if 导致子页销毁

DepositManage.vue

<DepositOrders v-if="activeTab === 'orders'" />
<PaymentMethods v-if="activeTab === 'methods'" />

同页内切换 tab 也会 destroy + onMounted(fetchList)

4. Matches 展开面板扇出请求

LeagueMatchesPanel.vue watch(..., { immediate: true }):恢复 session 展开最多 3 个联赛时,最多 3 路 GET /admin/matches;折叠再展开会 remount 重拉。

P1 — 间歇性卡顿(特定路径 / 时间)

5. Session hydrate 阻塞导航

60s TTL 过期后,每次切页先等 /manage/auth/me。弱网或后端慢时,侧边栏点击后「卡住」数秒。

6. HomeEntry 回 Dashboard 闪屏

HomeEntry.vueonBeforeMount 再次 ensureStaffSession + booting 全屏 loadingrouter 已做过 hydrate

7. 首次进入大 chunk 的 JS 解析

页面 风险
AgentManager.vue 巨型 SFC + 多子组件
Settlement.vue ~1500 行 + async echarts
Contents.vue ContentRichEditor.vue

P2 — 首屏 / 冷启动

8. Element Plus 全量注册

main.ts 全量 app.use(ElementPlus) + element-plus/dist/index.css,无按需引入。

9. i18n 三语未真正拆包

admin-messages.ts 仍静态 import zh/en/ms 全文;split-i18n.mjs 未落地,首屏携带全部语言文案。

10. App.vue 全局 CSS ~1900 行

无 scoped 的暗色/浅色双套 Element 覆盖,与全量 EP CSS 叠加。


四、问题分层矩阵

症状 最可能原因 验证方式
任意页切回上一页都慢 无 KeepAlive + onMounted refetch Network切回同页重复相同 API
/users 特别慢 AgentManager 多路并行 API + 大 chunk mount 时 3+ 请求Performance 看 JS
偶尔点菜单无反应数秒 ensureStaffSession 阻塞 切页瞬间是否有 /manage/auth/me
充值页 tab 切换慢 DepositManage v-if 切 tab 是否重复 deposit-orders 请求
首次进某页慢、之后再进仍慢 大 chunk + 仍无缓存 对比首次/二次 Network
整体首次打开就慢 EP 全量 + i18n 三语 + 全局 CSS pnpm --filter @thebet365/admin build:analyze

五、优化路径(分阶段)

阶段 A — 切页体验12 天,收益最大)

  1. ManageLayout.vue<RouterView> 外包 <KeepAlive :max="8">,列表页 defineOptions({ name })
  2. 列表页改 onActivated + stale-while-revalidate有缓存先展示后台静默刷新
  3. DepositManage.vuev-ifv-show 或 keep-alive 两个 tab
  4. HomeEntry.vue:去掉重复 hydrate / 仅首次 boot

阶段 B — 重型页与 API23 天)

  1. 拆分 AgentManager.vue:按 tab lazy或合并 bootstrap 为单一 page-init 接口
  2. 提取通用 useListCache(key, fetcher, ttl) 给 Bets/Users/Deposit 等
  3. LeagueMatchesPanel:对已加载 leagueId 短 TTL 缓存
  4. api.tsreconcileStaffSessionFromToken 移到 token 变更时,而非每请求

阶段 C — 守卫与 bundle35 天)

  1. beforeEach 改为同步 JWT/localStorage 校验;/me 仅登录/刷新时调用
  2. Element Plus 改按需 + 去全量 CSS
  3. 执行/合入 i18n split-i18n.mjs,首屏只加载当前语言
  4. 瘦身 App.vue 全局样式

阶段 D — 度量与验收

pnpm --filter @thebet365/admin build:analyze

验收指标Chrome DevToolsFast 3G

  • 切回已访问列表页:无重复全量列表 API或仅 background refresh
  • /users 二次进入API 数从 3+ 降到 01
  • 侧边栏切换guard 阶段无阻塞性 /me60s 内)

六、当前不必优先动的部分

  • ECharts:已 async chunk仅 dashboard/settlement 加载
  • ContentRichEditor:未全局引入,仅 contents 路由
  • deposit 30s 轮询:后台流量,通常不是切页主因
  • ManageLayout computed 菜单:开销相对小

七、推荐落地顺序

  1. 只做一处KeepAlive + 列表页 activated 缓存(阶段 A
  2. /users 最慢:在 A 之后做 AgentManager API 合并/延迟加载(阶段 B
  3. 首屏整体慢:再动 Element Plus / i18n 拆分(阶段 C

八、关键文件索引

职责 路径
路由 + beforeEach apps/admin/src/router/index.ts
布局壳 apps/admin/src/layouts/ManageLayout.vue
Session 水合 / TTL apps/admin/src/utils/session-hydrate.ts
Auth store apps/admin/src/stores/auth.ts
Axios 拦截器 apps/admin/src/api.ts
Dashboard 入口 apps/admin/src/views/HomeEntry.vue
Dashboard 数据缓存 apps/admin/src/composables/useAdminDashboard.ts
Deposit 轮询 apps/admin/src/composables/useDepositPendingCount.ts
Bootstrap apps/admin/src/main.ts
Vite 分包 apps/admin/vite.config.ts
重型用户页 apps/admin/src/views/AgentManager.vue
充值 tab apps/admin/src/views/DepositManage.vue