vue电商项目003:主页面布局,用户列表功能
1.主页面布局
1.1整体布局
整体布局:先上下划分再左右划分
主页面的效果图如下:
1.2布局需要用到的组件
在element-ui官方提供组建中找到我们自己需要的样式
<el-container class="home-container">
<!-- 头部区域 -->
<el-header>Header<el-button type="info" @click="logout"> 退出 </el-button></el-header>
<!-- 页面主体区域 -->
<el-container>
<!-- 侧边栏 -->
<el-aside width="200px">Aside</el-aside>
<!-- 主体结构 -->
<el-main>Main</el-main>
</el-container>
</el-container>
将对应的代码复制到Home.vue的相应位置
1.3注册组件
因为我们设置的是按需导入所以只要我们使用了新的组件就必须先注册在使用,不然就会报错
找到element.js文件在import中加入Container,Header,Aside,Main这四个组件
Vue.use(Container)
Vue.use(Header)
Vue.use(Aside)
Vue.use(Main
大家不要嫌麻烦,按需导入的方式极大的让我们的减少了项目需要加载的组件资源,大家只需要在使用一个新的组件时导入即可
1.4添加组件的样式
在默认的样式下element-ui组件同名的类名可以让我们快速的添加样式
我们找到Home.vue中的style样式区域,注意在style样式中使用less语法和scope保证兼容性以便于我们的开发
//部分样式是后来添加的进行优化
<style lang="less" scoped>
.home-container {
height: 100%;
}
.el-header {
background-color: #373D41;
display: flex;
justify-content: space-between;
padding-left: 0;
align-items: center;
color: #fff;
font-size: 20px;
>div {
display: flex;
align-items: center;
span {
margin-left: 15px;
}
}
}
.el-aside {
background-color: #333744;
.el-menu{
//优化右侧边框线
border-right: none;
}
}
.el-main {
// 修改背景颜色相同
background-color: #eaedf1;
}
.iconfont{
// 设置自定义的图片与文字的右间距
margin-right: 10px;
}
.toggle-button {
background-color: #4a5064;
font-size: 10px;
line-height: 20px;
color: #fff;
text-align: center;
letter-spacing: 0.2em;
cursor: pointer;
}
</style>
1.5侧边栏菜单的布局以及渲染
在element-ui中也提供了相应的组件,在NavMenu导航菜单中可以找到相应的组件对应的区域
当点击二级菜单的时候,被点击的二级子菜单并没有高亮,我们需要正在被使用的功能高亮显示
我们可以通过设置el-menu的default-active属性来设置当前激活菜单的index
但是default-active属性也不能写死,固定为某个菜单值
所以我们可以先给所有的二级菜单添加点击事件,并将path值作为方法的参数
<!-- 侧边栏菜单区域 -->
<el-menu background-color="#333744" text-color="#fff" active-text-color="#409eff" :unique-opened="true" :collapse="isCollapse"
:collapse-transition="false" :router="true" :default-active="activePath">
<!-- unique-opened:是否只保持一个子菜单的展开 -->
<!-- :collapse-transition折叠动画 -->
<!-- :router开启路由模式 -->
<!-- :default-active:高亮的路径 -->
<!-- 一级菜单 -->
<el-submenu :index="item.id+''" v-for="item in menuList" :key="item.id">
<!-- 一级菜单的模板区域 -->
<template slot="title">
<!-- 图标 -->
<i :class="iconsObj[item.id]"></i>
<!-- 文本 -->
<span>{{item.authName}}</span>
</template>
<!-- 二级菜单 -->
<el-menu-item v-for="subItem in item.children" :index="'/'+subItem.path" :key="subItem.id" @click="saveNavState('/'+subItem.path)">
<template slot="title">
<!-- 图标 -->
<i class="el-icon-menu"></i>
<!-- 文本 -->
<span>{{subItem.authName}}</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
大家记得导入对应的组件
1.6axios请求拦截器
后台除了登录接口之外,都需要token权限验证,我们可以通过添加axios请求拦截器来添加token,以保证拥有获取数据的权限
在main.js中添加代码,在将axios挂载到vue原型之前添加下面的代码
//axios请求拦截
axios.interceptors.request.use(config =>{
//为请求头对象,添加Token验证的Authorizatio·段
config.headers.Authorization=window.sessionStorage.getItem('token')
return config
})
1.7请求侧边栏数据
通过更改el-menu的active-text-color属性可以设置侧边栏菜单中点击的激活项的文字颜色
通过更改菜单项模板(template)中的i标签的类名,可以将左侧菜单栏的图标进行设置,我们需要在项目中使用第三方字体图标
在数据中添加一个iconsObj:
然后将图标类名进行数据绑定,绑定iconsObj中的数据:
为了保持左侧菜单每次只能打开一个,显示其中的子菜单,我们可以在el-menu中添加一个属性unique-opened
或者也可以数据绑定进行设置(此时true认为是一个bool值,而不是字符串) :unique-opened=“true”
<script>
export default {
data() {
return {
//左侧菜单数据
menuList: [],
iconsObj: {
'125': 'iconfont icon-user',
'103': 'iconfont icon-tijikongjian',
'101': 'iconfont icon-shangpin',
'102': 'iconfont icon-danju',
'145': 'iconfont icon-baobiao'
},
// 是否折叠
isCollapse: false,
// 被激活的链接地址
activePath: ''
}
},
created() {
//然后在数据中添加一个activePath绑定数据,并将el-menu的default-active属性设置为activePath
最后在created中将sessionStorage中的数据赋值给activePath
this.getMenuList()
this.activePath = window.sessionStorage.getItem('activePath')
},
methods: {
logout() {
window.sessionStorage.clear()
this.$router.push('/login')
},
//获取所有的菜单
async getMenuList() {
const {
data: res
} = await this.$http.get('menus')
if (res.meta.status !== 200) return this.$message.error(res.meta.msg)
this.menuList = res.data
},
// 点击按钮切换菜案的折叠与展开
toggleCollapse() {
this.isCollapse = !this.isCollapse
},
//在saveNavState方法中将path保存到sessionStorage中
saveNavState(activePath) {
//点击二级菜单的时候保存被点击的二级菜单信息
window.sessionStorage.setItem('activePath', activePath)
this.activePath = activePath
}
}
};
</script>
1.8制作侧边菜单栏的伸缩功能
在菜单栏上方添加一个div
<div class="toggle-button" @click="toggleCollapse">|||</div>
对应的toggleCollapse函数已经在1.7中写出来了
1.9在后台首页添加子级路由
新增子级路由组件Welcome.vue
在router.js中导入子级路由组件,并设置路由规则以及子级路由的默认重定向
打开Home.vue,在main的主体结构中添加一个路由占位符
制作好了Welcome子级路由之后,我们需要将所有的侧边栏二级菜单都改造成子级路由链接
我们只需要将el-menu的router属性设置为true就可以了,此时当我们点击二级菜单的时候,就会根据菜单的index
属性进行路由跳转,如: /110,
使用index id来作为跳转的路径不合适,我们可以重新绑定index的值为 :index="’/’+subItem.path"
1.10Home.vue的所有代码
<template>
<el-container class="home-container">
<!-- 头部区域 -->
<el-header>
<div>
<img src="../assets/heima.png" alt="" />
<span>电商后台管理系统</span>
</div>
<el-button type="info" @click="logout">退出</el-button>
</el-header>
<!-- 页面主体区域 -->
<el-container>
<!-- 侧边栏 -->
<!-- 侧边栏的宽度根据折叠还是展开变换 -->
<el-aside :width="isCollapse?'64px':'200px'">
<div class="toggle-button" @click="toggleCollapse">|||</div>
<!-- 侧边栏菜单区域 -->
<el-menu background-color="#333744" text-color="#fff" active-text-color="#409eff" :unique-opened="true" :collapse="isCollapse"
:collapse-transition="false" :router="true" :default-active="activePath">
<!-- unique-opened:是否只保持一个子菜单的展开 -->
<!-- :collapse-transition折叠动画 -->
<!-- :router开启路由模式 -->
<!-- :default-active:高亮的路径 -->
<!-- 一级菜单 -->
<el-submenu :index="item.id+''" v-for="item in menuList" :key="item.id">
<!-- 一级菜单的模板区域 -->
<template slot="title">
<!-- 图标 -->
<i :class="iconsObj[item.id]"></i>
<!-- 文本 -->
<span>{{item.authName}}</span>
</template>
<!-- 二级菜单 -->
<el-menu-item v-for="subItem in item.children" :index="'/'+subItem.path" :key="subItem.id" @click="saveNavState('/'+subItem.path)">
<template slot="title">
<!-- 图标 -->
<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>
</el-container>
</template>
<script>
export default {
data() {
return {
//左侧菜单数据
menuList: [],
iconsObj: {
'125': 'iconfont icon-user',
'103': 'iconfont icon-tijikongjian',
'101': 'iconfont icon-shangpin',
'102': 'iconfont icon-danju',
'145': 'iconfont icon-baobiao'
},
// 是否折叠
isCollapse: false,
// 被激活的链接地址
activePath: ''
}
},
created() {
this.getMenuList()
this.activePath = window.sessionStorage.getItem('activePath')
},
methods: {
logout() {
window.sessionStorage.clear()
this.$router.push('/login')
},
//获取所有的菜单
async getMenuList() {
const {
data: res
} = await this.$http.get('menus')
if (res.meta.status !== 200) return this.$message.error(res.meta.msg)
this.menuList = res.data
},
// 点击按钮切换菜案的折叠与展开
toggleCollapse() {
this.isCollapse = !this.isCollapse
},
//在saveNavState方法中将path保存到sessionStorage中
saveNavState(activePath) {
//点击二级菜单的时候保存被点击的二级菜单信息
window.sessionStorage.setItem('activePath', activePath)
this.activePath = activePath
}
}
};
</script>
<style lang="less" scoped>
.home-container {
height: 100%;
}
.el-header {
background-color: #373D41;
display: flex;
justify-content: space-between;
padding-left: 0;
align-items: center;
color: #fff;
font-size: 20px;
>div {
display: flex;
align-items: center;
span {
margin-left: 15px;
}
}
}
.el-aside {
background-color: #333744;
.el-menu {
//优化右侧边框线
border-right: none;
}
}
.el-main {
// 修改背景颜色相同
background-color: #eaedf1;
}
.iconfont {
// 设置自定义的图片与文字的右间距
margin-right: 10px;
}
.toggle-button {
background-color: #4a5064;
font-size: 10px;
line-height: 20px;
color: #fff;
text-align: center;
letter-spacing: 0.2em;
cursor: pointer;
}
</style>
部分的样式我没有具体的说,在上面的代码里面有
2.用户列表功能
2.1创建User.vue组件
在components目录下新建一个user的文件夹,在文件夹类创建User.vue
在路由规则中导入User.vue的路由,对页面进行初始化
2.2需要的element—ui组件
我们先来看一下效果图
上面用到BreadCRUMB了面包屑导航,Card卡片视图,Form表单,Table表格,DIalog对话框,Pagination分页,Tooltip文字提示,Switch开关,MessageBox这些组件,大家可以先在element.js中进行注册
2.3面包屑导航区域
<!-- 面包屑导航区域 -->
<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>
2.4卡片视图区域以及搜索框和添加按钮
放在卡片视图区域中
:gutter="20”,控制列与列的间距
:span=“9”:该列占用的宽度
搜索的图标是element-ui组件库自带的
<!-- 搜索与添加区域 -->
<el-row :gutter="20">
<el-col :span="9">
<el-input placeholder="请输入内容" v-model="queryInfo.query" clearable @clear="getUserList">
<el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
</el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="addDialogVisible=true">添加用户</el-button>
</el-col>
</el-row>
里面涉及到的事件和属性是在完成页面的布局后完成的
2.5请求用户列表数据
<script>
export default {
data() {
return {
//获取查询用户信息的参数
queryInfo: {
query: '',
pagenum: 1,
pagesize: 2
},
//保存请求回来的用户列表数据
userList:[],
total:0
}
},
created() {
this.getUserList()
},
methods: {
async getUserList() {
//发送请求获取用户列表数据
const { res: data } = await this.$http.get('users', {
params: this.queryInfo
})
//如果返回状态为异常状态则报错并返回
if (res.meta.status !== 200)
return this.$message.error('获取用户列表失败')
//如果返回状态正常,将请求的数据保存在data中
this.userList = res.data.users;
this.total = res.data.total;
}
}
}
</script>
2.6用户的列表区域
使用表格来展示用户列表数据,使用element-ui表格组件完成列表展示数据(复制表格代码,在element.js中导入组件Table,TableColumn)
在渲染展示状态时,会使用作用域插槽获取每一行的数据
再使用switch开关组件展示状态信息(复制开关组件代码,在element.js中导入组件Switch)
而渲染操作列时,也是使用作用域插槽来进行渲染的,
在操作列中包含了修改,删除,分配角色按钮,当我们把鼠标放到分配角色按钮上时
希望能有一些文字提示,此时我们需要使用文字提示组件(复制文字提示组件代码,在element.js中导入组件Tooltip)
<!-- 用户列表区 -->
<el-table :data="UserList" border stripe>
<el-table-column label="#" type="index"></el-table-column>
<el-table-column label="姓名" prop="username"></el-table-column>
<el-table-column label="邮箱" prop="email"></el-table-column>
<el-table-column label="电话" prop="mobile"></el-table-column>
<el-table-column label="角色" prop="role_name"></el-table-column>
<el-table-column label="状态">
<!-- 通过作用域插槽渲染状态栏 -->
<template slot-scope="scope">
<!-- {{scope.row}} -->
<el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="180px">
<template slot-scope="scope">
<!-- 修改按钮 -->
<el-button type="primary" icon="el-icon-edit" size="mini" @click="showEditDialog(scope.row.id)"></el-button>
<!-- 删除按钮 -->
<el-button type="danger" icon="el-icon-delete" size="mini" @click="removeUserById(scope.row.id)"></el-button>
<!-- 分配角色权限按钮 -->
<el-tooltip effect="dark" content="分配角色" placement="top" :enterable="false">
<el-button type="warning" icon="el-icon-setting" size="mini" @click="setRole(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
2.7用户分页
A.使用表格来展示用户列表数据,可以使用分页组件完成列表分页展示数据(复制分页组件代码,在element.js中导入组件Pagination)
B.更改组件中的绑定数据
@size-change:监听pagesize改变的事件
@current-change:监听页码值改变的事件
:current-page:当前页
:page-sizes:一页的的信息条数
:page-size:当前的页数
layout:控制显示内容
:total:总共的信息条数
<!-- 分页区域 -->
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum"
:page-sizes="[1, 2, 5, 10]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
2.8实现@size-change,@current-change
// 监听pagesize改变的事件
handleSizeChange(newSize) {
//pagesize改变时触发,当pagesize发生改变的时候,我们应该
//以最新的pagesize来请求数据并展示数据
this.queryInfo.pagesize = newSize
//重新按照pagesize发送请求,请求最新的数据
this.getUserList()
},
//监听页码值改变的事件
handleCurrentChange(newPage) {
//页码发生改变时触发当current发生改变的时候,我们应该
//以最新的current页码来请求数据并展示数据
this.queryInfo.pagenum = newPage
//重新按照pagenum发送请求,请求最新的数据
this.getUserList()
}
2.9实现更新用户状态
在上面的用户列表中已经使用了switch组件,要达到的效果就是当用户点击列表中的switch组件时,用户的状态应该跟随发生改变。我们在switch组件中定义了"userStateChanged(scope.row)函数并且把这一行的的数据通过作用域插槽进行渲染
//监听switch开关状态的改变
async userStateChanged(userinfo) {
const {
data: res
} = await this.$http.put(`users/${userinfo.id}/state/${userinfo.mg_state}`)
if (res.meta.status !== 200) {
return this.$message.error('更新用户状态失败!')
}
this.$message.success('更新用户状态成功!')
}
2.10实现搜索功能
搜索功能的实现比较简单只需要将值利用绑定到queryInfo.query即可
2.11实现添加用户
在添加按钮上绑定点击事件@click=“addDialogVisible=true”
在这里我们就要用到dialog对话框
title:显示的标题
:visible.sync:绑定显示还是隐藏的属性
width:宽度
@close:监听关闭对话框事件
el-form中的 :model、 :rules、 ref命名规范化
:rules在绑定表单的后面加Rules
ref在绑定表单的后面加Ref
如下就是 :model=“addForm” :rules=“addFormRules” ref=“addFormRef”
<!-- 添加用户的对话框 -->
<el-dialog title="添加用户" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed">
<!-- 内容主体区域 -->
<el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px">
<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"></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="addDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="addUser">确 定</el-button>
</span>
</el-dialog>
2.12添加数据绑定和校验规则
data() {
// 验证邮箱的规则
var checkEmail = (rule, value, cb) => {
// 验证邮箱的正则表达式
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if (regEmail.test(value)) {
// 合法的邮箱
return cb()
}
cb(new Error('请输入合法的邮箱'))
}
//验证手机号的规则
var checkMobile = (rule, value, cb) => {
// 验证手机号的正则表达式
const regMobile = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
if (regMobile.test(value)) {
return cb()
}
cb(new Error('请输入合法的手机号'))
}
return {
//获取用户列表的参数对象
queryInfo: {
//查询参数
query: '',
//当前页码
pagenum: 1,
//当前每页显示条数
pagesize: 2
},
UserList: [],
total: 0,
//控制添加用户对话框的显示与隐藏
addDialogVisible: false,
//添加用户的表单数据
addForm: {
username: '',
password: '',
email: '',
mobile: ''
},
//添加表单的验证规则对象
addFormRules: {
username: [{
required: true,
message: '请输入用户名',
trigger: 'blur'
},
{
min: 3,
max: 10,
message: '用户名的长度在 3 到 10 个字符之间',
trigger: 'blur'
}
],
password: [{
required: true,
message: '请输入密码',
trigger: 'blur'
},
{
min: 6,
max: 15,
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'
}]
}
对话框的关闭事件
写在methods中
//监听新增用户的关闭事件
addDialogClosed() {
this.$refs.addFormRef.resetFields()
}
添加新用户的事件
//店家按钮添加新用户
addUser() {
//如果所有的验证规则过过了则执行添加的操作,如果有验证规则没有满足则直接return
this.$refs.addFormRef.validate(async valid => {
if (!valid) return
//可以发起添加用户的网络请求
const {
data: res
} = await this.$http.post('users', this.addForm)
if (res.meta.status != 201) {
return this.$message.error('添加用户失败!')
}
this.$message.success('添加用户成功!')
//隐藏添加用户对话框
this.addDialogVisible = false
this.getUserList()
})
}
完成后的效果图如下
2.13用户列表信息的编辑功能
同样用到了dialog对话框
<!-- 修改用户界面 -->
<el-dialog title="修改用户" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed">
<!-- 内容主体区域 -->
<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
<el-form-item label="用户名">
<el-input v-model="editForm.username" disabled></el-input>
</el-form-item>
</el-form>
<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
<el-form-item label="邮箱" prop="email">
<el-input v-model="editForm.email" ></el-input>
</el-form-item>
</el-form>
<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
<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="editDialogVisible=flase">取 消</el-button>
<el-button type="primary" @click="editUserInfo" >确 定</el-button>
</span>
</el-dialog>
修改的表单以及验证规则
//控制修改用户对话框的显示与隐藏
editDialogVisible: false,
//查询到的用户信息对象
editForm: {
},
//修改表单的验证规则对象
editFormRules: {
email: [{
required: true,
message: '请输入用户邮箱',
trigger: 'blur'
}, {
validator: checkEmail,
trigger: 'blur'
}],
mobile: [{
required: true,
message: '请输入用户手机号',
trigger: 'blur'
}, {
validator: checkMobile,
trigger: 'blur'
}]
}
展示编辑用户的对话框事件,在编辑按钮上绑定@click="showEditDialog(scope.row.id)"传入这一行数据的id,根据这一行数据的id查询出对应的数据作为初始的数据显示在编辑对话框的页面上
//展示编辑用户的对话框
async showEditDialog(id) {
const {
data: res
} = await this.$http.get('users/' + id)
if(res.meta.status !== 200)
return this.$message.error('查询用户信息失败!')
this.editForm = res.data
this.editDialogVisible = true
}
对话框的关闭事件
//监听修改用户对话框的关闭事件
editDialogClosed(){
this.$refs.editFormRef.resetFields()
}
修改用户信息并提交
//修改用户信息并提交
editUserInfo(){
this.$refs.editFormRef.validate(async valid => {
if (!valid) return
//可以发起修改用户的网络请求
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('更新用户信息失败!')
}
//隐藏修改用户对话框
this.editDialogVisible = false
// 刷新列表列表
this.getUserList()
// 提示用户信息修改成功
this.$message.success('更新用户信息成功!')
})
}
完成后的效果
2.14删除用户信息
在删除用户信息前要先询问用户是否确认删除,用户确认后再删除,删除后刷新列表
在删除的按钮上绑定删除事件@click="removeUserById(scope.row.id)"把这一行数据的id作为参数传入
同时也用到了MessageBox组件,在使用MessageBox组件是如果点击了取消默认的情况下是会抛出异常的用catch捕获异常
// 根据id删除对应的用户信息
async removeUserById(id){
//弹框询问用户是否删除数据
const confirmRes=await this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err=>err)
//console.log(confirmRes)
//如果用户确认删除,则返回值为字符串confirm
//如果用户取消删除,则返回值为字符串cancel
if(confirmRes!=='confirm') {
return this.$message.info('已取消了删除!')
}
const {
data: res
} = await this.$http.delete('users/'+id)
if (res.meta.status !== 200) {
return this.$message.error('删除用户失败!')
}
// 刷新列表列表
this.getUserList()
// 提示用户信息修改成功
this.$message.success('删除用户信息成功!')
}
2.15展示分配角色的对话框
也用到了dialog对话框
<!-- 分配角色的对话框 -->
<el-dialog
title="分配角色"
:visible.sync="setRoleDialogVisible"
width="50%" @close="setRoleDialogClosed">
<div>
<p>当前的用户:{{userInfo.username}}</p>
<p>当前的角色:{{userInfo.role_name}}</p>
<p>分配新角色:
<el-select v-model="selectedRoleId" placeholder="请选择">
<el-option
v-for="item in rolesList"
:key="item.id"
:label="item.roleName"
:value="item.id">
</el-option>
</el-select></p>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="setRoleDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="saveRoleInfo">确 定</el-button>
</span>
</el-dialog>
展现对话框的事件
//展示分配角色的对话框
async setRole(userInfo){
this.userInfo=userInfo
//在展示对话框之前获取所有的角色列表
const {data:res}=await this.$http.get('roles')
if(res.meta.status!==200){
return this.$message.error('获取角色列表失败!')
}
this.rolesList=res.data
this.setRoleDialogVisible=true
}
监听对话框的关闭事件
//监听分配角色对话框的关闭事件
setRoleDialogClosed(){
this.selectedRoleId=''
this.userInfo={}
}
保存修改后的权限
async saveRoleInfo(){
if(!this.selectedRoleId){
return this.$message.error('请选择要分配的角色!')
}
const {data:res}=await this.$http.put(`users/${this.userInfo.id}/role`,{rid:this.selectedRoleId})
if(res.meta.status!==200){
return this.$message.error('更新角色失败!')
}
this.$message.success('更新角色成功!')
this.getUserList()
this.setRoleDialogVisible=false
}
3.16Users.vue的代码
<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 :gutter="20">
<el-col :span="9">
<el-input placeholder="请输入内容" v-model="queryInfo.query" clearable @clear="getUserList">
<el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
</el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="addDialogVisible=true">添加用户</el-button>
</el-col>
</el-row>
<!-- 用户列表区 -->
<el-table :data="UserList" border stripe>
<el-table-column label="#" type="index"></el-table-column>
<el-table-column label="姓名" prop="username"></el-table-column>
<el-table-column label="邮箱" prop="email"></el-table-column>
<el-table-column label="电话" prop="mobile"></el-table-column>
<el-table-column label="角色" prop="role_name"></el-table-column>
<el-table-column label="状态">
<!-- 通过作用域插槽渲染状态栏 -->
<template slot-scope="scope">
<!-- {{scope.row}} -->
<el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="180px">
<template slot-scope="scope">
<!-- 修改按钮 -->
<el-button type="primary" icon="el-icon-edit" size="mini" @click="showEditDialog(scope.row.id)"></el-button>
<!-- 删除按钮 -->
<el-button type="danger" icon="el-icon-delete" size="mini" @click="removeUserById(scope.row.id)"></el-button>
<!-- 分配角色权限按钮 -->
<el-tooltip effect="dark" content="分配角色" placement="top" :enterable="false">
<el-button type="warning" icon="el-icon-setting" size="mini" @click="setRole(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum"
:page-sizes="[1, 2, 5, 10]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</el-card>
<!-- 添加用户的对话框 -->
<el-dialog title="添加用户" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed">
<!-- 内容主体区域 -->
<el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px">
<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"></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="addDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="addUser">确 定</el-button>
</span>
</el-dialog>
<!-- 修改用户界面 -->
<el-dialog title="修改用户" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed">
<!-- 内容主体区域 -->
<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
<el-form-item label="用户名">
<el-input v-model="editForm.username" disabled></el-input>
</el-form-item>
</el-form>
<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
<el-form-item label="邮箱" prop="email">
<el-input v-model="editForm.email" ></el-input>
</el-form-item>
</el-form>
<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
<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="editDialogVisible=flase">取 消</el-button>
<el-button type="primary" @click="editUserInfo" >确 定</el-button>
</span>
</el-dialog>
<!-- 分配角色的对话框 -->
<el-dialog
title="分配角色"
:visible.sync="setRoleDialogVisible"
width="50%" @close="setRoleDialogClosed">
<div>
<p>当前的用户:{{userInfo.username}}</p>
<p>当前的角色:{{userInfo.role_name}}</p>
<p>分配新角色:
<el-select v-model="selectedRoleId" placeholder="请选择">
<el-option
v-for="item in rolesList"
:key="item.id"
:label="item.roleName"
:value="item.id">
</el-option>
</el-select></p>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="setRoleDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="saveRoleInfo">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
// 验证邮箱的规则
var checkEmail = (rule, value, cb) => {
// 验证邮箱的正则表达式
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if (regEmail.test(value)) {
// 合法的邮箱
return cb()
}
cb(new Error('请输入合法的邮箱'))
}
//验证手机号的规则
var checkMobile = (rule, value, cb) => {
// 验证手机号的正则表达式
const regMobile = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
if (regMobile.test(value)) {
return cb()
}
cb(new Error('请输入合法的手机号'))
}
return {
//获取用户列表的参数对象
queryInfo: {
//查询参数
query: '',
//当前页码
pagenum: 1,
//当前每页显示条数
pagesize: 2
},
UserList: [],
total: 0,
//控制添加用户对话框的显示与隐藏
addDialogVisible: false,
//添加用户的表单数据
addForm: {
username: '',
password: '',
email: '',
mobile: ''
},
//添加表单的验证规则对象
addFormRules: {
username: [{
required: true,
message: '请输入用户名',
trigger: 'blur'
},
{
min: 3,
max: 10,
message: '用户名的长度在 3 到 10 个字符之间',
trigger: 'blur'
}
],
password: [{
required: true,
message: '请输入密码',
trigger: 'blur'
},
{
min: 6,
max: 15,
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'
}]
},
//控制分配角色对话框的显示与隐藏
setRoleDialogVisible:false,
//需要被分配角色的用互信息
userInfo:{},
//所有角色的数据列表
rolesList:[],
// 已选中的角色id值
selectedRoleId:''
}
},
created() {
this.getUserList()
},
methods: {
async getUserList() {
const {
data: res
} = await this.$http.get('users', {
params: this.queryInfo
})
if (res.meta.status !== 200) {
return this.$message.error('获取用户列表失败')
}
this.UserList = res.data.users
this.total = res.data.total
},
// 监听pagesize改变的事件
handleSizeChange(newSize) {
this.queryInfo.pagesize = newSize
this.getUserList()
},
//监听页码值改变的事件
handleCurrentChange(newPage) {
this.queryInfo.pagenum = newPage
this.getUserList()
},
//监听switch开关状态的改变
async userStateChanged(userinfo) {
const {
data: res
} = await this.$http.put(`users/${userinfo.id}/state/${userinfo.mg_state}`)
if (res.meta.status !== 200) {
return this.$message.error('更新用户状态失败!')
}
this.$message.success('更新用户状态成功!')
},
//监听新增用户的关闭事件
addDialogClosed() {
this.$refs.addFormRef.resetFields()
},
//店家按钮添加新用户
addUser() {
this.$refs.addFormRef.validate(async valid => {
if (!valid) return
//可以发起添加用户的网络请求
const {
data: res
} = await this.$http.post('users', this.addForm)
if (res.meta.status != 201) {
return this.$message.error('添加用户失败!')
}
this.$message.success('添加用户成功!')
//隐藏添加用户对话框
this.addDialogVisible = false
this.getUserList()
})
},
//展示编辑用户的对话框
async showEditDialog(id) {
const {
data: res
} = await this.$http.get('users/' + id)
if(res.meta.status !== 200)
return this.$message.error('查询用户信息失败!')
this.editForm = res.data
this.editDialogVisible = true
},
//监听修改用户对话框的关闭事件
editDialogClosed(){
this.$refs.editFormRef.resetFields()
},
//修改用户信息并提交
editUserInfo(){
this.$refs.editFormRef.validate(async valid => {
if (!valid) return
//可以发起修改用户的网络请求
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('更新用户信息失败!')
}
//隐藏修改用户对话框
this.editDialogVisible = false
// 刷新列表列表
this.getUserList()
// 提示用户信息修改成功
this.$message.success('更新用户信息成功!')
})
},
// 根据id删除对应的用户信息
async removeUserById(id){
//弹框询问用户是否删除数据
const confirmRes=await this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err=>err)
//console.log(confirmRes)
//如果用户确认删除,则返回值为字符串confirm
//如果用户取消删除,则返回值为字符串cancel
if(confirmRes!=='confirm') {
return this.$message.info('已取消了删除!')
}
const {
data: res
} = await this.$http.delete('users/'+id)
if (res.meta.status !== 200) {
return this.$message.error('删除用户失败!')
}
// 刷新列表列表
this.getUserList()
// 提示用户信息修改成功
this.$message.success('删除用户信息成功!')
},
//展示分配角色的对话框
async setRole(userInfo){
this.userInfo=userInfo
//在展示对话框之前获取所有的角色列表
const {data:res}=await this.$http.get('roles')
if(res.meta.status!==200){
return this.$message.error('获取角色列表失败!')
}
this.rolesList=res.data
this.setRoleDialogVisible=true
},
async saveRoleInfo(){
if(!this.selectedRoleId){
return this.$message.error('请选择要分配的角色!')
}
const {data:res}=await this.$http.put(`users/${this.userInfo.id}/role`,{rid:this.selectedRoleId})
if(res.meta.status!==200){
return this.$message.error('更新角色失败!')
}
this.$message.success('更新角色成功!')
this.getUserList()
this.setRoleDialogVisible=false
},
//监听分配角色对话框的关闭事件
setRoleDialogClosed(){
this.selectedRoleId=''
this.userInfo={}
}
}
}
</script>
<style lang="less" scoped>
</style>
大家如果需要数据库和后端的接口以及有任何问题和建议欢迎大家留言,会持续更新,谢谢支持!!