diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index c8b1f76..383a244 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -10,4 +10,9 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 6c0b863..94a25f7 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/backend/src/main/java/lsgwr/exam/service/impl/ExamServiceImpl.java b/backend/src/main/java/lsgwr/exam/service/impl/ExamServiceImpl.java
index 9dd9a7e..ab40ce9 100644
--- a/backend/src/main/java/lsgwr/exam/service/impl/ExamServiceImpl.java
+++ b/backend/src/main/java/lsgwr/exam/service/impl/ExamServiceImpl.java
@@ -1,685 +1,13 @@
-/***********************************************************
- * @Description : 考试服务接口实现
- * @author : 梁山广(Laing Shan Guang)
- * @date : 2019-05-28 08:06
- * @email : liangshanguang2@gmail.com
- ***********************************************************/
-package lsgwr.exam.service.impl;
-
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
-import lsgwr.exam.entity.*;
-import lsgwr.exam.enums.QuestionEnum;
-import lsgwr.exam.service.ExamService;
-import lsgwr.exam.repository.*;
-import lsgwr.exam.vo.*;
-import org.springframework.beans.BeanUtils;
-import org.springframework.stereotype.Service;
-
-import javax.transaction.Transactional;
-import java.util.*;
-
-@Service
-@Transactional
-public class ExamServiceImpl implements ExamService {
-
- // 定义一个ExamRepository类型的私有变量
- private final ExamRepository examRepository;
-
- // 定义一个ExamRecordRepository类型的私有变量
- private final ExamRecordRepository examRecordRepository;
-
- // 定义一个QuestionRepository类型的私有变量
- private final QuestionRepository questionRepository;
-
- // 定义一个UserRepository类型的私有变量
- private final UserRepository userRepository;
-
- // 定义一个QuestionLevelRepository类型的私有变量
- private final QuestionLevelRepository questionLevelRepository;
-
- // 定义一个QuestionTypeRepository类型的私有变量
- private final QuestionTypeRepository questionTypeRepository;
-
- // 定义一个QuestionCategoryRepository类型的私有变量
- private final QuestionCategoryRepository questionCategoryRepository;
-
- // 定义一个QuestionOptionRepository类型的私有变量
- private final QuestionOptionRepository questionOptionRepository;
-
- // 构造函数,传入多个Repository类型的参数
- public ExamServiceImpl(QuestionRepository questionRepository, UserRepository userRepository, QuestionLevelRepository questionLevelRepository, QuestionTypeRepository questionTypeRepository, QuestionCategoryRepository questionCategoryRepository, QuestionOptionRepository questionOptionRepository, ExamRepository examRepository, ExamRecordRepository examRecordRepository) {
- this.questionRepository = questionRepository;
- this.userRepository = userRepository;
- this.questionLevelRepository = questionLevelRepository;
- this.questionTypeRepository = questionTypeRepository;
- this.questionCategoryRepository = questionCategoryRepository;
- this.questionOptionRepository = questionOptionRepository;
- this.examRepository = examRepository;
- this.examRecordRepository = examRecordRepository;
- }
-
- @Override
- public List getQuestionAll() {
- List questionList = questionRepository.findAll();
- return getQuestionVos(questionList);
- }
-
- private List getQuestionVos(List questionList) {
- // 需要自定义的question列表
- List questionVoList = new ArrayList<>();
- // 循环完成每个属性的定制
- for (Question question : questionList) {
- QuestionVo questionVo = getQuestionVo(question);
- questionVoList.add(questionVo);
- }
- return questionVoList;
- }
-
- // 根据传入的Question对象,返回一个QuestionVo对象
- private QuestionVo getQuestionVo(Question question) {
- // 创建一个新的QuestionVo对象
- QuestionVo questionVo = new QuestionVo();
- // 先复制能复制的属性
- BeanUtils.copyProperties(question, questionVo);
- // 设置问题的创建者
- questionVo.setQuestionCreator(
- Objects.requireNonNull(
- userRepository.findById(
- question.getQuestionCreatorId()
- ).orElse(null)
- ).getUserUsername());
-
- // 设置问题的难度
- questionVo.setQuestionLevel(
- Objects.requireNonNull(
- questionLevelRepository.findById(
- question.getQuestionLevelId()
- ).orElse(null)
- ).getQuestionLevelDescription());
-
- // 设置题目的类别,比如单选、多选、判断等
- questionVo.setQuestionType(
- Objects.requireNonNull(
- questionTypeRepository.findById(
- question.getQuestionTypeId()
- ).orElse(null)
- ).getQuestionTypeDescription());
-
- // 设置题目分类,比如数学、语文、英语、生活、人文等
- questionVo.setQuestionCategory(
- Objects.requireNonNull(
- questionCategoryRepository.findById(
- question.getQuestionCategoryId()
- ).orElse(null)
- ).getQuestionCategoryName()
- );
-
- // 选项的自定义Vo列表
- List optionVoList = new ArrayList<>();
-
- // 获得所有的选项列表
- List optionList = questionOptionRepository.findAllById(
- Arrays.asList(question.getQuestionOptionIds().split("-"))
- );
-
- // 获取所有的答案列表optionList中每个option的isAnswer选项
- List answerList = questionOptionRepository.findAllById(
- Arrays.asList(question.getQuestionAnswerOptionIds().split("-"))
- );
-
- // 根据选项和答案的id相同设置optionVo的isAnswer属性
- for (QuestionOption option : optionList) {
- QuestionOptionVo optionVo = new QuestionOptionVo();
- BeanUtils.copyProperties(option, optionVo);
- for (QuestionOption answer : answerList) {
- if (option.getQuestionOptionId().equals(answer.getQuestionOptionId())) {
- optionVo.setAnswer(true);
- }
- }
- optionVoList.add(optionVo);
- }
-
- // 设置题目的所有选项
- questionVo.setQuestionOptionVoList(optionVoList);
- return questionVo;
- }
-
- @Override
- public QuestionVo updateQuestion(QuestionVo questionVo) {
- // 1.把需要的属性都设置好
- StringBuilder questionAnswerOptionIds = new StringBuilder();
- List questionOptionList = new ArrayList<>();
- List questionOptionVoList = questionVo.getQuestionOptionVoList();
- int size = questionOptionVoList.size();
- for (int i = 0; i < questionOptionVoList.size(); i++) {
- QuestionOptionVo questionOptionVo = questionOptionVoList.get(i);
- QuestionOption questionOption = new QuestionOption();
- BeanUtils.copyProperties(questionOptionVo, questionOption);
- questionOptionList.add(questionOption);
- if (questionOptionVo.getAnswer()) {
- if (i != size - 1) {
- // 把更新后的答案的id加上去,记得用-连到一起
- questionAnswerOptionIds.append(questionOptionVo.getQuestionOptionId()).append("-");
- } else {
- // 最后一个不需要用-连接
- questionAnswerOptionIds.append(questionOptionVo.getQuestionOptionId());
- }
- }
- }
-
- // 1.更新问题
- Question question = questionRepository.findById(questionVo.getQuestionId()).orElse(null);
- assert question != null;
- BeanUtils.copyProperties(questionVo, question);
- question.setQuestionAnswerOptionIds(questionAnswerOptionIds.toString());
- questionRepository.save(question);
-
- // 2.更新所有的option
- questionOptionRepository.saveAll(questionOptionList);
-
- // 返回更新后的问题,方便前端局部刷新
- return getQuestionVo(question);
- }
-
- @Override
- public void questionCreate(QuestionCreateVo questionCreateVo) {
- // 问题创建
- Question question = new Question();
- // 把能复制的属性都复制过来
- BeanUtils.copyProperties(questionCreateVo, question);
- // 设置下questionOptionIds和questionAnswerOptionIds,需要自己用Hutool生成下
- List questionOptionList = new ArrayList<>();
- List questionOptionCreateVoList = questionCreateVo.getQuestionOptionCreateVoList();
- for (QuestionOptionCreateVo questionOptionCreateVo : questionOptionCreateVoList) {
- QuestionOption questionOption = new QuestionOption();
- // 设置选项的的内容
- questionOption.setQuestionOptionContent(questionOptionCreateVo.getQuestionOptionContent());
- // 设置选项的id
- questionOption.setQuestionOptionId(IdUtil.simpleUUID());
- questionOptionList.add(questionOption);
- }
- // 把选项都存起来,然后才能用于下面设置Question的questionOptionIds和questionAnswerOptionIds
- questionOptionRepository.saveAll(questionOptionList);
- String questionOptionIds = "";
- String questionAnswerOptionIds = "";
- // 经过上面的saveAll方法,所有的option的主键id都已经持久化了
- for (int i = 0; i < questionOptionCreateVoList.size(); i++) {
- // 获取指定选项
- QuestionOptionCreateVo questionOptionCreateVo = questionOptionCreateVoList.get(i);
- // 获取保存后的指定对象
- QuestionOption questionOption = questionOptionList.get(i);
- questionOptionIds += questionOption.getQuestionOptionId() + "-";
- if (questionOptionCreateVo.getAnswer()) {
- // 如果是答案的话
- questionAnswerOptionIds += questionOption.getQuestionOptionId() + "-";
- }
- }
- // 把字符串最后面的"-"给去掉
- questionAnswerOptionIds = replaceLastSeparator(questionAnswerOptionIds);
- questionOptionIds = replaceLastSeparator(questionOptionIds);
- // 设置选项id组成的字符串
- question.setQuestionOptionIds(questionOptionIds);
- // 设置答案选项id组成的字符串
- question.setQuestionAnswerOptionIds(questionAnswerOptionIds);
- // 自己生成问题的id
- question.setQuestionId(IdUtil.simpleUUID());
- // 先把创建时间和更新时间每次都取当前时间吧
- question.setCreateTime(new Date());
- question.setUpdateTime(new Date());
- // 保存问题到数据库
- questionRepository.save(question);
- }
-
- @Override
- public QuestionSelectionVo getSelections() {
- QuestionSelectionVo questionSelectionVo = new QuestionSelectionVo();
- questionSelectionVo.setQuestionCategoryList(questionCategoryRepository.findAll());
- questionSelectionVo.setQuestionLevelList(questionLevelRepository.findAll());
- questionSelectionVo.setQuestionTypeList(questionTypeRepository.findAll());
-
- return questionSelectionVo;
- }
-
- /**
- * 去除字符串最后的,防止split的时候出错
- *
- * @param str 原始字符串
- * @return
- */
- public static String trimMiddleLine(String str) {
- if (str.charAt(str.length() - 1) == '-') {
- str = str.substring(0, str.length() - 1);
- }
- return str;
- }
-
- @Override
- public QuestionDetailVo getQuestionDetail(String id) {
- Question question = questionRepository.findById(id).orElse(null);
- QuestionDetailVo questionDetailVo = new QuestionDetailVo();
- questionDetailVo.setId(id);
- questionDetailVo.setName(question.getQuestionName());
- questionDetailVo.setDescription(question.getQuestionDescription());
- // 问题类型,单选题/多选题/判断题
- questionDetailVo.setType(
- Objects.requireNonNull(
- questionTypeRepository.findById(
- question.getQuestionTypeId()
- ).orElse(null)
- ).getQuestionTypeDescription()
- );
- // 获取当前问题的选项
- String optionIdsStr = trimMiddleLine(question.getQuestionOptionIds());
- String[] optionIds = optionIdsStr.split("-");
- // 获取选项列表
- List optionList = questionOptionRepository.findAllById(Arrays.asList(optionIds));
- questionDetailVo.setOptions(optionList);
- return questionDetailVo;
- }
-
- @Override
- public List getExamAll() {
- List examList = examRepository.findAll();
- return getExamVos(examList);
- }
-
- private List getExamVos(List examList) {
- // 需要自定义的exam列表
- List examVoList = new ArrayList<>();
- // 循环完成每个属性的定制
- for (Exam exam : examList) {
- ExamVo examVo = new ExamVo();
- // 先尽量复制能复制的所有属性
- BeanUtils.copyProperties(exam, examVo);
- // 设置问题的创建者
- examVo.setExamCreator(
- Objects.requireNonNull(
- userRepository.findById(
- exam.getExamCreatorId()
- ).orElse(null)
- ).getUserUsername()
- );
-
- // 获取所有单选题列表,并赋值到ExamVo的属性ExamQuestionSelectVoRadioList上
- List radioQuestionVoList = new ArrayList<>();
- List radioQuestionList = questionRepository.findAllById(
- Arrays.asList(exam.getExamQuestionIdsRadio().split("-"))
- );
- for (Question question : radioQuestionList) {
- ExamQuestionSelectVo radioQuestionVo = new ExamQuestionSelectVo();
- BeanUtils.copyProperties(question, radioQuestionVo);
- radioQuestionVo.setChecked(true); // 考试中的问题肯定被选中的
- radioQuestionVoList.add(radioQuestionVo);
- }
- examVo.setExamQuestionSelectVoRadioList(radioQuestionVoList);
-
- // 获取所有多选题列表,并赋值到ExamVo的属性ExamQuestionSelectVoCheckList上
- List checkQuestionVoList = new ArrayList<>();
- List checkQuestionList = questionRepository.findAllById(
- Arrays.asList(exam.getExamQuestionIdsCheck().split("-"))
- );
- for (Question question : checkQuestionList) {
- ExamQuestionSelectVo checkQuestionVo = new ExamQuestionSelectVo();
- BeanUtils.copyProperties(question, checkQuestionVo);
- checkQuestionVo.setChecked(true); // 考试中的问题肯定被选中的
- checkQuestionVoList.add(checkQuestionVo);
- }
- examVo.setExamQuestionSelectVoCheckList(checkQuestionVoList);
-
- // 获取所有多选题列表,并赋值到ExamVo的属性ExamQuestionSelectVoJudgeList上
- List judgeQuestionVoList = new ArrayList<>();
- List judgeQuestionList = questionRepository.findAllById(
- Arrays.asList(exam.getExamQuestionIdsJudge().split("-"))
- );
- for (Question question : judgeQuestionList) {
- ExamQuestionSelectVo judgeQuestionVo = new ExamQuestionSelectVo();
- BeanUtils.copyProperties(question, judgeQuestionVo);
- judgeQuestionVo.setChecked(true); // 考试中的问题肯定被选中的
- judgeQuestionVoList.add(judgeQuestionVo);
- }
- examVo.setExamQuestionSelectVoJudgeList(judgeQuestionVoList);
-
- // 把examVo加到examVoList中
- examVoList.add(examVo);
- }
- return examVoList;
- }
-
-
-
- @Override
- public ExamQuestionTypeVo getExamQuestionType() {
- ExamQuestionTypeVo examQuestionTypeVo = new ExamQuestionTypeVo();
- // 获取所有单选题列表,并赋值到ExamVo的属性ExamQuestionSelectVoRadioList上
- List radioQuestionVoList = new ArrayList<>();
- List radioQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.RADIO.getId());
- for (Question question : radioQuestionList) {
- ExamQuestionSelectVo radioQuestionVo = new ExamQuestionSelectVo();
- BeanUtils.copyProperties(question, radioQuestionVo);
- radioQuestionVoList.add(radioQuestionVo);
- }
- examQuestionTypeVo.setExamQuestionSelectVoRadioList(radioQuestionVoList);
-
- // 获取所有多选题列表,并赋值到ExamVo的属性ExamQuestionSelectVoCheckList上
- List checkQuestionVoList = new ArrayList<>();
- List checkQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.CHECK.getId());
- for (Question question : checkQuestionList) {
- ExamQuestionSelectVo checkQuestionVo = new ExamQuestionSelectVo();
- BeanUtils.copyProperties(question, checkQuestionVo);
- checkQuestionVoList.add(checkQuestionVo);
- }
- examQuestionTypeVo.setExamQuestionSelectVoCheckList(checkQuestionVoList);
-
- // 获取所有多选题列表,并赋值到ExamVo的属性ExamQuestionSelectVoJudgeList上
- List judgeQuestionVoList = new ArrayList<>();
- List judgeQuestionList = questionRepository.findByQuestionTypeId(QuestionEnum.JUDGE.getId());
- for (Question question : judgeQuestionList) {
- ExamQuestionSelectVo judgeQuestionVo = new ExamQuestionSelectVo();
- BeanUtils.copyProperties(question, judgeQuestionVo);
- judgeQuestionVoList.add(judgeQuestionVo);
- }
- examQuestionTypeVo.setExamQuestionSelectVoJudgeList(judgeQuestionVoList);
- return examQuestionTypeVo;
- }
-
- @Override
- public Exam create(ExamCreateVo examCreateVo, String userId) {
- // 在线考试系统创建
- Exam exam = new Exam();
- BeanUtils.copyProperties(examCreateVo, exam);
- exam.setExamId(IdUtil.simpleUUID());
- exam.setExamCreatorId(userId);
- exam.setCreateTime(new Date());
- exam.setUpdateTime(new Date());
- // Todo:这两个日志后面是要在前端传入的,这里暂时定为当前日期
- exam.setExamStartDate(new Date());
- exam.setExamEndDate(new Date());
- String radioIdsStr = "";
- String checkIdsStr = "";
- String judgeIdsStr = "";
- List radios = examCreateVo.getRadios();
- List checks = examCreateVo.getChecks();
- List judges = examCreateVo.getJudges();
- int radioCnt = 0, checkCnt = 0, judgeCnt = 0;
- for (ExamQuestionSelectVo radio : radios) {
- if (radio.getChecked()) {
- radioIdsStr += radio.getQuestionId() + "-";
- radioCnt++;
- }
- }
- radioIdsStr = replaceLastSeparator(radioIdsStr);
- for (ExamQuestionSelectVo check : checks) {
- if (check.getChecked()) {
- checkIdsStr += check.getQuestionId() + "-";
- checkCnt++;
- }
- }
- checkIdsStr = replaceLastSeparator(checkIdsStr);
- for (ExamQuestionSelectVo judge : judges) {
- if (judge.getChecked()) {
- judgeIdsStr += judge.getQuestionId() + "-";
- judgeCnt++;
- }
- }
- judgeIdsStr = replaceLastSeparator(judgeIdsStr);
- exam.setExamQuestionIds(radioIdsStr + "-" + checkIdsStr + "-" + judgeIdsStr);
- // 设置各个题目的id
- exam.setExamQuestionIdsRadio(radioIdsStr);
- exam.setExamQuestionIdsCheck(checkIdsStr);
- exam.setExamQuestionIdsJudge(judgeIdsStr);
-
- // 计算总分数
- int examScore = radioCnt * exam.getExamScoreRadio() + checkCnt * exam.getExamScoreCheck() + judgeCnt * exam.getExamScoreJudge();
- exam.setExamScore(examScore);
- examRepository.save(exam);
- return exam;
- }
-
- @Override
- public Exam update(ExamVo examVo, String userId) {
- Exam exam = new Exam();
- BeanUtils.copyProperties(examVo, exam);
- exam.setExamCreatorId(userId); // 考试的更新人为最新的创建人
- exam.setUpdateTime(new Date()); // 考试的更新日期要记录下
-
- String radioIdsStr = "";
- String checkIdsStr = "";
- String judgeIdsStr = "";
- List radios = examVo.getExamQuestionSelectVoRadioList();
- List checks = examVo.getExamQuestionSelectVoCheckList();
- List judges = examVo.getExamQuestionSelectVoJudgeList();
- int radioCnt = 0, checkCnt = 0, judgeCnt = 0;
- for (ExamQuestionSelectVo radio : radios) {
- if (radio.getChecked()) {
- radioIdsStr += radio.getQuestionId() + "-";
- radioCnt++;
- }
- }
- radioIdsStr = replaceLastSeparator(radioIdsStr);
- for (ExamQuestionSelectVo check : checks) {
- if (check.getChecked()) {
- checkIdsStr += check.getQuestionId() + "-";
- checkCnt++;
- }
- }
- checkIdsStr = replaceLastSeparator(checkIdsStr);
- for (ExamQuestionSelectVo judge : judges) {
- if (judge.getChecked()) {
- judgeIdsStr += judge.getQuestionId() + "-";
- judgeCnt++;
- }
- }
- judgeIdsStr = replaceLastSeparator(judgeIdsStr);
- exam.setExamQuestionIds(radioIdsStr + "-" + checkIdsStr + "-" + judgeIdsStr);
- // 设置各个题目的id
- exam.setExamQuestionIdsRadio(radioIdsStr);
- exam.setExamQuestionIdsCheck(checkIdsStr);
- exam.setExamQuestionIdsJudge(judgeIdsStr);
-
- // 计算总分数
- int examScore = radioCnt * exam.getExamScoreRadio() + checkCnt * exam.getExamScoreCheck() + judgeCnt * exam.getExamScoreJudge();
- exam.setExamScore(examScore);
- examRepository.save(exam);
- return exam;
- }
-
- @Override
- public List getExamCardList() {
- List examList = examRepository.findAll();
- List examCardVoList = new ArrayList<>();
- for (Exam exam : examList) {
- ExamCardVo examCardVo = new ExamCardVo();
- BeanUtils.copyProperties(exam, examCardVo);
- examCardVoList.add(examCardVo);
- }
- return examCardVoList;
- }
-
- @Override
- public ExamDetailVo getExamDetail(String id) {
- Exam exam = examRepository.findById(id).orElse(null);
- ExamDetailVo examDetailVo = new ExamDetailVo();
- examDetailVo.setExam(exam);
- assert exam != null;
- examDetailVo.setRadioIds(exam.getExamQuestionIdsRadio().split("-"));
- examDetailVo.setCheckIds(exam.getExamQuestionIdsCheck().split("-"));
- examDetailVo.setJudgeIds(exam.getExamQuestionIdsJudge().split("-"));
- return examDetailVo;
- }
-
- @Override
- public ExamRecord judge(String userId, String examId, HashMap> answersMap) {
- // 开始考试判分啦~~~
- // 1.首先获取考试对象和选项数组
- ExamDetailVo examDetailVo = getExamDetail(examId);
- Exam exam = examDetailVo.getExam();
- // 2.然后获取该考试下所有的题目信息
- List questionIds = new ArrayList<>();
- // 2.1 题目id的数组
- List radioIdList = Arrays.asList(examDetailVo.getRadioIds());
- List checkIdList = Arrays.asList(examDetailVo.getCheckIds());
- List judgeIdList = Arrays.asList(examDetailVo.getJudgeIds());
- questionIds.addAll(radioIdList);
- questionIds.addAll(checkIdList);
- questionIds.addAll(judgeIdList);
- // 2.2 每种题目的分数
- int radioScore = exam.getExamScoreRadio();
- int checkScore = exam.getExamScoreCheck();
- int judgeScore = exam.getExamScoreJudge();
- // 2.3 根据问题id的数组拿到所有的问题对象,供下面步骤用
- List questionList = questionRepository.findAllById(questionIds);
- Map questionMap = new HashMap<>();
- for (Question question : questionList) {
- questionMap.put(question.getQuestionId(), question);
- }
- // 3.根据正确答案和用户作答信息进行判分
- Set questionIdsAnswer = answersMap.keySet();
- // 存储当前考试每个题目的得分情况
- Map judgeMap = new HashMap<>();
- // 考生作答地每个题目的选项(题目和题目之间用$分隔,题目有多个选项地话用-分隔,题目和选项之间用_分隔),用于查看考试详情
- // 例子:题目1的id_作答选项1-作答选项2&题目2的id_作答选项1&题目3_作答选项1-作答选项2-作答选项3
- StringBuilder answerOptionIdsSb = new StringBuilder();
- // 用户此次考试的总分
- int totalScore = 0;
- for (String questionId : questionIdsAnswer) {
- // 获取用户作答地这个题的答案信息
- Question question = questionMap.get(questionId);
- // 获取答案选项
- String questionAnswerOptionIds = replaceLastSeparator(question.getQuestionAnswerOptionIds());
- List questionAnswerOptionIdList = Arrays.asList(questionAnswerOptionIds.split("-"));
- Collections.sort(questionAnswerOptionIdList);
- String answerStr = listConcat(questionAnswerOptionIdList);
- // 获取用户作答
- List questionUserOptionIdList = answersMap.get(questionId);
- Collections.sort(questionUserOptionIdList);
- String userStr = listConcat(questionUserOptionIdList);
- // 判断questionAnswerOptionIds和answersMap里面的答案是否相等
- if (answerStr.equals(userStr)) {
- // 说明题目作答正确,下面根据题型给分
- int score = 0;
- if (radioIdList.contains(questionId)) {
- score = radioScore;
- }
- if (checkIdList.contains(questionId)) {
- score = checkScore;
- }
- if (judgeIdList.contains(questionId)) {
- score = judgeScore;
- }
- // 累计本次考试得分
- totalScore += score;
- // True代表题目答对
- answerOptionIdsSb.append(questionId + "@True_" + userStr + "$");
- judgeMap.put(questionId, score);
- } else {
- // 说明题目作答错误,直接判零分,False代表题目答错
- answerOptionIdsSb.append(questionId + "@False_" + userStr + "$");
- judgeMap.put(questionId, 0);
- }
- }
- // 4.计算得分,记录本次考试结果,存到ExamRecord中
- ExamRecord examRecord = new ExamRecord();
- examRecord.setExamRecordId(IdUtil.simpleUUID());
- examRecord.setExamId(examId);
- // 注意去掉最后可能有的&_-
- examRecord.setAnswerOptionIds(replaceLastSeparator(answerOptionIdsSb.toString()));
- examRecord.setExamJoinerId(userId);
- examRecord.setExamJoinDate(new Date());
- examRecord.setExamJoinScore(totalScore);
- examRecordRepository.save(examRecord);
- return examRecord;
- }
-
- @Override
- public List getExamRecordList(String userId) {
- // 获取指定用户下的考试记录列表
- List examRecordList = examRecordRepository.findByExamJoinerIdOrderByExamJoinDateDesc(userId);
- List examRecordVoList = new ArrayList<>();
- for (ExamRecord examRecord : examRecordList) {
- ExamRecordVo examRecordVo = new ExamRecordVo();
- Exam exam = examRepository.findById(examRecord.getExamId()).orElse(null);
- examRecordVo.setExam(exam);
- User user = userRepository.findById(userId).orElse(null);
- examRecordVo.setUser(user);
- examRecordVo.setExamRecord(examRecord);
- examRecordVoList.add(examRecordVo);
- }
- return examRecordVoList;
- }
-
- @Override
- public RecordDetailVo getRecordDetail(String recordId) {
- // 获取考试详情的封装对象
- ExamRecord record = examRecordRepository.findById(recordId).orElse(null);
- RecordDetailVo recordDetailVo = new RecordDetailVo();
- recordDetailVo.setExamRecord(record);
- // 用户的答案,需要解析
- HashMap> answersMap = new HashMap<>();
- HashMap resultsMap = new HashMap<>();
- assert record != null;
- String answersStr = record.getAnswerOptionIds();
- // $分隔题目,因为$在正则中有特殊用途(行尾),所以需要括起来
- String[] questionArr = answersStr.split("[$]");
- for (String questionStr : questionArr) {
- System.out.println(questionStr);
- // 区分开题目标题和选项
- String[] questionTitleResultAndOption = questionStr.split("_");
- String[] questionTitleAndResult = questionTitleResultAndOption[0].split("@");
- String[] questionOptions = questionTitleResultAndOption[1].split("-");
- // 题目:答案选项
- answersMap.put(questionTitleAndResult[0], Arrays.asList(questionOptions));
- // 题目:True / False
- resultsMap.put(questionTitleAndResult[0], questionTitleAndResult[1]);
- }
- recordDetailVo.setAnswersMap(answersMap);
- recordDetailVo.setResultsMap(resultsMap);
- // 下面再计算正确答案的map
- ExamDetailVo examDetailVo = getExamDetail(record.getExamId());
- List questionIdList = new ArrayList<>();
- questionIdList.addAll(Arrays.asList(examDetailVo.getRadioIds()));
- questionIdList.addAll(Arrays.asList(examDetailVo.getCheckIds()));
- questionIdList.addAll(Arrays.asList(examDetailVo.getJudgeIds()));
- // 获取所有的问题对象
- List questionList = questionRepository.findAllById(questionIdList);
- HashMap> answersRightMap = new HashMap<>();
- for (Question question : questionList) {
- // 记得去掉最后可能出现的特殊字符
- String questionAnswerOptionIdsStr = replaceLastSeparator(question.getQuestionAnswerOptionIds());
- String[] questionAnswerOptionIds = questionAnswerOptionIdsStr.split("-");
- answersRightMap.put(question.getQuestionId(), Arrays.asList(questionAnswerOptionIds));
- }
- recordDetailVo.setAnswersRightMap(answersRightMap);
- return recordDetailVo;
- }
-
- /**
- * 把字符串最后一个字符-替换掉
- *
- * @param str 原始字符串
- * @return 替换掉最后一个-的字符串
- */
- private String replaceLastSeparator(String str) {
- String lastChar = str.substring(str.length() - 1);
- // 题目和题目之间用$分隔,题目有多个选项地话用-分隔,题目和选项之间用_分隔
- if ("-".equals(lastChar) || "_".equals(lastChar) || "$".equals(lastChar)) {
- str = StrUtil.sub(str, 0, str.length() - 1);
- }
- return str;
- }
-
- /**
- * 把字符串用-连接起来
- *
- * @param strList 字符串列表
- * @return 拼接好的字符串,记住要去掉最后面的-
- */
- private String listConcat(List strList) {
- StringBuilder sb = new StringBuilder();
- for (String str : strList) {
- sb.append(str);
- sb.append("-");
- }
- return replaceLastSeparator(sb.toString());
- }
-}
+public class ActionVo {
+ // 使用@JsonProperty注解将actionName属性映射到JSON中的action字段
+ @JsonProperty("action")
+ private String actionName;
+
+ // 使用@JsonProperty注解将actionDescription属性映射到JSON中的describe字段
+ @JsonProperty("describe")
+ private String actionDescription;
+
+ // 使用@JsonProperty注解将defaultCheck属性映射到JSON中的defaultCheck字段
+ @JsonProperty("defaultCheck")
+ private Boolean defaultCheck;
+}
\ No newline at end of file
diff --git a/frontend/src/components/Menu/menu.js b/frontend/src/components/Menu/menu.js
index 458c19f..be5b0e0 100644
--- a/frontend/src/components/Menu/menu.js
+++ b/frontend/src/components/Menu/menu.js
@@ -6,20 +6,24 @@ const { Item, SubMenu } = Menu
export default {
name: 'SMenu',
props: {
+ // 菜单数据
menu: {
type: Array,
required: true
},
+ // 主题
theme: {
type: String,
required: false,
default: 'dark'
},
+ // 模式
mode: {
type: String,
required: false,
default: 'inline'
},
+ // 是否折叠
collapsed: {
type: Boolean,
required: false,
@@ -28,12 +32,16 @@ export default {
},
data () {
return {
+ // 打开的菜单项
openKeys: [],
+ // 选择的菜单项
selectedKeys: [],
+ // 缓存的打开的菜单项
cachedOpenKeys: []
}
},
computed: {
+ // 根菜单项的key
rootSubmenuKeys: vm => {
const keys = []
vm.menu.forEach(item => keys.push(item.path))
@@ -41,23 +49,29 @@ export default {
}
},
mounted () {
+ // 组件挂载时更新菜单
this.updateMenu()
},
watch: {
+ // 监听折叠状态的变化
collapsed (val) {
if (val) {
+ // 折叠时,缓存打开的菜单项
this.cachedOpenKeys = this.openKeys.concat()
this.openKeys = []
} else {
+ // 展开时,恢复打开的菜单项
this.openKeys = this.cachedOpenKeys
}
},
+ // 监听路由的变化
$route: function () {
+ // 更新菜单
this.updateMenu()
}
},
methods: {
- // select menu item
+ // 选择菜单项
onOpenChange (openKeys) {
// 在水平模式下时执行,并且不再执行后续
if (this.mode === 'horizontal') {
@@ -72,6 +86,7 @@ export default {
this.openKeys = latestOpenKey ? [latestOpenKey] : []
}
},
+ // 更新菜单
updateMenu () {
const routes = this.$route.matched.concat()
const { hidden } = this.$route.meta
@@ -91,13 +106,14 @@ export default {
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
},
- // render
+ // 渲染
renderItem (menu) {
if (!menu.hidden) {
return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu)
}
return null
},
+ // 渲染菜单项
renderMenuItem (menu) {
const target = menu.meta.target || null
const tag = target && 'a' || 'router-link'
@@ -122,6 +138,7 @@ export default {
)
},
+ // 渲染子菜单
renderSubMenu (menu) {
const itemArr = []
if (!menu.hideChildrenInMenu) {
@@ -137,6 +154,7 @@ export default {
)
},
+ // 渲染图标
renderIcon (icon) {
if (icon === 'none' || icon === undefined) {
return null
@@ -177,4 +195,4 @@ export default {
)
}
-}
+}
\ No newline at end of file
diff --git a/frontend/src/components/_util/util.js b/frontend/src/components/_util/util.js
index dd33231..651534e 100644
--- a/frontend/src/components/_util/util.js
+++ b/frontend/src/components/_util/util.js
@@ -7,7 +7,9 @@
* @param children
* @returns {*[]}
*/
+// 导出一个函数,用于过滤掉空节点
export function filterEmpty (children = []) {
+ // 过滤掉没有tag属性和text属性为空字符串的节点
return children.filter(c => c.tag || (c.text && c.text.trim() !== ''))
}
@@ -15,12 +17,17 @@ export function filterEmpty (children = []) {
* 获取字符串长度,英文字符 长度1,中文字符长度2
* @param {*} str
*/
+// 导出一个函数,用于获取字符串长度
export const getStrFullLength = (str = '') =>
+ // 将字符串分割成字符数组,然后使用reduce方法遍历数组,计算每个字符的长度
str.split('').reduce((pre, cur) => {
+ // 获取字符的Unicode编码
const charCode = cur.charCodeAt(0)
+ // 如果字符的Unicode编码在0-128之间,说明是英文字符,长度为1
if (charCode >= 0 && charCode <= 128) {
return pre + 1
}
+ // 否则,说明是中文字符,长度为2
return pre + 2
}, 0)
@@ -29,18 +36,26 @@ export const getStrFullLength = (str = '') =>
* @param {*} str
* @param {*} maxLength
*/
+// 导出一个函数,用于截取字符串
export const cutStrByFullLength = (str = '', maxLength) => {
+ // 初始化显示长度为0
let showLength = 0
+ // 将字符串分割成字符数组,然后使用reduce方法遍历数组,截取字符串
return str.split('').reduce((pre, cur) => {
+ // 获取字符的Unicode编码
const charCode = cur.charCodeAt(0)
+ // 如果字符的Unicode编码在0-128之间,说明是英文字符,长度为1
if (charCode >= 0 && charCode <= 128) {
showLength += 1
} else {
+ // 否则,说明是中文字符,长度为2
showLength += 2
}
+ // 如果显示长度小于等于maxLength,则将字符添加到结果中
if (showLength <= maxLength) {
return pre + cur
}
+ // 否则,返回结果
return pre
}, '')
}
diff --git a/frontend/src/views/account/settings/AvatarModal.vue b/frontend/src/views/account/settings/AvatarModal.vue
index 0ad9c41..6c0f31c 100644
--- a/frontend/src/views/account/settings/AvatarModal.vue
+++ b/frontend/src/views/account/settings/AvatarModal.vue
@@ -6,8 +6,10 @@
:confirmLoading="confirmLoading"
:width="800"
@cancel="cancelHandel">
+
+
+
+
取消
保存
@@ -44,18 +48,18 @@ export default {
*/
data () {
return {
- visible: false,
- id: null,
- confirmLoading: false,
+ visible: false, // 弹窗是否可见
+ id: null, // 头像id
+ confirmLoading: false, // 确认按钮是否加载中
options: {
- img: '/avatar2.jpg',
- autoCrop: true,
- autoCropWidth: 200,
- autoCropHeight: 200,
- fixedBox: true
+ img: '/avatar2.jpg', // 默认图片
+ autoCrop: true, // 是否自动裁剪
+ autoCropWidth: 200, // 自动裁剪宽度
+ autoCropHeight: 200, // 自动裁剪高度
+ fixedBox: true // 固定框
},
- previews: {}
+ previews: {} // 预览数据
}
},
methods: {
@@ -106,4 +110,4 @@ export default {
height: 100%;
}
}
-
+
\ No newline at end of file
diff --git a/frontend/src/views/account/settings/BaseSetting.vue b/frontend/src/views/account/settings/BaseSetting.vue
index 2980c28..9740680 100644
--- a/frontend/src/views/account/settings/BaseSetting.vue
+++ b/frontend/src/views/account/settings/BaseSetting.vue
@@ -1,26 +1,33 @@
+
+
+
+
+
+
+
+
提交
保存
@@ -35,18 +43,25 @@
+
+
+
+
+
+
@@ -54,6 +69,7 @@