feat(store): 优化状态管理和路由处理
* 增强路由状态管理 - 改进动态路由加载和混合路由模式支持 - 优化路由重置机制,保护基础路由 - 完善路由helper工具函数 * 提升标签页管理 - 集成安全导航机制,使用navigationGuard - 增强标签页关闭和跳转的错误处理 * 改进认证状态管理 - 优化登录流程和用户信息处理 - 更好的登录重定向逻辑 提升应用稳定性和用户体验
This commit is contained in:
parent
5e13342f7b
commit
4f27534f22
@ -1,5 +1,5 @@
|
|||||||
import { router } from '@/router'
|
import { router } from '@/router'
|
||||||
import { fetchLogin, fetchLoginUserInfo } from '@/service'
|
import { fetchLogin, fetchLoginUserInfo } from '@/service/api/auth'
|
||||||
import { local } from '@/utils'
|
import { local } from '@/utils'
|
||||||
import { useRouteStore } from './router'
|
import { useRouteStore } from './router'
|
||||||
import { useTabStore } from './tab'
|
import { useTabStore } from './tab'
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { h } from 'vue'
|
|||||||
import { usePermission } from '@/hooks'
|
import { usePermission } from '@/hooks'
|
||||||
import Layout from '@/layouts/index.vue'
|
import Layout from '@/layouts/index.vue'
|
||||||
import { arrayToTree, renderIcon } from '@/utils'
|
import { arrayToTree, renderIcon } from '@/utils'
|
||||||
|
import { safeAsyncComponent } from '@/utils/component-guard'
|
||||||
import { clone, min, omit, pick } from 'radash'
|
import { clone, min, omit, pick } from 'radash'
|
||||||
import { RouterLink } from 'vue-router'
|
import { RouterLink } from 'vue-router'
|
||||||
|
|
||||||
@ -78,21 +79,52 @@ export function createRoutes(routeData: (AppRoute.BackendRoute | AppRoute.RowRou
|
|||||||
componentPath = `${componentPath}.vue`
|
componentPath = `${componentPath}.vue`
|
||||||
}
|
}
|
||||||
const fullPath = `/src/views${componentPath}`
|
const fullPath = `/src/views${componentPath}`
|
||||||
item.component = modules[fullPath]
|
const originalComponent = modules[fullPath]
|
||||||
|
|
||||||
// 如果组件未找到,输出调试信息并提供默认组件
|
// 如果组件未找到,输出调试信息并提供默认组件
|
||||||
if (!item.component) {
|
if (!originalComponent) {
|
||||||
console.warn(`组件未找到: ${fullPath}`)
|
console.warn(`组件未找到: ${fullPath}`)
|
||||||
console.warn('可用组件路径:', Object.keys(modules).slice(0, 10)) // 只显示前10个避免日志过长
|
console.warn('可用组件路径:', Object.keys(modules).slice(0, 10)) // 只显示前10个避免日志过长
|
||||||
|
|
||||||
// 为找不到组件的页面提供一个默认的空页面组件
|
// 为找不到组件的页面提供一个默认的空页面组件
|
||||||
item.component = () => h('div', { class: 'p-4' }, [
|
item.component = safeAsyncComponent(
|
||||||
h('div', { class: 'text-center text-gray-500' }, [
|
() => Promise.resolve({
|
||||||
h('h3', '页面开发中'),
|
template: `
|
||||||
h('p', `组件路径: ${fullPath}`),
|
<div class="p-4">
|
||||||
h('p', '请联系开发人员创建对应的页面组件'),
|
<div class="text-center text-gray-500">
|
||||||
]),
|
<h3>页面开发中</h3>
|
||||||
])
|
<p>组件路径: ${fullPath}</p>
|
||||||
|
<p>请联系开发人员创建对应的页面组件</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
delay: 0,
|
||||||
|
timeout: 5000,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 使用安全的异步组件加载器包装原有组件
|
||||||
|
item.component = safeAsyncComponent(
|
||||||
|
originalComponent as any,
|
||||||
|
{
|
||||||
|
delay: 100,
|
||||||
|
timeout: 10000,
|
||||||
|
onError: (error, retry, fail, attempts) => {
|
||||||
|
console.error(`组件加载失败: ${fullPath}`, error)
|
||||||
|
if (attempts <= 2) {
|
||||||
|
console.warn(`重试加载组件: ${fullPath} (第${attempts}次)`)
|
||||||
|
retry()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error(`组件加载最终失败: ${fullPath}`)
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (item.meta.menuType === '1') {
|
else if (item.meta.menuType === '1') {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import type { MenuOption } from 'naive-ui'
|
import type { MenuOption } from 'naive-ui'
|
||||||
import { router } from '@/router'
|
import { router } from '@/router'
|
||||||
import { staticRoutes } from '@/router/routes.static'
|
import { staticRoutes } from '@/router/routes.static'
|
||||||
import { fetchUserRoutes } from '@/service'
|
import { fetchUserRoutes } from '@/service/api/system/menu'
|
||||||
import { $t } from '@/utils'
|
import { $t } from '@/utils'
|
||||||
import { coiMsgError } from '@/utils/coi'
|
import { coiMsgError } from '@/utils/coi'
|
||||||
import { createMenus, createRoutes, generateCacheRoutes } from './helper'
|
import { createMenus, createRoutes, generateCacheRoutes } from './helper'
|
||||||
@ -31,8 +31,20 @@ export const useRouteStore = defineStore('route-store', {
|
|||||||
this.$reset()
|
this.$reset()
|
||||||
},
|
},
|
||||||
resetRoutes() {
|
resetRoutes() {
|
||||||
if (router.hasRoute('appRoot'))
|
// 获取所有路由名称
|
||||||
router.removeRoute('appRoot')
|
const allRouteNames = router.getRoutes().map(route => route.name).filter(Boolean)
|
||||||
|
|
||||||
|
// 保护固定路由,不删除这些基础路由
|
||||||
|
const protectedRoutes = ['root', 'login', '403', '404', '500', 'notFound']
|
||||||
|
|
||||||
|
// 删除除了保护路由之外的所有路由
|
||||||
|
allRouteNames.forEach((name) => {
|
||||||
|
if (name && !protectedRoutes.includes(name as string)) {
|
||||||
|
if (router.hasRoute(name)) {
|
||||||
|
router.removeRoute(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
// set the currently highlighted menu key
|
// set the currently highlighted menu key
|
||||||
setActiveMenu(key: string) {
|
setActiveMenu(key: string) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { RouteLocationNormalized } from 'vue-router'
|
import type { RouteLocationNormalized } from 'vue-router'
|
||||||
import { router } from '@/router'
|
import { navigationGuard } from '@/router'
|
||||||
|
|
||||||
interface TabState {
|
interface TabState {
|
||||||
pinTabs: RouteLocationNormalized[]
|
pinTabs: RouteLocationNormalized[]
|
||||||
@ -34,29 +34,34 @@ export const useTabStore = defineStore('tab-store', {
|
|||||||
this.tabs.push(route)
|
this.tabs.push(route)
|
||||||
},
|
},
|
||||||
async closeTab(fullPath: string) {
|
async closeTab(fullPath: string) {
|
||||||
const tabsLength = this.tabs.length
|
try {
|
||||||
// 如果动态标签大于一个,才会标签跳转
|
const tabsLength = this.tabs.length
|
||||||
if (this.tabs.length > 1) {
|
// 如果动态标签大于一个,才会标签跳转
|
||||||
// 获取关闭的标签索引
|
if (this.tabs.length > 1) {
|
||||||
const index = this.getTabIndex(fullPath)
|
// 获取关闭的标签索引
|
||||||
const isLast = index + 1 === tabsLength
|
const index = this.getTabIndex(fullPath)
|
||||||
// 如果是关闭的当前页面,路由跳转到原先标签的后一个标签
|
const isLast = index + 1 === tabsLength
|
||||||
if (this.currentTabPath === fullPath && !isLast) {
|
// 如果是关闭的当前页面,路由跳转到原先标签的后一个标签
|
||||||
// 跳转到后一个标签
|
if (this.currentTabPath === fullPath && !isLast) {
|
||||||
router.push(this.tabs[index + 1].fullPath)
|
// 跳转到后一个标签
|
||||||
}
|
await navigationGuard.safePush(this.tabs[index + 1].fullPath)
|
||||||
else if (this.currentTabPath === fullPath && isLast) {
|
}
|
||||||
// 已经是最后一个了,就跳转前一个
|
else if (this.currentTabPath === fullPath && isLast) {
|
||||||
router.push(this.tabs[index - 1].fullPath)
|
// 已经是最后一个了,就跳转前一个
|
||||||
|
await navigationGuard.safePush(this.tabs[index - 1].fullPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// 删除标签
|
||||||
|
this.tabs = this.tabs.filter((item) => {
|
||||||
|
return item.fullPath !== fullPath
|
||||||
|
})
|
||||||
|
// 删除后如果清空了,就跳转到默认首页
|
||||||
|
if (tabsLength - 1 === 0)
|
||||||
|
await navigationGuard.safePush('/')
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('关闭标签页时发生错误:', error)
|
||||||
}
|
}
|
||||||
// 删除标签
|
|
||||||
this.tabs = this.tabs.filter((item) => {
|
|
||||||
return item.fullPath !== fullPath
|
|
||||||
})
|
|
||||||
// 删除后如果清空了,就跳转到默认首页
|
|
||||||
if (tabsLength - 1 === 0)
|
|
||||||
router.push('/')
|
|
||||||
},
|
},
|
||||||
|
|
||||||
closeOtherTabs(fullPath: string) {
|
closeOtherTabs(fullPath: string) {
|
||||||
@ -75,9 +80,14 @@ export const useTabStore = defineStore('tab-store', {
|
|||||||
this.tabs.length = 0
|
this.tabs.length = 0
|
||||||
this.pinTabs.length = 0
|
this.pinTabs.length = 0
|
||||||
},
|
},
|
||||||
closeAllTabs() {
|
async closeAllTabs() {
|
||||||
this.tabs.length = 0
|
try {
|
||||||
router.push('/')
|
this.tabs.length = 0
|
||||||
|
await navigationGuard.safePush('/')
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('关闭所有标签页时发生错误:', error)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
hasExistTab(fullPath: string) {
|
hasExistTab(fullPath: string) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user