Vue-admin-template笔记(一)
Vue-admin-template项目一、关于Vue-admin-template1.1 介绍vue-element-admin 是一个后台前端解决方案,它基于 vue 和 element-ui实现。可以把 vue-element-admin当做工具箱或者集成方案仓库,在 vue-admin-template 的基础上进行二次开发,想要什么功能或者组件就去 vue-element-admin 那
Vue-admin-template项目
一、关于Vue-admin-template
1.1 介绍
vue-element-admin 是一个后台前端解决方案,它基于 vue 和 element-ui实现。
可以把 vue-element-admin
当做工具箱或者集成方案仓库,在 vue-admin-template
的基础上进行二次开发,想要什么功能或者组件就去 vue-element-admin
那里复制过来。
首先前端目录结构
├── build // 构建相关
├── bin // 执行脚本
├── public // 公共文件
│ ├── favicon.ico // favicon图标
│ └── index.html // html模板
├── src // 源代码
│ ├── api // 所有请求
│ ├── assets // 主题 字体等静态资源
│ ├── components // 全局公用组件
│ ├── directive // 全局指令
│ ├── layout // 布局
│ ├── router // 路由
│ ├── store // 全局 store管理
│ ├── styles // css样式
│ ├── utils // 全局公用方法
│ ├── views // view
│ ├── App.vue // 入口页面
│ ├── main.js // 入口 加载组件 初始化等
│ ├── permission.js // 权限管理
│ └── settings.js // 系统配置
├── .editorconfig // 编码格式
├── .env.development // 开发环境配置
├── .env.production // 生产环境配置
├── .env.staging // 测试环境配置
├── .eslintignore // 忽略语法检查
├── .eslintrc.js // eslint 配置项
├── .gitignore // git 忽略项
├── .travis.yml // travis.yml
├── babel.config.js // babel.config.js
├── package.json // package.json
└── vue.config.js // vue.config.js
1.2 项目安装
# 项目地址
https://github.com/PanJiaChen/vue-admin-template
# 进入项目目录
cd vue-admin-template
# 安装依赖
npm install
# 本地开发 启动项目
npm run dev
二、登录模块
2.1 运行流程
-
login页面进行表单验证,(login/index.vue)
-
然后验证成功点击按钮,将数据发送到vuex,有actions的方法(store/modules/user.js)
-
发送请求login,发送请求时会进行一个请求拦截,会在请求头header里加入X-Token,
-
(utils/request.js)返回res以及其他数据如权限等并存储在vuex和cookie,login会返回一个Promise对象,方便login页面调用then或catch操作。
流程图
2.2 功能实现
首先是页面的搭建html部分
<template>
<div class="login-container">
<el-form
ref="loginForm"
:model="loginForm"
:rules="loginRules"
class="login-form"
auto-complete="on"
label-position="left"
>
<div class="title-container">
<h3 class="title">电商管理后台</h3>
</div>
<el-form-item prop="username">
<span class="svg-container">
<svg-icon icon-class="user" />
</span>
<el-input
ref="username"
v-model="loginForm.username"
placeholder="Username"
name="username"
type="text"
tabindex="1"
auto-complete="on"
v-focus
/>
</el-form-item>
<el-form-item prop="password">
<span class="svg-container">
<svg-icon icon-class="password" />
</span>
<el-input
:key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
placeholder="Password"
name="password"
tabindex="2"
auto-complete="on"
@keyup.enter.native="handleLogin"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon
:icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
/>
</span>
</el-form-item>
<el-button
:loading="loading"
type="primary"
style="width: 100%; margin-bottom: 30px"
@click.native.prevent="handleLogin"
>Login</el-button
>
<div class="tips">
<span style="margin-right: 20px">username: admin</span>
<span> password: any</span>
</div>
</el-form>
</div>
</template>
2.3 使用的form实现表单的数据绑定
在vue中,要用:model属性来绑定表单,在
data函数中规定返回的值的格式。
<script>
export default {
data(){
return{
//这是登录表单的数据绑定
loginForm:{
username:'',
password:''
}
};
}
};
</script>
不要忘记给el-input 添加属性type="password"来隐藏密码。
2.4 使用rules对表单做一些验证
在data中先定义一些规则
<script>
export default {
data(){
return{
//这是登录表单的验证规则
loginRules: {
username: [{ required: true, trigger: 'blur' },
{ min: 5, max: 12, trigger: 'blur', message: '用户名5到12位' }],
password: [{ required: true, trigger: 'blur' },
{ min: 5, max: 12, trigger: 'blur', message: '密码5到12位' }]
},
};
}
};
</script>
然后表单使用定义好的规则
注意: prop:与规则中的name属性相同
<el-form
ref="loginForm"
:model="loginForm"
:rules="loginRules" // 绑定已定义好的规则
class="login-form"
auto-complete="on"
label-position="left"
>
2.5 提交表单进行表单验证及http请求
async handleLogin () {
try {
await this.$refs.loginForm.validate() // 提交前做一次表单验证
this.loading = true
await this.$store.dispatch('user/login', this.loginForm) // http请求
this.$router.push({ path: '/' }) // 验证成功后进行页面跳转
this.loading = false
} catch (err) {
this.loading = false
}
}
三、主页模块
3.1 主页的token拦截处理
3.1.1 权限拦截的流程图
已经完成了登录的过程,并且存储了token,但是此时主页并没有因为token的有无而被控制访问权限
在基础框架阶段,**src/permission.js
**是专门处理路由权限的,所以在这里处理
3.1.2 代码实现
import router from './router'
import store from './store'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login', '/404'] // no redirect whitelist
router.beforeEach((to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
console.log(store.getters.token)
if (store.getters.token) {
// 如果有 token,判断是否请求的是登录页
if (to.path === '/login') {
// 如果请求的是登录页,因为具有 token ,表明已经登录了,就直接跳转主页即可
next('/')
} else {
// 如果请求的不是登录页,那就直接放行
next()
}
} else {
// 如果没有 token,说明没有登录,则判断用户请求的页面是否在白名单之中
if (whiteList.indexOf(to.path) > -1) {
// 直接放行
next()
} else {
next('/login')
}
}
NProgress.done() // 手动强制关闭一次 为了解决 手动切换地址时 进度条的不关闭的问题
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})
在导航守卫的位置,添加了NProgress的插件,可以完成进入时的进度条效果
3.2 主页搭建
3.2.1 设置左侧导航
左侧导航组件的样式文件 styles/siderbar.scss
设置左侧导航图片
.scrollbar-wrapper {
background: url('~@/assets/common/leftnavBg.png') no-repeat 0 100%;
}
显示左侧logo图片 src/setttings.js
module.exports = {
title: '小优电商后台管理系统',
fixedHeader: false,
sidebarLogo: true // 显示logo
}
设置头部图片结构 src/layout/components/Sidebar/Logo.vue
<div class="sidebar-logo-container" :class="{'collapse':collapse}">
<transition name="sidebarLogoFade">
<router-link key="collapse" class="sidebar-logo-link" to="/">
<img src="@/assets/common/logo.png" class="sidebar-logo ">
</router-link>
</transition>
</div>
设置大图和小图的样式
&.collapse {
.sidebar-logo {
margin-right: 0px;
width: 32px;
height: 32px;
}
}
// 小图样式
.sidebar-logo {
width: 140px;
vertical-align: middle;
margin-right: 12px;
}
// 大图样式
3.2.2 设置头部内容的布局和样式
头部组件位置 layout/components/Navbar.vue
添加公司名称,注释面包屑
<div class="app-breadcrumb">
北京小优智慧城市科技优先公司
<span class="breadBtn">V1.0</span>
</div>
<!-- <breadcrumb class="breadcrumb-container" /> -->
右侧下拉菜单设置
<div class="right-menu">
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<img src="@/assets/common/bigUserHeader.png" class="user-avatar">
<span class="name">管理员</span>
<i class="el-icon-caret-bottom" style="color:#fff" />
</div>
<el-dropdown-menu slot="dropdown" class="user-dropdown">
<router-link to="/">
<el-dropdown-item>
首页
</el-dropdown-item>
</router-link>
<a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/">
<el-dropdown-item>邮箱</el-dropdown-item>
</a>
<el-dropdown-item divided @click.native="logout">
<span style="display:block;">退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
四、路由模块
4.1 静态路由
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/import',
component: Layout,
hidden: true,//隐藏在左侧菜单中
children: [{
path: '',//二级路由path什么都不写表示二级默认路由
component: () => import('@/views/import')
}]
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: 'Dashboard', icon: 'dashboard' }
}]
},
4.2 动态路由封装成了组件先引入
// 引入动态路由
import user from './modules/user'
import role from './modules/role'
import rights from './modules/rights'
import goods from './modules/goods'
import category from './modules/category'
import report from './modules/report'
// 动态路由
export const permissionRouter = [ user, role, rights, goods, category, report]
4.3 改变路由模式
const createRouter = () => new Router({
mode: 'history', // 可以改路由hash和history模式
base:'/hr', //配置项目的基础地址
scrollBehavior: () => ({ y: 0 }),
// routes: [...constantRoutes, ...permissionRouter]
routes: [...constantRoutes]
})
4.4 左侧菜单路由的显示和隐藏
设置hidden为 true就不会在左侧显示了
{
path: 'detail/:id', // query传参 动态路由传参
component: () => import('@/views/user/detail'),
hidden: true, // 不在左侧菜单显示
meta: {
title: '用户详情' // 标记当前路由规则的中文名称 后续在做左侧菜单时 使用
}
},
五、用户管理
5.1 页面结构搭建
<template>
<div class="dashboard-container">
<div class="app-container">
<common-tools :show-before="true">
<span slot="before">共166条记录</span>
<template slot="after">
<el-button size="small" type="warning">导入</el-button>
<el-button size="small" type="danger">导出</el-button>
<el-button size="small" type="primary">新增用户</el-button>
</template>
</common-tools>
<!-- 放置表格和分页 -->
<el-card>
<el-table border>
<el-table-column label="序号" sortable="" />
<el-table-column label="用户名" sortable="" />
<el-table-column label="工号" sortable="" />
<el-table-column label="手机" sortable="" />
<el-table-column label="角色" sortable="" />
<el-table-column label="创建时间" sortable="" />
<el-table-column label="账户状态" sortable="" />
<el-table-column label="操作" sortable="" fixed="right" width="280">
<template>
<el-button type="text" size="small">查看</el-button>
<el-button type="text" size="small">角色</el-button>
<el-button type="text" size="small">编辑</el-button>
<el-button type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-row
type="flex"
justify="center"
align="middle"
style="height: 60px"
>
<el-pagination layout="prev, pager, next" />
</el-row>
</el-card>
</div>
</div>
</template>
5.2 页面数据的获取及渲染
// 获取页面列表数据
async getUserList () {
this.loading = true
const params = {
query: '',
pagenum: this.pagenum,
pagesize: this.pageSize,
total: 0
}
const { data: { data: { pagenum, total, users } } } = await getUserList(params)
this.userList = users
this.total = total
this.pagenum = pagenum
this.loading = false
}
5.3 过滤器解决时间格式问题
使用moment解决时间格式问题
import moment from 'moment'
export default {
filterTime: function (value) {
return moment(value * 1000).format('YYYY-MM-DD HH:mm:ss')
}
}
5.4 展示部门信息
5.4.1 编写api
import request from '@/utils/request'
/**
* 获取部门列表
*/
export function getDepartMent() {
return request({
url: `department`,
method: 'get'
})
}
5.4.2 获取部门数据,转化成需要的格式
import { getDepartMent } from '@/api/department'
import { tranListToTreeData } from '@/utils'
// 获取所有部门
async getAllDepartment() {
this.showTree = true
this.loading = true
const res = await getDepartMent()
this.treeData = tranListToTreeData(res, 0)
this.loading = false
}
data 中新增3个变量
treeData: [], // 存储部门的树形数据
showTree: false, // 部门文本框获取焦点时,设置为true,展示部门信息
loading: false, // 显示或隐藏进度
5.4.3 部门获取焦点时,展示数据
<el-form-item label="部门" prop="department_title">
<el-input
v-model="userForm.department_title"
@focus="getAllDepartment"
/>
<el-tree
v-if="showTree"
v-loading="loading"
:data="treeData"
:props="{ label: 'department_title' }"
@node-click="handleNodeClick"
/>
</el-form-item>
点击部门赋值表单数据
选择部门触发
handleNodeClick(node) {
console.log(node)
this.userForm.department_title = node.department_title
this.userForm.department_id = node.department_id
this.showTree = false
},
六、 权限管理
6.1 RBAC权限设计
RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。
如下图
6.2 权限模块
// vuex的权限模块
import { permissionRouter, constantRoutes } from '@/router'
// vuex 中的permission模块用来存放当前 静态路由 + 当前用户 的权限路由
const state = {
routes: constantRoutes // 所有人默认拥有静态路由
}
const mutations = {
// newRoutes可以认为是 用户登录 通过权限多得到的动态路由的部分
setRoutes (state, newRoutes) {
state.routes = [...constantRoutes, ...newRoutes]
}
}
const actions = {
filterRoutes (context, menus) {
const routes = []
menus.forEach(key => {
routes.push(... permissionRouter.filter(item => item.name === key))
})
routes.push( { path: '*', redirect: '/404', hidden: true })
context.commit('setRoutes',routes)
return routes
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
// vuex 中的permission模块用来存放当前 静态路由 + 当前用户 的权限路由
const state = {
routes: constantRoutes // 所有人默认拥有静态路由
}
const mutations = {
// newRoutes可以认为是 用户登录 通过权限多得到的动态路由的部分
setRoutes (state, newRoutes) {
state.routes = […constantRoutes, …newRoutes]
}
}
const actions = {
filterRoutes (context, menus) {
const routes = []
menus.forEach(key => {
routes.push(… permissionRouter.filter(item => item.name === key))
})
routes.push( { path: ‘*’, redirect: ‘/404’, hidden: true })
context.commit(‘setRoutes’,routes)
return routes
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
更多推荐
所有评论(0)