目录
添加 handleSizeChange 和 handleCurrentChange 方法,实现动态赋值与刷新列表
一、学员管理-列表查询
1.1 分页查询学员数据列表
1.1.1 nodejs 添加分页数据列表接口
创建student.js:
var mongoose = require('require');
mongoose.connect('mongodb://localhost/stu');
var Schema = mongoose.Schema;
var userSchema = new Schema({
stunum: {// 学号
type: String,
required: true
},
name: {
type: String,
required: true
},
adminssiondate: {// 入学时间
type: String,
required: true
},
phone: {
type: String,
required: true
},
teacher: {// 授课教师
type: String,
required: true
},
class: {
type: String,
required: true
},
job: {
type: String,
required: true
},
money: {// 薪资待遇
type: String,
required: true
},
})
module.exports = mongoose.model('Student', userSchema);
router.js中添加方法:
//?获取学生信息(带分页)
router.post('/student', function (req, res) {
//* 前端传入
const body = req.body;
let page = body.page;
let size = body.size;
let searchMap = body.searchMap;
//* 后端真正的判定条件
const obj = {};//将所有的查询条件放到obj中
searchMap.stunum ? obj['stunum'] = searchMap.stunum : obj;
searchMap.name ? obj['name'] = searchMap.name : obj;
searchMap.adminssiondate ? obj['adminssiondate'] = searchMap.adminssiondate : obj;
searchMap.teacher ? obj['teacher'] = searchMap.teacher : obj;
searchMap.class ? obj['class'] = searchMap.class : obj;
searchMap.job ? obj['job'] = searchMap.job : obj;
searchMap.money ? obj['money'] = searchMap.money : obj;
//这种写法,相当于给对象添加一个新的key,后边给key进行赋值,类似于添加新的属性.
Student.find(obj, function (err, data) {
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: 'server error'
})
}
// 查询成功,进行分页
const count = data.length;
Student.find(obj).skip((page - 1) * parseInt(size)).limit(parseInt(size)).exec(function (err, data) {
//exec方法,等前边查询截取限制一系列操作完成之后,再进行回调.
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: 'server error'
})
}
return res.status(200).json({
code: 2000,
flag: true,
message: '查找学生信息成功',
data: {
total: count,//总共返回多少条数据
rows: data,//真正的data
}
})
})
})
})
1.1.2 Api调用接口
在 src/api 下创建 student.js , 在导出的默认对象中,增加带分页查询方法调用接口代码如下:
import request from '@/utils/request.js'
export default {
//?带分页查找
search(page,size,searchMap) {
return request({
url: '/student/list',
method: 'post',
data: {
page,
size,
searchMap
}
})
}
}
在 src\views\student\index.vue 中, 添加 JS 代码如下:
import studentApi from '@/api/student.js'//导入Api
export default {
data() {
return {
tableData: [],//学生列表
currentPage: 1,//默认第一页
pageSize: 10,//每页默认分十条
searchMap: {
stunum: '',
name: '',
admissionDate: '',
teacher: '',
class: '',
job: '',
money: '',
},
total: 0,//总记录数
}
},
components: {},
created() {
this.fetchData()
},
methods: {
fetchData() {
studentApi.search(this.currentPage, this.pageSize, this.searchMap
).then(response => {
this.tableData = response.data.data.rows;
this.total = response.data.data.total;
})
}
},
}
1.1.3 列表与分页模板
在数据库中先手动添加数据
模板代码:
<!-- 学生列表 -->
<el-table
:data="tableData"
height="380"
border
style="width: 100%"
>
<!-- 绑定序号时,可以传index作为prop的键值,但用这种方法,就需要用type作键名 -->
<el-table-column
type="index"
label="序号"
width="80"
>
</el-table-column>
<el-table-column
prop="stunum"
label="学号"
width="80"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="100"
>
</el-table-column>
<el-table-column
prop="admissionDate"
label="入学时间"
width="200"
>
</el-table-column>
<el-table-column
prop="phone"
label="电话"
width="120"
>
</el-table-column>
<el-table-column
prop="teacher"
label="教师"
width="100"
>
</el-table-column>
<el-table-column
prop="class"
label="班级"
width="80"
>
</el-table-column>
<el-table-column
prop="job"
label="工作去向"
width="180"
>
</el-table-column>
<el-table-column
prop="money"
label="薪资待遇"
width="80"
>
</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="this.currentPage"
:page-sizes="[5, 10, 20]"
:page-size="this.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="this.total"
>
</el-pagination>
添加 handleSizeChange 和 handleCurrentChange 方法,实现动态赋值与刷新列表
handleSizeChange(val) {
//console.log(`每页 ${val} 条`);
this.pageSize = val;
this.fetchData();
},
handleCurrentChange(val) {
//console.log(`当前页: ${val}`);
this.currentPage = val;
this.fetchData();
},
fetchData() {
studentApi.search(this.currentPage, this.pageSize, this.searchMap
).then(response => {
this.tableData = response.data.data.rows;
this.total = response.data.data.total;
})
}
测试查看效果:
1.2 条件查询实现
1.2.1 条件查询模板
修改 src\views\student\index.vue ,增加条件查询模板代码:
<!-- 行内表单 条件查找 -->
<el-form
:inline="true"
:model="searchMap"
ref="searchForm"
style="margin-top:20px"
>
<el-form-item prop='stunum'>
<!-- 绑定prop才可以使用 -->
<el-input
v-model="searchMap.stunum"
placeholder="学号"
></el-input>
</el-form-item>
<el-form-item prop='name'>
<el-input
v-model="searchMap.name"
placeholder="姓名"
></el-input>
</el-form-item>
<el-form-item prop='teacher'>
<el-input
v-model="searchMap.teacher"
placeholder="授课教师"
></el-input>
</el-form-item>
<el-form-item prop='class'>
<el-input
v-model="searchMap.class"
placeholder="班级"
></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="searchData"
>查询</el-button>
<el-button type="primary">新增</el-button>
<el-button
type="primary"
@click="resetData('searchForm')"
>重置</el-button>
</el-form-item>
</el-form>
1.2.2 授课教师选择(父子组件信息传递)
将 teacher\index.vue 导入 student\index.vue 作为子组件使用
Component 中注册 Teacher 作为子组件
import Teacher from '@/views/teacher'//将教师作为子组件导入
components: { Teacher },
使用 dialog 对话框组件,包裹 Teacher 组件
<!-- 教师信息弹窗 -->
<el-dialog
title="选择教师"
:visible.sync="dialogTeacherVisible"
width="30%"
>
<teacher></teacher>
</el-dialog>
修改 授课教师 输入框readonly 只读框@click.native 点击事件。
注意: el-input 是组件,要在组件元素监听原生事件,需要使用 v-on:原生事件名.native="处理函数"
<el-form-item prop='teacher'>
<el-input
v-model="searchMap.teacher"
placeholder="授课教师"
readonly
@click.native="dialogTeacherVisible = true"
></el-input><!-- @click.native是原生点击事件 -->
</el-form-item>
教师页面在弹出时候很多是我们不需要的, 进行优化,父组件向子组件传递数据:通过 props 声明接收向教师 Teacher 子组件传入一个参数 isDialog , 如果是弹出窗口, 则弹出页面隐藏一些功能.
在 student\index.vue 上的 <teacher> 组件标签上绑定属性 :isDialog="true"
通过修改isDialog属性,来控制显示与不显示.
<teacher :isDialog='true'></teacher>
在 teacher\index.vue 中通过 props 选项 声明接收 isDialog
props: {// 父组件中传递的 isDialog 值通过子组件中 props 接收
// 接收父组件传递过来 的数据,通过isDialog来判断 是否为弹框
// 如果为 true, 则是弹框, false 就是列表
isDialog: Boolean
},
在分页组件中,采用三元表达式
:layout="
isDialog ? 'prev,pager,next':'total, sizes, prev, pager, next, jumper'
"
当点击列表中某一行教师,即选中;选中的那个教师数据传回到父组件 学员管理 中
<!-- highlight-current-row 激活单选行, isDialog为true时激活
@current-change 当点击某一行后,会触发这个事件,从而调用对应的函数clickCurrentChange
clickCurrentChange函数会接收两个参数:currentRow,oldCurrentRow
-->
<el-table
:data="tableData"
height="300"
border
style="width: 100%"
class="table"
:highlight-current-row="isDialog"
@current-change="clickCurrentChange"
>
在 teacher\index.vue 组件定义 clickCurrentChange 函数,向父组件传递点击数据。子组件向父组件传递数据:通过 $emit 触发事件的方式
clickCurrentChange(correntRow) {// 当点击某一行时,会调用这个函数进行处理
// 点击后,要将点击的数据传递到父组件,
// 则可以通过触发父组件中的option-teacher, 触发之后 ,
//父组件可以在 option-teacher 这个事件对应的处理函数中进行接收数据currentRow
this.$emit('option-teacher', correntRow)
},
在父组件 student\index.vue 的组件元素 teacher 上绑定自定义事件 option-teacher
<teacher
:isDialog='true'
@option-teacher='optionTeacher'
></teacher>
在父组件 student\index.vue 中添加 option-teacher 事件触发的函数 optionTeacher 进行回显数据
optionTeacher(correntRow) {//如果有correntRow,就把他放到查找框去
this.searchMap.teacher = correntRow.name;
this.dialogTeacherVisible = false;
},
1.2.3 重置功能
在 条件查询区域添加 一个 重置 按钮, 直接在上面调用重置方法, 注意 'searchForm'
<el-button
type="primary"
@click="resetData('searchForm')"
>重置</el-button>
resetData(formName) {
this.$refs[formName].resetFields();
this.fetchData();
},
二、学员管理-新增
2.1 新增窗口实现
在 src\views\student\index.vue 中分页区域的下方,新增对话框形式表单数据模板
<!-- 学生新增或编辑 弹窗 -->
<el-dialog
title="学员编辑"
:visible.sync="dialogFormVisible"
width="500px"
>
<el-form
:model="pojo"
:rules="rules"
ref="pojoForm"
label-width="100px"
label-position="right"
style="wideth=400px"
>
<el-form-item
label="学号"
prop="stunum"
>
<el-input v-model="pojo.stunum"></el-input>
</el-form-item>
<el-form-item
label="姓名"
prop="name"
>
<el-input v-model="pojo.name"></el-input>
</el-form-item>
<el-form-item
label="授课教师"
prop="teacher"
>
<el-input
v-model="pojo.teacher"
readonly
@click.native='dialogOptionTeacher'
></el-input>
</el-form-item>
<el-form-item
label="班级"
prop="class"
>
<el-input v-model="pojo.class"></el-input>
</el-form-item>
<el-form-item
label="入学时间"
prop="admissionDate"
>
<el-date-picker
v-model="pojo.admissionDate"
type="date"
placeholder="选择日期"
value-format='yyyy-MM-dd'
>
</el-date-picker>
</el-form-item>
<el-form-item
label="联系方式"
prop="phone"
>
<el-input v-model="pojo.phone"></el-input>
</el-form-item>
<el-form-item
label="工作去向"
prop="job"
>
<el-input v-model="pojo.job"></el-input>
</el-form-item>
<el-form-item
label="薪资"
prop="money"
>
<el-input v-model="pojo.money"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary">提交</el-button>
<el-button @click="dialogFormVisible = false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
data 选项中声明变量属性:pojo 提交表单对象,dialogFormVisible 当它为 true 弹出,false 不弹,rules : 定义校验规则
pojo: {
_id: null,
stunum: '',
name: '',
teacher: '',
class: '',
admissionDate: '',
phone: '',
job: '',
money: '',
},
dialogTeacherVisible: false,// 控制教师弹出框
dialogFormVisible: false,// 控制学生信息新增、编辑弹窗
rules: {
stunum: [{ required: true, message: '学号不能为空', trigger: 'blur' }],
name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
phone: [{ required: true, message: '电话不能为空', trigger: 'blur' }]
},
isEdit: false
在 methods 中添加 addData() 函数,提交表单数据用的
addData(formName) {
this.$ref[formName].validate(valid => {
if (valid) {
} else {
return false
}
})
},
在 template 中的查询按钮旁边添加一个 新增 按钮,用于打开新增会员对话框
<el-button
type="primary"
@click="handleAdd"
>新增</el-button>
在 methods 中添加 handleAdd() 函数, 打开新增对话框关闭窗口后,再次打开窗口,会发现表单里依然有数据,应当清除数据。
handleAdd() {
this.dialogFormVisible = true;
this.$nexttick(() => {
this.$ref['pojoForm'].resetFields();
})
},
测试发现,点击选择教师,数据没有回显,实际上是回显到搜索框(search)了.
解决:定义一个中间变量 isEdit: false, 打开时赋值 true, 然后在回显处,判断回显 search 还是 pojo修改编辑窗口的教师名称输入框绑定一个处理函数 optionTeacher
dialogOptionTeacher() {
this.dialogTeacherVisible = true;
this.isEdit = true
},
optionTeacher(correntRow) {//如果有correntRow,就把他放到查找框去
if (this.isEdit) {//学生修改弹窗
this.pojo.teacher = correntRow.name
} else {//教师列表弹窗
this.searchMap.teacher = correntRow.name;
}
this.isEdit = false
this.dialogTeacherVisible = false;
},
2.2 表单数据提交
当点击新增窗口中的确认按钮时, 提交表单数据,后台 API 服务接口响应新增成功或失败
2.2.1 nodejs 添加新增学员接口
//?新增学生
router.post('/students', function (req, res) {
new Student(req.body).save(function (err) {
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: 'server error'
})
}
return res.status(200).json({
code: 2000,
flag: true,
message: '新增学生信息成功'
})
})
})
2.2.2 Api 调用接口
src\api\student.js 导出的默认对象中,添加调用新增接口的方法
//?新增学生信息
add(pojo) {
return request({
url: '/students',
method: 'post',
data: pojo
//pojo是对象,可以不放到大括号中.服务端拿数据的时候不需要再.data 直接可以通过res.body拿到数据
})
}
在 src\views\student\index.vue 中的 addData 方法中提交数据,代码如下:
addData(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
//验证通过
studentApi.add(this.pojo).then(response => {
const resp = response.data;
if (resp.flag) {
this.fetchData();
this.dialogFormVisible = false
this.$message({
message: resp.message,
type: 'success'
})
} else {
//验证不通过
this.$message({
message: '你好',
type: 'warning'
})
}
})
} else {
return false
}
})
},
测试新增功能:
三、学员管理-修改
3.1 node.js 添加接口
3.1.1 ID查询数据接口
router.get('/students', function (req, res) {
Student.findById(req.query.id, function (err, data) {
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: 'server error'
})
}
return res.status(200).json({
code: 2000,
flag: true,
message: '根据ID查找学生信息成功',
data: data//data是根据ID查找到的数据,返回去
})
})
})
3.1.2 提交修改数据接口
router.put('/students', function (req, res) {
Student.findByIdAndUpdate(req.body._id, req.body, function (err) {
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: 'server error'
})
}
return res.status(200).json({
code: 2000,
flag: true,
message: '修改学生信息成功'
})
})
})
3.2 Api 调用接口
src\api\student.js 导出的默认对象中,添加 ID 查询方法 getById 和 更新方法 update
//?查找学生信息
getById(id) {
return request({
url: `/students?id=${id}`,
method: 'get',
})
},
//?修改学生信息
update(pojo) {
return request({
url: '/students',
method: 'put',
data: pojo
})
}
<template slot-scope="scope">
<el-button
size="mini"
@click="handleEdit(scope.row._id)"
>编辑</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>删除</el-button>
element-ui包装好的编辑删除按钮中自带的 scope.row 属性返回值是对象 ,其中包含所在横行的所有数据
在 src\views\student\index.vue 中的 handleEdit 方法做如下修改
handleEdit(id) {
// console.log(id);
this.handleAdd();//调用handleAdd方法,当用户点击编辑按钮时,产生弹窗
studentApi.getById(id).then(response => {
const resp = response.data
// console.log(resp);
if (resp.flag) {
this.pojo = resp.data
}
})
},
修改对话框中的确认按钮点击事件, pojo.id === null, 值为 true 是新增,有 id 说明是更新
<el-button
type="primary"
@click="pojo._id===null?addData('pojoForm'):updateData('pojoForm')"
>提交</el-button>
提交更新数据
updateData(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
studentApi.update(this.pojo).then(response => {
const resp = response.data;
if (resp.flag) {
this.fetchData();
this.dialogFormVisible = false;
this.$message({
message: resp.message,
type: 'success'
})
} else {
this.$message({
message: resp.message,
type: 'error'
})
}
})
} else {
return false
}
})
},
测试效果:
四、学生管理-删除
4.1 node.js 添加删除数据接口
//?根据id删除学生信息
router.delete('/students', function (req, res) {
Student.findByIdAndRemove(req.body.id, function (err) {
if (err) {
return res.status(500).json({
code: 3000,
flag: false,
message: 'server error'
})
}
return res.status(200).json({
code: 2000,
flag: true,
message: '删除学生信息成功'
})
})
})
4.2 Api 调用接口
src\api\student.js 导出的默认对象中,添加 deleteById 方法
//?删除学生信息
deleteById(id) {
return request({
url: '/students',
method: 'delete',
data: {
id
}
})
}
在 src\views\student\index.vue 中的 handleDele 方法做如下修改:
handleDelete(id) {
this.$confirm('此操作将永久删除该学员信息, 是否继续?', '删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
studentApi.deleteById(id).then(response => {
const resp = response.data;
this.$message({//不论成功失败都进行message的提示
message: resp.message,
type: resp.flag ? 'success' : 'error'
})
if (resp.flag) {//删除成功,刷新列表
this.fetchData();
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
测试效果: