0. 写在前面
vue-element-admin 是一个后台前端解决方案,它基于 vue 和 element-ui实现。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。[1]
vueAdmin-template 主要是基于vue-cli webpack模板为基础开发的,引入了如下dependencies:
- element-ui 饿了么出品的vue2.0 pc UI框架
- axios 一个现在主流并且很好用的请求库 支持Promise
- js-cookie 一个轻量的JavaScript库来处理cookie
- normalize.css 格式化css
- nprogress 轻量的全局进度条控制
- vuex 官方状态管理
- vue-router 官方路由
该项目只做了一个管理后台需要极简的功能,封装了axios请求,支持无限层级路由,动态权限和动态侧边栏。
本项目的定位是后台集成方案,不太适合当基础模板来进行二次开发。因为本项目集成了很多你可能用不到的功能,会造成不少的代码冗余。如果你的项目不关注这方面的问题,也可以直接基于它进行二次开发。
花裤衩建议
你可以把 vue-element-admin当做工具箱或者集成方案仓库,在 vue-admin-template 的基础上进行二次开发,想要什么功能或者组件就去 vue-element-admin 那里复制过来。
vue-admin-template/src下的目录结构:
.
├── App.vue //入口
├── api // 各种接口
├── assets // 图片等资源
├── components // 各种公共组件,非公共组件在各自view下维护
├── icons //svg icon
├── main.js //入口
├── permission.js //认证入口
├── router // 路由表
├── store // 存储
├── styles // 各种样式
├── utils // 公共工具,非公共工具,在各自view下维护
└── views // 各种layout
1. 我们对前端组件、框架的需求——关注点
登录与权限控制
菜单及其动态菜单
图表展现
图标
色彩搭配
中文处理
跨域问题
2. 裁剪前端vue-element-template工程——开始
按花裤衩的建议,使用vue-element-template为基础,进行二次开发。我们避免重复造轮子,尽量少改源代码,尽量抽取移植vue-element-admin工程内容,重新生成属于自己可控的开源框架平台。
根据Vue给定文件目录结构,我们重点选定如下内容:
功能点 | 专业名称 | 使用文件夹/文件 | 说明 |
---|---|---|---|
菜单 | 路由 | /src/router/index.js | 菜单与路由控制 |
登录 | /src/views/login/index.vue | 登录控制获取权限 | |
权限控制 | /src/permission.js | 与路由配合控制转向 |
我们可以这样理解vue-element-template工程(含权限控制版),vue-element-template只是包括菜单、路由、权限、API接口的基础集成,解决最基本的登录、权限、Token、菜单等最基本需求,其他扩展可以参考大而全的案例vue-element-admin,按需移植过来。
避免啰嗦和干扰,直接把/src/router/index.js中不需要的内容删除,结果如下:
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/newdashboard',
children: [{
path: 'newdashboard',
name: 'NewDashboard',
component: () => import('@/views/newdashboard/index'),
meta: { title: '首页', icon: 'dashboard' }
}]
}
]
3. 关于中文
3.1. 组件中文
如果有人要做国际化可以去element官网国际化看看写的很详细。
修改/src/main.js文件:
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
Vue.use(ElementUI, { locale })
替换en为zh-CN
import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n
3.2. 中文菜单
对于中文菜单,直接在路由的文件(/src/router/index.js),修改meta中title的描述为中文即可。
path: '/opeff',
component: Layout,
redirect: '/opeff/eff',
name: 'OpEff',
meta: { title: '作业效率分析', icon: 'money' },
4. 新增菜单及页面
4.1. 新增菜单
在当前菜单框架下,直接编辑路由文件(/src/router/index.js),按其树装结构和格式编写即可,效果如下:
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/newdashboard',
children: [{
path: 'newdashboard',
name: 'NewDashboard',
component: () => import('@/views/newdashboard/index'),
meta: { title: '首页', icon: 'dashboard' }
}]
},
{
path: '/opeff',
component: Layout,
redirect: '/opeff/eff',
name: 'OpEff',
meta: { title: '作业效率分析', icon: 'money' },
children: [
{
path: 'eff',
name: 'Eff',
component: () => import('@/views/opeff/eff/index'),
meta: { title: '效率综合分析', icon: 'eye-open' }
},
{
path: 'outlet',
name: 'Outlet',
component: () => import('@/views/opeff/outlet/index'),
meta: { title: '发油效率分析', icon: 'link' }
}
]
}
]
注:对于动态菜单,按权限控制菜单,由于文章逻辑和篇幅有限,先行略过,后续文章再写。
4.2. 新增页面
这里所说的新增页面,是指与新增菜单配套的页面,首先,根据上文菜单,在/src/views目录下形成如下文件夹结构:
在view目录下新增newdashboard目录,内新增index.vue, 作为改页面的入口。
/src/views/newdashboard/index.vue
拷贝vue-element-admin-master/src/views/dashboard/admin/index.vue内容,删减后保留如下内容:
<template>
<div class="dashboard-editor-container">
<github-corner class="github-corner" />
<panel-group @handleSetLineChartData="handleSetLineChartData" />
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
<line-chart :chart-data="lineChartData" />
</el-row>
</div>
</template>
<script>
import GithubCorner from '@/components/GithubCorner'
import PanelGroup from './components/PanelGroup'
import LineChart from './components/LineChart'
const lineChartData = {
......
}
export default {
name: 'DashboardAdmin',
components: {
GithubCorner,
PanelGroup,
LineChart
},
......
}
</script>
<style lang="scss" scoped>
......
</style>
在/src/views/newdashboard下建立components目录,拷贝vue-element-admin/src/views/admin/dashboard下的文件和文件夹:
/src/views/dashboard/admin/components/LineChart.vue
/src/views/dashboard/admin/components/PanelGroup.vue
/src/views/dashboard/admin/components/minxins
4.3. 迁移过程中遇到问题集锦
- “npm install”遇到的提示:
......
To install them, you can run: npm install --save echarts echarts/theme/macarons
To install it, you can run: npm install --save vue-count-to
注:解决方案见第5章。
- 启动服务webpack提示:
[Vue warn]: Error in mounted hook: “TypeError: Object(…) is not a function”
/src/views/newdashboard/components/LineChart.vue文件中
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
"./mixins/resize"指向/src/views/newdashboard/components/mixins/resize.js文件,文件中:
import { debounce } from '@/utils'
“@/utils”指向/src/utils/index.js文件,发现文件中没有“debounce”函数,需要从vue-element-admin工程中把代码拷贝移植过来。
- [Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components
出现这个错误的原因 检查一下你引入的组件里面是否在components里面写入子组件。
- /src/views/opeff/outlet/components/TransactionTable.vue?vue&type=script&lang=js&)
Module not found: Error: Can’t resolve ‘@/api/remote-search’ in ‘D:\VueApp\vue-admin-template-permission-control\src\views\opeff\outlet\components’
把/src/api/remote-search.js文件移植拷贝到工程中。
5. 增加图表组件ECharts
当在代码中引用ECharts、数字滚动等新增插件,需要在/package.json中注册插件,如下所示:
"dependencies": {
"axios": "0.18.1",
"core-js": "3.6.5",
"echarts": "4.2.1", //新增
"element-ui": "2.13.2",
"js-cookie": "2.2.0",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"vue": "2.6.10",
"vue-count-to": "1.0.13", //新增
"vue-router": "3.0.6",
"vuex": "3.1.0"
},
或者,手动安装echarts,npm install echarts --save。
注:在HBuilder X开发工具下,需要先删除目录/node_modules,并删除package-lock.json,修改package.json文件,增加“echarts”配置,重新npm install。
6. 图标处理
6.1. 菜单上的图标
路由文件(/src/router/index.js)中的icom的描述与图标对应。
path: 'newdashboard',
name: 'NewDashboard',
component: () => import('@/views/newdashboard/index'),
meta: { title: '首页', icon: 'dashboard' }
运行vue-element-admin项目,“Icons”菜单下能看到已经集成到的图标,按名称引用和拷贝。
6.2. 页面上的图标
例如/src/views/newdashboard/components/PanelGroup.vue文件需要图标,如下图所示,需要把图标peoples.svg拷贝到/src/icons/svg目录下。
7. 目录权限
做后台项目区别于做其它的项目,权限验证与安全性是非常重要的,可以说是一个后台项目一开始就必须考虑和搭建的基础核心功能。我们所要做到的是:不同的权限对应着不同的路由,同时侧边栏也需根据不同的权限,异步生成。这里先简单说一下,我实现登录和权限验证的思路。[2]
- 登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token,拿到token之后(我会将这个token存贮到cookie中,保证刷新页面后能记住用户登录状态),前端会根据token再去拉取一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息)。
- 权限验证:通过token获取用户对应的 role,动态根据用户的 role 算出其对应有权限的路由,通过 router.addRoutes 动态挂载这些路由。
7.1. 路由表定义菜单及权限
大多数系统都有根据用户权限,或者说角色,展示相应菜单/页面的需求,目录权限直接体现在/src/router/index中。
结合框架来实现目录的控制,如果是传统项目,一般是把目录结构整个存在后台数据库里,然后前端循环展示出来,但是这个在这里不需要这么麻烦,只需要把每个页面对应的权限保存起来就行了
/src/router/index表示目录为两个部分: constantRouterMap 与 asyncRouterMap
- constantRouterMap:主要是通用部分,每个用户都有的页面
- asyncRouterMap:需要进行权限过滤的页面
7.2. 根据角色选定菜单(权限)
通过“/src/permission.js ”代码,按角色控制选择菜单。
通过参考/mock/user.js,可以明确知道系统角色定义为admin和editor,参考如下:
const tokens = {
admin: {
token: 'admin-token'
},
editor: {
token: 'editor-token'
}
}
const users = {
'admin-token': {
roles: ['admin'],
introduction: 'I am a super administrator',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: 'Super Admin'
},
'editor-token': {
roles: ['editor'],
introduction: 'I am an editor',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: 'Normal Editor'
}
}
8. 效果
本实践后台采用Python开发,使用基于Tornado的pyrestful插件开发rest服务。后续详见《vue-element-admin/template+tornado(pyrestful)前后端分离框架实践(2)——登录过程与后端python服务》。
由于笔者水平有限,时间仓促,欢迎讨论交流。
参考:
[1]《vue-element-admin》
[2]《手摸手,带你用vue撸后台 系列二(登录权限篇)》 掘金 , 花裤衩 ,2017年5月
[3]《vue-element-admin登录流程》 CSDN博客 , 兔子零84 , 2019年09月
[4]《Vue 新手学习笔记:vue-element-admin 之登陆及目录权限控制》 CSDN博客 ,乐之终曲 ,2019年05月
[5]《Access-Control-Allow- 设置 跨域资源共享 CORS 详解》 CSDN博客 ,Normal Developer , 2017年12月
[6]《Cross-Origin Resource Sharing (CORS》) MDN web docs
[7]《使用vueAdmin开发后台管理系统(登录篇)》 CSDN博客 ,zw沐知 , 2020年7月
[8]《Nginx+Vue.js+Tornado前后端分离架构环境实践(2)》 CSDN博客 , 肖永威 2020年10月