PaperBasicInfo
parent
7775928024
commit
1e8386f7c4
|
|
@ -4,7 +4,9 @@ import io.swagger.annotations.Api;
|
|||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionDeleteDTO;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionRelUpdateDTO;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionSaveDTO;
|
||||
import org.qinan.cedu.model.dto.QuestionUpdateDTO;
|
||||
import org.qinan.cedu.service.PaperQuestionRelService;
|
||||
import org.qinan.safetyeval.client.dto.SingleResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
@ -38,4 +40,11 @@ public class PaperQuestionRelController {
|
|||
paperQuestionRelService.deletePaperQuestion(dto.getPaperId(), dto.getQuestionId());
|
||||
return SingleResponse.success();
|
||||
}
|
||||
|
||||
@ApiOperation("编辑试卷习题")
|
||||
@PostMapping("/modify")
|
||||
public SingleResponse<Void> modify(@Validated @RequestBody PaperQuestionRelUpdateDTO dto) {
|
||||
paperQuestionRelService.modify(dto);
|
||||
return SingleResponse.success();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package org.qinan.cedu.convertor;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionRelUpdateDTO;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionSaveDTO;
|
||||
import org.qinan.cedu.model.dto.QuestionOptionUpdateDTO;
|
||||
import org.qinan.cedu.model.dto.QuestionUpdateDTO;
|
||||
|
|
@ -45,4 +46,6 @@ public interface QuestionConvertor {
|
|||
QuestionOptionVO convertOptionEToVo(QuestionOptionDO entity);
|
||||
|
||||
List<QuestionOptionVO> convertOptionEListToVoList(List<QuestionOptionDO> list);
|
||||
|
||||
QuestionDO convertPaperQuestionRelUpdateDTOToE(PaperQuestionRelUpdateDTO dto);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package org.qinan.cedu.model.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 编辑习题请求(字段参考 QuestionVO)
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "QuestionUpdateDTO", description = "编辑习题请求")
|
||||
public class PaperQuestionRelUpdateDTO {
|
||||
|
||||
@ApiModelProperty(value = "试卷id", required = true)
|
||||
@NotNull(message = "试卷id不能为空")
|
||||
private Long paperId;
|
||||
|
||||
@ApiModelProperty(value = "试题id", required = true)
|
||||
@NotNull(message = "试题id不能为空")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "题目内容", required = true)
|
||||
@NotBlank(message = "题干不能为空")
|
||||
private String title;
|
||||
|
||||
@ApiModelProperty(value = "分值", required = true)
|
||||
@NotNull(message = "分值不能为空")
|
||||
@DecimalMin(value = "0.1", message = "分值必须大于0")
|
||||
@DecimalMax(value = "999.9", message = "分值不能超过999.9")
|
||||
@Digits(integer = 4, fraction = 1)
|
||||
private BigDecimal score;
|
||||
|
||||
@ApiModelProperty(value = "答案解析")
|
||||
private String analysis;
|
||||
|
||||
@ApiModelProperty(value = "标签类型")
|
||||
private String tagType;
|
||||
|
||||
@ApiModelProperty(value = "关联课件管理id", required = true)
|
||||
@NotNull(message = "关联课件不能为空")
|
||||
private Long coursewareManagementId;
|
||||
|
||||
@ApiModelProperty(value = "试题选项信息", required = true)
|
||||
@NotEmpty(message = "试题选项不能为空")
|
||||
@Valid
|
||||
private List<QuestionOptionUpdateDTO> questionOptionList;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package org.qinan.cedu.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionRelUpdateDTO;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionSaveDTO;
|
||||
import org.qinan.cedu.model.entity.PaperQuestionRelDO;
|
||||
|
||||
|
|
@ -25,4 +26,10 @@ public interface PaperQuestionRelService extends IService<PaperQuestionRelDO> {
|
|||
* @param questionId 试题id
|
||||
*/
|
||||
void deletePaperQuestion(@NotNull Long paperId, @NotNull Long questionId);
|
||||
|
||||
/**
|
||||
* modify
|
||||
* @param dto dto
|
||||
*/
|
||||
void modify(PaperQuestionRelUpdateDTO dto);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package org.qinan.cedu.service.impl;
|
|||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.baomidou.mybatisplus.extension.toolkit.Db;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
|
@ -13,6 +14,7 @@ import org.qinan.cedu.mapper.PaperMapper;
|
|||
import org.qinan.cedu.mapper.PaperQuestionRelMapper;
|
||||
import org.qinan.cedu.mapper.QuestionMapper;
|
||||
import org.qinan.cedu.mapper.QuestionOptionMapper;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionRelUpdateDTO;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionSaveDTO;
|
||||
import org.qinan.cedu.model.dto.QuestionOptionUpdateDTO;
|
||||
import org.qinan.cedu.model.entity.PaperDO;
|
||||
|
|
@ -25,7 +27,9 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -130,4 +134,95 @@ public class PaperQuestionRelServiceImpl extends ServiceImpl<PaperQuestionRelMap
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modify(PaperQuestionRelUpdateDTO dto) {
|
||||
// 校验试题存在且未删除
|
||||
QuestionDO exist = questionMapper.selectOne(new LambdaQueryWrapper<QuestionDO>().eq(QuestionDO::getId, dto.getId())
|
||||
.eq(QuestionDO::getDeleteEnum, DeleteEnum.FALSE.getCode()));
|
||||
if (exist == null) {
|
||||
throw new IllegalArgumentException("试题不存在");
|
||||
}
|
||||
|
||||
this.update(new LambdaUpdateWrapper<PaperQuestionRelDO>()
|
||||
.set(PaperQuestionRelDO::getScore, dto.getScore())
|
||||
.eq(PaperQuestionRelDO::getPaperId, dto.getPaperId())
|
||||
.eq(PaperQuestionRelDO::getQuestionId, dto.getId()));
|
||||
|
||||
// 更新试题基本信息(MapStruct转换,答案归一化后回填)
|
||||
QuestionDO question = questionConvertor.convertPaperQuestionRelUpdateDTOToE(dto);
|
||||
question.setAnswer(dto.getQuestionOptionList().stream()
|
||||
.filter(option -> Boolean.TRUE.equals(option.getIsCorrect()))
|
||||
.map(QuestionOptionUpdateDTO::getOptionKey)
|
||||
.collect(Collectors.joining(",")));
|
||||
question.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
// 同步选项:id在库的更新、无id的新增、多余的逻辑删除
|
||||
List<QuestionOptionDO> options = syncOptions(dto.getId(), dto.getQuestionOptionList());
|
||||
question.setAnswerQuestionOptionIds(options.stream()
|
||||
.filter(option -> Boolean.TRUE.equals(option.getIsCorrect()))
|
||||
.map(option -> String.valueOf(option.getId()))
|
||||
.collect(Collectors.joining(",")));
|
||||
|
||||
InsertFieldDefaults.applyForUpdate(question);
|
||||
boolean updated = questionMapper.updateById(question) != 0;
|
||||
if (!updated) {
|
||||
throw new IllegalArgumentException("编辑习题失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步试题选项:id在库中的更新、无id(或id不在库中)的新增、库中多余的选项逻辑删除
|
||||
*
|
||||
* @param questionId 所属试题id
|
||||
* @param optionDTOs 选项编辑内容
|
||||
* @return 处理后的选项实体列表(更新与新增的合集,含最终id)
|
||||
*/
|
||||
private List<QuestionOptionDO> syncOptions(Long questionId, List<QuestionOptionUpdateDTO> optionDTOs) {
|
||||
// 查询该试题现存未删除的选项id
|
||||
Set<Long> existingIds = questionOptionMapper.selectList(new LambdaQueryWrapper<QuestionOptionDO>()
|
||||
.select(QuestionOptionDO::getId)
|
||||
.eq(QuestionOptionDO::getQuestionId, questionId)
|
||||
.eq(QuestionOptionDO::getDeleteEnum, DeleteEnum.FALSE.getCode()))
|
||||
.stream()
|
||||
.map(QuestionOptionDO::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 组装选项:归一化标识、标记正确答案,按id是否在库分为更新与新增两组
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
List<QuestionOptionDO> options = questionConvertor.convertOptionDtoListToEList(optionDTOs);
|
||||
List<QuestionOptionDO> toUpdate = new ArrayList<>();
|
||||
List<QuestionOptionDO> toInsert = new ArrayList<>();
|
||||
int sortOrder = 1;
|
||||
for (QuestionOptionDO option : options) {
|
||||
String key = option.getOptionKey().trim().toUpperCase();
|
||||
option.setQuestionId(questionId);
|
||||
option.setOptionKey(key);
|
||||
option.setOptionName(key);
|
||||
option.setSortOrder(sortOrder++);
|
||||
if (option.getId() != null && existingIds.contains(option.getId())) {
|
||||
toUpdate.add(option);
|
||||
InsertFieldDefaults.applyForUpdate(option);
|
||||
} else {
|
||||
option.setId(IdUtil.getSnowflakeNextId());
|
||||
InsertFieldDefaults.applyIgnoreOrgId(option);
|
||||
toInsert.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
// 库中多余(未出现在本次请求中)的选项逻辑删除
|
||||
Set<Long> keepIds = toUpdate.stream().map(QuestionOptionDO::getId).collect(Collectors.toSet());
|
||||
List<Long> toDeleteIds = existingIds.stream()
|
||||
.filter(id -> !keepIds.contains(id))
|
||||
.collect(Collectors.toList());
|
||||
if (!toDeleteIds.isEmpty()) {
|
||||
questionOptionMapper.update(new LambdaUpdateWrapper<QuestionOptionDO>()
|
||||
.set(QuestionOptionDO::getDeleteEnum, DeleteEnum.TRUE.getCode())
|
||||
.set(QuestionOptionDO::getUpdateTime, now)
|
||||
.in(QuestionOptionDO::getId, toDeleteIds));
|
||||
}
|
||||
Db.updateBatchById(toUpdate);
|
||||
Db.saveBatch(toInsert);
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,8 @@ public class PaperServiceImpl extends ServiceImpl<PaperMapper, PaperDO> implemen
|
|||
target.setStatus(source.getStatus());
|
||||
target.setPaperType(source.getPaperType());
|
||||
target.setConfigRule(source.getConfigRule());
|
||||
target.setExamTime(source.getExamTime());
|
||||
InsertFieldDefaults.applyIgnoreOrgId(target);
|
||||
this.savePaper(target);
|
||||
|
||||
// 复制试题+选项+试卷试题关系(id全部换新雪花id)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
package org.qinan.cedu.service.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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.mapper.QuestionMapper;
|
||||
import org.qinan.cedu.mapper.QuestionOptionMapper;
|
||||
import org.qinan.cedu.model.dto.PaperQuestionPageQueryDTO;
|
||||
import org.qinan.cedu.model.dto.QuestionOptionUpdateDTO;
|
||||
import org.qinan.cedu.model.dto.QuestionTypeCountQueryDTO;
|
||||
|
|
@ -19,10 +22,8 @@ import org.qinan.cedu.model.entity.QuestionOptionDO;
|
|||
import org.qinan.cedu.model.vo.PaperQuestionVO;
|
||||
import org.qinan.cedu.model.vo.QuestionTypeCountVO;
|
||||
import org.qinan.cedu.model.vo.QuestionVO;
|
||||
import org.qinan.cedu.service.QuestionOptionService;
|
||||
import org.qinan.cedu.service.QuestionService;
|
||||
import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
|
@ -42,9 +43,7 @@ import java.util.stream.Collectors;
|
|||
@RequiredArgsConstructor
|
||||
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO> implements QuestionService {
|
||||
|
||||
@Autowired
|
||||
private QuestionOptionService questionOptionService;
|
||||
|
||||
private final QuestionOptionMapper questionOptionMapper;
|
||||
private final QuestionConvertor questionConvertor;
|
||||
|
||||
@Override
|
||||
|
|
@ -59,15 +58,14 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO>
|
|||
throw new IllegalArgumentException("试题不存在");
|
||||
}
|
||||
// 查询选项信息(仅查询VO需要的字段)
|
||||
List<QuestionOptionDO> options = questionOptionService.lambdaQuery()
|
||||
List<QuestionOptionDO> options = questionOptionMapper.selectList(new LambdaQueryWrapper<QuestionOptionDO>()
|
||||
.select(QuestionOptionDO::getId, QuestionOptionDO::getQuestionId,
|
||||
QuestionOptionDO::getOptionKey, QuestionOptionDO::getOptionName,
|
||||
QuestionOptionDO::getOptionText, QuestionOptionDO::getIsCorrect,
|
||||
QuestionOptionDO::getSortOrder)
|
||||
.eq(QuestionOptionDO::getQuestionId, questionId)
|
||||
.eq(QuestionOptionDO::getDeleteEnum, DeleteEnum.FALSE.getCode())
|
||||
.orderByAsc(QuestionOptionDO::getSortOrder)
|
||||
.list();
|
||||
.orderByAsc(QuestionOptionDO::getSortOrder));
|
||||
questionVO.setQuestionOptionVOList(questionConvertor.convertOptionEListToVoList(options));
|
||||
return questionVO;
|
||||
}
|
||||
|
|
@ -121,11 +119,10 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO>
|
|||
*/
|
||||
private List<QuestionOptionDO> syncOptions(Long questionId, List<QuestionOptionUpdateDTO> optionDTOs) {
|
||||
// 查询该试题现存未删除的选项id
|
||||
Set<Long> existingIds = questionOptionService.lambdaQuery()
|
||||
.select(QuestionOptionDO::getId)
|
||||
.eq(QuestionOptionDO::getQuestionId, questionId)
|
||||
.eq(QuestionOptionDO::getDeleteEnum, DeleteEnum.FALSE.getCode())
|
||||
.list()
|
||||
Set<Long> existingIds = questionOptionMapper.selectList(new LambdaQueryWrapper<QuestionOptionDO>()
|
||||
.select(QuestionOptionDO::getId)
|
||||
.eq(QuestionOptionDO::getQuestionId, questionId)
|
||||
.eq(QuestionOptionDO::getDeleteEnum, DeleteEnum.FALSE.getCode()))
|
||||
.stream()
|
||||
.map(QuestionOptionDO::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
|
@ -158,14 +155,13 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO>
|
|||
.filter(id -> !keepIds.contains(id))
|
||||
.collect(Collectors.toList());
|
||||
if (!toDeleteIds.isEmpty()) {
|
||||
questionOptionService.lambdaUpdate()
|
||||
questionOptionMapper.update(new LambdaUpdateWrapper<QuestionOptionDO>()
|
||||
.set(QuestionOptionDO::getDeleteEnum, DeleteEnum.TRUE.getCode())
|
||||
.set(QuestionOptionDO::getUpdateTime, now)
|
||||
.in(QuestionOptionDO::getId, toDeleteIds)
|
||||
.update();
|
||||
.in(QuestionOptionDO::getId, toDeleteIds));
|
||||
}
|
||||
questionOptionService.updateBatchById(toUpdate);
|
||||
questionOptionService.saveBatch(toInsert);
|
||||
Db.updateBatchById(toUpdate);
|
||||
Db.saveBatch(toInsert);
|
||||
return options;
|
||||
}
|
||||
|
||||
|
|
@ -185,11 +181,6 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO>
|
|||
if (questionDO == null) {
|
||||
return null;
|
||||
}
|
||||
List<QuestionOptionDO> options = questionOptionService.lambdaQuery()
|
||||
.eq(QuestionOptionDO::getQuestionId, id)
|
||||
.eq(QuestionOptionDO::getDeleteEnum, DeleteEnum.FALSE.getCode())
|
||||
.orderByAsc(QuestionOptionDO::getSortOrder)
|
||||
.list();
|
||||
return questionDO;
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +204,7 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO>
|
|||
questionDO.setUpdateTime(now);
|
||||
boolean updated = this.updateById(questionDO);
|
||||
if (updated) {
|
||||
questionOptionService.remove(Wrappers.<QuestionOptionDO>lambdaQuery()
|
||||
questionOptionMapper.delete(new LambdaUpdateWrapper<QuestionOptionDO>()
|
||||
.eq(QuestionOptionDO::getQuestionId, questionDO.getId()));
|
||||
saveOptions(questionDO.getId(), options, now);
|
||||
}
|
||||
|
|
@ -230,11 +221,10 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO>
|
|||
.eq(QuestionDO::getDeleteEnum, DeleteEnum.FALSE.getCode())
|
||||
.update();
|
||||
if (deleted) {
|
||||
questionOptionService.lambdaUpdate()
|
||||
questionOptionMapper.update(new LambdaUpdateWrapper<QuestionOptionDO>()
|
||||
.set(QuestionOptionDO::getDeleteEnum, DeleteEnum.TRUE.getCode())
|
||||
.set(QuestionOptionDO::getUpdateTime, LocalDateTime.now())
|
||||
.eq(QuestionOptionDO::getQuestionId, id)
|
||||
.update();
|
||||
.eq(QuestionOptionDO::getQuestionId, id));
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
|
@ -256,6 +246,6 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, QuestionDO>
|
|||
option.setCreateTime(now);
|
||||
option.setUpdateTime(now);
|
||||
});
|
||||
questionOptionService.saveBatch(options);
|
||||
Db.saveBatch(options);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue