PaperBasicInfo

dev-tmp1
luotaiqian 2026-08-20 09:37:54 +08:00
parent 6d3a68921c
commit 436cc83033
15 changed files with 261 additions and 2 deletions

View File

@ -0,0 +1,11 @@
-- =====================================================================
-- 变更说明:
-- 1. paper 表新增 paper_type(试卷类型, varchar(36), 非空, 默认fixed:
-- fixed平台试卷,config_rule规则试卷)
-- 2. paper 表新增 config_rule(配置规则, text, 可空)
-- 变更时间: 2026-08-20
-- =====================================================================
ALTER TABLE `paper`
ADD COLUMN `paper_type` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'fixed' COMMENT '试卷类型 fixed平台试卷,config_rule规则试卷' AFTER `status`,
ADD COLUMN `config_rule` text COLLATE utf8mb4_general_ci COMMENT '配置规则' AFTER `paper_type`;

View File

@ -3,9 +3,11 @@ package org.qinan.cedu.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.qinan.cedu.model.dto.*;
import org.qinan.cedu.model.vo.PaperImportVO;
import org.qinan.cedu.model.vo.PaperExamInfoVO;
import org.qinan.cedu.model.vo.PaperPageVO;
import org.qinan.cedu.model.vo.PaperQuestionVO;
import org.qinan.cedu.service.PaperService;
@ -73,4 +75,11 @@ public class PaperController {
IPage<PaperQuestionVO> page = questionService.pagePaperQuestions(query);
return PageResponse.of(page.getRecords(), page.getTotal());
}
@ApiOperation("试卷考试信息查询")
@GetMapping("/paper/exam/info")
public SingleResponse<PaperExamInfoVO> paperExamInfo(@RequestParam("paperId") @ApiParam(value = "试卷id", required = true) Long paperId) {
PaperExamInfoVO pageInfo = paperService.paperExamInfo(paperId);
return SingleResponse.success(pageInfo);
}
}

View File

@ -2,6 +2,7 @@ package org.qinan.cedu.convertor;
import org.mapstruct.Mapper;
import org.qinan.cedu.model.entity.PaperDO;
import org.qinan.cedu.model.vo.PaperBasicInfoVO;
import org.qinan.cedu.model.vo.PaperPageVO;
import java.util.List;
@ -12,4 +13,12 @@ public interface PaperConvertor {
PaperPageVO convertEToVo(PaperDO entity);
List<PaperPageVO> convertEListToVoList(List<PaperDO> list);
/**
* VO
*
* @param entity
* @return VO
*/
PaperBasicInfoVO convertEToBasicVo(PaperDO entity);
}

View File

@ -0,0 +1,46 @@
package org.qinan.cedu.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*
*/
@Getter
@AllArgsConstructor
public enum PaperTypeEnum {
/**
*
*/
FIXED("fixed", "平台试卷"),
/**
*
*/
CONFIG_RULE("config_rule", "规则试卷");
/**
*
*/
private final String value;
/**
*
*/
private final String label;
public static final String REMARKS = "试卷类型 fixed平台试卷,config_rule规则试卷";
/**
*
*/
public static PaperTypeEnum fromCode(String code) {
for (PaperTypeEnum type : values()) {
if (type.value.equals(code)) {
return type;
}
}
return null;
}
}

View File

