Vue3路由

静态路由:

公共路由(没有permissions)

动态路由:

后端新增菜单表,前端自动生成

┌─────────────────────────────────────────────────────────────────┐

│ 第一步:用户登录 │

└─────────────────────────────────────────────────────────────────┘

POST /login { username: 'ry', password: 'xxx' }

返回: { token: 'eyJhbGc...' }

localStorage.setItem('Admin-Token', token)

┌─────────────────────────────────────────────────────────────────┐

│ 第二步:路由守卫拦截 (permission.js) │

└─────────────────────────────────────────────────────────────────┘

检查 useUserStore().roles.length === 0

是 → 执行第三步

┌─────────────────────────────────────────────────────────────────┐

│ 第三步:获取用户信息和权限 │

└─────────────────────────────────────────────────────────────────┘

useUserStore().getInfo() → GET /getInfo

返回数据:

{

user: { userId: 2, userName: 'ry', ... },

roles: 'common', ← 角色列表

permissions: [ ← 权限标识列表

'pm:project:query', ✅ 项目列表权限

'pm:project:edit',

// 注意:没有 'pm:project:add' ❌ 没有新增权限

]

}

存储到 Store:

  • userStore.roles = 'common'

  • userStore.permissions = 'pm:project:query', ...

┌─────────────────────────────────────────────────────────────────┐

│ 第四步:生成动态路由 │

└─────────────────────────────────────────────────────────────────┘

usePermissionStore().generateRoutes()

GET /getRouters → 返回该用户可访问的菜单/路由

后端返回 JSON (根据角色权限过滤后):

{

"data": [

{

"name": "ProjectManagement",

"path": "/projectManagement",

"component": "Layout",

"meta": { "title": "项目管理", "icon": "project" },

"children": [

{

"name": "Project",

"path": "project",

"component": "projectManagement/project/index",

"meta": {

"title": "项目列表",

"icon": "list"

}

}

]

}

]

}

filterAsyncRouter() 转换组件:

'Layout' → Layout组件

'projectManagement/project/index' →

() => import('@/views/projectManagement/project/index.vue')

router.addRoute(route) 动态注册到路由表

渲染侧边栏菜单(显示"项目管理" → "项目列表")

┌─────────────────────────────────────────────────────────────────┐

│ 第五步:用户访问项目列表页面 │

└─────────────────────────────────────────────────────────────────┘

访问: /projectManagement/project

加载页面组件: projectManagement/project/index.vue

页面级权限控制

javascript 复制代码
<template>
  <div>
    <!-- 查询表单 -->
    <el-form>...</el-form>
    
    <!-- 操作按钮区 -->
    <el-row>
      <!-- ✅ 新增按钮 - 需要 pm:project:add 权限 -->
      <el-button
        type="primary"
        icon="Plus"
        @click="handleAdd"
        v-hasPermi="['pm:project:add']"
      >新增项目</el-button>
      
      <!-- ✅ 导出按钮 - 需要 pm:project:export 权限 -->
      <el-button
        type="warning"
        icon="Download"
        @click="handleExport"
        v-hasPermi="['pm:project:export']"
      >导出</el-button>
    </el-row>
    
    <!-- 数据表格 -->
    <el-table :data="projectList">
      <el-table-column label="项目名称" prop="projectName" />
      <el-table-column label="操作">
        <template #default="scope">
          <!-- ✅ 编辑按钮 - 需要 pm:project:edit 权限 -->
          <el-button
            link
            type="primary"
            icon="Edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['pm:project:edit']"
          >修改</el-button>
          
          <!-- ✅ 删除按钮 - 需要 pm:project:remove 权限 -->
          <el-button
            link
            type="danger"
            icon="Delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['pm:project:remove']"
          >删除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

按钮级-v-hasPermi 指令工作原理

根据已读取的代码,v-hasPermi 指令的实现逻辑:

javascript 复制代码
// src/directive/permission/hasPermi.js
export default {
  mounted(el, binding) {
    const { value } = binding
    const all_permission = "*:*:*"
    const permissions = useUserStore().permissions  // 从store获取权限列表
    
    if (value && value instanceof Array && value.length > 0) {
      const permissionFlag = value
      
      // 检查是否有对应的权限
      const hasPermissions = permissions.some(permission => {
        return all_permission === permission || permissionFlag.includes(permission)
      })
      
      // 如果没有权限,移除DOM元素
      if (!hasPermissions) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    }
  }
}

两级权限控制

第一级:路由级(菜单显示)

// 后端 /getRouters 接口会检查:

// 用户是否有 'pm:project:list' 权限

if (hasPermission('pm:project:list')) {

// ✅ 返回"项目列表"菜单

return { path: 'project', component: '...' }

} else {

// ❌ 不返回该菜单,侧边栏不显示

}

第二级:按钮级(功能控制)

<!-- 前端 v-hasPermi 指令检查 -->

<el-button v-hasPermi="'pm:project:add'">新增</el-button>

<!-- 如果 permissions 中没有 'pm:project:add',按钮DOM被移除 -->

总结

javascript 复制代码
// 1. 登录成功,存储token
localStorage.setItem('Admin-Token', 'xxx')

// 2. 路由守卫触发
router.beforeEach((to, from, next) => {
  if (useUserStore().roles.length === 0) {
    
    // 3. 获取用户信息
    useUserStore().getInfo().then(() => {
      // → roles: ['common']
      // → permissions: ['pm:project:query', 'pm:project:edit']
      
      // 4. 生成动态路由
      usePermissionStore().generateRoutes().then(routes => {
        // 5. 注册路由
        routes.forEach(route => router.addRoute(route))
        next({ ...to, replace: true })
      })
    })
  }
})

// 6. 进入页面,按钮权限控制
// v-hasPermi="['pm:project:add']"
// → permissions中没有 → 按钮被移除
相关推荐
流浪码农~4 小时前
Element Plus DatePicker 动态设置每周起始日
前端·vue.js·elementui
jason_yang4 小时前
刚发版就背锅?前端版本控制就靠他version-rocket
前端
如果超人不会飞4 小时前
TinyVue NavMenu导航菜单组件使用指南
前端·vue.js
Jason_chen4 小时前
Linux 3.0 串口机制深度解析:传统8250驱动与基础RS-232/485支持
linux·前端
TPBoreas4 小时前
前端面试问题打靶
前端
赵庆明老师4 小时前
JS检查提交的文件是否合规
开发语言·前端·javascript
禅思院4 小时前
前端请求取消与调度完全指南:从 AbortController 到企业级优先级架构
前端·设计模式·前端框架
颂love4 小时前
Vue的两大生态以及组件通信
前端·javascript·vue.js·typescript
甜汤圆4 小时前
Python 里**自定义数据单元**
前端
cidy_984 小时前
将 Figma 接入 Codex MCP:从 `/plugins` 到本地插件配置的完整教程
前端