From 0b0311d2d97c6bafb3137e80da36a1d260e42dcf Mon Sep 17 00:00:00 2001 From: lbw <1192299468@qq.com> Date: Thu, 25 Dec 2025 18:05:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor(exam):=20=E4=BC=98=E5=8C=96=E8=80=83?= =?UTF-8?q?=E8=AF=95=E5=8D=95=E8=AF=8D=E7=94=9F=E6=88=90=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=B9=B6=E6=96=B0=E5=A2=9E=E6=9C=9F=E4=B8=AD=E6=9C=9F=E6=9C=AB?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整考试类型选择,增加“期中”和“期末”选项 - 删除旧的gradeId和level参数,简化接口参数为studentId和type - 新增考试类型常量:期中(2)、期末(3) - 实现期中考试和期末考试生成逻辑,分别根据年级及单元名称筛选词汇 - 调整服务层方法签名及调用,支持新考试类型生成流程 - 扩展Mapper接口,支持按单元名称和单元ID查询词汇 - 优化导出逻辑,导出文件名和压缩包名称根据考试标题动态生成 - 调整测试代码,适配新的方法参数和实现细节 --- .../service/constant/ExamWordsConstant.java | 2 + .../controller/ExamWordsController.java | 8 +-- .../service/domain/mapper/UnitDOMapper.java | 2 + .../domain/mapper/VocabularyBankDOMapper.java | 2 + .../model/vo/exam/GenerateExamWordsReqVO.java | 2 - .../service/service/ExamWordsService.java | 2 +- .../service/exam/ExamWordsServiceImpl.java | 65 +++++++++++++++---- .../enlish/service/utils/WordExportUtil.java | 17 ++--- .../main/resources/mapper/UnitDOMapper.xml | 5 ++ .../mapper/VocabularyBankDOMapper.xml | 11 ++++ .../enlish/service/service/exam/ExamTest.java | 2 +- .../layouts/components/ExamGenerateDialog.vue | 5 +- 12 files changed, 92 insertions(+), 31 deletions(-) diff --git a/enlish-service/src/main/java/com/yinlihupo/enlish/service/constant/ExamWordsConstant.java b/enlish-service/src/main/java/com/yinlihupo/enlish/service/constant/ExamWordsConstant.java index c941e73..dcdc469 100644 --- a/enlish-service/src/main/java/com/yinlihupo/enlish/service/constant/ExamWordsConstant.java +++ b/enlish-service/src/main/java/com/yinlihupo/enlish/service/constant/ExamWordsConstant.java @@ -32,6 +32,8 @@ public class ExamWordsConstant { public static final int EXAM_TYPE_BASELINE = 1; + public static final int EXAM_TYPE_MIDTERM = 2; + public static final int EXAM_TYPE_FINAL = 3; public static int getZoneA(int gradeId) { return switch (gradeId) { diff --git a/enlish-service/src/main/java/com/yinlihupo/enlish/service/controller/ExamWordsController.java b/enlish-service/src/main/java/com/yinlihupo/enlish/service/controller/ExamWordsController.java index f8a4a63..7939ae3 100644 --- a/enlish-service/src/main/java/com/yinlihupo/enlish/service/controller/ExamWordsController.java +++ b/enlish-service/src/main/java/com/yinlihupo/enlish/service/controller/ExamWordsController.java @@ -42,15 +42,13 @@ public class ExamWordsController { @PostMapping("generate") public void generateFeltExamWords(@RequestBody GenerateExamWordsReqVO generateExamWordsReqVO, HttpServletResponse response) { - Integer gradeId = generateExamWordsReqVO.getGradeId(); - Integer level = generateExamWordsReqVO.getLevel(); Integer type = generateExamWordsReqVO.getType(); Integer studentId = generateExamWordsReqVO.getStudentId(); - if (studentId == null || gradeId == null || level == null) { + if (studentId == null) { throw new RuntimeException("参数错误"); } try { - ExamWordsDO examWordsDO = examWordsService.generateExamWords(gradeId, level, studentId, type); + ExamWordsDO examWordsDO = examWordsService.generateExamWords(studentId, type); if (examWordsDO == null || examWordsDO.getWordIds().isEmpty()) { throw new RuntimeException("没有单词"); } @@ -77,7 +75,7 @@ public class ExamWordsController { return data; }).toList(); - WordExportUtil.generateExamWords(maps, response, templateWordPath); + WordExportUtil.generateExamWords(maps, examWordsDO, response, templateWordPath); } catch (Exception e) { diff --git a/enlish-service/src/main/java/com/yinlihupo/enlish/service/domain/mapper/UnitDOMapper.java b/enlish-service/src/main/java/com/yinlihupo/enlish/service/domain/mapper/UnitDOMapper.java index b148685..ba658f1 100644 --- a/enlish-service/src/main/java/com/yinlihupo/enlish/service/domain/mapper/UnitDOMapper.java +++ b/enlish-service/src/main/java/com/yinlihupo/enlish/service/domain/mapper/UnitDOMapper.java @@ -25,4 +25,6 @@ public interface UnitDOMapper { List selectUnitDOList(@Param("startIndex") Integer startIndex, @Param("pageSize") Integer pageSize); Integer selectUnitDOListCount(); + + List selectByUnitName(@Param("unitName") String unitName); } \ No newline at end of file diff --git a/enlish-service/src/main/java/com/yinlihupo/enlish/service/domain/mapper/VocabularyBankDOMapper.java b/enlish-service/src/main/java/com/yinlihupo/enlish/service/domain/mapper/VocabularyBankDOMapper.java index 55d3df3..fd5e93f 100644 --- a/enlish-service/src/main/java/com/yinlihupo/enlish/service/domain/mapper/VocabularyBankDOMapper.java +++ b/enlish-service/src/main/java/com/yinlihupo/enlish/service/domain/mapper/VocabularyBankDOMapper.java @@ -24,4 +24,6 @@ public interface VocabularyBankDOMapper { List selectVocabularyBankListByGradeIdRandom(@Param("gradeId") Integer gradeId, @Param("wordCount") Integer wordCount); Integer selectWordTotal(); + + List selectByUnitIds(@Param("unitIds") List unitIds); } \ No newline at end of file diff --git a/enlish-service/src/main/java/com/yinlihupo/enlish/service/model/vo/exam/GenerateExamWordsReqVO.java b/enlish-service/src/main/java/com/yinlihupo/enlish/service/model/vo/exam/GenerateExamWordsReqVO.java index ffdceec..2a8d431 100644 --- a/enlish-service/src/main/java/com/yinlihupo/enlish/service/model/vo/exam/GenerateExamWordsReqVO.java +++ b/enlish-service/src/main/java/com/yinlihupo/enlish/service/model/vo/exam/GenerateExamWordsReqVO.java @@ -14,8 +14,6 @@ import java.util.List; @Builder public class GenerateExamWordsReqVO { - private Integer gradeId; - private Integer level; private Integer type; private Integer studentId; } diff --git a/enlish-service/src/main/java/com/yinlihupo/enlish/service/service/ExamWordsService.java b/enlish-service/src/main/java/com/yinlihupo/enlish/service/service/ExamWordsService.java index 7505b11..c909b2d 100644 --- a/enlish-service/src/main/java/com/yinlihupo/enlish/service/service/ExamWordsService.java +++ b/enlish-service/src/main/java/com/yinlihupo/enlish/service/service/ExamWordsService.java @@ -8,7 +8,7 @@ import java.util.List; public interface ExamWordsService { - ExamWordsDO generateExamWords(Integer gradeId, Integer level, Integer studentId, Integer type); + ExamWordsDO generateExamWords(Integer studentId, Integer type); int saveExamWordsPngToDbAndLocal(MultipartFile file); diff --git a/enlish-service/src/main/java/com/yinlihupo/enlish/service/service/exam/ExamWordsServiceImpl.java b/enlish-service/src/main/java/com/yinlihupo/enlish/service/service/exam/ExamWordsServiceImpl.java index 16d6955..6bb05c8 100644 --- a/enlish-service/src/main/java/com/yinlihupo/enlish/service/service/exam/ExamWordsServiceImpl.java +++ b/enlish-service/src/main/java/com/yinlihupo/enlish/service/service/exam/ExamWordsServiceImpl.java @@ -1,14 +1,12 @@ package com.yinlihupo.enlish.service.service.exam; import com.yinlihupo.enlish.service.constant.ExamWordsConstant; -import com.yinlihupo.enlish.service.domain.dataobject.ExamWordsDO; -import com.yinlihupo.enlish.service.domain.dataobject.ExamWordsJudgeResultDO; -import com.yinlihupo.enlish.service.domain.dataobject.StudentDO; -import com.yinlihupo.enlish.service.domain.dataobject.VocabularyBankDO; +import com.yinlihupo.enlish.service.domain.dataobject.*; import com.yinlihupo.enlish.service.domain.mapper.*; import com.yinlihupo.enlish.service.service.ExamWordsService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.checkerframework.checker.nullness.qual.NonNull; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; @@ -26,8 +25,6 @@ import java.util.UUID; @Slf4j public class ExamWordsServiceImpl implements ExamWordsService { - @Resource - private GradeUnitDOMapper gradeUnitDOMapper; @Resource private VocabularyBankDOMapper vocabularyBankDOMapper; @Resource @@ -38,6 +35,8 @@ public class ExamWordsServiceImpl implements ExamWordsService { private ExamWordsJudgeResultDOMapper examWordsJudgeResultDOMapper; @Resource private StudentDOMapper studentDOMapper; + @Resource + private UnitDOMapper unitDOMapper; @Value("${templates.count}") private Integer wordCount; @@ -46,7 +45,7 @@ public class ExamWordsServiceImpl implements ExamWordsService { @Override @Transactional(rollbackFor = RuntimeException.class) - public ExamWordsDO generateExamWords(Integer gradeId, Integer level, Integer studentId, Integer type) { + public ExamWordsDO generateExamWords(Integer studentId, Integer type) { ExamWordsDO examWordsDO; @@ -54,9 +53,10 @@ public class ExamWordsServiceImpl implements ExamWordsService { if (type == ExamWordsConstant.EXAM_TYPE_BASELINE) { log.info("生成摸底测试"); examWordsDO = generateBaselineExamWords(studentId); - } else { - // todo 生成期中考试待实现 - examWordsDO = null; + } else if (type == ExamWordsConstant.EXAM_TYPE_MIDTERM) { + examWordsDO = generateMidtermExamWords(studentId); + } else { + examWordsDO = generateFinalExamWords(studentId); } return examWordsDO; @@ -95,11 +95,54 @@ public class ExamWordsServiceImpl implements ExamWordsService { .gradeId(gradeId) .level(1) .type(ExamWordsConstant.EXAM_TYPE_BASELINE) - .title("摸低测试测试" + studentDO.getName()) + .title("摸低测试" + studentDO.getName()) .createdAt(LocalDateTime.now()) .wordIds(vocabularyBankDOS.stream().map(VocabularyBankDO::getId).toList()) .build(); + return getExamWordsDO(studentId, examWordsDO); + } + + private ExamWordsDO generateMidtermExamWords(Integer studentId) { + StudentDO studentDO = studentDOMapper.selectStudentById(studentId); + Integer gradeId = studentDO.getGradeId(); + List unitDOS = unitDOMapper.selectByUnitName(ExamWordsConstant.getGradeName(gradeId) + "上"); + ExamWordsDO examWordsDO = getExamWordsDO(studentId, studentDO, gradeId, unitDOS); + examWordsDO.setTitle("期中测试" + studentDO.getName()); + return getExamWordsDO(studentId, examWordsDO); + + } + + private ExamWordsDO generateFinalExamWords(Integer studentId) { + StudentDO studentDO = studentDOMapper.selectStudentById(studentId); + Integer gradeId = studentDO.getGradeId(); + List unitDOS = unitDOMapper.selectByUnitName(ExamWordsConstant.getGradeName(gradeId)); + ExamWordsDO examWordsDO = getExamWordsDO(studentId, studentDO, gradeId, unitDOS); + examWordsDO.setTitle("期末测试" + studentDO.getName()); + return getExamWordsDO(studentId, examWordsDO); + } + + @NonNull + private ExamWordsDO getExamWordsDO(Integer studentId, StudentDO studentDO, Integer gradeId, List unitDOS) { + if (unitDOS.isEmpty()) { + throw new RuntimeException("没有找到对应的单元"); + } + List vocabularyBankDOS = vocabularyBankDOMapper.selectByUnitIds(unitDOS.stream().map(UnitDO::getId).toList()); + + ExamWordsDO examWordsDO = ExamWordsDO.builder() + .gradeId(gradeId) + .level(1) + .type(ExamWordsConstant.EXAM_TYPE_BASELINE) + .title(studentDO.getName()) + .createdAt(LocalDateTime.now()) + .wordIds(vocabularyBankDOS.stream().map(VocabularyBankDO::getId).toList()) + .build(); + + return getExamWordsDO(studentId, examWordsDO); + } + + @NonNull + private ExamWordsDO getExamWordsDO(Integer studentId, ExamWordsDO examWordsDO) { int insert = examWordsDOMapper.insert(examWordsDO); if (insert <= 0) { throw new RuntimeException("插入考试失败"); diff --git a/enlish-service/src/main/java/com/yinlihupo/enlish/service/utils/WordExportUtil.java b/enlish-service/src/main/java/com/yinlihupo/enlish/service/utils/WordExportUtil.java index 265e40c..e6e7c9b 100644 --- a/enlish-service/src/main/java/com/yinlihupo/enlish/service/utils/WordExportUtil.java +++ b/enlish-service/src/main/java/com/yinlihupo/enlish/service/utils/WordExportUtil.java @@ -3,6 +3,7 @@ package com.yinlihupo.enlish.service.utils; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; +import com.yinlihupo.enlish.service.domain.dataobject.ExamWordsDO; import jakarta.servlet.http.HttpServletResponse; import java.io.*; @@ -48,7 +49,7 @@ public class WordExportUtil { /** * 公共入口:根据数据量决定是导出单文件还是压缩包 */ - public static void generateExamWords(List> data, HttpServletResponse response, String templateWordPath) { + public static void generateExamWords(List> data, ExamWordsDO examWordsDO, HttpServletResponse response, String templateWordPath) { if (data == null || data.isEmpty()) { return; } @@ -56,10 +57,10 @@ public class WordExportUtil { try { if (data.size() == 1) { // 如果只有一份数据,直接导出 docx,用户体验更好 - generateExamWordsDocx(data.get(0), response, templateWordPath); + generateExamWordsDocx(data.get(0), examWordsDO, response, templateWordPath); } else { // 如果有多份数据,打包导出 - generateExamWordsZip(data, response, templateWordPath); + generateExamWordsZip(data, examWordsDO, response, templateWordPath); } } catch (IOException e) { e.printStackTrace(); @@ -92,9 +93,9 @@ public class WordExportUtil { /** * 核心补充:批量渲染并打包为 ZIP */ - private static void generateExamWordsZip(List> data, HttpServletResponse response, String templateWordPath) throws IOException { + private static void generateExamWordsZip(List> data, ExamWordsDO examWordsDO, HttpServletResponse response, String templateWordPath) throws IOException { // 1. 设置响应头为 ZIP - String zipName = URLEncoder.encode("批量导出_摸底测试.zip", StandardCharsets.UTF_8).replaceAll("\\+", "%20"); + String zipName = URLEncoder.encode("批量导出_" + examWordsDO.getTitle() + ".zip", StandardCharsets.UTF_8).replaceAll("\\+", "%20"); response.setContentType("application/zip"); response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + zipName); @@ -106,7 +107,7 @@ public class WordExportUtil { for (Map itemData : data) { // 3. 确定压缩包内的文件名 // 优先从 map 中获取 'fileName' 字段,否则使用默认编号 - String entryName = (String) itemData.getOrDefault("fileName", "摸底测试_" + index); + String entryName = (String) itemData.getOrDefault("fileName", + index); // 确保文件名后缀正确 if (!entryName.endsWith(".docx")) { entryName += ".docx"; @@ -143,9 +144,9 @@ public class WordExportUtil { /** * 现有的单文件导出逻辑 */ - private static void generateExamWordsDocx(Map data, HttpServletResponse response, String templateWordPath) throws IOException { + private static void generateExamWordsDocx(Map data, ExamWordsDO examWordsDO, HttpServletResponse response, String templateWordPath) throws IOException { - String fileName = URLEncoder.encode("摸底测试" + ".docx", StandardCharsets.UTF_8).replaceAll("\\+", "%20"); + String fileName = URLEncoder.encode(examWordsDO.getTitle() + ".docx", StandardCharsets.UTF_8).replaceAll("\\+", "%20"); // 3. 设置响应头 response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); diff --git a/enlish-service/src/main/resources/mapper/UnitDOMapper.xml b/enlish-service/src/main/resources/mapper/UnitDOMapper.xml index f58a88e..d5a3957 100644 --- a/enlish-service/src/main/resources/mapper/UnitDOMapper.xml +++ b/enlish-service/src/main/resources/mapper/UnitDOMapper.xml @@ -101,5 +101,10 @@ select count(*) from unit + \ No newline at end of file diff --git a/enlish-service/src/main/resources/mapper/VocabularyBankDOMapper.xml b/enlish-service/src/main/resources/mapper/VocabularyBankDOMapper.xml index d6579f6..04acfc1 100644 --- a/enlish-service/src/main/resources/mapper/VocabularyBankDOMapper.xml +++ b/enlish-service/src/main/resources/mapper/VocabularyBankDOMapper.xml @@ -135,4 +135,15 @@ limit #{wordCount} + + \ No newline at end of file diff --git a/enlish-service/src/test/java/com/yinlihupo/enlish/service/service/exam/ExamTest.java b/enlish-service/src/test/java/com/yinlihupo/enlish/service/service/exam/ExamTest.java index b087d87..8e6b80d 100644 --- a/enlish-service/src/test/java/com/yinlihupo/enlish/service/service/exam/ExamTest.java +++ b/enlish-service/src/test/java/com/yinlihupo/enlish/service/service/exam/ExamTest.java @@ -26,7 +26,7 @@ public class ExamTest { private VocabularyService vocabularyService; @Test public void test() { - ExamWordsDO examWordsDO = examWordsService.generateExamWords(5, 0, 1, 0); + ExamWordsDO examWordsDO = examWordsService.generateExamWords(5, 0); log.info("{}", examWordsDO); List vocabularyBankDOS = vocabularyService.findVocabularyBankDOListById(examWordsDO.getWordIds()); List assessmentWords = vocabularyBankDOS.stream().map(vocabularyBankDO -> Word.builder() diff --git a/enlish-vue/src/layouts/components/ExamGenerateDialog.vue b/enlish-vue/src/layouts/components/ExamGenerateDialog.vue index 4e0c7f0..69b670e 100644 --- a/enlish-vue/src/layouts/components/ExamGenerateDialog.vue +++ b/enlish-vue/src/layouts/components/ExamGenerateDialog.vue @@ -5,7 +5,8 @@ - + + @@ -61,8 +62,6 @@ async function fetchGrades() { async function handleGenerate() { if (!type.value) return await generateExamWords({ - gradeId: Number(gradeId.value), - level: Number(level.value), type: Number(type.value), studentId: props.studentIds[0] })