vue通用后台管理系统(四)
四、用户管理页面及登录页面
1. 用户管理页面
(1)用户管理页面及form组件介绍
用户管理页面分为三个部分:右上侧的表单搜索区,可以对用户进行搜索过滤;中间是列表的展示区,包含用户的姓名、年龄、性别、出生日期、地址和操作(对每一行数据进行编辑和删除)以及分页;左上角的新增区,可以新增用户信息
elementui----提供form表单、Pagination分页
(2)用户管理页面功能form页面编写
点击新增会弹出一个信息框,进行用户信息的新增
elementUI ----Dialog对话框 ,form表单....ui框架真的好方便啊
//User.vue
<template>
<div class="manage">
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="50%">
<!-- 用户的表单信息 -->
<el-form ref="form" :inline="true" :model="form" label-width="80px">
<el-form-item label="姓名">
<el-input placeholder="请输入姓名" v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="年龄">
<el-input placeholder="请输入年龄" v-model="form.age"></el-input>
</el-form-item>
<el-from-item label="性别">
<el-select v-model="formInline.sex" placeholder="请选择">
<el-option label="男" value="1"></el-option>
<el-option label="女" value="0"></el-option>
</el-select>
</el-from-item>
<el-form-item label="出生日期">
<el-date-picker
v-model="form.birth"
type="date"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
<el-form-item label="地址">
<el-input placeholder="请输入地址" v-model="form.addr"></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="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
<div class="manage-header">
<el-button @click="dialogVisible=true" type="primary">
+ 新增
</el-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
dialogVisible: false,
form: {
name: '',
age: '',
sex: '',
birth: '',
addr:''
}
}
}
}
</script>
<style>
</style>
(3)用户管理页面form新增功能编写
在表单中未填写内容时点击确定提交----应该给一个必填的校验提示 ;点击确定时----应该拿到当前填写的数据
添加校验----elementui表单验证
通过rules设置表单验证的规则:
rules: {
name: [
{ required: true, message: '请输入姓名' }
],
age: [
{ required: true, message: '请输入年龄' }
],
sex: [
{ required: true, message: '请选择性别' }
],
birth: [
{ required: true, message: '请选择出生日期' }
],
addr: [
{ required: true, message: '请填写地址' }
],
}
在提交用户表单时(确定或取消),需要对表单信息进行校验
//提交用户表单
submit() {
//判断用户是否通过校验
this.$refs.form.validate((valid) => {
//如果通过校验,valid为true
if (valid) {
//后续对表单数据的处理
//清空表单的数据
this.$refs.form.resetFields()
//关闭弹窗
this.dialogVisible = false;
}
})
},
//弹窗关闭的时候触发
handleClose() {
this.$refs.form.resetFields()
this.dialogVisible=false
},
cancel() {
this.handleClose()
}
}
(4)用户管理页面table数据获取
① 使用mock仿真数据 ---src/api/mockServeData/uer.js
import Mock from 'mockjs'
// get请求从config.url获取参数,post从config.body中获取参数
function param2Obj(url) {
const search = url.split('?')[1]
if (!search) {
return {}
}
return JSON.parse(
'{"' +
decodeURIComponent(search)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"') +
'"}'
)
}
let List = []
const count = 200
for (let i = 0; i < count; i++) {
List.push(
Mock.mock({
id: Mock.Random.guid(),
name: Mock.Random.cname(),
addr: Mock.mock('@county(true)'),
'age|18-60': 1,
birth: Mock.Random.date(),
sex: Mock.Random.integer(0, 1)
})
)
}
export default {
/**
* 获取列表
* 要带参数 name, page, limt; name可以不填, page,limit有默认值。
* @param name, page, limit
* @return {{code: number, count: number, data: *[]}}
*/
getUserList: config => {
const { name, page = 1, limit = 20 } = param2Obj(config.url)
console.log('name:' + name, 'page:' + page, '分页大小limit:' + limit)
const mockList = List.filter(user => {
if (name && user.name.indexOf(name) === -1 && user.addr.indexOf(name) === -1) return false
return true
})
const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
return {
code: 20000,
count: mockList.length,
list: pageList
}
},
/**
* 增加用户
* @param name, addr, age, birth, sex
* @return {{code: number, data: {message: string}}}
*/
createUser: config => {
const { name, addr, age, birth, sex } = JSON.parse(config.body)
console.log(JSON.parse(config.body))
List.unshift({
id: Mock.Random.guid(),
name: name,
addr: addr,
age: age,
birth: birth,
sex: sex
})
return {
code: 20000,
data: {
message: '添加成功'
}
}
},
/**
* 删除用户
* @param id
* @return {*}
*/
deleteUser: config => {
const { id } = JSON.parse(config.body)
if (!id) {
return {
code: -999,
message: '参数不正确'
}
} else {
List = List.filter(u => u.id !== id)
return {
code: 20000,
message: '删除成功'
}
}
},
/**
* 批量删除
* @param config
* @return {{code: number, data: {message: string}}}
*/
batchremove: config => {
let { ids } = param2Obj(config.url)
ids = ids.split(',')
List = List.filter(u => !ids.includes(u.id))
return {
code: 20000,
data: {
message: '批量删除成功'
}
}
},
/**
* 修改用户
* @param id, name, addr, age, birth, sex
* @return {{code: number, data: {message: string}}}
*/
updateUser: config => {
const { id, name, addr, age, birth, sex } = JSON.parse(config.body)
const sex_num = parseInt(sex)
List.some(u => {
if (u.id === id) {
u.name = name
u.addr = addr
u.age = age
u.birth = birth
u.sex = sex_num
return true
}
})
return {
code: 20000,
data: {
message: '编辑成功'
}
}
}
}
② 请求mock中的数据
---src/api/index.js
export const getUser = (params) => {
//返回用户列表
return http.get('/user/getUser', params)
}
export const addUser = (data) => {
return http.post('/user/add', data)
}
export const editUser = (data) => {
return http.post('/user/edit', data)
}
export const delUser = (data) => {
return http.post('/user/del', data)
}
③ 获取mock中的数据
(5)用户管理页面table页面编写
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
prop="name"
label="姓名">
</el-table-column>
<el-table-column
prop="sex"
label="性别">
<template slot-scope="scope">
<i class="el-icon-time"></i>
// 通过 Scoped slot 可以获取到 row, column, $index 和 store(table 内部的状态管理)的数据
<span style="margin-left: 10px">{{ scope.row.sex ==1 ?'男':'女' }}</span>
</template>
</el-table-column>
<el-table-column
prop="age"
label="年龄">
</el-table-column>
<el-table-column
prop="birth"
label="出生日期">
</el-table-column>
<el-table-column
prop="addr"
label="地址">
</el-table-column>
<el-table-column
prop="addr"
label="地址">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
(6)用户管理页面新增编辑提交功能编写
点击新增打开之后是一个弹窗,然后在弹窗表单中填写用户信息后再点击确定----将用户填写的信息去调用接口
注:新增和编辑的弹窗是复用的,可以通过store中的state来区分是新增还是编辑--如果是新增,则用户信息开始是空白的,反之则是编辑
新增功能编写:先调用新增的接口去插入数据,然后再调用获取数据的接口去更新数据 (addUser -> getUser)
注:对于公共的方法可以进行方法的封装
删除的逻辑:
handleDelete(row) {
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delUser({id: row.id }).then(() => {
this.$message({
type: 'success',
message: '删除成功!'
});
//重新获取列表的接口
this.getList()
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
(7)用户管理页面剩余功能解决
① 调整样式---table数据的高度
② 分页组件----elementui Pagination分页----带斑马纹表格
③ 搜索表单
扩展运算符可合并对象:{...this.userForm,...this.pageData }
2.权限管理功能--面试高频
(1)权限管理功能介绍
①当前系统必须通过登录页进行登录之后才可以进入 ②当前系统会有对应的权限-菜单权限,和用户相关
(2)登录页面
登录路由/login,创建路由 ----->引入路由----->创建路由实例
本质是一个form表单加上一个校验---表单验证elementui --form中的rules属性
① 定义rules
② 结构的搭建
<template>
<el-form :model="form" :rules="rules">
<h3 class="login_title">系统登录</h3>
<el-form-item label="用户名" prop="username">
<!-- 数据的双向绑定 -->
<el-input v-model="form.username" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item label="密码" prop="username">
<!-- 数据的双向绑定 -->
<el-input type="password" v-model="form.password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary">登录</el-button>
</el-form-item>
</el-form>
</template>
③ 样式的布局
<template>
<el-form label-width="70px" class="login-container" :model="form" :rules="rules">
<h3 class="login_title">系统登录</h3>
<el-form-item label="用户名" prop="username">
<!-- 数据的双向绑定 -->
<el-input v-model="form.username" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item label="密码" prop="username">
<!-- 数据的双向绑定 -->
<el-input type="password" v-model="form.password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item>
<el-button style="margin-left: 50px;margin-top: 4px;" type="primary">登录</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
form: {
username: '',
password:''
},
rules: {
username: [
{ required: true, trigger: 'blur',messsage:'请输入用户名' }
],
password: [
{ required: true, trigger: 'blur', messsage: '请输入密码' }
]
}
}
}
}
</script>
<style lang="less" scoped>
.login-container {
width: 350px;
border: 1px solid #eaeaea;
margin: 180px auto;
padding:35px 35px 15px 35px;
background-color: #fff;
border-radius: 15px;
box-shadow: 0 0 25px #cac6c6;
box-sizing: border-box;
.login_title {
text-align: center;
margin-bottom: 40px;
color:#505458;
}
el-input {
width: 198px;
}
}
</style>
(3)登录权限和导航守卫
当用户开始登录时,系统会先识别当前用户,对用户的权限进行一个判断,同时不同的用户登录进来可以看到的页面也不同----添加用户权限token--判断用户是否合法
下载cookie插件,存储token信息:npm i js-cookie@3.0.1
在页面发生跳转的时候判断token存不存在,根据存在与否做出不同的操作----导航守卫
①mock模拟后端发出token信息:src/api/mockServeData/permission.js
import Mock from 'mockjs'
export default {
getMenu: config => {
const { username, password } = JSON.parse(config.body)
// 先判断用户是否存在
// 判断账号和密码是否对应
if (username === 'admin' && password === 'admin') {
return {
code: 20000,
data: {
menu: [
{
path: '/home',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home.vue'
},
{
path: '/mall',
name: 'mall',
label: '商品管理',
icon: 'video-play',
url: 'Mall.vue'
},
{
path: '/user',
name: 'user',
label: '用户管理',
icon: 'user',
url: 'User.vue'
},
{
label: '其他',
icon: 'location',
children: [
{
path: '/page1',
name: 'page1',
label: '页面1',
icon: 'setting',
url: 'PageOne.vue'
},
{
path: '/page2',
name: 'page2',
label: '页面2',
icon: 'setting',
url: 'PageTwo.vue'
}
]
}
],
token: Mock.Random.guid(),
message: '获取成功'
}
}
} else if (username === 'xiaoxiao' && password === 'xiaoxiao') {
return {
code: 20000,
data: {
menu: [
{
path: '/home',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home.vue'
},
{
path: '/video',
name: 'video',
label: '商品管理',
icon: 'video-play',
url: 'Mall.vue'
}
],
token: Mock.Random.guid(),
message: '获取成功'
}
}
} else {
return {
code: -999,
data: {
message: '密码错误'
}
}
}
}
}
(4)菜单权限功能
① 不同的账号登录,会有不同的菜单权限
② 通过url 输入地址来显示页面
-----动态添加、动态注册路由
③ 对于菜单的数据在不同页面之间的数据通信
-----没咋懂,好难,后面再来过一遍---------