教师端完善批改中心,增加教师端查看试卷功能,完善学生端部分功能缺少

main
yuan 3 months ago
parent 48a4c772b4
commit 390dd6aa8f

@ -128,8 +128,8 @@ public class StudentHomePageController {
return R.ok(iQuestionanswerService.selectQuestionanswer(id,testid));
}
//观题自动更改
@ApiOperation("任务中心观题批改")
//观题自动更改
@ApiOperation("任务中心观题批改")
@GetMapping("task_answerDisplay")
public R<String> taskAnswerDisplay(Long id) {
SysUser sysUser = SecurityUtils.getLoginUser().getUser();
@ -143,7 +143,7 @@ public class StudentHomePageController {
return R.fail("查不到该学生的考试记录!");
}
@ApiOperation("任务中心批改观题")
@ApiOperation("任务中心批改观题")
@PostMapping("task_markObjectiveQuestions")
public R<String> taskMarkObjectiveQuestions(@RequestBody QuestionAnswerDO questionAnswerDO) {
if(iQuestionanswerService.markObjectiveQuestions(questionAnswerDO)!=0){

@ -4,13 +4,17 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.test.domain.DO.Correct;
import com.ruoyi.test.domain.DO.QuestionAnswerDO;
import com.ruoyi.test.domain.Markedtest;
import com.ruoyi.test.domain.Message;
import com.ruoyi.test.domain.StudentClass;
import com.ruoyi.test.domain.TeacherManageClass;
import com.ruoyi.test.domain.Vo.MessageVo;
import com.ruoyi.test.seriver.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@ -43,12 +47,31 @@ public class TeacherAnswerSheetController {
@Autowired
private ITeacherManageClassService iTeacherManageClassService;
@Autowired
private IMassageService iMassageService;
@ApiOperation("查看学生的考试情况(最新)")
@GetMapping("selectQuestionanswer")
public R<QuestionAnswerDO> selectQuestionanswer(Long senderId, Long testid) {
System.out.println("==============="+senderId+" "+testid);
return R.ok(iQuestionanswerService.selectQuestionanswer(senderId,testid));
}
@ApiOperation("检查是否批改")
@GetMapping("selectMarkedtestList")
public R<List<Correct>> selectMarkedtestList() {
SysUser sysUser = SecurityUtils.getLoginUser().getUser();
List<TeacherManageClass> teacherManageClass = iTeacherManageClassService.selectById(sysUser.getUserId());
List<Long> list = iStudentClassService.selectByTeacherIdList(teacherManageClass);
return R.ok(iMarkedtestService.selectByStudentList(sysUser.getUserId(),list));
}
@ApiOperation("添加提醒消息")
@PostMapping("addMessage")
public R<Integer> addMessage(@RequestBody MessageVo messageVo) {
return R.ok(iMassageService.addMessage(messageVo));
}
@ApiOperation("批改客观题")
@PostMapping("markObjectiveQuestions")
public R<String> markObjectiveQuestions(@RequestBody QuestionAnswerDO questionAnswerDO) {
@ -58,6 +81,12 @@ public class TeacherAnswerSheetController {
return R.fail("批改提交失败!");
}
@ApiOperation("获取某一张的分数")
@GetMapping("getScoreByTestId")
public R<Markedtest> getScoreByTestId(Long studentId,Long testId) {
return R.ok(iMarkedtestService.selectmarkedtestByTestid(studentId,testId));
}
@ApiOperation("试卷批改完毕提交")
@PostMapping("addmarkedtest")

@ -0,0 +1,15 @@
package com.ruoyi.test.domain.DO;
import lombok.Data;
@Data
public class Correct {
private Long sendId;
private Long testId;
private String subject;
private String name;
private String senderName;
private Integer status;
}

@ -8,9 +8,9 @@ import lombok.Data;
public class Markedtest {
private Long senderId;
private long testid;
private double score;
private double totalscore;
private Long testid;
private Double score;
private Double totalscore;
private Integer totalquestions;
private Integer tquestions;
private Integer time;

@ -0,0 +1,13 @@
package com.ruoyi.test.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("message")
public class Message {
private Long teacherId;
private Long studentId;
private String source;
private String tf;
}

@ -0,0 +1,12 @@
package com.ruoyi.test.domain.Vo;
import lombok.Data;
@Data
public class MessageVo {
private Long teacherId;
private Long studentId;
private String source;
private String tf;
private String name;
}

@ -2,11 +2,15 @@ package com.ruoyi.test.domain.Vo;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
public class QuestionanswerVo {
private Long id;
private String content;
private List<Map<String,String>> chance;
//学生给的答案
private String idanswer;
@ -20,4 +24,6 @@ public class QuestionanswerVo {
private String analysis;
private String type;
}

@ -0,0 +1,12 @@
package com.ruoyi.test.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.test.domain.Message;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface MessageMapper extends BaseMapper<Message> {
int addMessage(@Param("message") Message message);
}

@ -15,4 +15,5 @@ public interface IAnswerService {
Boolean selectBySenderIdAndTestId(Long senderId,Long testid);
}

@ -1,6 +1,7 @@
package com.ruoyi.test.seriver;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.test.domain.DO.Correct;
import com.ruoyi.test.domain.Markedtest;
import com.ruoyi.test.domain.StudentClass;
@ -25,4 +26,6 @@ public interface IMarkedtestService {
Markedtest selectmarkedtestBySenderIdAndTestid(Long senderId,Long testId);
Markedtest selectmarkedtestByTestid(Long id,Long testId);
List<Correct> selectByStudentList(Long id,List<Long> list);
}

@ -0,0 +1,8 @@
package com.ruoyi.test.seriver;
import com.ruoyi.test.domain.Vo.MessageVo;
public interface IMassageService {
int addMessage(MessageVo messageVo);
}

@ -15,4 +15,7 @@ public interface IStudentClassService {
StudentClass selectById(Long id);
List<Long> selectByTeacherIdList(List<TeacherManageClass> teacherManageClasses);
}

@ -13,4 +13,8 @@ public interface ITeacherManageClassService {
int addclass1(Long teacherid,String grade,String Class1);
TeacherManageClass selectByGradeAndClass(String grade,String Class1);
List<TeacherManageClass> selectById(Long teacherid);
List<String> selectByTeacherId(Long teacherid);
}

@ -6,6 +6,6 @@ import java.util.List;
public interface ITeacherSubjectService {
List<TeacherSubject> select(Long teacherid);
List<String> select(Long teacherid);
}

@ -4,7 +4,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.test.domain.*;
import com.ruoyi.test.domain.DO.Correct;
import com.ruoyi.test.domain.DO.QuestionAnswerDO;
import com.ruoyi.test.domain.Vo.MarkedtestVo;
import com.ruoyi.test.domain.Vo.QuestionanswerVo;
@ -19,9 +21,8 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class MarkedtestServiceImpl extends ServiceImpl<MarkedtestMapper, Markedtest> implements IMarkedtestService {
@ -44,13 +45,21 @@ public class MarkedtestServiceImpl extends ServiceImpl<MarkedtestMapper, Markedt
@Autowired
private IExamPaperService iExamPaperService;
@Autowired
private ISysUserService iSysUserService;
@Autowired
private ITeacherSubjectService iTeacherSubjectService;
@Autowired
private ITeacherManageClassService iTeacherManageClassService;
@Override
public int addmarkedtest(Long senderId,Long testid) {
QuestionAnswerDO questionAnswerDO = iQuestionanswerService.selectQuestionanswer(senderId,testid);
int totalscore = 0;
int score = 0;
double totalscore = 0;
double score = 0;
int tquestions = 0;
int totalquestions = 0;
@ -176,4 +185,46 @@ public class MarkedtestServiceImpl extends ServiceImpl<MarkedtestMapper, Markedt
return markedtestMapper.selectOne(queryWrapper);
}
@Override
public List<Correct> selectByStudentList(Long id,List<Long> list) {
List<String> teacherSubjectList = iTeacherSubjectService.select(id);
List<String> teacherManageClasses = iTeacherManageClassService.selectByTeacherId(id);
LambdaQueryWrapper<ExamPaper> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(ExamPaper::getSubject,teacherSubjectList)
.in(ExamPaper::getGrade,teacherManageClasses);
List<ExamPaper> examPapers = examPaperMapper.selectList(queryWrapper);
List<Correct> list1 = list.stream()
.flatMap(studentId -> {
List<Correct> list2 = new ArrayList<>();
for(ExamPaper examPaper : examPapers){
Correct correct = new Correct();
correct.setSubject(examPaper.getSubject());
correct.setTestId(examPaper.getId());
correct.setName(examPaper.getName());
correct.setSenderName(iSysUserService.selectUserById(studentId).getUserName());
correct.setSendId(studentId);
if(iAnswerService.selectBySenderIdAndTestId(studentId,examPaper.getId())){
LambdaQueryWrapper<Markedtest> queryWrapper1 = new LambdaQueryWrapper<>();
queryWrapper1.eq(Markedtest::getSenderId,studentId)
.eq(Markedtest::getTestid,examPaper.getId());
if(markedtestMapper.selectCount(queryWrapper1)>0){
correct.setStatus(0);
}else{
correct.setStatus(1);
}
}else{
correct.setStatus(2);
}
list2.add(correct);
}
return list2.stream();
})
.collect(Collectors.toList());
return list1;
}
}

@ -0,0 +1,31 @@
package com.ruoyi.test.seriver.Impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.test.domain.Message;
import com.ruoyi.test.domain.Vo.MessageVo;
import com.ruoyi.test.mapper.MessageMapper;
import com.ruoyi.test.seriver.IMassageService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements IMassageService {
@Autowired
private MessageMapper messageMapper;
@Autowired
private ISysUserService iSysUserService;
@Override
public int addMessage(MessageVo messageVo) {
Message message = new Message();
BeanUtils.copyProperties(messageVo,message);
String teahcerName = iSysUserService.selectUserById(message.getTeacherId()).getUserName();
String source = "教师"+teahcerName+"提醒你请尽快完成"+messageVo.getName();
message.setSource(source);
return messageMapper.addMessage(message);
}
}

@ -12,6 +12,7 @@ import com.ruoyi.test.domain.Questionbank;
import com.ruoyi.test.domain.Vo.AnswerVo;
import com.ruoyi.test.domain.Vo.QuestionanswerVo;
import com.ruoyi.test.mapper.QuestionanswerMapper;
import com.ruoyi.test.seriver.IQuestionTypeService;
import com.ruoyi.test.seriver.IQuestionanswerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -24,6 +25,9 @@ public class QuestionanswerServiceImpl extends ServiceImpl<QuestionanswerMapper,
@Autowired
private QuestionanswerMapper questionanswerMapper;
@Autowired
private IQuestionTypeService iQuestionTypeService;
@Override
public QuestionAnswerDO createTest(List<Questionbank> list, Answer answer) {
QuestionAnswerDO questionAnswerDO = new QuestionAnswerDO();
@ -44,6 +48,10 @@ public class QuestionanswerServiceImpl extends ServiceImpl<QuestionanswerMapper,
questionanswerVo.setDifficulty(questionbank.getDifficulty());
questionanswerVo.setAnalysis(questionbank.getAnalysis());
questionanswerVo.setAnswer(questionbank.getAnswer());
String chance = questionbank.getChance();
List<Map<String,String>> listMap = gson.fromJson(chance,List.class);
questionanswerVo.setChance(listMap);
questionanswerVo.setType(iQuestionTypeService.getQuestiontype(questionbank.getQuestiontype()));
// 使用流和 Lambda 表达式查找具有特定键的 HashMap
Optional<AnswerVo> result = dataList.stream()
@ -97,14 +105,14 @@ public class QuestionanswerServiceImpl extends ServiceImpl<QuestionanswerMapper,
queryWrapper.eq(Questionanswer::getTestid,id);
queryWrapper.orderByDesc(Questionanswer::getCreatetime).last("LIMIT 1");
Questionanswer questionanswer = questionanswerMapper.selectOne(queryWrapper);
System.out.println("========"+questionanswer);
String qa = questionanswer.getQa();
// System.out.println(qa);
Gson gson = new Gson();
List<QuestionanswerVo> dataList = gson.fromJson(qa,List.class);
Type listType = new TypeToken<List<QuestionanswerVo>>(){}.getType();
List<QuestionanswerVo> questionAnswerList = gson.fromJson(qa, listType);
QuestionAnswerDO questionAnswerDO = new QuestionAnswerDO();
questionAnswerDO.setSenderId(senderId);
questionAnswerDO.setTestid(questionanswer.getTestid());
questionAnswerDO.setList(dataList);
questionAnswerDO.setList(questionAnswerList);
// System.out.println(questionAnswerDO);
return questionAnswerDO;
}
@ -117,6 +125,7 @@ public class QuestionanswerServiceImpl extends ServiceImpl<QuestionanswerMapper,
Gson gson = new Gson();
String qa = gson.toJson(list);
questionanswer.setQa(qa);
questionanswer.setSenderId(questionAnswerDO.getSenderId());
return questionanswerMapper.addQuestionanswer(questionanswer);
}
}

@ -9,7 +9,9 @@ import com.ruoyi.test.seriver.IStudentClassService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class StudentClassServiceImpl extends ServiceImpl<StudentClassMapper, StudentClass> implements IStudentClassService {
@ -49,5 +51,27 @@ public class StudentClassServiceImpl extends ServiceImpl<StudentClassMapper, Stu
return studentClassMapper.selectOne(queryWrapper);
}
@Override
public List<Long> selectByTeacherIdList(List<TeacherManageClass> teacherManageClasses) {
// 用于存储查询结果的学生ID列表
List<Long> studentIds = teacherManageClasses.stream()
.flatMap(teacherManageClass -> {
// 对每个TeacherManageClass查询符合的学生ID
LambdaQueryWrapper<StudentClass> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StudentClass::getClass1, teacherManageClass.getClass1())
.eq(StudentClass::getGrade, teacherManageClass.getGrade());
// 执行查询获取学生ID列表
List<Long> ids = studentClassMapper.selectList(queryWrapper)
.stream()
.map(StudentClass::getStudentid) // 提取学生ID
.collect(Collectors.toList());
return ids.stream();
})
.collect(Collectors.toList()); // 最终返回所有符合条件的学生ID列表
return studentIds;
}
}

@ -8,7 +8,9 @@ import com.ruoyi.test.seriver.ITeacherManageClassService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class TeacherManageClassServiceImpl extends ServiceImpl<TeacherManageClassMapper, TeacherManageClass> implements ITeacherManageClassService {
@ -40,4 +42,21 @@ public class TeacherManageClassServiceImpl extends ServiceImpl<TeacherManageClas
.eq(TeacherManageClass::getClass1,Class1);
return teacherManageClassMapper.selectOne(queryWrapper);
}
@Override
public List<TeacherManageClass> selectById(Long teacherid) {
LambdaQueryWrapper<TeacherManageClass> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TeacherManageClass::getTeacherid,teacherid);
return teacherManageClassMapper.selectList(queryWrapper);
}
@Override
public List<String> selectByTeacherId(Long teacherid) {
LambdaQueryWrapper<TeacherManageClass> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TeacherManageClass::getTeacherid,teacherid);
return teacherManageClassMapper.selectList(queryWrapper)
.stream()
.map(TeacherManageClass::getGrade)
.collect(Collectors.toList());
}
}

