fix(web): 防止页面异常阻塞路由切换

This commit is contained in:
chengqian committed 2026-07-30 14:40:10 +08:00
1 parent 8a8a96a012
commit 6ff5c6e949
6 files changed
+108 -3

No files matched your search

@@ -0,0 +1,45 @@
<script setup lang="ts">
import { onErrorCaptured, ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const error = ref<unknown>(null)
onErrorCaptured((caughtError, _instance, info) => {
error.value = caughtError
console.error('[RouteErrorBoundary]', info, caughtError)
return false
})
function reloadPage() {
window.location.reload()
}
async function goToDashboard() {
error.value = null
await router.push({ name: 'AdminDashboard' })
}
</script>
<template>
<slot v-if="!error" />
<div v-else class="route-error">
<AResult status="error" title="页面加载失败" subtitle="页面数据异常,请重试或返回仪表盘">
<template #extra>
<ASpace>
<AButton type="primary" @click="reloadPage">重新加载</AButton>
<AButton @click="goToDashboard">返回仪表盘</AButton>
</ASpace>
</template>
</AResult>
</div>
</template>
<style scoped>
.route-error {
display: flex;
min-height: min(520px, calc(100vh - 160px));
align-items: center;
justify-content: center;
}
</style>
+3
View File
@@ -27,6 +27,9 @@ console.log(
)
const app = createApp(App)
app.config.errorHandler = (error, _instance, info) => {
console.error('[VueError]', info, error)
}
app.use(createPinia())
app.use(ArcoVue)
app.use(router)
+5 -2
View File
@@ -5,6 +5,7 @@ import { Message } from '@arco-design/web-vue'
import axios from 'axios'
import { marked } from 'marked'
import request from '@/utils/request'
import RouteErrorBoundary from '@/components/RouteErrorBoundary.vue'
import { useWatermark } from '@/composables/useWatermark'
import { useSiteName } from '@/composables/useSiteName'
import {
@@ -610,9 +611,11 @@ onUnmounted(() => {
<!-- Content -->
<main class="admin-content page-bg">
<router-view v-slot="{ Component }">
<router-view v-slot="{ Component, route: currentRoute }">
<Transition name="page-fade" mode="out-in">
<component :is="Component" />
<RouteErrorBoundary :key="currentRoute.fullPath">
<component :is="Component" />
</RouteErrorBoundary>
</Transition>
</router-view>
</main>
@@ -0,0 +1,46 @@
<script setup lang="ts">
import { onErrorCaptured, ref } from 'vue'
import { useRouter } from 'vue-router'
import Icon from '@/components/common/Icon.vue'
const router = useRouter()
const error = ref<unknown>(null)
onErrorCaptured((caughtError, _instance, info) => {
error.value = caughtError
console.error('[RouteErrorBoundary]', info, caughtError)
return false
})
function reloadPage() {
window.location.reload()
}
async function goToDashboard() {
error.value = null
await router.push({ name: 'TenantDashboard' })
}
</script>
<template>
<slot v-if="!error" />
<div v-else class="flex min-h-[min(520px,calc(100vh-10rem))] items-center justify-center px-4">
<div class="w-full max-w-lg text-center">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-red-50 text-red-500">
<Icon name="exclamationCircle" size="xl" />
</div>
<h2 class="mt-5 text-lg font-semibold text-gray-900">页面加载失败</h2>
<p class="mt-2 text-sm text-gray-500">页面数据异常,请重试或返回仪表盘</p>
<div class="mt-6 flex flex-wrap justify-center gap-3">
<button type="button" class="btn btn-primary" @click="reloadPage">
<Icon name="refresh" size="sm" />
重新加载
</button>
<button type="button" class="btn btn-secondary" @click="goToDashboard">
<Icon name="chart" size="sm" />
返回仪表盘
</button>
</div>
</div>
</div>
</template>
+3
View File
@@ -29,6 +29,9 @@ console.log(
)
const app = createApp(App)
app.config.errorHandler = (error, _instance, info) => {
console.error('[VueError]', info, error)
}
app.use(head)
app.use(createPinia())
app.use(router)
+6 -1
View File
@@ -10,6 +10,7 @@ import { toast } from '@/utils/toast'
import Icon from '@/components/common/Icon.vue'
import MaintenanceBanner from '@/components/common/MaintenanceBanner.vue'
import AnnouncementBanner from '@/components/common/AnnouncementBanner.vue'
import RouteErrorBoundary from '@/components/common/RouteErrorBoundary.vue'
import { marked } from 'marked'
import request from '@/utils/request'
@@ -510,7 +511,11 @@ onBeforeUnmount(() => {
class="tenant-main px-3 pb-5 pt-4 md:px-5 md:pb-6 lg:pt-5"
:class="{ 'tenant-table-main': route.meta.viewportTable }"
>
<router-view />
<router-view v-slot="{ Component, route: currentRoute }">
<RouteErrorBoundary :key="currentRoute.fullPath">
<component :is="Component" />
</RouteErrorBoundary>
</router-view>
</main>
</div>
</div>