@ -36,6 +36,14 @@ public interface QuestionMapper extends BaseMapper<QuestionDO> {
*/
QuestionVO findQuestion(@Param("questionId") Long questionId);
/**
*
*
* @param paperId id
* @return VO
*/
List<QuestionVO> listPaperQuestions(@Param("paperId") Long paperId);
/**
* SQL
*

View File

@ -0,0 +1,9 @@
package org.qinan.cedu.model.dto;
import lombok.Data;
@Data
public class PaperConfigRuleDTO {
// private
}

View File

@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.qinan.cedu.enums.PaperTypeEnum;
import org.qinan.cedu.model.query.BasePageQuery;
import org.springframework.format.annotation.DateTimeFormat;
@ -20,6 +21,9 @@ public class PaperPageQueryDTO extends BasePageQuery {
@ApiModelProperty("试卷名称(模糊)")
private String paperName;
@ApiModelProperty(PaperTypeEnum.REMARKS)
private String paperType;
@ApiModelProperty("创建时间-开始yyyy-MM-dd含当天")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate createTimeStart;

View File

@ -38,4 +38,11 @@ public class PaperUpdateDTO {
@DecimalMin(value = "0", message = "合格分数不能小于0")
@DecimalMax(value = "9999.99", message = "合格分数不能超过9999.99")
private BigDecimal paperPassScore;
@ApiModelProperty("试卷类型 fixed平台试卷,config_rule规则试卷")
@Size(max = 36, message = "试卷类型长度不能超过36个字符")
private String paperType;
@ApiModelProperty("配置规则")
private String configRule;
}

View File

@ -36,4 +36,10 @@ public class PaperDO extends BaseEntity {
@ApiModelProperty("试卷状态 normal 正常")
private String status;
@ApiModelProperty("试卷类型 fixed平台试卷,config_rule规则试卷")
private String paperType;
@ApiModelProperty("配置规则")
private String configRule;
}

View File

@ -0,0 +1,45 @@
package org.qinan.cedu.model.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
*
*/
@Data
@ApiModel(value = "PaperBasicInfoVO", description = "试卷基础信息")
public class PaperBasicInfoVO {
@ApiModelProperty("id")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@ApiModelProperty("试卷名称")
private String paperName;
@ApiModelProperty("试卷总分")
private BigDecimal paperTotalScore;
@ApiModelProperty("合格分数")
private BigDecimal paperPassScore;
@ApiModelProperty("试卷状态 normal 正常")
private String status;
@ApiModelProperty("试卷类型 fixed平台试卷,config_rule规则试卷")
private String paperType;
@ApiModelProperty("配置规则")
private String configRule;
}

View File

@ -0,0 +1,21 @@
package org.qinan.cedu.model.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
*
*/
@Data
@ApiModel(value = "PaperExamInfoVO", description = "试卷考试信息")
public class PaperExamInfoVO {
@ApiModelProperty("试卷基本信息")
private PaperBasicInfoVO paperBasicInfoVO;
@ApiModelProperty("试题信息")
private List<QuestionVO> questionVOList;
}

View File

@ -33,6 +33,12 @@ public class PaperPageVO {
@ApiModelProperty("试卷状态 normal 正常")
private String status;
@ApiModelProperty("试卷类型 fixed平台试卷,config_rule规则试卷")
private String paperType;
@ApiModelProperty("配置规则")
private String configRule;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;

View File

@ -8,6 +8,7 @@ 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.vo.PaperImportVO;
import org.qinan.cedu.model.vo.PaperExamInfoVO;
import org.qinan.cedu.model.vo.PaperPageVO;
import java.util.List;
@ -20,7 +21,7 @@ public interface PaperService extends IService<PaperDO> {
/**
*
*
* @param query
* @param query
* @return
*/
IPage<PaperPageVO> pageQuery(PaperPageQueryDTO query);
@ -88,5 +89,11 @@ public interface PaperService extends IService<PaperDO> {
*/
String importQuestionsTemplate();
/**
* +
*
* @param paperId id
* @return
*/
PaperExamInfoVO paperExamInfo(Long paperId);
}

View File

@ -10,10 +10,13 @@ import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.qinan.cedu.convertor.PaperConvertor;
import org.qinan.cedu.convertor.QuestionConvertor;
import org.qinan.cedu.enums.DeleteEnum;
import org.qinan.cedu.enums.PaperStatusEnum;
import org.qinan.cedu.enums.PaperTypeEnum;
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.PaperCopyDTO;
import org.qinan.cedu.model.dto.PaperImportDTO;
@ -23,8 +26,11 @@ import org.qinan.cedu.model.entity.PaperDO;
import org.qinan.cedu.model.entity.PaperQuestionRelDO;
import org.qinan.cedu.model.entity.QuestionDO;
import org.qinan.cedu.model.entity.QuestionOptionDO;
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.support.QuestionExcelImporter;
import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults;
@ -49,9 +55,11 @@ import java.util.stream.Collectors;
public class PaperServiceImpl extends ServiceImpl<PaperMapper, PaperDO> implements PaperService {
private final PaperQuestionRelMapper paperQuestionRelMapper;
private final QuestionMapper questionMapper;
private final QuestionOptionMapper questionOptionMapper;
private final QuestionExcelImporter questionExcelImporter;
private final PaperConvertor paperConvertor;
private final QuestionConvertor questionConvertor;
@Value("${template.paper.importUrl:}")
private String paperImportUrl;
@ -131,6 +139,8 @@ public class PaperServiceImpl extends ServiceImpl<PaperMapper, PaperDO> implemen
target.setPaperTotalScore(copyDTO.getPaperTotalScore());
target.setPaperPassScore(copyDTO.getPaperPassScore());
target.setStatus(source.getStatus());
target.setPaperType(source.getPaperType());
target.setConfigRule(source.getConfigRule());
this.savePaper(target);
// 复制试题+选项+试卷试题关系id全部换新雪花id
@ -266,4 +276,52 @@ public class PaperServiceImpl extends ServiceImpl<PaperMapper, PaperDO> implemen
public String importQuestionsTemplate() {
return paperImportUrl;
}
@Override
public PaperExamInfoVO paperExamInfo(Long paperId) {
// 1. 查询试卷基础信息
PaperDO paper = this.lambdaQuery()
.eq(PaperDO::getId, paperId)
.eq(PaperDO::getDeleteEnum, DeleteEnum.FALSE.getCode())
.one();
if (paper == null) {
throw new IllegalArgumentException("试卷不存在");
}
PaperExamInfoVO examInfoVO = new PaperExamInfoVO();
examInfoVO.setPaperBasicInfoVO(paperConvertor.convertEToBasicVo(paper));
// 2. 查询试卷下试题(关联课件名称)并填充选项
List<QuestionVO> questionVOList = questionMapper.listPaperQuestions(paperId);
fillQuestionOptions(questionVOList);
examInfoVO.setQuestionVOList(questionVOList);
return examInfoVO;
}
/**
* id
*
* @param questionVOList VO
*/
private void fillQuestionOptions(List<QuestionVO> questionVOList) {
if (CollectionUtils.isEmpty(questionVOList)) {
return;
}
List<Long> questionIds = questionVOList.stream()
.map(question -> Long.valueOf(question.getId()))
.collect(Collectors.toList());
// 查询选项信息仅查询VO需要的字段按显示顺序排序
List<QuestionOptionDO> optionList = questionOptionMapper.selectList(new LambdaQueryWrapper<QuestionOptionDO>()
.select(QuestionOptionDO::getId, QuestionOptionDO::getQuestionId,
QuestionOptionDO::getOptionKey, QuestionOptionDO::getOptionName,
QuestionOptionDO::getOptionText, QuestionOptionDO::getIsCorrect,
QuestionOptionDO::getSortOrder)
.in(QuestionOptionDO::getQuestionId, questionIds)
.eq(QuestionOptionDO::getDeleteEnum, DeleteEnum.FALSE.getCode())
.orderByAsc(QuestionOptionDO::getSortOrder));
Map<Long, List<QuestionOptionVO>> optionMap = questionConvertor.convertOptionEListToVoList(optionList)
.stream()
.collect(Collectors.groupingBy(QuestionOptionVO::getQuestionId));
questionVOList.forEach(question -> question.setQuestionOptionVOList(
optionMap.getOrDefault(Long.valueOf(question.getId()), new ArrayList<>())));
}
}

View File

@ -32,6 +32,19 @@
AND q.delete_enum = 'false'
</select>
<select id="listPaperQuestions" resultType="org.qinan.cedu.model.vo.QuestionVO">
SELECT q.id, q.title, q.question_type, q.answer, q.answer_question_option_ids
, q.score, q.analysis, q.tag_type, q.courseware_management_id
, cm.courseware_name AS coursewareManagementName
FROM paper_question_rel pqr
JOIN question q ON pqr.question_id = q.id
LEFT JOIN courseware_management cm ON cm.id = q.courseware_management_id
WHERE pqr.paper_id = #{paperId}
AND pqr.delete_enum = 'false'
AND q.delete_enum = 'false'
ORDER BY pqr.question_num ASC, pqr.id ASC
</select>
<select id="countQuestionType" resultType="org.qinan.cedu.model.vo.QuestionTypeCountVO">
SELECT q.question_type AS questionType, COUNT(*) AS `count`
FROM question q