1.搭建项目工程
vue2基本目录结构:
element.js(引入使用element组件)、main.js(设置后端路径前缀和引入一些文件)、index.js(路由)的代码
element.js:
import Vue from 'vue'
import { Button,Form,FormItem,Input,Message,Container,Header,Aside,Main,Menu,
Submenu,
MenuItem,
Breadcrumb,
BreadcrumbItem,
Card,
Row,
Col,
Table,
TableColumn,
Switch,
Tooltip,
Pagination,
Tag,
Dialog,
Tree,
MessageBox
} from 'element-ui'
Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)
Vue.use(Container)
Vue.use(Header)
Vue.use(Aside)
Vue.use(Main)
Vue.use(Menu)
Vue.use(Submenu)
Vue.use(MenuItem)
Vue.use(Breadcrumb)
Vue.use(BreadcrumbItem)
Vue.use(Card)
Vue.use(Row)
Vue.use(Col)
Vue.use(Table)
Vue.use(TableColumn)
Vue.use(Switch)
Vue.use(Tooltip)
Vue.use(Pagination)
Vue.use(Tag)
Vue.use(Dialog)
Vue.use(Tree)
Vue.prototype.$message = Message
Vue.prototype.$confirm = MessageBox.confirm
main.js代码:
import Vue from 'vue'
import ElementUI from 'element-ui';
import App from './App.vue'
import router from './router'
import store from './store'
import './plugins/element.js'
//导入全局的css样式
import './assets/login.css'
//导入第三方样式
import './assets/fonts/iconfont.css'
Vue.config.productionTip = false
//导入axios,进行axios请求
import axios from 'axios'
axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/' //设置URL请求路径的前缀
/**
* 实现每次请求服务器都携带着token信息,服务器识别无误后进行数据的传递
* 通过拦截器来实现每次请求都携带token
*/
axios.interceptors.request.use(config => {
//将token信息添加在请求信息header中
config.headers.Authorization = window.sessionStorage.getItem("token")
console.log(config);
return config
})
Vue.prototype.$http = axios
new Vue({
router,
store,
render: function (h) { return h(App) }
}).$mount('#app')
index.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/login.vue' //导入login.vue
import Home from '../components/home.vue'
import Users from '../components/users.vue'
import Welcome from '../components/welcome.vue'
import Privileges from '../components/Privileges.vue'
import Roles from '../components/Roles.vue'
Vue.use(VueRouter)
const routes = [
//配置路径,使访问根组件时直接访问login.vue页面
{path:'/',redirect:'/login'},
{path:'/login',component:Login},
{path:'/home',component:Home,
redirect:'/welcome',
children:[
{path:'/welcome',component:Welcome},
{path:'/users',component:Users}, //users的路径访问
{path:'/rights',component:Privileges}, //Privileges的路径访问
{path:'/roles',component:Roles}
]
}
]
const router = new VueRouter({
routes
})
/**
* 挂载路由导航守卫
* 实现在没有登录的情况下不能访问下一个页面
*/
router.beforeEach((to,form,next) => {
/**
* to:要访问的页面,比如这里是shopping页面
* form:从哪个路径跳转过来的,比如这里是从login页面
* next:该函数控制本次访问是否可以正常执行
*/
console.log(to.path);
if(to.path == '/login') return next() //可以访问(放开)
const current_token = window.sessionStorage.getItem('token'); //取出token信息
console.log(current_token); //token信息
if(!current_token) return next('/login') //!current_token表示不存在token信息,说明没有登录,那就直接跳转到登录页面
//否则(登录了,有token信息),就放行
next()
})
export default router //导出router
通过VUE UI来搭建项目(黑窗口输入vue ui回车在浏览器中打开 Vue CLI)
-
添加插件:安装element UI(在)
-
添加依赖:安装axios依赖,less依赖,less-loader依赖
-
在此平台里再次启动看是否有问题(第一次是在node后端里进行启动)
2.启动服务端程序
-
配置MySQL数据:通过phpstudy的MySQL管理器的MySQL导入导出功能将数据导入到数据库中
-
启动服务端Node程序:之前启动之前需要通过 npm install 安装依赖,然后通过 node ./app.js 启动服务端程序。
-
测试服务端接口是否可以正常访问
3.登陆界面的开发
界面原型:
改造APP.vue
删除APP.vue里面初始化(template、script、style中的代码)
login.vue组件添加
-
在components中删除helloword.vue并且删除引用到helloword.vue的地方
-
再在components中新建login.vue组件,并完成页面的布局,再将此组件添加到根组件(App.vue)中
先将login.vue添加到根组件中,使其能够正常显示
App.vue:
<template>
<!-- 视图查看 此标签即可使login.vue正常显示-->
<router-view></router-view>
</template>
<script>
export default {
}
</script>
<style>
</style>
在router目录下的index.js中将根路径的访问目标改为login组件
import Vue from 'vue'
import VueRouter from 'vue-router'
import login from '../components/login.vue' //导入login.vue
Vue.use(VueRouter)
const routes = [
//配置路径,使访问根组件时直接访问login.vue页面
{path:'/',redirect:'/login'},
{path:'/login',component:login}
]
const router = new VueRouter({
routes
})
export default router //导出router
login.vue:
<template>
<div class="login_continer">
<div class="login_box">
<!-- 显示logo图标 -->
<div class="avatar_box">
<img src="../assets/logo.png">
</div>
<!-- 显示表单 用到了element UI组件-->
<el-form label-width="0px" class = "login_form">
<!-- 输入用户名 -->
<el-form-item>
<el-input></el-input>
</el-form-item>
<!-- 输入密码 -->
<el-form-item>
<el-input></el-input>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
name: "app"
};
</script>
<style lang="less" scoped> //less是为了用来打包处理css代码
//scoped是使这个css样式只在此组件有效,防止样式的冲突
.login_continer {
background-color: cadetblue;
height: 100%;
}
.login_box {
width: 450px;
height: 300px;
background-color: #ffffff;
border-radius: 10px;
position: absolute;
left: 50%;
top: 50%;
//配合上面两个使其居中显示
transform: translate(-50%, -50%);
.avatar_box {
height: 130px;
width: 130px;
border: 1px solid #eee;
border-radius: 50%;
padding: 10px;
box-shadow: 0 0 10px #ddd; //加上阴影
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
img {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #eee;
}
}
}
.login_form{
position: absolute;
bottom: 10px;
width: 100%;
box-sizing: border-box;
padding: 0 30px;
}
.btns{
display: flex;
justify-content: flex-end;
}
</style>
因为这里用到了element组件,要引入elementui的相应elementui样式
element.js:
import Vue from 'vue'
import { Button,Form,FormItem,Input} from 'element-ui' //引入
//使用
Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)
对于session的理解
-
用户登录成功之后,需要将用户的token信息保存到Session当中去。
-
token:服务端随机生成后返回给客户端的信息
-
作用:客户端用来保持跟服务端的会话(连接)
-
token的有效范围:只在一次会话当中,也就是在session中有效。
-
-
session可以表示为一次会话,例如:从通话开始到通话结束,也可以理解为从打开浏览器到关闭浏览器的一次行为。
-
token在会话结束后,也会被浏览器自动删除掉。
-
控制项目页面的访问权限
-
企业级的应用系统在没有登录的情况下是不能有访问权限的。
-
类似于教务管理系统,在没有登录的情况下是没法查询学生信息的。
-
实现方式:挂载路由导航守卫
//index.js:
import home from '../components/home.vue' //导入home.vue
{path:'/home',component:home} //home的路径访问
/*
挂载路由导航守卫:
实现在没有登录的情况下不能访问下一个页面
*/
router.beforeEach((to,form,next) => {
/**
* to:要访问的页面,比如这里是shopping页面
* form:从哪个路径跳转过来的,比如这里是从login页面
* next:该函数控制本次访问是否可以正常执行
*/
console.log(to.path);
if(to.path == '/login') return next() //可以访问(放开)
const current_token = window.sessionStorage.getItem('token'); //取出token信息
console.log(current_token); //token信息
if(!current_token) return next('/login') //!current_token表示不存在token信息,说明没有 //登录,那就直接跳转到登录页面,意思是让他先登录
//否则(登录了,有token信息),就放行
next()
})
-
涉及到的知识或新点(个人觉得):
1.组件实现页面的展示:要将组件引入到根组件App.vue中,而且要在router/index.js中进行路由
2.用到了elementUI的组件,特别方便 网址:Element - The world's most popular Vue UI framework
3.要引入elementUI中用到的组件:例如button,input,form.....
4.token的理解,在类似于电商的项目中对于访问页面中是必须携带的
登录界面到此完成!即将进入到主页的开发
4.主界面
其中涉及到知识点和注意的点都在代码中写了注释
Home界面格式和菜单数据展示
界面原型:
整体布局
<el-container>
<!-- 头部区域 -->
<el-header>
<div>
<img src = "../assets/images/logo.png">
<span>电商后台管理系统</span>
</div>
<!--在右侧加一个退出按钮-->
<el-button type = "info" @click = ”loginOut“>退出</el-button>
</el-header>
<!-- 主体区域 -->
<el-container>
<!-- 左侧菜单栏 -->
<el-aside width="200px"> <!--动态显示宽度-->
<h5>
Aside
</h5>
</el-aside>
<!-- 右侧内容展示区域 -->
<el-main>
<h5>Main</h5>
</el-main>
</el-container>
</el-container>
界面元素:
右侧菜单:
要去找一个两级菜单的element组件然后进行嵌套实现想要的效果
1.还有各个一级菜单的icon图标找一个合适的 2.二级菜单的选中高亮显示,要根据path来进行判断是否显示 3.菜单的展开折叠功能 4.刷新页面让他继续停住选中的二级菜单
左侧的数据展示:
1.头部面包屑 2.下面是一整个el-container组件
<template>
<!-- 主体区域 -->
<el-container>
<!-- 左侧菜单栏 -->
<el-aside :width="IsCollapse ? '50px': '200px'"> <!--动态显示宽度-->
<div class = "collapse-button" @click = "collapseButton">菜单</div>
<!-- 菜单栏 -->
<el-menu background-color="#545c64" text-color="#fff" unique-opened :collapse = "IsCollapse"
:collapse-transition = "false" :default-active = "HighlightValue" router
>
<!-- 一级菜单 -->
<el-submenu :index="item.id+''" v-for = "item in menulist" :key = "item.id">
<!--这里的index中item.id时整数,所以要加一个''变成字符串
用来实现一个子菜单的下拉 配合unique-opened实现
router:刷新页面时照样是选中的那一页
:collapse = "IsCollapse" 展开折叠
:collapse-transition = "false" :去除展开折叠的动画效果
:default-active = "HighlightValue" 高亮的显示控制
-->
<!-- 一级菜单的模板模型 -->
<template slot="title">
<!-- 一级菜单的icon -->
<i :class="menuIcons[item.id]"></i>
<!-- 一级菜单的菜单名
通过:class来进行属性的动态绑定return里面的数据
根据id进行动态显示icon
-->
<span>{{item.authName}}</span>
</template>
<!-- 二级菜单 -->
<el-menu-item :index="'/'+subItem.path" v-for = "subItem in item.children" :key = "subItem.id"
@click = "Highlight('/'+subItem.path)">
<!--这里的:index实现只高亮显示一个二级菜单-->
<template slot = "title">
<!-- 二级菜单icon -->
<i class="el-icon-menu"></i>
<!-- 二级菜单的菜单名 -->
<span>{{subItem.authName}}</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<!-- 右侧内容展示区域 -->
<el-main>
<!-- 在右侧展示数据内容 -->
<router-view></router-view>
</el-main>
</el-container>
</template>
<script>
export default {
/**
* 从服务器菜单栏数据
* 当页面加载的时候去获取数据
*/
data(){
return{
//菜单栏数据
menulist:[],
menuIcons:{
//给每个一级菜单栏设置icon
'125':"el-icon-s-custom",
'103':"el-icon-setting",
'101':"el-icon-s-goods",
'102':"el-icon-s-order",
'145':"el-icon-s-data",
},
IsCollapse:false, //首先默认false,不进行折叠
HighlightValue:"" //高亮显示,刚开始是无高亮显示的菜单
}
},
//created:在页面加载时去获取数据
created(){
//调用服务端接口获取数据
this.getMenuList()
//取出存放在session中的HighlightValue进行相应路径的菜单进行高亮显示
this.HighlightValue = window.sessionStorage.getItem("HighlightValue");
},
methods:{
//async:异步请求 await:处理async
async getMenuList(){
// 用于从返回的 Promise 对象中提取 data 属性,并将其赋值给变量 res
const {data : res} = await this.$http.get("menus")
console.log(res)
if(res.meta.status !== 200) return this.$message.error(res.meta.msg)
this.menulist = res.data //将数据赋值
},
collapseButton(){
//给IsCollapse取反,实现展开折叠的效果
this.IsCollapse = !this.IsCollapse
},
Highlight(path){
//将当前选中的路径保存放在session中,当页面初始化时,取出进行赋值实现高亮显示效果
window.sessionStorage.setItem("HighlightValue",path)
this.HighlightValue = path;
}
}
}
</script>
<style lang="less" scoped>
.el-container{
height: 100%;
}
.el-header{
background-color: #c2c8cc;
display: flex;
justify-content: space-between; //两边对齐
align-items: center; //整体水平居中对齐
padding-left: 0px; //logo与左边边距为0
color: #fff;
font-size: 22px;
> div{
display: flex;
align-items: center;
span{
margin-left: 16px;
}
}
}
.el-aside{
background-color: #395cce;
}
.el-main{
background-color: #dee3eb;
}
.el-menu{
//清除菜单栏右侧的1px线
border-right: none;
}
.collapse-button{
text-align: center;
font-size: 18px;
line-height: 25px;
color: #fff;
cursor: pointer;
letter-spacing: 0.3em; //字与字之间的间距
}
</style>
用户菜单对应的数据展示(前面这里只是图形编写)
这里主要是左侧的数据展示
搜索框和添加按钮:
搜索框的功能实现:利用v-model来进行对请求数据时的query参数进行双向绑定就好了,这样在输入姓名查询时,在搜索icon上绑定一个请求数据的事件,再次请求时就会携带着输入的姓名参数去进行请求服务端,然后显示查询到的数据
添加功能的实现:需要一个对话框,控制对话框的显示和关闭,然后在对话框中添加一个有四行输入框的form表单(用element组件),在关闭的时候要将所有输入框的数据清空,还有就是校验:
姓名和密码可以简单校验,邮箱和手机号要进行严格的数据校验,在确定按钮绑上一个去请求添加用户的事件
<template>
<el-card>
<el-row :gutter="25">
<!-- 搜索框
实现搜索功能:v-model:双向绑定
clearable:点击小叉子清空功能
@clear = "getUsersList():当输入框被清空时触发该事件,显示全部数据
:gutter="25" 输入框和添加按钮之间间隔25px
-->
<el-col :span="8">
<el-input placeholder="请输入内容" v-model = "params.query" clearable @clear = "getUsersList()">
<el-button slot="append" icon="el-icon-search" @click = "getUsersList()" ></el-button>
</el-input>
</el-col>
<!-- 添加用户的按钮 -->
<el-col :span="4" >
<el-button type="primary" @click = "dialogVisible=true">添加用户</el-button>
</el-col>
</el-row>
</el-card>
</template>
数据表格+分页
这里的点主要有:
1.数据表的请求,然后显示
2.状态字段的显示:用后端传来的true和false来完成switch开关的显示,并且在进行改变的时候要请求服务端将数据库中的状态值改变,然后再次请求数据库来显示状态值,来实现永久性的改变(指的就是刷新后改变的switch不会是原始的)
3.编辑功能的实现:和后端逻辑一样,先回显,然后姓名字段不可更改,然后进行put请求进行修改
4.删除功能:根据id来进行删除
5,权限分配的鼠标悬浮消息提示:
effect="dark" content="分配角色" placement="top-end" 实现顶部显示
:enterable = "false" 鼠标不可进入到提示框中
<!-- 数据表格区域: -->
<template>
<div>
<el-card>
</el-row>
<el-table :data = "userList" border>
<el-table-column type="index"></el-table-column>
<el-table-column prop = "username" label="姓名"></el-table-column>
<el-table-column prop = "email" label="邮箱"></el-table-column>
<el-table-column prop = "mobile" label="电话"></el-table-column>
<el-table-column prop = "role_name" label="角色"></el-table-column>
<el-table-column label="状态">
<!-- 根据状态字段的值来进行动态显示
mg_state:true就打开
mg_state:false就关闭
基于作用域插槽实现,为了获取状态的值(true or false)
-->
<template slot-scope = "scope">
<!-- change:状态值的永久改变(请求后端改变数据库的内容)
scope.row:将当前行的数据传递给该事件
change switch 状态发生变化时的回调函数 新状态的值
-->
<el-switch v-model="scope.row.mg_state" @change = "mg_state_change(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column width = "200" label="操作">
<!-- 也是基于作用域插槽的方法实现:方便后面的按钮功能的实现时获取数据
size 用于控制该表单内组件的尺寸 string medium / small / mini
effect 默认提供的主题 String dark/light dark
enterable 鼠标是否可进入到 tooltip 中 Boolean — true
-->
<template v-slot:default="scope">
<!-- 编辑按钮 -->
<el-button type = "primary" icon = "el-icon-edit" size = "mini" @click = "echoEditDialog(scope.row.id)"></el-button>
<!-- 删除按钮 -->
<el-button type = "danger" icon = "el-icon-delete" size = "mini" @click = "deleteUserById(scope.row.id)"></el-button>
<!-- 指定(分配角色按钮) -->
<el-tooltip class="item" effect="dark" content="分配角色" placement="top-end" :enterable = "false">
<el-button type = "warning" icon = "el-icon-s-tools" size = "mini"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<!-- 分页显示
:total 当前页面总共有多少条数据,这个值来自后端
:page-size 每页显示多少条,根据请求的参数来进行显示
:current-page 当前页码
@size-change:改变每页显示的数据
@current-change:数据跟着页码进行改变
-->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="params.pagenum"
:page-sizes="[5, 10, 15, 20]"
:page-size="params.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</el-card>
<!-- 添加用户对话框
close Dialog 关闭的回调
:visible.sync="dialogVisible" 对话框的显示控制
-->
<el-dialog
title="添加用户"
:visible.sync="dialogVisible"
width="50%"
@close="user_addform_close">
<!-- 内容区域 -->
<el-form :model="addForm" label-width="70px" ref = "addFormRef" :rules = "addFormRules">
<el-form-item label="用户名" prop = "username">
<el-input v-model="addForm.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop = "password">
<el-input v-model="addForm.password" type = "password"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop = "email">
<el-input v-model="addForm.email"></el-input>
</el-form-item>
<el-form-item label="手机" prop = "mobile">
<el-input v-model="addForm.mobile"></el-input>
</el-form-item>
</el-form>
<!-- 底部 取消和确定按钮 -->
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click = "addUser">确 定</el-button>
</span>
</el-dialog>
<!-- 修改用户信息的对话框 -->
<el-dialog title="修改用户信息" :visible.sync="editDialogVisible" width="50%" @close="user_editForm_close">
<el-form :model="editForm" label-width="70px" ref = "editFormRef" :ruler = "editFormRules">
<!-- 显示需要修改的用户信息 -->
<el-form-item label="用户名" prop = "username">
<el-input v-model="editForm.username" disabled></el-input>
</el-form-item>
<el-form-item label="邮箱" prop = "email">
<el-input v-model="editForm.email"></el-input>
</el-form-item>
<el-form-item label="手机" prop = "mobile">
<el-input v-model="editForm.mobile"></el-input>
</el-form-item>
</el-form>
<!-- 底部 取消和确定按钮 -->
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click = "editUser">保 存</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data(){
/**
* rule:路径
* value:校验值(true/false)
* callback:返回信息
*/
const checkEmail = (rule, value, callback) => {
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if(regEmail.test(value)){
return callback()
}
return callback("邮箱的输入格式不正确!")
}
const checkMobile = (rule, value, callback) => {
const regMobile = /^(86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
if(regMobile.test(value)){
return callback()
}
return callback("手机号码的输入格式不正确!")
}
return{
//调用后端数据需要的参数
params:{
//查询条件,显示条件
query:'',
//页码
pagenum:'1',
//每页显示多少条数据
pagesize:'5'
},
//用户数据数组
userList:[],
//总页数
total:0,
//对话框的控制
dialogVisible:false,
addForm:{
username:'',
password:'',
email:'',
mobile:''
},
addFormRules:{
username:[
{required: true, message:"请输入用户名",trigger:"blur"},
{min: 6, max: 16, message:"用户名的长度为6~15个字符",trigger:"blur"}
],
password:[
{required: true, message:"请输入密码",trigger:"blur"},
{min: 6, max: 16, message:"密码的长度为6~15个字符",trigger:"blur"}
],
email: [
{required: true, message:"请输入邮箱",trigger:"blur"},
{ validator: checkEmail, trigger: 'blur' }
],
mobile:[
{required: true, message:"请输入手机号码",trigger:"blur"},
{ validator: checkMobile, trigger: 'blur' }
]
},
//控制修改用户对话框的显示
editDialogVisible: false,
editForm: {},
editFormRules:{
email: [
{required: true, message:"请输入邮箱",trigger:"blur"},
{ validator: checkEmail, trigger: 'blur' }
],
mobile:[
{required: true, message:"请输入手机号码",trigger:"blur"},
{ validator: checkMobile, trigger: 'blur' }
]
}
}
},
created(){
//调用后端接口获取用户数据进行显示
this.getUsersList()
},
methods:{
//获取后端的数据库数据
async getUsersList(){
const {data:res} = await this.$http.get('users',{params:this.params}) //{params:请求的参数}
// console.log(res)
if(res.meta.status !== 200) return this.$message.error("获取用户列表失败")
this.userList = res.data.users
//给total赋值
this.total = res.data.total
},
//实现每页显示几条数据
handleSizeChange(s_size){
this.params.pagesize = s_size //将每页显示的数据改为选择的数字
this.getUsersList() //在改变条数成功后,重新去后端加载数据显示
},
//实现数据跟着页码变化
handleCurrentChange(s_sise){
this.params.pagenum = s_sise
this.getUsersList()
},
//row代表当前的这条数据
async mg_state_change(row){
console.log(row)
//发送修改请求到后端
const {data:res} = await this.$http.put(`users/${row.id}/state/${row.mg_state}`)
if(res.meta.status !== 200){
return this.$message.error("用户状态更新失败")
//更新失败了取反改回来
row.mg_state = !row.mg_state
}
return this.$message.success("用户状态更新成功")
},
//关闭添加对话框时触发
user_addform_close(){
//清空输入框
this.$refs.addFormRef.resetFields()
},
/**
* 实现添加(保存)用户信息
* 前提条件:前面的校验都通过了
*/
addUser(){
this.$refs.addFormRef.validate(async valid => {
if(!valid) return
//发起请求后端
const {data:res} = await this.$http.post('users',this.addForm)
// console.log(res)
if(res.meta.status !== 201) return this.$message.error("添加用户数据失败") //直接return掉
this.$message.success("添加用户成功")
//添加成功后将对话框隐藏
this.dialogVisible = false
//重新进行向后端数据请求获取
this.getUsersList()
})
},
//关闭对话框时把文本进行重置清空
user_editForm_close(){
this.$refs.addFormRef.resetFields()
},
//回显数据在对话框中
async echoEditDialog(id){
//查询
const {data:res} = await this.$http.get('users/'+id)
if(res.meta.status !== 200){
return this.$message.error("查询用户信息失败!")
}
// console.log(res.data)
//将查询到的数据给到editForm对象进行显示
this.editForm = res.data
//并显示对话框
this.editDialogVisible = true
},
//保存修改后的数据
editUser(){
this.$refs.editFormRef.validate(async valid => {
if(!valid) return
//发起修改信息请求
/**
* 第二个参数表示修改的属性,需要的是一个json格式的数据
*/
const {data:res} = await this.$http.put('users/'+this.editForm.id,
{
email:this.editForm.email,
mobile:this.editForm.mobile
})
//对发送修改请求的结果进行判断(成功/失败)
if(res.meta.status !== 200) return this.$message.error("修改用户信息失败!") //直接return掉
this.$message.success("修改用户信息成功")
//添加成功后将对话框隐藏
this.editDialogVisible = false
//重新进行向后端数据请求获取
this.getUsersList()
})
},
//根据用户id删除用户信息
async deleteUserById(id){
//首先弹窗询问用户是否确定删除
const confirmResult = await this.$confirm(
'此操作将永久删除该文件, 是否继续?',
'提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).catch((err) => err)
//如果用户确认删除,则返回值字符串confirmResult为confirm
//如果用户确认删除,则返回值字符串confirmResult为cancel
console.log(confirmResult)
if(confirmResult !== 'confirm'){
return this.$message.info("已取消删除")
}
const {data:res} = await this.$http.delete('users/'+id)
if(res.meta.status !== 200){
return this.$message.error("删除用户失败!")
}
this.$message.success("删除用户成功!")
this.getUsersList()
}
}
}
</script>
权限菜单对应的数据展示
首先也是一个面包屑导航栏
首页>权限管理>权限列表
<template>
<div>
<!-- 面包屑导航栏区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>角色列表</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>
数据显示:
1.在布局好数据显示的表格样式后加上一个斑马线的属性
stripe
属性可以创建带斑马纹的表格。它接受一个Boolean
,默认为false
,设置为true
即为启用。
2.权限等级的标签样式显示
<el-tag>标签一</el-tag> <el-tag type="success">标签二</el-tag> <el-tag type="info">标签三</el-tag> <el-tag type="warning">标签四</el-tag> <el-tag type="danger">标签五</el-tag>
对应上面的标签效果
通过type属性来渲染权限的等级
其他的就很简单,和user的一样的做法(获取数据展示啥的)
<template>
<div>
<!-- 数据展示区域 -->
<el-card>
<el-table :data = "privilegesList" border>
<el-table-column type="index"></el-table-column>
<el-table-column prop = "authName" label="权限名称"></el-table-column>
<el-table-column prop = "path" label="路径"></el-table-column>
<el-table-column prop = "level" label="权限等级">
<!-- 作用域插槽的方式来进行 -->
<template v-slot:default="scope">
<el-tag v-if = "scope.row.level === '0'">一级</el-tag>
<el-tag type="success" v-else-if = "scope.row.level === '1'">二级</el-tag>
<el-tag type="warning" v-else>三级</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
data(){
return{
privilegesList:[]
}
},
created(){
//获取所有的权限列表
this.getPrivilegesList()
},
methods:{
async getPrivilegesList(){
const {data:res} = await this.$http.get('rights/list')
console.log(res)
if(res.meta.status !== 200) return this.$message.error("获取权限列表失败!")
this.privilegesList = res.data
}
}
}
</script>
<style lang="less" scoped>
.el-card{
margin-top: 20px;
}
</style>
角色菜单对应的数据显示
涉及到的元素:
面包屑
添加角色按钮+表格+最左列的展开折叠效果,来查看角色对应的权限
新鲜点:
主要就是查看各个角色对应的权限有哪些
这里要将展示权限的表格进行分割为24列
进行数据的规格化展示
水平居中
小箭头:
<i class="el-icon-caret-right"></i> icon图标
拥有的所有的功能权限的小叉叉删除
closable @close="dleteRightById(scope.row, item3.id)"
<!--为close绑上删除的功能-->
<template>
<div>
<!-- 面包屑导航栏区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>角色列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 数据展示的卡片区域 -->
<el-card>
<el-row>
<el-col>
<el-button type="primary">添加角色</el-button>
</el-col>
</el-row>
<el-table :data = "rolesList" border stripe>
<!-- type="expand":>的icon -->
<el-table-column type="expand">
<!-- 通过插槽的方法来实现渲染权限级别 -->
<template v-slot:default = "scope">
<el-row :class = "['role-bdbottom-line',il === 0 ? 'role-top-line' : '','role-content-center']" v-for = "(item,il) in scope.row.children" :key = "item.id">
<!-- 渲染一级权限 -->
<el-col :span = "5">
<el-tag>
{{item.authName}}
</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<!-- 渲染二级和三级权限 -->
<el-col :span = "19">
<el-row :class = "[i2 === 0 ? '': 'role-top-line','role-content-center']" v-for = "(item2,i2) in scope.row.children" :key = "item2.id">
<!-- 二级渲染 -->
<el-col :span = "6">
<el-tag type = "success">
{{item2.authName}}
</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<!-- 三级渲染 -->
<el-col :span = "18">
<el-tag type = "warning" closable @close="dleteRightById(scope.row, item3.id)" v-for = "(item3) in item2.children" :key = "item3.id">
{{item3.authName}}
</el-tag>
</el-col>
</el-row>
</el-col>
</el-row>
</template>
</el-table-column>
<el-table-column type = "index"></el-table-column>
<el-table-column prop = "roleName" label="角色名称"></el-table-column>
<el-table-column prop = "roleDesc" label="角色描述"></el-table-column>
<el-table-column width = "300" label="操作">
<template v-slot:default="scope">
<!-- 编辑按钮 -->
<el-button type = "primary" icon = "el-icon-edit" size = "mini" @click = "echoEditDialog(scope.row.id)">编辑</el-button>
<!-- 删除按钮 -->
<el-button type = "danger" icon = "el-icon-delete" size = "mini" @click = "deleteRolesById(scope.row.id)">删除</el-button>
<!-- 指定(分配角色按钮) -->
<el-button type = "warning" icon = "el-icon-setting" size = "mini" @click = "showSetRolePrivilegeDialog(scope.row)">分配权限</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 显示编辑对话框 -->
<el-dialog title="分配权限" :visible.sync="setRolePrivilegeDialogVisible" width="50%" >
<!-- 树形控件 -->
<el-tree :data="privilegeList" :props="treeProps" ></el-tree>
<span slot="footer" class="dialog-footer">
<el-button @click="setRolePrivilegeDialogVisible = false">取 消</el-button>
<el-button type="primary" >确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data(){
return{
//角色列表
rolesList:[],
//分配权限对话框的显示和隐藏控制
setRolePrivilegeDialogVisible: false,
//权限列表
privilegeList:[],
treeProps:{
label: 'authName',
children: 'children'
}
}
},
created(){
//权限列表数据数组
this.getRolesList()
},
methods:{
async getRolesList(){
const {data:res} = await this.$http.get('roles')
console.log(res.data)
if(res.meta.status !== 200) return this.$message.error("获取角色列表失败")
this.rolesList = res.data
},
async dleteRightById(role,privilege_id){
//根据id删除相应的权限
const confirmResult = await this.$confirm(
'此操作将永久删除该文件, 是否继续?',
'提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).catch((err) => err)
//如果用户确认删除,则返回值字符串confirmResult为confirm
//如果用户确认删除,则返回值字符串confirmResult为cancel
console.log(confirmResult)
if(confirmResult !== 'confirm'){
return this.$message.info("已取消删除")
}
const {data:res} = await this.$http.delete( `roles/${role.id}/rights/${privilege_id}`)
if(res.meta.status !== 200){
return this.$message.error("删除权限失败!")
}
role.children = res.data //重新赋值展示权限
},
//权限分配
async showSetRolePrivilegeDialog(row){
//向服务端获取全部权限数据
const {data:res} = await this.$http.get('rights/tree')
if(res.meta.status !== 200){
return this.$message.error("获取权限数据失败!")
}
this.privilegeList = res.data
//打开对话框
this.setRolePrivilegeDialogVisible = true
},
deleteRolesById(id){
}
}
}
</script>
<style lang="less" scoped>
.el-card{
margin-top: 20px;
}
.el-table{
font-size: 15px;
margin-top: 18px;
}
.el-tag{
//调整一个个标签tag之间的距离
margin: 8px
}
//上边框
.role-top-line{
border-top: 1px solid #eee;
}
//下边框
.role-bdbottom-line{
border-bottom: 1px solid #eee;
}
//居中显示
.role-content-center{
display: flex;
align-items: center;
}
</style>