一、 需求分析
教师管理主要针对充值教师进行管理,首先开发教师管理模块中的列表功能,包含条件查询、下拉框、日期功能、 数据列表、分页。
二、 教师数据列表
1 nodejs 添加数据列表接口,去node文件,在创建一个teacher.js,创建教师的一个规则:
const mongoose = require('mongoose')
mongoose.connect('mongodb://localhost/test') //和test数据库创建连接
module.exports = mongoose.model('Teacher', { //数据库的规则
jobnumber: {
type: String,
required: true
},
name: {
type: String,
required: true
},
role: {
type: String,
required: true
},
entrydate: {
type: String,
required: true
},
phone: {
type: String,
required: true
}
})
2.让路由管理一下他,在router.js中引入
let Teacher = require('./teacher.js')
3.然后在下面写一个接口,在这之前,先把数据存到数据库中,创建出Teacher这个表,打开mongoose
mongo
use 数据库名称
db.createCollection("teachers")
2(教师) 1(班主任)
工号 姓名 职务 入职时间 电话db.teachers.insert([{'jobnumber':'001','name':'申秀莲','role':'1','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'002','name':'周蛋挞','role':'1','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'003','name':'千瑞珍','role':'2','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'004','name':'吴允熙','role':'2','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'005','name':'夏博士','role':'1','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'006','name':'杨狗蛋','role':'1','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'007','name':'麻辣烫','role':'1','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'008','name':'闵雪雅','role':'1','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'009','name':'周锡京','role':'2','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'0010','name':'夏恩星','role':'1','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'0011','name':'下线','role':'1','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'0012','name':'泡菜小锅','role':'2','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'0013','name':'周周','role':'1','entrydate':'2015-11-11','phone':'15022221111'},{'jobnumber':'0014','name':'下班','role':'1','entrydate':'2015-11-11','phone':'15022221111'}])
db.teachers.find()
4.写一个接口,在router.js中添加获取教师列表方法
// 访问教师管理
// 查询所有---获取教师列表
router.get("/teacher/list", (req, res) => {
Teacher.find({}).then((data, err) => {
if (err) {
return res.status(500).json({ //如果err,就是错误就是数据库中没有
code: 3000,
flag: false,
message: "服务器后台错误"
})
}
// 分页需要数据的长度
let content = data.length
return res.status(200).json({
"code": 2000,
"flag": true,
"message": "查询成功",
"data": {
content,
"rows": data
} //把数据返回出去
})
})
})
三、 Api 调用接口
1. 在 src/api 下创建 teacher.js , 调用接口代码如下:
import request from "@/utils/request";
export function getTeacherList() { //获取教师列表
return request({
url: "/teacher/list", //和node接口地址一致
method: "get",
})
}
2. 在 src\views\teacher\index.vue 中, 添加 JS 代码如下:
import { getTeacherList } from "@/api/teacher";
export default {
name: "Teacher",
created() {
this.getList()
},
methods: {
getList() {
getTeacherList().then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
}
}
}
</script>
3.点击教师的时候,能拿到下图数据
四、列表模板
1. 修改 src\views\teacher\index.vue ,编写模板代码:
<template>
<div>
<el-table :data="tableData" height="400" border style="width: 100%">
<el-table-column type="index" label="序号"> </el-table-column>
<el-table-column prop="jobnumber" label="工号"> </el-table-column>
<el-table-column prop="name" label="姓名"> </el-table-column>
<el-table-column prop="role" label="职务"></el-table-column>
<el-table-column prop="entrydate" label="入职时间"> </el-table-column>
<el-table-column prop="phone" label="电话"> </el-table-column>
</el-table>
</div>
</template>
<script>
import { getTeacherList } from "@/api/teacher";
export default {
name: "Teacher",
data() {
return {
tableData: []
}
},
created() {
this.getList()
},
methods: {
getList() {
getTeacherList().then(res => {
this.tableData = res.data.data.rows
}).catch(err => {
console.log(err);
})
}
}
}
</script>
<style></style>
五、解决CSS问题
之前的页面有些问题,下面改正:
1.去App.vue
<template>
<div id="app" v-cloak>
<router-view />
</div>
</template>
<style >
body,
html {
margin: 0 auto;
width: 100%;
height: 100%;
}
#app {
width: 100%;
height: 100%;
overflow: hidden;
}
[v-cloak] {
display: none;
}
</style>
2.layout.vue:
<template>
<div class="layout">
<app-header />
<app-main />
<app-navbar />
</div>
</template>
<script>
import AppHeader from "./AppHeader/index.vue";
import AppMain from "./AppMain/index.vue";
import AppNavbar from "./AppNavbar/index.vue";
export default {
components: {
AppHeader,
AppMain,
AppNavbar,
},
};
</script>
<style scoped>
.layout {
width: 100%;
height: 100%;
}
</style>
3AppHeader的index.vue:
<style scoped>
.header {
position: absolute;
line-height: 50px;
background-color: cornflowerblue;
padding: 0;
top: 0;
width: 100%;
}
.logo {
vertical-align: middle;
width: 30px;
padding: 0 10px 0 50px;
}
.company {
position:absolute;
color: white;
}
a {
text-decoration: none;
}
.el-dropdown {
float: right;
margin-right: 40px;
cursor: pointer;
color: white;
}
</style>
4.AppNavbar的index.vue:
<style scoped>
.navbar {
position: absolute;
top: 50px;
width: 16%;
left: 0;
background-color: darkseagreen;
overflow: hidden;
}
5.AppMain的index.vue:
<style scoped>
.main {
position: absolute;
top: 50px;
left: 16%;
width: 80%;
padding: 10px;
background-color: pink;
overflow: hidden;
/* z-index: 99; */
}
六、过滤器实现数据转换
1. 用过滤器在teacher的index.vue中,添加一个规则,然后去组件当中去使用,由于他只需要在当前组件中使用,所以写局部的一个:
<script>
import { getTeacherList } from "@/api/teacher";
let roleOptions = [
{ type: "1", name: "班主任" },
{ type: "2", name: "教师" },
];
export default {
name: "Teacher",
data() {
return {
tableData: [],
}
},
created() {
this.getList()
},
methods: {
getList() {
getTeacherList().then(res => {
console.log(res.data.data.rows);
this.tableData = res.data.data.rows
}).catch(err => {
console.log(err);
})
}
},
filters: {
roleFilter(val) {
// if (val == '1') {
// val = '班主任'
// } else {
// val = '教师'
// }
// return val
// ------------------------------------
// obj return出来的是符合条件的那一条数据
let obj = roleOptions.find(item => {
return item.type === val
})
return obj ? obj.name : null
}
}
}
</script>
2.修改 模板代码
<el-table-column prop="role" label="职务">
<template slot-scope="scope">
<span style="margin-left: 10px">{{ scope.row.role | roleFilter }</span>
</template>
</el-table-column>
3.在“电话”后添加删除和修改:
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)"
>编辑</el-button
>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>删除</el-button
>
</template>
</el-table-column>
4.在方法里添加:
handleEdit(index, row) {
console.log(index, row);
},
handleDelete(index, row) {
console.log(index, row);
},
七、分页功能实现
1.为列表数据添加分页功能,使用分页组件完成分页功能,去node文件的router.js中,添加分页模拟接口
// 分页
router.post("/teacher/listPage", (req, res) => {
console.log(req.body);
})
2. Api 调用接口,在 src\api 下的 teacher.js ,增加分页查询
export function getListPage(page, size, searchMap) { //分页
return request({
url: "/teacher/listPage",
method: "post",
data: {
page,
size,
searchMap
}
})
}
3.在 src\views\teacher\index.vue 中,引入
import { getTeacherList, getListPage } from "@/api/teacher";
在created 时获取分页数据:
created() {
this.getList()
this.ListPage()
},
methods: {
// 1.获取教师列表
getList() {
getTeacherList().then(res => {
console.log(res.data.data.rows);
this.tableData = res.data.data.rows
}).catch(err => {
console.log(err);
})
},
// 分页
ListPage() {
getListPage(1, 2, 3).then(res => {//先传参数,看后端是否接收到
console.log(res);
}).catch(err => {
console.log(err);
})
},
后台拿到数据:
现在添加HTML分页的模板,添加代码如下:
<template>
<div>
<el-table :data="tableData" height="400" border style="width: 100%">
<el-table-column type="index" label="序号"> </el-table-column>
<el-table-column prop="jobnumber" label="工号"> </el-table-column>
<el-table-column prop="name" label="姓名"> </el-table-column>
<el-table-column prop="role" label="职务">
<template slot-scope="scope">
<span style="margin-left: 10px">{{ scope.row.role | roleFilter }}</span>
</template>
</el-table-column>
<el-table-column prop="entrydate" label="入职时间"> </el-table-column>
<el-table-column prop="phone" label="电话"> </el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage"
:page-sizes="[100, 200, 300, 400]" :page-size="100" layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
</div>
</template>
现在分页效果:
数据都是假的,我们让他展示从后台拿到的数据
4.在data里:
data() {
return {
tableData: [],
currentPage: 1,//当前页数
pageSize: 5,//每页显示多少条数据
pageSizes: [5, 10, 15, 20],// 每页显示个数选择器的选项设置
total: 0,
searchMap: {}//后面用来搜索查询的数据
}
},
5.在node终端能拿到页码数,然后在node的router.js中:
// 分页
router.post("/teacher/listPage", (req, res) => {
let page = req.body.page || 1; //页数
let size = req.body.size || 10; //一页显示多少条
let searchMap = req.body.searchMap || {} //用来做条件查询的
// console.log(page, size, searchMap);
let obj = {} //用来接收??数据
Teacher.find(obj).then((data, err) => { //去数据库中查找
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: "服务器后台错误"
})
}
let content = data.length
//skip跳过多少条,limit查询多少个,exec当前面的代码,执行完毕后,产生的回调
Teacher.find(obj).skip((page - 1) * parseInt(size)).limit(parseInt(size)).exec().then((data, err) => {
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: "服务器后台错误"
})
}
return res.status(200).json({
"code": 2000,
"flag": true,
"message": "查询成功",
"data": {
content,
"rows": data
}
})
})
})
})
6.我们获取的列表数据显示在页面上,这次是用分页接口拿到了数据列表,上面的获取教师列表接口和函数,可以不用了,用分页接口返回来的数据就可以,他刚好按分页返回来的数据,代码:
created() {
// this.getList()
this.ListPage()
},
// 1.获取教师列表
// getList() {
// getTeacherList().then(res => {
// this.tableData = res.data.data.rows
// }).catch(err => {
// console.log(err);
// })
// },
// 分页并获取教师列表
ListPage() {
getListPage(this.currentPage, this.pageSize, this.searchMap).then(res => {
// console.log(res);
let resArr = res.data
this.total = resArr.data.content
this.tableData = resArr.data.rows
}).catch(err => {
console.log(err);
})
},
7.运行效果:
八、解决动态页码和当前页
问题:上面当你改变页码后,请求URL的 {page}/{size} 不会变,一直是初始值,那是因为没有监听到改变的值。
解决:在 methods 中添加函数,
handleSizeChange(val) {
this.pageSize = val;
this.ListPage()
},
handleCurrentChange(val) {
this.currentPage = val;
this.ListPage()
},
3. 测试可通过。
九、条件查询实现-----在列表上方添加查询功能。
1. 修改 src\views\teacher\index.vue ,增加条件查询模板代码,并在方法中去调用他们:
<template>
<div>
<!-- 搜索区 -->
<el-form :inline="true" :model="searchMap" ref="searchForm" class="demo-form-inline">
<!-- prop 表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的 -->
<el-form-item label="工号" prop="jobnumber">
<el-input v-model="searchMap.jobnumber" placeholder="工号"></el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="searchMap.name" placeholder="姓名"></el-input>
</el-form-item>
<el-form-item label="职务" prop="role">
<el-select v-model="searchMap.role" placeholder="职务">
<el-option :key="index" v-for="(item, index) in roleOptions" :label="item.name"
:value="item.type"></el-option>
</el-select>
</el-form-item>
<el-form-item label="入职时间" prop="entrydate">
<el-date-picker type="date" placeholder="选择日期" v-model="searchMap.entrydate"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">查询</el-button>
<el-button @click="resetForm('searchForm')">重置</el-button>
</el-form-item>
</el-form>
<!-- 教师列表 -->
<el-table :data="tableData" height="400" border style="width: 100%">
<el-table-column type="index" label="序号"> </el-table-column>
<el-table-column prop="jobnumber" label="工号"> </el-table-column>
<el-table-column prop="name" label="姓名"> </el-table-column>
<el-table-column prop="role" label="职务">
<template slot-scope="scope">
<span style="margin-left: 10px">{{ scope.row.role | roleFilter }}</span>
</template>
</el-table-column>
<el-table-column prop="entrydate" label="入职时间"> </el-table-column>
<el-table-column prop="phone" label="电话"> </el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页区 -->
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage"
:page-sizes="pageSizes" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</template>
2.js部分:
<script>
import { getListPage } from "@/api/teacher";
let roleOptions = [
{ type: "1", name: "班主任" },
{ type: "2", name: "教师" },
];
export default {
name: "Teacher",
data() {
return {
tableData: [],//列表——教师列表数据
currentPage: 1,//当前页数
pageSize: 5,//每页显示多少条数据
pageSizes: [5, 10, 15, 20],// 每页显示个数选择器的选项设置
total: 0,
searchMap: {//搜索栏数据
jobnumber: "",
name: "",
role: "",
entrydate: ""
},
roleOptions//简写形式,=>roleOptions:roleOptions
}
},
created() {
this.ListPage()// 页面初始化完成加载分页并获取教师列表
},
methods: {
// 分页并获取教师列表
ListPage() {
getListPage(this.currentPage, this.pageSize, this.searchMap).then(res => {
// console.log(res);
let resArr = res.data
this.total = resArr.data.content
this.tableData = resArr.data.rows
}).catch(err => {
console.log(err);
})
},
// 编辑
handleEdit(index, row) {
console.log(index, row);
},
// 删除
handleDelete(index, row) {
console.log(index, row);
},
//element-ui 的控制表格方法
handleSizeChange(val) {
this.pageSize = val;
this.ListPage()
},
//element-ui 的控制表格方法
handleCurrentChange(val) {
this.currentPage = val;
this.ListPage()
},
// 查询
onSubmit() {
// 点击查询,重新分页并获取教师列表
this.currentPage = 1;
this.ListPage()
},
//element-ui 的重置方法
resetForm(formName) {
this.$refs[formName].resetFields();
// 点击重置,重新分页并获取教师列表
this.currentPage = 1;
this.ListPage()
}
},
filters: {
roleFilter(val) {
// if (val == '1') {
// val = '班主任'
// } else {
// val = '教师'
// }
// return val
// ------------------------------------
// obj return出来的是符合条件的那一条数据
let obj = roleOptions.find(item => {
return item.type === val
})
return obj ? obj.name : null
}
}
}
</script>
3.在node文件的router.js中,添加条件查询代码:
// 分页
router.post("/teacher/listPage", (req, res) => {
let page = req.body.page || 1; //页数
let size = req.body.size || 10; //一页显示多少条
let searchMap = req.body.searchMap || {} //用来做条件查询的
// console.log(page, size, searchMap);
let obj = {} //用来接收搜索栏数据,实现按条件查询
// searchMap中是否包含jobnumber、name、role、entrydate,如果有,把他们存到obj里
searchMap.jobnumber ? obj["jobnumber"] = searchMap.jobnumber : obj
searchMap.name ? obj["name"] = searchMap.name : obj
searchMap.role ? obj["role"] = searchMap.role : obj
searchMap.entrydate ? obj["entrydate"] = searchMap.entrydate : obj
console.log(searchMap, obj);
Teacher.find(obj).then((data, err) => { //去数据库中查找
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: "服务器后台错误"
})
}
let content = data.length
//skip跳过多少条,limit查询多少个,exec当前面的代码,执行完毕后,产生的回调
Teacher.find(obj).skip((page - 1) * parseInt(size)).limit(parseInt(size)).exec().then((data, err) => {
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: "服务器后台错误"
})
}
return res.status(200).json({
"code": 2000,
"flag": true,
"message": "查询成功",
"data": {
content,
"rows": data
}
})
})
})
})
注释:searchMap和obj都是能去数据库中查到数据的,直接用searchMap也能查到数据,为什么还要再用obj去查询数据?
原因:先看图:
如图,因为searchMap打印的是所有的条件,而obj打印的是你在搜索栏输入了哪个条件,就会根据哪个条件去查找
4.接下来我们的搜索栏部分就完成了,但是测试的时候发现时间查询查不到数据,我们看看问题出现在哪里,(学会查看问题是开发中很重要的一步):
我们在后台看到时间打印出来的信息:
而我们存储数据时的格式是这样的:
我们去element-ui官网去查找看有没有控制格式的,我们发现:
所以我们添加value-format="yyyy-MM-dd"就好了:
<el-form-item label="入职时间" prop="entrydate">
<el-date-picker type="date" placeholder="选择日期" value-format="yyyy-MM-dd" v-
model="searchMap.entrydate"></el-date-picker>
</el-form-item>
后台时间格式:
查询成功: