由于项目是边学习边进行实践,所以对应的注释会比较多。
在最近的一段时间,一直负责公司的后台管理系统的开发和维护,整个技术栈涉及到react + redux + redux-thunk + ant design
,并且将react
升级到了16.8
最新版本,尝试了react hooks
的使用。之后自己也在github
写了一个react
版本 的后台管理系统的模板。
这之前一直有用vue
写一些组件,但是却一直没有写过后台管理系统,所以这次既算是对vue
写后管理系统的一次尝试,也是自己对后台管理系统相关业务需求和vue
整体知识的一个总结,方便之后自己复习和回顾,也希望能帮助到社区的小伙伴。
该项目是一个vue
技术栈结合express+mongodb
实现的一个后台管理系统,其中后台只是实现了登录注册等用户接口以及一个列表的增删改查。
整个项目以前端为主,是一个通用的后台管理系统,并且集成了富文本、echarts
并进行了二次封装。由于element-ui
提供的icon
图表较少,自己也在项目中加入了一个AdminIcon
组件。
项目中的大多数需求都是根据自己工作中碰到需求的一个总结,有可能带有一些片面性,在使用的时候要根据自己的需求进行改进。项目中也通过几个真实的后台接口,模拟了一个简单的增删改查。在写登录注册时也对jsonwebtoken
进行了简单实践,这也算是自己在后端接口方面的一个实战。
想要学习node
的小伙伴可以点击这里:node
入门笔记 ,这是我在网上整理的一份node
入门笔记,喜欢的可以star
。
git clone git@github.com:wangkaiwd/vue-admin.git
cd vue-admin
# 启动项目
yarn
yarn start
# 打包
yarn build:test
yarn build:pro
# 打包文件分析
yarn build:analyze
注意事项:
- 本地开发的话可以结合对应的真实接口来使用,接口
dmoe
我写到了另外一个仓库:node-interface-demo
- 使用真实接口开发的话要注释
axios
的baseURL
,并在vue.config.js
中配置服务代理
前端是以vue
为主的技术栈,包括如下:
vue
vue-router
vuex
后端是以express
为主结合mongodb
数据库完成:
express
mongodb
- 后台接口
- 登录
- 注册
- 退出
- 使用
token
实现身份认证 - 列表数据(增、删、改、查、分页)
vue
组件封装- 富文本组件(图片上传暂未实现)
-
echarts
组件 - 区域分割组件
- 项目模块
-
axios
请求封装 -
list
页面增删改查demo
- 左侧导航栏收缩
-
mock
数据接入
-
axios
:基于Promise
的http
客户端,用于浏览器和node.js
qs
:支持解析嵌套的querystring
。通俗来讲就是可以将以key1=val1&key2=val2&...
格式的字符串转换为对象格式{key1:val1,key2:val2,...}
elemente ui
:基于Vue 2.0
的桌面端组件库dayjs
: 一个轻量的日期处理库,用法和moment.js
类似countup.js
: 一个有趣的数字动画库wangeditor
: 基于javascript和css开发的 Web富文本编辑器, 轻量、简洁、易用、开源免费echarts
:一个使用 JavaScript 实现的开源可视化库
在实际工作中,前端是不可能一个人完成权限控制的,我们需要与后端配合。这个时候后端需要返回给我们类似这样的数据:
const data = {
page: {
'dashboard': true,
'main': true,
'editTable': false,
'editor': true,
'list': true,
'components': true,
'splitPanel': true,
'dirTree': true,
'form': true,
'mapForm': true
},
component: {
'list:edit':true,
'list:publish': true
}
}
在路由列表配置的时候,我们设置了meta
属性,通过meta
中的access
属性来过滤出符合有权限的路由列表。这里后端返回的数据包含所有的权限,那我们可以通过beforeEach
全局前置路由守卫来判断将要进入的页面是否有权限,没有权限跳转401
页面
const noAuth = to.meta.access && !store.getters['router/page'][to.meta.access] && to.path !== '/401';
if (noAuth) {
return next({ path: '/401', replace: true });
}
由于menus
会在侧边栏组件,登录组件以及路由守卫和初始化组件(刷新页面重新获取信息)的时候用到,而如果我们的权限如果精确到操作按钮的话,那么几乎每个页面都可能用到,所以我们将这些信息存储到vuex
中,单独用一个router modules
来进行管理:
// 目录: store -> modules -> routers
/**
* 根据权限信息过滤路由生成的侧边栏
* FIXME: 在调用之前注意要深拷贝
* @param array 侧边栏数组
* @param authInfo 权限信息
* @returns {array} 返回过滤后的新数组
*/
const getAuthMenus = (array, authInfo) => {
return array.filter(item => {
if (item.meta.access && authInfo.page[item.meta.access]) {
if (item.children) item.children = getAuthMenus(item.children, authInfo);
return true;
}
});
};
const router = {
namespaced: true,
state: {
authInfo: {},
menus: []
},
getters: {
page (state) {
return state.authInfo.page || {};
},
component (state) {
return state.authInfo.component || {};
}
},
mutations: {
SET_MENUS (state, { authInfo, menus }) {
localStorage.setItem('authInfo', JSON.stringify(authInfo));
state.menus = menus;
state.authInfo = authInfo;
}
},
actions: {
GET_MENUS ({ commit }) {
// 调用时机:1. 用户登录之后, 2. 权限发生变化之后
return fetchRouter().then(
res => {
// 当访问不存时要跳转401页面
// 这里深拷贝之后component属性会消失,需要留意一下
const copyMenus = JSON.parse(JSON.stringify(menus));
const authMenus = getAuthMenus(copyMenus, res.data);
commit('SET_MENUS', { authInfo: res.data, menus: authMenus });
return Promise.resolve({ authInfo: res.data, menus: authMenus });
}
);
}
}
};
参考了社区优秀的vue-admin
项目,给各位大佬递茶: