dev-tmp1
luotaiqian 2026-08-19 16:02:19 +08:00
parent 7a1545f7b5
commit 85e96a07b6
5 changed files with 84 additions and 97 deletions

View File

@ -1,6 +1,7 @@
package org.qinan.cedu.convertor;
import org.mapstruct.Mapper;
import org.qinan.cedu.model.dto.PaperQuestionSaveDTO;
import org.qinan.cedu.model.dto.QuestionOptionUpdateDTO;
import org.qinan.cedu.model.dto.QuestionUpdateDTO;
import org.qinan.cedu.model.entity.QuestionDO;
@ -25,6 +26,14 @@ public interface QuestionConvertor {
*/
QuestionDO convertDtoToE(QuestionUpdateDTO dto);
/**
*
*
* @param dto
* @return
*/
QuestionDO convertPaperDtoToE(PaperQuestionSaveDTO dto);
/**
* DTO
*

View File

@ -4,18 +4,14 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.List;
/**
*
* QuestionUpdateDTOid
*/
@Data
@ApiModel(value = "PaperQuestionSaveDTO", description = "新增试卷试题请求")
@ -25,45 +21,34 @@ public class PaperQuestionSaveDTO {
@NotNull(message = "试卷id不能为空")
private Long paperId;
@ApiModelProperty(value = "类型single单选/multiple多选", required = true)
@NotBlank(message = "类型不能为空")
@Pattern(regexp = "single|multiple", message = "类型只能填写single单选或multiple多选")
@ApiModelProperty(value = "题类型single单选/multiple多选", required = true)
@NotBlank(message = "题类型不能为空")
@Pattern(regexp = "single|multiple", message = "题类型只能填写single单选或multiple多选")
private String questionType;
@ApiModelProperty(value = "题", required = true)
@ApiModelProperty(value = "题目内容", required = true)
@NotBlank(message = "题干不能为空")
private String title;
@ApiModelProperty(value = "分值", required = true)
@NotNull(message = "分值不能为空")
@DecimalMin(value = "0.01", message = "分值必须大于0")
@DecimalMax(value = "999.99", message = "分值不能超过999.99")
@DecimalMin(value = "0.1", message = "分值必须大于0")
@DecimalMax(value = "999.9", message = "分值不能超过999.9")
@Digits(integer = 4, fraction = 1)
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 = "答案解析")
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;
}

View File

@ -12,9 +12,9 @@ import javax.validation.constraints.NotNull;
public interface PaperQuestionRelService extends IService<PaperQuestionRelDO> {
/**
* +
* +isCorrect
*
* @param dto id+
* @param dto id+++
*/
void savePaperQuestion(PaperQuestionSaveDTO dto);

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.qinan.cedu.convertor.QuestionConvertor;
import org.qinan.cedu.enums.DeleteEnum;
import org.qinan.cedu.enums.QuestionTypeEnum;
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.QuestionOptionMapper;
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.PaperQuestionRelDO;
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.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@ -40,78 +38,52 @@ public class PaperQuestionRelServiceImpl extends ServiceImpl<PaperQuestionRelMap
private final PaperMapper paperMapper;
private final QuestionMapper questionMapper;
private final QuestionOptionMapper questionOptionMapper;
private final QuestionConvertor questionConvertor;
@Override
@Transactional(rollbackFor = Exception.class)
public void savePaperQuestion(PaperQuestionSaveDTO dto) {
// 校验试卷存在
// 校验试卷存在且未删除
boolean exists = paperMapper.exists(new LambdaQueryWrapper<PaperDO>()
.eq(PaperDO::getId, dto.getPaperId())
.eq(PaperDO::getDeleteEnum, DeleteEnum.FALSE.getCode()));
if (exists) {
if (!exists) {
throw new IllegalArgumentException("试卷不存在id=" + dto.getPaperId());
}
// 组装选项按A-D列空白列不生成选项
Map<String, String> optionTexts = new LinkedHashMap<>();
optionTexts.put("A", dto.getOptionA().trim());
optionTexts.put("B", dto.getOptionB().trim());
putIfHasText(optionTexts, "C", dto.getOptionC());
putIfHasText(optionTexts, "D", dto.getOptionD());
// 校验答案必须能找到对应的选项
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) + "]找不到对应的选项");
// 校验正确答案:至少一个;单选题只能有一个
List<QuestionOptionUpdateDTO> optionDTOs = dto.getQuestionOptionList();
long correctCount = optionDTOs.stream()
.filter(option -> Boolean.TRUE.equals(option.getIsCorrect()))
.count();
if (correctCount == 0) {
throw new IllegalArgumentException("正确答案不能为空");
}
boolean single = QuestionTypeEnum.SINGLE.getCode().equals(dto.getQuestionType());
if (single && answers.size() != 1) {
if (single && correctCount != 1) {
throw new IllegalArgumentException("单选题答案只能有一个");
}
// 保存试题和选项id用雪花id
LocalDateTime now = LocalDateTime.now();
QuestionDO question = new QuestionDO();
QuestionDO question = questionConvertor.convertPaperDtoToE(dto);
question.setId(IdUtil.getSnowflakeNextId());
question.setTitle(dto.getTitle().trim());
question.setQuestionType(dto.getQuestionType());
question.setAnswer(String.join(",", answers));
question.setScore(dto.getScore());
question.setAnalysis(StringUtils.hasText(dto.getAnalysis()) ? dto.getAnalysis().trim() : null);
question.setCoursewareManagementId(dto.getCoursewareManagementId());
question.setCreateTime(now);
question.setUpdateTime(now);
question.setVersion(0);
question.setAnswer(optionDTOs.stream()
.filter(option -> Boolean.TRUE.equals(option.getIsCorrect()))
.map(QuestionOptionUpdateDTO::getOptionKey)
.map(String::trim)
.map(String::toUpperCase)
.collect(Collectors.joining(",")));
List<QuestionOptionDO> options = new ArrayList<>();
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);
}
List<QuestionOptionDO> options = buildOptions(question.getId(), optionDTOs, now);
question.setAnswerQuestionOptionIds(options.stream()
.filter(option -> Boolean.TRUE.equals(option.getIsCorrect()))
.map(option -> String.valueOf(option.getId()))
.collect(Collectors.joining(",")));
question.setCreateTime(now);
question.setUpdateTime(now);
question.setVersion(0);
questionMapper.insert(question);
Db.saveBatch(options);
@ -124,6 +96,31 @@ public class PaperQuestionRelServiceImpl extends ServiceImpl<PaperQuestionRelMap
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
@Transactional(rollbackFor = Exception.class)
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());
}
}
}

View File

@ -181,6 +181,7 @@ public class OrgPersonnelExecutor implements OrgPersonnelApi {
cmd.setJoinWorkDate(resolveJoinWorkDate(cmd.getWorkDateAge(), cmd.getJoinWorkDate()));
OrgPersonnelEntity entity = orgPersonnelConvertor.toEntity(cmd);
entity.setId(cmd.getId());
entity.setIsCertComplete(true);
OrgPersonnelEntity result = orgPersonnelDomainService.modify(entity);
// 组织信息变更,清理该用户机构缓存
if (userOrgIdResolver != null) {