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中没有 → 按钮被移除
相关推荐
AI浩16 小时前
【Labelme数据操作】LabelMe标注批量复制工具 - 完整教程
运维·服务器·前端
涔溪16 小时前
CSS 网格布局(Grid Layout)核心概念、基础语法、常用属性、实战示例和进阶技巧全面讲解
前端·css
2401_8784545317 小时前
浏览器工作原理
前端·javascript
西陵17 小时前
为什么说 AI 赋能前端开发,已经不是选择题,而是必然趋势?
前端·架构·ai编程
by__csdn18 小时前
Vue3 setup()函数终极攻略:从入门到精通
开发语言·前端·javascript·vue.js·性能优化·typescript·ecmascript
天天扭码18 小时前
前端如何实现RAG?一文带你速通,使用RAG实现长期记忆
前端·node.js·ai编程
一条可有可无的咸鱼19 小时前
企业招聘信息,企业资讯进行公示
java·vue.js·spring boot·uni-app
Luna-player19 小时前
在前端中,<a> 标签的 href=“javascript:;“ 这个是什么意思
开发语言·前端·javascript
lionliu051919 小时前
js的扩展运算符的理解
前端·javascript·vue.js
小草cys19 小时前
项目7-七彩天气app任务7.4.2“关于”弹窗
开发语言·前端·javascript