@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class TeacherSubjectServiceImpl extends ServiceImpl<TeacherSubjectMapper, TeacherSubject> implements ITeacherSubjectService {
@ -17,9 +18,12 @@ public class TeacherSubjectServiceImpl extends ServiceImpl<TeacherSubjectMapper,
private TeacherSubjectMapper teacherSubjectMapper;
@Override
public List<TeacherSubject> select(Long teacherid) {
public List<String> select(Long teacherid) {
LambdaQueryWrapper<TeacherSubject> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TeacherSubject::getTeacherid,teacherid);
return teacherSubjectMapper.selectList(queryWrapper);
return teacherSubjectMapper.selectList(queryWrapper)
.stream()
.map(TeacherSubject::getSubject)
.collect(Collectors.toList());
}
}

@ -8,7 +8,6 @@
<insert id="addmarkedtest" parameterType="Markedtest">
insert into markedtest(
sender_id,
sender,
testid,
score,
totalscore,
@ -18,7 +17,6 @@
finishtime
)values (
#{markedtest.senderId},
#{markedtest.sender},
#{markedtest.testid},
#{markedtest.score},
#{markedtest.totalscore},

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mybatis-3-mapper.dtd:约束文件的名称限制和检查在当前文件中出现的标签和属性符合mybatis的要求-->
<!--namespace命名空间要有唯一的值要求使用dao接口的权限定名称一个dao接口对应一个mappernamespace指明对应哪个dao接口-->
<mapper namespace="com.ruoyi.test.mapper.MessageMapper">
<!-- 所有的数据库操作都要写在mapper标签中可以使用特定的标签表示数据库中的特定操作 -->
<insert id="addMessage" parameterType="Message">
insert into message(
teacher_id,
student_id,
source,
tf
)values (
#{message.teacherId},
#{message.studentId},
#{message.source},
#{message.tf}
)
</insert>
</mapper>

@ -15,15 +15,15 @@
<i class="el-icon-house"></i>
<span>主页</span>
</el-menu-item>
<el-menu-item :index="`/student/exam?userId=${userId}`">
<el-menu-item :index="`/teacher/exam?userId=${userId}`">
<i class="el-icon-message"></i>
<span>试卷中心</span>
</el-menu-item>
<el-menu-item :index="`/student/scoreList?userId=${userId}`">
<el-menu-item :index="`/teacher/scoreList?userId=${userId}`">
<i class="el-icon-s-data"></i>
<span>分数查询</span>
</el-menu-item>
<el-menu-item :index="`/student/scoreList?userId=${userId}`">
<el-menu-item :index="`/teacher/correct?userId=${userId}`">
<i class="el-icon-edit"></i>
<span>批改中心</span>
</el-menu-item>

@ -1,11 +1,11 @@
import Vue from 'vue';
import App from './App.vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import './assets/gloable.css';
import store from './store'; // 确保这个路径是正确的
import router from './router';
import request from "@/utils/request";
import Vue from 'vue';
import App from './App.vue';
import ElementUI from 'element-ui';
// 使用 ElementUI 组件库
Vue.use(ElementUI, { size: 'small' });

@ -8,6 +8,12 @@ import store from '../store'; // 引入 Vuex store
Vue.use(VueRouter);
const routes = [
{
path:'/teacher/viewExamPaper',
name:'ViewExamPaper',
component: () => import(/* webpackChunkName: "about" */ '../views/Teacher/ViewExamPaper.vue'),
meta: { requiresAuth: true }
},
{
path: '/teacher/homePage',
name: 'HomePage',
@ -73,7 +79,7 @@ const router = new VueRouter({
// 路由守卫
router.beforeEach((to, from, next) => {
const userId = to.query.userId;
console.log('userId:', to);
console.log('userId:', store.state.tokens[userId]);
// 判断该路由是否需要登录权限
if (to.matched.some(record => record.meta.requiresAuth)) {
// 如果未登录,跳转到登录页

@ -1,8 +1,6 @@
<template>
<div class="exam-container">
<!-- 左侧栏 -->
<div class="sidebar">
<!-- 返回按钮 -->
<div class="back-button">
<button @click="goBack">
<span>返回</span>
@ -25,7 +23,6 @@
</div>
</div>
<!-- 主内容 -->
<div class="main-content" v-if="!loading && questions.length">
<div
v-for="(question, index) in questions"
@ -35,6 +32,49 @@
:class="{ correct: question.tf === 'true', incorrect: question.tf === 'false', active: currentQuestionIndex === index }"
>
<p>{{ index + 1 }}. {{ question.content }}</p>
<!-- Check and Display Options -->
<div class="options">
<!-- 单选题 (Single Choice) -->
<template v-if="question.type === '单选题'">
<div v-for="(option, optIndex) in question.chance" :key="optIndex"
class="option"
:class="{ selected: answers[question.id] === option.label }">
{{ option.label }}: {{ option.text }}
</div>
</template>
<!-- 多选题 (Multiple Choice) -->
<template v-else-if="question.type === ''">
<div v-for="(option, optIndex) in question.chance" :key="optIndex" class="option">
{{ option.label }}: {{ option.text }}
</div>
</template>
<!-- 判断题 (True/False) -->
<template v-else-if="question.type === ''">
<div>
<input
type="radio"
:name="'question-' + question.id"
value="true"
:checked="answers[question.id] === 'true'"
disabled
/>
T
</div>
<div>
<input
type="radio"
:name="'question-' + question.id"
value="false"
:checked="answers[question.id] === 'false'"
disabled
/>
F
</div>
</template>
</div>
<p>你的答案<span>{{ question.answer }}</span></p>
<p>正确答案<span>{{ question.idanswer }}</span></p>
<p>分数{{ question.score }} </p>
@ -42,18 +82,17 @@
</div>
</div>
<!-- 加载中 -->
<div v-if="loading" class="loading">
正在加载试题请稍候...
</div>
<!-- 空状态 -->
<div v-if="!loading && !questions.length" class="empty">
未找到试题请联系管理员
</div>
</div>
</template>
<script>
import axios from "axios";
import exam from "@/views/Student/Exam.vue";
@ -156,6 +195,7 @@ export default {
this.fetchExamData();
},
created() {
this.userId = this.$route.query.userId;
this.examname = this.$route.query.name;
this.id = this.$route.query.id;
this.getTest();
@ -190,11 +230,15 @@ export default {
}
.sidebar {
width: 25%;
position: fixed; /* 固定左侧栏 */
top: 0;
left: 0;
width: 20%;
height: 100%;
padding: 20px;
background-color: #f4f4f4;
overflow-y: auto; /* 允许左侧栏滚动 */
border-right: 1px solid #ddd;
display: flex;
flex-direction: column;
}
.sidebar h2,
@ -244,8 +288,11 @@ export default {
}
.main-content {
flex: 1;
margin-left: 20%; /* 右侧主内容的宽度根据左侧栏的宽度调整 */
padding: 20px;
width: 80%;
overflow-y: auto; /* 使右侧内容可滚动 */
height: 100vh;
}
.question {

@ -15,18 +15,76 @@
<!-- 主内容 -->
<el-main>
<el-card>
<el-table :data="examPapers" border stripe style="width: 100%">
<el-table-column prop="id" label="试卷ID" width="120" />
<el-table-column prop="title" label="试卷名称" />
<el-table-column prop="submitter" label="提交人" width="150" />
<!-- 搜索框 -->
<el-form :model="searchQuery" label-width="100px" style="margin-bottom: 20px;">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="试卷名称">
<el-input v-model="searchQuery.name" placeholder="请输入试卷名称" suffix-icon="el-icon-search" @input="filterPapers" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="提交人">
<el-input v-model="searchQuery.submitter" placeholder="请输入提交人" suffix-icon="el-icon-search" @input="filterPapers" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="批改状态">
<el-select v-model="searchQuery.status" placeholder="选择批改状态" @change="filterPapers">
<el-option label="全部" value=""></el-option>
<el-option label="已批改" value="0"></el-option>
<el-option label="未批改" value="1"></el-option>
<el-option label="未作答" value="2"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 表格 -->
<el-table :data="filteredExamPapers" border stripe style="width: 100%">
<el-table-column prop="testId" label="试卷ID" width="120" />
<el-table-column prop="name" label="试卷名称" />
<el-table-column prop="subject" label="学科" />
<el-table-column prop="senderName" label="提交人" width="150" />
<el-table-column prop="status" label="批改状态" width="120">
<template #default="{ row }">
<el-tag :type="row.status === '未批改' ? 'info' : 'success'">{{ row.status }}</el-tag>
<el-tag :type="row.status === 0 ? 'success' : (row.status === 1 ? 'warning' : 'info')">
{{ row.status === 0 ? '已批改' : (row.status === 1 ? '未批改' : '未作答') }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button size="small" type="primary" @click="viewPaper(row)"></el-button>
<el-button
v-if="row.status === 0"
size="small"
type="primary"
@click="viewPaper(row)">
查看试卷
</el-button>
<!-- 如果状态是 1显示批改按钮 -->
<el-button
v-else-if="row.status === 1"
size="small"
type="primary"
@click="correctPaper(row)"
style="width: 78px;">
批改
</el-button>
<!-- 如果状态是 2显示提醒按钮 -->
<el-button
v-else
size="small"
type="primary"
@click="remind(row)"
style="width: 78px;">
提醒
</el-button>
</template>
</el-table-column>
</el-table>
@ -53,19 +111,27 @@
<script>
import Header from "@/components/Teacher/Header.vue";
import Aside from "@/components/Teacher/Aside.vue";
import axios from "axios";
export default {
name: "CorrectPapers",
components: { Aside, Header },
data() {
return {
userId: "",
collapseBtnClass: "el-icon-s-fold",
isCollapse: false,
sideWidth: 200,
logoTextShow: true,
examPapers: [], //
filteredExamPapers: [], //
dialogVisible: false, //
selectedPaper: null, //
searchQuery: {
name: "", //
status: "", //
submitter: "", //
},
};
},
methods: {
@ -81,16 +147,73 @@ export default {
this.logoTextShow = true;
}
},
fetchExamPapers() {
//
this.examPapers = [
{id: 1, title: "试卷一", submitter: "张三", status: "未批改", answers: "答案内容1"},
{id: 2, title: "试卷二", submitter: "李四", status: "已批改", answers: "答案内容2"},
];
async fetchExamPapers() {
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push("/login"); //
return;
}
const response = await axios.get('http://localhost:8080/teacher/answerSheet/selectMarkedtestList', {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
}
});
if (response.data.code == 200) {
this.examPapers = response.data.data;
this.filteredExamPapers = [...this.examPapers]; // Initially, show all exam papers
} else {
alert("数据加载失败");
}
} catch (error) {
console.error('获取数据失败', error);
}
},
filterPapers() {
this.filteredExamPapers = this.examPapers.filter(paper => {
const matchesName = paper.name.toLowerCase().includes(this.searchQuery.name.toLowerCase());
const matchesSubmitter = paper.senderName.toLowerCase().includes(this.searchQuery.submitter.toLowerCase());
const matchesStatus = this.searchQuery.status === "" || paper.status == this.searchQuery.status;
return matchesName && matchesSubmitter && matchesStatus;
});
},
viewPaper(paper) {
this.selectedPaper = paper;
this.dialogVisible = true;
console.log('paper', paper);
this.$router.push({
name: 'ViewExamPaper',
query: { userId: this.userId,studentId: paper.sendId, testid: paper.testId ,name: paper.name} // ID
});
},
correctPaper(paper){
},
async remind(paper){
const name = paper.name;
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push("/login"); //
return;
}
const res =await axios.post(`http://localhost:8080/teacher/answerSheet/addMessage`,
{teacherId: this.userId,
studentId: paper.sendId,
tf: false,
name: name,
},{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
}
});
console.log(res);
if(res.data.code == 200){
this.$message.success("提醒成功!");
}else{
this.$message.error("发送失败!");
}
},
submitCorrection() {
this.dialogVisible = false;
@ -100,6 +223,7 @@ export default {
},
},
mounted() {
this.userId = this.$route.query.userId;
this.fetchExamPapers();
},
};

@ -0,0 +1,328 @@
<template>
<div class="exam-container">
<!-- 左侧栏 -->
<div class="sidebar">
<!-- 返回按钮 -->
<div class="back-button">
<button @click="goBack">
<span>返回</span>
</button>
</div>
<h2>{{ examTitle }}</h2>
<p>答题人{{ sender }}</p>
<p>得分{{ currentScore }} &nbsp; 总分{{ totalScore }}</p>
<p>已答对{{ correctQuestions }} &nbsp; 总题数{{ totalQuestions }}</p>
<div class="question-navigation">
<div
v-for="(question, index) in questions"
:key="question.id"
class="question-box"
:class="{ answered: answers[question.id]?.length > 0, active: currentQuestionIndex === index, correct: question.tf === 'true', incorrect: question.tf === 'false' }"
@click="scrollToQuestion(index)"
>
{{ index + 1 }}
</div>
</div>
</div>
<!-- 主内容 -->
<div class="main-content" v-if="!loading && questions.length">
<div
v-for="(question, index) in questions"
:key="question.id"
class="question"
:ref="'question-' + question.id"
:class="{ correct: question.tf === 'true', incorrect: question.tf === 'false', active: currentQuestionIndex === index }"
>
<p>{{ index + 1 }}. {{ question.content }}</p>
<div class="options">
<!-- 单选题 (Single Choice) -->
<template v-if="question.type === '单选题'">
<div v-for="(option, optIndex) in question.chance" :key="optIndex"
class="option"
:class="{ selected: answers[question.id] === option.label }">
{{ option.label }}: {{ option.text }}
</div>
</template>
<!-- 多选题 (Multiple Choice) -->
<template v-else-if="question.type === ''">
<div v-for="(option, optIndex) in question.chance" :key="optIndex" class="option">
{{ option.label }}: {{ option.text }}
</div>
</template>
<!-- 判断题 (True/False) -->
<template v-else-if="question.type === ''">
<div>
<input
type="radio"
:name="'question-' + question.id"
value="true"
:checked="answers[question.id] === 'true'"
disabled
/>
T
</div>
<div>
<input
type="radio"
:name="'question-' + question.id"
value="false"
:checked="answers[question.id] === 'false'"
disabled
/>
F
</div>
</template>
</div>
<p>你的答案<span>{{ question.answer }}</span></p>
<p>正确答案<span>{{ question.idanswer }}</span></p>
<p>分数{{ question.score }} </p>
<p v-if="question.analysis">{{ question.analysis }}</p>
</div>
</div>
<!-- 加载中 -->
<div v-if="loading" class="loading">
正在加载试题请稍候...
</div>
<!-- 空状态 -->
<div v-if="!loading && !questions.length" class="empty">
未找到试题请联系管理员
</div>
</div>
</template>
<script>
import axios from "axios";
import exam from "@/views/Student/Exam.vue";
export default {
name: "ViewExamPaper",
data() {
return {
examTitle: this.examname, //
sender: "", //
totalScore: 0, //
duration: "", //
questions: [], //
answers: {}, //
correctQuestions: 0, //
currentScore: 0, //
totalQuestions: 0, //
loading: true, //
submitted: false, //
currentQuestionIndex: 0, //
};
},
computed: {
totalQuestions() {
return this.questions.length;
},
},
methods: {
async fetchExamData() {
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push("/login");
return;
}
const response = await axios.get(
"http://localhost:8080/teacher/answerSheet/selectQuestionanswer",
{
params: { senderId: this.studentId,testid: this.testid },
headers: { Authorization: `Bearer ${token}` },
}
);
const { sender, list, testid } = response.data.data;
this.examTitle = this.examname;
this.sender = sender;
this.questions = list;
console.log('list', list);
this.totalScore = list.reduce((sum, q) => sum + q.score, 0);
this.correctQuestions = list.filter((q) => q.tf === "true").length;
this.loading = false;
} catch (error) {
console.error("获取试题失败", error);
this.loading = false;
}
},
async getTest() {
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push("/login");
return;
}
const response = await axios.get(
"http://localhost:8080/teacher/answerSheet/getScoreByTestId",
{
params: { studentId:this.studentId, testId: this.testId },
headers: { Authorization: `Bearer ${token}` },
}
);
const data = response.data.data;
this.sender = data.sender;
this.currentScore = data.score;
this.totalScore = data.totalscore;
this.correctQuestions = data.tquestions;
this.totalQuestions = data.totalquestions;
} catch (error) {
console.error("获取试卷信息失败", error);
this.loading = false;
}
},
scrollToQuestion(index) {
this.$nextTick(() => {
const questionRef = this.$refs[`question-${this.questions[index].id}`];
if (questionRef && questionRef[0]) {
questionRef[0].scrollIntoView({ behavior: "smooth", block: "start" });
this.currentQuestionIndex = index;
}
});
},
//
goBack() {
this.$router.go(-1); //
},
},
mounted() {
this.fetchExamData();
},
created() {
this.userId = this.$route.query.userId;
this.examname = this.$route.query.name;
this.testid = this.$route.query.testid;
this.studentId = this.$route.query.studentId;
this.getTest();
},
};
</script>
<style scoped>
.back-button {
padding-bottom: 10px;
text-align: center;
}
.back-button button {
background-color: #1976d2;
color: white;
padding: 8px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 18px;
display: flex;
align-items: center;
}
.back-button button:hover {
background-color: #1565c0;
}
.exam-container {
display: flex;
}
.sidebar {
position: fixed; /* 固定左侧栏 */
top: 0;
left: 0;
width: 20%;
height: 100%;
padding: 20px;
background-color: #f4f4f4;
overflow-y: auto; /* 允许左侧栏滚动 */
border-right: 1px solid #ddd;
}
.sidebar h2,
.sidebar p {
margin-bottom: 10px;
}
.question-navigation {
display: grid;
grid-template-columns: repeat(5, 1fr); /* Adjust number of columns */
gap: 10px;
margin-top: 20px;
}
.question-box {
padding: 15px;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 18px;
cursor: pointer;
transition: background-color 0.3s;
}
.question-box:hover {
background-color: #e0e0e0;
}
.question-box.active {
background-color: #bbdefb; /* Highlight active question */
font-weight: bold;
}
.question-box.answered {
background-color: #c8e6c9; /* Highlight answered question */
}
.question-box.correct {
background-color: #e0f7fa; /* Correct answer color */
color: #00796b; /* Text color for correct answers */
}
.question-box.incorrect {
background-color: #ffebee; /* Incorrect answer color */
color: #d32f2f; /* Text color for incorrect answers */
}
.main-content {
margin-left: 20%; /* 右侧主内容的宽度根据左侧栏的宽度调整 */
padding: 20px;
width: 80%;
overflow-y: auto; /* 使右侧内容可滚动 */
height: 100vh;
}
.question {
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 5px;
}
.correct {
background-color: #e0f7fa;
color: #00796b;
}
.incorrect {
background-color: #ffebee;
color: #d32f2f;
}
.loading,
.empty {
text-align: center;
margin-top: 50px;
font-size: 18px;
}
.empty {
color: #888;
}
</style>
Loading…
Cancel
Save