一、系统架构设计
本教程将基于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. 项目创建与基础配置
# 使用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;
}
七、总结与扩展
本教程构建了一个完整的企业级后台管理系统:
- 实现了RBAC权限控制系统
- 开发了高级表格和表单组件
- 优化了前端性能表现
- 配置了生产环境部署
扩展方向:
- 微前端架构集成
- SSR服务器端渲染
- 自动化测试体系
- 移动端适配方案