Vue2后台管理系统开发实战 | RBAC权限控制与高级组件开发

2025-08-14 0 577

一、系统架构设计

本教程将基于Vue 2.6 + Element UI构建一个完整的企业级后台管理系统,实现精细化权限控制和高效数据展示。

技术架构:

  • 核心框架:Vue 2.6 + Vue Router + Vuex
  • UI组件:Element UI 2.15
  • 权限控制:RBAC模型 + JWT认证
  • 数据交互:Axios + RESTful API
  • 构建工具:Webpack 4 + Babel 7

核心功能模块:

  1. 动态路由与权限验证
  2. 高级表格与表单组件
  3. 数据可视化展示
  4. 多标签页导航
  5. 性能优化方案

二、项目初始化与配置

1. 项目创建与基础配置

# 使用Vue CLI创建项目
vue create admin-system

# 安装核心依赖
cd admin-system
vue add router
vue add vuex
npm install element-ui axios js-cookie path-to-regexp

# 配置vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true
      }
    }
  },
  chainWebpack: config => {
    // 添加分析工具
    if (process.env.NODE_ENV === 'production') {
      config.plugin('webpack-bundle-analyzer')
        .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
    }
  }
}

2. 目录结构设计

src/
├── api/               # API接口
├── assets/            # 静态资源
├── components/        # 公共组件
│   ├── Table/         # 高级表格组件
│   └── Form/          # 动态表单组件
├── directive/         # 自定义指令
├── filters/           # 全局过滤器
├── layout/            # 布局组件
├── router/            # 路由配置
│   ├── index.js       # 基础路由
│   └── permission.js  # 路由守卫
├── store/             # Vuex状态管理
│   ├── modules/       # 模块化store
│   └── index.js       # 主store文件
├── utils/             # 工具函数
├── views/             # 页面组件
│   ├── dashboard/     # 仪表盘
│   ├── system/        # 系统管理
│   └── ...            # 其他模块
├── App.vue            # 根组件
└── main.js            # 入口文件

三、权限控制系统

1. 动态路由实现

// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Layout from '@/layout'
import { getRoutes } from '@/api/user'

Vue.use(Router)

// 静态路由(所有用户可见)
const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login'),
    hidden: true
  },
  {
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },
  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard'),
      meta: { title: '首页', icon: 'dashboard' }
    }]
  }
]

// 动态路由(根据权限加载)
export const asyncRoutes = []

const createRouter = () => new Router({
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
})

const router = createRouter()

// 重置路由
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher
}

// 动态添加路由
export function addRoutes(routes) {
  resetRouter()
  router.addRoutes(routes)
}

// 获取用户路由
export function getUserRoutes() {
  return new Promise((resolve, reject) => {
    getRoutes().then(response => {
      const { data } = response
      const accessedRoutes = filterAsyncRoutes(data)
      addRoutes(accessedRoutes)
      resolve(accessedRoutes)
    }).catch(error => {
      reject(error)
    })
  })
}

// 路由过滤
function filterAsyncRoutes(routes) {
  const res = []
  
  routes.forEach(route => {
    const tmp = { ...route }
    if (tmp.component === 'Layout') {
      tmp.component = Layout
    } else {
      tmp.component = loadView(route.component)
    }
    
    if (tmp.children) {
      tmp.children = filterAsyncRoutes(tmp.children)
    }
    
    res.push(tmp)
  })
  
  return res
}

function loadView(view) {
  return () => import(`@/views/${view}`)
}

export default router

2. 路由权限守卫

// router/permission.js
import router from './'
import store from '@/store'
import { getToken } from '@/utils/auth'
import { Message } from 'element-ui'

const whiteList = ['/login', '/auth-redirect']

