树形控件:
<!--显示菜单数据树形控件data 要显示的数据show-checkbox 是否显示checkbox框数据node-key: node的key 对应的菜单数据的编号props 节点配置 {children(下级节点): '菜单数据中对应的下级名称', label(节点显示的名称): '菜单数据中的标题'}default-expand-all 是否展开所有的节点--><el-treeref="tree":data="menuList"node-key="id"show-checkboxdefault-expand-all:props="{children: 'children', label: 'title'}">
添加表单自定义验证
data () {const checkMenus = (rule, value, callback) => {// 获取树形控件的选择的节点// this.$refs.tree.getCheckedKeys() 获取选中的节点的key// this.$refs.tree.getHalfCheckedKeys() 获取半选中的节点的keyconst 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.jsimport http from './http'// 添加角色export const addRole = (data) => {return http.post('/roleadd', data)}// 修改角色export const updateRole = (data) => {// 判断data中是否包含id属性且大于0if (!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属性且大于0if (!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, slottotal: 总数量page-size: 每页的数量@current-change 当前页码发生改变时触发至少有2页时才显示分页组件--><el-pagination@current-change="onCurrentChange"class="page-container":page-size="size"backgroundlayout="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 = 0if (this.page === 1) {page = 1} else {page = this.page - 1}this.$mit('user/SET_PAGE', page)}// 刷新列表数据this.$store.dispatch('user/getUserList')}})
菜单生成
在主页面的Menu组件中获取登录用户的菜单并生成菜单html
<template><el-menurouter: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('/')}}}})