From a4e5283f86727153a47c3bca55a0fccd7e72da8d Mon Sep 17 00:00:00 2001 From: luotaiqian <1147642922@qq.com> Date: Thu, 20 Aug 2026 11:04:01 +0800 Subject: [PATCH] PaperBasicInfo --- .../cedu/controller/PaperController.java | 11 +++-- .../org/qinan/cedu/mapper/QuestionMapper.java | 12 +++++ .../cedu/model/dto/PaperConfigRuleDTO.java | 29 +++++++++++ .../dto/PaperCoursewareQuestionRuleDTO.java | 49 +++++++++++++++++++ .../qinan/cedu/model/dto/PaperImportDTO.java | 9 ++-- .../org/qinan/cedu/service/PaperService.java | 11 +++++ .../cedu/service/impl/PaperServiceImpl.java | 47 ++++++++++++++++++ .../main/resources/mapper/QuestionMapper.xml | 13 +++++ 8 files changed, 171 insertions(+), 10 deletions(-) create mode 100644 safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperCoursewareQuestionRuleDTO.java diff --git a/safety-cedu-service/src/main/java/org/qinan/cedu/controller/PaperController.java b/safety-cedu-service/src/main/java/org/qinan/cedu/controller/PaperController.java index 087687da..3b43b48a 100644 --- a/safety-cedu-service/src/main/java/org/qinan/cedu/controller/PaperController.java +++ b/safety-cedu-service/src/main/java/org/qinan/cedu/controller/PaperController.java @@ -6,10 +6,7 @@ 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.model.vo.*; import org.qinan.cedu.service.PaperService; import org.qinan.cedu.service.QuestionService; import org.qinan.safetyeval.client.dto.PageResponse; @@ -69,6 +66,12 @@ public class PaperController { return SingleResponse.success(paperService.importQuestionsTemplate()); } + @ApiOperation("新建试卷-自动生成试卷") + @PostMapping("/courseware/question/rule") + public SingleResponse coursewareQuestionRule(@Validated @RequestBody PaperCoursewareQuestionRuleDTO dto) { + return SingleResponse.success(paperService.coursewareQuestionRule(dto)); + } + @ApiOperation("试卷试题分页查询") @GetMapping("/paper/question/page") public PageResponse page(@Validated PaperQuestionPageQueryDTO query) { diff --git a/safety-cedu-service/src/main/java/org/qinan/cedu/mapper/QuestionMapper.java b/safety-cedu-service/src/main/java/org/qinan/cedu/mapper/QuestionMapper.java index 0e57c26b..d4887758 100644 --- a/safety-cedu-service/src/main/java/org/qinan/cedu/mapper/QuestionMapper.java +++ b/safety-cedu-service/src/main/java/org/qinan/cedu/mapper/QuestionMapper.java @@ -51,4 +51,16 @@ public interface QuestionMapper extends BaseMapper { * @return 各题型的试题数量 */ List countQuestionType(@Param("dto") QuestionTypeCountQueryDTO dto); + + /** + * 按课件id集合+题型随机抽取指定数量的试题id + * + * @param coursewareManagementIdList 课件管理id列表 + * @param questionType 题型编码 + * @param num 抽取数量 + * @return 随机试题id列表 + */ + List listRandomQuestionIds(@Param("coursewareManagementIdList") List coursewareManagementIdList, + @Param("questionType") String questionType, + @Param("num") Integer num); } diff --git a/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperConfigRuleDTO.java b/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperConfigRuleDTO.java index 39b13d39..1088d0d1 100644 --- a/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperConfigRuleDTO.java +++ b/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperConfigRuleDTO.java @@ -1,9 +1,38 @@ package org.qinan.cedu.model.dto; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import org.hibernate.validator.constraints.Range; +import org.qinan.cedu.enums.QuestionTypeEnum; + +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import java.math.BigDecimal; @Data public class PaperConfigRuleDTO { // private + + + @Data + public static class QuestionTypeRule { + @ApiModelProperty(QuestionTypeEnum.REMARKS) + @NotNull(message = QuestionTypeEnum.REMARKS) + @Pattern(regexp = QuestionTypeEnum.PATTERN) + private String questionType; + + @ApiModelProperty("需要的试题数量") + @NotNull(message = "试题数量1-1024") + @Range(min = 1, max = 1024, message = "试题数量1-1024") + private Integer num; + + @ApiModelProperty("每题的分数") + @NotNull(message = "每题的分数") + @DecimalMin(value = "0.1") + @DecimalMax(value = "999.9") + private BigDecimal score; + } } diff --git a/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperCoursewareQuestionRuleDTO.java b/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperCoursewareQuestionRuleDTO.java new file mode 100644 index 00000000..8016f521 --- /dev/null +++ b/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperCoursewareQuestionRuleDTO.java @@ -0,0 +1,49 @@ +package org.qinan.cedu.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.Range; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.math.BigDecimal; +import java.util.List; + +/** + * 新建试卷-导入试题 请求对象 + */ +@Data +@ApiModel(value = "PaperImportDTO", description = "新建试卷-导入试题请求") +public class PaperCoursewareQuestionRuleDTO { + + @ApiModelProperty(value = "试卷名称", required = true) + @NotBlank(message = "试卷名称 不能为空") + @Size(max = 128, message = "试卷名称长度不能超过128个字符") + private String paperName; + + @ApiModelProperty(value = "试卷总分", required = true) + @NotNull(message = "试卷总分不能为空") + @DecimalMin(value = "0.1", message = "试卷总分必须大于0") + @DecimalMax(value = "9999.9", message = "试卷总分不能超过9999.99") + private BigDecimal paperTotalScore; + + @ApiModelProperty(value = "合格分数", required = true) + @NotNull(message = "合格分数不能为空") + @DecimalMin(value = "0", message = "合格分数不能小于0") + @DecimalMax(value = "9999.9", message = "合格分数不能超过9999.99") + private BigDecimal paperPassScore; + + @ApiModelProperty("考试时长(分钟)") + @Range(min = 1, max = 3600, message = "考试时长必须大于0小于3600") + private Integer examTime; + + @ApiModelProperty("课件id") + @NotNull(message = "请选择课程课件") + @Size(min = 1, max = 1024, message = "请选择课程课件") + private List coursewareManagementIdList; + + @NotNull(message = "试题规则不能为空") + @Valid + private List questionTypeRuleList; +} diff --git a/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperImportDTO.java b/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperImportDTO.java index 55dd7adc..6db92657 100644 --- a/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperImportDTO.java +++ b/safety-cedu-service/src/main/java/org/qinan/cedu/model/dto/PaperImportDTO.java @@ -3,13 +3,10 @@ package org.qinan.cedu.model.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import org.hibernate.validator.constraints.Range; import org.springframework.web.multipart.MultipartFile; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import javax.validation.constraints.*; import java.math.BigDecimal; /** @@ -37,7 +34,7 @@ public class PaperImportDTO { private BigDecimal paperPassScore; @ApiModelProperty("考试时长(分钟)") - @Min(value = 1, message = "考试时长必须大于0") + @Range(min = 1, max = 3600, message = "考试时长必须大于0小于3600") private Integer examTime; @ApiModelProperty(value = "试题Excel文件(第一个sheet单选题,第二个sheet多选题,第三个sheet判断题)", required = true) diff --git a/safety-cedu-service/src/main/java/org/qinan/cedu/service/PaperService.java b/safety-cedu-service/src/main/java/org/qinan/cedu/service/PaperService.java index 42110b03..eeb0560b 100644 --- a/safety-cedu-service/src/main/java/org/qinan/cedu/service/PaperService.java +++ b/safety-cedu-service/src/main/java/org/qinan/cedu/service/PaperService.java @@ -3,10 +3,12 @@ package org.qinan.cedu.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; 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.PaperPageQueryDTO; import org.qinan.cedu.model.dto.PaperUpdateDTO; import org.qinan.cedu.model.entity.PaperDO; +import org.qinan.cedu.model.vo.PaperBasicInfoVO; import org.qinan.cedu.model.vo.PaperImportVO; import org.qinan.cedu.model.vo.PaperExamInfoVO; import org.qinan.cedu.model.vo.PaperPageVO; @@ -89,6 +91,15 @@ public interface PaperService extends IService { */ String importQuestionsTemplate(); + /** + * 新建试卷-自动生成试卷:按题型规则从关联课件下随机抽题,某题型数量不足直接报错, + * 全部满足后创建试卷(规则试卷)并绑定试卷试题关系 + * + * @param dto 试卷信息+课件id列表+题型抽题规则 + * @return 试卷基础信息 + */ + PaperBasicInfoVO coursewareQuestionRule(PaperCoursewareQuestionRuleDTO dto); + /** * 查询试卷考试信息(试卷基础信息+试题列表含选项) * diff --git a/safety-cedu-service/src/main/java/org/qinan/cedu/service/impl/PaperServiceImpl.java b/safety-cedu-service/src/main/java/org/qinan/cedu/service/impl/PaperServiceImpl.java index 5deb2081..7739c14f 100644 --- a/safety-cedu-service/src/main/java/org/qinan/cedu/service/impl/PaperServiceImpl.java +++ b/safety-cedu-service/src/main/java/org/qinan/cedu/service/impl/PaperServiceImpl.java @@ -1,6 +1,7 @@ package org.qinan.cedu.service.impl; import cn.hutool.core.util.IdUtil; +import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -14,11 +15,14 @@ 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.enums.QuestionTypeEnum; 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.PaperConfigRuleDTO; 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.PaperPageQueryDTO; import org.qinan.cedu.model.dto.PaperUpdateDTO; @@ -26,6 +30,7 @@ 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.PaperBasicInfoVO; import org.qinan.cedu.model.vo.PaperExamInfoVO; import org.qinan.cedu.model.vo.PaperImportVO; import org.qinan.cedu.model.vo.PaperPageVO; @@ -278,6 +283,48 @@ public class PaperServiceImpl extends ServiceImpl implemen return paperImportUrl; } + @Override + @Transactional(rollbackFor = Exception.class) + public PaperBasicInfoVO coursewareQuestionRule(PaperCoursewareQuestionRuleDTO dto) { + // 1. 循环题型规则从关联课件下随机抽题,某题型数量不足直接报错 + List questionIds = new ArrayList<>(); + for (PaperConfigRuleDTO.QuestionTypeRule rule : dto.getQuestionTypeRuleList()) { + List ids = questionMapper.listRandomQuestionIds( + dto.getCoursewareManagementIdList(), rule.getQuestionType(), rule.getNum()); + if (ids.size() < rule.getNum()) { + QuestionTypeEnum typeEnum = QuestionTypeEnum.fromCode(rule.getQuestionType()); + String typeDesc = typeEnum != null ? typeEnum.getDesc() : rule.getQuestionType(); + throw new IllegalArgumentException( + typeDesc + "题数量不足:需要" + rule.getNum() + "道,当前仅有" + ids.size() + "道"); + } + questionIds.addAll(ids); + } + + // 2. 创建试卷(规则试卷,保存抽题规则) + PaperDO paper = new PaperDO(); + paper.setPaperName(dto.getPaperName().trim()); + paper.setPaperTotalScore(dto.getPaperTotalScore()); + paper.setPaperPassScore(dto.getPaperPassScore()); + paper.setExamTime(dto.getExamTime()); + paper.setPaperType(PaperTypeEnum.CONFIG_RULE.getValue()); + paper.setConfigRule(JSONUtil.toJsonStr(dto.getQuestionTypeRuleList())); + InsertFieldDefaults.applyIgnoreOrgId(paper); + this.savePaper(paper); + + // 3. 绑定试卷试题关系(含试题号) + List rels = new ArrayList<>(questionIds.size()); + for (int i = 0; i < questionIds.size(); i++) { + PaperQuestionRelDO rel = new PaperQuestionRelDO(); + rel.setPaperId(paper.getId()); + rel.setQuestionId(questionIds.get(i)); + rel.setQuestionNum(i + 1); + InsertFieldDefaults.applyIgnoreOrgId(rel); + rels.add(rel); + } + Db.saveBatch(rels); + return paperConvertor.convertEToBasicVo(paper); + } + @Override public PaperExamInfoVO paperExamInfo(Long paperId) { // 1. 查询试卷基础信息 diff --git a/safety-cedu-service/src/main/resources/mapper/QuestionMapper.xml b/safety-cedu-service/src/main/resources/mapper/QuestionMapper.xml index 01313eae..965600ac 100644 --- a/safety-cedu-service/src/main/resources/mapper/QuestionMapper.xml +++ b/safety-cedu-service/src/main/resources/mapper/QuestionMapper.xml @@ -55,4 +55,17 @@ AND q.delete_enum = 'false' GROUP BY q.question_type + +