This commit is contained in:
parent
d6db9996be
commit
12c7c59595
|
|
@ -107,6 +107,26 @@ router.beforeEach(async (to, _from, next) => {
|
|||
}
|
||||
// 生成动态路由
|
||||
const accessRoutes = await permissionStore.generateRoutes()
|
||||
|
||||
// 如果用户没有任何菜单权限,提示并退出登录
|
||||
if (!accessRoutes || accessRoutes.length === 0) {
|
||||
console.warn('当前用户没有任何菜单权限')
|
||||
dynamicRoutesLoaded = false
|
||||
const { ElMessageBox } = await import('element-plus')
|
||||
const roles = userStore.userInfo?.roles?.join('、') || '无'
|
||||
await ElMessageBox.alert(
|
||||
`当前账号未分配菜单权限,无法进入系统。<br/><br/>` +
|
||||
`<b>账号:</b>${userStore.userInfo?.username}<br/>` +
|
||||
`<b>角色:</b>${roles}<br/><br/>` +
|
||||
`请联系超级管理员,在「系统管理 - 角色管理」中为对应角色分配菜单,或在「管理员管理」中为该账号分配专属菜单。`,
|
||||
'无菜单权限',
|
||||
{ dangerouslyUseHTMLString: true, confirmButtonText: '返回登录', type: 'warning' }
|
||||
).catch(() => {})
|
||||
userStore.resetState()
|
||||
next(`/login?redirect=${to.path}`)
|
||||
return
|
||||
}
|
||||
|
||||
// 添加动态路由
|
||||
accessRoutes.forEach(route => {
|
||||
router.addRoute(route)
|
||||
|
|
|
|||
|
|
@ -3,19 +3,137 @@
|
|||
<div class="error-content">
|
||||
<h1>404</h1>
|
||||
<p>抱歉,您访问的页面不存在</p>
|
||||
<el-button type="primary" @click="goHome">返回首页</el-button>
|
||||
|
||||
<!-- 权限提示信息 -->
|
||||
<div v-if="permissionInfo.show" class="permission-info">
|
||||
<el-alert type="warning" :closable="false" show-icon>
|
||||
<template #title>
|
||||
<span>当前账号缺少访问该页面的菜单权限</span>
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="info-detail">
|
||||
<p><span class="label">访问路径:</span>{{ permissionInfo.path }}</p>
|
||||
<p><span class="label">所需菜单:</span>{{ permissionInfo.menuName || '未知' }}</p>
|
||||
<p v-if="permissionInfo.permission"><span class="label">权限标识:</span>{{ permissionInfo.permission }}</p>
|
||||
<p><span class="label">当前账号:</span>{{ permissionInfo.username }}</p>
|
||||
<p><span class="label">当前角色:</span>{{ permissionInfo.roles }}</p>
|
||||
<p class="tip">请联系超级管理员,在「角色管理」中为对应角色分配菜单,或在「管理员管理」中分配专属菜单。</p>
|
||||
</div>
|
||||
</template>
|
||||
</el-alert>
|
||||
</div>
|
||||
|
||||
<div class="error-actions">
|
||||
<el-button type="primary" @click="goHome">返回首页</el-button>
|
||||
<el-button @click="handleLogout">退出登录</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { reactive, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
/**
|
||||
* 已知路径与菜单名称的映射表
|
||||
*/
|
||||
const pathMenuMap: Record<string, { name: string; permission?: string }> = {
|
||||
'/dashboard': { name: '数据统计' },
|
||||
'/system': { name: '系统管理' },
|
||||
'/system/admin': { name: '系统管理 > 管理员管理', permission: 'system:admin:view' },
|
||||
'/system/role': { name: '系统管理 > 角色管理', permission: 'system:role:view' },
|
||||
'/system/menu': { name: '系统管理 > 菜单管理', permission: 'system:menu:view' },
|
||||
'/system/dept': { name: '系统管理 > 部门管理', permission: 'system:dept:view' },
|
||||
'/system/dict': { name: '系统管理 > 字典管理', permission: 'system:dict:view' },
|
||||
'/system/log': { name: '系统管理 > 操作日志', permission: 'system:log:view' },
|
||||
'/system/config': { name: '系统管理 > 系统配置', permission: 'system:config:view' },
|
||||
'/user': { name: '用户管理' },
|
||||
'/user/list': { name: '用户管理 > 用户列表', permission: 'user:view' },
|
||||
'/assessment': { name: '测评管理' },
|
||||
'/assessment/type': { name: '测评管理 > 测评类型', permission: 'assessment:view' },
|
||||
'/assessment/question': { name: '测评管理 > 题库管理', permission: 'question:view' },
|
||||
'/assessment/category': { name: '测评管理 > 报告分类', permission: 'category:view' },
|
||||
'/assessment/conclusion': { name: '测评管理 > 报告结论', permission: 'conclusion:view' },
|
||||
'/assessment/scoreOption': { name: '测评管理 > 评分标准', permission: 'assessment:view' },
|
||||
'/assessment/record': { name: '测评管理 > 测评记录', permission: 'assessmentRecord:view' },
|
||||
'/assessment/report-page-config': { name: '测评管理 > 报告页面配置', permission: 'assessment:view' },
|
||||
'/order': { name: '订单管理' },
|
||||
'/order/list': { name: '订单管理 > 订单列表', permission: 'order:view' },
|
||||
'/planner': { name: '规划师管理' },
|
||||
'/planner/list': { name: '规划师管理 > 规划师列表', permission: 'planner:view' },
|
||||
'/planner/booking': { name: '规划师管理 > 预约记录', permission: 'booking:view' },
|
||||
'/distribution': { name: '分销管理' },
|
||||
'/distribution/invite-code': { name: '分销管理 > 邀请码管理', permission: 'inviteCode:view' },
|
||||
'/distribution/commission': { name: '分销管理 > 佣金记录', permission: 'commission:view' },
|
||||
'/distribution/withdrawal': { name: '分销管理 > 提现管理', permission: 'withdrawal:view' },
|
||||
'/content': { name: '内容管理' },
|
||||
'/content/banner': { name: '内容管理 > 轮播图管理', permission: 'banner:view' },
|
||||
'/content/promotion': { name: '内容管理 > 宣传图管理', permission: 'promotion:view' },
|
||||
'/content/business-page': { name: '内容管理 > 业务介绍页', permission: 'businessPage:view' },
|
||||
'/content/navigation': { name: '内容管理 > 首页导航管理', permission: 'content:view' },
|
||||
}
|
||||
|
||||
const permissionInfo = reactive({
|
||||
show: false,
|
||||
path: '',
|
||||
menuName: '',
|
||||
permission: '',
|
||||
username: '',
|
||||
roles: ''
|
||||
})
|
||||
|
||||
/**
|
||||
* 尝试从后端菜单数据中查找路径对应的菜单名称
|
||||
*/
|
||||
function findMenuNameFromStore(path: string): string | null {
|
||||
const menus = permissionStore.menus
|
||||
if (!menus || menus.length === 0) return null
|
||||
|
||||
function search(items: any[]): string | null {
|
||||
for (const item of items) {
|
||||
if (item.path === path) return item.name
|
||||
if (item.children?.length) {
|
||||
const found = search(item.children)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
return search(menus)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 获取原始访问路径(从 query.redirect 或 referrer 中推断)
|
||||
const originalPath = (route.query.redirect as string) || route.redirectedFrom?.path || ''
|
||||
|
||||
if (originalPath && originalPath !== '/404' && userStore.userInfo) {
|
||||
const mapped = pathMenuMap[originalPath]
|
||||
const storeMenuName = findMenuNameFromStore(originalPath)
|
||||
|
||||
permissionInfo.show = true
|
||||
permissionInfo.path = originalPath
|
||||
permissionInfo.menuName = storeMenuName || mapped?.name || originalPath
|
||||
permissionInfo.permission = mapped?.permission || ''
|
||||
permissionInfo.username = userStore.userInfo.username || ''
|
||||
permissionInfo.roles = userStore.userInfo.roles?.join('、') || '无'
|
||||
}
|
||||
})
|
||||
|
||||
const goHome = () => {
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
const handleLogout = async () => {
|
||||
await userStore.logout()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
@ -29,6 +147,9 @@ const goHome = () => {
|
|||
|
||||
.error-content {
|
||||
text-align: center;
|
||||
max-width: 560px;
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.error-content h1 {
|
||||
|
|
@ -40,6 +161,36 @@ const goHome = () => {
|
|||
.error-content p {
|
||||
font-size: 18px;
|
||||
color: #606266;
|
||||
margin: 20px 0 30px;
|
||||
margin: 20px 0 20px;
|
||||
}
|
||||
|
||||
.permission-info {
|
||||
margin-bottom: 24px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.info-detail p {
|
||||
margin: 6px 0;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.info-detail .label {
|
||||
color: #909399;
|
||||
display: inline-block;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.info-detail .tip {
|
||||
margin-top: 12px;
|
||||
color: #e6a23c;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.error-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user