|
@@ -0,0 +1,332 @@
|
|
|
+package cn.com.qmth.dp.examcloud.oe.modules.export_exam_student_score;
|
|
|
+
|
|
|
+import cn.com.qmth.dp.examcloud.oe.modules.export_exam_student_score.vo.ExamQuestionVO;
|
|
|
+import cn.com.qmth.dp.examcloud.oe.modules.export_exam_student_score.vo.ExamRecordQuestionVO;
|
|
|
+import cn.com.qmth.dp.examcloud.oe.modules.export_exam_student_score.vo.ExamStudentVO;
|
|
|
+import cn.com.qmth.dp.examcloud.oe.modules.export_exam_student_score.vo.ScoreVO;
|
|
|
+import cn.com.qmth.examcloud.commons.helpers.poi.ExcelWriter;
|
|
|
+import org.apache.commons.collections.CollectionUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.assertj.core.util.Lists;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.mongodb.core.MongoTemplate;
|
|
|
+import org.springframework.data.mongodb.core.query.Criteria;
|
|
|
+import org.springframework.data.mongodb.core.query.Query;
|
|
|
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
|
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Component
|
|
|
+public class ExportExamStudentScore {
|
|
|
+
|
|
|
+ private static Logger log = LoggerFactory.getLogger(ExportExamStudentScore.class);
|
|
|
+
|
|
|
+ private static final Long MARKING_TYPE_KEY = 24L;// 阅卷方式KEY
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private JdbcTemplate jdbcTemplate;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private MongoTemplate mongoTemplate;
|
|
|
+
|
|
|
+ public void start() {
|
|
|
+ Set<Long> examIds = new HashSet<>();
|
|
|
+ // examIds.add(808L);
|
|
|
+ // examIds.add(815L);
|
|
|
+ // examIds.add(816L);
|
|
|
+ // examIds.add(817L);
|
|
|
+ // examIds.add(818L);
|
|
|
+ // examIds.add(821L);
|
|
|
+ // examIds.add(822L);
|
|
|
+ // examIds.add(823L);
|
|
|
+ examIds.add(47L);
|
|
|
+
|
|
|
+ Map<Long, String> orgNameMaps = new HashMap<>(), courseNameMaps = new HashMap<>();
|
|
|
+ for (Long examId : examIds) {
|
|
|
+ log.info("===> export starting, examId = " + examId);
|
|
|
+
|
|
|
+ List<Long> examCourseIds = this.queryExamCourseIds(examId);
|
|
|
+ log.info("---> examCourseIds size is " + examCourseIds.size());
|
|
|
+
|
|
|
+ for (Long courseId : examCourseIds) {
|
|
|
+ // 按考试的每个课程依次导出
|
|
|
+ this.export(examId, courseId, orgNameMaps, courseNameMaps);
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("---> orgMap size is " + orgNameMaps.size());
|
|
|
+ log.info("---> courseMap size is " + courseNameMaps.size());
|
|
|
+ log.info("===> export finished, examId = " + examId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void export(Long examId, Long courseId, Map<Long, String> orgNameMaps, Map<Long, String> courseNameMaps) {
|
|
|
+ List<ExamStudentVO> examStudents = this.queryExamStudents(examId, courseId);
|
|
|
+ log.info(String.format("---> examId = %s, courseId = %s, examStudentSize = %s", examId, courseId, examStudents.size()));
|
|
|
+
|
|
|
+ boolean hasDynamicExcelHeaderSetting = false;
|
|
|
+ List<String> dynamicExcelHeaders = new ArrayList<>();// Excel动态列
|
|
|
+ List<String> dynamicDefaultValues = new ArrayList<>();// Excel动态列默认值
|
|
|
+
|
|
|
+ for (ExamStudentVO examStudent : examStudents) {
|
|
|
+ if (!orgNameMaps.containsKey(examStudent.getOrgId())) {
|
|
|
+ String orgName = this.queryOrgName(examStudent.getOrgId());
|
|
|
+ orgNameMaps.put(examStudent.getOrgId(), orgName);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!courseNameMaps.containsKey(examStudent.getCourseId())) {
|
|
|
+ String courseName = this.queryCourseName(examStudent.getCourseId());
|
|
|
+ courseNameMaps.put(examStudent.getCourseId(), courseName);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置学习中心名称、课程名称
|
|
|
+ examStudent.setOrgName(orgNameMaps.get(examStudent.getOrgId()));
|
|
|
+ examStudent.setCourseName(courseNameMaps.get(examStudent.getCourseId()));
|
|
|
+
|
|
|
+ // 成绩默认值
|
|
|
+ examStudent.setObjectiveScore(0d);
|
|
|
+ examStudent.setSubjectiveScore(0d);
|
|
|
+ examStudent.setTotalScore(0d);
|
|
|
+
|
|
|
+ if (!examStudent.getFinished()) {
|
|
|
+ // 跳过缺考的情况
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取考试记录
|
|
|
+ List<Map<String, Object>> examRecordDataList = this.queryExamRecordDataList(examId, courseId, examStudent.getExamStudentId());
|
|
|
+ if (CollectionUtils.isEmpty(examRecordDataList)) {
|
|
|
+ // 跳过暂无有效考试记录的情况
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Long okExamRecordDataId;
|
|
|
+ if (examRecordDataList.size() == 1) {
|
|
|
+ // 只有一条考试记录情况
|
|
|
+ okExamRecordDataId = (Long) examRecordDataList.get(0).get("id");
|
|
|
+
|
|
|
+ // 获取考试记录对应的成绩
|
|
|
+ ScoreVO okScore = this.queryExamScore(okExamRecordDataId);
|
|
|
+ examStudent.setObjectiveScore(okScore.getObjectiveScore());
|
|
|
+ examStudent.setSubjectiveScore(okScore.getSubjectiveScore());
|
|
|
+ examStudent.setTotalScore(okScore.getTotalScore());
|
|
|
+ } else {
|
|
|
+ // 多条考试记录情况
|
|
|
+ List<ScoreVO> scores = new ArrayList<>();
|
|
|
+ for (Map<String, Object> examRecordData : examRecordDataList) {
|
|
|
+ Long examRecordDataId = (Long) examRecordData.get("id");
|
|
|
+ // 分别获取考试记录对应的成绩
|
|
|
+ ScoreVO score = this.queryExamScore(examRecordDataId);
|
|
|
+ scores.add(score);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取考试的阅卷方式
|
|
|
+ String markingType = this.queryExamMarkingType(examId, MARKING_TYPE_KEY);
|
|
|
+ log.info("---> markingType is " + markingType);
|
|
|
+
|
|
|
+ ScoreVO okScore;
|
|
|
+ if (markingType.equals("ALL") || markingType.equals("OBJECT_SCORE_MAX")) {
|
|
|
+ // 全部评阅规则 或 客观分最高规则:取总分最高
|
|
|
+ okScore = scores.stream()
|
|
|
+ .sorted((obj1, obj2) -> obj2.getTotalScore().compareTo(obj1.getTotalScore()))
|
|
|
+ .collect(Collectors.toList())
|
|
|
+ .get(0);
|
|
|
+ } else {
|
|
|
+ // 否则:取最后一次的成绩
|
|
|
+ okScore = scores.stream()
|
|
|
+ .sorted((obj1, obj2) -> obj2.getId().compareTo(obj1.getId()))
|
|
|
+ .collect(Collectors.toList())
|
|
|
+ .get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ okExamRecordDataId = okScore.getExamRecordDataId();
|
|
|
+ examStudent.setObjectiveScore(okScore.getObjectiveScore());
|
|
|
+ examStudent.setSubjectiveScore(okScore.getSubjectiveScore());
|
|
|
+ examStudent.setTotalScore(okScore.getTotalScore());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取试题作答记录
|
|
|
+ // ExamRecordQuestionVO questions = this.queryExamRecordQuestions(okExamRecordDataId);
|
|
|
+ ExamRecordQuestionVO questions = this.queryExamRecordQuestions(11346965L);
|
|
|
+ if (questions == null || CollectionUtils.isEmpty(questions.getExamQuestionEntities())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<ExamQuestionVO> examQuestionEntities = questions.getExamQuestionEntities();
|
|
|
+
|
|
|
+ if (!hasDynamicExcelHeaderSetting) {
|
|
|
+ for (ExamQuestionVO question : examQuestionEntities) {
|
|
|
+ String questionType = this.convertQuestionType(question.getQuestionType());
|
|
|
+ if ("SINGLE_CHOICE".equals(question.getQuestionType()) || "MULTIPLE_CHOICE".equals(question.getQuestionType()) || "TRUE_OR_FALSE".equals(question.getQuestionType())) {
|
|
|
+ String titleX = questionType + question.getMainNumber() + "-" + question.getOrder() + " 作答";
|
|
|
+ String titleY = questionType + question.getMainNumber() + "-" + question.getOrder() + " 得分";
|
|
|
+ dynamicExcelHeaders.add(titleX);
|
|
|
+ dynamicExcelHeaders.add(titleY);
|
|
|
+ dynamicDefaultValues.add("");
|
|
|
+ dynamicDefaultValues.add("0");
|
|
|
+ } else {
|
|
|
+ // 主观题不设置“作答”列
|
|
|
+ String title = questionType + question.getMainNumber() + "-" + question.getOrder() + " 得分";
|
|
|
+ dynamicExcelHeaders.add(title);
|
|
|
+ dynamicDefaultValues.add("");
|
|
|
+ }
|
|
|
+ hasDynamicExcelHeaderSetting = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (ExamQuestionVO question : examQuestionEntities) {
|
|
|
+ if ("SINGLE_CHOICE".equals(question.getQuestionType()) || "MULTIPLE_CHOICE".equals(question.getQuestionType()) || "TRUE_OR_FALSE".equals(question.getQuestionType())) {
|
|
|
+ examStudent.addDetail(question.getStudentAnswer());
|
|
|
+ examStudent.addDetail(question.getQuestionScore() != null ? question.getQuestionScore().toString() : "0");
|
|
|
+ } else {
|
|
|
+ examStudent.addDetail(question.getQuestionScore() != null ? question.getQuestionScore().toString() : "0");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 补全缺失的作答区
|
|
|
+ for (ExamStudentVO examStudent : examStudents) {
|
|
|
+ if (CollectionUtils.isNotEmpty(examStudent.getDetails())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ examStudent.setDetails(dynamicDefaultValues);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<String> fixedExcelHeaders = Lists.newArrayList("学习中心", "课程代码", "课程名称", "层次", "是否缺考", "身份证号", "学号", "姓名", "年级", "专业", "客观总分", "主观总分", "总分");
|
|
|
+ fixedExcelHeaders.addAll(dynamicExcelHeaders);
|
|
|
+
|
|
|
+ this.toExcel(examId, courseId, examStudents, fixedExcelHeaders);
|
|
|
+
|
|
|
+ examStudents.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void toExcel(Long examId, Long courseId, List<ExamStudentVO> examStudents, List<String> excelHeaders) {
|
|
|
+ // 处理Excel
|
|
|
+ List<Object[]> excelRows = new ArrayList<>();
|
|
|
+
|
|
|
+ if (CollectionUtils.isNotEmpty(examStudents)) {
|
|
|
+ for (ExamStudentVO vo : examStudents) {
|
|
|
+ List<Object> rowValues = Lists.newArrayList(vo.getOrgName(), vo.getCourseCode(), vo.getCourseName(),
|
|
|
+ vo.getCourseLevel(), vo.getFinished() ? "否" : "是", vo.getIdentityNumber(),
|
|
|
+ vo.getStudentCode(), vo.getStudentName(), vo.getGrade(), vo.getSpecialtyName(),
|
|
|
+ vo.getObjectiveScore().toString(), vo.getSubjectiveScore().toString(),
|
|
|
+ vo.getTotalScore().toString());
|
|
|
+
|
|
|
+ if (CollectionUtils.isNotEmpty(vo.getDetails())) {
|
|
|
+ rowValues.addAll(vo.getDetails());
|
|
|
+ }
|
|
|
+
|
|
|
+ excelRows.add(rowValues.toArray(new Object[rowValues.size()]));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Class<String>[] excelTypes = new Class[excelHeaders.size()];
|
|
|
+ for (int n = 0; n < excelHeaders.size(); n++) {
|
|
|
+ excelTypes[n] = String.class;
|
|
|
+ }
|
|
|
+
|
|
|
+ final String filePath = String.format("/home/oa/exam_%s/exam_student_score_%s.xlsx", examId, courseId);
|
|
|
+ ExcelWriter.write(excelHeaders.toArray(new String[excelHeaders.size()]), excelTypes, excelRows, new File(filePath));
|
|
|
+ }
|
|
|
+
|
|
|
+ private String queryOrgName(Long orgId) {
|
|
|
+ final String querySql = String.format("select name from ec_b_org where id = %s", orgId);
|
|
|
+ return jdbcTemplate.queryForObject(querySql, String.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String queryCourseName(Long courseId) {
|
|
|
+ final String querySql = String.format("select name from ec_b_course where id = %s", courseId);
|
|
|
+ return jdbcTemplate.queryForObject(querySql, String.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Long> queryExamCourseIds(Long examId) {
|
|
|
+ final String querySql = String.format("select distinct course_id from ec_oe_exam_student where exam_id = %s and enable = 1", examId);
|
|
|
+ return jdbcTemplate.queryForList(querySql, Long.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<ExamStudentVO> queryExamStudents(Long examId, Long courseId) {
|
|
|
+ final String columns = "exam_student_id,student_code,student_name,identity_number,org_id,course_id,course_code,course_level,grade,specialty_name,finished";
|
|
|
+ final String querySql = String.format("select %s from ec_oe_exam_student where exam_id = %s and course_id = %s and enable = 1", columns, examId, courseId);
|
|
|
+ return jdbcTemplate.query(querySql, new BeanPropertyRowMapper(ExamStudentVO.class));
|
|
|
+ }
|
|
|
+
|
|
|
+ private String queryExamMarkingType(Long examId, Long markingTypeKey) {
|
|
|
+ final String querySql = String.format("select value from ec_e_exam_prop where exam_id = %s and key_id = %s", examId, markingTypeKey);
|
|
|
+ String value = jdbcTemplate.queryForObject(querySql, String.class);
|
|
|
+ if (StringUtils.isBlank(value)) {
|
|
|
+ return "ALL";// 默认值
|
|
|
+ }
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Map<String, Object>> queryExamRecordDataList(Long examId, Long courseId, Long examStudentId) {
|
|
|
+ final String querySql = String.format("select id,exam_record_status from ec_oe_exam_record_data where exam_id = %s and course_id = %s and exam_student_id = %s", examId, courseId, examStudentId);
|
|
|
+ List<Map<String, Object>> result = jdbcTemplate.queryForList(querySql);
|
|
|
+
|
|
|
+ List<Map<String, Object>> okList = new ArrayList<>();
|
|
|
+ if (CollectionUtils.isNotEmpty(result)) {
|
|
|
+ for (Map<String, Object> row : result) {
|
|
|
+ // 过滤无效数据
|
|
|
+ String examRecordStatus = (String) row.get("exam_record_status");
|
|
|
+ if ("EXAM_END".equals(examRecordStatus) || "EXAM_OVERDUE".equals(examRecordStatus)) {
|
|
|
+ okList.add(row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return okList;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ScoreVO queryExamScore(Long examRecordDataId) {
|
|
|
+ final String querySql = String.format("select id,objective_score,subjective_score,total_score from ec_oe_exam_score where exam_record_data_id = %s", examRecordDataId);
|
|
|
+ List<ScoreVO> result = jdbcTemplate.query(querySql, new BeanPropertyRowMapper(ScoreVO.class));
|
|
|
+
|
|
|
+ ScoreVO score;
|
|
|
+ if (CollectionUtils.isNotEmpty(result)) {
|
|
|
+ score = result.get(0);
|
|
|
+ } else {
|
|
|
+ score = new ScoreVO();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 默认值
|
|
|
+ score.setExamRecordDataId(examRecordDataId);
|
|
|
+ score.setObjectiveScore(score.getObjectiveScore() != null ? score.getObjectiveScore() : 0d);
|
|
|
+ score.setSubjectiveScore(score.getSubjectiveScore() != null ? score.getSubjectiveScore() : 0d);
|
|
|
+ score.setTotalScore(score.getTotalScore() != null ? score.getTotalScore() : 0d);
|
|
|
+
|
|
|
+ return score;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ExamRecordQuestionVO queryExamRecordQuestions(Long examRecordDataId) {
|
|
|
+ Query query = new Query();
|
|
|
+ query.addCriteria(Criteria.where("examRecordDataId").is(examRecordDataId));
|
|
|
+ List<ExamRecordQuestionVO> result = mongoTemplate.find(query, ExamRecordQuestionVO.class, "examRecordQuestions");
|
|
|
+ if (CollectionUtils.isNotEmpty(result)) {
|
|
|
+ return result.get(0);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String convertQuestionType(String type) {
|
|
|
+ switch (type) {
|
|
|
+ case "SINGLE_CHOICE":
|
|
|
+ return "单选题";
|
|
|
+ case "MULTIPLE_CHOICE":
|
|
|
+ return "多选题";
|
|
|
+ case "FILL_UP":
|
|
|
+ return "填空题";
|
|
|
+ case "TRUE_OR_FALSE":
|
|
|
+ return "判断题";
|
|
|
+ case "ESSAY":
|
|
|
+ return "问答题";
|
|
|
+ default:
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|