router.beforeEach(async (to, from, next) => {
  // 设置页面标题
  document.title = to.meta.title || '管理系统'
  
  // 确定用户是否已登录
  const hasToken = getToken()
  
  if (hasToken) {
    if (to.path === '/login') {
      // 如果已登录,重定向到首页
      next({ path: '/' })
    } else {
      // 检查用户是否已获得权限
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      
      if (hasRoles) {
        next()
      } else {
        try {
          // 获取用户信息
          const { roles } = await store.dispatch('user/getInfo')
          
          // 根据角色生成可访问路由
          const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
          
          // 动态添加路由
          router.addRoutes(accessRoutes)
          
          // 确保addRoutes完成
          next({ ...to, replace: true })
        } catch (error) {
          // 移除token并跳转到登录页
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
        }
      }
    }
  } else {
    // 未登录
    if (whiteList.indexOf(to.path) !== -1) {
      // 白名单直接放行
      next()
    } else {
      // 其他页面跳转到登录页
      next(`/login?redirect=${to.path}`)
    }
  }
})

router.afterEach(() => {
  // 完成进度条
  NProgress.done()
})

四、高级组件开发

1. 智能表格组件

// components/Table/index.vue

  
新增 删除 导出 当前页 全部数据
编辑 删除
export default { name: 'SmartTable', props: { columns: { type: Array, required: true }, fetchData: { type: Function, required: true }, border: { type: Boolean, default: true }, stripe: { type: Boolean, default: true }, height: { type: [String, Number], default: 'auto' }, hasSelection: { type: Boolean, default: false }, hasOperation: { type: Boolean, default: true }, exportable: { type: Boolean, default: false }, pagination: { type: Boolean, default: true }, permissions: { type: Array, default: () => [] } }, data() { return { loading: false, tableData: [], selectedItems: [], searchQuery: '', currentPage: 1, pageSize: 10, total: 0, sortProp: '', sortOrder: '' } }, created() { this.getData() }, methods: { async getData() { this.loading = true try { const params = { page: this.currentPage, size: this.pageSize, query: this.searchQuery, sort: this.sortProp, order: this.sortOrder } const { data } = await this.fetchData(params) this.tableData = data.list || [] this.total = data.total || 0 } catch (error) { console.error(error) } finally { this.loading = false } }, handleSelectionChange(val) { this.selectedItems = val }, handleSortChange({ prop, order }) { this.sortProp = prop this.sortOrder = order === 'ascending' ? 'asc' : 'desc' this.getData() }, handleSizeChange(val) { this.pageSize = val this.getData() }, handleCurrentChange(val) { this.currentPage = val this.getData() }, handleSearch() { this.currentPage = 1 this.getData() }, handleAdd() { this.$emit('add') }, handleEdit(index, row) { this.$emit('edit', row) }, handleDelete(index, row) { this.$confirm('确认删除该记录吗?', '提示', { type: 'warning' }).then(() => { this.$emit('delete', row.id) }) }, handleBatchDelete() { this.$confirm(`确认删除选中的${this.selectedItems.length}条记录吗?`, '提示', { type: 'warning' }).then(() => { const ids = this.selectedItems.map(item => item.id) this.$emit('batch-delete', ids) }) }, handleExport(command) { this.$emit('export', command) }, hasPermission(action) { if (!this.permissions.length) return true return this.permissions.includes(action) }, // 暴露给父组件调用的刷新方法 refresh() { this.getData() } } }

2. 动态表单组件

// components/Form/index.vue

  
    
    
      
      
        
          {{ item.prepend }}
          {{ item.append }}
        
      
      
      
      
        
          
          
        
      
      
      
      
        
        
      
      
      
      
        
          
            {{ opt.label }}
          
        
      
      
      
      
        
          
            {{ opt.label }}
          
        
      
      
      
      
        
        
      
      
      
      
        
      
    
    
    
    
      提交
      重置
    
  



export default {
  name: 'DynamicForm',
  props: {
    formItems: { type: Array, required: true },
    formData: { type: Object, required: true },
    rules: { type: Object, default: () => ({}) },
    labelWidth: { type: String, default: '100px' },
    showButtons: { type: Boolean, default: true },
    disabled: { type: Boolean, default: false }
  },
  methods: {
    submitForm() {
      this.$refs.form.validate(valid => {
        if (valid) {
          this.$emit('submit', this.formData)
        } else {
          return false
        }
      })
    },
    
    resetForm() {
      this.$refs.form.resetFields()
    },
    
    validate() {
      return new Promise((resolve, reject) => {
        this.$refs.form.validate(valid => {
          if (valid) {
            resolve(this.formData)
          } else {
            reject(new Error('表单验证失败'))
          }
        })
      })
    },
    
    clearValidate(props) {
      this.$refs.form.clearValidate(props)
    }
  }
}

五、性能优化方案

1. 路由懒加载与组件缓存

// 路由懒加载配置
const UserList = () => import(/* webpackChunkName: "user" */ '@/views/system/user/list')
const UserEdit = () => import(/* webpackChunkName: "user" */ '@/views/system/user/edit')

{
  path: 'user',
  component: Layout,
  redirect: '/system/user/list',
  name: 'User',
  meta: { title: '用户管理', icon: 'user' },
  children: [
    {
      path: 'list',
      name: 'UserList',
      component: UserList,
      meta: { title: '用户列表', cache: true }
    },
    {
      path: 'edit/:id?',
      name: 'UserEdit',
      component: UserEdit,
      meta: { title: '用户编辑', activeMenu: '/system/user/list' }
    }
  ]
}

// 使用keep-alive缓存组件

  
export default { name: 'AppMain', computed: { cachedViews() { return this.$store.state.tagsView.cachedViews }, key() { return this.$route.path } } }

2. 按需加载与代码分割

// 按需引入Element UI组件
import Vue from 'vue'
import { 
  Button, 
  Table, 
  TableColumn,
  Pagination,
  MessageBox,
  Message
} from 'element-ui'

Vue.use(Button)
Vue.use(Table)
Vue.use(TableColumn)
Vue.use(Pagination)

Vue.prototype.$confirm = MessageBox.confirm
Vue.prototype.$message = Message

// 动态加载第三方库
function loadScript(src) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script')
    script.src = src
    script.onload = resolve
    script.onerror = reject
    document.body.appendChild(script)
  })
}

