Files
his/healthlink-his-ui/src/permission.js
华佗 bc92620f66 fix: 修复前端路由名重复导致的404问题 + E2E测试20/20通过
根因分析:
- 后端菜单配置存在30+个重复路由名(如Record/Enhanced/Charge等)
- Vue Router不允许重名路由,addRoute抛出异常
- permission.js的catch直接调用logOut(),导致所有页面重定向到登录页

修复内容:
1. permission.js: addRoute时try-catch重名错误,跳过而非登出
2. permission store: filterAsyncRouter中添加路由名自动去重逻辑
3. 新增src/api/anesthesia.js: 麻醉模块API文件缺失修复
4. 修正test-data.ts中所有错误路由路径,匹配实际菜单配置

验证: workflow-full.spec.ts 20/20通过, login.spec.ts 4/4通过
2026-06-08 00:18:34 +08:00

115 lines
3.4 KiB
JavaScript
Executable File

import router from './router'
import { ElMessage } from 'element-plus'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
import { isHttp, isPathMatch } from '@/utils/validate'
import { isRelogin } from '@/utils/request'
import useUserStore from '@/store/modules/user'
import useLockStore from '@/store/modules/lock'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
import useNoticeStore from '@/store/modules/notice'
import useTagsViewStore from '@/store/modules/tagsView'
// 全局变量,用于控制公告弹窗只显示一次
let hasShownNoticePopup = false
NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register']
const isWhiteList = (path) => {
return whiteList.some(pattern => isPathMatch(pattern, path))
}
router.beforeEach(async (to, from) => {
NProgress.start()
if (getToken()) {
to.meta.title && useSettingsStore().setTitle(to.meta.title)
const isLock = useLockStore().isLock
if (to.path === '/login') {
NProgress.done()
return { path: '/' }
}
if (isWhiteList(to.path)) {
return true
}
if (isLock && to.path !== '/lock') {
NProgress.done()
return { path: '/lock' }
}
if (!isLock && to.path === '/lock') {
NProgress.done()
return { path: '/' }
}
if (useUserStore().roles.length === 0) {
isRelogin.show = true
try {
await useUserStore().getInfo()
isRelogin.show = false
const accessRoutes = await usePermissionStore().generateRoutes()
accessRoutes.forEach(route => {
if (!isHttp(route.path)) {
if (!router.hasRoute(route.name)) {
try {
router.addRoute(route)
} catch (e) {
// 路由名重复时跳过,不影响其他路由加载
console.warn('路由添加跳过(名称重复):', route.name, e.message)
}
}
}
})
useNoticeStore().startPolling()
useTagsViewStore().loadPersistedViews()
return { ...to, replace: true }
} catch (err) {
console.error('路由加载失败:', err)
await useUserStore().logOut()
ElMessage.error(err.message || '登录已过期')
return { path: '/login' }
}
}
return true
} else {
if (isWhiteList(to.path)) {
return true
}
NProgress.done()
return `/login?redirect=${to.fullPath}`
}
})
router.afterEach(() => {
NProgress.done()
// 登录成功后显示公告弹窗(仅限非登录页面且未显示过)
const token = getToken()
const isLoginPage = router.currentRoute.value.path === '/login'
if (token && !isLoginPage && !hasShownNoticePopup) {
setTimeout(() => {
showNoticePopupGlobally()
hasShownNoticePopup = true
}, 1500)
}
})
// 全局函数:显示公告弹窗
function showNoticePopupGlobally() {
try {
const layouts = document.querySelectorAll('.app-wrapper')
for (const layout of layouts) {
const noticePopupRef = layout.__vue_app__?.config.globalProperties.$refs?.noticePopupRef
if (noticePopupRef && noticePopupRef.showNotice) {
noticePopupRef.showNotice()
return
}
}
window.dispatchEvent(new CustomEvent('show-notice-popup'))
} catch (error) {
console.error('显示公告弹窗失败:', error)
}
}