Browse Source

update content-service exam module

reghao 7 months ago
parent
commit
27b0c83aea
27 changed files with 424 additions and 217 deletions
  1. 3 2
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/controller/ExamController.java
  2. 6 2
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/controller/PaperController.java
  3. 0 1
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/db/mapper/PaperMapper.java
  4. 1 0
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/db/mapper/PaperQuestionMapper.java
  5. 1 0
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/db/mapper/PaperResultMapper.java
  6. 4 6
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/constant/QuestionType.java
  7. 0 29
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/dto/UserAnswer.java
  8. 5 4
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/dto/UserResult.java
  9. 4 3
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/po/PaperAnswer.java
  10. 5 18
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/po/PaperQuestion.java
  11. 2 2
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/po/PaperResult.java
  12. 2 2
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/po/Question.java
  13. 1 1
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/provider/QuestionAddGroupSequenceProvider.java
  14. 5 2
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/query/ExamQuery.java
  15. 8 1
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/query/PaperQuery.java
  16. 5 5
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/PaperDetail.java
  17. 2 2
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/PaperView.java
  18. 53 0
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/QuestionAnswer.java
  19. 2 4
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/QuestionAnswerInfo.java
  20. 2 1
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/QuestionInfo.java
  21. 0 1
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/service/ExamResultService.java
  22. 52 27
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/service/ExamService.java
  23. 183 56
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/service/PaperService.java
  24. 2 3
      content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/service/QuestionService.java
  25. 6 6
      content/content-service/src/main/resources/mapper/exam/PaperQuestionMapper.xml
  26. 16 0
      content/content-service/src/main/resources/mapper/exam/PaperResultMapper.xml
  27. 54 39
      content/content-service/src/test/java/cn/reghao/tnb/content/app/exam/service/ExamTest.java

+ 3 - 2
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/controller/ExamController.java

@@ -10,6 +10,7 @@ import cn.reghao.tnb.content.app.exam.service.PaperService;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.Operation;
 import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
