简易的学生请假系统
该管理模块是基于node下面的express模块和jq来写的,该请假系统只是在练习本人学到的一些知识,还有很多功能暂未写出
最终样式图如下图所示:
登录页面
老师列表页面
老师新增学生信息
老师管理学生的请假信息
学生进入自己的请假列表
学生新增自己的请假信息
分析
学生请假系统中存在两种身份
- 老师---------管理者(审批是否同意学生请假)
- 学生---------请假者(查看自己的已有的请假信息,并且增加请假)
所以我们应该根据所登录的人的身份不同,控制他们进入不同的页面
老师---------进入管理页面
页面功能:
查看学生的请假信息(审批学生的请假信息)
查看所有学生的信息列表 增,删学生
学生---------进入自己的信息页
页面功能:
查看自己已有的请假信息
新增自己的请假信息
所以大致的将以上信息总结为2个表
用户模块表(主要用于登录和老师新增学生时使用)
username(用户名) string
userpwd(登录密码) string
usertype(登录者类型 1表示老师 2表示学生) number
请假模块表(主要用于老师查看所有学生请假信息,以及学生自己查案请假信息)
userid(通过用户模块的id确定此userid,确保其的唯一性,保证一个学生可以提交多条请假信息,通过session保存,并且存到此表中)string 学生标号
username(用户名,存在于session中) string 用户姓名
title string 请假标题
content string 请假内容
type number 1 请假内容待审批2 请假内容已审批3 请假被拒绝
start number请假开始时间
end number 请假的结束时间
第一步 创建express模块
express -e Studentleave
cd Studentleave
npm install
nodemon ./bin/www
第二步 列出大致模块,建立文件夹,路由等
第三步 建表连接数据库
Mongoose使用模块的引入
`1 npm install mongoose --save
2 建一个用于公共连接 文件db.js ,并写入如下内容
var mongoose = require(“mongoose”); //引入mongoose模块
var DB_URL = “mongodb://localhost:27017/Studentleave”;
mongoose.connect(DB_URL,{useNewUrlParser: true }); //连接数据库
//下述内容可写可不写,但写了以后可以跟好的判断数据库的连接状态
//状态的监听
mongoose.connection.on("connected",function () {
console.log("连接成功");
});
mongoose.connection.on("error", function (err) {
console.log(err);
});
mongoose.connection.on("disconnected", function () {
console.log("连接断开");
});
//导出方便其他地方使用
module.exports = mongoose;
3 建立一个文件作为表的数据模型 为后面做增删改查做示例和规范说明,因为普通的mongo无法对数据类型做规范 但是mongoose是可以的
//teacherModel
var mongoose = require("../db.js");
var schema = mongoose.Schema; //模型生成器(表生成器)
var userSchema = new schema({
username: String,
userpwd: String,
usertype:Number //确定登录人的类型 1为老师,2为学生
});
//给结构取了一个名称
module.exports = mongoose.model("userinfo", userSchema);
//studentModel模型
var mongoose = require("../db.js");
var schema = mongoose.Schema; //模型生成器(表生成器)
var userSchema = new schema({
userid: String, //给每一个学生确定一个私有id,一个id可以包含多条请假信息,存储在session中
username:String, //存储在session中
title: String, //请假标题
content:String, //请假内容
start:Date, //请假开始时间
end:Date, //请假结束时间
type:Number //确定所请的假的审批情况,1待批准,2已同意,3已拒绝
});
//给结构取了一个名称
module.exports = mongoose.model("leaveinfo", userSchema);
老师模型中数据库方法的调用
//引入数据库模块
var userinfo=require("./teacherModel")
let user={
//根据所传入的obj对象查找数据库中符合条件的人
//一般用于检验用户名是否已经存在
findUserInfoByName:function(obj){
return userinfo.findOne(obj);
},
//用来查询满足条件的数据
list:function(){
return userinfo.find({usertype:2});
},
//向数据库中插入数据学生信息
userinst:function(obj){
return userinfo.insertMany([obj])
},
//根据用户id删除数据
userdel:function(_id){
return userinfo.deleteOne({_id:_id})
},
}
module.exports = user;
学生模型中数据库方法的调用
//引入数据库模块
var leaveinfo=require("./studentModel.js");
var leave={
//学生用来查看自己的学生列表
studentList:function(obj){
return leaveinfo.find(obj)
},
//学生向数据库中添加自己的学生信息
create:function(obj){
return leaveinfo.insertMany([obj]);
},
//老师查看所有学生的请假信息
teacherkan:function(){
return leaveinfo.find().sort({type:1});
},
//老师审批学生的请假信息
teacherup:function(obj1,obj2){
return leaveinfo.updateOne(obj1,obj2);
}
}
module.exports = leave;
第四步 登录页面的创建
登录的ejs页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>leave</title>
//引入bootstrap插件进行页面布局
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Roboto:400,100,300,500">
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="/assets/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="/assets/css/form-elements.css">
<link rel="stylesheet" href="/assets/css/style.css">
<link rel="shortcut icon" href="/assets/ico/favicon.png">
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/assets/ico/apple-touch-icon-144-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/assets/ico/apple-touch-icon-114-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="/assets/ico/apple-touch-icon-72-precomposed.png">
<link rel="apple-touch-icon-precomposed" href="/assets/ico/apple-touch-icon-57-precomposed.png">
</head>
<body>
<div class="top-content">
<div class="inner-bg">
<div class="container">
<div class="row">
<div class="col-sm-8 col-sm-offset-2 text">
<h1><strong>My 请假系统</strong> 登录</h1>
</div>
</div>
<div class="row">
<div class="col-sm-6 col-sm-offset-3 form-box">
<div class="form-top">
<div class="form-top-left">
<h3>Login to our site</h3>
<p>Enter your username and password to log on:</p>
</div>
<div class="form-top-right">
<i class="fa fa-key"></i>
</div>
</div>
<div class="form-bottom">
<form role="form" id="myform" class="login-form">
<div class="form-group">
<label class="sr-only" for="username">Username</label>
<input type="text" id="username" name="username" placeholder="Username..."
class="form-username form-control" id="form-username">
</div>
<div class="form-group">
<label class="sr-only" for="password">Password</label>
<input type="password" id="password" name="password" placeholder="Password..."
class="form-password form-control" id="form-password">
</div>
<button type="button" class="btn" id="login">Sign in!</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Javascript -->
<script src="/assets/js/jquery-1.11.1.min.js"></script>
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
<script src="/assets/js/jquery.backstretch.min.js"></script>
<script src="/assets/js/scripts.js"></script>
</body>
<script>
//点击登录按钮
$("#login").click(function(){
$.ajax({
type:"post", //因为是使用表单,使用post提交数据
url:"http://localhost:3003/users/login", //传回判断登录是否成功的数据
data:$("#myform").serializeArray(), //将表单中的数据自动整理为数组传入
dataType:"json" //传回数据为json数据
}).then(function(res){
if(res.code==1){
if(res.usertype==1){
//如果登录类型为老师,则进入老师列表页面
alert("进入老师列表页");
window.location.href="/teacher"
}
if(res.usertype==2){
//如果登录类型为学生,则进入学生列表页面
alert("进入学生列表页")
window.location.href="/student"
}
}else{
alert(res.msg)
}
})
})
</script>
</html>
传回登录是否成功的路由接口
var express = require('express');
var router = express.Router();
//引入数据库中的方法
var user = require('../model/teacher/index')
//使其登录http://localhost:3000/users时自动进入由view目录下users目录下login.ejs渲染的页面
router.get('/', function (req, res, next) {
res.render("users/login")
});
//接收表单验证中的数据,判断是否登录
router.post('/login', (req, res, next) => {
//通过表单传回来的数据通过body接收
var username = req.body.username;
var userpwd = req.body.password;
console.log( username,userpwd)
//先判断数据库中是否存在该用户,使用数据库中的方法
user.findUserInfoByName({username}).then(function (data) {
console.log(data);
//存在该用户名
if(data){
//判断返回的对象的密码是否合输入的密码相等
if (data.userpwd == userpwd) {
//如何密码相等,将该用户的用户名和id存入session中,只有当session中存在该数据时,才能进入列表页面
req.session.userid = data["_id"];
req.session.username = data["username"];
res.json({
code: 1,
msg: "登录成功",
usertype: data.usertype,
})
}else{
res.json({
code:0,
msg: "用户名和密码不匹配!!",
})
}
}else{
//未返回数组时,该用户名不存在
res.json({
code:0,
msg: "该用户不存在",
})
}
})
})
module.exports = router;
上述操作中存在使用sesson来将用户部分信息存在localstroage中,以便在后续的操作中,保证只有当在本地中存在用户信息时,才能跳转到列表页面
那么下面将讲述在express模块中使用session第三方插件的方法
1 第一步安装
npm install express-session --save
2第二步引入 在app.js中
var session = require("express-session");
3配置中间件 供给其他方法使用 设置以后可以在req中调用 不设置就不行
app.use(session({
secret: 'secret', // 对session id 相关的cookie 进行签名
resave: true,
saveUninitialized: true, // 是否保存未初始化的会话
cookie: {
maxAge: 1000 * 60 * 3, // 设置 session 的有效时间,单位毫秒
},
}));
4:使用
//设置
req.session.userid =1;
//获取
req.session.useid
5:清除
req.session.destroy();
第四步 进入老师的列表页,进行老师的相关操作
老师列表页的list.ejs文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<a href="/teacher">学员管理</a>
<a href="/teacher/manage">请假管理</a>
<!-- 访问的路由 -->
<div class="table-responsive">
<table class="table">
<caption>学员列表</caption>
<button type="button" class="btn btn-primary" id="create">新增</button>
<thead>
<tr>
<th>学员姓名</th>
<th>密码</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody">
<% list.forEach(function(item){%>
<tr>
<td><%= item.username%></td>
<td><%= item.userpwd%></td>
<td data_id="<%= item['_id']%>" class="del">删除</td>
</tr>
<%})%>
</tbody>
</table>
</div>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×
</button>
<h4 class="modal-title" id="myModalLabel">
新增学员
</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" role="form" id="createform">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="username" id="username"
placeholder="请输入名字">
</div>
</div>
<div class="form-group">
<label for="userpwd" class="col-sm-2 control-label">密码</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="userpwd" id="userpwd"
placeholder="请输入姓">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default"
data-dismiss="modal">取消
</button>
<button type="button" class="btn btn-primary" id="ok">
确定
</button>
</div>
</div>
</div>
</div>
</body>
<script>
//点击新增按钮
$("#create").click(function(){
$("#myModal").modal('show');
})
//新增学生信息
$("#ok").click(function(){
$.ajax({
type:"post",
url:"http://localhost:3003/teacher/list",
data:$("#createform").serializeArray(),
dataType:"json"
}).then(function(res){
if(res.code==1){
alert(res.msg);
window.location.reload();
}else{
alert(res.msg);
}
})
})
//删除学生信息
$(document).on("click",".del",function(){
var id=$(this).attr("data_id");
var that=this;
$.ajax({
type:"get",
url:"http://localhost:3003/teacher/del",
data:{id},
dataType:"json"
}).then(function(res){
if(res.code==1){
alert(res.msg);
$(that).parent().remove();
}else{
alert(res.msg)
}
})
})
</script>
</html>
管理老师列表页数据的路由
var express = require('express');
var router = express.Router();
//引入老师数据库模块
var user=require("../model/teacher/index");
//引入学生数据库模块
var leave=require("../model/student/index");
//引入日期格式化 npm install moment
const moment = require('moment'); //日期格式化
router.get('/', function(req, res, next) {
var username=req.session.username;
//传出数据,渲染列表页面
router.get('/', function(req, res, next) {
//判断session中是否存入数据
var username=req.session.username;
//如果session中存在数据,则进入列表页
//查找所有学生对象,通过view目录下teacher下的list.ejs文件渲染页面
if(username){
user.list().then(function(data){
res.render('teacher/list',{
list:data,
username,
moment:moment
});
})
}else{
//如何session中未存在数据,则经过重定向跳登录页面
res.redirect("/users/");
}
});
//添加学生,前端通过post请求发送数据,后端需要用post接收
router.post('/list',function(req,res,next){
//post方法传过来的数据存在于req.body中,而get请求获取的数据存在于req.query中
//获取表单传回来的数据
var username=req.body.username;
var userpwd=req.body.userpwd;
//并他们存为对象,因为mongos是通过对象来保存数据的
var obj={
username,
userpwd,
usertype:2 /使所存入人的身份为学生
}
//先判断所存入的名字是否在存在
user.findUserInfoByName({username}).then(function(data){
//如果找到数据,则该用户名已经存在
if(data){
res.json({
code:0,
msg:"用户名已存在!!"
})
}else{
//否则插入该数据
user.userinst(obj).then(function(data){
//此从数据库中返回的data对象中有一个length属性,若其变为1,则新增该用户成功,否则,新增该用户失败
if(data.length){
res.json({
code:1,
msg:"新增用户成功"
})
}else{
res.json({
code:0,
mag:"数据库正在更新中,请稍后再试!!"
})
}
})
}
})
})
//删除学生,通过get请求传回学生的id,以便判断要删除那个学生
router.get('/del',function(req,res,next){
/通过req.query获取将要删除的学生的id
var id=req.query.id;
//调用数据库中的方法进行删除
user.userdel(id).then(function(data){
//此时从数据库中传回的data对象中存在一个deletedCount属性,如果该值大于0则删除成功,否则删除失败
if(data.deletedCount>0){
res.json({
code:1,
msg:"删除成功"
})
}else{
res.json({
code:0,
msg:"数据库正在更新中,请稍后再试!!"
})
}
})
})
//老师管理学生请假的页面
//渲染所有学生的请假信息,使用的是leave表单
router.get("/manage",(req,res,next)=>{
//还是需要判断session中是否存在用户信息,若不存在,则重定向回登录页面
var username=req.session.username;
if(username){
leave.teacherkan().then(function(data){
if(data){
//通过render,使用view文件夹下的teacher文件夹下的manage.ejs文件渲染http:localhost:3000/teacher/manage下面的页面
res.render("teacher/manage",{
list:data,
moment:moment
})
}
})
}else{
res.redirect('/users/')
}
})
//老师更新学生的请假信息,同意或拒绝
router.get("/teacherupya",(req,res,next)=>{
//通过该请假信息的id来更新数据库中的type
//不能使用session中的userid的原因是userid对应的是把每个学生
//而每个学生可以对应多条请假信息,如果通过userid来更新type,则会同时更新多条该学生的请假信息
//如果只更改i对应的type,则每次只更新该条请教信息
var id = req.query.id;
var type = req.query.type;
//调用数据库中的方法更新信息
leave.teacherup({_id:id},{type:type}).then(function(data){
//当调用数据库中的更新方法时,数据库传回的对象data中存在nModified属性,如果该属性值大于或等于1,则数据更新成功
if(data.nModified){
res.json({
code:1,
msg:"成功"
})
}else{
res.json({
code:0,
msg:"失败"
})
}
})
})
module.exports = router;
第五步 进入学生的列表页,进行学生申请请假
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="/stylesheets/bootstrap-datepicker.min.css" rel="stylesheet">
<script src="/javascripts/bootstrap-datepicker.min.js"></script>
</head>
<body>
<div class="table-responsive">
<table class="table">
<caption><%=username%>的请假列表</caption>
<button type="button" class="btn btn-primary" id="create">新增</button>
<thead>
<tr>
<th>标题</th>
<th>内容</th>
<th>开始时间</th>
<th>结束时间</th>
<th>状态</th>
</tr>
</thead>
<tbody id="tbody">
<% if(list.length){ %>
<% list.forEach(function(item){ %>
<tr>
<td><%= item.title%></td>
<td><%= item.content%></td>
<td><%= moment(item.start).format("YYYY-MM-DD") %></td>
<td><%= moment(item.end).format("YYYY-MM-DD")%></td>
<td>
<% if(item.type==1){%>
<button type="button" class="btn btn-warning">待同意</button>
<% } else if(item.type ==2 ){ %>
<button type="button" class="btn btn-success">已同意</button>
<%}else{%>
<button type="button" class="btn btn-danger">已拒绝</button>
<%}%>
</td>
</tr>
<% })%>
<% }else{%>
<tr><td>您还没有请假信息</td></tr>
<% }%>
</tbody>
</table>
</div>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×
</button>
<h4 class="modal-title" id="myModalLabel">
请假
</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" role="form" id="createform">
<div class="form-group">
<label for="title" class="col-sm-2 control-label">标题</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="title" id="title"
placeholder="请输入标题">
</div>
</div>
<div class="form-group">
<label for="content" class="col-sm-2 control-label">内容</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="content" id="content"
placeholder="请输入内容">
</div>
</div>
<div class="form-group">
<label for="start" class="col-sm-2 control-label">开始时间</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="start" id="start"
placeholder="请输入开始时间">
</div>
</div>
<div class="form-group">
<label for="end" class="col-sm-2 control-label">结束时间</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="end" id="end"
placeholder="请输入结束时间">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default"
data-dismiss="modal">取消
</button>
<button type="button" class="btn btn-primary" id="ok">
确定
</button>
</div>
</div>
</div>
</div>
</body>
<script>
//引入时间插件,调用其中的格式时间代码
$("#start,#end").datepicker({
format:"yyyy-mm-dd",
autoclose:true,
})
$("#create").click(function(){
$("#myModal").modal("show");
})
//添加自己的请假信息
$("#ok").click(function(){
console.log(111)
$.ajax({
type:"post",
url:'http://localhost:3003/student/create',
data:$("#createform").serializeArray(),
dataType:"json"
}).then(function(res){
if(res.code==1){
alert(res.msg);
window.location.reload();
}else{
alert(res.msg)
}
})
})
</script>
</html>
管理学生页数据的路由
var express = require('express');
var router = express.Router();
const moment = require('moment');
var leave=require("../model/student/index.js");
//通过leave数据库中的username或userid来找到该学生对应的请假信息,并用来渲染请假列表
router.get('/', function(req, res, next) {
var username=req.session.username;
//还是先判断是否在本地中存储了用户信息
if(username){
leave.studentList({username}).then(function(data){
//若存在,则渲染页面
res.render('student/list', {
list:data,
username,
moment:moment
})
})
}else{
res.redirect("/users/")
}
});
//通过表单来提交自己的请假信息,并在数据库中插入信息
router.post("/create",(req,res,next)=>{
var title=req.body.title;
var content = req.body.content;
var start = new Date(req.body.start);
var end = new Date(req.body.end);
var type = 1; //1表示提交 2:同意 3:拒绝
username=req.session.username;
userid=req.session.userid;
//数据库中存入信息时是通过对象来存入的
var obj={
username,
userid,
title,
content,
start,
end,
type
}
leave.create(obj).then(function(data){
if(data.length>0){
res.json({
code:1,
msg:"新增请假信息成功"
})
}else{
res.json({
code:0,
msg:"数据库正在更新中,请稍后再试"
})
}
})
})
module.exports = router;