// 使用示例
async function initECharts() {
  if (!window.echarts) {
    await loadScript('https://cdn.jsdelivr.net/npm/echarts@5.1.2/dist/echarts.min.js')
  }
  const chart = echarts.init(document.getElementById('chart'))
  // ...
}

// Webpack代码分割
const Dashboard = () => import(
  /* webpackChunkName: "dashboard" */ 
  /* webpackPrefetch: true */
  '@/views/dashboard'
)

六、部署与监控

1. Nginx生产环境配置

server {
    listen 80;
    server_name admin.example.com;
    
    # 开启gzip压缩
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_vary on;
    
    # 静态资源缓存
    location /static {
        alias /var/www/admin-system/dist/static;
        expires 365d;
        access_log off;
        add_header Cache-Control "public";
    }
    
    # 前端路由处理
    location / {
        root /var/www/admin-system/dist;
        try_files $uri $uri/ /index.html;
        expires -1;
    }
    
    # API代理
    location /api {
        proxy_pass http://backend-server;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    # 开启HTTP2
    listen 443 ssl http2;
    ssl_certificate /etc/letsencrypt/live/admin.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/admin.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
}

七、总结与扩展

本教程构建了一个完整的企业级后台管理系统:

  1. 实现了RBAC权限控制系统
  2. 开发了高级表格和表单组件
  3. 优化了前端性能表现
  4. 配置了生产环境部署

扩展方向:

  • 微前端架构集成
  • SSR服务器端渲染
  • 自动化测试体系
  • 移动端适配方案

完整项目代码已开源:https://github.com/example/vue2-admin-system

Vue2后台管理系统开发实战 | RBAC权限控制与高级组件开发
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 vue2 Vue2后台管理系统开发实战 | RBAC权限控制与高级组件开发 https://www.taomawang.com/web/vue2/828.html

下一篇:

已经没有下一篇了!

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务