树形控件:
<!--
显示菜单数据
树形控件
data 要显示的数据
show-checkbox 是否显示checkbox框数据
node-key: node的key 对应的菜单数据的编号
props 节点配置 {children(下级节点): '菜单数据中对应的下级名称', label(节点显示的名称): '菜单数据中的标题'}
default-expand-all 是否展开所有的节点
-->
<el-tree
ref="tree"
:data="menuList"
node-key="id"
show-checkbox
default-expand-all
:props="{children: 'children', label: 'title'}"
>
添加表单自定义验证
data () {
const checkMenus = (rule, value, callback) => {
// 获取树形控件的选择的节点
// this.$refs.tree.getCheckedKeys() 获取选中的节点的key
// this.$refs.tree.getHalfCheckedKeys() 获取半选中的节点的key
const selectMenus = [...this.$refs.tree.getCheckedKeys(), ...this.$refs.tree.getHalfCheckedKeys()]
if (selectMenus.length === 0) {
this.form.menus = '' // 还原表单数据中的菜单
// 没有选择任何的菜单
callback(new Error('请选择权限'))
} else {
this.form.menus = selectMenus // 把选择的权限赋值给表单数据
callback()
}
}
return {
title: '', // 对话框的标题
dialogFormVisible: true, // 是否显示对话框
form: {...defaultData}, // 复制一份默认数据
rules: {
rolename: [
{ required: true, message: '请输入角色名称', trigger: 'blur' }
],
menus: [
{ validator: checkMenus, trigger: 'change' }
]
}
}
},
角色管理:
编写页面布局->写添加页面的界面(选择对话框组件和合适的表单组件,处理表单的验证)->编写接口文件(添加功能)->编写对应的vuex模块(获取数据)->编写接口文件(获取数据)->显示数据(使用合适的表格组件)->编写修改的功能(界面和添加一样)->编辑接口文件(修改功能)->做删除->编辑接口文件(删除功能)
编辑时给表单赋值:
// 修改的时候设置表单数据
setFormData (data) {
this.form = {...data}
// 给树形控件赋值
// data.menus '1,2,3'
const keys = data.menus.split(',')
this.checkStrictly = true // 在渲染树形组件之前关闭父子节点的联动选择
this.$nextTick(() => {
// 将回调延迟到下次 DOM 更新循环之后执行。在本次dom完全渲染之后触发
this.$refs.tree.setCheckedKeys(keys) // 参数必须是数组
this.checkStrictly = false // 在赋值之后开启父子节点的联动选择
})
}
角色的接口文件
// /api/role.js
import http from './http'
// 添加角色
export const addRole = (data) => {
return http.post('/roleadd', data)
}
// 修改角色
export const updateRole = (data) => {
// 判断data中是否包含id属性且大于0
if (!Reflect.has(data, 'id') || data.id <= 0) {
return Promise.reject(new Error('缺少ID参数或id参数错误'))
}
return http.post('/roleedit', data)
}
// 获取角色列表
export const getRoleList = () => {
return http.get('/rolelist')
}
// 删除菜单
export const deleteRole = (id) => {
return http.post('/roledelete', { id })
}
管理员管理
表单验证
data () {
// 自定义验证规则
// value就是要验证的表单项的值
// callback: function 输出验证的信息
// 验证通过调用callback() 验证没有通过调用callback(Error对象)
const checkRole = (rule, value, callback) => {
// 如果值不为0代表通过
// 是菜单的时候链接就必填
if (value === 0) {
callback(new Error('请选择角色'))
} else {
callback()
}
}
const checkPassword = (rule, value, callback) => {
// 添加时必填,修改时可以不填
if (this.form.id > 0) {
callback()
} else {
if (value === '') {
callback(new Error('请输入密码'))
} else {
callback()
}
}
}
return {
dialogFormVisible: false,
title: '', // 对话框的标题
form: {...defaultData}, // 复制一份默认数据
rules: {
// 0也代表已填
// 如果没有使用自定义验证,那规则的属性就必须在表单的数据中存在
roleid: [
{ validator: checkRole, trigger: 'change' }
],
username: [
{ required: true, message: '请输入账号', trigger: 'blur' }
],
password: [
{ validator: checkPassword, trigger: 'blur' }
]
}
}
},
分页显示管理员
管理员的数据接口
import http from './http'
// 登录
export const login = (username, password) => {
if (!username || !password) {
return Promise.reject(new Error('账号或密码为空'))
}
return http.post('/userlogin', {
username,
password
})
}
// 添加管理员
export const addUser = (data) => {
return http.post('/useradd', data)
}
// 删除管理员
export const deleteUser = (uid) => {
return http.post('/userdelete', { uid })
}
// 修改管理员
export const updateUser = (data) => {
// 判断data中是否包含id属性且大于0
if (!Reflect.has(data, 'id') || data.id <= 0) {
return Promise.reject(new Error('缺少ID参数或id参数错误'))
}
return http.post('/useredit', data)
}
/*
@ 分页获取管理员数据
@param page number 当前的页码
@param size number 每页获取的数量
@return Promise
*/
export const getPageUser = (page = 1, size = 10) => {
return http.get('/userlist', {
params: {
page,
size
}
})
}
// 获取管理员总数量
export const getUserTotal = () => {
return http.get('/usercount')
}
vuex的管理员模块
// 导入会员的接口文件(分页获取)
import { getPageUser, getUserTotal } from '@/api/user'
export default {
namespaced: true,
state: {
list: [],
page: 1, // 当前的页码
size: 10, // 每页获取的数据
total: 0 // 管理员总数量
},
mutations: {
SET_LIST (state, list) {
state.list = list
},
SET_TOTAL (state, total) {
state.total = total
},
SET_PAGE (state, page) {
state.page = page
}
},
actions: {
getUserList ({ commit, state }) {
getPageUser(state.page, state.size).then(res => {
commit('SET_LIST', res)
})
},
getUserTotal ({ commit }) {
getUserTotal().then(res => {
commit('SET_TOTAL', res[0].total || 0)
})
}
}
}
分页组件
<!--
分页组件
layout 组件布局,子组件名用逗号分隔 sizes, prev, pager, next, jumper, ->, total, slot
total: 总数量
page-size: 每页的数量
@current-change 当前页码发生改变时触发
至少有2页时才显示分页组件
-->
<el-pagination
@current-change="onCurrentChange"
class="page-container"
:page-size="size"
background
layout="prev, pager, next"
:total="total"
v-if="total > size"
>
</el-pagination>
删除时修改页码
this.$message.success({
message: '删除成功',
onClose: () => {
// 重新获取总数量
this.$store.dispatch('user/getUserTotal')
// 如果当前页的数据已经全部删除,就修改page
// 刷新列表数据之前,要删除的数据还没有变化
if (this.list.length === 1) {
let page = 0
if (this.page === 1) {
page = 1
} else {
page = this.page - 1
}
this.$store.commit('user/SET_PAGE', page)
}
// 刷新列表数据
this.$store.dispatch('user/getUserList')
}
})
菜单生成
在主页面的Menu组件中获取登录用户的菜单并生成菜单html
<template>
<el-menu
router
:default-active="$route.path"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<!--没有下级菜单的菜单项-->
<el-menu-item index="/statistics">
<i class="el-icon-s-home"></i>
<span slot="title">首页</span>
</el-menu-item>
<template v-for="(menu,index) of menuList">
<!--有下级菜单-->
<el-submenu :index="'1' + index" :key="menu.id" v-if="menu.children && menu.children.length > 0">
<!--一级菜单的名称-->
<template slot="title">
<i v-if="menu.icon !== ''" :class="menu.icon"></i>
<span>{{menu.title}}</span>
</template>
<!--二级菜单项-->
<el-menu-item-group>
<el-menu-item v-for="item of menu.children" :key="item.id" :index="item.url">
<i v-if="item.icon !== ''" :class="item.icon"></i>
<span slot="title">{{item.title}}</span>
</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-menu-item :index="menu.url" v-else :key="menu.id">
<i class="el-icon-s-home"></i>
<span slot="title">首页</span>
</el-menu-item>
</template>
</el-menu>
</template>
<script>
export default {
data () {
return {
menuList: []
}
},
mounted () {
const userInfo = JSON.parse(sessionStorage.getItem('user'))
this.menuList = userInfo.menus || []
console.log(userInfo)
}
}
</script>
添加导航守卫阻止用户访问没有权限的页面
// 拦截
router.beforeEach((to, from, next) => {
// 设置页面标题
document.title = to.meta.title || '小U商城后台管理系统'
// 如果要跳转的页面不是登录页面,就必要要登录成功之后才能访问
if (to.path === '/login') {
// 要跳转就是登录页面,不做拦截
next()
} else {
// 要跳转不是登录页面,就必要要登录成功之后才能访问
let userInfo = sessionStorage.getItem('user')
if (!userInfo) {
// 没有登录
next('/login')
} else {
// 判断登录用户是否拥有对应的权限
userInfo = JSON.parse(userInfo)
// 首页是所有的用户都能访问
userInfo.menus_url.push('/', '/statistics')
if (userInfo.menus_url.includes(to.path)) { // userInfo.menus_url就是当前登录用户能够访问路由的path数组
next()
} else {
// 没有权限访问就自动跳转到首页
next('/')
}
}
}
})