Pārlūkot izejas kodu

3.4.4 update-20250324,bug修改

xiaofei 3 mēneši atpakaļ
vecāks
revīzija
f79c8e639d

+ 2 - 0
distributed-print/install/mysql/upgrade/3.4.4.sql

@@ -352,3 +352,5 @@ CREATE TABLE `mark_archive_student` (
            PRIMARY KEY (`student_id`))
     COMMENT = '考生归档数据表';
 
+ALTER TABLE `mark_paper` ADD COLUMN `archive` TINYINT(1) NULL DEFAULT 0 COMMENT '是否归档,1-已归档' AFTER `merge_marker`;
+

+ 560 - 0
distributed-print/src/main/java/com/qmth/distributed/print/upgrade/DataUpgrade_3_4_4_1.java

@@ -0,0 +1,560 @@
+package com.qmth.distributed.print.upgrade;
+
+import com.alibaba.fastjson.JSON;
+import com.qmth.boot.data.upgrade.annotation.DataUpgradeVersion;
+import com.qmth.boot.data.upgrade.service.DataUpgradeService;
+import com.qmth.boot.data.upgrade.utils.ResourceFileHelper;
+import com.qmth.distributed.print.business.entity.ExamCard;
+import com.qmth.distributed.print.business.entity.ExamCardModelFour;
+import com.qmth.teachcloud.common.bean.dto.mark.PictureConfig;
+import com.qmth.teachcloud.common.entity.BasicExam;
+import com.qmth.teachcloud.common.entity.MarkQuestion;
+import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ExamModelEnum;
+import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.util.ResultUtil;
+import com.qmth.teachcloud.mark.dto.mark.MarkQuestionAnswerVo;
+import com.qmth.teachcloud.mark.dto.mark.manage.MarkerScoreDTO;
+import com.qmth.teachcloud.mark.dto.mark.manage.TaskQuestion;
+import com.qmth.teachcloud.mark.dto.mark.manage.TrackDTO;
+import com.qmth.teachcloud.mark.dto.mark.score.SheetUrlDto;
+import com.qmth.teachcloud.mark.dto.mark.score.StudentObjectiveAnswerDto;
+import com.qmth.teachcloud.mark.dto.mark.score.StudentPaperDetailDto;
+import com.qmth.teachcloud.mark.entity.*;
+import com.qmth.teachcloud.mark.enums.CardSource;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 升级3.4.4后,3.4.3及以前历史数据的归档
+ */
+//@DataUpgradeVersion("3.4.4")
+public class DataUpgrade_3_4_4_1 implements DataUpgradeService {
+
+    private static final Logger log = LoggerFactory.getLogger(DataUpgrade_3_4_4_1.class);
+
+    // 一页1000条
+    private static int PAGE_SIZE = 500;
+
+    @Override
+    public void process(JdbcTemplate jdbcTemplate) {
+        log.info("process...");
+        // 执行升级脚本
+//        this.execUpgradeSql(jdbcTemplate);
+
+        // 执行历史数据归档
+//        this.execDataArchive(jdbcTemplate);
+
+    }
+
+    private void execDataArchive(JdbcTemplate jdbcTemplate) {
+        // 用户数据
+        Map<Long, SysUser> sysUserMap = this.mapSysUserSql(jdbcTemplate);
+
+        List<MarkPaper> markPaperList = this.listMarkPaper(jdbcTemplate);
+        for (MarkPaper markPaper : markPaperList) {
+            Long examId = markPaper.getExamId();
+            BasicExam basicExam = getBasicExam(jdbcTemplate, examId);
+            String paperNumber = markPaper.getPaperNumber();
+            List<MarkStudent> markStudentList = this.listMarkStudent(jdbcTemplate, examId, paperNumber);
+            // 客观题数据
+            Map<String, List<MarkQuestionAnswerVo>> objectiveQuestionMap = this.mapObjectiveMarkQuestion(jdbcTemplate, examId, paperNumber);
+            // 主观题数据
+            List<MarkQuestion> markQuestionList = this.listSubjectiveMarkQuestionSql(jdbcTemplate, examId, paperNumber);
+
+            List<MarkArchiveStudent> markArchiveStudents = new ArrayList<>();
+            for (MarkStudent markStudent : markStudentList) {
+                MarkArchiveStudent markArchiveStudent = new MarkArchiveStudent();
+                markArchiveStudent.setStudentId(markStudent.getId());
+                markArchiveStudent.setExamId(examId);
+                markArchiveStudent.setPaperNumber(paperNumber);
+                markArchiveStudent.setBasicStudentId(markStudent.getBasicStudentId());
+                markArchiveStudent.setStudentCode(markStudent.getStudentCode());
+                markArchiveStudent.setSheetUrls(buildSheetUrls(jdbcTemplate, markStudent));
+                markArchiveStudent.setSubjectiveQuestions(buildSubjectiveQuestions(jdbcTemplate, markStudent, markQuestionList, sysUserMap));
+                markArchiveStudent.setObjectiveQuestions(buildObjectiveQuestions(objectiveQuestionMap, markStudent));
+                markArchiveStudent.setCardContent(getCardContent(jdbcTemplate, markStudent, basicExam));
+                markArchiveStudent.setCreateTime(System.currentTimeMillis());
+                markArchiveStudents.add(markArchiveStudent);
+            }
+            long count = this.batchInsert(jdbcTemplate, markArchiveStudents);
+            if (count == markArchiveStudents.size()) {
+                // 更新归档状态
+                this.updateMarkPaperArchive(jdbcTemplate, markPaper.getId());
+            } else {
+                // 回滚事务
+            }
+        }
+    }
+
+    /**
+     * 电子卡格式信息
+     */
+    private String getCardContent(JdbcTemplate jdbcTemplate, MarkStudent markStudent, BasicExam basicExam) {
+        if (markStudent.getCardNumber() != null) {
+            ScanAnswerCard scanAnswerCard = this.getScanAnswerCard(jdbcTemplate, markStudent.getExamId(), markStudent.getCardNumber());
+            if (scanAnswerCard != null) {
+                if (StringUtils.isNotBlank(scanAnswerCard.getContent())) {
+                    return scanAnswerCard.getContent();
+                } else {
+                    // 自定义卡格式,取电子卡格式的cardId
+                    if (ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
+                        if (scanAnswerCard.getCardId() == null) {
+                            List<ScanAnswerCard> scanAnswerCardWebList = this.listScanAnswerCardWeb(jdbcTemplate, scanAnswerCard.getExamId(), scanAnswerCard.getCoursePaperId(), CardSource.WEB);
+                            if (CollectionUtils.isNotEmpty(scanAnswerCardWebList)) {
+                                ExamCardModelFour examCardModelFour = getExamCardModelFour(jdbcTemplate, scanAnswerCardWebList.get(0).getCardId());
+                                return examCardModelFour == null ? null : examCardModelFour.getContent();
+                            }
+                        } else {
+                            ExamCardModelFour examCardModelFour = getExamCardModelFour(jdbcTemplate, scanAnswerCard.getCardId());
+                            return examCardModelFour == null ? null : examCardModelFour.getContent();
+                        }
+                    } else {
+                        if (scanAnswerCard.getCardId() == null) {
+                            List<ScanAnswerCard> scanAnswerCardWebList = this.listScanAnswerCardWeb(jdbcTemplate, scanAnswerCard.getExamId(), scanAnswerCard.getCoursePaperId(), CardSource.WEB);
+                            if (CollectionUtils.isNotEmpty(scanAnswerCardWebList)) {
+                                ExamCard examCard = getExamCard(jdbcTemplate, scanAnswerCardWebList.get(0).getCardId());
+                                return examCard == null ? null : examCard.getContent();
+                            }
+                        } else {
+                            ExamCard examCard = getExamCard(jdbcTemplate, scanAnswerCard.getCardId());
+                            return examCard == null ? null : examCard.getContent();
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 客观题信息
+     */
+    private String buildObjectiveQuestions(Map<String, List<MarkQuestionAnswerVo>> objectiveQuestionMap, MarkStudent markStudent) {
+        List<String> answers = markStudent.getAnswerList();
+        List<String> answerScores = markStudent.getAnswerScoreList();
+        List<MarkQuestionAnswerVo> questions = objectiveQuestionMap.get(markStudent.getPaperType());
+        int questionCount = questions.size();
+        int answerCount = answers.size();
+        int answerScoreCount = answerScores.size();
+
+        List<StudentObjectiveAnswerDto> answerDtoList = new ArrayList<>();
+        // 已设置客观题
+        int maxCount = Math.max(questionCount, answerCount);
+        for (int i = 0; i < maxCount; i++) {
+            MarkQuestionAnswerVo q = questionCount > i ? questions.get(i) : null;
+            String answer = answerCount > i ? answers.get(i) : "#";
+            String answerScore = answerScoreCount > i ? answerScores.get(i) : "0";
+            StudentObjectiveAnswerDto studentObjectiveAnswerDto = new StudentObjectiveAnswerDto();
+            studentObjectiveAnswerDto.setMainNumber(q != null ? q.getMainNumber() : 0);
+            studentObjectiveAnswerDto.setSubNumber(q != null ? q.getSubNumber() : 0);
+            studentObjectiveAnswerDto.setStandardAnswer(q != null ? q.getAnswer() : null);
+            studentObjectiveAnswerDto.setAnswer(answer);
+            studentObjectiveAnswerDto.setScore(Double.valueOf(answerScore));
+            studentObjectiveAnswerDto.setTotalScore(q != null && q.getTotalScore() != null ? q.getTotalScore() : 0);
+            studentObjectiveAnswerDto.setExist(q != null && q.getTotalScore() != null && q.getTotalScore() > 0);
+            studentObjectiveAnswerDto.setQuestionType(q != null ? q.getQuestionType() : 0);
+            answerDtoList.add(studentObjectiveAnswerDto);
+        }
+        return JSON.toJSONString(answerDtoList);
+    }
+
+    /**
+     * 主观题信息
+     */
+    private String buildSubjectiveQuestions(JdbcTemplate jdbcTemplate, MarkStudent markStudent, List<MarkQuestion> sList, Map<Long, SysUser> sysUserMap) {
+        Long examId = markStudent.getExamId();
+        String paperNumber = markStudent.getPaperNumber();
+        Long studentId = markStudent.getId();
+        List<TaskQuestion> taskQuestions = new ArrayList<>();
+        List<MarkSubjectiveScore> scoreList = this.listMarkSubjectiveScore(jdbcTemplate, studentId);
+        for (int i = 0; i < scoreList.size(); i++) {
+            MarkQuestion question = sList.get(i);
+            String questionNumber = question.getMainNumber() + "." + question.getSubNumber();
+            TaskQuestion step = buildStep(question);
+            // 管理员复核时,默认全部为自己评
+            step.setSelfMark(true);
+            Double score = scoreList.get(i).getScore();
+            if (!scoreList.isEmpty() && scoreList.size() == sList.size()) {
+                step.setMarkerScore(score);
+            }
+            // 增加阅卷轨迹列表获取
+            List<MarkTask> markTaskList = this.listMarkTask(jdbcTemplate, studentId, question.getGroupNumber());
+            // 不管单评还是多评显示所有评卷员给分轨迹
+            for (MarkTask markTask : markTaskList) {
+                for (MarkTrack markTrack : this.listMarkTrack(jdbcTemplate, markTask.getId(), questionNumber)) {
+                    TrackDTO track = new TrackDTO(markTrack);
+                    SysUser user = sysUserMap.get(markTask.getUserId());
+                    track.setUserId(markTask.getUserId());
+                    track.setUserName(user.getRealName() + "(" + user.getLoginName() + ")");
+                    step.addMarkTrack(track);
+                }
+
+                List<MarkHeaderTrack> markHeaderTracks = this.listMarkHeaderTrack(jdbcTemplate, studentId, questionNumber);
+                if (CollectionUtils.isNotEmpty(markHeaderTracks) && markTask.getTaskNumber() == 1) {
+                    for (MarkHeaderTrack markHeaderTrack : markHeaderTracks) {
+                        TrackDTO track = new TrackDTO(markHeaderTrack);
+                        SysUser sysUser = sysUserMap.get(markTask.getHeaderId());
+                        if (sysUser != null) {
+                            track.setUserId(sysUser.getId());
+                            track.setUserName(sysUser.getRealName() + "(" + sysUser.getLoginName() + ")");
+                        }
+                        track.setHeaderType(markTask.getStatus());
+                        step.addHeadTrack(track);
+                    }
+                }
+
+                // 普通模式无轨迹数据。单独处理评卷员每题得分
+                if (CollectionUtils.isEmpty(step.getMarkerTrackList()) && markTask.getMarkerScore() != null) {
+                    // 评卷员
+                    MarkerScoreDTO markerScoreDTO = new MarkerScoreDTO();
+                    markerScoreDTO.setUserId(markTask.getUserId());
+                    SysUser markerUser = sysUserMap.get(markTask.getUserId());
+                    if (markerUser != null) {
+                        markerScoreDTO.setLoginName(markerUser.getLoginName());
+                        markerScoreDTO.setUserName(markerUser.getRealName());
+                    }
+                    markerScoreDTO.setScore(score);
+                    markerScoreDTO.setHeader(false);
+                    step.addMarkerList(markerScoreDTO);
+
+                    // 科组长
+                    if (CollectionUtils.isEmpty(markHeaderTracks) && markTask.getTaskNumber() == 1) {
+                        if (!markTask.getMarkerScore().equals(score)) {
+                            MarkerScoreDTO headerScoreDTO = new MarkerScoreDTO();
+                            headerScoreDTO.setUserId(markTask.getHeaderId());
+                            SysUser headerUser = sysUserMap.get(markTask.getHeaderId());
+                            if (headerUser != null) {
+                                headerScoreDTO.setLoginName(headerUser.getLoginName());
+                                headerScoreDTO.setUserName(headerUser.getRealName());
+                            }
+                            headerScoreDTO.setScore(score);
+                            headerScoreDTO.setHeader(true);
+                            headerScoreDTO.setHeaderType(markTask.getStatus());
+                            step.addMarkerList(headerScoreDTO);
+                        }
+                    }
+                }
+            }
+            taskQuestions.add(step);
+        }
+        return JSON.toJSONString(taskQuestions);
+    }
+
+    private TaskQuestion buildStep(MarkQuestion question) {
+        TaskQuestion step = new TaskQuestion();
+        step.setMainNumber(question.getMainNumber());
+        step.setSubNumber(question.getSubNumber());
+        step.setQuestionType(question.getQuestionType());
+        step.setPicList(StringUtils.isNotBlank(question.getPicList()) ? JSON.parseArray(question.getPicList(), PictureConfig.class) : null);
+        step.setQuestionId(question.getId());
+        step.setTitle(question.getMainTitle());
+        step.setDefaultScore(0d);
+        step.setMaxScore(question.getTotalScore());
+        step.setMinScore(0d);
+        step.setIntervalScore(question.getIntervalScore());
+        step.setUncalculate(false);
+        return step;
+    }
+
+    /**
+     * 图片信息
+     */
+    private String buildSheetUrls(JdbcTemplate jdbcTemplate, MarkStudent markStudent) {
+        // 原图
+        List<SheetUrlDto> sheetUrls = new ArrayList<>();
+        List<StudentPaperDetailDto> studentPaperDetailDtoList = this.listData(jdbcTemplate, getSheetUrlsSql(markStudent.getId()), StudentPaperDetailDto.class);
+        for (int i = 0; i < studentPaperDetailDtoList.size(); i++) {
+            StudentPaperDetailDto studentPaperDetailDto = studentPaperDetailDtoList.get(i);
+            sheetUrls.add(new SheetUrlDto(
+                    2 * (studentPaperDetailDto.getPaperIndex() - 1) + studentPaperDetailDto.getPageIndex(),
+                    studentPaperDetailDto.getSheetPath(),
+                    studentPaperDetailDto.getRecogData()));
+        }
+        return JSON.toJSONString(sheetUrls);
+    }
+
+    private void execUpgradeSql(JdbcTemplate jdbcTemplate) {
+        String rootPath = System.getProperty("user.dir");
+        StringJoiner sj = new StringJoiner(File.separator);
+        sj.add(rootPath).add("distributed-print").add("install").add("mysql").add("upgrade").add("3.4.4.sql");
+        try {
+            FileInputStream inputStream = new FileInputStream(sj.toString());
+            String[] sqlList = StringUtils.split(ResourceFileHelper.readContent(inputStream), ";");
+            Arrays.stream(sqlList).filter(StringUtils::isNotBlank).forEach(sql -> {
+                log.info(sql);
+                jdbcTemplate.execute(sql);
+            });
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private <T> T getOne(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass) {
+        //将查询的语句封装到List集合中,集合中存储每一个员工实体
+        T t = null;
+        try {
+            t = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(tClass));
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("查询失败:" + e.getMessage());
+        }
+        return t;
+    }
+
+    private <T> List<T> listData(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass) {
+        //将查询的语句封装到List集合中,集合中存储每一个员工实体
+        List<T> list = new ArrayList<>();
+        try {
+            list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(tClass));
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("查询失败:" + e.getMessage());
+        }
+        return list;
+    }
+
+    private int update(JdbcTemplate jdbcTemplate, String sql) {
+        try {
+            return jdbcTemplate.update(sql);
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("更新失败:" + e.getMessage());
+        }
+    }
+
+    private <T> List<T> pageData(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass) {
+        if (!sql.contains("limit")) {
+            sql += " limit ?,?";
+        }
+        //将查询的语句封装到List集合中,集合中存储每一个员工实体
+        List<T> listAll = new ArrayList<>();
+        try {
+            List<T> list;
+            int pageNumber = 0;
+            do {
+                int offset = pageNumber * PAGE_SIZE + PAGE_SIZE;
+                list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(tClass), pageNumber, offset);
+                if (CollectionUtils.isNotEmpty(list)) {
+                    listAll.addAll(list);
+                    pageNumber++;
+                }
+            } while (CollectionUtils.isNotEmpty(list));
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("查询失败:" + e.getMessage());
+        }
+        return listAll;
+    }
+
+    private <T> List<T> pageData(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass, int pageNumber) {
+        //将查询的语句封装到List集合中,集合中存储每一个员工实体
+        List<T> listAll = new ArrayList<>();
+        try {
+            int offset = pageNumber * PAGE_SIZE + PAGE_SIZE;
+            List<T> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(tClass), pageNumber, offset);
+            if (CollectionUtils.isNotEmpty(list)) {
+                listAll.addAll(list);
+            }
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("查询失败:" + e.getMessage());
+        }
+        return listAll;
+    }
+
+    private String getSheetUrlsSql(Long studentId) {
+        StringBuffer sql = new StringBuffer();
+        sql.append("SELECT                                                      ");
+        sql.append("ssp.student_id studentId,                                   ");
+        sql.append("ssp.paper_index paperIndex,                                 ");
+        sql.append("ssp.paper_id paperId,                                       ");
+        sql.append("sp.card_number cardNumber,                                  ");
+        sql.append("spp.page_index pageIndex,                                   ");
+        sql.append("spp.sheet_path sheetPath,                                   ");
+        sql.append("spp.recog_data recogData                                    ");
+        sql.append("FROM                                                        ");
+        sql.append("       (SELECT                                              ");
+        sql.append("               student_id, paper_index, paper_id            ");
+        sql.append("                FROM                                        ");
+        sql.append("               scan_student_paper                           ");
+        sql.append("                WHERE                                       ");
+        sql.append("                student_id = " + studentId + ") ssp         ");
+        sql.append("        JOIN                                                ");
+        sql.append("scan_paper sp ON ssp.paper_id = sp.id                       ");
+        sql.append("AND ssp.paper_index = sp.number                             ");
+        sql.append("JOIN                                                        ");
+        sql.append("scan_paper_page spp ON sp.id = spp.paper_id                 ");
+        sql.append("ORDER BY ssp.paper_index , spp.page_index                   ");
+        return sql.toString();
+    }
+
+    private Map<String, List<MarkQuestionAnswerVo>> mapObjectiveMarkQuestion(JdbcTemplate jdbcTemplate, Long examId, String paperNumber) {
+        StringBuffer sql = new StringBuffer();
+        sql.append(" SELECT                                                                     ");
+        sql.append("     mqa.paper_type,                                                        ");
+        sql.append("     mqa.answer,                                                            ");
+        sql.append("     mqa.objective_policy,                                                  ");
+        sql.append("     mqa.objective_policy_score,                                            ");
+        sql.append("     mq.main_number,                                                        ");
+        sql.append("     mq.sub_number,                                                         ");
+        sql.append("     mq.total_score,                                                        ");
+        sql.append("     mq.question_type                                                       ");
+        sql.append(" FROM                                                                       ");
+        sql.append("     (SELECT                                                                ");
+        sql.append("         *                                                                  ");
+        sql.append("     FROM                                                                   ");
+        sql.append("         mark_question                                                      ");
+        sql.append("     WHERE                                                                  ");
+        sql.append("         exam_id = " + examId + " AND paper_number = " + paperNumber + "    ");
+        sql.append("             AND objective = TRUE) mq                                       ");
+        sql.append("         LEFT JOIN                                                          ");
+        sql.append("     (SELECT                                                                ");
+        sql.append("         *                                                                  ");
+        sql.append("     FROM                                                                   ");
+        sql.append("         mark_question_answer                                               ");
+        sql.append("     WHERE                                                                  ");
+        sql.append("         exam_id = " + examId + " AND paper_number = " + paperNumber + ") mqa    ");
+        sql.append("       ON mq.main_number = mqa.main_number                                  ");
+        sql.append("         AND mq.sub_number = mqa.sub_number                                 ");
+        sql.append(" ORDER BY mq.main_number , mq.sub_number                                    ");
+
+        List<MarkQuestionAnswerVo> questions = this.listData(jdbcTemplate, sql.toString(), MarkQuestionAnswerVo.class);
+        Map<String, List<MarkQuestionAnswerVo>> objectiveQuestionMap = questions.stream().collect(Collectors.groupingBy(MarkQuestionAnswerVo::getPaperType));
+        return objectiveQuestionMap;
+    }
+
+    private List<MarkQuestion> listSubjectiveMarkQuestionSql(JdbcTemplate jdbcTemplate, Long examId, String paperNumber) {
+        StringBuffer sql = new StringBuffer();
+        sql.append(" SELECT                                                     ");
+        sql.append("     *                                                      ");
+        sql.append(" FROM                                                       ");
+        sql.append("     mark_question mq                                       ");
+        sql.append(" WHERE                                                      ");
+        sql.append("     mq.exam_id = " + examId + " AND mq.paper_number = " + paperNumber + "                 ");
+        sql.append("         AND mq.objective = FALSE                           ");
+        sql.append(" ORDER BY mq.main_number , mq.sub_number                    ");
+        return this.listData(jdbcTemplate, sql.toString(), MarkQuestion.class);
+    }
+
+    private List<MarkSubjectiveScore> listMarkSubjectiveScore(JdbcTemplate jdbcTemplate, Long studentId) {
+        StringBuffer sql = new StringBuffer();
+        sql.append(" SELECT                                                         ");
+        sql.append("     *                                                          ");
+        sql.append(" FROM                                                           ");
+        sql.append("     mark_subjective_score mss                                  ");
+        sql.append(" WHERE                                                          ");
+        sql.append("     mss.student_id = " + studentId + "                         ");
+        sql.append(" ORDER BY mss.main_number , mss.sub_number                      ");
+        return this.listData(jdbcTemplate, sql.toString(), MarkSubjectiveScore.class);
+    }
+
+    private List<MarkGroup> listMarkGroup(JdbcTemplate jdbcTemplate, Long examId, String paperNumber) {
+        String sql = "select * from mark_group where exam_id = " + examId + " and paper_number = '" + paperNumber + "'";
+        return this.listData(jdbcTemplate, sql, MarkGroup.class);
+    }
+
+    private List<MarkTask> listMarkTask(JdbcTemplate jdbcTemplate, Long studentId, Integer groupNumber) {
+        StringBuffer sql = new StringBuffer();
+        sql.append(" SELECT                                                             ");
+        sql.append("     *                                                              ");
+        sql.append(" FROM                                                               ");
+        sql.append("     mark_task mt                                                   ");
+        sql.append(" WHERE                                                              ");
+        sql.append("     mt.student_id = " + studentId + " AND mt.group_number = " + groupNumber + "  ");
+        return this.listData(jdbcTemplate, sql.toString(), MarkTask.class);
+    }
+
+    private List<MarkTrack> listMarkTrack(JdbcTemplate jdbcTemplate, Long taskId, String questionNumber) {
+        String sql = "select * from mark_track where task_id = " + taskId + " and question_number = '" + questionNumber + "'";
+        return this.listData(jdbcTemplate, sql, MarkTrack.class);
+    }
+
+    private List<MarkHeaderTrack> listMarkHeaderTrack(JdbcTemplate jdbcTemplate, Long studentId, String questionNumber) {
+        String sql = "select * from mark_header_track where task_id = " + studentId + " and question_number = '" + questionNumber + "' order by number";
+        return this.listData(jdbcTemplate, sql, MarkHeaderTrack.class);
+    }
+
+    private Map<Long, SysUser> mapSysUserSql(JdbcTemplate jdbcTemplate) {
+        String sql = "select * from sys_user";
+        List<SysUser> sysUserList = this.listData(jdbcTemplate, sql, SysUser.class);
+        Map<Long, SysUser> sysUserMap = sysUserList.stream().collect(Collectors.toMap(m -> m.getId(), Function.identity()));
+        return sysUserMap;
+    }
+
+    private List<MarkPaper> listMarkPaper(JdbcTemplate jdbcTemplate) {
+        String sql = "select * from mark_paper where status = 'FINISH'";
+        return this.listData(jdbcTemplate, sql, MarkPaper.class);
+    }
+
+    private List<MarkStudent> listMarkStudent(JdbcTemplate jdbcTemplate, Long examId, String paperNumber) {
+        String sql = "select * from mark_student where exam_id = " + examId + " and paper_number = '" + paperNumber + "'";
+        return this.listData(jdbcTemplate, sql, MarkStudent.class);
+    }
+
+    private ScanAnswerCard getScanAnswerCard(JdbcTemplate jdbcTemplate, Long examId, Integer cardNumber) {
+        String sql = "select * from scan_answer_card where exam_id = " + examId + " and number = '" + cardNumber + "'";
+        return this.getOne(jdbcTemplate, sql, ScanAnswerCard.class);
+    }
+
+    private List<ScanAnswerCard> listScanAnswerCardWeb(JdbcTemplate jdbcTemplate, Long examId, String coursePaperId, CardSource source) {
+        String sql = "select * from scan_answer_card where exam_id = " + examId + " and course_paper_id = '" + coursePaperId + "' and source = '" + source + "'";
+        return this.listData(jdbcTemplate, sql, ScanAnswerCard.class);
+    }
+
+    private BasicExam getBasicExam(JdbcTemplate jdbcTemplate, Long examId) {
+        String sql = "select * from basic_exam where id = " + examId;
+        return this.getOne(jdbcTemplate, sql, BasicExam.class);
+    }
+
+    private ExamCard getExamCard(JdbcTemplate jdbcTemplate, Long cardId) {
+        String sql = "select * from exam_card where id = " + cardId;
+        return this.getOne(jdbcTemplate, sql, ExamCard.class);
+    }
+
+    private ExamCardModelFour getExamCardModelFour(JdbcTemplate jdbcTemplate, Long examId) {
+        String sql = "select * from exam_card_model_four where id = " + examId;
+        return this.getOne(jdbcTemplate, sql, ExamCardModelFour.class);
+    }
+
+    private int updateMarkPaperArchive(JdbcTemplate jdbcTemplate, Long id) {
+        String sql = "update mark_paper set archive = 1 where id = " + id;
+        return this.update(jdbcTemplate, sql);
+    }
+
+    private long batchInsert(JdbcTemplate jdbcTemplate, List<MarkArchiveStudent> markArchiveStudents) {
+        String sql = "insert into mark_archive_student(student_id, exam_id, paper_number, student_code, basic_student_id, sheet_urls, subjective_questions, objective_questions, card_content, create_time) values (?,?,?,?,?,?,?,?,?,?)";
+        int[] ints = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
+            @Override
+            public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
+                final MarkArchiveStudent mas = markArchiveStudents.get(i);
+                // 参数赋值的时候,序号是从 1 开始的,这一点要注意
+                preparedStatement.setLong(1, mas.getStudentId());
+                preparedStatement.setLong(2, mas.getExamId());
+                preparedStatement.setString(3, mas.getPaperNumber());
+                preparedStatement.setString(4, mas.getStudentCode());
+                preparedStatement.setLong(5, mas.getBasicStudentId());
+                preparedStatement.setString(6, mas.getSheetUrls());
+                preparedStatement.setString(7, mas.getSubjectiveQuestions());
+                preparedStatement.setString(8, mas.getObjectiveQuestions());
+                preparedStatement.setString(9, mas.getCardContent());
+                preparedStatement.setLong(10, System.currentTimeMillis());
+            }
+
+            @Override
+            public int getBatchSize() {
+                return markArchiveStudents.size();
+            }
+        });
+        return Arrays.stream(ints).mapToLong(m -> m).sum();
+    }
+}

+ 139 - 6
distributed-print/src/main/java/com/qmth/distributed/print/upgrade/DataUpgrade_3_4_4.java → distributed-print/src/main/java/com/qmth/distributed/print/upgrade/DataUpgrade_3_4_4_2.java

@@ -4,9 +4,13 @@ import com.alibaba.fastjson.JSON;
 import com.qmth.boot.data.upgrade.annotation.DataUpgradeVersion;
 import com.qmth.boot.data.upgrade.service.DataUpgradeService;
 import com.qmth.boot.data.upgrade.utils.ResourceFileHelper;
+import com.qmth.distributed.print.business.entity.ExamCard;
+import com.qmth.distributed.print.business.entity.ExamCardModelFour;
 import com.qmth.teachcloud.common.bean.dto.mark.PictureConfig;
+import com.qmth.teachcloud.common.entity.BasicExam;
 import com.qmth.teachcloud.common.entity.MarkQuestion;
 import com.qmth.teachcloud.common.entity.SysUser;
+import com.qmth.teachcloud.common.enums.ExamModelEnum;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
 import com.qmth.teachcloud.mark.dto.mark.MarkQuestionAnswerVo;
 import com.qmth.teachcloud.mark.dto.mark.manage.MarkerScoreDTO;
@@ -16,24 +20,31 @@ import com.qmth.teachcloud.mark.dto.mark.score.SheetUrlDto;
 import com.qmth.teachcloud.mark.dto.mark.score.StudentObjectiveAnswerDto;
 import com.qmth.teachcloud.mark.dto.mark.score.StudentPaperDetailDto;
 import com.qmth.teachcloud.mark.entity.*;
+import com.qmth.teachcloud.mark.enums.CardSource;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+/**
+ * 升级3.4.4后,新版本数据的归档
+ */
 @DataUpgradeVersion("3.4.4")
-public class DataUpgrade_3_4_4 implements DataUpgradeService {
+public class DataUpgrade_3_4_4_2 implements DataUpgradeService {
 
-    private static final Logger log = LoggerFactory.getLogger(DataUpgrade_3_4_4.class);
+    private static final Logger log = LoggerFactory.getLogger(DataUpgrade_3_4_4_2.class);
 
     // 一页1000条
     private static int PAGE_SIZE = 500;
@@ -56,6 +67,7 @@ public class DataUpgrade_3_4_4 implements DataUpgradeService {
         List<MarkPaper> markPaperList = this.listMarkPaper(jdbcTemplate);
         for (MarkPaper markPaper : markPaperList) {
             Long examId = markPaper.getExamId();
+            BasicExam basicExam = getBasicExam(jdbcTemplate, examId);
             String paperNumber = markPaper.getPaperNumber();
             List<MarkStudent> markStudentList = this.listMarkStudent(jdbcTemplate, examId, paperNumber);
             // 客观题数据
@@ -63,6 +75,7 @@ public class DataUpgrade_3_4_4 implements DataUpgradeService {
             // 主观题数据
             List<MarkQuestion> markQuestionList = this.listSubjectiveMarkQuestionSql(jdbcTemplate, examId, paperNumber);
 
+            List<MarkArchiveStudent> markArchiveStudents = new ArrayList<>();
             for (MarkStudent markStudent : markStudentList) {
                 MarkArchiveStudent markArchiveStudent = new MarkArchiveStudent();
                 markArchiveStudent.setStudentId(markStudent.getId());
@@ -73,8 +86,16 @@ public class DataUpgrade_3_4_4 implements DataUpgradeService {
                 markArchiveStudent.setSheetUrls(buildSheetUrls(jdbcTemplate, markStudent));
                 markArchiveStudent.setSubjectiveQuestions(buildSubjectiveQuestions(jdbcTemplate, markStudent, markQuestionList, sysUserMap));
                 markArchiveStudent.setObjectiveQuestions(buildObjectiveQuestions(objectiveQuestionMap, markStudent));
-                markArchiveStudent.setCardContent(getCardContent(jdbcTemplate, markStudent));
+                markArchiveStudent.setCardContent(getCardContent(jdbcTemplate, markStudent, basicExam));
                 markArchiveStudent.setCreateTime(System.currentTimeMillis());
+                markArchiveStudents.add(markArchiveStudent);
+            }
+            long count = this.batchInsert(jdbcTemplate, markArchiveStudents);
+            if (count == markArchiveStudents.size()) {
+                // 更新归档状态
+                this.updateMarkPaperArchive(jdbcTemplate, markPaper.getId());
+            } else {
+                // 回滚事务
             }
         }
     }
@@ -82,7 +103,40 @@ public class DataUpgrade_3_4_4 implements DataUpgradeService {
     /**
      * 电子卡格式信息
      */
-    private String getCardContent(JdbcTemplate jdbcTemplate, MarkStudent markStudent) {
+    private String getCardContent(JdbcTemplate jdbcTemplate, MarkStudent markStudent, BasicExam basicExam) {
+        if (markStudent.getCardNumber() != null) {
+            ScanAnswerCard scanAnswerCard = this.getScanAnswerCard(jdbcTemplate, markStudent.getExamId(), markStudent.getCardNumber());
+            if (scanAnswerCard != null) {
+                if (StringUtils.isNotBlank(scanAnswerCard.getContent())) {
+                    return scanAnswerCard.getContent();
+                } else {
+                    // 自定义卡格式,取电子卡格式的cardId
+                    if (ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
+                        if (scanAnswerCard.getCardId() == null) {
+                            List<ScanAnswerCard> scanAnswerCardWebList = this.listScanAnswerCardWeb(jdbcTemplate, scanAnswerCard.getExamId(), scanAnswerCard.getCoursePaperId(), CardSource.WEB);
+                            if (CollectionUtils.isNotEmpty(scanAnswerCardWebList)) {
+                                ExamCardModelFour examCardModelFour = getExamCardModelFour(jdbcTemplate, scanAnswerCardWebList.get(0).getCardId());
+                                return examCardModelFour == null ? null : examCardModelFour.getContent();
+                            }
+                        } else {
+                            ExamCardModelFour examCardModelFour = getExamCardModelFour(jdbcTemplate, scanAnswerCard.getCardId());
+                            return examCardModelFour == null ? null : examCardModelFour.getContent();
+                        }
+                    } else {
+                        if (scanAnswerCard.getCardId() == null) {
+                            List<ScanAnswerCard> scanAnswerCardWebList = this.listScanAnswerCardWeb(jdbcTemplate, scanAnswerCard.getExamId(), scanAnswerCard.getCoursePaperId(), CardSource.WEB);
+                            if (CollectionUtils.isNotEmpty(scanAnswerCardWebList)) {
+                                ExamCard examCard = getExamCard(jdbcTemplate, scanAnswerCardWebList.get(0).getCardId());
+                                return examCard == null ? null : examCard.getContent();
+                            }
+                        } else {
+                            ExamCard examCard = getExamCard(jdbcTemplate, scanAnswerCard.getCardId());
+                            return examCard == null ? null : examCard.getContent();
+                        }
+                    }
+                }
+            }
+        }
         return null;
     }
 
@@ -245,6 +299,24 @@ public class DataUpgrade_3_4_4 implements DataUpgradeService {
         }
     }
 
+    private <T> T getOne(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass) {
+        //将查询的语句封装到List集合中,集合中存储每一个员工实体
+        T t = null;
+        try {
+            t = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(tClass));
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("查询失败:" + e.getMessage());
+        }
+        return t;
+    }
+
+    private int update(JdbcTemplate jdbcTemplate, String sql) {
+        try {
+            return jdbcTemplate.update(sql);
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception("更新失败:" + e.getMessage());
+        }
+    }
 
     private <T> List<T> listData(JdbcTemplate jdbcTemplate, String sql, Class<T> tClass) {
         //将查询的语句封装到List集合中,集合中存储每一个员工实体
@@ -311,7 +383,7 @@ public class DataUpgrade_3_4_4 implements DataUpgradeService {
         sql.append("                FROM                                        ");
         sql.append("               scan_student_paper                           ");
         sql.append("                WHERE                                       ");
-        sql.append("                student_id = " + studentId + ")             ");
+        sql.append("                student_id = " + studentId + ") ssp         ");
         sql.append("        JOIN                                                ");
         sql.append("scan_paper sp ON ssp.paper_id = sp.id                       ");
         sql.append("AND ssp.paper_index = sp.number                             ");
@@ -324,10 +396,14 @@ public class DataUpgrade_3_4_4 implements DataUpgradeService {
     private Map<String, List<MarkQuestionAnswerVo>> mapObjectiveMarkQuestion(JdbcTemplate jdbcTemplate, Long examId, String paperNumber) {
         StringBuffer sql = new StringBuffer();
         sql.append(" SELECT                                                                     ");
+        sql.append("     mqa.paper_type,                                                        ");
         sql.append("     mqa.answer,                                                            ");
         sql.append("     mqa.objective_policy,                                                  ");
         sql.append("     mqa.objective_policy_score,                                            ");
-        sql.append("     mq.*                                                                   ");
+        sql.append("     mq.main_number,                                                        ");
+        sql.append("     mq.sub_number,                                                         ");
+        sql.append("     mq.total_score,                                                        ");
+        sql.append("     mq.question_type                                                       ");
         sql.append(" FROM                                                                       ");
         sql.append("     (SELECT                                                                ");
         sql.append("         *                                                                  ");
@@ -404,4 +480,61 @@ public class DataUpgrade_3_4_4 implements DataUpgradeService {
         String sql = "select * from mark_student where exam_id = " + examId + " and paper_number = '" + paperNumber + "'";
         return this.listData(jdbcTemplate, sql, MarkStudent.class);
     }
+
+    private ScanAnswerCard getScanAnswerCard(JdbcTemplate jdbcTemplate, Long examId, Integer cardNumber) {
+        String sql = "select * from scan_answer_card where exam_id = " + examId + " and number = '" + cardNumber + "'";
+        return this.getOne(jdbcTemplate, sql, ScanAnswerCard.class);
+    }
+
+    private List<ScanAnswerCard> listScanAnswerCardWeb(JdbcTemplate jdbcTemplate, Long examId, String coursePaperId, CardSource source) {
+        String sql = "select * from scan_answer_card where exam_id = " + examId + " and course_paper_id = '" + coursePaperId + "' and source = '" + source + "'";
+        return this.listData(jdbcTemplate, sql, ScanAnswerCard.class);
+    }
+
+    private BasicExam getBasicExam(JdbcTemplate jdbcTemplate, Long examId) {
+        String sql = "select * from basic_exam where id = " + examId;
+        return this.getOne(jdbcTemplate, sql, BasicExam.class);
+    }
+
+    private ExamCard getExamCard(JdbcTemplate jdbcTemplate, Long cardId) {
+        String sql = "select * from exam_card where id = " + cardId;
+        return this.getOne(jdbcTemplate, sql, ExamCard.class);
+    }
+
+    private ExamCardModelFour getExamCardModelFour(JdbcTemplate jdbcTemplate, Long examId) {
+        String sql = "select * from exam_card_model_four where id = " + examId;
+        return this.getOne(jdbcTemplate, sql, ExamCardModelFour.class);
+    }
+
+    private int updateMarkPaperArchive(JdbcTemplate jdbcTemplate, Long id) {
+        String sql = "update mark_paper set archive = 1 where id = " + id;
+        return this.update(jdbcTemplate, sql);
+    }
+
+    private long batchInsert(JdbcTemplate jdbcTemplate, List<MarkArchiveStudent> markArchiveStudents) {
+        String sql = "insert into mark_archive_student(student_id, exam_id, paper_number, student_code, basic_student_id, sheet_urls, subjective_questions, objective_questions, card_content, create_time) values (?,?,?,?,?,?,?,?,?,?)";
+        int[] ints = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
+            @Override
+            public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
+                final MarkArchiveStudent mas = markArchiveStudents.get(i);
+                // 参数赋值的时候,序号是从 1 开始的,这一点要注意
+                preparedStatement.setLong(1, mas.getStudentId());
+                preparedStatement.setLong(2, mas.getExamId());
+                preparedStatement.setString(3, mas.getPaperNumber());
+                preparedStatement.setString(4, mas.getStudentCode());
+                preparedStatement.setLong(5, mas.getBasicStudentId());
+                preparedStatement.setString(6, mas.getSheetUrls());
+                preparedStatement.setString(7, mas.getSubjectiveQuestions());
+                preparedStatement.setString(8, mas.getObjectiveQuestions());
+                preparedStatement.setString(9, mas.getCardContent());
+                preparedStatement.setLong(10, System.currentTimeMillis());
+            }
+
+            @Override
+            public int getBatchSize() {
+                return markArchiveStudents.size();
+            }
+        });
+        return Arrays.stream(ints).mapToLong(m -> m).sum();
+    }
 }

+ 11 - 0
teachcloud-common/src/main/java/com/qmth/teachcloud/common/entity/MarkQuestion.java

@@ -48,6 +48,9 @@ public class MarkQuestion extends BaseEntity implements Serializable {
     @ApiModelProperty(value = "是否客观题")
     private Boolean objective;
 
+    @ApiModelProperty(value = "分组号")
+    private Integer groupNumber;
+
     @ApiModelProperty(value = "大题号")
     private Integer mainNumber;
 
@@ -162,6 +165,14 @@ public class MarkQuestion extends BaseEntity implements Serializable {
         this.objective = objective;
     }
 
+    public Integer getGroupNumber() {
+        return groupNumber;
+    }
+
+    public void setGroupNumber(Integer groupNumber) {
+        this.groupNumber = groupNumber;
+    }
+
     public Integer getMainNumber() {
         return mainNumber;
     }

+ 327 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkGroup.java

@@ -0,0 +1,327 @@
+package com.qmth.teachcloud.mark.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.github.jeffreyning.mybatisplus.anno.MppMultiId;
+import com.qmth.teachcloud.common.entity.MarkQuestion;
+import com.qmth.teachcloud.mark.dto.mark.ScoreItem;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * <p>
+ * 评卷分组表
+ * </p>
+ *
+ * @author xf
+ * @since 2023-09-22
+ */
+@TableName("mark_group")
+@ApiModel(value = "MarkGroup对象", description = "评卷分组表")
+public class MarkGroup implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "考试ID")
+    @MppMultiId(value = "exam_id")
+    private Long examId;
+
+    @ApiModelProperty(value = "课程ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    @TableField(value = "course_id", updateStrategy = FieldStrategy.IGNORED)
+    private Long courseId;
+
+    @ApiModelProperty(value = "课程代码")
+    private String courseCode;
+
+    @ApiModelProperty(value = "课程名称")
+    private String courseName;
+
+    @ApiModelProperty(value = "试卷编号")
+    @MppMultiId(value = "paper_number")
+    private String paperNumber;
+
+    @ApiModelProperty(value = "序号")
+    @MppMultiId(value = "number")
+    private Integer number;
+
+    @ApiModelProperty(value = "小图配置")
+    private String picList;
+
+    @ApiModelProperty(value = "满分")
+    private Double totalScore;
+
+
+    @ApiModelProperty(value = "是否开启双评")
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private Boolean doubleEnable;
+
+    @ApiModelProperty(value = "双评比例")
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private Double doubleRate;
+
+    @ApiModelProperty(value = "仲裁阈值")
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private Double arbitrateThreshold;
+
+    @ApiModelProperty(value = "任务总量")
+    private Integer taskCount;
+
+    @ApiModelProperty(value = "已评数量")
+    private Integer markedCount;
+
+    @ApiModelProperty(value = "剩余数量")
+    private Integer leftCount;
+
+    /**
+     * 大题号集合(逗号分隔)
+     */
+    @TableField(exist = false)
+    private String mainNumber;
+    /**
+     * 大题名称集合(逗号分隔)
+     */
+    @TableField(exist = false)
+    private String title;
+    /**
+     * 大题名称+小题号集合(逗号分隔)
+     */
+    @TableField(exist = false)
+    private String questionTitle;
+    /**
+     * 大题号+小题号集合(逗号分隔)
+     */
+    @TableField(exist = false)
+    private String groupQuestions;
+    /**
+     * 主观题小题满分集合(逗号分隔)
+     */
+    @TableField(exist = false)
+    private String scoreList;
+
+    @TableField(exist = false)
+    private double markScore;
+
+    @TableField(exist = false)
+    private List<ScoreItem> markScoreDetail;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public Long getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Long courseId) {
+        this.courseId = courseId;
+    }
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getPaperNumber() {
+        return paperNumber;
+    }
+
+    public void setPaperNumber(String paperNumber) {
+        this.paperNumber = paperNumber;
+    }
+
+    public Integer getNumber() {
+        return number;
+    }
+
+    public void setNumber(Integer number) {
+        this.number = number;
+    }
+
+    public String getPicList() {
+        return picList;
+    }
+
+    public void setPicList(String picList) {
+        this.picList = picList;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public Boolean getDoubleEnable() {
+        return doubleEnable;
+    }
+
+    public void setDoubleEnable(Boolean doubleEnable) {
+        this.doubleEnable = doubleEnable;
+    }
+
+    public Double getDoubleRate() {
+        return doubleRate;
+    }
+
+    public void setDoubleRate(Double doubleRate) {
+        this.doubleRate = doubleRate;
+    }
+
+    public Double getArbitrateThreshold() {
+        return arbitrateThreshold;
+    }
+
+    public void setArbitrateThreshold(Double arbitrateThreshold) {
+        this.arbitrateThreshold = arbitrateThreshold;
+    }
+
+    public Integer getTaskCount() {
+        return taskCount;
+    }
+
+    public void setTaskCount(Integer taskCount) {
+        this.taskCount = taskCount;
+    }
+
+    public Integer getMarkedCount() {
+        return markedCount;
+    }
+
+    public void setMarkedCount(Integer markedCount) {
+        this.markedCount = markedCount;
+    }
+
+    public Integer getLeftCount() {
+        return leftCount;
+    }
+
+    public void setLeftCount(Integer leftCount) {
+        this.leftCount = leftCount;
+    }
+
+    public String getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(String mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getQuestionTitle() {
+        return questionTitle;
+    }
+
+    public void setQuestionTitle(String questionTitle) {
+        this.questionTitle = questionTitle;
+    }
+
+    public String getGroupQuestions() {
+        return groupQuestions;
+    }
+
+    public void setGroupQuestions(String groupQuestions) {
+        this.groupQuestions = groupQuestions;
+    }
+
+    public String getScoreList() {
+        return scoreList;
+    }
+
+    public void setScoreList(String scoreList) {
+        this.scoreList = scoreList;
+    }
+
+    public double getMarkScore() {
+        return markScore;
+    }
+
+    public void setMarkScore(double markScore) {
+        this.markScore = markScore;
+    }
+
+    public List<ScoreItem> getMarkScoreDetail() {
+        return markScoreDetail;
+    }
+
+    public void setMarkScoreDetail(List<ScoreItem> markScoreDetail) {
+        this.markScoreDetail = markScoreDetail;
+    }
+
+    public void setQuestionList(List<MarkQuestion> questionList) {
+        DecimalFormat format = new DecimalFormat("####.##");
+        Set<Integer> mainNumbers = new LinkedHashSet<>();
+        Set<String> mainTitles = new LinkedHashSet<>();
+        Set<String> questionTitles = new LinkedHashSet<>();
+        Set<String> groupQuestions = new LinkedHashSet<>();
+        StringBuilder score = new StringBuilder();
+        for (MarkQuestion question : questionList) {
+            if (score.length() > 0) {
+                score.append(",");
+            }
+            score.append(format.format(question.getTotalScore()));
+            mainNumbers.add(question.getMainNumber());
+            mainTitles.add(question.getMainTitle());
+            questionTitles.add(question.getMainTitle() + '-' + question.getSubNumber());
+            groupQuestions.add(String.valueOf(question.getMainNumber()) + '-' + question.getSubNumber());
+        }
+        this.mainNumber = StringUtils.join(mainNumbers, ",");
+        this.title = StringUtils.join(mainTitles, ",");
+        this.questionTitle = StringUtils.join(questionTitles, ",");
+        this.groupQuestions = StringUtils.join(groupQuestions, ",");
+        this.scoreList = score.toString();
+    }
+
+    @Override
+    public String toString() {
+        return "MarkGroup{" +
+                "examId=" + examId +
+                ", courseCode=" + courseCode +
+                ", paperNumber=" + paperNumber +
+                ", number=" + number +
+                ", picList=" + picList +
+                ", totalScore=" + totalScore +
+                ", doubleRate=" + doubleRate +
+                ", arbitrateThreshold=" + arbitrateThreshold +
+                ", taskCount=" + taskCount +
+                ", markedCount=" + markedCount +
+                ", leftCount=" + leftCount +
+                "}";
+    }
+}

+ 13 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkPaper.java

@@ -13,6 +13,7 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import org.apache.commons.lang3.StringUtils;
 
+import java.io.PipedReader;
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.Collections;
@@ -140,6 +141,9 @@ public class MarkPaper implements Serializable {
     @ApiModelProperty(value = "试卷类型")
     private String paperType;
 
+    @ApiModelProperty(value = "是否归档")
+    private Boolean archive;
+
     @TableField(exist = false)
     private List<String> paperTypeList;
 
@@ -172,6 +176,7 @@ public class MarkPaper implements Serializable {
         this.excellentScore = 80D;
         this.forceMode = true;
         this.showObjectScore = false;
+        this.archive = false;
     }
 
     public MarkPaper(Long examId, String courseCode, String courseName, String paperNumber, Double totalScore, Double passScore) {
@@ -472,6 +477,14 @@ public class MarkPaper implements Serializable {
         this.paperType = paperType;
     }
 
+    public Boolean getArchive() {
+        return archive;
+    }
+
+    public void setArchive(Boolean archive) {
+        this.archive = archive;
+    }
+
     public List<String> getPaperTypeList() {
         return StringUtils.isBlank(this.paperType) ? Collections.emptyList() : Arrays.asList(this.paperType.split(","));
     }

+ 4 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkServiceImpl.java

@@ -1263,6 +1263,10 @@ public class MarkServiceImpl implements MarkService {
             // 未评完
             resetStudentStatus(task.getStudentId());
         } else {
+            // 回评时,分数不一致,需要重新统分
+            if (task.getMarkerScore() != null && !task.getMarkerScore().equals(result.getMarkerScore())) {
+                resetStudentStatus(task.getStudentId());
+            }
             // 判断当前分组是否已完成评卷
             checkStudentQuestion(task.getStudentId(), markQuestion, result.getMarkerScore());
         }

+ 57 - 20
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/TaskServiceImpl.java

@@ -12,6 +12,8 @@ import com.qmth.teachcloud.common.service.TeachcloudCommonService;
 import com.qmth.teachcloud.mark.dto.mark.MarkStudentVo;
 import com.qmth.teachcloud.mark.dto.mark.ScoreItem;
 import com.qmth.teachcloud.mark.dto.mark.manage.*;
+import com.qmth.teachcloud.mark.dto.mark.score.SheetUrlDto;
+import com.qmth.teachcloud.mark.dto.mark.score.StudentObjectiveAnswerDto;
 import com.qmth.teachcloud.mark.entity.*;
 import com.qmth.teachcloud.mark.enums.MarkTaskStatus;
 import com.qmth.teachcloud.mark.service.*;
@@ -43,6 +45,8 @@ public class TaskServiceImpl implements TaskService {
     private MarkProblemHistoryService markProblemHistoryService;
     @Resource
     private SysUserService sysUserService;
+    @Resource
+    private MarkArchiveStudentService markArchiveStudentService;
 
     @Override
     public Task build(MarkArbitrateHistory markArbitrateHistory, MarkQuestion markQuestion) {
@@ -94,25 +98,58 @@ public class TaskServiceImpl implements TaskService {
         MarkStudentVo markStudent = markStudentService.getMarkStudentVoByStudentId(studentId);
         TaskArchive task = new TaskArchive();
         if (markStudent != null) {
-            task.setExamId(markStudent.getExamId());
-            task.setPaperNumber(markStudent.getPaperNumber());
-            task.setStudentId(markStudent.getId());
-            task.setSecretNumber(markStudent.getSecretNumber());
-            task.setStudentName(markStudent.getStudentName());
-            task.setStudentCode(markStudent.getStudentCode());
-            task.setPaperType(markStudent.getPaperType());
-            task.setCourseCode(markStudent.getCourseCode());
-            task.setCourseName(markStudent.getCourseName());
-            task.setObjectiveScore(StringUtils.isNotBlank(markStudent.getObjectiveScoreList()) ? markStudent.getObjectiveScore() : null);
-            task.setSubjectiveScore(StringUtils.isNotBlank(markStudent.getSubjectiveScoreList()) ? markStudent.getSubjectiveScore() : null);
-            // 原图
-            task.setSheetUrls(markStudentService.buildSheetUrls(studentId));
-            // 主观题
-            task.setSubjectiveQuestions(buildHeaderQuestionList(markStudent));
-            // 客观题
-            task.setObjectiveQuestions(markStudentService.buildObjectiveQuestion(markStudent));
-            // 题卡卡格式
-            task.setCardContent(markStudentService.getCardContent(markStudent));
+            MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(markStudent.getExamId(), markStudent.getPaperNumber());
+            if (markPaper.getArchive()) {
+                MarkArchiveStudent markArchiveStudent = markArchiveStudentService.getById(studentId);
+                if (markArchiveStudent != null) {
+                    task.setExamId(markArchiveStudent.getExamId());
+                    task.setPaperNumber(markArchiveStudent.getPaperNumber());
+                    task.setStudentId(studentId);
+                    task.setSecretNumber(markStudent.getSecretNumber());
+                    task.setStudentName(markStudent.getStudentName());
+                    task.setStudentCode(markStudent.getStudentCode());
+                    task.setPaperType(markStudent.getPaperType());
+                    task.setCourseCode(markStudent.getCourseCode());
+                    task.setCourseName(markStudent.getCourseName());
+                    task.setObjectiveScore(StringUtils.isNotBlank(markStudent.getObjectiveScoreList()) ? markStudent.getObjectiveScore() : null);
+                    task.setSubjectiveScore(StringUtils.isNotBlank(markStudent.getSubjectiveScoreList()) ? markStudent.getSubjectiveScore() : null);
+                    // 原图
+                    String sheetUrls = markArchiveStudent.getSheetUrls();
+                    if (StringUtils.isNotBlank(sheetUrls)) {
+                        List<SheetUrlDto> sheetUrlDtos = JSON.parseArray(sheetUrls, SheetUrlDto.class);
+                        for (SheetUrlDto sheetUrlDto : sheetUrlDtos) {
+                            sheetUrlDto.setUrl(teachcloudCommonService.filePreview(sheetUrlDto.getUrl()));
+                        }
+                        task.setSheetUrls(sheetUrlDtos);
+                    }
+                    // 主观题
+                    task.setSubjectiveQuestions(StringUtils.isNotBlank(markArchiveStudent.getSubjectiveQuestions()) ? JSON.parseArray(markArchiveStudent.getSubjectiveQuestions(), TaskQuestion.class) : null);
+                    // 客观题
+                    task.setObjectiveQuestions(StringUtils.isNotBlank(markArchiveStudent.getObjectiveQuestions()) ? JSON.parseArray(markArchiveStudent.getObjectiveQuestions(), StudentObjectiveAnswerDto.class) : null);
+                    // 题卡卡格式
+                    task.setCardContent(markStudentService.getCardContent(markStudent));
+                }
+            } else {
+                task.setExamId(markStudent.getExamId());
+                task.setPaperNumber(markStudent.getPaperNumber());
+                task.setStudentId(markStudent.getId());
+                task.setSecretNumber(markStudent.getSecretNumber());
+                task.setStudentName(markStudent.getStudentName());
+                task.setStudentCode(markStudent.getStudentCode());
+                task.setPaperType(markStudent.getPaperType());
+                task.setCourseCode(markStudent.getCourseCode());
+                task.setCourseName(markStudent.getCourseName());
+                task.setObjectiveScore(StringUtils.isNotBlank(markStudent.getObjectiveScoreList()) ? markStudent.getObjectiveScore() : null);
+                task.setSubjectiveScore(StringUtils.isNotBlank(markStudent.getSubjectiveScoreList()) ? markStudent.getSubjectiveScore() : null);
+                // 原图
+                task.setSheetUrls(markStudentService.buildSheetUrls(studentId));
+                // 主观题
+                task.setSubjectiveQuestions(buildHeaderQuestionList(markStudent));
+                // 客观题
+                task.setObjectiveQuestions(markStudentService.buildObjectiveQuestion(markStudent));
+                // 题卡卡格式
+                task.setCardContent(markStudentService.getCardContent(markStudent));
+            }
             return task;
         }
         return task;
@@ -181,7 +218,7 @@ public class TaskServiceImpl implements TaskService {
     }
 
     private Double calcTotalScore(List<TaskQuestion> questionList) {
-        return questionList.stream().filter(m->m.getMarkerScore() != null).mapToDouble(m->m.getMarkerScore()).sum();
+        return questionList.stream().filter(m -> m.getMarkerScore() != null).mapToDouble(m -> m.getMarkerScore()).sum();
     }
 
     private List<MarkConfigItem> buildPic(List<MarkTask> markTaskList) {

+ 2 - 2
teachcloud-mark/src/main/resources/mapper/MarkPaperMapper.xml

@@ -42,7 +42,7 @@
         mp.serial_number serialNumber,
         mp.paper_type paperType
         FROM
-        mark_paper mp
+        (select * from mark_paper where archive = 0) mp
             LEFT JOIN
         basic_course bc ON mp.course_id = bc.id
             LEFT JOIN
@@ -113,7 +113,7 @@
         ifnull(c.student_count, 0) studentCount,
         mp.upload_count uploadCount
         FROM
-        mark_paper mp
+        (select * from mark_paper where archive = 0) mp
         LEFT JOIN basic_course bc ON mp.course_id = bc.id
         LEFT JOIN sys_org so ON bc.teaching_room_id = so.id
          JOIN (SELECT exam_id, paper_number, count(1) student_count FROM  (select exam_id, paper_number,basic_student_id from mark_student where exam_id = #{examId}

+ 1 - 1
teachcloud-mark/src/main/resources/mapper/MarkTaskMapper.xml

@@ -32,7 +32,7 @@
             mp.paper_number paperNumber,
             mp.paper_type paperType,
             mp.status
-        FROM mark_paper mp
+        FROM (select * from mark_paper where archive = 0) mp
             left join basic_course bc on mp.course_id = bc.id
             left join sys_org so on bc.teaching_room_id = so.id
         <where>