test
parent
7a1545f7b5
commit
85e96a07b6
|
|
@ -1,6 +1,7 @@
|
||||||
package org.qinan.cedu.convertor;
|
package org.qinan.cedu.convertor;
|
||||||
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
|
import org.qinan.cedu.model.dto.PaperQuestionSaveDTO;
|
||||||
import org.qinan.cedu.model.dto.QuestionOptionUpdateDTO;
|
import org.qinan.cedu.model.dto.QuestionOptionUpdateDTO;
|
||||||
import org.qinan.cedu.model.dto.QuestionUpdateDTO;
|
import org.qinan.cedu.model.dto.QuestionUpdateDTO;
|
||||||
import org.qinan.cedu.model.entity.QuestionDO;
|
import org.qinan.cedu.model.entity.QuestionDO;
|
||||||
|
|
@ -25,6 +26,14 @@ public interface QuestionConvertor {
|
||||||
*/
|
*/
|
||||||
QuestionDO convertDtoToE(QuestionUpdateDTO dto);
|
QuestionDO convertDtoToE(QuestionUpdateDTO dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增试卷试题请求转试题实体
|
||||||
|
*
|
||||||
|
* @param dto 新增内容
|
||||||
|
* @return 试题实体
|
||||||
|
*/
|
||||||
|
QuestionDO convertPaperDtoToE(PaperQuestionSaveDTO dto);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选项编辑DTO列表转选项实体列表
|
* 选项编辑DTO列表转选项实体列表
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,14 @@ import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.validation.constraints.DecimalMax;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.DecimalMin;
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.*;
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import javax.validation.constraints.Pattern;
|
|
||||||
import javax.validation.constraints.Size;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增试卷试题(习题)请求
|
* 新增试卷试题(习题)请求(字段参考 QuestionUpdateDTO,另含试卷id和试题类型)
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@ApiModel(value = "PaperQuestionSaveDTO", description = "新增试卷试题请求")
|
@ApiModel(value = "PaperQuestionSaveDTO", description = "新增试卷试题请求")
|
||||||
|
|
@ -25,45 +21,34 @@ public class PaperQuestionSaveDTO {
|
||||||
@NotNull(message = "试卷id不能为空")
|
@NotNull(message = "试卷id不能为空")
|
||||||
private Long paperId;
|
private Long paperId;
|
||||||
|
|
||||||
@ApiModelProperty(value = "题目类型:single单选/multiple多选", required = true)
|
@ApiModelProperty(value = "试题类型:single单选/multiple多选", required = true)
|
||||||
@NotBlank(message = "题目类型不能为空")
|
@NotBlank(message = "试题类型不能为空")
|
||||||
@Pattern(regexp = "single|multiple", message = "题目类型只能填写single(单选)或multiple(多选)")
|
@Pattern(regexp = "single|multiple", message = "试题类型只能填写single(单选)或multiple(多选)")
|
||||||
private String questionType;
|
private String questionType;
|
||||||
|
|
||||||
@ApiModelProperty(value = "题干", required = true)
|
@ApiModelProperty(value = "题目内容", required = true)
|
||||||
@NotBlank(message = "题干不能为空")
|
@NotBlank(message = "题干不能为空")
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
@ApiModelProperty(value = "分值", required = true)
|
@ApiModelProperty(value = "分值", required = true)
|
||||||
@NotNull(message = "分值不能为空")
|
@NotNull(message = "分值不能为空")
|
||||||
@DecimalMin(value = "0.01", message = "分值必须大于0")
|
@DecimalMin(value = "0.1", message = "分值必须大于0")
|
||||||
@DecimalMax(value = "999.99", message = "分值不能超过999.99")
|
@DecimalMax(value = "999.9", message = "分值不能超过999.9")
|
||||||
|
@Digits(integer = 4, fraction = 1)
|
||||||
private BigDecimal score;
|
private BigDecimal score;
|
||||||
|
|
||||||
@ApiModelProperty(value = "选项A内容", required = true)
|
|
||||||
@NotBlank(message = "选项A不能为空")
|
|
||||||
private String optionA;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "选项B内容", required = true)
|
|
||||||
@NotBlank(message = "选项B不能为空")
|
|
||||||
private String optionB;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "选项C内容")
|
|
||||||
@Size(max = 64, message = "选项C长度不能超过64个字符")
|
|
||||||
private String optionC;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "选项D内容")
|
|
||||||
@Size(max = 64, message = "选项D长度不能超过64个字符")
|
|
||||||
private String optionD;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "答案:单选填写A,多选填写A,B", required = true)
|
|
||||||
@NotEmpty(message = "答案不能为空")
|
|
||||||
private List<String> answer;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "关联课件id courseware_management_id", required = true)
|
|
||||||
@NotNull(message = "关联课件不能为空")
|
|
||||||
private Long coursewareManagementId;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "答案解析")
|
@ApiModelProperty(value = "答案解析")
|
||||||
private String analysis;
|
private String analysis;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "标签类型")
|
||||||
|
private String tagType;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "关联课件管理id", required = true)
|
||||||
|
@NotNull(message = "关联课件不能为空")
|
||||||
|
private Long coursewareManagementId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "试题选项信息(isCorrect标记正确答案)", required = true)
|
||||||
|
@NotEmpty(message = "试题选项不能为空")
|
||||||
|
@Valid
|
||||||
|
private List<QuestionOptionUpdateDTO> questionOptionList;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ import javax.validation.constraints.NotNull;
|
||||||
public interface PaperQuestionRelService extends IService<PaperQuestionRelDO> {
|
public interface PaperQuestionRelService extends IService<PaperQuestionRelDO> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增试卷试题(习题):保存试题+选项,并绑定试卷
|
* 新增试卷试题(习题):保存试题+选项(isCorrect标记正确答案),并绑定试卷
|
||||||
*
|
*
|
||||||
* @param dto 试卷id+题目内容
|
* @param dto 试卷id+试题类型+题目内容+选项列表
|
||||||
*/
|
*/
|
||||||
void savePaperQuestion(PaperQuestionSaveDTO dto);
|
void savePaperQuestion(PaperQuestionSaveDTO dto);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.baomidou.mybatisplus.extension.toolkit.Db;
|
import com.baomidou.mybatisplus.extension.toolkit.Db;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.qinan.cedu.convertor.QuestionConvertor;
|
||||||
import org.qinan.cedu.enums.DeleteEnum;
|
import org.qinan.cedu.enums.DeleteEnum;
|
||||||
import org.qinan.cedu.enums.QuestionTypeEnum;
|
import org.qinan.cedu.enums.QuestionTypeEnum;
|
||||||
import org.qinan.cedu.mapper.PaperMapper;
|
import org.qinan.cedu.mapper.PaperMapper;
|
||||||
|
|
@ -13,6 +14,7 @@ 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.PaperQuestionSaveDTO;
|
import org.qinan.cedu.model.dto.PaperQuestionSaveDTO;
|
||||||
|
import org.qinan.cedu.model.dto.QuestionOptionUpdateDTO;
|
||||||
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;
|
||||||
|
|
@ -20,13 +22,9 @@ import org.qinan.cedu.model.entity.QuestionOptionDO;
|
||||||
import org.qinan.cedu.service.PaperQuestionRelService;
|
import org.qinan.cedu.service.PaperQuestionRelService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -40,78 +38,52 @@ public class PaperQuestionRelServiceImpl extends ServiceImpl<PaperQuestionRelMap
|
||||||
private final PaperMapper paperMapper;
|
private final PaperMapper paperMapper;
|
||||||
private final QuestionMapper questionMapper;
|
private final QuestionMapper questionMapper;
|
||||||
private final QuestionOptionMapper questionOptionMapper;
|
private final QuestionOptionMapper questionOptionMapper;
|
||||||
|
private final QuestionConvertor questionConvertor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void savePaperQuestion(PaperQuestionSaveDTO dto) {
|
public void savePaperQuestion(PaperQuestionSaveDTO dto) {
|
||||||
// 校验试卷存在
|
// 校验试卷存在且未删除
|
||||||
boolean exists = paperMapper.exists(new LambdaQueryWrapper<PaperDO>()
|
boolean exists = paperMapper.exists(new LambdaQueryWrapper<PaperDO>()
|
||||||
.eq(PaperDO::getId, dto.getPaperId())
|
.eq(PaperDO::getId, dto.getPaperId())
|
||||||
.eq(PaperDO::getDeleteEnum, DeleteEnum.FALSE.getCode()));
|
.eq(PaperDO::getDeleteEnum, DeleteEnum.FALSE.getCode()));
|
||||||
if (exists) {
|
if (!exists) {
|
||||||
throw new IllegalArgumentException("试卷不存在:id=" + dto.getPaperId());
|
throw new IllegalArgumentException("试卷不存在:id=" + dto.getPaperId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 组装选项(按A-D列,空白列不生成选项)
|
// 校验正确答案:至少一个;单选题只能有一个
|
||||||
Map<String, String> optionTexts = new LinkedHashMap<>();
|
List<QuestionOptionUpdateDTO> optionDTOs = dto.getQuestionOptionList();
|
||||||
optionTexts.put("A", dto.getOptionA().trim());
|
long correctCount = optionDTOs.stream()
|
||||||
optionTexts.put("B", dto.getOptionB().trim());
|
.filter(option -> Boolean.TRUE.equals(option.getIsCorrect()))
|
||||||
putIfHasText(optionTexts, "C", dto.getOptionC());
|
.count();
|
||||||
putIfHasText(optionTexts, "D", dto.getOptionD());
|
if (correctCount == 0) {
|
||||||
|
throw new IllegalArgumentException("正确答案不能为空");
|
||||||
// 校验答案必须能找到对应的选项
|
|
||||||
List<String> answers = dto.getAnswer().stream()
|
|
||||||
.map(String::trim)
|
|
||||||
.map(String::toUpperCase)
|
|
||||||
.distinct()
|
|
||||||
.sorted()
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
List<String> notMatched = answers.stream()
|
|
||||||
.filter(answer -> !optionTexts.containsKey(answer))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
if (!notMatched.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("答案[" + String.join(",", notMatched) + "]找不到对应的选项");
|
|
||||||
}
|
}
|
||||||
boolean single = QuestionTypeEnum.SINGLE.getCode().equals(dto.getQuestionType());
|
boolean single = QuestionTypeEnum.SINGLE.getCode().equals(dto.getQuestionType());
|
||||||
if (single && answers.size() != 1) {
|
if (single && correctCount != 1) {
|
||||||
throw new IllegalArgumentException("单选题答案只能有一个");
|
throw new IllegalArgumentException("单选题答案只能有一个");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存试题和选项(id用雪花id)
|
// 保存试题和选项(id用雪花id)
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
QuestionDO question = new QuestionDO();
|
QuestionDO question = questionConvertor.convertPaperDtoToE(dto);
|
||||||
question.setId(IdUtil.getSnowflakeNextId());
|
question.setId(IdUtil.getSnowflakeNextId());
|
||||||
question.setTitle(dto.getTitle().trim());
|
question.setAnswer(optionDTOs.stream()
|
||||||
question.setQuestionType(dto.getQuestionType());
|
.filter(option -> Boolean.TRUE.equals(option.getIsCorrect()))
|
||||||
question.setAnswer(String.join(",", answers));
|
.map(QuestionOptionUpdateDTO::getOptionKey)
|
||||||
question.setScore(dto.getScore());
|
.map(String::trim)
|
||||||
question.setAnalysis(StringUtils.hasText(dto.getAnalysis()) ? dto.getAnalysis().trim() : null);
|
.map(String::toUpperCase)
|
||||||
question.setCoursewareManagementId(dto.getCoursewareManagementId());
|
.collect(Collectors.joining(",")));
|
||||||
question.setCreateTime(now);
|
|
||||||
question.setUpdateTime(now);
|
|
||||||
question.setVersion(0);
|
|
||||||
|
|
||||||
List<QuestionOptionDO> options = new ArrayList<>();
|
List<QuestionOptionDO> options = buildOptions(question.getId(), optionDTOs, now);
|
||||||
int sortOrder = 1;
|
|
||||||
for (Map.Entry<String, String> entry : optionTexts.entrySet()) {
|
|
||||||
QuestionOptionDO option = new QuestionOptionDO();
|
|
||||||
option.setId(IdUtil.getSnowflakeNextId());
|
|
||||||
option.setQuestionId(question.getId());
|
|
||||||
option.setOptionKey(entry.getKey());
|
|
||||||
option.setOptionName(entry.getKey());
|
|
||||||
option.setOptionText(entry.getValue());
|
|
||||||
option.setIsCorrect(answers.contains(entry.getKey()));
|
|
||||||
option.setSortOrder(sortOrder++);
|
|
||||||
option.setCreateTime(now);
|
|
||||||
option.setUpdateTime(now);
|
|
||||||
option.setVersion(0);
|
|
||||||
options.add(option);
|
|
||||||
}
|
|
||||||
question.setAnswerQuestionOptionIds(options.stream()
|
question.setAnswerQuestionOptionIds(options.stream()
|
||||||
.filter(option -> Boolean.TRUE.equals(option.getIsCorrect()))
|
.filter(option -> Boolean.TRUE.equals(option.getIsCorrect()))
|
||||||
.map(option -> String.valueOf(option.getId()))
|
.map(option -> String.valueOf(option.getId()))
|
||||||
.collect(Collectors.joining(",")));
|
.collect(Collectors.joining(",")));
|
||||||
|
|
||||||
|
question.setCreateTime(now);
|
||||||
|
question.setUpdateTime(now);
|
||||||
|
question.setVersion(0);
|
||||||
questionMapper.insert(question);
|
questionMapper.insert(question);
|
||||||
Db.saveBatch(options);
|
Db.saveBatch(options);
|
||||||
|
|
||||||
|
|
@ -124,6 +96,31 @@ public class PaperQuestionRelServiceImpl extends ServiceImpl<PaperQuestionRelMap
|
||||||
this.save(rel);
|
this.save(rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装试题选项列表(归一化选项标识、填充雪花id与排序)
|
||||||
|
*
|
||||||
|
* @param questionId 所属试题id
|
||||||
|
* @param optionDTOs 选项内容
|
||||||
|
* @param now 统一的创建/修改时间
|
||||||
|
* @return 选项实体列表
|
||||||
|
*/
|
||||||
|
private List<QuestionOptionDO> buildOptions(Long questionId, List<QuestionOptionUpdateDTO> optionDTOs, LocalDateTime now) {
|
||||||
|
List<QuestionOptionDO> options = questionConvertor.convertOptionDtoListToEList(optionDTOs);
|
||||||
|
int sortOrder = 1;
|
||||||
|
for (QuestionOptionDO option : options) {
|
||||||
|
String key = option.getOptionKey().trim().toUpperCase();
|
||||||
|
option.setId(IdUtil.getSnowflakeNextId());
|
||||||
|
option.setQuestionId(questionId);
|
||||||
|
option.setOptionKey(key);
|
||||||
|
option.setOptionName(key);
|
||||||
|
option.setSortOrder(sortOrder++);
|
||||||
|
option.setCreateTime(now);
|
||||||
|
option.setUpdateTime(now);
|
||||||
|
option.setVersion(0);
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void deletePaperQuestion(Long paperId, Long questionId) {
|
public void deletePaperQuestion(Long paperId, Long questionId) {
|
||||||
|
|
@ -143,9 +140,4 @@ public class PaperQuestionRelServiceImpl extends ServiceImpl<PaperQuestionRelMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putIfHasText(Map<String, String> optionTexts, String key, String value) {
|
|
||||||
if (StringUtils.hasText(value)) {
|
|
||||||
optionTexts.put(key, value.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,7 @@ public class OrgPersonnelExecutor implements OrgPersonnelApi {
|
||||||
cmd.setJoinWorkDate(resolveJoinWorkDate(cmd.getWorkDateAge(), cmd.getJoinWorkDate()));
|
cmd.setJoinWorkDate(resolveJoinWorkDate(cmd.getWorkDateAge(), cmd.getJoinWorkDate()));
|
||||||
OrgPersonnelEntity entity = orgPersonnelConvertor.toEntity(cmd);
|
OrgPersonnelEntity entity = orgPersonnelConvertor.toEntity(cmd);
|
||||||
entity.setId(cmd.getId());
|
entity.setId(cmd.getId());
|
||||||
|
entity.setIsCertComplete(true);
|
||||||
OrgPersonnelEntity result = orgPersonnelDomainService.modify(entity);
|
OrgPersonnelEntity result = orgPersonnelDomainService.modify(entity);
|
||||||
// 组织信息变更,清理该用户机构缓存
|
// 组织信息变更,清理该用户机构缓存
|
||||||
if (userOrgIdResolver != null) {
|
if (userOrgIdResolver != null) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue