archive file

dev-tmp1
luotaiqian 2026-08-27 10:58:11 +08:00
parent 1fb5839a02
commit 5004254c45
10 changed files with 130 additions and 75 deletions

View File

@ -73,7 +73,7 @@ public class PaperController {
@ApiOperation("新建试卷-导入试题") @ApiOperation("新建试卷-导入试题")
@PostMapping("/import") @PostMapping("/import")
public SingleResponse<PaperImportVO> importQuestions(@Validated PaperImportDTO paperImportDTO) { public SingleResponse<QuestionImportVO> importQuestions(@Validated PaperImportDTO paperImportDTO) {
return SingleResponse.success(paperService.importQuestions(paperImportDTO)); return SingleResponse.success(paperService.importQuestions(paperImportDTO));
} }

View File

@ -6,6 +6,7 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.qinan.cedu.model.dto.*; import org.qinan.cedu.model.dto.*;
import org.qinan.cedu.model.vo.QuestionImportVO;
import org.qinan.cedu.model.vo.QuestionCoursewareVO; import org.qinan.cedu.model.vo.QuestionCoursewareVO;
import org.qinan.cedu.model.vo.QuestionTypeCountVO; import org.qinan.cedu.model.vo.QuestionTypeCountVO;
import org.qinan.cedu.model.vo.QuestionVO; import org.qinan.cedu.model.vo.QuestionVO;
@ -94,4 +95,10 @@ public class QuestionController {
return PageResponse.of(page.getRecords(), page.getTotal()); return PageResponse.of(page.getRecords(), page.getTotal());
} }
@ApiOperation("导入试题")
@PostMapping("/import")
public SingleResponse<QuestionImportVO> importQuestions(@Validated QuestionImportDTO questionImportDTO) {
return SingleResponse.success(questionService.importQuestions(questionImportDTO));
}
} }

View File

@ -0,0 +1,23 @@
package org.qinan.cedu.model.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotNull;
/**
* -
*/
@Data
@ApiModel(value = "PaperImportDTO", description = "新建试卷-导入试题请求")
public class QuestionImportDTO {
@ApiModelProperty("关联课件管理id")
private Long coursewareManagementId;
@ApiModelProperty(value = "试题Excel文件第一个sheet单选题第二个sheet多选题第三个sheet判断题", required = true)
@NotNull(message = "请上传试题Excel文件")
private MultipartFile file;
}

View File

@ -11,7 +11,7 @@ import lombok.NoArgsConstructor;
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class PaperImportErrorVO { public class QuestionImportErrorVO {
@ApiModelProperty(value = "Excel行号从1开始的物理行号") @ApiModelProperty(value = "Excel行号从1开始的物理行号")
private Integer rowIndex; private Integer rowIndex;
@ -22,7 +22,7 @@ public class PaperImportErrorVO {
@ApiModelProperty(value = "异常原因") @ApiModelProperty(value = "异常原因")
private String errorMessage; private String errorMessage;
public PaperImportErrorVO(Integer rowIndex, String sheetName, String errorMessage) { public QuestionImportErrorVO(Integer rowIndex, String sheetName, String errorMessage) {
this.rowIndex = rowIndex; this.rowIndex = rowIndex;
this.sheetName = sheetName; this.sheetName = sheetName;
this.errorMessage = errorMessage; this.errorMessage = errorMessage;

View File

@ -14,15 +14,15 @@ import java.util.List;
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class PaperImportVO { public class QuestionImportVO {
@ApiModelProperty(value = "成功导入条数") @ApiModelProperty(value = "成功导入条数")
private Integer successCount; private Integer successCount;
@ApiModelProperty(value = "异常明细") @ApiModelProperty(value = "异常明细")
private List<PaperImportErrorVO> errors = new ArrayList<>(); private List<QuestionImportErrorVO> errors = new ArrayList<>();
public PaperImportVO(Integer successCount, List<PaperImportErrorVO> errors) { public QuestionImportVO(Integer successCount, List<QuestionImportErrorVO> errors) {
this.successCount = successCount; this.successCount = successCount;
this.errors = errors; this.errors = errors;
} }

View File

@ -10,7 +10,7 @@ import org.qinan.cedu.model.dto.PaperPageQueryDTO;
import org.qinan.cedu.model.dto.PaperUpdateDTO; import org.qinan.cedu.model.dto.PaperUpdateDTO;
import org.qinan.cedu.model.entity.PaperDO; import org.qinan.cedu.model.entity.PaperDO;
import org.qinan.cedu.model.vo.PaperBasicInfoVO; import org.qinan.cedu.model.vo.PaperBasicInfoVO;
import org.qinan.cedu.model.vo.PaperImportVO; import org.qinan.cedu.model.vo.QuestionImportVO;
import org.qinan.cedu.model.vo.PaperExamInfoVO; import org.qinan.cedu.model.vo.PaperExamInfoVO;
import org.qinan.cedu.model.vo.PaperPageVO; import org.qinan.cedu.model.vo.PaperPageVO;
@ -91,7 +91,7 @@ public interface PaperService extends IService<PaperDO> {
* @param importDTO +Excel * @param importDTO +Excel
* @return + * @return +
*/ */
PaperImportVO importQuestions(PaperImportDTO importDTO); QuestionImportVO importQuestions(PaperImportDTO importDTO);
/** /**
* importQuestionsTemplate * importQuestionsTemplate

View File

@ -5,10 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import org.qinan.cedu.model.dto.*; import org.qinan.cedu.model.dto.*;
import org.qinan.cedu.model.entity.QuestionDO; import org.qinan.cedu.model.entity.QuestionDO;
import org.qinan.cedu.model.entity.QuestionOptionDO; import org.qinan.cedu.model.entity.QuestionOptionDO;
import org.qinan.cedu.model.vo.PaperQuestionVO; import org.qinan.cedu.model.vo.*;
import org.qinan.cedu.model.vo.QuestionCoursewareVO;
import org.qinan.cedu.model.vo.QuestionTypeCountVO;
import org.qinan.cedu.model.vo.QuestionVO;
import java.util.List; import java.util.List;
@ -122,4 +119,12 @@ public interface QuestionService extends IService<QuestionDO> {
* @param dto dto * @param dto dto
*/ */
void addQuestion(QuestionAddDTO dto); void addQuestion(QuestionAddDTO dto);
/**
*
*
* @param questionImportDTO questionImportDTO
* @return QuestionImportVO
*/
QuestionImportVO importQuestions(QuestionImportDTO questionImportDTO);
} }

View File

@ -8,12 +8,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db; import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.lowagie.text.Document; import com.lowagie.text.*;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.BaseFont; import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfWriter; import com.lowagie.text.pdf.PdfWriter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -28,23 +23,12 @@ import org.qinan.cedu.mapper.PaperMapper;
import org.qinan.cedu.mapper.PaperQuestionRelMapper; import org.qinan.cedu.mapper.PaperQuestionRelMapper;
import org.qinan.cedu.mapper.QuestionMapper; import org.qinan.cedu.mapper.QuestionMapper;
import org.qinan.cedu.mapper.QuestionOptionMapper; import org.qinan.cedu.mapper.QuestionOptionMapper;
import org.qinan.cedu.model.dto.PaperConfigRuleDTO; import org.qinan.cedu.model.dto.*;
import org.qinan.cedu.model.dto.PaperCopyDTO;
import org.qinan.cedu.model.dto.PaperCoursewareQuestionRuleDTO;
import org.qinan.cedu.model.dto.PaperImportDTO;
import org.qinan.cedu.model.dto.PaperOrgPageQueryDTO;
import org.qinan.cedu.model.dto.PaperPageQueryDTO;
import org.qinan.cedu.model.dto.PaperUpdateDTO;
import org.qinan.cedu.model.entity.PaperDO; import org.qinan.cedu.model.entity.PaperDO;
import org.qinan.cedu.model.entity.PaperQuestionRelDO; import org.qinan.cedu.model.entity.PaperQuestionRelDO;
import org.qinan.cedu.model.entity.QuestionDO; import org.qinan.cedu.model.entity.QuestionDO;
import org.qinan.cedu.model.entity.QuestionOptionDO; import org.qinan.cedu.model.entity.QuestionOptionDO;
import org.qinan.cedu.model.vo.PaperBasicInfoVO; import org.qinan.cedu.model.vo.*;
import org.qinan.cedu.model.vo.PaperExamInfoVO;
import org.qinan.cedu.model.vo.PaperImportVO;
import org.qinan.cedu.model.vo.PaperPageVO;
import org.qinan.cedu.model.vo.QuestionOptionVO;
import org.qinan.cedu.model.vo.QuestionVO;
import org.qinan.cedu.service.PaperService; import org.qinan.cedu.service.PaperService;
import org.qinan.cedu.service.support.QuestionExcelImporter; import org.qinan.cedu.service.support.QuestionExcelImporter;
import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults; import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults;
@ -276,12 +260,13 @@ public class PaperServiceImpl extends ServiceImpl<PaperMapper, PaperDO> implemen
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public PaperImportVO importQuestions(PaperImportDTO importDTO) { public QuestionImportVO importQuestions(PaperImportDTO importDTO) {
QuestionExcelImporter.ParseResult parseResult = questionExcelImporter.parse(importDTO.getFile()); QuestionExcelImporter.ParseResult parseResult = questionExcelImporter.parse(
importDTO.getFile(), null);
if (!CollectionUtils.isEmpty(parseResult.getErrors())) { if (!CollectionUtils.isEmpty(parseResult.getErrors())) {
// 没有任何校验通过的试题,不创建试卷,直接返回异常明细 // 没有任何校验通过的试题,不创建试卷,直接返回异常明细
return new PaperImportVO(0, parseResult.getErrors()); return new QuestionImportVO(0, parseResult.getErrors());
} }
// 创建试卷 // 创建试卷
@ -311,7 +296,7 @@ public class PaperServiceImpl extends ServiceImpl<PaperMapper, PaperDO> implemen
rels.add(rel); rels.add(rel);
} }
Db.saveBatch(rels); Db.saveBatch(rels);
return new PaperImportVO(questions.size(), parseResult.getErrors()); return new QuestionImportVO(questions.size(), parseResult.getErrors());
} }
@Override @Override

View File

@ -16,11 +16,9 @@ import org.qinan.cedu.mapper.QuestionOptionMapper;
import org.qinan.cedu.model.dto.*; import org.qinan.cedu.model.dto.*;
import org.qinan.cedu.model.entity.QuestionDO; import org.qinan.cedu.model.entity.QuestionDO;
import org.qinan.cedu.model.entity.QuestionOptionDO; import org.qinan.cedu.model.entity.QuestionOptionDO;
import org.qinan.cedu.model.vo.PaperQuestionVO; import org.qinan.cedu.model.vo.*;
import org.qinan.cedu.model.vo.QuestionCoursewareVO;
import org.qinan.cedu.model.vo.QuestionTypeCountVO;
import org.qinan.cedu.model.vo.QuestionVO;
import org.qinan.cedu.service.QuestionService; import org.qinan.cedu.service.QuestionService;
import org.qinan.cedu.service.support.QuestionExcelImporter;
import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults; import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -43,6 +41,7 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO>
private final QuestionOptionMapper questionOptionMapper; private final QuestionOptionMapper questionOptionMapper;
private final QuestionConvertor questionConvertor; private final QuestionConvertor questionConvertor;
private final QuestionExcelImporter questionExcelImporter;
@Override @Override
public IPage<PaperQuestionVO> pagePaperQuestions(PaperQuestionPageQueryDTO query) { public IPage<PaperQuestionVO> pagePaperQuestions(PaperQuestionPageQueryDTO query) {
@ -274,6 +273,23 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO>
Db.saveBatch(options); Db.saveBatch(options);
} }
@Override
@Transactional(rollbackFor = Exception.class)
public QuestionImportVO importQuestions(QuestionImportDTO importDTO) {
QuestionExcelImporter.ParseResult parseResult = questionExcelImporter.parse(
importDTO.getFile(), importDTO.getCoursewareManagementId());
if (!CollectionUtils.isEmpty(parseResult.getErrors())) {
// 没有任何校验通过的试题,不创建试卷,直接返回异常明细
return new QuestionImportVO(0, parseResult.getErrors());
}
// 保存试题和选项id已预置雪花id
Db.saveBatch(parseResult.getQuestions());
Db.saveBatch(parseResult.getOptions());
return new QuestionImportVO(parseResult.getQuestions().size(), parseResult.getErrors());
}
/** /**
* idid * idid
* *

View File

@ -1,6 +1,7 @@
package org.qinan.cedu.service.support; package org.qinan.cedu.service.support;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader; import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadSheet;
@ -14,7 +15,7 @@ import org.qinan.cedu.mapper.CoursewareManagementMapper;
import org.qinan.cedu.model.entity.CoursewareManagementDO; import org.qinan.cedu.model.entity.CoursewareManagementDO;
import org.qinan.cedu.model.entity.QuestionDO; import org.qinan.cedu.model.entity.QuestionDO;
import org.qinan.cedu.model.entity.QuestionOptionDO; import org.qinan.cedu.model.entity.QuestionOptionDO;
import org.qinan.cedu.model.vo.PaperImportErrorVO; import org.qinan.cedu.model.vo.QuestionImportErrorVO;
import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults; import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -71,54 +72,58 @@ public class QuestionExcelImporter {
private static final String COMMA_DELIMITER = ","; private static final String COMMA_DELIMITER = ",";
private static final String VIOLATION_DELIMITER = ""; private static final String VIOLATION_DELIMITER = "";
public static final String DEFAULT_IMPORT_COURSEWARE_NAME = "默认使用导入试题关联的课件_id";
private final CoursewareManagementMapper coursewareManagementMapper; private final CoursewareManagementMapper coursewareManagementMapper;
private final Validator validator; private final Validator validator;
/** /**
* Excelid * Excelid
* *
* @param file Excel * @param file Excel
* @param coursewareManagementId coursewareManagementId
* @return * @return
*/ */
public ParseResult parse(MultipartFile file) { public ParseResult parse(MultipartFile file, Long coursewareManagementId) {
if (file == null || file.isEmpty()) { if (file == null || file.isEmpty()) {
throw new IllegalArgumentException(UPLOAD_EMPTY_MESSAGE); throw new IllegalArgumentException(UPLOAD_EMPTY_MESSAGE);
} }
byte[] bytes = readBytes(file); byte[] bytes = readBytes(file);
Map<Integer, String> sheetNames = readSheetNames(bytes); Map<Integer, String> sheetNames = readSheetNames(bytes);
List<PaperImportErrorVO> errors = new ArrayList<>(); List<QuestionImportErrorVO> errors = new ArrayList<>();
List<ChoiceQuestionImportRow> singleRows = new ArrayList<>(); List<ChoiceQuestionImportRow> singleRows = new ArrayList<>();
List<ChoiceQuestionImportRow> multipleRows = new ArrayList<>(); List<ChoiceQuestionImportRow> multipleRows = new ArrayList<>();
List<JudgeQuestionImportRow> judgeRows = new ArrayList<>(); List<JudgeQuestionImportRow> judgeRows = new ArrayList<>();
try { try {
singleRows = readSheet(bytes, SINGLE_SHEET_NO, ChoiceQuestionImportRow.class); singleRows = readSheet(bytes, SINGLE_SHEET_NO, ChoiceQuestionImportRow.class);
} catch (Exception e) { } catch (Exception e) {
errors.add(new PaperImportErrorVO(null, sheetName(sheetNames, SINGLE_SHEET_NO) errors.add(new QuestionImportErrorVO(null, sheetName(sheetNames, SINGLE_SHEET_NO)
, READ_SINGLE_SHEET_FAIL_PREFIX + e.getMessage())); , READ_SINGLE_SHEET_FAIL_PREFIX + e.getMessage()));
} }
try { try {
multipleRows = readSheet(bytes, MULTIPLE_SHEET_NO, ChoiceQuestionImportRow.class); multipleRows = readSheet(bytes, MULTIPLE_SHEET_NO, ChoiceQuestionImportRow.class);
} catch (Exception e) { } catch (Exception e) {
errors.add(new PaperImportErrorVO(null, sheetName(sheetNames, MULTIPLE_SHEET_NO) errors.add(new QuestionImportErrorVO(null, sheetName(sheetNames, MULTIPLE_SHEET_NO)
, READ_MULTIPLE_SHEET_FAIL_PREFIX + e.getMessage())); , READ_MULTIPLE_SHEET_FAIL_PREFIX + e.getMessage()));
} }
try { try {
judgeRows = readSheet(bytes, JUDGE_SHEET_NO, JudgeQuestionImportRow.class); judgeRows = readSheet(bytes, JUDGE_SHEET_NO, JudgeQuestionImportRow.class);
} catch (Exception e) { } catch (Exception e) {
errors.add(new PaperImportErrorVO(null, sheetName(sheetNames, JUDGE_SHEET_NO) errors.add(new QuestionImportErrorVO(null, sheetName(sheetNames, JUDGE_SHEET_NO)
, READ_JUDGE_SHEET_FAIL_PREFIX + e.getMessage())); , READ_JUDGE_SHEET_FAIL_PREFIX + e.getMessage()));
} }
Map<String, Long> coursewareManagementIdByName = loadCoursewareIdByName(singleRows, multipleRows, judgeRows); Map<String, Long> coursewareManagementIdByName = loadCoursewareIdByName(
singleRows, multipleRows, judgeRows, coursewareManagementId);
ParseResult parseResult = new ParseResult(errors); ParseResult parseResult = new ParseResult(errors);
convertChoiceRows(singleRows, sheetName(sheetNames, SINGLE_SHEET_NO) convertChoiceRows(singleRows, sheetName(sheetNames, SINGLE_SHEET_NO)
, QuestionTypeEnum.SINGLE, coursewareManagementIdByName, parseResult); , QuestionTypeEnum.SINGLE, coursewareManagementIdByName, parseResult, coursewareManagementId);
convertChoiceRows(multipleRows, sheetName(sheetNames, MULTIPLE_SHEET_NO) convertChoiceRows(multipleRows, sheetName(sheetNames, MULTIPLE_SHEET_NO)
, QuestionTypeEnum.MULTIPLE, coursewareManagementIdByName, parseResult); , QuestionTypeEnum.MULTIPLE, coursewareManagementIdByName, parseResult, coursewareManagementId);
convertJudgeRows(judgeRows, sheetName(sheetNames, JUDGE_SHEET_NO) convertJudgeRows(judgeRows, sheetName(sheetNames, JUDGE_SHEET_NO)
, coursewareManagementIdByName, parseResult); , coursewareManagementIdByName, parseResult, coursewareManagementId);
return parseResult; return parseResult;
} }
@ -185,20 +190,23 @@ public class QuestionExcelImporter {
/** /**
* id -> id * id -> id
* *
* @param singleRows * @param singleRows
* @param multipleRows * @param multipleRows
* @param judgeRows * @param judgeRows
* @param coursewareManagementId coursewareManagementId
* @return id * @return id
*/ */
private Map<String, Long> loadCoursewareIdByName(List<ChoiceQuestionImportRow> singleRows, private Map<String, Long> loadCoursewareIdByName(List<ChoiceQuestionImportRow> singleRows
List<ChoiceQuestionImportRow> multipleRows, , List<ChoiceQuestionImportRow> multipleRows, List<JudgeQuestionImportRow> judgeRows, Long coursewareManagementId) {
List<JudgeQuestionImportRow> judgeRows) {
Set<String> names = new HashSet<>(); Set<String> names = new HashSet<>();
singleRows.forEach(row -> addCoursewareName(names, row.getCoursewareName())); singleRows.forEach(row -> addCoursewareName(names, row.getCoursewareName()));
multipleRows.forEach(row -> addCoursewareName(names, row.getCoursewareName())); multipleRows.forEach(row -> addCoursewareName(names, row.getCoursewareName()));
judgeRows.forEach(row -> addCoursewareName(names, row.getCoursewareName())); judgeRows.forEach(row -> addCoursewareName(names, row.getCoursewareName()));
if (names.isEmpty()) { if (names.isEmpty()) {
return Collections.emptyMap(); if (coursewareManagementId == null) {
return Collections.emptyMap();
}
return Collections.singletonMap(DEFAULT_IMPORT_COURSEWARE_NAME, coursewareManagementId);
} }
List<CoursewareManagementDO> coursewares = coursewareManagementMapper.selectList( List<CoursewareManagementDO> coursewares = coursewareManagementMapper.selectList(
new LambdaQueryWrapper<CoursewareManagementDO>() new LambdaQueryWrapper<CoursewareManagementDO>()
@ -209,6 +217,9 @@ public class QuestionExcelImporter {
for (CoursewareManagementDO courseware : coursewares) { for (CoursewareManagementDO courseware : coursewares) {
idByName.putIfAbsent(courseware.getCoursewareName(), courseware.getId()); idByName.putIfAbsent(courseware.getCoursewareName(), courseware.getId());
} }
if (coursewareManagementId != null) {
idByName.putIfAbsent(DEFAULT_IMPORT_COURSEWARE_NAME, coursewareManagementId);
}
return idByName; return idByName;
} }
@ -232,10 +243,11 @@ public class QuestionExcelImporter {
* @param questionType / * @param questionType /
* @param coursewareManagementIdByName id * @param coursewareManagementIdByName id
* @param parseResult * @param parseResult
* @param formCoursewareManagementId formCoursewareManagementId
*/ */
private void convertChoiceRows(List<ChoiceQuestionImportRow> rows, String sheetName, QuestionTypeEnum questionType, private void convertChoiceRows(List<ChoiceQuestionImportRow> rows, String sheetName, QuestionTypeEnum questionType,
Map<String, Long> coursewareManagementIdByName, ParseResult parseResult) { Map<String, Long> coursewareManagementIdByName, ParseResult parseResult, Long formCoursewareManagementId) {
List<PaperImportErrorVO> errors = parseResult.getErrors(); List<QuestionImportErrorVO> errors = parseResult.getErrors();
boolean single = questionType == QuestionTypeEnum.SINGLE; boolean single = questionType == QuestionTypeEnum.SINGLE;
for (int i = 0; i < rows.size(); i++) { for (int i = 0; i < rows.size(); i++) {
ChoiceQuestionImportRow row = rows.get(i); ChoiceQuestionImportRow row = rows.get(i);
@ -244,11 +256,15 @@ public class QuestionExcelImporter {
continue; continue;
} }
row.setRowIndex(rowIndex); row.setRowIndex(rowIndex);
String coursewareName = StrUtil.trim(row.getCoursewareName());
if (!StringUtils.hasText(coursewareName) && formCoursewareManagementId != null) {
row.setCoursewareName(DEFAULT_IMPORT_COURSEWARE_NAME);
}
// JSR-303 校验(必填、数据库长度限制),不通过则跳过该行 // JSR-303 校验(必填、数据库长度限制),不通过则跳过该行
Set<ConstraintViolation<ChoiceQuestionImportRow>> violations = validator.validate(row); Set<ConstraintViolation<ChoiceQuestionImportRow>> violations = validator.validate(row);
if (!violations.isEmpty()) { if (!violations.isEmpty()) {
errors.add(new PaperImportErrorVO(rowIndex, sheetName, joinViolationMessages(violations))); errors.add(new QuestionImportErrorVO(rowIndex, sheetName, joinViolationMessages(violations)));
continue; continue;
} }
@ -262,14 +278,14 @@ public class QuestionExcelImporter {
} }
} }
if (options.size() < 2) { if (options.size() < 2) {
errors.add(new PaperImportErrorVO(rowIndex, sheetName, OPTION_AT_LEAST_TWO_MESSAGE)); errors.add(new QuestionImportErrorVO(rowIndex, sheetName, OPTION_AT_LEAST_TWO_MESSAGE));
continue; continue;
} }
// 校验答案:必须有答案且答案必须能找到对应的选项 // 校验答案:必须有答案且答案必须能找到对应的选项
String answerRaw = row.getAnswer().trim().toUpperCase(); String answerRaw = row.getAnswer().trim().toUpperCase();
if (!answerRaw.chars().allMatch(c -> c >= 'A' && c <= 'F')) { if (!answerRaw.chars().allMatch(c -> c >= 'A' && c <= 'F')) {
errors.add(new PaperImportErrorVO(rowIndex, sheetName, CHOICE_ANSWER_LETTER_MESSAGE)); errors.add(new QuestionImportErrorVO(rowIndex, sheetName, CHOICE_ANSWER_LETTER_MESSAGE));
continue; continue;
} }
List<String> answerLetters = answerRaw.chars() List<String> answerLetters = answerRaw.chars()
@ -278,23 +294,22 @@ public class QuestionExcelImporter {
.sorted() .sorted()
.collect(Collectors.toList()); .collect(Collectors.toList());
if (single && answerLetters.size() != 1) { if (single && answerLetters.size() != 1) {
errors.add(new PaperImportErrorVO(rowIndex, sheetName, SINGLE_ANSWER_LETTER_MESSAGE)); errors.add(new QuestionImportErrorVO(rowIndex, sheetName, SINGLE_ANSWER_LETTER_MESSAGE));
continue; continue;
} }
List<String> notMatched = answerLetters.stream() List<String> notMatched = answerLetters.stream()
.filter(letter -> !options.containsKey(letter)) .filter(letter -> !options.containsKey(letter))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (!notMatched.isEmpty()) { if (!notMatched.isEmpty()) {
errors.add(new PaperImportErrorVO(rowIndex, sheetName, errors.add(new QuestionImportErrorVO(rowIndex, sheetName,
String.format(ANSWER_NOT_MATCH_OPTION_TEMPLATE, String.join("", notMatched)))); String.format(ANSWER_NOT_MATCH_OPTION_TEMPLATE, String.join("", notMatched))));
continue; continue;
} }
// 校验关联课件名称查询到后回填coursewareManagementId // 校验关联课件名称查询到后回填coursewareManagementId
String coursewareName = row.getCoursewareName().trim();
Long coursewareManagementId = coursewareManagementIdByName.get(coursewareName); Long coursewareManagementId = coursewareManagementIdByName.get(coursewareName);
if (coursewareManagementId == null) { if (coursewareManagementId == null) {
errors.add(new PaperImportErrorVO(rowIndex, sheetName, String.format(COURSEWARE_NOT_EXIST_TEMPLATE, coursewareName))); errors.add(new QuestionImportErrorVO(rowIndex, sheetName, String.format(COURSEWARE_NOT_EXIST_TEMPLATE, coursewareName)));
continue; continue;
} }
@ -339,10 +354,11 @@ public class QuestionExcelImporter {
* @param sheetName sheet * @param sheetName sheet
* @param coursewareManagementIdByName id * @param coursewareManagementIdByName id
* @param parseResult * @param parseResult
* @param formCoursewareManagementId formCoursewareManagementId
*/ */
private void convertJudgeRows(List<JudgeQuestionImportRow> rows, String sheetName, private void convertJudgeRows(List<JudgeQuestionImportRow> rows, String sheetName,
Map<String, Long> coursewareManagementIdByName, ParseResult parseResult) { Map<String, Long> coursewareManagementIdByName, ParseResult parseResult, Long formCoursewareManagementId) {
List<PaperImportErrorVO> errors = parseResult.getErrors(); List<QuestionImportErrorVO> errors = parseResult.getErrors();
for (int i = 0; i < rows.size(); i++) { for (int i = 0; i < rows.size(); i++) {
JudgeQuestionImportRow row = rows.get(i); JudgeQuestionImportRow row = rows.get(i);
int rowIndex = i + HEAD_ROW_NUMBER + 1; int rowIndex = i + HEAD_ROW_NUMBER + 1;
@ -350,23 +366,26 @@ public class QuestionExcelImporter {
continue; continue;
} }
row.setRowIndex(rowIndex); row.setRowIndex(rowIndex);
String coursewareName = StrUtil.trim(row.getCoursewareName());
if (!StringUtils.hasText(coursewareName) && formCoursewareManagementId != null) {
row.setCoursewareName(DEFAULT_IMPORT_COURSEWARE_NAME);
}
Set<ConstraintViolation<JudgeQuestionImportRow>> violations = validator.validate(row); Set<ConstraintViolation<JudgeQuestionImportRow>> violations = validator.validate(row);
if (!violations.isEmpty()) { if (!violations.isEmpty()) {
errors.add(new PaperImportErrorVO(rowIndex, sheetName, joinViolationMessages(violations))); errors.add(new QuestionImportErrorVO(rowIndex, sheetName, joinViolationMessages(violations)));
continue; continue;
} }
String answerRaw = row.getAnswer().trim().toUpperCase(); String answerRaw = row.getAnswer().trim().toUpperCase();
if (!JUDGE_ANSWER_TRUE.equals(answerRaw) && !JUDGE_ANSWER_FALSE.equals(answerRaw)) { if (!JUDGE_ANSWER_TRUE.equals(answerRaw) && !JUDGE_ANSWER_FALSE.equals(answerRaw)) {
errors.add(new PaperImportErrorVO(rowIndex, sheetName, JUDGE_ANSWER_LETTER_MESSAGE)); errors.add(new QuestionImportErrorVO(rowIndex, sheetName, JUDGE_ANSWER_LETTER_MESSAGE));
continue; continue;
} }
String coursewareName = row.getCoursewareName().trim();
Long coursewareManagementId = coursewareManagementIdByName.get(coursewareName); Long coursewareManagementId = coursewareManagementIdByName.get(coursewareName);
if (coursewareManagementId == null) { if (coursewareManagementId == null) {
errors.add(new PaperImportErrorVO(rowIndex, sheetName, String.format(COURSEWARE_NOT_EXIST_TEMPLATE, coursewareName))); errors.add(new QuestionImportErrorVO(rowIndex, sheetName, String.format(COURSEWARE_NOT_EXIST_TEMPLATE, coursewareName)));
continue; continue;
} }
@ -517,7 +536,7 @@ public class QuestionExcelImporter {
/** /**
* *
*/ */
private final List<PaperImportErrorVO> errors; private final List<QuestionImportErrorVO> errors;
/** /**
* *
@ -526,7 +545,7 @@ public class QuestionExcelImporter {
* @param options * @param options
* @param errors * @param errors
*/ */
public ParseResult(List<QuestionDO> questions, List<QuestionOptionDO> options, List<PaperImportErrorVO> errors) { public ParseResult(List<QuestionDO> questions, List<QuestionOptionDO> options, List<QuestionImportErrorVO> errors) {
this.questions = questions; this.questions = questions;
this.options = options; this.options = options;
this.questionNumByQuestionId = new HashMap<>(); this.questionNumByQuestionId = new HashMap<>();
@ -548,7 +567,7 @@ public class QuestionExcelImporter {
* *
* @param errors * @param errors
*/ */
public ParseResult(List<PaperImportErrorVO> errors) { public ParseResult(List<QuestionImportErrorVO> errors) {
this.questions = new ArrayList<>(64); this.questions = new ArrayList<>(64);
this.options = new ArrayList<>(256); this.options = new ArrayList<>(256);
this.questionNumByQuestionId = new HashMap<>(); this.questionNumByQuestionId = new HashMap<>();