前端增加教师端试卷中心,学生端消息中心,消息提示图标,完善教师端分数中心部分功能

main
yuan 3 months ago
parent 121f74b222
commit 3528d25c79

@ -76,7 +76,7 @@ public class StudentExamPaperController {
List<ExamPaperDO1> list1 = new ArrayList<>();
for(ClassExamPaper classExamPaper : list ){
ExamPaper examPaper = iExamPaperService.selectById(classExamPaper.getId());
if(examPaper.getStatus()==0L){
if(examPaper.getExamPaperStatus()==0L){
continue;
}
if(type!=null&&!examPaper.getType().equals(type)){

@ -16,11 +16,13 @@ import com.ruoyi.test.seriver.*;
import com.ruoyi.web.controller.system.SysUserController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@Api(tags = "学生端主页")
@RestController
@ -54,6 +56,26 @@ public class StudentHomePageController {
@Autowired
private IInstructorManageClassService iInstructorManageClassService;
@Autowired
private IMessageService iMessageService;
@ApiOperation("查看消息记录")
@GetMapping("getMessage")
public R<List<Message>> getMessage() {
SysUser sysUser = SecurityUtils.getLoginUser().getUser();
Long id = sysUser.getUserId();
return R.ok(iMessageService.selectById(id));
}
@ApiOperation("更新消息记录状态")
@PutMapping("updateMessage")
public R<Integer> updateMessage(@RequestBody Map<String, Long> params) {
System.out.println("============="+params);
Long id = params.get("id");
System.out.println("================="+id);
return R.ok(iMessageService.updateMessage(id));
}
@ApiOperation("获取用户信息")
@GetMapping("getUser")
public R<UserDO> getUser() {
@ -66,8 +88,10 @@ public class StudentHomePageController {
userDO.setGrade(studentClass.getGrade());
userDO.setClass1(studentClass.getClass1());
InstructorManageClass instructorManageClass = iInstructorManageClassService.selectByGradeAndClass1(userDO.getGrade(),userDO.getClass1());
SysUser sysUser1 = iSysUserService.selectUserById(instructorManageClass.getId());
userDO.setTeacherName(sysUser1.getUserName());
if(instructorManageClass!=null){
SysUser sysUser1 = iSysUserService.selectUserById(instructorManageClass.getId());
userDO.setTeacherName(sysUser1.getUserName());
}
return R.ok(userDO);
}

@ -1,26 +1,25 @@
package com.ruoyi.web.controller.test.teacher;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.*;
import com.ruoyi.test.domain.DO.Correct;
import com.ruoyi.test.domain.DO.QuestionAnswerDO;
import com.ruoyi.test.domain.DO.ScoreListDO;
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.ExamPaperVo;
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.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Api(tags = "教师端答卷管理")
@RestController
@ -36,6 +35,9 @@ public class TeacherAnswerSheetController {
@Autowired
private IExamCreateService iExamCreateService;
@Autowired
private IExamPaperService iExamPaperService;
@Autowired
private IQuestionanswerService iQuestionanswerService;
@ -49,16 +51,35 @@ public class TeacherAnswerSheetController {
private ITeacherManageClassService iTeacherManageClassService;
@Autowired
private IMassageService iMassageService;
private IMessageService iMessageService;
@ApiOperation("学生成绩列表")
@GetMapping("selectScoreList")
public R<IPage<ScoreListDO>> selectScoreList(int pageNum,int pageSize){
@Autowired
private IClassExamPaperService iClassExamPaperService;
@ApiOperation("发布成绩")
@PutMapping("fabu")
public R<Integer> fabu(Long testid,String grade,String Class1) {
return R.ok(iMarkedtestService.fabu(testid,grade,Class1));
}
@ApiOperation("试卷列表查询")
@GetMapping("getExamPaperList")
public R<IPage<ExamPaperVo>> getExamPaperList(int pageNum,int pageSize) {
SysUser sysUser = SecurityUtils.getLoginUser().getUser();
Long teacherId = sysUser.getUserId();
List<TeacherManageClass> teacherManageClass = iTeacherManageClassService.selectById(teacherId);
List<StudentClass> studentList = iStudentClassService.getStudentClassByTeacherIdList(teacherManageClass);
return R.ok(iMarkedtestService.selectScoreList(pageNum,pageSize,studentList,teacherId));
List<ExamPaperVo> list = iExamPaperService.getExamPaperList(teacherId);
IPage<ExamPaperVo> page = new Page<>(pageNum, pageSize);
// 将 List 设置为 records
page.setRecords(list);
return R.ok(page);
}
@ApiOperation("学生成绩列表")
@GetMapping("selectScoreList")
public R<List<ScoreListDO>> selectScoreList(Long testid,String grade,String Class1){
return R.ok(iMarkedtestService.selectScoreList(testid,grade,Class1));
}
@ApiOperation("查看学生的考试情况(最新)")
@ -71,15 +92,23 @@ public class TeacherAnswerSheetController {
@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));
List<ExamPaper> examPapers = iExamPaperService.selectByGlId(sysUser.getUserId());
List<ClassExamPaper> list = new ArrayList<>();
for(ExamPaper examPaper : examPapers){
List<ClassExamPaper> studentClass = iClassExamPaperService.selectById(examPaper.getId());
list.addAll(studentClass);
}
List<Long> list1 = iStudentClassService.getStudentClassByClassExamPaperList(list)
.stream()
.map(StudentClass::getStudentid)
.collect(Collectors.toList());
return R.ok(iMarkedtestService.selectByStudentList(sysUser.getUserId(),list1));
}
@ApiOperation("添加提醒消息")
@PostMapping("addMessage")
public R<Integer> addMessage(@RequestBody MessageVo messageVo) {
return R.ok(iMassageService.addMessage(messageVo));
return R.ok(iMessageService.addMessage(messageVo));
}
@ApiOperation("批改客观题")

@ -13,6 +13,7 @@ import com.ruoyi.test.domain.TeacherManageClass;
import com.ruoyi.test.seriver.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@ -44,6 +45,46 @@ public class TeacherExamPaperController {
@Autowired
private IQuestionbankService iQuestionbankService;
@ApiOperation("发布试卷")
@PostMapping("addExamPaper")
public R<Integer> addExamPaper(@RequestBody ClassExamPaper classExamPaper){
return R.ok(iClassExamPaperService.addClassExamPaper(classExamPaper.getGrade(),
classExamPaper.getClass1(),classExamPaper.getId()));
}
@ApiOperation("班级试卷发布查询")
@GetMapping("selectClassRelease")
public R<List<ClassRelease>> selectClassRelease(Long testid){
SysUser sysUser = SecurityUtils.getLoginUser().getUser();
Long id = sysUser.getUserId();
List<TeacherManageClass> list1 = iTeacherManageClassService.selectById(id);
List<ClassRelease> list = new ArrayList<>();
for(TeacherManageClass teacherManageClass : list1){
ClassRelease classRelease = new ClassRelease();
BeanUtils.copyProperties(teacherManageClass,classRelease);
if(iClassExamPaperService.selectByGradeAndClassAndTestId(teacherManageClass.getGrade(),teacherManageClass.getClass1(),testid)){
classRelease.setRelease(1L);
}else{
classRelease.setRelease(0L);
}
list.add(classRelease);
}
return R.ok(list);
}
@ApiOperation("试卷获取")
@GetMapping("getExamPaper")
public R<IPage<ExamPaper>> getExamPaper(@RequestParam int pageNum,@RequestParam int pageSize) {
IPage<ExamPaper> page = new Page<>(pageNum,pageSize);
SysUser sysUser = SecurityUtils.getLoginUser().getUser();
Long id = sysUser.getUserId();
List<ExamPaper> list = iExamPaperService.selectByGlId(id);
IPage<ExamPaper> iPage = new Page<>(page.getCurrent(),page.getSize(),page.getTotal());
iPage.setRecords(list);
return R.ok(iPage);
}
@ApiOperation("试卷列表")
@GetMapping("examPaperList")
public R<IPage<ClassExamPaperDO>> examPaperList(int pagenum){

@ -0,0 +1,13 @@
package com.ruoyi.test.domain.DO;
import lombok.Data;
@Data
public class ClassRelease {
private String grade;
private String Class1;
private Long release;
}

@ -7,16 +7,16 @@ import java.util.Map;
@Data
public class HomepageDO {
private Integer sumclass;
private Integer sumclass;//班级总数
private Integer sunnumclass;
private Integer sunnumclass;//班级总人数
private Integer exampapersum;
private Integer exampapersum;//试卷总数
private Integer sumtimu;
private Integer sumtimu;//题目总数
private Map<String,Integer> classsize;
private Map<String,Integer> classsize;//班级人数分布
private Map<String,Integer> examPaperSize;
private Map<String,Integer> examPaperSize;//班级试卷分布
}

@ -9,12 +9,8 @@ public class ScoreListDO {
private Long senderId;
private String senderName;
private String grade;
private String Class1;
private Long testid;
private Double score;
private String examName;
private Integer ranking;//排名
private Long status;
}

@ -1,6 +1,7 @@
package com.ruoyi.test.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.models.auth.In;
import lombok.Data;
@Data
@TableName("exam_paper")
@ -15,4 +16,6 @@ public class ExamPaper {
private String type;
private Integer time;
private Integer status;
private Integer examPaperStatus;
}

@ -3,11 +3,16 @@ package com.ruoyi.test.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@TableName("message")
public class Message {
private Long id;
private Long teacherId;
private Long studentId;
private String source;
private String tf;
private LocalDateTime createtime;
}

@ -0,0 +1,18 @@
package com.ruoyi.test.domain.Vo;
import lombok.Data;
@Data
public class ExamPaperVo {
private Long id;
private Long glId;
private String grade;
private String Class1;
private String subject;
private String name;
private String type;
private Long completedCount;//完成人数
private Long totalCount;//全部人数
private Integer examPaperStatus;//试卷分布状态
private Integer status;//成绩分布状态
}

@ -10,4 +10,6 @@ import org.apache.ibatis.annotations.Param;
public interface ExamPaperMapper extends BaseMapper<ExamPaper> {
int addPaperExam(@Param("paperCreateDO") PaperCreateDO paperCreateDO);
int updateExamPaper(@Param("testid")Long testid);
}

@ -5,9 +5,13 @@ import com.ruoyi.test.domain.Markedtest;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface MarkedtestMapper extends BaseMapper<Markedtest> {
int addmarkedtest(@Param("markedtest") Markedtest markedtest);
int updateStatusBatch(@Param("testid") Long testid,@Param("list") List<Long> list);
}

@ -9,4 +9,6 @@ import org.apache.ibatis.annotations.Param;
public interface MessageMapper extends BaseMapper<Message> {
int addMessage(@Param("message") Message message);
int updateMessage(@Param("id") Long id);
}

@ -10,5 +10,8 @@ public interface IClassExamPaperService {
int addClassExamPaper(String grade,String Class1,Long id);
List<ClassExamPaper> selectById(Long id);
Boolean selectByGradeAndClassAndTestId(String grade,String Class1,Long testid);
}

@ -5,6 +5,7 @@ import com.ruoyi.test.domain.DO.PaperCreateDO;
import com.ruoyi.test.domain.ExamPaper;
import com.ruoyi.test.domain.TeacherManageClass;
import com.ruoyi.test.domain.TeacherSubject;
import com.ruoyi.test.domain.Vo.ExamPaperVo;
//import com.ruoyi.test.domain.Vo.ExamCreateVo;
import java.util.List;
@ -41,4 +42,6 @@ public interface IExamPaperService {
IPage<ExamPaper> selectByGrateAndSubjectAndId(int pagenum,int pagesize,String grade,String subject,Long id);
List<ExamPaper> selectByGlId(Long teacherId);
List<ExamPaperVo> getExamPaperList(Long teacherId);
}

@ -30,5 +30,8 @@ public interface IMarkedtestService {
List<Correct> selectByStudentList(Long id,List<Long> list);
IPage<ScoreListDO> selectScoreList(int pageNum,int pageSize,List<StudentClass> studentList,Long teacherId);
List<ScoreListDO> selectScoreList(Long testid,String grade,String Class1);
Integer fabu(Long testid,String grade,String Class1);
}

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

@ -0,0 +1,15 @@
package com.ruoyi.test.seriver;
import com.ruoyi.test.domain.Message;
import com.ruoyi.test.domain.Vo.MessageVo;
import java.util.List;
public interface IMessageService {
int addMessage(MessageVo messageVo);
List<Message> selectById(Long id);
Integer updateMessage(Long id);
}

@ -1,5 +1,6 @@
package com.ruoyi.test.seriver;
import com.ruoyi.test.domain.ClassExamPaper;
import com.ruoyi.test.domain.StudentClass;
import com.ruoyi.test.domain.TeacherManageClass;
@ -19,4 +20,5 @@ public interface IStudentClassService {
List<StudentClass> getStudentClassByTeacherIdList(List<TeacherManageClass> teacherManageClasses);
List<StudentClass> getStudentClassByClassExamPaperList(List<ClassExamPaper> list);
}

@ -8,6 +8,7 @@ import com.ruoyi.test.seriver.IClassExamPaperService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
@Service
@ -29,4 +30,23 @@ public class ClassExamPaperServiceImpl extends ServiceImpl<ClassExamPaperMapper,
return classExamPaperMapper.addClassExamPaper(grade,Class1,id);
}
@Override
public List<ClassExamPaper> selectById(Long id) {
LambdaQueryWrapper<ClassExamPaper> queryWrapper = new LambdaQueryWrapper<>();;
queryWrapper.eq(ClassExamPaper::getId,id);
return classExamPaperMapper.selectList(queryWrapper);
}
@Override
public Boolean selectByGradeAndClassAndTestId(String grade, String Class1, Long testid) {
LambdaQueryWrapper<ClassExamPaper> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ClassExamPaper::getGrade,grade)
.eq(ClassExamPaper::getClass1,Class1)
.eq(ClassExamPaper::getId,testid);
if(classExamPaperMapper.selectCount(queryWrapper)>0){
return true;
}
return false;
}
}

@ -4,13 +4,15 @@ 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.test.domain.*;
import com.ruoyi.test.domain.DO.PaperCreateDO;
import com.ruoyi.test.domain.ExamPaper;
import com.ruoyi.test.domain.Subject;
import com.ruoyi.test.domain.TeacherManageClass;
import com.ruoyi.test.domain.TeacherSubject;
import com.ruoyi.test.domain.Vo.ExamPaperVo;
import com.ruoyi.test.mapper.ClassExamPaperMapper;
import com.ruoyi.test.mapper.ExamPaperMapper;
import com.ruoyi.test.mapper.MarkedtestMapper;
import com.ruoyi.test.mapper.StudentClassMapper;
import com.ruoyi.test.seriver.IExamPaperService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Service;
@ -18,12 +20,19 @@ import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ExamPaperServiceImpl extends ServiceImpl<ExamPaperMapper, ExamPaper> implements IExamPaperService {
@Autowired
private ExamPaperMapper examPaperMapper;
@Autowired
private ClassExamPaperMapper classExamPaperMapper;
@Autowired
private StudentClassMapper studentClassMapper;
@Autowired
private MarkedtestMapper markedtestMapper;
@Override
public IPage<ExamPaper> selectAll(int pagenum,int pagesize) {
@ -149,6 +158,40 @@ public class ExamPaperServiceImpl extends ServiceImpl<ExamPaperMapper, ExamPaper
return examPaperMapper.selectList(queryWrapper);
}
@Override
public List<ExamPaperVo> getExamPaperList(Long teacherId) {
LambdaQueryWrapper<ExamPaper> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ExamPaper::getGlId,teacherId);
List<ExamPaper> list = examPaperMapper.selectList(queryWrapper);
List<ExamPaperVo> list1 = new ArrayList<>();
for(ExamPaper examPaper : list){
Long testid = examPaper.getId();
LambdaQueryWrapper<ClassExamPaper> queryWrapper1 = new LambdaQueryWrapper<>();
queryWrapper1.eq(ClassExamPaper::getId,testid);
List<ClassExamPaper> studentClasses = classExamPaperMapper.selectList(queryWrapper1);
for(ClassExamPaper classExamPaper : studentClasses){
ExamPaperVo examPaperVo = new ExamPaperVo();
BeanUtils.copyProperties(examPaper,examPaperVo);
examPaperVo.setClass1(classExamPaper.getClass1());
LambdaQueryWrapper<StudentClass> queryWrapper2 = new LambdaQueryWrapper<>();
queryWrapper2.eq(StudentClass::getGrade,classExamPaper.getGrade())
.eq(StudentClass::getClass1,classExamPaper.getClass1());
List<Long> studentList = studentClassMapper.selectList(queryWrapper2)
.stream()
.map(StudentClass::getStudentid)
.collect(Collectors.toList());
examPaperVo.setTotalCount((long) studentList.size());
LambdaQueryWrapper<Markedtest> queryWrapper3 = new LambdaQueryWrapper<>();
queryWrapper3.eq(Markedtest::getTestid,testid)
.in(Markedtest::getSenderId,studentList);
examPaperVo.setCompletedCount(markedtestMapper.selectCount(queryWrapper3));
list1.add(examPaperVo);
}
}
return list1;
}
// @Override
// public List<ExamPaper> totalExamPaper(List<TeacherManageClass> list, List<TeacherSubject> list2) {
// List<ExamPaper> list1 = new ArrayList<>();

@ -14,6 +14,7 @@ import com.ruoyi.test.domain.Vo.QuestionbankVo;
import com.ruoyi.test.mapper.AnswerMapper;
import com.ruoyi.test.mapper.ExamPaperMapper;
import com.ruoyi.test.mapper.MarkedtestMapper;
import com.ruoyi.test.mapper.StudentClassMapper;
import com.ruoyi.test.seriver.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
@ -27,6 +28,9 @@ import java.util.stream.Collectors;
@Service
public class MarkedtestServiceImpl extends ServiceImpl<MarkedtestMapper, Markedtest> implements IMarkedtestService {
@Autowired
private StudentClassMapper studentClassMapper;
@Autowired
private MarkedtestMapper markedtestMapper;
@ -231,68 +235,93 @@ public class MarkedtestServiceImpl extends ServiceImpl<MarkedtestMapper, Markedt
}
@Override
public IPage<ScoreListDO> selectScoreList(int pageNum, int pageSize, List<StudentClass> studentList, Long teacherId) {
List<ExamPaper> examPapers = iExamPaperService.selectByGlId(teacherId);
List<ScoreListDO> scoreList = new ArrayList<>();
for(ExamPaper examPaper : examPapers){
for(StudentClass studentClass : studentList){
LambdaQueryWrapper<Markedtest> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Markedtest::getSenderId,studentClass.getStudentid())
.eq(Markedtest::getTestid,examPaper.getId());
Markedtest markedtest = markedtestMapper.selectOne(queryWrapper);
ScoreListDO scoreListDO = new ScoreListDO();
if(markedtest!=null){
scoreListDO.setSenderId(studentClass.getStudentid());
scoreListDO.setTestid(examPaper.getId());
scoreListDO.setSenderName(iSysUserService.selectUserById(studentClass.getStudentid()).getUserName());
scoreListDO.setExamName(examPaper.getName());
scoreListDO.setScore(markedtest.getScore());
scoreListDO.setGrade(studentClass.getGrade());
scoreListDO.setClass1(studentClass.getClass1());
scoreListDO.setStatus(markedtest.getStatus());
scoreList.add(scoreListDO);
}
public List<ScoreListDO> selectScoreList(Long testid, String grade, String Class1) {
LambdaQueryWrapper<StudentClass> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StudentClass::getGrade,grade)
.eq(StudentClass::getClass1,Class1);
List<StudentClass> list = studentClassMapper.selectList(queryWrapper);
List<ScoreListDO> list1 = new ArrayList<>();
for(StudentClass studentClass : list){
ScoreListDO scoreListDO = new ScoreListDO();
scoreListDO.setTestid(testid);
scoreListDO.setSenderId(studentClass.getStudentid());
scoreListDO.setSenderName(iSysUserService.selectUserById(studentClass.getStudentid()).getUserName());
LambdaQueryWrapper<Markedtest> queryWrapper1 = new LambdaQueryWrapper<>();
queryWrapper1.eq(Markedtest::getTestid,testid)
.eq(Markedtest::getSenderId,studentClass.getStudentid());
Markedtest markedtest = markedtestMapper.selectOne(queryWrapper1);
if(markedtest==null){
scoreListDO.setScore(null);
}else{
scoreListDO.setScore(markedtest.getScore());
}
list1.add(scoreListDO);
}
list1.sort((o1, o2) -> {
// 处理 null 分数的情况
Double score1 = o1.getScore();
Double score2 = o2.getScore();
// 如果两个分数都为 null认为它们相等
if (score1 == null && score2 == null) {
return 0;
}
System.out.println(scoreList);
// 按年级和班级分组
Map<String, List<ScoreListDO>> groupedByGradeAndClass = scoreList.stream()
.collect(Collectors.groupingBy(score -> score.getGrade() + "-" + score.getClass1()));
// 计算每个组内的排名
for (Map.Entry<String, List<ScoreListDO>> entry : groupedByGradeAndClass.entrySet()) {
List<ScoreListDO> students = entry.getValue();
// 如果分数1是 null分数2不是 null则分数1排在后面
else if (score1 == null) {
return 1;
}
// 按得分降序排序
students.sort((s1, s2) -> Double.compare(s2.getScore(), s1.getScore()));
// 如果分数2是 null分数1不是 null则分数2排在后面
else if (score2 == null) {
return -1;
}
// 给每个学生计算排名
int rank = 1;
for (int i = 0; i < students.size(); i++) {
ScoreListDO student = students.get(i);
// 如果与前一个学生分数相同,则排名相同
if (i > 0 && students.get(i).getScore() == students.get(i - 1).getScore()) {
student.setRanking(students.get(i - 1).getRanking());
} else {
student.setRanking(rank);
}
rank++;
// 否则按分数降序排列
else {
return Double.compare(o2.getScore(), o1.getScore());
}
});
// 为每个ScoreListDO设置排名
int rank = 1;
for (int i = 0; i < list1.size(); i++) {
ScoreListDO scoreListDO = list1.get(i);
// 如果当前分数与前一个分数相同,则排名相同
if (i > 0 && scoreListDO.getScore() != null && scoreListDO.getScore().equals(list1.get(i - 1).getScore())) {
scoreListDO.setRanking(list1.get(i - 1).getRanking());
} else if (scoreListDO.getScore() != null) {
// 如果当前分数不为 null设置当前排名
scoreListDO.setRanking(rank);
} else {
// 如果分数为 null直接设置一个排名值跳过之前的排名
scoreListDO.setRanking(rank);
}
// 增加排名
rank++;
}
return list1;
}
// 把所有学生数据合并回一个列表并返回
List<ScoreListDO> collect = groupedByGradeAndClass.values().stream()
.flatMap(List::stream)
@Override
public Integer fabu(Long testid, String grade, String Class1) {
LambdaQueryWrapper<StudentClass> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StudentClass::getGrade,grade)
.eq(StudentClass::getClass1,Class1);
List<Long> list = studentClassMapper.selectList(queryWrapper).stream()
.map(StudentClass::getStudentid)
.collect(Collectors.toList());
// 创建 Page 对象,设置当前页和每页大小
IPage<ScoreListDO> page = new Page<>(pageNum, pageSize);
// 将 List 设置为 records
page.setRecords(collect);
return page;
if(examPaperMapper.updateExamPaper(testid)>0){
if(markedtestMapper.updateStatusBatch(testid,list)>0){
return 1;
}
return -1;
}
return -1;
}
}

@ -1,17 +1,21 @@
package com.ruoyi.test.seriver.Impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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 com.ruoyi.test.seriver.IMessageService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
@Service
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements IMassageService {
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements IMessageService {
@Autowired
private MessageMapper messageMapper;
@ -28,4 +32,21 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
message.setSource(source);
return messageMapper.addMessage(message);
}
@Override
public List<Message> selectById(Long id) {
LambdaQueryWrapper<Message> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Message::getStudentId, id) // 按照学生 ID 查询
.orderBy(true, true, Message::getTf) // 按照 tf 字段的值进行降序排列
.orderByDesc(Message::getCreatetime); // 如果 tf 相同,再按照 createtime 字段降序排序
return messageMapper.selectList(queryWrapper);
}
@Override
public Integer updateMessage(Long id) {
return messageMapper.updateMessage(id);
}
}

@ -2,6 +2,7 @@ package com.ruoyi.test.seriver.Impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.test.domain.ClassExamPaper;
import com.ruoyi.test.domain.StudentClass;
import com.ruoyi.test.domain.TeacherManageClass;
import com.ruoyi.test.mapper.StudentClassMapper;
@ -9,6 +10,7 @@ import com.ruoyi.test.seriver.IStudentClassService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@ -92,5 +94,17 @@ public class StudentClassServiceImpl extends ServiceImpl<StudentClassMapper, Stu
return studentIds;
}
@Override
public List<StudentClass> getStudentClassByClassExamPaperList(List<ClassExamPaper> list) {
List<StudentClass> studentIds = new ArrayList<>();
for(ClassExamPaper classExam : list){
LambdaQueryWrapper<StudentClass> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StudentClass::getGrade,classExam.getGrade())
.eq(StudentClass::getClass1,classExam.getClass1());
studentIds.addAll(studentClassMapper.selectList(queryWrapper));
}
return studentIds;
}
}

@ -24,4 +24,10 @@
Now()
)
</insert>
<update id="updateExamPaper" parameterType="long">
UPDATE exam_paper
SET status = 1
WHERE id = #{testid}
</update>
</mapper>

@ -29,4 +29,16 @@
)
</insert>
<!-- 批量更新状态 -->
<update id="updateStatusBatch">
UPDATE markedtest
SET status = 1
WHERE testid = #{testid}
AND sender_id IN
<foreach item="item" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</update>
</mapper>

@ -10,12 +10,18 @@
teacher_id,
student_id,
source,
tf
tf,
createtime
)values (
#{message.teacherId},
#{message.studentId},
#{message.source},
#{message.tf}
#{message.tf},
Now()
)
</insert>
<update id="updateMessage" parameterType="Long">
update message set tf="true" where id=#{id}
</update>
</mapper>

