在线考试系统各个模块的实现

数据库表设计

  • 题库Library:用来放置试题
    var librarySchema = new Schema({
        number: Number,
        content: String
    });
  • 试题库:用来放学生抽到的试题
    var testSchema = new Schema({
          uid:{
            type: Schema.Types.ObjectId,
            ref: 'student'//关联student表
          },
          qId: {
            type: Schema.Types.ObjectId,
            ref: 'Library'
          },
          qContent: String,
          answer: String,
          score: String
    });

学生端

  • 考生一共有四个状态:"UNLOGIN":表示考生未登录;"LOGIN":表示考生已登录;"TEST":表示考生已开始答卷;"SUBMIT":表示考生已交卷。
  • 考试开始之后,考生点击开始考试按钮,改变学生的状态为"TEST",同时通知服务器进行分题,
    socket.emit("allocate",usrId);
  • 系统从题库中抽题并分配给该考生,同时保证题目没有重复的。因为考生中途掉线之后再登录的话可能会出现重复分题的情况,所以要先判断有没有给改考生分配过题,分配过的话就不重复再分。
    //考生题目分配,分配完之后通知学生端显示题目,同时通知教师端
      socket.on("allocate",function (usrId) {
        dbHelper.allocate(usrId,function(success,doc) {
          console.log("allocate success")
        });
        socket.emit("show question",usrId);
        sockets[teacher].emit("check student");
      });
    
exports.allocate = function(data,cb) {
    //先判断是不是已经分过题了,如果分过了就不用再分题了。
      Test.find({uid: data}).exec(function(err,docs){
        if(docs.length==0){
          var array=JSON.parse(JSON.stringify(questions));
          var num=new Array;
          //避免考生抽到重复的题
          for (var i=0;i<array.length;i++){
            num[i]=i+1;
          }
          num.sort(function(){ return 0.5 - Math.random();});
          for (var i = 0; i < 3; i++) {
            Library.findOne({number: num[i]})
              .exec(function (err, doc) {
                var test = new Test({
                  uid: data,
                  qId: doc._id,
                  qContent: doc.content
                });
                test.save(function (err, test) {
                  if (err) {
                    entries.code = 500;
                  } else {
                    entries.code = 0;
                  }
                });
              });
          }
          cb(true,entries);
        } else{
          cb(false, entries);
        }
      });
    }
  • 考生开始答题,考生点击保存按钮,可以保存答案,同时会自动每隔一分钟保存答案。
    function doSave() {
      var val=$('#v'+testId+' textarea').val();
      $.ajax({
        type: "POST",
        url: "/saveAnswer",
        contentType: "application/json",
        data: JSON.stringify({
          'testId': testId,
          'answer': '<pre>'+val+'</pre>'
        }),
        success: function (data) {
           console.log("save success");
           setTimeout(doSave,60*1000);
        }
      });
    }
  • 考生点击提交按钮,会通知服务器
    socket.emit("student submit",usrId);
  • 服务器收到信号,先改变学生的状态,然后通知老师。
    socket.on('student submit',function (usrId) {
        var status="SUBMIT";
        var data = {
          usrId: usrId,
          status: status
        }
        console.log(teacher);
        dbHelper.changeStatus(data,function(success,doc) {
          console.log("状态改为提交");
        });
        sockets[teacher].emit("check student");//通知老师
      });
  • 考试的时间到了之后,考生停止答题。

教师端

  • 教师登录之后,能直接看到考生的状态,灰色代表考生未登录,红色代表考生已登录,蓝色代表考生已经开始答题,绿色代表考生已经提交试卷
    socket.on("check student",function () {
        initStudentList();
    });
    function initStudentList(){
      $.ajax({
        type: "POST",
        url: "/getStudentList",
        contentType: "application/json",
        data: JSON.stringify({
          'teaId': teaId
        }),
        success: function (data) {
          $(".tea_wrapper .content").html("");
          for(var i=0;i<data.length;i++){
            $(".tea_wrapper .content").append(
              ' <div class="studentStatus" id="student'+data[i]._id+'v">'
              * '<span>' + data[i].stuName + '</span>'
              * '<span>' + data[i].stuId + '</span>'
              * '</div>');
            if(data[i].status=="LOGIN"){
              $("#student"+data[i]._id+'v').css("background","#FF6766")
            } else if(data[i].status=="TEST"){
              $("#student"+data[i]._id+'v').css("background","#2376ae")
            } else if(data[i].status=="SUBMIT"){
              $("#student"+data[i]._id+'v').css("background","#007722")
            } else{
              $("#student"+data[i]._id+'v').css("background","#dddddd")
            }
          }
          setTimeout(initStudentList,1000);
        }
      });
    }
  • 同时老师能够点击已经提交试卷的考生进行批改试卷,会显示该考生的试题以及答案信息。
    1.PNG
  • 老师改完题目之后,可以点击保存,保存成绩,然后后台去改学生的成绩

    function doSaveScore() {
      var sum=0;
      for(var i=0;i<grade.length;i++){
        var val=$('#g'+grade[i]+'a').val();
        console.log(val);
        sum=sum+parseInt(val);
        socket.emit('change score',sid,grade[i],val);
      }
        socket.emit('change student grade',sid,sum);
        $('.alert').show();
    }
//改每一题的成绩
socket.on('change score',function (sid,tid,value) {
    var data={
      uid: sid,
      _id: tid,
      score: value
    }
    dbHelper.setScore(data,function (success,doc) {
      console.log("save score success");
    })
  })
  //改学生的总成绩
  socket.on('change student grade',function(sid,sum){
    var data={
      _id: sid,
      grade: sum
    }
    dbHelper.changeStudentGrade(data,function (success,doc) {
      console.log("save score success");
    })
  });
  • 同时老师可以添加考生
    2.PNG

题库可以以json文件的格式进行导入

    var questions  = require('../db/json');
    exports.allQuestions=function (cb) {
      var array=JSON.parse(JSON.stringify(questions));
      for(var i=0;i<array.length;i++){
        var question=new Library({
          number: array[i].num,
          content: array[i].content
        });
        question.save(function (err,doc) {
          if(err){
            entries.code=500;
            cb(false, entries);
          } else{
            entries.code=0;
            cb(true, entries);
          }
        });
      }
    }

参考网址:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容