Vue项目 成员管理系统 学生管理模块(7)

目录

一、学员管理-列表查询

1.1 分页查询学员数据列表

1.1.1 nodejs 添加分页数据列表接口

1.1.2 Api调用接口

1.1.3 列表与分页模板

添加 handleSizeChange 和 handleCurrentChange 方法,实现动态赋值与刷新列表

1.2 条件查询实现 

1.2.1 条件查询模板

1.2.2 授课教师选择(父子组件信息传递) 

1.2.3 重置功能 

二、学员管理-新增 

2.1 新增窗口实现

2.2 表单数据提交

2.2.1 nodejs 添加新增学员接口

 2.2.2  Api 调用接口

三、学员管理-修改

3.1 node.js 添加接口

3.1.1 ID查询数据接口

3.1.2 提交修改数据接口 

 3.2 Api 调用接口

四、学生管理-删除

4.1 node.js 添加删除数据接口

4.2  Api 调用接口


一、学员管理-列表查询

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: '已取消删除'
                });
            });
        },

测试效果:

 


 

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不是独角兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值