12451 b553c4e519 feat: API 统一 + 设备详情补全 + H5 导航优化
- API 路由统一: 移除 /api/h5/,统一 /api/pms/ 入口
- 二进制改名: api-server -> pms-api(与服务名一致)
- nginx: 合并 /api/ + /pms/api/ 为 /api/pms/
- 新增 docs/API.md 接口文档
- 后端: CabinetDetail 增加 rssi/pow_fail/address/soc 等字段
- Redis 管道批量读取仓体实时数据(SOC/电压/电流/功率)
- DB: 所有 TIMESTAMP 列改为 DATETIME(修复类型不匹配)
- 用户管理: 新增创建时间/修改时间列,状态改用 Switch
- 角色管理/用户管理: 操作按钮改为图标
- PC 设备详情: 基本信息补全 RSSI/ICCID/电源/地址
- PC 卡片: 通道统计改用 Lucide 图标,颜色统一
- PC 二维码: canvas 渲染,含编号文字,支持右键下载
- H5: 按 uni-app 规范修正导航(navigateTo 替代 reLaunch)
- H5: 详情页加返回导航条
- H5: 扫码支持摄像头(jsQR)+ ?id= 参数
- H5: 底部 tabBar 在所有页面常显
- H5: 首页统计改为 6 项(设备/通道/空闲/充电/充满/故障)
- H5: 下拉刷新 / 上拉加载
- 产品首页: 添加业务联系
- 文档: 清理过时文件,补充缺失规范章节
2026-07-04 04:03:02 +08:00

3.6 KiB

Correct Nesting Order: RouterView, Transition, KeepAlive, Suspense

Rule

When combining <Suspense> with <Transition>, <KeepAlive>, and <RouterView>, the nesting order must be: RouterView -> Transition -> KeepAlive -> Suspense. Incorrect nesting causes components to not work together properly.

Why This Matters

Each of these components wraps and controls its child in specific ways. Incorrect nesting leads to:

  • Transitions not animating
  • Components not being cached by KeepAlive
  • Suspense not catching async dependencies
  • Subtle bugs that are hard to diagnose

Bad Code

<template>
  <!-- Wrong order - Suspense wrapping KeepAlive -->
  <RouterView v-slot="{ Component }">
    <Suspense>
      <KeepAlive>
        <Transition mode="out-in">
          <component :is="Component" />
        </Transition>
      </KeepAlive>
    </Suspense>
  </RouterView>
</template>
<template>
  <!-- Wrong - KeepAlive outside Transition -->
  <RouterView v-slot="{ Component }">
    <KeepAlive>
      <Transition mode="out-in">
        <Suspense>
          <component :is="Component" />
        </Suspense>
      </Transition>
    </KeepAlive>
  </RouterView>
</template>

Good Code

<template>
  <RouterView v-slot="{ Component }">
    <template v-if="Component">
      <Transition mode="out-in">
        <KeepAlive>
          <Suspense>
            <!-- Main content -->
            <component :is="Component" />

            <!-- Loading state -->
            <template #fallback>
              <div class="route-loading">
                Loading...
              </div>
            </template>
          </Suspense>
        </KeepAlive>
      </Transition>
    </template>
  </RouterView>
</template>

With Selective KeepAlive

<template>
  <RouterView v-slot="{ Component, route }">
    <template v-if="Component">
      <Transition :name="route.meta.transition || 'fade'" mode="out-in">
        <KeepAlive :include="cachedViews">
          <Suspense :timeout="200">
            <component :is="Component" :key="route.fullPath" />

            <template #fallback>
              <RouteLoadingSkeleton :route="route" />
            </template>
          </Suspense>
        </KeepAlive>
      </Transition>
    </template>
  </RouterView>
</template>

<script setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()

// Only cache specific routes
const cachedViews = computed(() => ['Dashboard', 'Profile', 'Settings'])
</script>

Why This Order?

  1. RouterView - Provides the route component via scoped slot
  2. Transition - Needs to wrap what animates (the cached/suspended content)
  3. KeepAlive - Caches the Suspense + component together
  4. Suspense - Directly wraps the async component to handle loading

Important Notes

  • Vue Router's lazy-loaded route components (via dynamic imports) don't trigger Suspense directly
  • Only async components within the route component trigger Suspense
  • Use v-if="Component" to handle the case when no route matches
  • The :key on the component can force re-render and re-trigger Suspense

Key Points

  1. Always follow the order: RouterView -> Transition -> KeepAlive -> Suspense
  2. Each wrapper serves a specific purpose in this hierarchy
  3. Use mode="out-in" on Transition to prevent overlap during route changes
  4. Consider using route-based keys for fine-grained control over when Suspense triggers

References