@@ -55,14 +56,14 @@ public class ExamController {
 
     @Operation(summary = "暂存用户提交的答案", description = "N")
     @PostMapping(value = "/cache", produces = MediaType.APPLICATION_JSON_VALUE)
-    public String cacheExamPaper1(@RequestBody UserResult userResult) {
+    public String cacheExamPaper1(@Validated @RequestBody UserResult userResult) {
         paperService.cacheUserAnswers(userResult);
         return WebResult.success();
     }
 
     @Operation(summary = "用户提交考试答案", description = "N")
     @PostMapping(value = "/submit", produces = MediaType.APPLICATION_JSON_VALUE)
-    public String submitExamPaper1(@RequestBody UserResult userResult) {
+    public String submitExamPaper1(@Validated @RequestBody UserResult userResult) {
         int resultId = examService.submitExamPaper(userResult);
         return WebResult.success(resultId);
     }

+ 6 - 2
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/controller/PaperController.java

@@ -54,8 +54,12 @@ public class PaperController {
 
     @Operation(summary = "获取试卷详情", description = "N")
     @GetMapping(value = "/{paperId}", produces = MediaType.APPLICATION_JSON_VALUE)
-    public String getPaper(@PathVariable("paperId") Integer paperId) {
-        PaperDetail paperDetail = paperService.getPaperDetail(paperId);
+    public String getPaper(@PathVariable("paperId") Integer paperId, @RequestParam("status") int status) {
+        PaperDetail paperDetail = paperService.getPaperDetail(paperId, status);
+        if (paperDetail == null) {
+            return WebResult.notFound();
+        }
+
         return WebResult.success(paperDetail);
     }
 

+ 0 - 1
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/db/mapper/PaperMapper.java

@@ -17,7 +17,6 @@ import java.util.List;
 public interface PaperMapper extends BaseMapper<Paper> {
     void deleteById(int paperId);
 
-    Paper findByPaperId(int paperId);
     int countByCriteria(PaperQuery paperQuery);
     List<Paper> findPaperByPage(Page page, @Param("paperQuery") PaperQuery paperQuery);
 }

+ 1 - 0
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/db/mapper/PaperQuestionMapper.java

@@ -15,5 +15,6 @@ import java.util.List;
 public interface PaperQuestionMapper extends BaseMapper<PaperQuestion> {
     void deleteByPaperId(int paperId);
     List<PaperQuestion> findByPaperId(int paperId);
+    @Deprecated
     List<PaperQuestion> findByPaperIdAndPid(@Param("paperId") int paperId, @Param("pid") long pid);
 }

+ 1 - 0
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/db/mapper/PaperResultMapper.java

@@ -21,4 +21,5 @@ public interface PaperResultMapper extends BaseMapper<PaperResult> {
     List<PaperResult> findByPaperId(int paperId);
     int countByCriteria(ExamQuery examQuery);
     List<ExamResults> findExamResultsByPage(Page page, @Param("examQuery") ExamQuery examQuery);
+    List<PaperResult> findPaperResultByPage(Page page, @Param("examQuery") ExamQuery examQuery);
 }

+ 4 - 6
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/constant/QuestionType.java

@@ -12,12 +12,10 @@ import java.util.Map;
 public enum QuestionType {
     QUESTION1(1, "单选题"),
     QUESTION2(2, "多选题"),
-    QUESTION3(3, "不定项选择题"),
-    QUESTION4(4, "判断题"),
-    QUESTION5(5, "填空题"),
-    QUESTION6(6, "问答题"),
-    QUESTION7(7, "理解题"),
-    QUESTION8(8, "組题/综合题");
+    QUESTION3(3, "判断题"),
+    QUESTION4(4, "填空题"),
+    QUESTION5(5, "问答题"),
+    QUESTION6(6, "组合题");
 
     private final int code;
     private final String desc;

+ 0 - 29
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/dto/UserAnswer.java

@@ -1,29 +0,0 @@
-package cn.reghao.tnb.content.app.exam.model.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
-
-/**
- * @author reghao
- * @date 2024-08-28 13:07:23
- */
-@AllArgsConstructor
-@NoArgsConstructor
-@Setter
-@Getter
-public class UserAnswer {
-    @NotNull
-    private Long questionId;
-    @Size(min = 1, max = 20)
-    private String[] answers;
-
-    private long pid;
-    private int pos;
-    private int questionType;
-    private String answer;
-}

+ 5 - 4
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/dto/UserResult.java

@@ -1,5 +1,6 @@
 package cn.reghao.tnb.content.app.exam.model.dto;
 
+import cn.reghao.tnb.content.app.exam.model.vo.QuestionAnswer;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
@@ -22,12 +23,12 @@ import java.util.Map;
 public class UserResult {
     @NotNull
     private Integer paperId;
-    private Map<Long, List<Object>> cachedUserAnswers;
+    private Map<Long, QuestionAnswer> cachedUserAnswers;
     @Size(min = 1, max = 100)
-    private List<UserAnswer> userAnswers;
+    private List<QuestionAnswer> userAnswers;
 
-    public UserResult(int paperId, Map<Long, List<Object>> userAnswerMap) {
+    public UserResult(int paperId, Map<Long, QuestionAnswer> questionAnswerMap) {
         this.paperId = paperId;
-        this.cachedUserAnswers = userAnswerMap;
+        this.cachedUserAnswers = questionAnswerMap;
     }
 }

+ 4 - 3
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/po/PaperAnswer.java

@@ -1,9 +1,10 @@
 package cn.reghao.tnb.content.app.exam.model.po;
 
 import cn.reghao.jutil.jdk.db.BaseObject;
-import cn.reghao.tnb.content.app.exam.model.dto.UserAnswer;
+import cn.reghao.tnb.content.app.exam.model.vo.QuestionAnswer;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
+import lombok.Setter;
 
 /**
  * 用户提交的答案
@@ -12,6 +13,7 @@ import lombok.NoArgsConstructor;
  * @date 2024-09-02 09:37:46
  */
 @NoArgsConstructor
+@Setter
 @Getter
 public class PaperAnswer extends BaseObject<Integer> {
     private Integer resultId;
@@ -24,12 +26,11 @@ public class PaperAnswer extends BaseObject<Integer> {
     private Integer score;
     private String review;
 
-    public PaperAnswer(UserAnswer userAnswer) {
+    public PaperAnswer(QuestionAnswer userAnswer) {
         this.pos = userAnswer.getPos();
         this.pid = userAnswer.getPid();
         this.questionId = userAnswer.getQuestionId();
         this.questionType = userAnswer.getQuestionType();
-        this.answer = userAnswer.getAnswer();
     }
 
     public void setResultId(Integer resultId) {

+ 5 - 18
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/po/PaperQuestion.java

@@ -1,8 +1,8 @@
 package cn.reghao.tnb.content.app.exam.model.po;
 
 import cn.reghao.jutil.jdk.db.BaseObject;
-import cn.reghao.tnb.content.app.exam.model.constant.QuestionType;
 import lombok.Getter;
+import lombok.NoArgsConstructor;
 import lombok.Setter;
 
 import javax.validation.constraints.NotNull;
@@ -15,6 +15,7 @@ import java.util.Objects;
  * @author reghao
  * @date 2024-08-28 08:48:47
  */
+@NoArgsConstructor
 @Setter
 @Getter
 public class PaperQuestion extends BaseObject<Integer> {
@@ -23,25 +24,15 @@ public class PaperQuestion extends BaseObject<Integer> {
     private Integer pos;
     @NotNull
     private Long questionId;
+    private Integer type;
     @NotNull
     private Integer score;
-
-    private Long pid;
-    private Integer type;
-    private Boolean child;
-    @Size(max = 20)
-    private transient List<PaperQuestion> children = new ArrayList<>();
-
-    public PaperQuestion() {
-        this.pid = 0L;
-        this.child = false;
-    }
+    //@Size(max = 20)
+    //private transient List<PaperQuestion> children = new ArrayList<>();
 
     public PaperQuestion(int pos, Question question, int score) {
-        this.pid = question.getPid();
         this.questionId = question.getQuestionId();
         this.type = question.getType();
-        this.child = Objects.equals(question.getType(), QuestionType.QUESTION8.getCode());
         this.pos = pos;
         this.score = score;
     }
@@ -49,8 +40,4 @@ public class PaperQuestion extends BaseObject<Integer> {
     public void setPaperId(Integer paperId) {
         this.paperId = paperId;
     }
-
-    public void setChild(Boolean child) {
-        this.child = child;
-    }
 }

+ 2 - 2
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/po/PaperResult.java

@@ -23,7 +23,7 @@ public class PaperResult extends BaseObject<Integer> {
     private Long createBy;
     private Boolean marked;
 
-    public PaperResult(int paperId, int objectiveScore) {
+    public PaperResult(int paperId, int objectiveScore, boolean marked) {
         this.paperId = paperId;
         this.objectiveScore = objectiveScore;
         this.subjectiveScore = 0;
@@ -31,6 +31,6 @@ public class PaperResult extends BaseObject<Integer> {
         this.examTime = LocalDateTime.now();
         this.consumedTime = 0;
         this.createBy = UserContext.getUser();
-        this.marked = false;
+        this.marked = marked;
     }
 }

+ 2 - 2
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/po/Question.java

@@ -43,7 +43,7 @@ public class Question extends BaseObject<Integer> {
         this.content = content;
         this.analysis = "";
         this.pid = 0L;
-        this.child = questionType == QuestionType.QUESTION8.getCode();
+        this.child = questionType == QuestionType.QUESTION6.getCode();
         this.pos = 0;
         this.extra = extra;
     }
@@ -56,7 +56,7 @@ public class Question extends BaseObject<Integer> {
         this.content = questionAddDto.getQuestionContent();
         this.analysis = questionAddDto.getAnalysis();
         this.pid = 0L;
-        this.child = Objects.equals(questionAddDto.getQuestionType(), QuestionType.QUESTION8.getCode());
+        this.child = Objects.equals(questionAddDto.getQuestionType(), QuestionType.QUESTION6.getCode());
         this.pos = 0;
     }
 

+ 1 - 1
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/provider/QuestionAddGroupSequenceProvider.java

@@ -19,7 +19,7 @@ public class QuestionAddGroupSequenceProvider implements DefaultGroupSequencePro
 
         if (questionAddDto != null) {
             int questionType = questionAddDto.getQuestionType();
-            if (questionType == QuestionType.QUESTION8.getCode()) {
+            if (questionType == QuestionType.QUESTION6.getCode()) {
                 defaultGroupSequence.add(QuestionAddDto.GroupQuestion.class);
             } else {
                 defaultGroupSequence.add(QuestionAddDto.NoneGroupQuestion.class);

+ 5 - 2
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/query/ExamQuery.java

@@ -21,7 +21,6 @@ public class ExamQuery {
     public ExamQuery() {
         this.pageNumber = 1;
         this.pageSize = 10;
-        this.loginUser = UserContext.getUser();
         this.marked = false;
     }
 
@@ -47,7 +46,11 @@ public class ExamQuery {
         public Builder() {
             this.pageNumber = 1;
             this.pageSize = 10;
-            this.loginUser = UserContext.getUser();
+        }
+
+        public Builder loginUser(long loginUser) {
+            this.loginUser = loginUser;
+            return this;
         }
 
         public Builder paperId(int paperId) {

+ 8 - 1
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/query/PaperQuery.java

@@ -26,9 +26,10 @@ public class PaperQuery {
     }
 
     private PaperQuery(Builder builder) {
-        this.subjectId = builder.subjectId;
         this.pageNumber = builder.pageNumber;
         this.pageSize = builder.pageSize;
+        this.loginUser = builder.loginUser;
+        this.subjectId = builder.subjectId;
         this.type = builder.type;
         this.level = builder.level;
     }
@@ -40,6 +41,7 @@ public class PaperQuery {
     public static final class Builder {
         private Integer pageNumber;
         private Integer pageSize;
+        private Long loginUser;
         private Integer subjectId;
         private Integer type;
         private Integer level;
@@ -59,6 +61,11 @@ public class PaperQuery {
             return this;
         }
 
+        public Builder loginUser(long loginUser) {
+            this.loginUser = loginUser;
+            return this;
+        }
+
         public Builder subjectId(int subjectId) {
             this.subjectId = subjectId;
             return this;

+ 5 - 5
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/PaperDetail.java

@@ -15,20 +15,20 @@ import java.util.Map;
 public class PaperDetail {
     private int paperId;
     private String name;
-    private String description;
+    private int status;
     private int duration;
     private int totalScore;
-    private List<QuestionInfo> questions;
+    // questionType -> list
     private Map<Integer, List<QuestionInfo>> questionMap;
     private UserResult userResult;
 
-    public PaperDetail(Paper paper, List<QuestionInfo> questions, Map<Integer, List<QuestionInfo>> questionMap) {
+    public PaperDetail(Paper paper, int status, Map<Integer, List<QuestionInfo>> questionMap, UserResult userResult) {
         this.paperId = paper.getId();
         this.name = paper.getName();
-        this.description = paper.getDescription();
+        this.status = status;
         this.duration = paper.getDuration();
         this.totalScore = paper.getTotalScore();
-        this.questions = questions;
         this.questionMap = questionMap;
+        this.userResult = userResult;
     }
 }

+ 2 - 2
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/PaperView.java

@@ -20,7 +20,7 @@ public class PaperView {
     private Integer passScore;
     private Integer status;
 
-    public PaperView(Paper paper) {
+    public PaperView(Paper paper, int status) {
         this.type = 1;
         this.examId = paper.getId();
         this.examName = paper.getName();
@@ -31,6 +31,6 @@ public class PaperView {
         this.endTime = DateTimeConverter.format(paper.getEndTime());
         this.totalScore = paper.getTotalScore();
         this.passScore = paper.getPassScore();
-        this.status = 1;
+        this.status = status;
     }
 }

+ 53 - 0
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/QuestionAnswer.java

@@ -0,0 +1,53 @@
+package cn.reghao.tnb.content.app.exam.model.vo;
+
+import cn.reghao.tnb.content.app.exam.model.po.PaperAnswer;
+import cn.reghao.tnb.content.app.exam.model.po.Question;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+
+/**
+ * @author reghao
+ * @date 2025-08-09 14:00:42
+ */
+@NoArgsConstructor
+@Setter
+@Getter
+public class QuestionAnswer implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @NotNull
+    private Long questionId;
+    @NotNull
+    private Integer questionType;
+    @NotNull
+    private Integer pos;
+    @Size(min = 1, max = 20)
+    private Object[] submitAnswer = {};
+    @Size(min = 1, max = 20)
+    private Object[] correctAnswer = {};
+
+    private Long pid = 0L;
+
+    public QuestionAnswer(QuestionInfo questionInfo) {
+        this.questionId = questionInfo.getQuestionId();
+        this.questionType = questionInfo.getQuestionType();
+        this.pos = questionInfo.getPos();
+    }
+
+    public QuestionAnswer(PaperAnswer paperAnswer) {
+        this.questionId = paperAnswer.getQuestionId();
+        this.questionType = paperAnswer.getQuestionType();
+        this.pos = paperAnswer.getPos();
+    }
+
+    public QuestionAnswer(Question question) {
+        this.questionId = question.getQuestionId();
+        this.questionType = question.getType();
+        this.pos = 1;
+    }
+}

+ 2 - 4
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/QuestionAnswerInfo.java

@@ -17,13 +17,11 @@ import lombok.Setter;
 public class QuestionAnswerInfo {
     private Long questionId;
     private Integer pos;
-    private String answer;
-    private Boolean correct;
+    private String content;
 
     public QuestionAnswerInfo(QuestionOption questionOption) {
         this.questionId = questionOption.getQuestionId();
         this.pos = questionOption.getPos();
-        this.answer = questionOption.getContent();
-        this.correct = questionOption.getCorrect();
+        this.content = questionOption.getContent();
     }
 }

+ 2 - 1
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/model/vo/QuestionInfo.java

@@ -18,8 +18,9 @@ public class QuestionInfo {
     private int questionType;
     private long questionId;
     private String questionContent;
+    private List<QuestionAnswerInfo> questionOptions;
     private int score;
-    private List<String> images;
+    @Deprecated
     private List<QuestionAnswerInfo> answer;
     private List<QuestionInfo> children;
 

+ 0 - 1
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/service/ExamResultService.java

@@ -7,7 +7,6 @@ import cn.reghao.tnb.account.api.iface.AccountQuery;
 import cn.reghao.tnb.content.app.exam.db.mapper.*;
 import cn.reghao.tnb.content.app.exam.model.constant.QuestionType;
 import cn.reghao.tnb.content.app.exam.model.dto.ExamMarkForm;
-import cn.reghao.tnb.content.app.exam.model.dto.UserAnswer;
 import cn.reghao.tnb.content.app.exam.model.po.*;
 import cn.reghao.tnb.content.app.exam.model.query.ExamQuery;
 import cn.reghao.tnb.content.app.exam.model.vo.*;

+ 52 - 27
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/service/ExamService.java

@@ -1,10 +1,12 @@
 package cn.reghao.tnb.content.app.exam.service;
 
+import cn.reghao.tnb.common.auth.UserContext;
 import cn.reghao.tnb.content.app.exam.db.mapper.*;
 import cn.reghao.tnb.content.app.exam.model.constant.QuestionType;
-import cn.reghao.tnb.content.app.exam.model.dto.UserAnswer;
 import cn.reghao.tnb.content.app.exam.model.dto.UserResult;
 import cn.reghao.tnb.content.app.exam.model.po.*;
+import cn.reghao.tnb.content.app.exam.model.vo.QuestionAnswer;
+import cn.reghao.tnb.content.app.util.redis.ds.RedisOps;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -22,33 +24,38 @@ public class ExamService {
     private final PaperQuestionMapper paperQuestionMapper;
     private final PaperResultMapper paperResultMapper;
     private final PaperAnswerMapper paperAnswerMapper;
+    private RedisOps redisOps;
 
     public ExamService(QuestionMapper questionMapper, QuestionOptionMapper questionOptionMapper,
                        PaperQuestionMapper paperQuestionMapper, PaperResultMapper paperResultMapper,
-                       PaperAnswerMapper paperAnswerMapper) {
+                       PaperAnswerMapper paperAnswerMapper, RedisOps redisOps) {
         this.questionMapper = questionMapper;
         this.questionOptionMapper = questionOptionMapper;
         this.paperQuestionMapper = paperQuestionMapper;
         this.paperResultMapper = paperResultMapper;
         this.paperAnswerMapper = paperAnswerMapper;
+        this.redisOps = redisOps;
     }
 
     public int submitExamPaper(UserResult userResult) {
         int paperId = userResult.getPaperId();
         List<PaperQuestion> paperQuestions = paperQuestionMapper.findByPaperId(paperId);
-        Map<Long, PaperQuestion> paperQuestionsMap = paperQuestions.stream()
-                .collect(Collectors.toMap(PaperQuestion::getQuestionId, k -> k));
+        Long totalObjectiveQuestions = paperQuestions.stream()
+                .filter(paperQuestion -> {
+                    int type = paperQuestion.getType();
+                    return type <= QuestionType.QUESTION5.getCode();
+                }).count();
 
         Map<Long, Integer> scoreMap = paperQuestions.stream()
                 .collect(Collectors.toMap(PaperQuestion::getQuestionId, PaperQuestion::getScore));
 
-        // pid -> List<UserAnswer>
-        Map<Long, List<UserAnswer>> group = userResult.getUserAnswers().stream()
-                .collect(Collectors.groupingBy(UserAnswer::getPid));
+        // pid -> List<QuestionAnswer>
+        Map<Long, List<QuestionAnswer>> group = userResult.getUserAnswers().stream()
+                .collect(Collectors.groupingBy(QuestionAnswer::getPid));
         List<PaperAnswer> paperAnswers = new ArrayList<>();
-        for (Map.Entry<Long, List<UserAnswer>> entry : group.entrySet()) {
+        for (Map.Entry<Long, List<QuestionAnswer>> entry : group.entrySet()) {
             long pid = entry.getKey();
-            List<UserAnswer> answers = entry.getValue();
+            List<QuestionAnswer> answers = entry.getValue();
             if (pid == 0) {
                 List<PaperAnswer> list1 = calculateScore(answers, scoreMap);
                 paperAnswers.addAll(list1);
@@ -66,8 +73,15 @@ public class ExamService {
                 .filter(Objects::nonNull)
                 .mapToInt(Integer::intValue)
                 .sum();
-        PaperResult paperResult = new PaperResult(paperId, objectiveScore);
+
+        boolean marked = totalObjectiveQuestions.intValue() == paperQuestions.size();
+        PaperResult paperResult = new PaperResult(paperId, objectiveScore, marked);
         int resultId = save(paperResult, paperAnswers);
+
+        long loginUser = UserContext.getUser();
+        String keyPrefix = "tnb:exam:result";
+        String key = String.format("%s:%s:%s", keyPrefix, paperId, loginUser);
+        redisOps.del(key);
         return resultId;
     }
 
@@ -87,22 +101,23 @@ public class ExamService {
      * @return
      * @date 2025-08-06 10:18:57
      */
-    private List<PaperAnswer> calculateScore(List<UserAnswer> userAnswers, Map<Long, Integer> scoreMap) {
+    private List<PaperAnswer> calculateScore(List<QuestionAnswer> userAnswers, Map<Long, Integer> scoreMap) {
         List<PaperAnswer> list = new ArrayList<>();
-        for (UserAnswer userAnswer : userAnswers) {
+        for (QuestionAnswer userAnswer : userAnswers) {
             PaperAnswer paperAnswer = new PaperAnswer(userAnswer);
-
             long questionId = userAnswer.getQuestionId();
-            String submitAnswer = userAnswer.getAnswer();
+            Object[] submitAnswers = userAnswer.getSubmitAnswer();
             Question question = questionMapper.findByQuestionId(questionId);
             List<QuestionOption> correctOptions = questionOptionMapper.findByQuestionId(questionId).stream()
                     .filter(QuestionOption::getCorrect)
                     .collect(Collectors.toList());
 
+            String answer = "";
             int type = question.getType();
-            if (type == QuestionType.QUESTION1.getCode() || type == QuestionType.QUESTION4.getCode()) {
+            if (type == QuestionType.QUESTION1.getCode() || type == QuestionType.QUESTION3.getCode()) {
                 // 单选和判断
-                int option = Integer.parseInt(submitAnswer)+1;
+                int option = (int)submitAnswers[0];
+                answer += option;
                 int correctOption = correctOptions.get(0).getPos();
                 if (option == correctOption) {
                     paperAnswer.setCorrect(true);
@@ -111,16 +126,22 @@ public class ExamService {
                     paperAnswer.setCorrect(false);
                     paperAnswer.setScore(0);
                 }
-            } else if (type == QuestionType.QUESTION2.getCode() || type == QuestionType.QUESTION3.getCode()) {
-                // 多选和不定项
-                List<Integer> submitAnswers = Arrays.stream(submitAnswer.split(","))
-                        .map(str -> Integer.parseInt(str) + 1).collect(Collectors.toList());
+            } else if (type == QuestionType.QUESTION2.getCode()) {
+                // 多选
+                StringBuilder sb = new StringBuilder();
+                for (Object obj : submitAnswers) {
+                    sb.append((String) obj).append(",");
+                }
+                answer = sb.toString();
+                int idx = answer.lastIndexOf(",");
+                answer = answer.substring(0, idx);
+
                 Set<Integer> correctAnswers = correctOptions.stream()
                         .map(QuestionOption::getPos)
                         .collect(Collectors.toSet());
 
-                if (submitAnswers.size() == correctAnswers.size()) {
-                    long total = submitAnswers.stream().filter(correctAnswers::contains).count();
+                if (submitAnswers.length == correctAnswers.size()) {
+                    long total = Arrays.stream(submitAnswers).filter(correctAnswers::contains).count();
                     if (correctAnswers.size() == total) {
                         paperAnswer.setCorrect(true);
                         paperAnswer.setScore(scoreMap.get(questionId));
@@ -130,15 +151,19 @@ public class ExamService {
                 }
                 paperAnswer.setCorrect(false);
                 paperAnswer.setScore(0);
-            } else if (type == QuestionType.QUESTION5.getCode()) {
+            } else if (type == QuestionType.QUESTION4.getCode()) {
                 // 填空题
-            } else if (type == QuestionType.QUESTION6.getCode()) {
+                answer = (String) userAnswer.getSubmitAnswer()[0];
+            } else if (type == QuestionType.QUESTION5.getCode()) {
                 // 问答题
-            } else if (type == QuestionType.QUESTION8.getCode()) {
-                // 組题
+                answer = (String) userAnswer.getSubmitAnswer()[0];
+            } else if (type == QuestionType.QUESTION6.getCode()) {
+                // 组合题
+                answer = (String) userAnswer.getSubmitAnswer()[0];
             } else {
+                answer = (String) userAnswer.getSubmitAnswer()[0];
             }
-
+            paperAnswer.setAnswer(answer);
             list.add(paperAnswer);
         }
 

+ 183 - 56
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/service/PaperService.java

@@ -7,15 +7,15 @@ import cn.reghao.jutil.jdk.serializer.JsonConverter;
 import cn.reghao.tnb.common.auth.UserContext;
 import cn.reghao.tnb.common.db.KeyValue;
 import cn.reghao.tnb.content.app.exam.db.mapper.*;
+import cn.reghao.tnb.content.app.exam.model.constant.PaperStatus;
 import cn.reghao.tnb.content.app.exam.model.constant.QuestionType;
 import cn.reghao.tnb.content.app.exam.model.dto.PaperAddDto;
-import cn.reghao.tnb.content.app.exam.model.dto.UserAnswer;
 import cn.reghao.tnb.content.app.exam.model.dto.UserResult;
 import cn.reghao.tnb.content.app.exam.model.po.*;
+import cn.reghao.tnb.content.app.exam.model.query.ExamQuery;
 import cn.reghao.tnb.content.app.exam.model.query.PaperQuery;
 import cn.reghao.tnb.content.app.exam.model.vo.*;
 import cn.reghao.tnb.content.app.util.redis.ds.RedisHash;
-import org.springframework.data.redis.support.collections.RedisMap;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -34,21 +34,26 @@ public class PaperService {
     private final QuestionOptionMapper questionOptionMapper;
     private final RedisHash redisHash;
     private String keyPrefix = "tnb:exam:result";
+    private PaperResultMapper paperResultMapper;
+    private PaperAnswerMapper paperAnswerMapper;
 
     public PaperService(PaperMapper paperMapper, PaperQuestionMapper paperQuestionMapper,
                         QuestionMapper questionMapper, QuestionOptionMapper questionOptionMapper,
-                        RedisHash redisHash) {
+                        RedisHash redisHash, PaperResultMapper paperResultMapper,
+                        PaperAnswerMapper paperAnswerMapper) {
         this.paperMapper = paperMapper;
         this.paperQuestionMapper = paperQuestionMapper;
         this.questionMapper = questionMapper;
         this.questionOptionMapper = questionOptionMapper;
         this.redisHash = redisHash;
+        this.paperResultMapper = paperResultMapper;
+        this.paperAnswerMapper = paperAnswerMapper;
     }
 
     public Result createExamPaper(PaperAddDto paperAddDto) {
         Paper paper = new Paper(paperAddDto);
-        List<PaperQuestion> questions = paperAddDto.getQuestions();
-        save(paper, questions);
+        List<PaperQuestion> paperQuestions = paperAddDto.getQuestions();
+        save(paper, paperQuestions);
         return Result.success();
     }
 
@@ -58,12 +63,9 @@ public class PaperService {
         int paperId = paper.getId();
         list.forEach(paperQuestion -> {
             paperQuestion.setPaperId(paperId);
-            if (!paperQuestion.getChildren().isEmpty()) {
-                paperQuestion.setChild(true);
-            }
         });
 
-        List<PaperQuestion> list1 = list.stream()
+        /*List<PaperQuestion> list1 = list.stream()
                 .map(paperQuestion -> {
                     if (paperQuestion.getChildren().isEmpty()) {
                         return null;
@@ -78,12 +80,12 @@ public class PaperService {
                 })
                 .filter(Objects::nonNull)
                 .flatMap(Collection::stream)
-                .collect(Collectors.toList());
+                .collect(Collectors.toList());*/
 
         paperQuestionMapper.saveAll(list);
-        if (!list1.isEmpty()) {
+        /*if (!list1.isEmpty()) {
             paperQuestionMapper.saveAll(list1);
-        }
+        }*/
     }
 
     public Result deleteExamPaper(int paperId) {
@@ -92,17 +94,42 @@ public class PaperService {
     }
 
     public PageList<PaperView> getExamPapers(PaperQuery paperQuery) {
+        long loginUser = paperQuery.getLoginUser();
         int total = paperMapper.countByCriteria(paperQuery);
         Page page = paperQuery.getPage();
         List<Paper> list = paperMapper.findPaperByPage(page, paperQuery);
-        List<PaperView> list1 = list.stream().map(PaperView::new).collect(Collectors.toList());
+        List<PaperView> list1 = list.stream()
+                .map(paper -> {
+                    int paperId = paper.getId();
+                    int paperType = paper.getStatus();
+                    PaperResult paperResult = getPaperResult(paperId, loginUser);
+                    int status;
+                    // 1. 试卷未完成
+                    // 2. 试卷已完成, 待批改
+                    // 3. 试卷已完成, 自己批改
+                    // 4. 试卷已完成, 已批改
+                    if (paperResult == null) {
+                        status = 1;
+                    } else if (paperResult.getMarked()) {
+                        //status = paperResult.getMarked() ? 4 : 2;
+                        status = 4;
+                    } else if (paperType == 2) {
+                        status = 3;
+                    } else {
+                        status = 2;
+                    }
+
+                    return new PaperView(paper, status);
+                })
+                .collect(Collectors.toList());
+
         return PageList.pageList(page, total, list1);
     }
 
     public List<QuestionInfo> getPaperQuestions(int paperId) {
-        List<PaperQuestion> questions = paperQuestionMapper.findByPaperId(paperId);
+        List<PaperQuestion> paperQuestions = paperQuestionMapper.findByPaperId(paperId);
         // questionId -> pos
-        Map<Long, PaperQuestion> questionMap = questions.stream()
+        Map<Long, PaperQuestion> questionMap = paperQuestions.stream()
                 .collect(Collectors.toMap(PaperQuestion::getQuestionId, k -> k));
         List<Question> list1 = questionMapper.findByQuestionIds(new ArrayList<>(questionMap.keySet()));
         return list1.stream().map(question -> {
@@ -140,23 +167,32 @@ public class PaperService {
                     .sorted(Comparator.comparingInt(QuestionAnswerInfo::getPos))
                     .collect(Collectors.toList());
             questionInfo.setAnswer(answerInfos);
+            questionInfo.setQuestionOptions(answerInfos);
         }
 
         return questionInfo;
     }
 
-    public PaperDetail getPaperDetail(int paperId) {
+    public PaperDetail getPaperDetail(int paperId, int status) {
+        long loginUser = UserContext.getUser();
+        Map<Long, QuestionAnswer> paperAnswers;
+        if (status == PaperStatus.PaperPreview.getCode()) {
+            paperAnswers = getPaperAnswersFromResult(paperId, loginUser);
+        } else if (status == PaperStatus.PaperExam.getCode()) {
+            paperAnswers = getPaperAnswersFromCache(paperId, loginUser);
+        } else if (status == PaperStatus.PaperMark.getCode()) {
+            paperAnswers = getPaperAnswersFromResult(paperId, loginUser);
+        } else if (status == PaperStatus.PaperResult.getCode()) {
+            paperAnswers = getPaperAnswersFromResult(paperId, loginUser);
+        } else {
+            paperAnswers = getPaperAnswersFromResult(paperId, loginUser);
+        }
+
         Paper paper = paperMapper.findById(paperId);
-        List<QuestionInfo> questions = getPaperQuestions(paperId);
-        Map<Integer, List<QuestionInfo>> groupMap = questions.stream()
+        Map<Integer, List<QuestionInfo>> questionMap = getPaperQuestions(paperId).stream()
                 .collect(Collectors.groupingBy(QuestionInfo::getQuestionType));
-
-        Map<Long, List<Object>> cachedUserAnswers = getCachedUserAnswers(paperId);
-        UserResult userResult = new UserResult(1, cachedUserAnswers);
-
-        PaperDetail paperDetail=  new PaperDetail(paper, questions, groupMap);
-        paperDetail.setUserResult(userResult);
-        return paperDetail;
+        UserResult userResult = new UserResult(paperId, paperAnswers);
+        return new PaperDetail(paper, status, questionMap, userResult);
     }
 
     public void cacheUserAnswers(UserResult userResult) {
@@ -164,39 +200,28 @@ public class PaperService {
         int paperId = userResult.getPaperId();
         String key = String.format("%s:%s:%s", keyPrefix, paperId, loginUser);
 
-        List<UserAnswer> userAnswers = userResult.getUserAnswers();
-        for (UserAnswer userAnswer : userAnswers) {
+        List<QuestionAnswer> userAnswers = userResult.getUserAnswers();
+        for (QuestionAnswer userAnswer : userAnswers) {
             long questionId = userAnswer.getQuestionId();
-            String[] answers = userAnswer.getAnswers();
-            //String answersJson = JsonConverter.objectToJson(answers);
-            redisHash.hset(key, ""+questionId, answers);
+            redisHash.hset(key, ""+questionId, userAnswer);
         }
-        /*Map<Long, List<String>> cachedUserAnswers = userResult.getCachedUserAnswers();
-        cachedUserAnswers.forEach((k, v) -> {
-            redisHash.hset(key, ""+k, v);
-        });*/
     }
 
-    private Map<Long, List<Object>> getCachedUserAnswers(int paperId) {
-        Map<Long, List<Object>> map = new HashMap<>();
-
-        long loginUser = UserContext.getUser();
-        String key = String.format("%s:%s:%s", keyPrefix, paperId, loginUser);
-        Map cachedMap = redisHash.hgetall(key);
-        cachedMap.forEach((k, v) -> {
-            long questionId = Long.parseLong((String) k);
-            Question question = questionMapper.findByQuestionId(questionId);
-            int type = question.getType();
-            String[] answers = (String[]) v;
-            List<Object> objectList;
-            if (type == QuestionType.QUESTION1.getCode() || type == QuestionType.QUESTION4.getCode()) {
-                objectList = Arrays.stream(answers)
-                        .map(val -> val.isBlank() ? -1 : Integer.parseInt(val))
-                        .collect(Collectors.toList());
-            } else {
-                objectList = Arrays.asList(answers);
+    private Map<Long, QuestionAnswer> getPaperAnswersFromCache(int paperId, long userId) {
+        Map<Long, QuestionAnswer> map = new HashMap<>();
+        String key = String.format("%s:%s:%s", keyPrefix, paperId, userId);
+        redisHash.hgetall(key).forEach((k, v) -> {
+            QuestionAnswer questionAnswer = (QuestionAnswer) v;
+            long questionId = questionAnswer.getQuestionId();
+            Object[] submitAnswer = questionAnswer.getSubmitAnswer();
+            int questionType = questionAnswer.getQuestionType();
+            if (questionType == QuestionType.QUESTION1.getCode()) {
+                if (submitAnswer[0] instanceof String) {
+                    Object[] submitAnswer1 = new Object[] {Integer.parseInt((String) submitAnswer[0])};
+                    questionAnswer.setSubmitAnswer(submitAnswer1);
+                }
             }
-            map.put(questionId, objectList);
+            map.put(questionId, questionAnswer);
         });
         if (!map.isEmpty()) {
             return map;
@@ -204,23 +229,125 @@ public class PaperService {
 
         List<QuestionInfo> questions = getPaperQuestions(paperId);
         for (QuestionInfo questionInfo : questions) {
+            QuestionAnswer questionAnswer = new QuestionAnswer(questionInfo);
             long questionId = questionInfo.getQuestionId();
             int type = questionInfo.getQuestionType();
             List<QuestionOption> questionOptionList = questionOptionMapper.findByQuestionId(questionId);
             long count = questionOptionList.stream().filter(QuestionOption::getCorrect).count();
             List<Object> list = new ArrayList<>();
             for (int i = 0; i < count; i++) {
-                if (type == QuestionType.QUESTION1.getCode() || type == QuestionType.QUESTION4.getCode()) {
+                if (type == QuestionType.QUESTION1.getCode() || type == QuestionType.QUESTION3.getCode()) {
+                    // 单选题和判断题前端使用 radio, 需要 int 类型来表示选中的 radio
                     list.add(-1);
-                } else if (type == QuestionType.QUESTION2.getCode() || type == QuestionType.QUESTION3.getCode()) {
+                } else if (type == QuestionType.QUESTION2.getCode()) {
+                    // 多选题前端使用 checkbox, 使用 string[] 来表示选中的 checkbox
+                    // 空数组表示没有选中
                 } else {
+                    // 填空题和简答题使用空字符串占位
                     list.add("");
                 }
+                questionAnswer.setSubmitAnswer(list.toArray(new Object[0]));
             }
 
-            map.putIfAbsent(questionId, list);
+            map.putIfAbsent(questionId, questionAnswer);
+        }
+
+        return map;
+    }
+
+    private Map<Long, QuestionAnswer> getPaperAnswersFromResult(int paperId, long userId) {
+        PaperResult paperResult = getPaperResult(paperId, userId);
+        if (paperResult == null) {
+            return getPaperAnswersFromCorrect(paperId);
         }
 
+        int resultId = paperResult.getId();
+        return getPaperAnswersFromResult(resultId);
+    }
+
+    private PaperResult getPaperResult(int paperId, long userId) {
+        ExamQuery examQuery = new ExamQuery.Builder()
+                .loginUser(userId)
+                .paperId(paperId)
+                .build();
+        Page page = examQuery.getPage();
+        List<PaperResult> list = paperResultMapper.findPaperResultByPage(page, examQuery);
+        return list.isEmpty() ? null : list.get(0);
+    }
+
+    private Map<Long, QuestionAnswer> getPaperAnswersFromResult(int resultId) {
+        Map<Long, QuestionAnswer> map = new HashMap<>();
+        List<PaperAnswer> paperAnswerList = paperAnswerMapper.findByResultId(resultId);
+        paperAnswerList.forEach(paperAnswer -> {
+            QuestionAnswer questionAnswer = new QuestionAnswer(paperAnswer);
+            long questionId = paperAnswer.getQuestionId();
+            setSubmitAnswer(paperAnswer, questionAnswer);
+            setCorrectAnswer(questionAnswer);
+            map.put(questionId, questionAnswer);
+        });
+
+        return map;
+    }
+
+    private void setCorrectAnswer(QuestionAnswer questionAnswer) {
+        long questionId = questionAnswer.getQuestionId();
+        List<QuestionOption> list = questionOptionMapper.findByQuestionId(questionId);
+        List<Object> correctAnswers = list.stream()
+                .filter(QuestionOption::getCorrect)
+                .map(QuestionOption::getContent)
+                .collect(Collectors.toList());
+        questionAnswer.setCorrectAnswer(correctAnswers.toArray(new Object[0]));
+    }
+
+    private void setSubmitAnswer(PaperAnswer paperAnswer, QuestionAnswer questionAnswer) {
+        int type = paperAnswer.getQuestionType();
+        String submitAnswer = paperAnswer.getAnswer();
+        List<Object> submitAnswerList;
+        if (type == QuestionType.QUESTION1.getCode() || type == QuestionType.QUESTION3.getCode()) {
+            submitAnswerList = List.of(Integer.parseInt(submitAnswer));
+        } else if (type == QuestionType.QUESTION2.getCode()) {
+            String[] answerArr = submitAnswer.split(",");
+            submitAnswerList = List.of(answerArr);
+        } else {
+            submitAnswerList = List.of(submitAnswer);
+        }
+        questionAnswer.setSubmitAnswer(submitAnswerList.toArray(new Object[0]));
+    }
+
+    @Deprecated
+    private Map<Long, QuestionAnswer> getPaperAnswersFromCorrect(int paperId) {
+        Map<Long, QuestionAnswer> map = new HashMap<>();
+        List<PaperQuestion> paperQuestions = paperQuestionMapper.findByPaperId(paperId);
+        List<Long> questionIds = paperQuestions.stream().map(PaperQuestion::getQuestionId).collect(Collectors.toList());
+        List<Question> questions = questionMapper.findByQuestionIds(questionIds);
+        questions.forEach(question -> {
+            QuestionAnswer questionAnswer = new QuestionAnswer(question);
+            long questionId = question.getQuestionId();
+            int type = question.getType();
+
+            List<QuestionOption> list = questionOptionMapper.findByQuestionId(questionId);
+            // 正确答案
+            List<Object> correctAnswerList;
+            if (type == QuestionType.QUESTION1.getCode() || type == QuestionType.QUESTION3.getCode()) {
+                correctAnswerList = list.stream()
+                        .filter(QuestionOption::getCorrect)
+                        .map(QuestionOption::getPos)
+                        .collect(Collectors.toList());
+            } else if (type == QuestionType.QUESTION2.getCode()) {
+                correctAnswerList = list.stream()
+                        .filter(QuestionOption::getCorrect)
+                        .map(QuestionOption::getPos)
+                        .collect(Collectors.toList());
+            } else {
+                correctAnswerList = list.stream()
+                        .filter(QuestionOption::getCorrect)
+                        .map(QuestionOption::getContent)
+                        .collect(Collectors.toList());
+            }
+
+            questionAnswer.setCorrectAnswer(correctAnswerList.toArray(new Object[0]));
+            map.put(questionId, questionAnswer);
+        });
         return map;
     }
 

+ 2 - 3
content/content-service/src/main/java/cn/reghao/tnb/content/app/exam/service/QuestionService.java

@@ -49,7 +49,7 @@ public class QuestionService {
     public Result addQuestion(QuestionAddDto questionAddDto) {
         long questionId = idGenerator.nextId();
         int type = questionAddDto.getQuestionType();
-        if (type == QuestionType.QUESTION8.getCode()) {
+        if (type == QuestionType.QUESTION6.getCode()) {
             Question question = new Question(questionId, questionAddDto, true);
             questionMapper.save(question);
 
@@ -74,7 +74,6 @@ public class QuestionService {
         } else if (type == QuestionType.QUESTION4.getCode()) {
         } else if (type == QuestionType.QUESTION5.getCode()) {
         } else if (type == QuestionType.QUESTION6.getCode()) {
-        } else if (type == QuestionType.QUESTION7.getCode()) {
         } else {
         }
 
@@ -153,7 +152,7 @@ public class QuestionService {
         int level = question.getLevel();
         String levelStr = QuestionLevel.getDescByCode(level);
         QuestionDetail questionDetail = new QuestionDetail(question, subject.getName(), typeStr, levelStr, options);
-        if (type == QuestionType.QUESTION8.getCode()) {
+        if (type == QuestionType.QUESTION6.getCode()) {
             List<QuestionDetail> list1 = questionMapper.findByPid(questionId).stream().map(question1 -> {
                 long questionId1 = question1.getQuestionId();
                 int type1 = question1.getType();

+ 6 - 6
content/content-service/src/main/resources/mapper/exam/PaperQuestionMapper.xml

@@ -4,16 +4,16 @@
 <mapper namespace="cn.reghao.tnb.content.app.exam.db.mapper.PaperQuestionMapper">
     <insert id="save" useGeneratedKeys="true" keyProperty="id">
         insert into exam_paper_question
-        (`paper_id`,`pos`,`question_id`,`score`,`pid`,`child`)
+        (`paper_id`,`pos`,`question_id`,`score`,`type`)
         values
-        (#{paperId},#{pos},#{questionId},#{score},#{pid},#{child})
+        (#{paperId},#{pos},#{questionId},#{score},#{type})
     </insert>
     <insert id="saveAll" useGeneratedKeys="true" keyProperty="id">
         insert ignore into exam_paper_question
-        (`paper_id`,`pos`,`question_id`,`score`,`pid`,`child`)
+        (`paper_id`,`pos`,`question_id`,`score`,`type`)
         values
         <foreach collection="list" item="item" index="index" separator=",">
-            (#{item.paperId},#{item.pos},#{item.questionId},#{item.score},#{item.pid},#{item.child})
+            (#{item.paperId},#{item.pos},#{item.questionId},#{item.score},#{item.type})
         </foreach>
     </insert>
 
@@ -25,11 +25,11 @@
     <select id="findByPaperId" resultType="cn.reghao.tnb.content.app.exam.model.po.PaperQuestion">
         select *
         from exam_paper_question
-        where paper_id=#{paperId} and pid=0
+        where paper_id=#{paperId}
     </select>
     <select id="findByPaperIdAndPid" resultType="cn.reghao.tnb.content.app.exam.model.po.PaperQuestion">
         select *
         from exam_paper_question
-        where paper_id=#{paperId} and pid=#{pid}
+        where paper_id=#{paperId}
     </select>
 </mapper>

+ 16 - 0
content/content-service/src/main/resources/mapper/exam/PaperResultMapper.xml

@@ -68,4 +68,20 @@
             and paper_id=#{examQuery.paperId}
         </if>
     </select>
+    <select id="findPaperResultByPage" resultType="cn.reghao.tnb.content.app.exam.model.po.PaperResult">
+        select *
+        from exam_paper_result
+        <where>
+            deleted=0
+            <if test="examQuery.marked != null">
+                and marked=#{examQuery.marked}
+            </if>
+            <if test="examQuery.paperId != null">
+                and paper_id=#{examQuery.paperId}
+            </if>
+            <if test="examQuery.loginUser != null">
+                and create_by=#{examQuery.loginUser}
+            </if>
+        </where>
+    </select>
 </mapper>

+ 54 - 39
content/content-service/src/test/java/cn/reghao/tnb/content/app/exam/service/ExamTest.java

@@ -4,12 +4,15 @@ import cn.reghao.jutil.jdk.db.Page;
 import cn.reghao.jutil.jdk.serializer.JsonConverter;
 import cn.reghao.jutil.jdk.text.TextFile;
 import cn.reghao.jutil.tool.id.SnowFlake;
+import cn.reghao.tnb.common.auth.UserContext;
 import cn.reghao.tnb.content.app.ContentApplication;
 import cn.reghao.tnb.content.app.exam.db.mapper.*;
 import cn.reghao.tnb.content.app.exam.model.constant.QuestionType;
 import cn.reghao.tnb.content.app.exam.model.dto.PaperAddDto;
 import cn.reghao.tnb.content.app.exam.model.po.*;
 import cn.reghao.tnb.content.app.exam.model.query.QuestionQuery;
+import cn.reghao.tnb.content.app.exam.model.vo.QuestionInfo;
+import cn.reghao.tnb.content.app.util.redis.ds.RedisHash;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import lombok.Getter;
@@ -59,8 +62,8 @@ public class ExamTest {
 
     SnowFlake idGenerator = new SnowFlake(1L, 1L);
     @Test
-    public void setQuestion8Test() {
-        int questionType = QuestionType.QUESTION8.getCode();
+    public void setQuestion6Test() {
+        int questionType = QuestionType.QUESTION6.getCode();
         long questionId = idGenerator.nextId();
         String content = "阅读下面的文字,完成1—3题。   \n" +
                 "\n" +
@@ -170,7 +173,7 @@ public class ExamTest {
 
     @Test
     public void parseQuestionTest() {
-        String filePath = "/home/reghao/Downloads/xxqg.json";
+        String filePath = "/home/reghao/Dropbox/tiku/xxqg.json";
         JsonObject jsonObject = JsonConverter.jsonFileToObject(new File(filePath), JsonObject.class);
         List<AhaQuestion> questionList = new ArrayList<>();
         jsonObject.entrySet().forEach(entry -> {
@@ -239,13 +242,13 @@ public class ExamTest {
 
     @Test
     public void gaokaoQuestionTest() {
-        String baseDir = "/home/reghao/Downloads/gaokao/objective";
+        String baseDir = "/home/reghao/Dropbox/tiku/gaokao/objective";
         File dir = new File(baseDir);
         for (File file : dir.listFiles()) {
             parseQuestion(file.getAbsolutePath());
         }
 
-        baseDir = "/home/reghao/Downloads/gaokao/subjective";
+        baseDir = "/home/reghao/Dropbox/tiku/gaokao/subjective";
         dir = new File(baseDir);
         for (File file : dir.listFiles()) {
             parseQuestion1(file.getAbsolutePath());
@@ -431,10 +434,35 @@ public class ExamTest {
     PaperService paperService;
     @Test
     public void createPaperTest() {
+        List<PaperQuestion> paperQuestions = new ArrayList<>();
+        List<PaperQuestion> paperQuestions1 = getObjective(10);
+        List<PaperQuestion> paperQuestions2 = getSubjective(2);
+        paperQuestions.addAll(paperQuestions1);
+        //paperQuestions.addAll(paperQuestions2);
+
+        int totalScore = paperQuestions.stream().mapToInt(PaperQuestion::getScore).sum();
+        Double passScoreDouble = totalScore * 0.6;
+        int passScore = passScoreDouble.intValue();
+        String paperName = "主客观10题(自测)";
+        paperName = "客观10题";
+        //paperName = "主客观10题";
+
+        PaperAddDto paperAddDto = new PaperAddDto();
+        paperAddDto.setExamName(paperName);
+        paperAddDto.setTotalScore(totalScore);
+        paperAddDto.setPassScore(passScore);
+        paperAddDto.setExamDuration(90);
+        paperAddDto.setStartTime(new Date());
+        paperAddDto.setEndTime(new Date());
+        paperAddDto.setQuestions(paperQuestions);
+        paperService.createExamPaper(paperAddDto);
+    }
+
+    private List<PaperQuestion> getObjective(int size) {
         int questionType = QuestionType.QUESTION1.getCode();
         QuestionQuery questionQuery = new QuestionQuery.Builder()
                 .pageNumber(1)
-                .pageSize(50)
+                .pageSize(size)
                 .type(questionType)
                 .build();
         Page page = questionQuery.getPage();
@@ -447,15 +475,19 @@ public class ExamTest {
             paperQuestions.add(new PaperQuestion(pos, question, score));
         }
 
-        questionType = QuestionType.QUESTION6.getCode();
-        questionQuery = new QuestionQuery.Builder()
+        return paperQuestions;
+    }
+
+    private List<PaperQuestion> getSubjective(int size) {
+        int questionType = QuestionType.QUESTION6.getCode();
+        QuestionQuery questionQuery = new QuestionQuery.Builder()
                 .pageNumber(1)
-                .pageSize(50)
+                .pageSize(size)
                 .type(questionType)
                 .build();
-        page = questionQuery.getPage();
-        questions = questionMapper.findQuestionByPage(page, questionQuery);
-        paperQuestions = new ArrayList<>();
+        Page page = questionQuery.getPage();
+        List<Question> questions = questionMapper.findQuestionByPage(page, questionQuery);
+        List<PaperQuestion> paperQuestions = new ArrayList<>();
         for (int i = 0; i < questions.size(); i++) {
             Question question = questions.get(i);
             int pos = i + 1;
@@ -463,39 +495,23 @@ public class ExamTest {
             paperQuestions.add(new PaperQuestion(pos, question, score));
         }
 
-
-        int totalScore = paperQuestions.stream().mapToInt(PaperQuestion::getScore).sum();
-        Double passScoreDouble = totalScore * 0.6;
-        int passScore = passScoreDouble.intValue();
-
-        PaperAddDto paperAddDto = new PaperAddDto();
-        paperAddDto.setExamName("Exam2025");
-        paperAddDto.setTotalScore(totalScore);
-        paperAddDto.setPassScore(passScore);
-        paperAddDto.setExamDuration(90);
-        paperAddDto.setStartTime(new Date());
-        paperAddDto.setEndTime(new Date());
-        paperAddDto.setQuestions(paperQuestions);
-        paperService.createExamPaper(paperAddDto);
-    }
-
-    private void getPaper(PaperAddDto paperAddDto) {
-        List<Long> questionIdList = paperAddDto.getQuestions().stream()
-                .map(PaperQuestion::getQuestionId)
-                .collect(Collectors.toList());
-        List<Question> questionList = questionMapper.findByQuestionIds(questionIdList);
-        List<Question> list = questionList.stream().map(question -> {
-            return question;
-        }).filter(Objects::nonNull).collect(Collectors.toList());
+        return paperQuestions;
     }
 
     @Test
     public void getPaperAnswerTest() {
         int paperId = 1;
+        //Paper paper = paperMapper.findById(paperId);
+        List<PaperQuestion> paperQuestions = paperQuestionMapper.findByPaperId(paperId);
+
         int resultId = 1;
-        List<PaperAnswer> paperAnswerList = paperAnswerMapper.findByResultId(resultId);
+        //Map<Long, List<Object>> map = getPaperAnswersFromResult(resultId);
+        System.out.println();
+    }
 
+    private Map<Long, List<Object>> getPaperAnswersFromResult(int resultId) {
         Map<Long, List<Object>> map = new HashMap<>();
+        List<PaperAnswer> paperAnswerList = paperAnswerMapper.findByResultId(resultId);
         paperAnswerList.forEach(paperAnswer -> {
             long questionId = paperAnswer.getQuestionId();
             int type = paperAnswer.getQuestionType();
@@ -511,7 +527,6 @@ public class ExamTest {
                         .filter(QuestionOption::getCorrect)
                         .map(QuestionOption::getContent)
                         .collect(Collectors.toList());
-                System.out.println();
             } else {
                 objectList = Arrays.asList(answers);
             }
@@ -519,6 +534,6 @@ public class ExamTest {
             map.put(questionId, objectList);
         });
 
-        System.out.println();
+        return map;
     }
 }