@ -40,7 +40,7 @@
"axios": "0.28.1",
"clipboard": "2.0.8",
"core-js": "3.37.1",
"echarts": "5.4.0",
"echarts": "^4.9.0",
"element-ui": "2.15.14",
"file-saver": "2.0.5",
"fuse.js": "6.4.3",

@ -10,6 +10,7 @@
"dependencies": {
"axios": "^1.7.7",
"core-js": "^3.39.0",
"echarts": "^4.9.0",
"element-ui": "^2.15.14",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
@ -4948,6 +4949,14 @@
"node": ">=6.0.0"
}
},
"node_modules/echarts": {
"version": "4.9.0",
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-4.9.0.tgz",
"integrity": "sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==",
"dependencies": {
"zrender": "4.3.2"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz",
@ -10416,6 +10425,11 @@
"engines": {
"node": ">=10"
}
},
"node_modules/zrender": {
"version": "4.3.2",
"resolved": "https://registry.npmmirror.com/zrender/-/zrender-4.3.2.tgz",
"integrity": "sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g=="
}
}
}

@ -9,6 +9,7 @@
"dependencies": {
"axios": "^1.7.7",
"core-js": "^3.39.0",
"echarts": "^4.9.0",
"element-ui": "^2.15.14",
"vue": "^2.6.14",
"vue-router": "^3.5.1",

@ -86,10 +86,8 @@ export default {
if(res.data.code==200){
const token = response.data.token;
const userId = res.data.user.userId;
console.log('userId', userId);
this.$store.dispatch('setToken', { userId, token });
if(res.data.roles[0] === 'student'){
// 使 Vue Router
this.$router.push({
path: '/user/profile',
query: { userId: userId }

@ -18,7 +18,7 @@
</el-menu-item>
<el-menu-item :index="`/student/exam?userId=${userId}`">
<i class="el-icon-message"></i>
<i class="el-icon-edit-outline"></i>
<span>试卷中心</span>
</el-menu-item>
@ -26,6 +26,11 @@
<i class="el-icon-s-data"></i>
<span>分数查询</span>
</el-menu-item>
<el-menu-item :index="`/student/message?userId=${userId}`">
<i class="el-icon-message"></i>
<span>消息查询</span>
</el-menu-item>
</el-menu>
</template>

@ -3,6 +3,22 @@
<div class="left-section">
<span :class="collapseBtnClass" class="collapse-icon" @click="collapse"></span>
</div>
<!-- 显示未确认消息数量 -->
<div class="message-container">
<!-- 动态绑定类名根据 unconfirmedCount 改变图标颜色添加悬浮提示 -->
<span
:class="['message-icon', iconClass]"
@click="goToMessages"
:title="unconfirmedCount > 0 ? `有 ${unconfirmedCount} 条消息为确认` : ''">
<i class="el-icon-message-solid"></i>
</span>
<!-- 悬浮提示框 -->
<div v-if="unconfirmedCount > 0" class="tooltip">
{{ unconfirmedCount }} 条消息为确认
</div>
</div>
<div class="logout-container">
<span class="logout-btn" @click="logout">退</span>
</div>
@ -10,23 +26,83 @@
</template>
<script>
import axios from "axios";
export default {
name: "Header",
props: {
collapseBtnClass: String,
collapse: Boolean,
},
data() {
return {
collapseBtnClass: 'el-icon-s-fold',
unconfirmedCount: 0, //
};
},
created() {
this.userId = this.$route.query.userId;
this.sss();
},
methods: {
logout() {
//
this.$store.dispatch("logout"); // Vuex
this.$router.push("/login"); //
},
async sss(){
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push('/login');
return false;
}
const response = await axios.get("http://localhost:8080/student/homepage/getMessage", {
headers: {
Authorization: `Bearer ${token}`,
}
});
if (response.data.code === 200) {
//
const unconfirmedCount = response.data.data.filter(message => message.tf === 'false').length;
this.unconfirmedCount = unconfirmedCount;
}
}catch (error){
console.error('请求错误:', error);
alert('请求错误');
}
},
goToMessages() {
const currentRoute = this.$route.path;
const targetRoute = '/student/message';
const targetQuery = { userId: this.userId };
//
if (currentRoute === targetRoute && JSON.stringify(this.$route.query) === JSON.stringify(targetQuery)) {
return;
}
this.$router.push({ path: targetRoute, query: targetQuery });
}
},
computed: {
//
iconClass() {
return this.unconfirmedCount > 0 ? 'warning' : 'success';
}
}
}
</script>
<style scoped lang="scss">
.warning {
color: red; /* 未读消息时,警告颜色 */
}
.success {
color: green; /* 没有未读消息时,成功颜色 */
}
.header-container {
display: flex;
justify-content: space-between;
@ -46,6 +122,72 @@ export default {
font-size: 20px;
}
.message-container {
display: flex;
align-items: center;
margin-right: 20px; /* 保证图标和退出按钮之间有间距 */
position: relative;
}
.message-icon {
font-size: 20px;
cursor: pointer;
position: relative;
display: inline-block;
width: 40px;
height: 40px;
background-color: #f0f2f5; /* 背景颜色 */
border-radius: 50%; /* 圆形 */
display: flex;
justify-content: center;
align-items: center;
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; /* 更快速的悬浮效果 */
}
.message-icon:hover {
transform: scale(1.3); /* 鼠标悬停时图标放大 */
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2); /* 增加阴影 */
}
.tooltip {
position: absolute;
top: 50%;
left: -150px; /* 调整为左侧显示 */
transform: translateY(-50%); /* 垂直居中对齐 */
background-color: rgba(0, 0, 0, 0.75);
color: white;
font-size: 12px;
padding: 8px 12px;
border-radius: 6px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
white-space: nowrap;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease;
z-index: 10; /* 确保悬浮框显示在前面 */
}
.message-container:hover .tooltip {
opacity: 1;
visibility: visible;
}
.message-count {
position: absolute;
top: -5px;
right: -5px;
background-color: red;
color: white;
font-size: 12px;
padding: 2px 5px;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.logout-container {
display: flex;
align-items: center;

@ -16,10 +16,10 @@
<span>主页</span>
</el-menu-item>
<!-- <el-menu-item :index="`/teacher/exam?userId=${userId}`">-->
<!-- <i class="el-icon-message"></i>-->
<!-- <span>试卷中心</span>-->
<!-- </el-menu-item>-->
<el-menu-item :index="`/teacher/teacherExam?userId=${userId}`">
<i class="el-icon-message"></i>
<span>试卷中心</span>
</el-menu-item>
<el-menu-item :index="`/teacher/score?userId=${userId}`">
<i class="el-icon-s-data"></i>

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

@ -82,7 +82,7 @@ export default {
components: {Aside, Header},
data() {
return {
paperTypes: ["固定试卷", "时段试卷", "班级试卷"], //
paperTypes: ["固定试卷","随机试卷"], //
subjects: ["语文", "数学"], //
selectedType: "班级试卷", //
selectedSubject: "语文", //

@ -0,0 +1,165 @@
<template>
<el-container style="min-height: 100vh">
<el-aside :width="sideWidth+'px'" style="background-color: rgb(238, 241, 246); box-shadow: 2px 0 6px rgb(0 21 41 / 35%)">
<Aside :isCollapse="isCollapse" :logoTextShow="logoTextShow"/>
</el-aside>
<el-container>
<el-header style="border-bottom:1px solid #ccc;">
<Header :collapseBtnClass="collapseBtnClass" :collapse="collapse"/>
</el-header>
<el-main>
<!-- 消息列表 -->
<el-table :data="messages" style="width: 100%">
<el-table-column label="消息内容" prop="source"></el-table-column>
<!-- 确认状态 -->
<el-table-column label="确认状态" width="150">
<template #default="{ row }">
<el-tag :type="row.tf === 'true' ? 'success' : 'danger'" style="border-radius: 5px; font-size: 14px;">
{{ row.tf === 'true' ? '已确认' : '未确认' }}
</el-tag>
</template>
</el-table-column>
<!-- 操作按钮 -->
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button
@click="confirmMessage(row)"
:type="row.tf === 'false' ? 'primary' : 'success'"
size="small"
:disabled="row.tf === 'true'">
{{ row.tf === 'false' ? '确认' : '已确认' }}
</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</el-container>
</template>
<script>
import axios from "axios";
import { mapActions } from "vuex";
import Aside from "@/components/Student/Aside.vue";
import Header from "@/components/Student/Header.vue";
export default {
name: "Message",
components: { Aside, Header },
data() {
return {
collapseBtnClass: 'el-icon-s-fold',
isCollapse: false,
sideWidth: 200,
logoTextShow: true,
messages: [], //
userId: null, // ID
unconfirmedCount: 0, //
};
},
methods: {
collapse() {
this.isCollapse = !this.isCollapse;
if (this.isCollapse) {
this.sideWidth = 64;
this.collapseBtnClass = 'el-icon-s-unfold';
this.logoTextShow = false;
} else {
this.sideWidth = 200;
this.collapseBtnClass = 'el-icon-s-fold';
this.logoTextShow = true;
}
},
//
async fetchMessages() {
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push('/login');
return false;
}
const response = await axios.get("http://localhost:8080/student/homepage/getMessage", {
headers: {
Authorization: `Bearer ${token}`,
}
});
console.log("response", response);
if (response.data.code === 200) {
this.messages = response.data.data;
//
const unconfirmedCount = this.messages.filter(message => message.tf === 'false').length;
} else {
console.error("获取消息失败", response.data.message);
}
} catch (error) {
console.error("请求错误:", error);
}
},
//
async confirmMessage(row) {
console.log("row", row.id);
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push('/login');
return false;
}
const id = row.id;
const response = await axios.put(
"http://localhost:8080/student/homepage/updateMessage",
{ id: id },
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
}
}
);
console.log("response", response);
if (response.data.code === 200) {
this.$message.success("消息已确认");
location.reload();
} else {
this.$message.error("确认消息失败");
}
} catch (error) {
console.error("请求错误:", error);
this.$message.error("请求错误");
}
}
},
created() {
this.userId = this.$route.query.userId;
this.fetchMessages(); //
}
};
</script>
<style scoped lang="scss">
/* 自定义样式 */
.el-table {
margin-top: 20px;
}
.el-button {
width: 100px;
margin: 0 auto;
}
.el-tag {
font-size: 14px;
margin: 0;
}
</style>

@ -1,212 +0,0 @@
<script>
export default {
name: "Class"
}
</script>
<template>
</template>
<style scoped lang="scss">
</style>
<template>
<el-container style="min-height: 100vh">
<el-aside :width="sideWidth+'px'" style="background-color: rgb(238, 241, 246); box-shadow: 2px 0 6px rgb(0 21 41 / 35%)">
<el-menu :default-openeds="['1', '3']" style="min-height: 100%; overflow-x: hidden"
background-color="rgb(48,65,86)"
text-color="#fff"
active-text-color="#ffd04b"
:collapse-transition="false"
:collapse="isCollapse"
>
<div style="height: 60px;line-height: 60px;text-align: center">
<img src="../assets/logo.png" alt="" style="width: 20px;position: relative;top: 5px;margin-right: 5px">
<b style="color: white" v-show="logoTextShow"></b>
</div>
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>
<span slot="title">导航一</span>
</template>
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="1-1">选项1</el-menu-item>
<el-menu-item index="1-2">选项2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="1-3">选项3</el-menu-item>
</el-menu-item-group>
<el-submenu index="1-4">
<template slot="title">选项4</template>
<el-menu-item index="1-4-1">选项4-1</el-menu-item>
</el-submenu>
</el-submenu>
<el-submenu index="2">
<template slot="title"><i class="el-icon-menu"></i>
<span slot="title">导航二</span>
</template>
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="2-1">选项1</el-menu-item>
<el-menu-item index="2-2">选项2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="2-3">选项3</el-menu-item>
</el-menu-item-group>
<el-submenu index="2-4">
<template slot="title">选项4</template>
<el-menu-item index="2-4-1">选项4-1</el-menu-item>
</el-submenu>
</el-submenu>
<el-submenu index="3">
<template slot="title"><i class="el-icon-setting"></i>
<span slot="title">导航三</span>
</template>
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="3-1">选项1</el-menu-item>
<el-menu-item index="3-2">选项2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="3-3">选项3</el-menu-item>
</el-menu-item-group>
<el-submenu index="3-4">
<template slot="title">选项4</template>
<el-menu-item index="3-4-1">选项4-1</el-menu-item>
</el-submenu>
</el-submenu>
</el-menu>
</el-aside>
<el-container>
<el-header style="font-size: 12px;border-bottom:1px solid #ccc;line-height: 60px;display: flex">
<div style="flex: 1;font-size: 20px">
<span :class="collapseBtnClass" style="cursor:pointer" @click="collapse"></span>
</div>
<el-dropdown style="width: 70px; cursor: pointer">
<span>王小虎</span>
<i class="el-icon-arrow-down" style="margin-left: 5px"></i>
<!-- <i class="el-icon-setting" style="margin-right: 15px"></i>-->
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人信息</el-dropdown-item>
<el-dropdown-item>退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-header>
<el-main>
<div style="padding: 10px 0">
<el-input style="width: 200px" placeholder="请输入名称" suffix-icon="el-icon-search"></el-input>
<el-input style="width: 200px" placeholder="请输入邮箱" suffix-icon="el-icon-message" class="ml-5"></el-input>
<el-input style="width: 200px" placeholder="请输入地址" suffix-icon="el-icon-position" class="ml-5"></el-input>
<el-button class="ml-5" type="primary">搜索</el-button>
</div>
<div style="margin:10px 0">
<el-button type="primary">新增<i class="el-icon-circle-plus-outline"></i></el-button>
<el-button type="danger">批量删除<i class="el-icon-circle-plus-outline"></i></el-button>
<el-button type="primary">导入<i class="el-icon-circle-plus-outline"></i></el-button>
<el-button type="primary">导出<i class="el-icon-circle-plus-outline"></i></el-button>
</div>
<el-table :data="tableData" border stripe header-row-class-name="headerBg">
<el-table-column prop="sumclass" label="班级总数" width="140">
</el-table-column>
<el-table-column prop="sunnumclass" label="班级人数总数" width="120">
</el-table-column>
<el-table-column prop="exampapersum" label="试卷总数">
</el-table-column>
<el-table-column prop="sumtimu" label="题目总数">
</el-table-column>
<el-table-column>
<template slot-scope="scope">
<el-button type="success">编辑 <i class="el-icon-edit"></i></el-button>
<el-button type="danger">删除 <i class="el-icon-circle-plus-outline"></i></el-button>
</template>
</el-table-column>
</el-table>
<div>
<el-pagination
:page-sizes="[5, 10, 15, 20]"
:page-size="10"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
name: 'HomeView',
data(){
return {
tableData: [],
total:0,
collapseBtnClass:'el-icon-s-fold',
isCollapse: false,
sideWidth: 200,
logoTextShow: true
}
},
created() {
// 使 Vuex getter token
const token = this.$store.state.token;
console.log("token:",token);
if (!token) {
console.error('No token found, redirecting to login page...');
this.$router.push({ name: 'login' }); //
return;
}
this.fetchHomePageData(token);
},
methods: {
async fetchHomePageData(token) {
try {
const response = await fetch('http://localhost:8080/teacher/homepage/homepagesuju', {
method: 'GET',
headers: {
'Authorization': token,
'Content-Type': 'application/json',
}
});
const data = await response.json();
if (response.ok && data.code === 200) {
const { sumclass, sunnumclass, exampapersum, sumtimu } = data.data;
console.log("API Response:", data.data);
this.tableData = [
{ sumclass, sunnumclass, exampapersum, sumtimu }
];
} else {
console.error('Failed to fetch data:', data.msg || 'Unknown error');
}
} catch (error) {
console.error('Error fetching data:', error);
}
},
collapse(){
//
this.isCollapse = !this.isCollapse
if(this.isCollapse){
this.sideWidth = 64
this.collapseBtnClass = 'el-icon-s-unfold'
this.logoTextShow = false
}else{
this.sideWidth = 200
this.collapseBtnClass = 'el-icon-s-fold'
this.logoTextShow = true
}
}
}
}
</script>

@ -1,47 +1,48 @@
<template>
<el-container style="min-height: 100vh">
<!-- 左侧导航 -->
<el-aside :width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246); box-shadow: 2px 0 6px rgb(0 21 41 / 35%)">
<el-aside :width="sideWidth + 'px'" style="background-color: #f4f6f9; box-shadow: 2px 0 6px rgba(0, 21, 41, 0.1)">
<Aside :isCollapse="isCollapse" :logoTextShow="logoTextShow" />
</el-aside>
<!-- 右侧内容 -->
<el-container>
<!-- 顶部导航 -->
<el-header style="border-bottom:1px solid #ccc;">
<el-header style="border-bottom: 1px solid #e0e0e0; background-color: #ffffff; padding: 10px;">
<Header :collapseBtnClass="collapseBtnClass" :collapse="collapse" />
</el-header>
<!-- 主内容 -->
<el-main>
<el-main style="padding: 20px; background-color: #f9f9f9;">
<div class="dashboard">
<!-- 统计卡片 -->
<el-row :gutter="20">
<el-col :span="6" v-for="(item, index) in summaryData" :key="index">
<el-card class="card-box">
<el-card class="card-box" :body-style="{ padding: '20px' }" shadow="hover">
<div slot="header" class="card-header">
<i :class="item.icon" class="card-icon"></i> <!-- 图标 -->
{{ item.title }}
<span>{{ item.title }}</span>
</div>
<div class="card-content">
<span class="value-text">{{ item.value }}</span>
</div>
<div class="card-content">{{ item.value }}</div>
</el-card>
</el-col>
</el-row>
<!-- 图表展示 -->
<el-row :gutter="20" style="margin-top: 20px;">
<!-- 图表展示区域 -->
<el-row :gutter="20">
<el-col :span="12">
<div class="chart-card">
<h3>班级人数分布</h3>
<div ref="genderPieChart" class="chart-container"></div>
<h3 class="chart-title">班级人数分布</h3>
<div ref="genderPieChart" class="chart-container" style="height: 300px; border-radius: 10px; border: 2px solid #f0f0f0;"></div>
</div>
</el-col>
<el-col :span="12">
<div class="chart-card">
<h3>班级试卷分布</h3>
<div ref="songTypeBarChart" class="chart-container"></div>
<h3 class="chart-title">班级试卷分布</h3>
<div ref="examPaperPieChart" class="chart-container" style="height: 300px; border-radius: 10px; border: 2px solid #f0f0f0;"></div>
</div>
</el-col>
</el-row>
</div>
</el-main>
</el-container>
@ -51,32 +52,34 @@
<script>
import Header from "@/components/Teacher/Header.vue";
import Aside from "@/components/Teacher/Aside.vue";
import axios from 'axios'; // axios
import axios from 'axios';
import * as echarts from 'echarts';
export default {
name: "HomePage",
components: { Aside, Header },
data() {
return {
userId:"",
userId: "",
collapseBtnClass: "el-icon-s-fold",
isCollapse: false,
sideWidth: 200,
logoTextShow: true,
// value
summaryData: [
{ title: "班级总数", icon: "el-icon-user", value: "" }, //
{ title: "班级总数", icon: "el-icon-user", value: "" },
{ title: "班级总人数", icon: "el-icon-s-custom", value: "" },
{ title: "试卷总数", icon: "el-icon-folder-checked", value: "" },
{ title: "题目总数", icon: "el-icon-tickets", value: "" }
]
],
classsize: {},
examPaperSize: {}
};
},
mounted() {
// API
this.fetchSummaryData();
//
this.initCharts();
this.$nextTick(() => {
this.initCharts();
});
},
created() {
this.userId = this.$route.query.userId;
@ -94,97 +97,229 @@ export default {
this.logoTextShow = true;
}
},
//
async fetchSummaryData() {
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push("/login"); //
return;
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push("/login");
return;
}
const response = await axios.get('http://localhost:8080/teacher/homepage/homepagesuju', {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
}
const response = await axios.get('http://localhost:8080/teacher/homepage/homepagesuju',{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
}
}); // API
// `value`
const data = response.data;
console.log('data',data);
// summaryData value
});
const data = response.data.data;
// summaryData
this.summaryData = this.summaryData.map(item => {
return {...item, value: data[item.title] || "0"}; // title
switch (item.title) {
case "班级总数":
item.value = data.sumclass || "0";
break;
case "班级总人数":
item.value = data.sunnumclass || "0";
break;
case "试卷总数":
item.value = data.exampapersum || "0";
break;
case "题目总数":
item.value = data.sumtimu || "0";
break;
default:
break;
}
return item;
});
this.classsize = data.classsize;
this.examPaperSize = data.examPaperSize;
this.initCharts(); //
} catch (error) {
console.error('获取数据失败', error);
}
},
initCharts() {
//
// genderPieChart
// new ChartLibrary(this.$refs.genderPieChart, options);
const classsizeData = Object.entries(this.classsize).map(([key, value]) => ({
name: key,
value: value
}));
const examPaperData = Object.entries(this.examPaperSize).map(([key, value]) => ({
name: key,
value: value
}));
//
let genderPieChart = echarts.getInstanceByDom(this.$refs.genderPieChart);
if (genderPieChart) {
genderPieChart.dispose();
}
genderPieChart = echarts.init(this.$refs.genderPieChart);
genderPieChart.setOption({
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: Object.keys(this.classsize),
top: 'middle',
textStyle: {
fontSize: 14
}
},
series: [
{
name: '班级人数分布',
type: 'pie',
radius: ['50%', '70%'], //
data: classsizeData,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
itemStyle: {
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
position: 'outside', //
formatter: '{b}: {c} ({d}%)', //
fontSize: 14,
fontWeight: 'bold',
color: '#333'
},
labelLine: {
show: true, // 线
length: 15, // 线
lineStyle: {
width: 2,
type: 'solid',
color: '#333'
}
}
}
],
});
//
let examPaperPieChart = echarts.getInstanceByDom(this.$refs.examPaperPieChart);
if (examPaperPieChart) {
examPaperPieChart.dispose();
}
examPaperPieChart = echarts.init(this.$refs.examPaperPieChart);
examPaperPieChart.setOption({
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: Object.keys(this.examPaperSize),
top: 'middle',
textStyle: {
fontSize: 14
}
},
series: [
{
name: '试卷分布',
type: 'pie',
radius: ['50%', '70%'], //
data: examPaperData,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
itemStyle: {
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
position: 'outside', //
formatter: '{b}: {c} ({d}%)', //
fontSize: 14,
fontWeight: 'bold',
color: '#333'
},
labelLine: {
show: true, // 线
length: 15, // 线
lineStyle: {
width: 2,
type: 'solid',
color: '#333'
}
}
}
],
});
}
}
}
</script>
<style scoped>
.dashboard {
padding: 20px;
}
.card-box {
background: #fff;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
display: flex;
flex-direction: column;
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
text-align: center; /* 保证文字居中 */
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
transition: transform 0.3s ease;
}
.card-box:hover {
transform: translateY(-5px);
}
.card-header {
font-size: 18px;
color: #333;
font-weight: bold;
color: #409EFF;
display: flex;
align-items: center;
justify-content: center; /* 水平居中 */
}
.card-icon {
margin-right: 10px; /* 图标与文字之间的间距 */
font-size: 24px; /* 图标大小 */
}
.card-content {
font-size: 24px;
margin-top: 10px;
}
/* 卡片悬停效果 */
.card-box:hover {
transform: scale(1.05);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
margin-right: 10px;
}
.chart-card {
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
.value-text {
font-size: 22px;
font-weight: bold;
color: #409eff;
}
.chart-card:hover {
transform: scale(1.05);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
.chart-title {
font-size: 18px;
color: #333;
font-weight: bold;
margin-bottom: 10px;
}
.chart-container {
height: 300px;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
</style>

@ -1,78 +1,128 @@
<template>
<el-container style="min-height: 100vh; width: 100%">
<!-- 左侧导航 -->
<el-aside :width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246); box-shadow: 2px 0 6px rgb(0 21 41 / 35%)">
<Aside :isCollapse="isCollapse" :logoTextShow="logoTextShow" />
</el-aside>
<!-- 右侧内容 -->
<el-container style="width: calc(100% - 200px);"> <!-- Adjust width based on aside -->
<!-- 顶部导航 -->
<el-header style="border-bottom: 1px solid #ccc;">
<Header :collapseBtnClass="collapseBtnClass" :collapse="collapse" />
</el-header>
<el-main style="padding: 20px;">
<el-row>
<!-- 搜索框 -->
<el-col :span="8">
<el-input
v-model="searchQuery.name"
placeholder="请输入试卷名称"
clearable
@input="fetchScores"
style="width: 100%; margin-bottom: 20px;"
/>
</el-col>
<el-col :span="8">
<el-input
v-model="searchQuery.testID"
placeholder="请输入试卷ID"
clearable
@input="fetchScores"
style="width: 100%; margin-bottom: 20px;"
/>
</el-col>
</el-row>
<!-- 试卷成绩列表 -->
<el-table :data="papers" style="width: 100%" border>
<el-table-column prop="testid" label="试卷ID" width="100" />
<el-table-column prop="senderName" label="学生姓名" width="150" />
<el-table-column prop="examName" label="试卷名称" width="150" />
<el-table-column prop="grade" label="年级" width="100" />
<el-table-column prop="class1" label="班级" width="100" />
<el-table-column prop="score" label="得分" width="180" />
<el-table-column prop="ranking" label="排名" width="180" />
<!-- 状态列已发布为绿色未发布为红色 -->
<el-table-column label="状态" width="160">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
{{ scope.row.status === 1 ? '已发布' : '未发布' }}
</el-tag>
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-button type="primary" size="small" @click="viewDetail(scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="pageNum"
:page-size="pageSize"
:total="total"
@current-change="handlePageChange"
layout="total, prev, pager, next, jumper"
style="text-align: right; margin-top: 20px;"
/>
</el-main>
<div>
<el-container style="min-height: 100vh; width: 100%">
<!-- Left sidebar -->
<el-aside :width="sideWidth + 'px'" style="background-color: #f4f7fc; box-shadow: 2px 0 6px rgba(0, 21, 41, 0.15)">
<Aside :isCollapse="isCollapse" :logoTextShow="logoTextShow" />
</el-aside>
<!-- Main content -->
<el-container style="width: calc(100% - 200px);">
<el-header style="border-bottom: 1px solid #e1e4ea; padding: 10px 20px; background: #fff;">
<Header :collapseBtnClass="collapseBtnClass" :collapse="collapse" />
</el-header>
<el-main style="padding: 20px;">
<!-- Search bar -->
<el-row gutter={20} style="margin-bottom: 20px;">
<el-col :span="12">
<el-input
v-model="searchQuery.name"
placeholder="请输入试卷名称"
clearable
@input="fetchScores"
style="width: 100%; border-radius: 5px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"
/>
</el-col>
<el-col :span="12">
<el-input
v-model="searchQuery.testID"
placeholder="请输入试卷ID"
clearable
@input="fetchScores"
style="width: 100%; border-radius: 5px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"
/>
</el-col>
</el-row>
<!-- Exam papers table -->
<el-table :data="papers" style="width: 100%" border>
<el-table-column prop="id" label="试卷ID" width="100" />
<el-table-column prop="name" label="试卷名称" width="200" />
<el-table-column prop="subject" label="学科" width="150" />
<el-table-column prop="grade" label="年级" width="100" />
<el-table-column prop="class1" label="班级" width="100" />
<el-table-column label="完成人数" width="200">
<template slot-scope="scope">
<span>{{ scope.row.completedCount }} / {{ scope.row.totalCount }}</span>
</template>
</el-table-column>
<el-table-column label="成绩分布" width="160">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'" style="border-radius: 5px; font-size: 14px;">
{{ scope.row.status === 1 ? '已发布' : '未发布' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="320">
<template slot-scope="scope">
<div style="display: flex; width: 100%; gap: 10px;">
<el-button
type="primary"
size="small"
style="flex: 1; border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"
@click="openRankingDetail(scope.row.id, scope.row.grade, scope.row.class1)">
查看排名
</el-button>
<el-button
type="primary"
size="small"
style="flex: 1; border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"
@click="publishExam(scope.row.id,scope.row.grade, scope.row.class1)">
发布
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!-- Pagination -->
<el-pagination
:current-page="pageNum"
:page-size="pageSize"
:total="total"
@current-change="handlePageChange"
layout="total, prev, pager, next, jumper"
style="text-align: right; margin-top: 20px; border-top: 1px solid #e1e4ea; padding-top: 10px;"
/>
</el-main>
</el-container>
</el-container>
</el-container>
<!-- Ranking detail dialog -->
<el-dialog :visible.sync="rankingDialogVisible" title="排名详情" width="50%">
<p>试卷ID: {{ selectedTestId }}</p>
<el-table :data="rankingDetails" style="width: 100%" border>
<el-table-column prop="ranking" label="排名" width="100" />
<el-table-column prop="senderName" label="学生姓名" width="150" />
<el-table-column prop="score" label="得分" width="150" />
<el-table-column label="操作" width="250">
<template slot-scope="scope">
<el-button
type="primary"
size="small"
style="border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"
@click="viewDetails(scope.row)"
>
详细
</el-button>
</template>
</el-table-column>
</el-table>
<!-- Footer buttons -->
<span slot="footer" class="dialog-footer" style="display: flex; justify-content: flex-end;">
<el-button @click="rankingDialogVisible = false" style="border-radius: 4px;">
关闭
</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
@ -98,6 +148,9 @@ export default {
pageNum: 1, //
pageSize: 10, //
total: 0, //
rankingDialogVisible: false, //
selectedTestId: null, // ID
rankingDetails: [], //
};
},
created() {
@ -107,16 +160,11 @@ export default {
methods: {
collapse() {
this.isCollapse = !this.isCollapse;
if (this.isCollapse) {
this.sideWidth = 64;
this.collapseBtnClass = "el-icon-s-unfold";
this.logoTextShow = false;
} else {
this.sideWidth = 200;
this.collapseBtnClass = "el-icon-s-fold";
this.logoTextShow = true;
}
this.sideWidth = this.isCollapse ? 64 : 200;
this.collapseBtnClass = this.isCollapse ? "el-icon-s-unfold" : "el-icon-s-fold";
this.logoTextShow = !this.isCollapse;
},
//
async fetchScores() {
try {
@ -127,26 +175,22 @@ export default {
return;
}
const response = await axios.get(
"http://localhost:8080/teacher/answerSheet/selectScoreList", //
{
params: {
pageNum: this.pageNum, //
pageSize: this.pageSize, //
name: this.searchQuery.name, //
testID: this.searchQuery.testID, //
},
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const response = await axios.get("http://localhost:8080/teacher/answerSheet/getExamPaperList", {
params: {
pageNum: this.pageNum,
pageSize: this.pageSize,
},
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log("responser",response);
if (response.data.code === 200) {
console.log(response.data);
// papers
this.papers = response.data.data.records || [];
this.total = response.data.data.total || 0; //
this.pageNum = response.data.data.current || 1; //
//
const allPapers = response.data.data.records || [];
this.papers = this.filterPapers(allPapers); //
this.total = response.data.data.total || 0;
this.pageNum = response.data.data.current || 1;
} else {
this.$message.error("查询异常!");
}
@ -155,29 +199,98 @@ export default {
}
},
//
viewDetail(paper) {
this.$router.push({
path: "/teacher/paper/detail",
query: {
testID: paper.testid, //
name: paper.examName,
},
//
filterPapers(papers) {
return papers.filter(paper => {
// ID
const matchesName = this.searchQuery.name
? paper.name.includes(this.searchQuery.name)
: true;
const matchesTestID = this.searchQuery.testID
? paper.id.toString().includes(this.searchQuery.testID)
: true;
return matchesName && matchesTestID;
});
},
//
//
openRankingDetail(testId,grade,class1) {
this.selectedTestId = testId; // Set the selectedTestId to the row's testId
this.fetchRankingDetails(testId,grade,class1); // Fetch ranking details for the selected test
this.rankingDialogVisible = true; // Show the ranking details dialog
},
//
async fetchRankingDetails(testId,grade,class1) {
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push("/login");
return;
}
console.log('grade',grade);
// 使 testId
const response = await axios.get(`http://localhost:8080/teacher/answerSheet/selectScoreList`, {
params: { testid: testId, grade: grade, Class1: class1}, // testId
headers: { Authorization: `Bearer ${token}` }, // token
});
console.log("response",response);
//
if (response.data.code === 200) {
//
this.rankingDetails = response.data.data || [];
} else {
//
this.$message.error("查询排名详情失败!");
}
} catch (error) {
console.error("获取排名详情失败", error);
this.$message.error("获取排名详情失败");
}
},
//
async publishExam(testId, grade, class1) {
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push("/login");
return;
}
const response = await axios.put(`http://localhost:8080/teacher/answerSheet/fabu`, { testid: testId }, {
params: { testid: testId, grade: grade, Class1: class1},
headers: { Authorization: `Bearer ${token}` },
});
console.log("response",response);
if (response.data.code === 200) {
this.fetchScores(); //
this.$message.success("发布成功!");
} else {
this.$message.error("发布失败!");
}
} catch (error) {
console.error("发布试卷失败", error);
}
},
//
handlePageChange(pageNum) {
this.pageNum = pageNum;
this.fetchScores(); //
this.fetchScores();
},
},
};
</script>
<style scoped lang="scss">
/* 你可以在这里加入你的样式 */
.el-container {
margin: 0;
padding: 0;
@ -187,5 +300,56 @@ export default {
.el-main {
padding: 20px;
background-color: #f9f9f9;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.el-header {
background-color: #fff;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
.el-table th {
background-color: #f5f7fa;
color: #333;
font-weight: 500;
}
.el-table-row:hover {
background-color: #f2f8ff;
}
.el-button {
transition: background-color 0.3s ease, box-shadow 0.3s ease;
}
.el-button:hover {
background-color: #409eff;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
.el-input {
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.el-pagination {
margin-top: 10px;
}
.el-dialog {
background-color: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.el-dialog .el-button {
border-radius: 4px;
}
.el-tag {
font-size: 14px;
}
</style>

@ -0,0 +1,227 @@
<template>
<el-container style="min-height: 100vh; width: 100%">
<!-- Left sidebar -->
<el-aside :width="sideWidth + 'px'" style="background-color: #f4f7fc; box-shadow: 2px 0 6px rgba(0, 21, 41, 0.15)">
<Aside :isCollapse="isCollapse" :logoTextShow="logoTextShow" />
</el-aside>
<!-- Main content -->
<el-container style="width: calc(100% - 200px);">
<el-header style="border-bottom: 1px solid #e1e4ea; padding: 10px 20px; background: #fff;">
<Header :collapseBtnClass="collapseBtnClass" :collapse="collapse" />
</el-header>
<el-main style="padding: 20px;">
<!-- 搜索框 -->
<el-input
v-model="searchQuery"
placeholder="请输入试卷名称进行搜索"
suffix-icon="el-icon-search"
style="width: 300px; margin-left: auto;"
/>
<!-- 试卷列表 -->
<el-table :data="filteredExams" style="width: 100%">
<el-table-column prop="id" label="ID" width="100"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="subject" label="学科"></el-table-column>
<el-table-column prop="type" label="类型"></el-table-column>
<el-table-column label="操作" width="180">
<template slot-scope="scope">
<el-button @click="openDistributionDialog(scope.row)" type="primary" size="small">发布情况</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="currentPage"
:page-size="pageSize"
:total="totalExams"
@current-change="handlePageChange"
layout="total, prev, pager, next, jumper"
/>
<!-- 分发弹窗 -->
<el-dialog :visible.sync="isDistributionDialogVisible" title="分发试卷">
<el-table :data="classList" style="width: 100%">
<el-table-column prop="grade" label="年级"></el-table-column>
<el-table-column prop="class1" label="班级"></el-table-column>
<el-table-column label="状态" width="180">
<template slot-scope="scope">
<el-tag :type="scope.row.release === 1 ? 'success' : 'danger'" style="border-radius: 5px; font-size: 14px;">
{{ scope.row.release === 1 ? '已发布' : '未发布' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template slot-scope="scope">
<el-button @click="distributeExam(selectedExam.id,scope.row)" type="success" size="small">发布</el-button>
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="isDistributionDialogVisible = false">取消</el-button>
</span>
</el-dialog>
</el-main>
</el-container>
</el-container>
</template>
<script>
import Header from "@/components/Teacher/Header.vue";
import Aside from "@/components/Teacher/Aside.vue";
import axios from "axios"; // axios API
export default {
name: "TeacherExam",
components: { Aside, Header },
data() {
return {
collapseBtnClass: "el-icon-s-fold",
isCollapse: false,
sideWidth: 200,
logoTextShow: true,
exams: [], //
classList: [], //
selectedExam: null, //
isDistributionDialogVisible: false, //
searchQuery: "", //
currentPage: 1, //
pageSize: 10, //
totalExams: 0, //
};
},
computed: {
//
filteredExams() {
if (this.searchQuery) {
return this.exams.filter((exam) =>
exam.name.toLowerCase().includes(this.searchQuery.toLowerCase()) //
);
}
return this.exams; //
},
},
methods: {
collapse() {
this.isCollapse = !this.isCollapse;
this.sideWidth = this.isCollapse ? 64 : 200;
this.collapseBtnClass = this.isCollapse ? "el-icon-s-unfold" : "el-icon-s-fold";
this.logoTextShow = !this.isCollapse;
},
//
openDistributionDialog(exam) {
this.selectedExam = exam;
this.fetchClassList(exam.id);
this.isDistributionDialogVisible = true;
},
//
async fetchClassList(testid) {
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/examPaper/selectClassRelease",{
params:{testid:testid},
headers:{Authorization:`Bearer ${token}`}
});
if(response.data.code===200){
this.classList = response.data.data;
}
}catch (error){
alert("用户未登录,请重新登录!");
this.$router.push("/login");
return;
}
},
//
updateStatus(classInfo) {
console.log("更新状态:", classInfo.className, "为", classInfo.status);
},
//
async distributeExam(testid,classInfo) {
try {
const token = this.$store.state.tokens[this.userId];
if (!token) {
alert("用户未登录,请重新登录!");
this.$router.push("/login");
return;
}
console.log("class1",classInfo.class1);
const response = await axios.post("http://localhost:8080/teacher/examPaper/addExamPaper", {
id: testid, //
grade: classInfo.grade,
class1: classInfo.class1
}, {
headers: { Authorization: `Bearer ${token}` }
});
console.log("response",response);
if(response.data.code===200){
this.$message.success("分发成功!");
this.fetchClassList(testid);
}else{
this.$message.error("分发失败!");
}
}catch (error){
console.log("数据异常"+error);
}
},
//
async fetchExams() {
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/examPaper/getExamPaper",{
params: {
pageNum: this.currentPage,
pageSize: this.pageSize,
},
headers: {
Authorization: `Bearer ${token}`,
}
});
if(response.data.code===200){
this.exams = response.data.data.records;
}else{
this.$message.error("获取数据异常");
}
}catch(error) {
console.error("获取试卷列表失败:", error);
}
},
//
handlePageChange(page) {
this.currentPage = page;
this.fetchExams(); //
},
},
created() {
this.userId = this.$route.query.userId;
this.fetchExams(); //
},
};
</script>
<style scoped lang="scss">
.el-table {
margin-top: 20px;
}
</style>

@ -20,12 +20,6 @@
<span>个人信息</span>
</div>
<div class="text-center">
<el-avatar
:src="user.avatar || defaultAvatar"
size="large"
class="user-avatar"
shape="circle"
/>
</div>
<ul class="profile-info">
<li>
@ -60,6 +54,10 @@
<svg-icon icon-class="user-tie" /> 辅导员
<div class="info-value">{{ user.teacherName || "暂无数据" }}</div>
</li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</el-card>
</el-col>

Loading…
Cancel
Save