From 15541d95c4dcbb961006250f1beca9ded8d30401 Mon Sep 17 00:00:00 2001 From: dlaren Date: Sun, 17 Aug 2025 21:08:35 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BF=AE=E6=94=B9=E3=80=91=201?= =?UTF-8?q?=E3=80=81WPS=E7=9B=B8=E5=85=B3=E8=AF=95=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E8=80=83=E7=82=B9=E5=85=A8=E5=AF=B9=E8=BF=94=E5=9B=9E=E8=AF=95?= =?UTF-8?q?=E9=A2=98=E5=88=86=E6=95=B0=EF=BC=8C2=E3=80=81=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E9=82=AE=E7=AE=B1=E5=88=A4=E5=88=86=E4=B8=8E=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=96=87=E4=BB=B6=E6=96=B9=E6=B3=95=EF=BC=8C3?= =?UTF-8?q?=E3=80=81=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=A4=87=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exam/controller/auto/AutoController.java | 131 ++- .../exam/controller/auto/vo/StuInfoVo.java | 4 +- .../AutoForWinEmailSettingService.java | 16 + .../AutoForWinEmailSettingServiceImpl.java | 286 +++++++ .../AutoForWinEdgeSettingServiceImpl.java | 40 +- .../brower/JudgementBrowerServiceImpl.java | 45 +- .../service/mysql/IMysqlLocalService.java | 3 +- .../service/mysql/IMysqlLocalServiceImpl.java | 3 - .../exam/exam/service/ps/PsService.java | 4 +- .../stupaperscore/StuPaperScoreService.java | 7 +- .../service/winfile/FileServericeImpl.java | 42 +- .../exam/service/winfile/IFileServerice.java | 2 - .../wpsexcel/JudgementWpsExcelService.java | 2 +- .../JudgementWpsExcelServiceImpl.java | 27 +- .../excel/JudgementForExcelService.java | 4 +- .../excel/JudgementForExcelServiceImpl.java | 1 - .../wpspptx/JudgementWpsPptxService.java | 2 +- .../wpspptx/JudgementWpsPptxServiceImpl.java | 30 +- .../wpspptx/pptx/JudgementForPptxService.java | 4 +- .../service/wpspptx/pptx4j/ShapePage.java | 748 ++++++------------ .../exam/service/wpspptx/pptx4j/ShapePic.java | 531 +++---------- .../wpspptx/pptx4j/SlideConversion.java | 97 --- .../service/wpspptx/pptx4j/SlideMaster.java | 8 +- .../wpsword/JudgementWpsWordService.java | 4 +- .../wpsword/JudgementWpsWordServiceImpl.java | 26 +- 25 files changed, 840 insertions(+), 1227 deletions(-) create mode 100644 src/main/java/com/example/exam/exam/service/autoForEmailSetting/AutoForWinEmailSettingService.java create mode 100644 src/main/java/com/example/exam/exam/service/autoForEmailSetting/AutoForWinEmailSettingServiceImpl.java delete mode 100644 src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/SlideConversion.java diff --git a/src/main/java/com/example/exam/exam/controller/auto/AutoController.java b/src/main/java/com/example/exam/exam/controller/auto/AutoController.java index 6d9b55a..f24700a 100644 --- a/src/main/java/com/example/exam/exam/controller/auto/AutoController.java +++ b/src/main/java/com/example/exam/exam/controller/auto/AutoController.java @@ -2,6 +2,7 @@ package com.example.exam.exam.controller.auto; import com.example.exam.exam.controller.auto.vo.StuInfoVo; import com.example.exam.exam.dal.StuPaperScoreDO; +import com.example.exam.exam.service.autoForEmailSetting.AutoForWinEmailSettingService; import com.example.exam.exam.service.autoForWinEdgeSetting.AutoForWinEdgeSettingService; import com.example.exam.exam.service.autoforbrower.AutoForBrowerService; import com.example.exam.exam.service.autoforps.AutoForPsService; @@ -56,19 +57,26 @@ public class AutoController { AutoForPsService autoForPsService; @Resource AutoForWinEdgeSettingService autoForWinEdgeSettingService; + @Resource + AutoForWinEmailSettingService autoForWinEmailSettingService; + /** + * 考试完成后,获取总分 + * @param stuInfoVo 学生信息 + * @return 分数 + */ @GetMapping("/getStuSource") - public Result getStuSource(StuInfoVo stuInfoVo){ + public Result getStuSource(StuInfoVo stuInfoVo) { BigDecimal source = new BigDecimal(0); List stuPaperScoreDOList = stuPaperScoreService.findByStuIDAndPaperId(stuInfoVo.getStuId(), stuInfoVo.getPaperId(), stuInfoVo.getTemporaryId()); - for (StuPaperScoreDO stuPaperScoreDO : stuPaperScoreDOList){ + for (StuPaperScoreDO stuPaperScoreDO : stuPaperScoreDOList) { source = source.add(stuPaperScoreDO.getScore()); } return Result.success(source); } - // C语言 /** * C语言判分 + * * @param stuInfoVo 学生信息 * @return 判分结果 */ @@ -76,96 +84,171 @@ public class AutoController { public Result judgementForC(@RequestBody StuInfoVo stuInfoVo) throws IOException { return Result.success(autoService.autoForC(stuInfoVo)); } - // WPS-WORD + + /** + * WPS-WORD 判分 + * @param stuInfoVo 学生信息 + * @return 分数 + * @throws Exception 异常信息 + */ @PostMapping("/judgementForWord") public Result judgementForWord(@RequestBody StuInfoVo stuInfoVo) throws Exception { return Result.success(judgementForWordService.autoForWpsWord(stuInfoVo)); } - // WPS-EXCEL + /** + * WPS-EXCEL 判分 + * @param stuInfoVo 学生信息 + * @return 分数 + * @throws Exception 异常信息 + */ @PostMapping("/judgementForExcel") public Result judgementForExcel(@RequestBody StuInfoVo stuInfoVo) throws Exception { return Result.success(judgementForExcelService.autoForWpsExcel(stuInfoVo)); } - // WPS-PPT + /** + * WPS-PPT 判分 + * @param stuInfoVo 学生信息 + * @return 分数 + * @throws Exception 异常信息 + */ @PostMapping("/judgementForPptx") public Result judgementForPptx(@RequestBody StuInfoVo stuInfoVo) throws Exception { return Result.success(judgementForPptxService.autoForWpsPptx(stuInfoVo)); } - // Mysql + /** + * Mysql 判分 + * @param stuInfoVo 学生信息 + * @return 分数 + * @throws SQLException 异常信息 + * @throws IOException 异常信息 + */ @PostMapping("/judgementForMysql") public Result judgementForMysql(@RequestBody StuInfoVo stuInfoVo) throws SQLException, IOException { return Result.success(autoForMysqlService.autoForMysql(stuInfoVo)); } - // Mysql文件 + + /** + * Mysql 文件 + * @param stuInfoVo 学生信息 + * @return 分数 + * @throws SQLException 异常信息 + * @throws IOException 异常信息 + */ @PostMapping("/judgementForMysqlFile") public Result judgementForMysqlFile(@RequestBody StuInfoVo stuInfoVo) throws SQLException, IOException { return Result.success(autoForMysqlService.autoForMysqlFile(stuInfoVo)); } + /** * 删除 本地学生的连接和库 - * @param tNames - * @throws Exception + * + * @param tNames 表名 + * @throws Exception 异常信息 */ @PostMapping("/delMysqlConnect") public void delete(@RequestBody List tNames) throws Exception { mysqlLocalService.delMysqlConnect(tNames); } - // 文件处理 + /** + * 文件提 判分 + * @param stuInfoVo 学生信息 + * @return 分数 + * @throws SQLException 异常信息 + * @throws IOException 异常信息 + */ @PostMapping("/judgementForFile") public Result judgementForFile(@RequestBody StuInfoVo stuInfoVo) throws SQLException, IOException { return Result.success(autoForFileService.autoForFile(stuInfoVo)); } - // 浏览器 + + /** + * 浏览器题 判分 + * @param stuInfoVo 学生信息 + * @return 分数 + * @throws SQLException 异常信息 + * @throws IOException 异常信息 + */ @PostMapping("/judgementForBrower") public Result judgementForBrower(@RequestBody StuInfoVo stuInfoVo) throws SQLException, IOException { return Result.success(autoForBrowerService.autoForBrower(stuInfoVo)); } - // windows网络设置 /** * 将浏览器的页面写入到JSON文件中 - * @param stuInfoVo 学生选择题信息 + * + * @param stuInfoVo 学生信息 * @return String */ @PostMapping("/judgementForEdgeDummyToJson") - public Result judgementForEdgeDummyToJson(@RequestBody StuInfoVo stuInfoVo){ + public Result judgementForEdgeDummyToJson(@RequestBody StuInfoVo stuInfoVo) { return Result.success(autoForWinEdgeSettingService.autoForEdgeToJson(stuInfoVo)); } + + /** + * 邮箱设置判分 + * + * @param stuInfoVo 学生信息 + * @return String + */ + @PostMapping("/judgementForEmailDummy") + public Result judgementForEmailDummy(@RequestBody StuInfoVo stuInfoVo) throws IOException { + return Result.success(autoForWinEdgeSettingService.autoForEdge(stuInfoVo)); + } + + /** + * 邮箱的页面写入到JSON文件中 + * + * @param stuInfoVo 学生信息 + * @return String + */ + @PostMapping("/judgementForEmailDummyToJson") + public Result judgementForEmailDummyToJson(@RequestBody StuInfoVo stuInfoVo) { + return Result.success(autoForWinEmailSettingService.autoForEmailToJson(stuInfoVo)); + } + /** * windows网络设置判分 - * @param stuInfoVo 学生选择题信息 + * + * @param stuInfoVo 学生信息 * @return String */ @PostMapping("/judgementForEdgeDummy") public Result judgementForEdgeDummy(@RequestBody StuInfoVo stuInfoVo) throws IOException { - return Result.success(autoForWinEdgeSettingService.autoForEdge(stuInfoVo)); + return Result.success(autoForWinEmailSettingService.autoForEmail(stuInfoVo)); } - // QQ邮箱 // win10虚拟界面 - //PS + /** + * PS 判分 + * @param stuInfoVo 学生信息 + * @return 分数 + * @throws SQLException 异常信息 + * @throws IOException 异常信息 + */ @PostMapping("/judgementForPS") public Result judgementForPS(@RequestBody StuInfoVo stuInfoVo) throws SQLException, IOException { return Result.success(autoForPsService.autoForPs(stuInfoVo)); } - // 单项选择 /** * 将选择题写入到JSON文件中 - * @param stuInfoVo 学生选择题信息 - * @return String + * + * @param stuInfoVo 学生信息 + * @return 分数 */ @PostMapping("/judgementForChoiceToJson") - public Result judgementForChoiceToJson(@RequestBody StuInfoVo stuInfoVo){ + public Result judgementForChoiceToJson(@RequestBody StuInfoVo stuInfoVo) { return Result.success(autoForChoiceService.autoForChoiceToJson(stuInfoVo)); } + /** * 选择题判分 - * @param stuInfoVo 学生选择题信息 + * + * @param stuInfoVo 学生信息 * @return String */ @PostMapping("/judgementForChoice") diff --git a/src/main/java/com/example/exam/exam/controller/auto/vo/StuInfoVo.java b/src/main/java/com/example/exam/exam/controller/auto/vo/StuInfoVo.java index 35773c9..23da3c5 100644 --- a/src/main/java/com/example/exam/exam/controller/auto/vo/StuInfoVo.java +++ b/src/main/java/com/example/exam/exam/controller/auto/vo/StuInfoVo.java @@ -23,10 +23,10 @@ public class StuInfoVo { // 选择题学生答案 private String choiceAnswerId; - // Edge学生设置Key + // Edge学生设置Key(邮箱也使用) private String edgeAnswerKeys; - // Edge学生设置Value + // Edge学生设置Value(邮箱也使用) private String edgeAnswerValues; // 学校名称 diff --git a/src/main/java/com/example/exam/exam/service/autoForEmailSetting/AutoForWinEmailSettingService.java b/src/main/java/com/example/exam/exam/service/autoForEmailSetting/AutoForWinEmailSettingService.java new file mode 100644 index 0000000..09100b0 --- /dev/null +++ b/src/main/java/com/example/exam/exam/service/autoForEmailSetting/AutoForWinEmailSettingService.java @@ -0,0 +1,16 @@ +package com.example.exam.exam.service.autoForEmailSetting; + +import com.example.exam.exam.controller.auto.vo.StuInfoVo; + +import java.io.IOException; +import java.math.BigDecimal; + +/** + * @author REN + */ +public interface AutoForWinEmailSettingService { + + String autoForEmailToJson(StuInfoVo stuInfoVo); + + BigDecimal autoForEmail(StuInfoVo stuInfoVo) throws IOException; +} diff --git a/src/main/java/com/example/exam/exam/service/autoForEmailSetting/AutoForWinEmailSettingServiceImpl.java b/src/main/java/com/example/exam/exam/service/autoForEmailSetting/AutoForWinEmailSettingServiceImpl.java new file mode 100644 index 0000000..dac2e0a --- /dev/null +++ b/src/main/java/com/example/exam/exam/service/autoForEmailSetting/AutoForWinEmailSettingServiceImpl.java @@ -0,0 +1,286 @@ +package com.example.exam.exam.service.autoForEmailSetting; + +import com.example.exam.exam.controller.auto.vo.StuInfoVo; +import com.example.exam.exam.dal.*; +import com.example.exam.exam.mapper.EducationPaperMapper; +import com.example.exam.exam.mapper.EducationPaperQuMapper; +import com.example.exam.exam.mapper.EducationPaperSchemeMapper; +import com.example.exam.exam.service.c.JudgementService; +import com.example.exam.exam.service.question.IExamQuestionService; +import com.example.exam.exam.service.stupaperscore.StuPaperScoreService; +import com.example.exam.exam.service.tenant.SystemTenantService; +import com.example.exam.exam.utils.HtmlAppender; +import com.example.exam.exam.utils.c.LogFileUtils; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.*; +import java.math.BigDecimal; +import java.util.*; + +@Service +public class AutoForWinEmailSettingServiceImpl implements AutoForWinEmailSettingService { + + @Resource + JudgementService judgementService; + @Resource + EducationPaperSchemeMapper educationPaperSchemeMapper; + @Resource + IExamQuestionService examQuestionService; + @Resource + EducationPaperQuMapper educationPaperQuMapper; + @Resource + StuPaperScoreService stuPaperScoreService; + @Resource + SystemTenantService systemTenantService; + @Autowired + private EducationPaperMapper educationPaperMapper; + + /** + * 自动判题邮箱 + * + * @param stuInfoVo 学生考试信息 + * @return 是否通过 + */ + @Override + public String autoForEmailToJson(StuInfoVo stuInfoVo) { + // 写入到文件夹 + // 试题ID + String quId = stuInfoVo.getQuestionId(); + String edgeAnswerKey = stuInfoVo.getEdgeAnswerKeys(); + String edgeAnswerValue = stuInfoVo.getEdgeAnswerValues(); + // 保存ID路径 + String filePath = stuInfoVo.getFilePath(); + File file = new File(filePath + "/" + quId + "@EmailDummy.json"); + if (!file.exists()) { + LogFileUtils.createFile(filePath + "/" + quId + "@EmailDummy.json"); + } + Map map = new HashMap<>(); + map.put(edgeAnswerKey, edgeAnswerValue); + return writeMapToJson(map, filePath + "/" + quId + "@EmailDummy.json"); + } + + @Override + public BigDecimal autoForEmail(StuInfoVo stuInfoVo) throws IOException { + SystemTenant systemTenant = systemTenantService.getId(stuInfoVo.getSchoolName()); + BigDecimal score = new BigDecimal(0); + // 获取Paper下的所有windows网络设置ID + List examQuestions = educationPaperMapper.selectPaperQuByPaperId(stuInfoVo.getPaperId()); + List edgeList = new ArrayList<>(); + for (ExamQuestion examQuestion : examQuestions) { + if ("邮箱".equals(examQuestion.getSubjectName())) { + edgeList.add(examQuestion); + } + } + // 获取所有json文件,并取出试题ID + List resultFile = new ArrayList<>(); + File dir = new File(stuInfoVo.getFilePath()); + File[] files = dir.listFiles(); + if (files == null) return null; + for (File file : files) { + if (file.isFile() + && file.getName().contains("@EmailDummy") + && file.getName().toLowerCase().endsWith(".json")) { + resultFile.add(file); + } + } + List trueFileQuid = new ArrayList<>(); + List noFileQuid = new ArrayList<>(); + // 开始读取文件并进行拆分 + for (ExamQuestion examQuestion : edgeList) { + boolean fileIsTrue = false; + for (File file : resultFile) { + String quId = file.getName().split("@")[0]; + if (quId.equals(examQuestion.getQuId())) { + fileIsTrue = true; + trueFileQuid.add(quId); + break; + } + } + if (!fileIsTrue) { + noFileQuid.add(examQuestion.getQuId()); + } + } + // 查询哪些文件已经进行获取到学生作答文件了 + for (String str : trueFileQuid) { + // 查询到学生文件 + Optional fileResult = resultFile.stream().filter(resultFiles -> resultFiles.getName().contains(str)).findFirst(); + if (fileResult.isPresent()) { + File file = fileResult.get(); + // 创建 ObjectMapper 实例 + File jsonFile = new File(file.getPath()); + ObjectMapper objectMapper = new ObjectMapper(); + if (jsonFile.exists()) { + Double oneScore = 0.0; + String quId = file.getName().split("@")[0]; + List educationPaperQus = educationPaperQuMapper.selectPaperQuListByPaperId(stuInfoVo.getPaperId()); + Optional resultss = educationPaperQus.stream().filter(entry -> entry.getQuId().equals(quId)) + .findFirst(); + // 获取排序 + EducationPaperQu educationPaperQu = resultss.get(); + + // 试题分数 + List educationPaperSchemeList = educationPaperSchemeMapper.selectEducationPaperTaskByPaperId(stuInfoVo.getPaperId()); + Optional result = educationPaperSchemeList.stream().filter(quLists -> quLists.getSpName().equals("windows网络设置")).findFirst(); + String quScore = result.get().getQuScores(); + // 根据ID查询试题 + ExamQuestion examQuestion = examQuestionService.selectExamQuestionByQuId(quId); + + // 读取学生文件 + try (FileInputStream fileInputStream = new FileInputStream(jsonFile)) { + // 读取文件并转换为 JsonNode + JsonNode rootNode = objectMapper.readTree(fileInputStream); + String jsonText = objectMapper.writeValueAsString(rootNode); + // 从 JSON 文件读取并转换为 Person 对象 + Map map = objectMapper.readValue(jsonText, Map.class); + + String judgementStr = "

-----------------------------------------------------------

"; + judgementStr += "

试题序号:" + educationPaperQu.getSort() + "

"; + judgementStr += "

试题编号:" + examQuestion.getQuNum() + "

"; + judgementStr += "

试题分数:" + Double.parseDouble(quScore) + "

"; + judgementStr += "

试题名称: 邮箱

"; + + // 考试进行比对 + for (ExamQuestionAnswer questionAnswer : examQuestion.getAnswerList()) { + boolean flag = false; + double one_sorce = 0; + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + // 使用map组合成考点 + String point = key + "@" + value; + if (questionAnswer.getContent().equals(point)) { + // 说明正确 + flag = true; + // 得分 根据权重进行得分 每个选项分值 = 总分 / 总权重 + if (questionAnswer.getScoreRate().equals("1")) { + // 说明权重相等,直接平分分数 + one_sorce = Double.parseDouble(quScore) / examQuestion.getAnswerList().size(); + } else { + one_sorce = Double.parseDouble(quScore) * Double.parseDouble(questionAnswer.getScoreRate()); + } + break; + } + } + oneScore += one_sorce; + score = score.add(new BigDecimal(one_sorce)); + if (flag) { + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ " + questionAnswer.getContentIn() + " 得分成功,得分:" + one_sorce); + } else { + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ " + questionAnswer.getContentIn() + " 得分失败"); + } + } + judgementStr += "

试题得分: " + oneScore + "

"; + StuPaperScoreDO insertInfo = new StuPaperScoreDO(); + insertInfo.setStuId(stuInfoVo.getStuId()); + insertInfo.setPaperId(stuInfoVo.getPaperId()); + insertInfo.setQuId(quId); + insertInfo.setScore(new BigDecimal(oneScore)); + insertInfo.setContent(judgementStr); + insertInfo.setSort(educationPaperQu.getSort()); + insertInfo.setSubjectName("邮箱"); + int isTrue = oneScore == 0 ? 1 : oneScore == Double.parseDouble(quScore) ? 0 : 2; + insertInfo.setIsTrue(isTrue); + insertInfo.setTenantId(systemTenant.getId()); + insertInfo.setTemporaryId(stuInfoVo.getTemporaryId()); + insertInfo.setTrueScore(new BigDecimal(quScore)); + stuPaperScoreService.insertStuPaperScore(insertInfo); + if (fileInputStream != null) { + try { + fileInputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + // 没有作答的题目直接0分 + for (String str : noFileQuid) { + String quId = str; + List educationPaperQus = educationPaperQuMapper.selectPaperQuListByPaperId(stuInfoVo.getPaperId()); + Optional resultss = educationPaperQus.stream().filter(entry -> entry.getQuId().equals(quId)) + .findFirst(); + // 获取排序 + EducationPaperQu educationPaperQu = resultss.get(); + + // 试题分数 + List educationPaperSchemeList = educationPaperSchemeMapper.selectEducationPaperTaskByPaperId(stuInfoVo.getPaperId()); + Optional result = educationPaperSchemeList.stream().filter(quLists -> quLists.getSpName().equals("windows网络设置")).findFirst(); + String quScore = result.get().getQuScores(); + // 根据ID查询试题 + ExamQuestion examQuestion = examQuestionService.selectExamQuestionByQuId(quId); + String judgementStr = "

-----------------------------------------------------------

"; + judgementStr += "

试题序号:" + educationPaperQu.getSort() + "

"; + judgementStr += "

试题编号:" + examQuestion.getQuNum() + "

"; + judgementStr += "

试题分数:" + Double.parseDouble(quScore) + "

"; + judgementStr += "

试题名称: 邮箱

"; + judgementStr += "

❌ 未成功检测到作答情况

"; + judgementStr += "

试题得分: 0分

"; + StuPaperScoreDO insertInfo = new StuPaperScoreDO(); + insertInfo.setStuId(stuInfoVo.getStuId()); + insertInfo.setPaperId(stuInfoVo.getPaperId()); + insertInfo.setQuId(quId); + insertInfo.setScore(new BigDecimal(0)); + insertInfo.setContent(judgementStr); + insertInfo.setSort(educationPaperQu.getSort()); + insertInfo.setSubjectName("邮箱"); + insertInfo.setIsTrue(1); + insertInfo.setTenantId(systemTenant.getId()); + insertInfo.setTemporaryId(stuInfoVo.getTemporaryId()); + insertInfo.setTrueScore(new BigDecimal(quScore)); + stuPaperScoreService.insertStuPaperScore(insertInfo); + } + return score.setScale(1, BigDecimal.ROUND_HALF_UP); + } + + // 将Map写入JSON文件 + // 将Map追加到JSON文件 + public static String writeMapToJson(Map map, String filePath) { + ObjectMapper objectMapper = new ObjectMapper(); + File file = new File(filePath); + + try { + Map existingMap = new HashMap<>(); + + if (file.exists() && file.length() > 0) { + try (InputStream fis = new FileInputStream(file)) { + existingMap = objectMapper.readValue(fis, Map.class); + } + } + + existingMap.putAll(map); + + try (OutputStream fos = new FileOutputStream(file, false); + BufferedOutputStream bos = new BufferedOutputStream(fos)) { + objectMapper.writeValue(bos, existingMap); + bos.flush(); // 强制刷新 + } + + // 可选占用测试 + boolean released = file.renameTo(file); + System.out.println("文件释放状态: " + released); + + } catch (IOException e) { + e.printStackTrace(); + } + + return "学生答案已经写入到 " + filePath; + } + + + public static String convertToLetter(int number) { + // 判断是否在 1 到 26 的范围内 + if (number >= 1 && number <= 26) { + return String.valueOf((char) ('A' + number - 1)); // 转换为对应的字母 + } else { + return "Invalid"; // 如果不在 1-26 范围内,返回 "Invalid" + } + } +} diff --git a/src/main/java/com/example/exam/exam/service/autoForWinEdgeSetting/AutoForWinEdgeSettingServiceImpl.java b/src/main/java/com/example/exam/exam/service/autoForWinEdgeSetting/AutoForWinEdgeSettingServiceImpl.java index f5a7ca2..994115a 100644 --- a/src/main/java/com/example/exam/exam/service/autoForWinEdgeSetting/AutoForWinEdgeSettingServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/autoForWinEdgeSetting/AutoForWinEdgeSettingServiceImpl.java @@ -40,7 +40,7 @@ public class AutoForWinEdgeSettingServiceImpl implements AutoForWinEdgeSettingSe private EducationPaperMapper educationPaperMapper; /** - * 自动判题选择题 + * 自动判题Edge * * @param stuInfoVo 学生考试信息 * @return 是否通过 @@ -223,31 +223,19 @@ public class AutoForWinEdgeSettingServiceImpl implements AutoForWinEdgeSettingSe judgementStr += "

试题名称: windows网络设置

"; judgementStr += "

❌ 未成功检测到作答情况

"; judgementStr += "

试题得分: 0分

"; - StuPaperScoreDO stuPaperScoreDO = stuPaperScoreService.getStuScoreByPaperIdAndQuid(stuInfoVo.getStuId(), stuInfoVo.getPaperId(), quId); - if (stuPaperScoreDO != null) { - // 说明已经是做过该题,需要更新数据 - stuPaperScoreDO.setScore(new BigDecimal(0)); - stuPaperScoreDO.setContent(judgementStr); - stuPaperScoreDO.setSort(educationPaperQu.getSort()); - stuPaperScoreDO.setSubjectName("windows网络设置"); - stuPaperScoreDO.setIsTrue(1); - stuPaperScoreDO.setTrueScore(new BigDecimal(quScore)); - stuPaperScoreDO.setTenantId(systemTenant.getId()); - stuPaperScoreService.updateStuPaperScore(stuPaperScoreDO); - } else { - StuPaperScoreDO insertInfo = new StuPaperScoreDO(); - insertInfo.setStuId(stuInfoVo.getStuId()); - insertInfo.setPaperId(stuInfoVo.getPaperId()); - insertInfo.setQuId(quId); - insertInfo.setScore(new BigDecimal(0)); - insertInfo.setContent(judgementStr); - insertInfo.setSort(educationPaperQu.getSort()); - insertInfo.setSubjectName("windows网络设置"); - insertInfo.setIsTrue(1); - insertInfo.setTenantId(systemTenant.getId()); - insertInfo.setTrueScore(new BigDecimal(quScore)); - stuPaperScoreService.insertStuPaperScore(insertInfo); - } + StuPaperScoreDO insertInfo = new StuPaperScoreDO(); + insertInfo.setStuId(stuInfoVo.getStuId()); + insertInfo.setPaperId(stuInfoVo.getPaperId()); + insertInfo.setQuId(quId); + insertInfo.setScore(new BigDecimal(0)); + insertInfo.setContent(judgementStr); + insertInfo.setSort(educationPaperQu.getSort()); + insertInfo.setSubjectName("windows网络设置"); + insertInfo.setIsTrue(1); + insertInfo.setTenantId(systemTenant.getId()); + insertInfo.setTemporaryId(stuInfoVo.getTemporaryId()); + insertInfo.setTrueScore(new BigDecimal(quScore)); + stuPaperScoreService.insertStuPaperScore(insertInfo); } return score.setScale(1, BigDecimal.ROUND_HALF_UP); } diff --git a/src/main/java/com/example/exam/exam/service/brower/JudgementBrowerServiceImpl.java b/src/main/java/com/example/exam/exam/service/brower/JudgementBrowerServiceImpl.java index 8ee03b7..3f2e830 100644 --- a/src/main/java/com/example/exam/exam/service/brower/JudgementBrowerServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/brower/JudgementBrowerServiceImpl.java @@ -12,17 +12,15 @@ import com.example.exam.exam.utils.file.GetDifferencesBetweenFolders; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; -import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; + @Service public class JudgementBrowerServiceImpl implements JudgementBrowerService { - static String answerLogPath ; // 文件路径 + static String answerLogPath; // 文件路径 @Resource private ExamQuestionAnswerMapper examQuestionAnswerMapper; private static final DateTimeFormatter formatter = @@ -30,6 +28,7 @@ public class JudgementBrowerServiceImpl implements JudgementBrowerService { //EDGE浏览器 String chromeBookmarkPath = System.getenv("LOCALAPPDATA") + "\\Microsoft\\Edge\\User Data\\Default\\Bookmarks"; + @Override public SourceAndText Judgement(double score, File file, ExamQuestion question, String judgementStr) throws IOException { //根据题目,查找考点 @@ -72,22 +71,22 @@ public class JudgementBrowerServiceImpl implements JudgementBrowerService { // appendToFile(answerLogPath,"=== 学生提交内容(stu 目录) ==="); // // stuFiles.forEach((key, value) -> appendToFile(answerLogPath,key + " -> " + value)); - appendToFile(answerLogPath,"=== 学生提交内容得分点 ==="); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr,"=== 学生提交内容得分点 ==="); + appendToFile(answerLogPath, "=== 学生提交内容得分点 ==="); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "=== 学生提交内容得分点 ==="); // 计算试题总分 int totalScore = answerList.stream() .mapToInt(a -> Integer.parseInt(a.getScoreRate())) .sum(); //这里指挥判断存在文件夹的得分点 - SourceAndTextAndTotal studentScorePojo = compareStuAndTestFiles(answerList, stuFiles,score,totalScore,judgementStr); + SourceAndTextAndTotal studentScorePojo = compareStuAndTestFiles(answerList, stuFiles, score, totalScore, judgementStr); double studentScore = studentScorePojo.getScore(); - correctCount= studentScorePojo.getTotal(); + correctCount = studentScorePojo.getTotal(); judgementStr = studentScorePojo.getText(); //判断收藏夹得分点 for (ExamQuestionAnswer examQuestionAnswer : answerList) { int currentScore = Integer.parseInt(examQuestionAnswer.getScoreRate()); // 当前得分 - if ( "添加到收藏夹".equals(examQuestionAnswer.getContentIn())){ + if ("添加到收藏夹".equals(examQuestionAnswer.getContentIn())) { String bookmarkNameToDelete = examQuestionAnswer.getContent(); //检查收藏夹是否有书签 boolean isCorrect = BookmarkChecker.bookmarkExists(chromeBookmarkPath, bookmarkNameToDelete); @@ -100,14 +99,13 @@ public class JudgementBrowerServiceImpl implements JudgementBrowerService { double weightScore = ((double) currentScore / totalScore) * score; String formattedWeightScore = String.format("%.1f", weightScore); - appendToFile(answerLogPath,"✅考点"+bookmarkNameToDelete + " -> 得分权值:" + currentScore+"-> 得分:"+formattedWeightScore); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr,"✅考点"+bookmarkNameToDelete + " -> 得分权值:" + currentScore+"-> 得分:"+formattedWeightScore); + appendToFile(answerLogPath, "✅考点" + bookmarkNameToDelete + " -> 得分权值:" + currentScore + "-> 得分:" + formattedWeightScore); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅考点" + bookmarkNameToDelete + " -> 得分权值:" + currentScore + "-> 得分:" + formattedWeightScore); //删除此书签 BookmarkDeleter.deleteBookmarkByName(chromeBookmarkPath, bookmarkNameToDelete); - } - else { - appendToFile(answerLogPath,"❌考点"+bookmarkNameToDelete + " -> 得分权值:" + currentScore+"-> 得分:0"); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr,"❌考点"+bookmarkNameToDelete + " -> 得分权值:" + currentScore+"-> 得分:0"); + } else { + appendToFile(answerLogPath, "❌考点" + bookmarkNameToDelete + " -> 得分权值:" + currentScore + "-> 得分:0"); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌考点" + bookmarkNameToDelete + " -> 得分权值:" + currentScore + "-> 得分:0"); } } @@ -117,11 +115,11 @@ public class JudgementBrowerServiceImpl implements JudgementBrowerService { // 计算最终得分比例(保留两位小数) double scoreRatio = totalScore == 0 ? 0 : (double) studentScore / totalScore; - double roundedScoreRatio = Math.round(scoreRatio*score * 100.0) / 100.0; // 四舍五入到2位小数 + double roundedScoreRatio = Math.round(scoreRatio * score * 100.0) / 100.0; // 四舍五入到2位小数 if (correctCount == totalQuestions) { roundedScoreRatio = score; // 全对,直接给满分 } - appendToFile(answerLogPath," 得分:"+roundedScoreRatio); + appendToFile(answerLogPath, " 得分:" + roundedScoreRatio); sourceAndText.setScore(roundedScoreRatio); sourceAndText.setText(judgementStr); return sourceAndText; @@ -129,7 +127,7 @@ public class JudgementBrowerServiceImpl implements JudgementBrowerService { // 对比学生提交内容与试题得分点 - static SourceAndTextAndTotal compareStuAndTestFiles(List answerList, Map stuFiles,double score,int total, String judgementStr) { + static SourceAndTextAndTotal compareStuAndTestFiles(List answerList, Map stuFiles, double score, int total, String judgementStr) { int totalScore = 0; // 记录总得分 int correctCount = 0; // 完全正确的题目数量 SourceAndTextAndTotal sourceAndText = new SourceAndTextAndTotal(); @@ -147,11 +145,11 @@ public class JudgementBrowerServiceImpl implements JudgementBrowerService { // 计算该考点的权重得分并保留一位小数 double weightScore = ((double) currentScore / total) * score; String formattedWeightScore = String.format("%.1f", weightScore); - appendToFile(answerLogPath,"✅考点"+answer.getContent() + " -> 得分权值:" + answer.getScoreRate()+"-> 得分:"+formattedWeightScore); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr,"✅考点"+answer.getContent() + " -> 得分权值:" + answer.getScoreRate()+"-> 得分:"+formattedWeightScore); - }else { - appendToFile(answerLogPath,"❌考点"+answer.getContent() + " -> 得分权值:" + answer.getScoreRate()+"-> 得分:0"); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr,"❌考点"+answer.getContent() + " -> 得分权值:" + answer.getScoreRate()+"-> 得分:0"); + appendToFile(answerLogPath, "✅考点" + answer.getContent() + " -> 得分权值:" + answer.getScoreRate() + "-> 得分:" + formattedWeightScore); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅考点" + answer.getContent() + " -> 得分权值:" + answer.getScoreRate() + "-> 得分:" + formattedWeightScore); + } else { + appendToFile(answerLogPath, "❌考点" + answer.getContent() + " -> 得分权值:" + answer.getScoreRate() + "-> 得分:0"); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌考点" + answer.getContent() + " -> 得分权值:" + answer.getScoreRate() + "-> 得分:0"); } } } @@ -161,6 +159,7 @@ public class JudgementBrowerServiceImpl implements JudgementBrowerService { sourceAndText.setTotal(correctCount); return sourceAndText; } + /** * 将指定内容追加写入到指定文件中。 * diff --git a/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalService.java b/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalService.java index b62a9ca..dcba630 100644 --- a/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalService.java +++ b/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalService.java @@ -1,6 +1,5 @@ package com.example.exam.exam.service.mysql; -import com.example.exam.exam.controller.auto.vo.StuInfoVo; import com.example.exam.exam.dal.ExamQuestion; import com.example.exam.exam.dal.SourceAndText; @@ -14,7 +13,7 @@ public interface IMysqlLocalService { void delMysqlConnect(List tNames); - SourceAndText Judgement(double sorce, File file, ExamQuestion examQuestion, String judgementStr) throws IOException, SQLException; + SourceAndText Judgement(double source, File file, ExamQuestion examQuestion, String judgementStr) throws IOException, SQLException; void JudgementFile(File mysqlFile, ExamQuestion examQuestion); diff --git a/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalServiceImpl.java b/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalServiceImpl.java index 064861b..b277bf7 100644 --- a/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalServiceImpl.java @@ -6,7 +6,6 @@ import com.example.exam.exam.dal.ExamQuestionAnswer; import com.example.exam.exam.dal.SourceAndText; import com.example.exam.exam.mapper.ExamMysqlKeywordMapper; import com.example.exam.exam.mapper.ExamQuestionAnswerMapper; -import com.example.exam.exam.service.mysql.IMysqlLocalService; import com.example.exam.exam.service.mysql.vo.MysqlBooleanVo; import com.example.exam.exam.service.mysql.vo.MysqlVo; import com.example.exam.exam.utils.HtmlAppender; @@ -14,7 +13,6 @@ import com.example.exam.exam.utils.mysql.MySQLExporterUtil; import com.example.exam.exam.utils.zip.ZipUtil; import io.micrometer.common.util.StringUtils; import jakarta.annotation.Resource; -import org.apache.commons.lang3.StringEscapeUtils; import org.springframework.stereotype.Service; @@ -29,7 +27,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.sql.*; -import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.List; diff --git a/src/main/java/com/example/exam/exam/service/ps/PsService.java b/src/main/java/com/example/exam/exam/service/ps/PsService.java index e6fc0f2..7ba6b44 100644 --- a/src/main/java/com/example/exam/exam/service/ps/PsService.java +++ b/src/main/java/com/example/exam/exam/service/ps/PsService.java @@ -11,9 +11,9 @@ public interface PsService { * 读取考生文件,与题型中要求进行判断 * @param path 文件路径 * @param examQuestion 试题参数 - * @param sorce 试题分数 + * @param source 试题分数 * @return 得分 * @throws Exception 异常 */ - SourceAndText Judgement(double sorce, String lastFilePath, String path, ExamQuestion examQuestion, String judgementStr) throws IOException; + SourceAndText Judgement(double source, String lastFilePath, String path, ExamQuestion examQuestion, String judgementStr) throws IOException; } diff --git a/src/main/java/com/example/exam/exam/service/stupaperscore/StuPaperScoreService.java b/src/main/java/com/example/exam/exam/service/stupaperscore/StuPaperScoreService.java index 5095a89..c107a78 100644 --- a/src/main/java/com/example/exam/exam/service/stupaperscore/StuPaperScoreService.java +++ b/src/main/java/com/example/exam/exam/service/stupaperscore/StuPaperScoreService.java @@ -15,10 +15,5 @@ public interface StuPaperScoreService { List findByStuIDAndPaperId(Long stuId, String paperId, String temporaryId); void insertStuPaperScore(StuPaperScoreDO stuPaperScoreDO); - - void updateStuPaperScore(StuPaperScoreDO stuPaperScoreDO); - - StuPaperScoreDO getStuScoreByPaperIdAndQuid(Long stuId, String paperId, String quId); - - void deleteStuPaperScore(Long stuId, String paperId); + } \ No newline at end of file diff --git a/src/main/java/com/example/exam/exam/service/winfile/FileServericeImpl.java b/src/main/java/com/example/exam/exam/service/winfile/FileServericeImpl.java index 3538585..3ad1da2 100644 --- a/src/main/java/com/example/exam/exam/service/winfile/FileServericeImpl.java +++ b/src/main/java/com/example/exam/exam/service/winfile/FileServericeImpl.java @@ -11,11 +11,8 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; -import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; @@ -23,11 +20,12 @@ import java.util.Map; @Service public class FileServericeImpl implements IFileServerice { - static String answerLogPath ; // 文件路径 + static String answerLogPath; // 文件路径 @Resource private ExamQuestionAnswerMapper examQuestionAnswerMapper; private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + @Override public SourceAndText Judgement(double score, File file, ExamQuestion question, String judgementStr) throws IOException { SourceAndText sourceAndText = new SourceAndText(); @@ -60,21 +58,21 @@ public class FileServericeImpl implements IFileServerice { int totalScore = answerList.stream() .mapToInt(a -> Integer.parseInt(a.getScoreRate())) .sum(); - appendToFile(answerLogPath,"=== 学生提交内容得分点 ==="); + appendToFile(answerLogPath, "=== 学生提交内容得分点 ==="); judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "=== 学生提交内容得分点 ==="); // 对比学生提交内容与试题得分点 - SourceAndTextAndTotal studentScorePojo = compareStuAndTestFiles(answerList, stuFiles,score,totalScore,judgementStr); + SourceAndTextAndTotal studentScorePojo = compareStuAndTestFiles(answerList, stuFiles, score, totalScore, judgementStr); double studentScore = studentScorePojo.getScore(); judgementStr = studentScorePojo.getText(); //获取answerList里的所有sorcerate,和integer相除得到一个小于等于1的数 // 计算最终得分比例(保留两位小数) double scoreRatio = totalScore == 0 ? 0 : (double) studentScore / totalScore; - double roundedScoreRatio = Math.round(scoreRatio * 100.0*score) / 100.0; // 四舍五入到2位小数 + double roundedScoreRatio = Math.round(scoreRatio * 100.0 * score) / 100.0; // 四舍五入到2位小数 if (correctCount == totalQuestions) { roundedScoreRatio = score; // 全对,直接给满分 } - appendToFile(answerLogPath,"得分:"+roundedScoreRatio); + appendToFile(answerLogPath, "得分:" + roundedScoreRatio); // judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "得分:"+roundedScoreRatio*score); sourceAndText.setScore(roundedScoreRatio); sourceAndText.setText(judgementStr); @@ -83,11 +81,11 @@ public class FileServericeImpl implements IFileServerice { // 对比学生提交内容与试题得分点 - static SourceAndTextAndTotal compareStuAndTestFiles(List answerList, Map stuFiles, double score, int total, String judgementStr) { - SourceAndTextAndTotal sourceAndText = new SourceAndTextAndTotal(); - int correctCount = 0; // 完全正确的题目数量 - int totalQuestions = answerList.size(); // 总题目数量// 总题目数量 - double totalScore = 0; // 记录总得分 + static SourceAndTextAndTotal compareStuAndTestFiles(List answerList, Map stuFiles, double score, int total, String judgementStr) { + SourceAndTextAndTotal sourceAndText = new SourceAndTextAndTotal(); + int correctCount = 0; // 完全正确的题目数量 + int totalQuestions = answerList.size(); // 总题目数量// 总题目数量 + double totalScore = 0; // 记录总得分 for (ExamQuestionAnswer answer : answerList) { String filePath = answer.getContent(); // 试题文件路径 String checkType = answer.getContentIn(); // 考察类型(考察删除 / 考察名称 / 考察属性) @@ -115,18 +113,18 @@ public class FileServericeImpl implements IFileServerice { // 计算该考点的权重得分并保留一位小数 double weightScore = ((double) currentScore / total) * score; String formattedWeightScore = String.format("%.1f", weightScore); - appendToFile(answerLogPath,"√"+answer.getContent() + " -> " + answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate()+"-> 得分:"+formattedWeightScore); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ " + answer.getContent() + " -> " + answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate()+"-> 得分:"+formattedWeightScore); - }else { - appendToFile(answerLogPath,"×"+answer.getContent() + " -> " + answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate()+"-> 得分:0"); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ " + answer.getContent() + " -> " + answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate()+"-> 得分:0"); + appendToFile(answerLogPath, "√" + answer.getContent() + " -> " + answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate() + "-> 得分:" + formattedWeightScore); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ " + answer.getContent() + " -> " + answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate() + "-> 得分:" + formattedWeightScore); + } else { + appendToFile(answerLogPath, "×" + answer.getContent() + " -> " + answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate() + "-> 得分:0"); + judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ " + answer.getContent() + " -> " + answer.getContentIn() + " -> 得分权值:" + answer.getScoreRate() + "-> 得分:0"); } } - sourceAndText.setText(judgementStr); - sourceAndText.setScore(totalScore); - sourceAndText.setTotal(correctCount); + sourceAndText.setText(judgementStr); + sourceAndText.setScore(totalScore); + sourceAndText.setTotal(correctCount); //返回累加的总分 - return sourceAndText; + return sourceAndText; } /** diff --git a/src/main/java/com/example/exam/exam/service/winfile/IFileServerice.java b/src/main/java/com/example/exam/exam/service/winfile/IFileServerice.java index d567e70..fe19bb5 100644 --- a/src/main/java/com/example/exam/exam/service/winfile/IFileServerice.java +++ b/src/main/java/com/example/exam/exam/service/winfile/IFileServerice.java @@ -10,8 +10,6 @@ import java.io.IOException; public interface IFileServerice { - - SourceAndText Judgement(double score, File file, ExamQuestion question, String judgementStr) throws IOException; diff --git a/src/main/java/com/example/exam/exam/service/wpsexcel/JudgementWpsExcelService.java b/src/main/java/com/example/exam/exam/service/wpsexcel/JudgementWpsExcelService.java index 5ac8729..1c72485 100644 --- a/src/main/java/com/example/exam/exam/service/wpsexcel/JudgementWpsExcelService.java +++ b/src/main/java/com/example/exam/exam/service/wpsexcel/JudgementWpsExcelService.java @@ -14,5 +14,5 @@ import java.util.List; public interface JudgementWpsExcelService { // 根据给定的分数、路径、考试题目和判断题字符串,返回一个SourceAndText对象 - SourceAndText judgementWpsXlsx(double sorce, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception; + SourceAndText judgementWpsXlsx(double source, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception; } diff --git a/src/main/java/com/example/exam/exam/service/wpsexcel/JudgementWpsExcelServiceImpl.java b/src/main/java/com/example/exam/exam/service/wpsexcel/JudgementWpsExcelServiceImpl.java index 0e459a6..d075e8c 100644 --- a/src/main/java/com/example/exam/exam/service/wpsexcel/JudgementWpsExcelServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/wpsexcel/JudgementWpsExcelServiceImpl.java @@ -23,10 +23,10 @@ public class JudgementWpsExcelServiceImpl implements JudgementWpsExcelService { @Override - public SourceAndText judgementWpsXlsx(double sorce, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception { + public SourceAndText judgementWpsXlsx(double source, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception { SourceAndText sourceAndText = new SourceAndText(); List wpsXlsxInfos = new ArrayList<>(); - + boolean isAllTrue = true; // 判断考点是否全对标识 // 日志:开始判分 judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 开始WPS_Xlsx判分"); double wps_xlsx_score = 0; @@ -36,56 +36,46 @@ public class JudgementWpsExcelServiceImpl implements JudgementWpsExcelService { for (ExamQuestionAnswer examQuestionAnswer : answerList) { List cell = new ArrayList<>(); String[] docxInfo = examQuestionAnswer.getContent().split("@"); - // 避免越界,至少保证前 5 项 if (docxInfo.length < 5) { continue; // 数据不完整,跳过 } - WpsXlsxInfoVo wpsXlsxInfoVo = new WpsXlsxInfoVo(); wpsXlsxInfoVo.setFirstName(docxInfo[0]); wpsXlsxInfoVo.setIndex(docxInfo[1]); wpsXlsxInfoVo.setFunction(docxInfo[2]); wpsXlsxInfoVo.setExamName(docxInfo[3]); wpsXlsxInfoVo.setExamCode(docxInfo[4]); - // 如果有第 6 个字段,加入 cell if (docxInfo.length > 5 && docxInfo[5] != null && !docxInfo[5].isEmpty()) { cell.add(docxInfo[5]); } wpsXlsxInfoVo.setCell(cell); - wpsXlsxInfos.add(wpsXlsxInfoVo); } // 文件转 MultipartFile MultipartFile multipartFile = new CustomMultipartFile(new File(path)); - // 获取判分结果 List judgementXlsxVOS = XlsxMaster.xlsxMaster(wpsXlsxInfos, multipartFile); - // 逐个答案进行判分 for (ExamQuestionAnswer examQuestionAnswer : answerList) { boolean flag = false; // 每个答案单独判断 double one_score = 0; - for (JudgementXlsxVO wordJudgementDto : judgementXlsxVOS) { if (wordJudgementDto.getContent() != null && wordJudgementDto.getContent().equals(examQuestionAnswer.getContent())) { - flag = true; // 权重分值计算 if ("1".equals(examQuestionAnswer.getScoreRate())) { - one_score = sorce / answerList.size(); + one_score = source / answerList.size(); } else { - one_score = sorce * Double.parseDouble(examQuestionAnswer.getScoreRate()); + one_score = source * Double.parseDouble(examQuestionAnswer.getScoreRate()); } break; // 找到匹配立即退出 } } - wps_xlsx_score += one_score; - if (flag) { judgementStr = HtmlAppender.appendHtmlLine( judgementStr, @@ -93,14 +83,19 @@ public class JudgementWpsExcelServiceImpl implements JudgementWpsExcelService { new BigDecimal(one_score).setScale(1, RoundingMode.HALF_UP) ); } else { + isAllTrue = false; judgementStr = HtmlAppender.appendHtmlLine( judgementStr, "❌ " + examQuestionAnswer.getContentIn() + " 得分失败" ); } } - - sourceAndText.setScore(wps_xlsx_score); + if (isAllTrue) { + // 如果所有考点都正确,直接给满分 + sourceAndText.setScore(source); + } else { + sourceAndText.setScore(wps_xlsx_score); + } sourceAndText.setText(judgementStr); return sourceAndText; } diff --git a/src/main/java/com/example/exam/exam/service/wpsexcel/excel/JudgementForExcelService.java b/src/main/java/com/example/exam/exam/service/wpsexcel/excel/JudgementForExcelService.java index 0dba4cb..1678a60 100644 --- a/src/main/java/com/example/exam/exam/service/wpsexcel/excel/JudgementForExcelService.java +++ b/src/main/java/com/example/exam/exam/service/wpsexcel/excel/JudgementForExcelService.java @@ -7,14 +7,14 @@ import com.example.exam.exam.controller.auto.vo.StuInfoVo; import java.math.BigDecimal; /** - * 判分逻辑集合(wps word) + * 判分逻辑集合(wps excel) * * @author rwb */ public interface JudgementForExcelService { /** - * word 判分 + * excel 判分 * @param stuInfoVo 学生考试信息 * @return 结果 */ diff --git a/src/main/java/com/example/exam/exam/service/wpsexcel/excel/JudgementForExcelServiceImpl.java b/src/main/java/com/example/exam/exam/service/wpsexcel/excel/JudgementForExcelServiceImpl.java index 9a4117a..2f7b4ba 100644 --- a/src/main/java/com/example/exam/exam/service/wpsexcel/excel/JudgementForExcelServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/wpsexcel/excel/JudgementForExcelServiceImpl.java @@ -10,7 +10,6 @@ import com.example.exam.exam.service.question.IExamQuestionService; import com.example.exam.exam.service.stupaperscore.StuPaperScoreService; import com.example.exam.exam.service.tenant.SystemTenantService; import com.example.exam.exam.service.wpsexcel.JudgementWpsExcelService; -import com.example.exam.exam.service.wpspptx.JudgementWpsPptxService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/example/exam/exam/service/wpspptx/JudgementWpsPptxService.java b/src/main/java/com/example/exam/exam/service/wpspptx/JudgementWpsPptxService.java index 0e2810f..96c59e8 100644 --- a/src/main/java/com/example/exam/exam/service/wpspptx/JudgementWpsPptxService.java +++ b/src/main/java/com/example/exam/exam/service/wpspptx/JudgementWpsPptxService.java @@ -10,5 +10,5 @@ import java.util.List; * @author REN */ public interface JudgementWpsPptxService { - SourceAndText judgementWpsPptx(double sorce, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception; + SourceAndText judgementWpsPptx(double source, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception; } diff --git a/src/main/java/com/example/exam/exam/service/wpspptx/JudgementWpsPptxServiceImpl.java b/src/main/java/com/example/exam/exam/service/wpspptx/JudgementWpsPptxServiceImpl.java index 9b62d16..6802355 100644 --- a/src/main/java/com/example/exam/exam/service/wpspptx/JudgementWpsPptxServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/wpspptx/JudgementWpsPptxServiceImpl.java @@ -5,10 +5,11 @@ import com.example.exam.exam.dal.ExamQuestionAnswer; import com.example.exam.exam.dal.SourceAndText; import com.example.exam.exam.service.wpspptx.pptx4j.SlideMaster; import com.example.exam.exam.service.wpspptx.pptx4j.vo.JudgementSlidesVO; -import com.example.exam.exam.service.wpspptx.pptx4j.vo.SlideDataInfoVO; import com.example.exam.exam.service.wpspptx.pptx4j.vo.WpsSlideInfoVo; +import com.example.exam.exam.utils.CustomMultipartFile; import com.example.exam.exam.utils.HtmlAppender; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.math.BigDecimal; @@ -23,16 +24,14 @@ import java.util.List; public class JudgementWpsPptxServiceImpl implements JudgementWpsPptxService { @Override - public SourceAndText judgementWpsPptx(double sorce, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception { + public SourceAndText judgementWpsPptx(double source, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception { SourceAndText sourceAndText = new SourceAndText(); - // 创建log文件txt,用于记录 -// LogFileUtils.createFile(pathC + "/WPS_Word判分过程.txt"); -// LogFileUtils.writeLine("✅ 开始WPS_Pptx判分"); + Boolean isAllTrue = true; judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 开始WPS_Pptx判分"); double wpsPptScore = 0; List judgementReq = new ArrayList<>(); // 3、获取答案得组成 - List answerList = examQuestion.getAnswerList(); + List answerList = examQuestion.getAnswerList(); for (ExamQuestionAnswer examQuestionAnswer : answerList) { WpsSlideInfoVo judgementReqVo = new WpsSlideInfoVo(); // 拆分数据、 @@ -45,7 +44,8 @@ public class JudgementWpsPptxServiceImpl implements JudgementWpsPptxService { judgementReqVo.setMethod(pptxInfos[5]); judgementReq.add(judgementReqVo); } - List judgementDtos = SlideMaster.slideMaster(judgementReq, new File(path)); + MultipartFile multipartFile = new CustomMultipartFile(new File(path)); + List judgementDtos = SlideMaster.slideMaster(judgementReq, multipartFile); // 4、进行关联判断 for (ExamQuestionAnswer examQuestionAnswer : answerList) { boolean flag = false; @@ -56,26 +56,26 @@ public class JudgementWpsPptxServiceImpl implements JudgementWpsPptxService { // 得分 根据权重进行得分 每个选项分值 = 总分 / 总权重 if (examQuestionAnswer.getScoreRate().equals("1")) { // 说明权重相等,直接平分分数 - one_sorce = sorce / answerList.size(); + one_sorce = source / answerList.size(); } else { - one_sorce = sorce * Double.parseDouble(examQuestionAnswer.getScoreRate()); + one_sorce = source * Double.parseDouble(examQuestionAnswer.getScoreRate()); } break; } } wpsPptScore += one_sorce; if (flag) { -// LogFileUtils.writeLine("✅" + examQuestionAnswer.getContentIn() + " 得分成功,得分:" + one_sorce); judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ " + examQuestionAnswer.getContentIn() + " 得分成功,得分:" + new BigDecimal(one_sorce).setScale(1, RoundingMode.HALF_UP)); } else { -// LogFileUtils.writeLine("❌ " + examQuestionAnswer.getContentIn() + " 得分失败"); + isAllTrue = false; judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "❌ " + examQuestionAnswer.getContentIn() + " 得分失败"); } } -// LogFileUtils.writeLine("✅ 结束WPS_Pptx判分,试题得分:" + wpsPptScore); - // 关闭已经打开得文件 -// LogFileUtils.close(); - sourceAndText.setScore(wpsPptScore); + if (isAllTrue) { + sourceAndText.setScore(source); + } else { + sourceAndText.setScore(wpsPptScore); + } sourceAndText.setText(judgementStr); return sourceAndText; } diff --git a/src/main/java/com/example/exam/exam/service/wpspptx/pptx/JudgementForPptxService.java b/src/main/java/com/example/exam/exam/service/wpspptx/pptx/JudgementForPptxService.java index 54280c5..12fd327 100644 --- a/src/main/java/com/example/exam/exam/service/wpspptx/pptx/JudgementForPptxService.java +++ b/src/main/java/com/example/exam/exam/service/wpspptx/pptx/JudgementForPptxService.java @@ -7,14 +7,14 @@ import com.example.exam.exam.controller.auto.vo.StuInfoVo; import java.math.BigDecimal; /** - * 判分逻辑集合(wps word) + * 判分逻辑集合(wps ppt) * * @author rwb */ public interface JudgementForPptxService { /** - * word 判分 + * ppt 判分 * @param stuInfoVo 学生考试信息 * @return 结果 */ diff --git a/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/ShapePage.java b/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/ShapePage.java index 23fd46d..57b902f 100644 --- a/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/ShapePage.java +++ b/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/ShapePage.java @@ -5,11 +5,12 @@ import org.docx4j.dml.*; import org.pptx4j.pml.*; import java.math.BigInteger; +import java.util.List; public class ShapePage { // 大小 - 高度 - public static String getShapeSizeHeight(Shape sp, CTSlideTiming timing) { + public static String getShapeSizeHeight(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTTransform2D xfrm = sp.getSpPr().getXfrm(); // 获取位置和尺寸(单位 EMU,1英寸=914400 EMU,1cm≈360000 EMU) CTPositiveSize2D ext = xfrm.getExt(); // 尺寸 @@ -18,7 +19,7 @@ public class ShapePage { } // 大小 - 宽度 - public static String getShapeSizeWidthPt(Shape sp, CTSlideTiming timing) { + public static String getShapeSizeWidthPt(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTTransform2D xfrm = sp.getSpPr().getXfrm(); // 获取位置和尺寸(单位 EMU,1英寸=914400 EMU,1cm≈360000 EMU) CTPositiveSize2D ext = xfrm.getExt(); // 尺寸 @@ -27,7 +28,7 @@ public class ShapePage { } // 大小 - 锁定纵横比 - public static String getShapeSizeLockAspectRatio(Shape sp, CTSlideTiming timing) { + public static String getShapeSizeLockAspectRatio(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTTransform2D xfrm = sp.getSpPr().getXfrm(); // 获取位置和尺寸(单位 EMU,1英寸=914400 EMU,1cm≈360000 EMU) CTPositiveSize2D ext = xfrm.getExt(); // 尺寸 @@ -54,12 +55,12 @@ public class ShapePage { } /// 大小 旋转 - public static String getShapeSizeRotate(Shape sp, CTSlideTiming timing) { + public static String getShapeSizeRotate(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } // 位置 水平位置 - public static String getShapePositionLeft(Shape sp, CTSlideTiming timing) { + public static String getShapePositionLeft(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTTransform2D xfrm = sp.getSpPr().getXfrm(); if (xfrm != null) { long x = xfrm.getOff().getX(); // 水平位置(EMU) @@ -69,7 +70,7 @@ public class ShapePage { } // 位置 垂直位置 - public static String getShapePositionTop(Shape sp, CTSlideTiming timing) { + public static String getShapePositionTop(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTTransform2D xfrm = sp.getSpPr().getXfrm(); if (xfrm != null) { long y = xfrm.getOff().getY(); // 垂直位置(EMU) @@ -77,19 +78,20 @@ public class ShapePage { } return ""; } + /// 替换文字 说明 - public static String getShapeText(Shape sp, CTSlideTiming timing) { + public static String getShapeText(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } // 形状填充 填充方式 - public static String getShapeFillType(Shape sp, CTSlideTiming timing) { + public static String getShapeFillType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); return SlideUtils.getFillType(spPr); } // 形状填充 纯色填充-颜色 - public static String getShapeFillSolidColor(Shape sp, CTSlideTiming timing) { + public static String getShapeFillSolidColor(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); if (spPr != null && spPr.getSolidFill() != null) { return SlideUtils.getSolidFillColor(spPr.getSolidFill()); @@ -98,7 +100,7 @@ public class ShapePage { } // 形状填充 渐变填充-效果 - public static String getShapeFillGradientType(Shape sp, CTSlideTiming timing) { + public static String getShapeFillGradientType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); if (spPr != null && spPr.getGradFill() != null) { @@ -109,7 +111,7 @@ public class ShapePage { } // 形状填充 图片填充-效果 - public static String getShapeFillPictureType(Shape sp, CTSlideTiming timing) { + public static String getShapeFillPictureType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); if (spPr != null && spPr.getBlipFill() != null) { @@ -120,7 +122,7 @@ public class ShapePage { } // 形状填充 纹理填充-效果 - public static String getShapeFillTextureType(Shape sp, CTSlideTiming timing) { + public static String getShapeFillTextureType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); if (spPr != null && spPr.getPattFill() != null) { return SlideUtils.printPatternFill(spPr.getPattFill()); @@ -129,7 +131,7 @@ public class ShapePage { } // 形状填充 图案填充-效果 - public static String getShapeFillPatternType(Shape sp, CTSlideTiming timing) { + public static String getShapeFillPatternType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); if (spPr != null && spPr.getPattFill() != null) { return spPr.getPattFill().getPrst().value(); @@ -138,17 +140,17 @@ public class ShapePage { } // 形状填充 幻灯片背景填充-效果 - public static String getShapeFillSlideBackgroundType(Shape sp, CTSlideTiming timing) { + public static String getShapeFillSlideBackgroundType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } // 形状填充 填充透明度 - public static String getShapeFillOpacity(Shape sp, CTSlideTiming timing) { + public static String getShapeFillOpacity(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } // 形状线条 绘制 - public static String getShapeLineDraw(Shape sp, CTSlideTiming timing) { + public static String getShapeLineDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); if (spPr != null && spPr.getLn() != null) { @@ -180,7 +182,7 @@ public class ShapePage { } // 形状线条 线条颜色 - public static String getShapeLineColor(Shape sp, CTSlideTiming timing) { + public static String getShapeLineColor(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); if (spPr != null && spPr.getLn() != null) { @@ -195,7 +197,7 @@ public class ShapePage { } // 形状线条 线条宽度 - public static String getShapeLineWidth(Shape sp, CTSlideTiming timing) { + public static String getShapeLineWidth(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); if (spPr != null && spPr.getLn() != null) { @@ -208,13 +210,13 @@ public class ShapePage { } // 形状线条 透明度 - public static String getShapeLineOpacity(Shape sp, CTSlideTiming timing) { + public static String getShapeLineOpacity(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return ""; } // 形状线条 复合类型 - public static String getStrokeCompound(Shape sp, CTSlideTiming timing) { + public static String getStrokeCompound(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp == null || sp.getSpPr() == null) return "未定义"; CTShapeProperties spPr = sp.getSpPr(); CTLineProperties ln = spPr.getLn(); @@ -238,7 +240,7 @@ public class ShapePage { } // 形状线条 短划线类型 - public static String getStrokeDash(Shape sp, CTSlideTiming timing) { + public static String getStrokeDash(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp == null || sp.getSpPr() == null) return "solid"; CTShapeProperties spPr = sp.getSpPr(); CTLineProperties ln = spPr.getLn(); @@ -264,8 +266,9 @@ public class ShapePage { // 3) 未设置 → 视为实线 return "solid"; } + // 形状线条 开始箭头类型 - public static String getShapeLineStartArrow(Shape sp, CTSlideTiming timing) { + public static String getShapeLineStartArrow(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); if (spPr != null && spPr.getLn() != null) { CTLineProperties ln = spPr.getLn(); @@ -275,22 +278,25 @@ public class ShapePage { } return "无箭头"; } + // 形状线条 开始箭头粗细 - public static String getShapeLineStartArrowWidth(Shape sp, CTSlideTiming timing) { + public static String getShapeLineStartArrowWidth(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + // 形状线条 结尾箭头类型 - public static String getShapeLineEndArrow(Shape sp, CTSlideTiming timing) { + public static String getShapeLineEndArrow(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + // 形状线条 结尾箭头粗细 - public static String getShapeLineEndArrowWidth(Shape sp, CTSlideTiming timing) { + public static String getShapeLineEndArrowWidth(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } // 形状效果 阴影-绘制 - public static String getShapeShadowDraw(Shape sp, CTSlideTiming timing) { + public static String getShapeShadowDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); CTEffectList effList = spPr.getEffectLst(); if (effList == null) { @@ -303,7 +309,7 @@ public class ShapePage { } // 形状效果 阴影-效果 - public static String getShapeShadowEffect(Shape sp, CTSlideTiming timing) { + public static String getShapeShadowEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp == null || sp.getSpPr() == null) { return "无阴影"; } @@ -324,7 +330,7 @@ public class ShapePage { } // 形状效果 倒影-绘制 - public static String getShapeReflectionDraw(Shape sp, CTSlideTiming timing) { + public static String getShapeReflectionDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTShapeProperties spPr = sp.getSpPr(); CTEffectList effList = spPr.getEffectLst(); if (effList == null) { @@ -340,7 +346,7 @@ public class ShapePage { } // 形状效果 倒影-效果 - public static String getShapeReflectionEffect(Shape sp, CTSlideTiming timing) { + public static String getShapeReflectionEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTReflectionEffect r = SlideUtils.getReflection(sp); if (r == null) return "无倒影"; @@ -366,7 +372,7 @@ public class ShapePage { } // 形状效果 发光 - public static String getShapeGlow(Shape sp, CTSlideTiming timing) { + public static String getShapeGlow(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp == null || sp.getSpPr() == null) return null; CTShapeProperties spPr = sp.getSpPr(); CTEffectList eff = spPr.getEffectLst(); @@ -374,36 +380,39 @@ public class ShapePage { } // 形状效果 发光-效果 - public static String getShapeGlowEffect(Shape sp, CTSlideTiming timing) { + public static String getShapeGlowEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } // 形状效果 柔化边缘-绘制 - public static String getShapeSoftEdgesDraw(Shape sp, CTSlideTiming timing) { + public static String getShapeSoftEdgesDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTSoftEdgesEffect se = getSoftEdge(sp); return (se != null) ? "是" : "否"; } // 形状效果 柔化边缘→大小 - public static String getShapeSoftEdgesSize(Shape sp, CTSlideTiming timing) { + public static String getShapeSoftEdgesSize(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { CTSoftEdgesEffect se = getSoftEdge(sp); return (se != null) ? String.valueOf(se.getRad()) : null; } + // 形状效果 三维效果→绘制 - public static String getShape3DEffectDraw(Shape sp, CTSlideTiming timing) { + public static String getShape3DEffectDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + // 形状效果 三维格式→效果 - public static String getShape3DEffect(Shape sp, CTSlideTiming timing) { + public static String getShape3DEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + // 形状效果 三维旋转→效果 - public static String getShape3DRotation(Shape sp, CTSlideTiming timing) { + public static String getShape3DRotation(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } /* —— 内部:spPr/effectLst/softEdge —— */ - private static CTSoftEdgesEffect getSoftEdge(Shape shape) { + private static CTSoftEdgesEffect getSoftEdge(org.pptx4j.pml.Shape shape) { if (shape == null || shape.getSpPr() == null) return null; CTShapeProperties spPr = shape.getSpPr(); CTEffectList eff = spPr.getEffectLst(); @@ -413,440 +422,47 @@ public class ShapePage { // 动画 效果 -// public static String getAnimation(org.pptx4j.pml.Shape sp, CTSlideTiming timing) throws JAXBException, XPathBinderAssociationIsPartialException { -// // 获取形状中的ID -// if (sp == null) return "无动画"; -// long spId = sp.getNvSpPr().getCNvPr().getId(); -// // 获取动画效果 -// CTTimeNodeList timeNodeList = timing.getTnLst(); -// for (Object obj : timeNodeList.getParOrSeqOrExcl()) { -// if (obj instanceof CTTLTimeNodeParallel) { -// CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj; -// CTTLCommonTimeNodeData node = par.getCTn(); -// if (node.getChildTnLst().getParOrSeqOrExcl() != null) { -// CTTimeNodeList childTimeNodeList = node.getChildTnLst(); -// for (Object object : childTimeNodeList.getParOrSeqOrExcl()) { -// if (object instanceof CTTLSetBehavior) { -// if (((CTTLSetBehavior) object).getCBhvr() != null) { -// if (((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt() != null) { -// // 检查目标形状ID是否匹配 -// if (((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) { -// // 返回动画效果 -// -// } -// } -// } -// } -// if (object instanceof CTTLTimeNodeSequence) { -// CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object; -// CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst(); -// for (Object seqObjs : seqNodeList.getParOrSeqOrExcl()) { -// if (seqObjs instanceof CTTLSetBehavior) { -// if (((CTTLSetBehavior) seqObjs).getCBhvr() != null) { -// if (((CTTLSetBehavior) seqObjs).getCBhvr().getTgtEl().getSpTgt() != null) { -// // 检查目标形状ID是否匹配 -// if (((CTTLSetBehavior) seqObjs).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) { -// // 返回动画效果 -// -// } -// } -// } -// } -// if (seqObjs instanceof CTTLTimeNodeSequence) { -// CTTLTimeNodeSequence seqObj = (CTTLTimeNodeSequence) seqObjs; -// CTTimeNodeList seqNodeLists = seqObj.getCTn().getChildTnLst(); -// for (Object seqObjss : seqNodeLists.getParOrSeqOrExcl()) { -// if (seqObjss instanceof CTTLSetBehavior) { -// if (((CTTLSetBehavior) seqObjss).getCBhvr() != null) { -// if (((CTTLSetBehavior) seqObjss).getCBhvr().getTgtEl().getSpTgt() != null) { -// // 检查目标形状ID是否匹配 -// if (((CTTLSetBehavior) seqObjss).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) { -// // 返回动画效果 -// -// } -// } -// } -// } -// } -// } -// } -// } -// } -// } -// -// -// if (node.getDur() != null && !"indefinite".equals(node.getDur())) { -// return node.getDur(); -// } -// System.out.println(par.getCTn()); -// } -// } -// return "待开发"; -// } - - public static String getAnimation(Shape sp, CTSlideTiming timing) { - if (sp == null || timing == null || timing.getTnLst() == null) return "无动画"; - final String spId = String.valueOf(sp.getNvSpPr().getCNvPr().getId()); - CTTimeNodeList root = timing.getTnLst(); - - // 先找进入类(effect) - String entrance = findFirstBehavior(root, spId, /*preferEntrance=*/true); - if (entrance != null) return entrance; - - // 再找其它类型(包括 CTTLAnimateBehavior 的 ppt_x/ppt_y) - String any = findFirstBehavior(root, spId, /*preferEntrance=*/false); - return any != null ? any : "无动画"; + public static String getAnimation(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { + long spId = sp.getNvSpPr().getCNvPr().getId(); + CTTimeNodeList ctTimeNodeList = timing.getTnLst(); + if (ctTimeNodeList == null) return "无动画"; + // 第一层 + List parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl(); + String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "type"); + if (!value.isEmpty()) { + return value; + } + return ""; } - /* 递归遍历所有 time nodes,返回首个命中的行为字符串 */ - private static String findFirstBehavior(CTTimeNodeList list, String spId, boolean preferEntrance) { - if (list == null || list.getParOrSeqOrExcl() == null) return null; - - for (Object raw : list.getParOrSeqOrExcl()) { - Object node = unwrap(raw); - - // 1) 直接是某种行为(Behavior) - String desc = tryDescribeIfBehavior(node, spId, preferEntrance); - if (desc != null) return desc; - - // 2) par / seq / excl,进入子列表递归 - CTTimeNodeList child = getChildList(node); - if (child != null) { - String got = findFirstBehavior(child, spId, preferEntrance); - if (got != null) return got; - } - } - return null; - } - - /* 如果对象是某种 Behavior,且目标命中当前 spId,则返回描述;否则返回 null */ - private static String tryDescribeIfBehavior(Object obj, String spId, boolean preferEntrance) { - // 统一 unwrap - obj = unwrap(obj); - - // --- 进入类效果(Effect)--- - if (obj instanceof CTTLAnimateEffectBehavior) { - CTTLAnimateEffectBehavior b = (CTTLAnimateEffectBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) { - String filter = safe(b.getFilter()); // 如 "fade"、"strips(downRight)" 等 - return filter.isEmpty() ? "进入效果" : ("进入效果:" + filter); - } - } - - // 非优先阶段:其它类型 - if (!preferEntrance) { - // 通用 Animate (B 动画关键:ppt_x / ppt_y) - if (obj instanceof CTTLAnimateBehavior) { - CTTLAnimateBehavior b = (CTTLAnimateBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) { - String attr = firstAttrName(b.getCBhvr()); - if ("ppt_x".equalsIgnoreCase(attr)) return "位置动画:X(ppt_x)"; - if ("ppt_y".equalsIgnoreCase(attr)) return "位置动画:Y(ppt_y)"; - return attr.isEmpty() ? "数值动画(Animate)" : ("数值动画(" + attr + ")"); - } - } - if (obj instanceof CTTLAnimateMotionBehavior) { - CTTLAnimateMotionBehavior b = (CTTLAnimateMotionBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "路径动画(Motion)"; - } - if (obj instanceof CTTLAnimateRotationBehavior) { - CTTLAnimateRotationBehavior b = (CTTLAnimateRotationBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "旋转动画"; - } - if (obj instanceof CTTLAnimateScaleBehavior) { - CTTLAnimateScaleBehavior b = (CTTLAnimateScaleBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "缩放动画"; - } - if (obj instanceof CTTLSetBehavior) { - CTTLSetBehavior b = (CTTLSetBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) { - String to = (b.getTo()!=null && b.getTo().getStrVal()!=null) ? safe(b.getTo().getStrVal().getVal()) : ""; - String attr = firstAttrName(b.getCBhvr()); - if (!attr.isEmpty() || !to.isEmpty()) { - return "属性设置(Set):" + (attr.isEmpty() ? "" : attr) + (to.isEmpty() ? "" : (" -> " + to)); + public static String getAniationInfo(List objects, List upObjects, String spId, String parameter) { + for (Object object : objects) { + if (object instanceof CTTLSetBehavior) { + String spIds = ((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt().getSpid(); + // 判断ID是否一致 + if (spIds.equals(spId)) { + // 持续时间 + if (parameter.equals("dur")) { + return ((CTTLSetBehavior) object).getCBhvr().getCTn().getDur(); } - return "属性设置(Set)"; - } - } - if (obj instanceof CTTLAnimateColorBehavior) { - CTTLAnimateColorBehavior b = (CTTLAnimateColorBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "颜色动画"; - } - if (obj instanceof CTTLCommandBehavior) { - CTTLCommandBehavior b = (CTTLCommandBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "命令动画(Command)"; - } - } - return null; - } - - /* 提取并返回子节点列表(par/seq/excl 三种) */ - private static CTTimeNodeList getChildList(Object node) { - node = unwrap(node); - if (node instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel n = (CTTLTimeNodeParallel) node; - return n.getCTn() != null ? n.getCTn().getChildTnLst() : null; - } - if (node instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence n = (CTTLTimeNodeSequence) node; - return n.getCTn() != null ? n.getCTn().getChildTnLst() : null; - } - if (node instanceof CTTLTimeNodeExclusive) { - CTTLTimeNodeExclusive n = (CTTLTimeNodeExclusive) node; - return n.getCTn() != null ? n.getCTn().getChildTnLst() : null; - } - return null; - } - - /* 判断行为的目标是否命中当前形状 spId */ - private static boolean isTarget(CTTLCommonBehaviorData cb, String spId) { - if (cb == null || cb.getTgtEl() == null || cb.getTgtEl().getSpTgt() == null) return false; - String tgt = cb.getTgtEl().getSpTgt().getSpid(); - return String.valueOf(spId).equals(tgt); - } - - /* 读第一个 attrName(如 ppt_x / ppt_y / style.visibility ...)*/ - private static String firstAttrName(CTTLCommonBehaviorData cb) { - if (cb == null || cb.getAttrNameLst() == null) return ""; - java.util.List names = cb.getAttrNameLst().getAttrName(); - return (names != null && !names.isEmpty()) ? safe(names.get(0)) : ""; - } - - /* 统一解包 JAXBElement */ - private static Object unwrap(Object o) { - return (o instanceof JAXBElement) ? ((JAXBElement) o).getValue() : o; - } - - /* 安全字符串 */ - private static String safe(String s) { - return s == null ? "" : s.trim(); - } - - - // 动画-方向 - public static String getAnimateDirection(Shape sp, CTSlideTiming timing) { - String dir = getAnimation(sp, timing); - if (dir.equals("downRight")) { - return "右下"; - } - if (dir.equals("downLeft")) { - return "左下"; - } - if (dir.equals("upRight")) { - return "右上"; - } - if (dir.equals("upLeft")) { - return "左上"; - } - if (dir.equals("right")) { - return "向右"; - } - if (dir.equals("left")) { - return "向左"; - } - if (dir.equals("down")) { - return "向下"; - } - if (dir.equals("up")) { - return "向上"; - } - if (dir.equals("fromTop")) { - return "从顶部"; - } - if (dir.equals("fromBottom")) { - return "从底部"; - } - if (dir.equals("fromLeft")) { - return "从左侧"; - } - if (dir.equals("fromRight")) { - return "从右侧"; - } - return ""; - } - - // 动画 触发方式 - public static String getAnimateTrigger(Shape sp, CTSlideTiming timing) { - // 获取形状中的ID - if (sp == null) return "无动画"; - long spId = sp.getNvSpPr().getCNvPr().getId(); - // 获取动画效果 - CTTimeNodeList timeNodeList = timing.getTnLst(); - for (Object obj : timeNodeList.getParOrSeqOrExcl()) { - if (obj instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj; - CTTLCommonTimeNodeData node = par.getCTn(); - if (node.getChildTnLst().getParOrSeqOrExcl() != null) { - CTTimeNodeList childTimeNodeList = node.getChildTnLst(); - for (Object object : childTimeNodeList.getParOrSeqOrExcl()) { - if (object instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object; - if (seq.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seq.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } else { - CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst(); - for (Object seqObj : seqNodeList.getParOrSeqOrExcl()) { - if (seqObj instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqs = (CTTLTimeNodeSequence) seqObj; - if (seqs.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } else { - CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst(); - for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) { - if (seqObjs instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs; - if (seqss.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } - } - } - } - } else { - if (seqObj instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel seqs = (CTTLTimeNodeParallel) seqObj; - if (seqs.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } else { - CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst(); - for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) { - if (seqObjs instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs; - if (seqss.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - return ""; - } - // 动画 持续时间 - public static String getAnimationDuration(Shape sp, CTSlideTiming timing) { - if (sp == null || timing == null || timing.getTnLst() == null) return "无动画"; - - final String spId = String.valueOf(sp.getNvSpPr().getCNvPr().getId()); - CTTimeNodeList root = timing.getTnLst(); - - // 先找“进入类效果(effect)” - String entrance = findFirstBehavior(root, spId, /*preferEntrance=*/true); - if (entrance != null) return entrance; - - // 找不到进入类,再找其它类型(运动、旋转、缩放、Set 等) - String any = findFirstBehavior(root, spId, /*preferEntrance=*/false); - return any != null ? any : "无动画"; - } - - // 动画 延迟 - public static String getAnimationDelay(Shape sp, CTSlideTiming timing) { - // 获取形状中的ID - if (sp == null) return "无动画"; - long spId = sp.getNvSpPr().getCNvPr().getId(); - // 获取动画效果 - CTTimeNodeList timeNodeList = timing.getTnLst(); - for (Object obj : timeNodeList.getParOrSeqOrExcl()) { - if (obj instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj; - CTTLCommonTimeNodeData node = par.getCTn(); - if (node.getChildTnLst().getParOrSeqOrExcl() != null) { - CTTimeNodeList childTimeNodeList = node.getChildTnLst(); - for (Object object : childTimeNodeList.getParOrSeqOrExcl()) { - if (object instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object; - if (seq.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seq.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } else { - CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst(); - for (Object seqObj : seqNodeList.getParOrSeqOrExcl()) { - if (seqObj instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqs = (CTTLTimeNodeSequence) seqObj; - if (seqs.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } else { - CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst(); - for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) { - if (seqObjs instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs; - if (seqss.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } - } - } - } - } else { - if (seqObj instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel seqs = (CTTLTimeNodeParallel) seqObj; - if (seqs.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } else { - CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst(); - for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) { - if (seqObjs instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs; - if (seqss.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } - } - } - } - } + // 向上获取延迟 + for (Object upObject : upObjects) { + if (upObject instanceof CTTLTimeNodeParallel) { + // 获取动画效果 + if (parameter.equals("type")) { + Integer type = ((CTTLTimeNodeParallel) upObject).getCTn().getPresetSubtype(); + return String.valueOf(type); + } + // 触发方式 + if (parameter.equals("function")) { + return ((CTTLTimeNodeParallel) upObject).getCTn().getNodeType().value(); + } + // 获取延迟方法 + for (Object condObject : ((CTTLTimeNodeParallel) upObject).getCTn().getStCondLst().getCond()) { + if (condObject instanceof CTTLTimeCondition) { + // 获取延迟 + if (parameter.equals("delay")) { + return ((CTTLTimeCondition) condObject).getDelay(); } } } @@ -854,17 +470,76 @@ public class ShapePage { } } } + if (object instanceof CTTLTimeNodeParallel obj) { + String result = getAniationInfo(obj.getCTn().getChildTnLst().getParOrSeqOrExcl(), objects, spId, parameter); + if (!result.isEmpty()) { + return result; + } + } + if (object instanceof CTTLTimeNodeSequence obj) { + String result = getAniationInfo(obj.getCTn().getChildTnLst().getParOrSeqOrExcl(), objects, spId, parameter); + if (!result.isEmpty()) { + return result; + } + } + } + + return ""; + } + + // 动画-方向 + public static String getAnimateDirection(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { + return "待开发"; + } + + // 动画 触发方式 + public static String getAnimateTrigger(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { + long spId = sp.getNvSpPr().getCNvPr().getId(); + CTTimeNodeList ctTimeNodeList = timing.getTnLst(); + if (ctTimeNodeList == null) return "无动画"; + // 第一层 + List parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl(); + String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "function"); + if (!value.isEmpty()) { + return value; } return ""; } + // 动画 持续时间 + public static String getAnimationDuration(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { + long spId = sp.getNvSpPr().getCNvPr().getId(); + CTTimeNodeList ctTimeNodeList = timing.getTnLst(); + if (ctTimeNodeList == null) return "无动画"; + // 第一层 + List parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl(); + String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "dur"); + if (!value.isEmpty()) { + return value; + } + return ""; + } + + // 动画 延迟 + public static String getAnimationDelay(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { + long spId = sp.getNvSpPr().getCNvPr().getId(); + CTTimeNodeList ctTimeNodeList = timing.getTnLst(); + if (ctTimeNodeList == null) return "无动画"; + // 第一层 + List parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl(); + String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "delay"); + if (!value.isEmpty()) { + return value; + } + return ""; + } /// 形状动作,鼠标单机-动作 /// 文本框 文本 - public static String getTextBoxText(Shape sp, CTSlideTiming timing) { + public static String getTextBoxText(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { StringBuilder textContent = new StringBuilder(); // 检查形状是否有文本框 if (sp.getTxBody() != null) { @@ -887,7 +562,7 @@ public class ShapePage { } /// 文本框 文本-垂直对齐 - public static String getTextBoxVerticalAlign(Shape sp, CTSlideTiming timing) { + public static String getTextBoxVerticalAlign(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBodyProperties textBody = sp.getTxBody().getBodyPr(); STTextAnchoringType anchor = textBody.getAnchor(); @@ -908,7 +583,7 @@ public class ShapePage { } /// 文本框 文本-对齐 - public static String getTextBoxAlign(Shape sp, CTSlideTiming timing) { + public static String getTextBoxAlign(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { STTextVerticalType stTextVerticalType = sp.getTxBody().getBodyPr().getVert(); if (stTextVerticalType != null) { return stTextVerticalType.value(); @@ -918,7 +593,7 @@ public class ShapePage { } /// 文本框 文本-大小调整方式 - public static String getTextBoxSizeAdjust(Shape sp, CTSlideTiming timing) { + public static String getTextBoxSizeAdjust(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() == null || sp.getTxBody().getBodyPr() == null) { return "noAutofit"; // 默认值 } @@ -936,7 +611,7 @@ public class ShapePage { } /// 文本框 上边距 - public static String getTextBoxTopMargin(Shape sp, CTSlideTiming timing) { + public static String getTextBoxTopMargin(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null && sp.getTxBody().getBodyPr() != null) { CTTextBodyProperties bodyPr = sp.getTxBody().getBodyPr(); Integer top = bodyPr.getTIns(); @@ -946,7 +621,7 @@ public class ShapePage { } /// 文本框 下边距 - public static String getTextBoxBottomMargin(Shape sp, CTSlideTiming timing) { + public static String getTextBoxBottomMargin(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null && sp.getTxBody().getBodyPr() != null) { CTTextBodyProperties bodyPr = sp.getTxBody().getBodyPr(); Integer bottom = bodyPr.getBIns(); @@ -956,7 +631,7 @@ public class ShapePage { } /// 文本框 左边距 - public static String getTextBoxLeftMargin(Shape sp, CTSlideTiming timing) { + public static String getTextBoxLeftMargin(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null && sp.getTxBody().getBodyPr() != null) { CTTextBodyProperties bodyPr = sp.getTxBody().getBodyPr(); Integer left = bodyPr.getLIns(); @@ -966,7 +641,7 @@ public class ShapePage { } /// 文本框 右边距 - public static String getTextBoxRightMargin(Shape sp, CTSlideTiming timing) { + public static String getTextBoxRightMargin(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null && sp.getTxBody().getBodyPr() != null) { CTTextBodyProperties bodyPr = sp.getTxBody().getBodyPr(); Integer right = bodyPr.getRIns(); @@ -976,7 +651,7 @@ public class ShapePage { } /// 文本框 自动换行 - public static String getTextBoxAutoWrap(Shape sp, CTSlideTiming timing) { + public static String getTextBoxAutoWrap(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null && sp.getTxBody().getBodyPr() != null) { STTextWrappingType stTextWrappingType = sp.getTxBody().getBodyPr().getWrap(); @@ -986,7 +661,7 @@ public class ShapePage { } /// 字体 西文字体 - public static String getTextBoxFontFamily(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontFamily(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1002,7 +677,7 @@ public class ShapePage { } // 字体 中文字体 - public static String getTextBoxFontFamilyChinese(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontFamilyChinese(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1018,7 +693,7 @@ public class ShapePage { } /// 字体 字体大小 - public static String getTextBoxFontSize(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontSize(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1034,7 +709,7 @@ public class ShapePage { } /// 字体 加粗 - public static String getTextBoxFontBold(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontBold(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1054,7 +729,7 @@ public class ShapePage { } /// 字体 倾斜 - public static String getTextBoxFontItalic(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontItalic(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1074,7 +749,7 @@ public class ShapePage { } /// 字体 字体颜色 - public static String getTextBoxFontColor(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontColor(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1090,7 +765,7 @@ public class ShapePage { } /// 字体 下划线线型 - public static String getTextBoxFontUnderline(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontUnderline(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1106,7 +781,7 @@ public class ShapePage { } /// 字体 下划线颜色 - public static String getTextBoxFontUnderlineColor(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontUnderlineColor(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); for (CTTextParagraph paragraph : textBody.getP()) { @@ -1124,7 +799,7 @@ public class ShapePage { } /// 字体 删除线 - public static String getTextBoxFontStrike(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontStrike(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { // 获取文本框字体是否有删除线 if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); @@ -1143,45 +818,45 @@ public class ShapePage { } /// 字体 双删除线 - public static String getTextBoxFontDoubleStrike(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontDoubleStrike(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } /// 字体 上标 - public static String getTextBoxFontSuperscript(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontSuperscript(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } /// 字体 下标 - public static String getTextBoxFontSubscript(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontSubscript(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } /// 字体 偏移量 - public static String getTextBoxFontOffset(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontOffset(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } /// 字体 小型大写字母 - public static String getTextBoxFontSmallCaps(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontSmallCaps(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } /// 字体 全部大写 - public static String getTextBoxFontAllCaps(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontAllCaps(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } /// 字体 等高字符 - public static String getTextBoxFontFixedWidth(Shape sp, CTSlideTiming timing) { + public static String getTextBoxFontFixedWidth(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } /// 段落 对齐方式 - public static String getTextBoxParagraphAlign(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphAlign(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1195,7 +870,7 @@ public class ShapePage { } /// 段落 文本之前 - public static String getTextBoxParagraphIndentBefore(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphIndentBefore(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1209,7 +884,7 @@ public class ShapePage { } /// 段落 缩进→特殊 - public static String getTextBoxParagraphIndentSpecial(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphIndentSpecial(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1221,8 +896,9 @@ public class ShapePage { } return "0"; } + /// 段落 缩进→度量值 - public static String getTextBoxParagraphIndentMeasure(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphIndentMeasure(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1234,8 +910,9 @@ public class ShapePage { } return "0"; } + /// 段落 间距→段前 - public static String getTextBoxParagraphSpaceBefore(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphSpaceBefore(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1247,8 +924,9 @@ public class ShapePage { } return ""; } + /// 段落 间距→段后 - public static String getTextBoxParagraphSpaceAfter(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphSpaceAfter(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1260,8 +938,9 @@ public class ShapePage { } return ""; } + /// 段落 间距→行距→类型 - public static String getTextBoxParagraphSpaceLine(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphSpaceLine(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 @@ -1276,14 +955,15 @@ public class ShapePage { } return ""; } + /// 段落 间距→行距→设置值 - public static String getTextBoxParagraphSpaceLineValue(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphSpaceLineValue(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); // 遍历所有段落 for (CTTextParagraph paragraph : textBody.getP()) { if (paragraph.getPPr().getLnSpc().getSpcPct() != null) { - return paragraph.getPPr().getLnSpc().getSpcPct().getVal() / 100000 + "倍行距"; // EMU 转 pt + return paragraph.getPPr().getLnSpc().getSpcPct().getVal() / 100000 + "倍行距"; // EMU 转 pt } else if (paragraph.getPPr().getLnSpc().getSpcPts() != null) { return paragraph.getPPr().getLnSpc().getSpcPts().getVal() / 10 + "磅固定行距"; // EMU 转 pt } @@ -1292,13 +972,14 @@ public class ShapePage { } return ""; } + /// 段落 项目符号和编号→类型 - public static String getTextBoxParagraphSymbol(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphSymbol(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } /// 文本填充 填充方式 - public static String getTextBoxParagraphFillType(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphFillType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); for (CTTextParagraph paragraph : textBody.getP()) { @@ -1329,8 +1010,9 @@ public class ShapePage { } return ""; } + /// 文本填充 纯色填充→颜色 - public static String getTextBoxParagraphFillColor(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphFillColor(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { CTTextBody textBody = sp.getTxBody(); for (CTTextParagraph paragraph : textBody.getP()) { @@ -1353,28 +1035,34 @@ public class ShapePage { } return ""; } + /// 文本填充 渐变填充→效果 - public static String getTextBoxParagraphFillGradient(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphFillGradient(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + /// 文本填充 图片填充→效果 - public static String getTextBoxParagraphFillImage(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphFillImage(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + /// 文本填充 纹理填充→效果 - public static String getTextBoxParagraphFillTexture(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphFillTexture(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + /// 文本填充 图案填充→效果 - public static String getTextBoxParagraphFillPattern(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphFillPattern(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + /// 文本填充 填充透明度 - public static String getTextBoxParagraphFillOpacity(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphFillOpacity(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + /// 文本轮廓 颜色 - public static String getTextBoxParagraphOutlineColor(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphOutlineColor(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { for (CTTextParagraph paragraph : sp.getTxBody().getP()) { for (Object obj : paragraph.getEGTextRun()) { @@ -1389,8 +1077,9 @@ public class ShapePage { return ""; } + /// 文本轮廓 透明度 - public static String getTextBoxParagraphOutlineOpacity(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphOutlineOpacity(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { for (CTTextParagraph paragraph : sp.getTxBody().getP()) { for (Object obj : paragraph.getEGTextRun()) { @@ -1402,8 +1091,7 @@ public class ShapePage { int alpha = 0; if (fill.getSrgbClr() != null) { alpha = Integer.parseInt(fill.getSrgbClr().getVal()); - } - else if (fill.getSchemeClr() != null) { + } else if (fill.getSchemeClr() != null) { alpha = fill.getSchemeClr().getVal().ordinal(); } return String.valueOf((100000 - alpha) / 1000.0); @@ -1413,8 +1101,9 @@ public class ShapePage { } return ""; } + /// 文本轮廓 宽度 - public static String getTextBoxParagraphOutlineWidth(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphOutlineWidth(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { for (CTTextParagraph paragraph : sp.getTxBody().getP()) { for (Object obj : paragraph.getEGTextRun()) { @@ -1432,8 +1121,9 @@ public class ShapePage { } return ""; } + /// 文本轮廓 高度 - public static String getTextBoxParagraphOutlineHeight(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphOutlineHeight(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { for (CTTextParagraph paragraph : sp.getTxBody().getP()) { for (Object obj : paragraph.getEGTextRun()) { @@ -1451,17 +1141,19 @@ public class ShapePage { } return ""; } + /// 文本轮廓 复合类型 - public static String getTextBoxParagraphOutlineType(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphOutlineType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + /// 文本轮廓 短划线类型 - public static String getTextBoxParagraphOutlineDashType(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphOutlineDashType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } // 文字效果 阴影→绘制 - public static String getTextBoxParagraphShadowDraw(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphShadowDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { for (CTTextParagraph paragraph : sp.getTxBody().getP()) { for (Object obj : paragraph.getEGTextRun()) { @@ -1479,14 +1171,15 @@ public class ShapePage { } return ""; } + // 文字效果 阴影→预设 // 文字效果 阴影→效果 - public static String getTextBoxParagraphShadowEffect(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphShadowEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } // 文字效果 倒影→绘制 - public static String getTextBoxParagraphReflectionDraw(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphReflectionDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { for (CTTextParagraph paragraph : sp.getTxBody().getP()) { for (Object obj : paragraph.getEGTextRun()) { @@ -1508,7 +1201,7 @@ public class ShapePage { // 文字效果 倒影→预设 // 文字效果 倒影→效果 - public static String getTextBoxParagraphReflectionEffect(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphReflectionEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { if (sp.getTxBody() != null) { for (CTTextParagraph paragraph : sp.getTxBody().getP()) { for (Object obj : paragraph.getEGTextRun()) { @@ -1523,21 +1216,24 @@ public class ShapePage { } return ""; } + // 文字效果 发光→绘制 - public static String getTextBoxParagraphGlowDraw(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphGlowDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + // 文字效果 发光→效果 - public static String getTextBoxParagraphGlowEffect(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphGlowEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } + // 文字效果 转换→弯曲 - public static String getTextBoxParagraphConvertCurve(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphConvertCurve(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { return "待开发"; } // 文字效果 单机鼠标 - public static String getTextBoxParagraphMouseClick(Shape sp, CTSlideTiming timing) { + public static String getTextBoxParagraphMouseClick(org.pptx4j.pml.Shape sp, CTSlideTiming timing) { System.out.println(timing); return "待开发"; } diff --git a/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/ShapePic.java b/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/ShapePic.java index 6c81612..abdc678 100644 --- a/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/ShapePic.java +++ b/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/ShapePic.java @@ -5,6 +5,7 @@ import org.docx4j.dml.*; import org.pptx4j.pml.*; import java.math.BigInteger; +import java.util.List; public class ShapePic { @@ -409,440 +410,46 @@ public class ShapePic { // 动画 效果 -// public static String getAnimation(org.pptx4j.pml.Shape sp, CTSlideTiming timing) throws JAXBException, XPathBinderAssociationIsPartialException { -// // 获取形状中的ID -// if (sp == null) return "无动画"; -// long spId = sp.getNvSpPr().getCNvPr().getId(); -// // 获取动画效果 -// CTTimeNodeList timeNodeList = timing.getTnLst(); -// for (Object obj : timeNodeList.getParOrSeqOrExcl()) { -// if (obj instanceof CTTLTimeNodeParallel) { -// CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj; -// CTTLCommonTimeNodeData node = par.getCTn(); -// if (node.getChildTnLst().getParOrSeqOrExcl() != null) { -// CTTimeNodeList childTimeNodeList = node.getChildTnLst(); -// for (Object object : childTimeNodeList.getParOrSeqOrExcl()) { -// if (object instanceof CTTLSetBehavior) { -// if (((CTTLSetBehavior) object).getCBhvr() != null) { -// if (((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt() != null) { -// // 检查目标形状ID是否匹配 -// if (((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) { -// // 返回动画效果 -// -// } -// } -// } -// } -// if (object instanceof CTTLTimeNodeSequence) { -// CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object; -// CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst(); -// for (Object seqObjs : seqNodeList.getParOrSeqOrExcl()) { -// if (seqObjs instanceof CTTLSetBehavior) { -// if (((CTTLSetBehavior) seqObjs).getCBhvr() != null) { -// if (((CTTLSetBehavior) seqObjs).getCBhvr().getTgtEl().getSpTgt() != null) { -// // 检查目标形状ID是否匹配 -// if (((CTTLSetBehavior) seqObjs).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) { -// // 返回动画效果 -// -// } -// } -// } -// } -// if (seqObjs instanceof CTTLTimeNodeSequence) { -// CTTLTimeNodeSequence seqObj = (CTTLTimeNodeSequence) seqObjs; -// CTTimeNodeList seqNodeLists = seqObj.getCTn().getChildTnLst(); -// for (Object seqObjss : seqNodeLists.getParOrSeqOrExcl()) { -// if (seqObjss instanceof CTTLSetBehavior) { -// if (((CTTLSetBehavior) seqObjss).getCBhvr() != null) { -// if (((CTTLSetBehavior) seqObjss).getCBhvr().getTgtEl().getSpTgt() != null) { -// // 检查目标形状ID是否匹配 -// if (((CTTLSetBehavior) seqObjss).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) { -// // 返回动画效果 -// -// } -// } -// } -// } -// } -// } -// } -// } -// } -// } -// -// -// if (node.getDur() != null && !"indefinite".equals(node.getDur())) { -// return node.getDur(); -// } -// System.out.println(par.getCTn()); -// } -// } -// return "待开发"; -// } - - public static String getAnimation(Pic sp, CTSlideTiming timing) { - if (sp == null || timing == null || timing.getTnLst() == null) return "无动画"; - final String spId = String.valueOf(sp.getNvPicPr().getCNvPr().getId()); - CTTimeNodeList root = timing.getTnLst(); - - // 先找进入类(effect) - String entrance = findFirstBehavior(root, spId, /*preferEntrance=*/true); - if (entrance != null) return entrance; - - // 再找其它类型(包括 CTTLAnimateBehavior 的 ppt_x/ppt_y) - String any = findFirstBehavior(root, spId, /*preferEntrance=*/false); - return any != null ? any : "无动画"; - } - - /* 递归遍历所有 time nodes,返回首个命中的行为字符串 */ - private static String findFirstBehavior(CTTimeNodeList list, String spId, boolean preferEntrance) { - if (list == null || list.getParOrSeqOrExcl() == null) return null; - - for (Object raw : list.getParOrSeqOrExcl()) { - Object node = unwrap(raw); - - // 1) 直接是某种行为(Behavior) - String desc = tryDescribeIfBehavior(node, spId, preferEntrance); - if (desc != null) return desc; - - // 2) par / seq / excl,进入子列表递归 - CTTimeNodeList child = getChildList(node); - if (child != null) { - String got = findFirstBehavior(child, spId, preferEntrance); - if (got != null) return got; - } + public static String getAnimation(org.pptx4j.pml.Pic sp, CTSlideTiming timing) { + long spId = sp.getNvPicPr().getCNvPr().getId(); + CTTimeNodeList ctTimeNodeList = timing.getTnLst(); + if (ctTimeNodeList == null) return "无动画"; + // 第一层 + List parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl(); + String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "type"); + if (!value.isEmpty()) { + return value; } - return null; + return ""; } - - /* 如果对象是某种 Behavior,且目标命中当前 spId,则返回描述;否则返回 null */ - private static String tryDescribeIfBehavior(Object obj, String spId, boolean preferEntrance) { - // 统一 unwrap - obj = unwrap(obj); - - // --- 进入类效果(Effect)--- - if (obj instanceof CTTLAnimateEffectBehavior) { - CTTLAnimateEffectBehavior b = (CTTLAnimateEffectBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) { - String filter = safe(b.getFilter()); // 如 "fade"、"strips(downRight)" 等 - return filter.isEmpty() ? "进入效果" : ("进入效果:" + filter); - } - } - - // 非优先阶段:其它类型 - if (!preferEntrance) { - // 通用 Animate (B 动画关键:ppt_x / ppt_y) - if (obj instanceof CTTLAnimateBehavior) { - CTTLAnimateBehavior b = (CTTLAnimateBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) { - String attr = firstAttrName(b.getCBhvr()); - if ("ppt_x".equalsIgnoreCase(attr)) return "位置动画:X(ppt_x)"; - if ("ppt_y".equalsIgnoreCase(attr)) return "位置动画:Y(ppt_y)"; - return attr.isEmpty() ? "数值动画(Animate)" : ("数值动画(" + attr + ")"); - } - } - if (obj instanceof CTTLAnimateMotionBehavior) { - CTTLAnimateMotionBehavior b = (CTTLAnimateMotionBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "路径动画(Motion)"; - } - if (obj instanceof CTTLAnimateRotationBehavior) { - CTTLAnimateRotationBehavior b = (CTTLAnimateRotationBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "旋转动画"; - } - if (obj instanceof CTTLAnimateScaleBehavior) { - CTTLAnimateScaleBehavior b = (CTTLAnimateScaleBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "缩放动画"; - } - if (obj instanceof CTTLSetBehavior) { - CTTLSetBehavior b = (CTTLSetBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) { - String to = (b.getTo()!=null && b.getTo().getStrVal()!=null) ? safe(b.getTo().getStrVal().getVal()) : ""; - String attr = firstAttrName(b.getCBhvr()); - if (!attr.isEmpty() || !to.isEmpty()) { - return "属性设置(Set):" + (attr.isEmpty() ? "" : attr) + (to.isEmpty() ? "" : (" -> " + to)); + public static String getAniationInfo(List objects, List upObjects, String spId, String parameter) { + for (Object object : objects) { + if (object instanceof CTTLSetBehavior) { + String spIds = ((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt().getSpid(); + // 判断ID是否一致 + if (spIds.equals(spId)) { + // 持续时间 + if (parameter.equals("dur")) { + return ((CTTLSetBehavior) object).getCBhvr().getCTn().getDur(); } - return "属性设置(Set)"; - } - } - if (obj instanceof CTTLAnimateColorBehavior) { - CTTLAnimateColorBehavior b = (CTTLAnimateColorBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "颜色动画"; - } - if (obj instanceof CTTLCommandBehavior) { - CTTLCommandBehavior b = (CTTLCommandBehavior) obj; - if (isTarget(b.getCBhvr(), spId)) return "命令动画(Command)"; - } - } - return null; - } - - /* 提取并返回子节点列表(par/seq/excl 三种) */ - private static CTTimeNodeList getChildList(Object node) { - node = unwrap(node); - if (node instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel n = (CTTLTimeNodeParallel) node; - return n.getCTn() != null ? n.getCTn().getChildTnLst() : null; - } - if (node instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence n = (CTTLTimeNodeSequence) node; - return n.getCTn() != null ? n.getCTn().getChildTnLst() : null; - } - if (node instanceof CTTLTimeNodeExclusive) { - CTTLTimeNodeExclusive n = (CTTLTimeNodeExclusive) node; - return n.getCTn() != null ? n.getCTn().getChildTnLst() : null; - } - return null; - } - - /* 判断行为的目标是否命中当前形状 spId */ - private static boolean isTarget(CTTLCommonBehaviorData cb, String spId) { - if (cb == null || cb.getTgtEl() == null || cb.getTgtEl().getSpTgt() == null) return false; - String tgt = cb.getTgtEl().getSpTgt().getSpid(); - return String.valueOf(spId).equals(tgt); - } - - /* 读第一个 attrName(如 ppt_x / ppt_y / style.visibility ...)*/ - private static String firstAttrName(CTTLCommonBehaviorData cb) { - if (cb == null || cb.getAttrNameLst() == null) return ""; - java.util.List names = cb.getAttrNameLst().getAttrName(); - return (names != null && !names.isEmpty()) ? safe(names.get(0)) : ""; - } - - /* 统一解包 JAXBElement */ - private static Object unwrap(Object o) { - return (o instanceof JAXBElement) ? ((JAXBElement) o).getValue() : o; - } - - /* 安全字符串 */ - private static String safe(String s) { - return s == null ? "" : s.trim(); - } - - - // 动画-方向 - public static String getAnimateDirection(Pic sp, CTSlideTiming timing) { - String dir = getAnimation(sp, timing); - if (dir.equals("downRight")) { - return "右下"; - } - if (dir.equals("downLeft")) { - return "左下"; - } - if (dir.equals("upRight")) { - return "右上"; - } - if (dir.equals("upLeft")) { - return "左上"; - } - if (dir.equals("right")) { - return "向右"; - } - if (dir.equals("left")) { - return "向左"; - } - if (dir.equals("down")) { - return "向下"; - } - if (dir.equals("up")) { - return "向上"; - } - if (dir.equals("fromTop")) { - return "从顶部"; - } - if (dir.equals("fromBottom")) { - return "从底部"; - } - if (dir.equals("fromLeft")) { - return "从左侧"; - } - if (dir.equals("fromRight")) { - return "从右侧"; - } - return ""; - } - - // 动画 触发方式 - public static String getAnimateTrigger(Pic sp, CTSlideTiming timing) { - // 获取形状中的ID - if (sp == null) return "无动画"; - long spId = sp.getNvPicPr().getCNvPr().getId(); - // 获取动画效果 - CTTimeNodeList timeNodeList = timing.getTnLst(); - for (Object obj : timeNodeList.getParOrSeqOrExcl()) { - if (obj instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj; - CTTLCommonTimeNodeData node = par.getCTn(); - if (node.getChildTnLst().getParOrSeqOrExcl() != null) { - CTTimeNodeList childTimeNodeList = node.getChildTnLst(); - for (Object object : childTimeNodeList.getParOrSeqOrExcl()) { - if (object instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object; - if (seq.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seq.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } else { - CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst(); - for (Object seqObj : seqNodeList.getParOrSeqOrExcl()) { - if (seqObj instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqs = (CTTLTimeNodeSequence) seqObj; - if (seqs.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } else { - CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst(); - for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) { - if (seqObjs instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs; - if (seqss.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } - } - } - } - } else { - if (seqObj instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel seqs = (CTTLTimeNodeParallel) seqObj; - if (seqs.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } else { - CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst(); - for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) { - if (seqObjs instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs; - if (seqss.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getEvt().value(); - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - return ""; - } - // 动画 持续时间 - public static String getAnimationDuration(Pic sp, CTSlideTiming timing) { - if (sp == null || timing == null || timing.getTnLst() == null) return "无动画"; - - final String spId = String.valueOf(sp.getNvPicPr().getCNvPr().getId()); - CTTimeNodeList root = timing.getTnLst(); - - // 先找“进入类效果(effect)” - String entrance = findFirstBehavior(root, spId, /*preferEntrance=*/true); - if (entrance != null) return entrance; - - // 找不到进入类,再找其它类型(运动、旋转、缩放、Set 等) - String any = findFirstBehavior(root, spId, /*preferEntrance=*/false); - return any != null ? any : "无动画"; - } - - // 动画 延迟 - public static String getAnimationDelay(Pic sp, CTSlideTiming timing) { - // 获取形状中的ID - if (sp == null) return "无动画"; - long spId = sp.getNvPicPr().getCNvPr().getId(); - // 获取动画效果 - CTTimeNodeList timeNodeList = timing.getTnLst(); - for (Object obj : timeNodeList.getParOrSeqOrExcl()) { - if (obj instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj; - CTTLCommonTimeNodeData node = par.getCTn(); - if (node.getChildTnLst().getParOrSeqOrExcl() != null) { - CTTimeNodeList childTimeNodeList = node.getChildTnLst(); - for (Object object : childTimeNodeList.getParOrSeqOrExcl()) { - if (object instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object; - if (seq.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seq.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } else { - CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst(); - for (Object seqObj : seqNodeList.getParOrSeqOrExcl()) { - if (seqObj instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqs = (CTTLTimeNodeSequence) seqObj; - if (seqs.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } else { - CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst(); - for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) { - if (seqObjs instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs; - if (seqss.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } - } - } - } - } else { - if (seqObj instanceof CTTLTimeNodeParallel) { - CTTLTimeNodeParallel seqs = (CTTLTimeNodeParallel) seqObj; - if (seqs.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } else { - CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst(); - for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) { - if (seqObjs instanceof CTTLTimeNodeSequence) { - CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs; - if (seqss.getCTn().getStCondLst() != null) { - CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst(); - for (CTTLTimeCondition o : stCondLst.getCond()) { - if (o.getEvt() != null) { - return o.getDelay(); - } - } - } - } - } - } - } + // 向上获取延迟 + for (Object upObject : upObjects) { + if (upObject instanceof CTTLTimeNodeParallel) { + // 获取动画效果 + if (parameter.equals("type")) { + Integer type = ((CTTLTimeNodeParallel) upObject).getCTn().getPresetSubtype(); + return String.valueOf(type); + } + // 触发方式 + if (parameter.equals("function")) { + return ((CTTLTimeNodeParallel) upObject).getCTn().getNodeType().value(); + } + // 获取延迟方法 + for (Object condObject : ((CTTLTimeNodeParallel) upObject).getCTn().getStCondLst().getCond()) { + if (condObject instanceof CTTLTimeCondition) { + // 获取延迟 + if (parameter.equals("delay")) { + return ((CTTLTimeCondition) condObject).getDelay(); } } } @@ -850,10 +457,68 @@ public class ShapePic { } } } + if (object instanceof CTTLTimeNodeParallel obj) { + String result = getAniationInfo(obj.getCTn().getChildTnLst().getParOrSeqOrExcl(), objects, spId, parameter); + if (!result.isEmpty()) { + return result; + } + } + if (object instanceof CTTLTimeNodeSequence obj) { + String result = getAniationInfo(obj.getCTn().getChildTnLst().getParOrSeqOrExcl(), objects, spId, parameter); + if (!result.isEmpty()) { + return result; + } + } + } + + return ""; + } + + // 动画-方向 + public static String getAnimateDirection(org.pptx4j.pml.Pic sp, CTSlideTiming timing) { + return "待开发"; + } + + // 动画 触发方式 + public static String getAnimateTrigger(org.pptx4j.pml.Pic sp, CTSlideTiming timing) { + long spId = sp.getNvPicPr().getCNvPr().getId(); + CTTimeNodeList ctTimeNodeList = timing.getTnLst(); + if (ctTimeNodeList == null) return "无动画"; + // 第一层 + List parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl(); + String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "function"); + if (!value.isEmpty()) { + return value; } return ""; } - /// 形状动作,鼠标单机-动作 + // 动画 持续时间 + public static String getAnimationDuration(org.pptx4j.pml.Pic sp, CTSlideTiming timing) { + long spId = sp.getNvPicPr().getCNvPr().getId(); + CTTimeNodeList ctTimeNodeList = timing.getTnLst(); + if (ctTimeNodeList == null) return "无动画"; + // 第一层 + List parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl(); + String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "dur"); + if (!value.isEmpty()) { + return value; + } + return ""; + } -} + // 动画 延迟 + public static String getAnimationDelay(org.pptx4j.pml.Pic sp, CTSlideTiming timing) { + long spId = sp.getNvPicPr().getCNvPr().getId(); + CTTimeNodeList ctTimeNodeList = timing.getTnLst(); + if (ctTimeNodeList == null) return "无动画"; + // 第一层 + List parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl(); + String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "delay"); + if (!value.isEmpty()) { + return value; + } + return ""; + } + /// 形状动作,鼠标单机-动作 +} \ No newline at end of file diff --git a/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/SlideConversion.java b/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/SlideConversion.java deleted file mode 100644 index 357e566..0000000 --- a/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/SlideConversion.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.example.exam.exam.service.wpspptx.pptx4j; - -import com.example.exam.exam.service.wpspptx.pptx4j.vo.SlideDataInfoVO; -import org.apache.poi.xslf.usermodel.XMLSlideShow; -import org.apache.poi.xslf.usermodel.XSLFSlide; -import org.apache.xmlbeans.XmlCursor; -import org.springframework.web.multipart.MultipartFile; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -public class SlideConversion { - // 大纲 - // 1、获取第一层目录 幻灯片 - 母版 - 设置 - 其他 - // 2、获取第二层目录 第x页 - 幻灯片母版/备注母版 - 幻灯片设置 - 文件操作 - // 3、获取第三层目录 幻灯片设置/形状 - 幻灯片母版 - 幻灯片设置 - 文件操作 - public static List SlideDataInfos(MultipartFile file) throws Exception { - List dataInfoVOS = new ArrayList<>(); - try (InputStream inputStream = file.getInputStream(); - XMLSlideShow pptxXml = new XMLSlideShow(inputStream)) { - int index = 0; - String firstId = getStringRandom(); - setSlideDataInfo(firstId, "", "幻灯片", "slide", "", false, dataInfoVOS); - for (XSLFSlide slides : pptxXml.getSlides()){ - index += 1; - String secondId = getStringRandom(); - setSlideDataInfo(secondId, firstId, "第"+index+"页", "sld", String.valueOf(index), true, dataInfoVOS); - // 第三层 - String thirdId = getStringRandom(); - int indexCnvPr = 1; - setSlideDataInfo(thirdId, secondId, "幻灯片设置", "slideSetting", String.valueOf(index) + "_0", true, dataInfoVOS); - XmlCursor spCursor = slides.getXmlObject().newCursor(); - spCursor.selectPath("declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//p:sp"); - while (spCursor.toNextSelection()) { - XmlCursor cNvPrXml = spCursor.newCursor(); - cNvPrXml.selectPath("declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//p:cNvPr/@name"); - if (cNvPrXml.toNextSelection()) { - String name = cNvPrXml.getTextValue(); - String fourId = getStringRandom(); - setSlideDataInfo(fourId, secondId, "形状"+indexCnvPr+"->"+name, "shape", String.valueOf(index) + "_" + String.valueOf(indexCnvPr), true, dataInfoVOS); - indexCnvPr += 1; - } - } - XmlCursor picCursor = slides.getXmlObject().newCursor(); - System.out.println(picCursor.xmlText()); - picCursor.selectPath("declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//p:pic"); - int indexCnvPrPic = 1; - while (picCursor.toNextSelection()) { - String fourId = getStringRandom(); - setSlideDataInfo(fourId, secondId, "图像"+indexCnvPrPic+"->图像", "shapePic", String.valueOf(indexCnvPrPic), true, dataInfoVOS); - indexCnvPrPic += 1; - } - } - // 设置 - String firstIds = getStringRandom(); - setSlideDataInfo(firstIds, "", "设置", "presentation", String.valueOf(0), false, dataInfoVOS); - String secondIds = getStringRandom(); - setSlideDataInfo(secondIds, firstIds, "幻灯片设置", "presentation", String.valueOf(0), true, dataInfoVOS); - - // 母版 -// String dFirstId = getStringRandom(); -// setPptxInfo("母版", "p:sld", "p:sld", filePath, dFirstId, "0", pptxInfoReqVos); - } catch (Exception e) { - throw new RuntimeException(e); - } - return dataInfoVOS; - } - - public static String getStringRandom() { - String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - Random random = new Random(); - StringBuilder sb = new StringBuilder(); - - // 生成指定长度的随机字符字符串 - for (int i = 0; i < 10; i++) { - int randomIndex = random.nextInt(characters.length()); - // 随机字符 - sb.append(characters.charAt(randomIndex)); - } - return sb.toString(); - } - - // 想数组中添加数据 - public static void setSlideDataInfo(String id, String parentId, String text, - String type, String index, boolean isTrue, List dataInfoVOS) throws Exception { - SlideDataInfoVO dataInfo = new SlideDataInfoVO(); - dataInfo.setId(id); - dataInfo.setParentId(parentId); - dataInfo.setName(text); - dataInfo.setType(type); - dataInfo.setIndex(index); - dataInfo.setClick(isTrue); - dataInfoVOS.add(dataInfo); - } -} diff --git a/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/SlideMaster.java b/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/SlideMaster.java index d03c417..c49aa56 100644 --- a/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/SlideMaster.java +++ b/src/main/java/com/example/exam/exam/service/wpspptx/pptx4j/SlideMaster.java @@ -21,15 +21,14 @@ import java.util.List; public class SlideMaster { - public static List slideMaster(List wpsSlideInfoVos, File file) throws IOException, Docx4JException { + public static List slideMaster(List wpsSlideInfoVos, MultipartFile file) throws IOException, Docx4JException { // File files = new File("E:\\Project\\Exam\\Software\\Temp\\1.pptx"); List judgementSlidesVOS = new ArrayList<>(); // 1、获取想要判断的文件地址(文件流) -// try (InputStream inputStream = file.getInputStream()) { - try { + try (InputStream inputStream = file.getInputStream()) { // 加载 .pptx 文件 PresentationMLPackage ppt = - (PresentationMLPackage) OpcPackage.load(file); + (PresentationMLPackage) OpcPackage.load(inputStream); // 你可以在这里处理 ppt,比如读取文字、页数等 for (WpsSlideInfoVo wpsSlideInfoVo : wpsSlideInfoVos) { // 幻灯片位置(第几张幻灯片) @@ -45,7 +44,6 @@ public class SlideMaster { String examCode = wpsSlideInfoVo.getExamCode(); // 方式方法 String method = wpsSlideInfoVo.getMethod(); - String content = wpsSlideInfoVo.getSlideIndex() + "@" + firstName + "@" + function + "@" + examName + "@" + examCode + "@" + method; // 查询幻灯片图片 List slideParts = ppt.getMainPresentationPart().getSlideParts(); diff --git a/src/main/java/com/example/exam/exam/service/wpsword/JudgementWpsWordService.java b/src/main/java/com/example/exam/exam/service/wpsword/JudgementWpsWordService.java index 04736d1..31a8318 100644 --- a/src/main/java/com/example/exam/exam/service/wpsword/JudgementWpsWordService.java +++ b/src/main/java/com/example/exam/exam/service/wpsword/JudgementWpsWordService.java @@ -18,9 +18,9 @@ public interface JudgementWpsWordService { * 读取考生文件,与题型中要求进行判断 * @param path 文件路径 * @param examQuestion 试题参数 - * @param sorce 试题分数 + * @param source 试题分数 * @return 得分 * @throws Exception 异常 */ - SourceAndText judgementWpsWord(double sorce, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception; + SourceAndText judgementWpsWord(double source, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception; } diff --git a/src/main/java/com/example/exam/exam/service/wpsword/JudgementWpsWordServiceImpl.java b/src/main/java/com/example/exam/exam/service/wpsword/JudgementWpsWordServiceImpl.java index ed31a7c..fd96e69 100644 --- a/src/main/java/com/example/exam/exam/service/wpsword/JudgementWpsWordServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/wpsword/JudgementWpsWordServiceImpl.java @@ -9,8 +9,6 @@ import com.example.exam.exam.service.wpsword.docx4j.vo.JudgementWordsVO; import com.example.exam.exam.service.wpsword.docx4j.vo.WpsDocxInfoVo; import com.example.exam.exam.utils.CustomMultipartFile; import com.example.exam.exam.utils.HtmlAppender; -import com.example.exam.exam.utils.c.LogFileUtils; -import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -27,14 +25,13 @@ import java.util.List; public class JudgementWpsWordServiceImpl implements JudgementWpsWordService { @Override - public SourceAndText judgementWpsWord(double sorce, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception { + public SourceAndText judgementWpsWord(double source, String pathC, String path, ExamQuestion examQuestion, String judgementStr) throws Exception { SourceAndText sourceAndText = new SourceAndText(); List wpsDocxInfos = new ArrayList<>(); - + boolean isAllTrue = true; // 判断考点是否全对标识 // 日志:开始判分 judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 开始WPS_Word判分"); double wps_word_sorce = 0; - // 获取答案组成 List answerList = examQuestion.getAnswerList(); for (ExamQuestionAnswer examQuestionAnswer : answerList) { @@ -50,13 +47,10 @@ public class JudgementWpsWordServiceImpl implements JudgementWpsWordService { wpsDocxInfos.add(wpsDocxInfoVo); } } - // 将文件转成 MultipartFile MultipartFile multipartFile = new CustomMultipartFile(new File(path)); - // 获取文档检测结果 List judgementWordsVOS = DocxMaster.docxMaster(wpsDocxInfos, multipartFile); - // 判分 for (ExamQuestionAnswer examQuestionAnswer : answerList) { boolean flag = false; // 每个答案单独判断 @@ -69,16 +63,15 @@ public class JudgementWpsWordServiceImpl implements JudgementWpsWordService { flag = true; // 计算分数 if ("1".equals(examQuestionAnswer.getScoreRate())) { - one_sorce = sorce / answerList.size(); + one_sorce = source / answerList.size(); } else { - one_sorce = sorce * Double.parseDouble(examQuestionAnswer.getScoreRate()); + one_sorce = source * Double.parseDouble(examQuestionAnswer.getScoreRate()); } break; // 找到匹配立即跳出 } } - + // 分数相加 wps_word_sorce += one_sorce; - if (flag) { judgementStr = HtmlAppender.appendHtmlLine( judgementStr, @@ -86,14 +79,19 @@ public class JudgementWpsWordServiceImpl implements JudgementWpsWordService { new BigDecimal(one_sorce).setScale(1, RoundingMode.HALF_UP) ); } else { + isAllTrue = false; // 有一个考点不对,标识为不全对 judgementStr = HtmlAppender.appendHtmlLine( judgementStr, "❌ " + examQuestionAnswer.getContentIn() + " 得分失败" ); } } - - sourceAndText.setScore(wps_word_sorce); + if (isAllTrue) { + // 如果全对,分数为总分 + sourceAndText.setScore(source); + } else { + sourceAndText.setScore(wps_word_sorce); + } sourceAndText.setText(judgementStr); return sourceAndText; }