【修改】 1、WPS相关试题,考点全对返回试题分数,2、新增邮箱判分与生成文件方法,3、优化代码,增加备注
This commit is contained in:
@@ -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<BigDecimal> getStuSource(StuInfoVo stuInfoVo){
|
||||
public Result<BigDecimal> getStuSource(StuInfoVo stuInfoVo) {
|
||||
BigDecimal source = new BigDecimal(0);
|
||||
List<StuPaperScoreDO> 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<BigDecimal> 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<BigDecimal> 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<BigDecimal> 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<BigDecimal> 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<BigDecimal> 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<String> tNames) throws Exception {
|
||||
mysqlLocalService.delMysqlConnect(tNames);
|
||||
}
|
||||
// 文件处理
|
||||
|
||||
/**
|
||||
* 文件提 判分
|
||||
* @param stuInfoVo 学生信息
|
||||
* @return 分数
|
||||
* @throws SQLException 异常信息
|
||||
* @throws IOException 异常信息
|
||||
*/
|
||||
@PostMapping("/judgementForFile")
|
||||
public Result<BigDecimal> judgementForFile(@RequestBody StuInfoVo stuInfoVo) throws SQLException, IOException {
|
||||
return Result.success(autoForFileService.autoForFile(stuInfoVo));
|
||||
}
|
||||
// 浏览器
|
||||
|
||||
/**
|
||||
* 浏览器题 判分
|
||||
* @param stuInfoVo 学生信息
|
||||
* @return 分数
|
||||
* @throws SQLException 异常信息
|
||||
* @throws IOException 异常信息
|
||||
*/
|
||||
@PostMapping("/judgementForBrower")
|
||||
public Result<BigDecimal> 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<String> judgementForEdgeDummyToJson(@RequestBody StuInfoVo stuInfoVo){
|
||||
public Result<String> judgementForEdgeDummyToJson(@RequestBody StuInfoVo stuInfoVo) {
|
||||
return Result.success(autoForWinEdgeSettingService.autoForEdgeToJson(stuInfoVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱设置判分
|
||||
*
|
||||
* @param stuInfoVo 学生信息
|
||||
* @return String
|
||||
*/
|
||||
@PostMapping("/judgementForEmailDummy")
|
||||
public Result<BigDecimal> judgementForEmailDummy(@RequestBody StuInfoVo stuInfoVo) throws IOException {
|
||||
return Result.success(autoForWinEdgeSettingService.autoForEdge(stuInfoVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱的页面写入到JSON文件中
|
||||
*
|
||||
* @param stuInfoVo 学生信息
|
||||
* @return String
|
||||
*/
|
||||
@PostMapping("/judgementForEmailDummyToJson")
|
||||
public Result<String> judgementForEmailDummyToJson(@RequestBody StuInfoVo stuInfoVo) {
|
||||
return Result.success(autoForWinEmailSettingService.autoForEmailToJson(stuInfoVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* windows网络设置判分
|
||||
* @param stuInfoVo 学生选择题信息
|
||||
*
|
||||
* @param stuInfoVo 学生信息
|
||||
* @return String
|
||||
*/
|
||||
@PostMapping("/judgementForEdgeDummy")
|
||||
public Result<BigDecimal> 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<BigDecimal> 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<String> judgementForChoiceToJson(@RequestBody StuInfoVo stuInfoVo){
|
||||
public Result<String> judgementForChoiceToJson(@RequestBody StuInfoVo stuInfoVo) {
|
||||
return Result.success(autoForChoiceService.autoForChoiceToJson(stuInfoVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择题判分
|
||||
* @param stuInfoVo 学生选择题信息
|
||||
*
|
||||
* @param stuInfoVo 学生信息
|
||||
* @return String
|
||||
*/
|
||||
@PostMapping("/judgementForChoice")
|
||||
|
||||
@@ -23,10 +23,10 @@ public class StuInfoVo {
|
||||
// 选择题学生答案
|
||||
private String choiceAnswerId;
|
||||
|
||||
// Edge学生设置Key
|
||||
// Edge学生设置Key(邮箱也使用)
|
||||
private String edgeAnswerKeys;
|
||||
|
||||
// Edge学生设置Value
|
||||
// Edge学生设置Value(邮箱也使用)
|
||||
private String edgeAnswerValues;
|
||||
|
||||
// 学校名称
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<String, String> 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<ExamQuestion> examQuestions = educationPaperMapper.selectPaperQuByPaperId(stuInfoVo.getPaperId());
|
||||
List<ExamQuestion> edgeList = new ArrayList<>();
|
||||
for (ExamQuestion examQuestion : examQuestions) {
|
||||
if ("邮箱".equals(examQuestion.getSubjectName())) {
|
||||
edgeList.add(examQuestion);
|
||||
}
|
||||
}
|
||||
// 获取所有json文件,并取出试题ID
|
||||
List<File> 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<String> trueFileQuid = new ArrayList<>();
|
||||
List<String> 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<File> 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<EducationPaperQu> educationPaperQus = educationPaperQuMapper.selectPaperQuListByPaperId(stuInfoVo.getPaperId());
|
||||
Optional<EducationPaperQu> resultss = educationPaperQus.stream().filter(entry -> entry.getQuId().equals(quId))
|
||||
.findFirst();
|
||||
// 获取排序
|
||||
EducationPaperQu educationPaperQu = resultss.get();
|
||||
|
||||
// 试题分数
|
||||
List<EducationPaperScheme> educationPaperSchemeList = educationPaperSchemeMapper.selectEducationPaperTaskByPaperId(stuInfoVo.getPaperId());
|
||||
Optional<EducationPaperScheme> 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<String, String> map = objectMapper.readValue(jsonText, Map.class);
|
||||
|
||||
String judgementStr = "<p>-----------------------------------------------------------</p>";
|
||||
judgementStr += "<p>试题序号:" + educationPaperQu.getSort() + "</p>";
|
||||
judgementStr += "<p>试题编号:" + examQuestion.getQuNum() + "</p>";
|
||||
judgementStr += "<p>试题分数:" + Double.parseDouble(quScore) + "</p>";
|
||||
judgementStr += "<p>试题名称: 邮箱 </p>";
|
||||
|
||||
// 考试进行比对
|
||||
for (ExamQuestionAnswer questionAnswer : examQuestion.getAnswerList()) {
|
||||
boolean flag = false;
|
||||
double one_sorce = 0;
|
||||
for (Map.Entry<String, String> 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 += "<p>试题得分: " + oneScore + " </p>";
|
||||
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<EducationPaperQu> educationPaperQus = educationPaperQuMapper.selectPaperQuListByPaperId(stuInfoVo.getPaperId());
|
||||
Optional<EducationPaperQu> resultss = educationPaperQus.stream().filter(entry -> entry.getQuId().equals(quId))
|
||||
.findFirst();
|
||||
// 获取排序
|
||||
EducationPaperQu educationPaperQu = resultss.get();
|
||||
|
||||
// 试题分数
|
||||
List<EducationPaperScheme> educationPaperSchemeList = educationPaperSchemeMapper.selectEducationPaperTaskByPaperId(stuInfoVo.getPaperId());
|
||||
Optional<EducationPaperScheme> result = educationPaperSchemeList.stream().filter(quLists -> quLists.getSpName().equals("windows网络设置")).findFirst();
|
||||
String quScore = result.get().getQuScores();
|
||||
// 根据ID查询试题
|
||||
ExamQuestion examQuestion = examQuestionService.selectExamQuestionByQuId(quId);
|
||||
String judgementStr = "<p>-----------------------------------------------------------</p>";
|
||||
judgementStr += "<p>试题序号:" + educationPaperQu.getSort() + "</p>";
|
||||
judgementStr += "<p>试题编号:" + examQuestion.getQuNum() + "</p>";
|
||||
judgementStr += "<p>试题分数:" + Double.parseDouble(quScore) + "</p>";
|
||||
judgementStr += "<p>试题名称: 邮箱 </p>";
|
||||
judgementStr += "<p>❌ 未成功检测到作答情况</p>";
|
||||
judgementStr += "<p>试题得分: 0分 </p>";
|
||||
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<String, String> map, String filePath) {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
File file = new File(filePath);
|
||||
|
||||
try {
|
||||
Map<String, String> 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 += "<p>试题名称: windows网络设置 </p>";
|
||||
judgementStr += "<p>❌ 未成功检测到作答情况</p>";
|
||||
judgementStr += "<p>试题得分: 0分 </p>";
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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<ExamQuestionAnswer> answerList, Map<String, String> stuFiles,double score,int total, String judgementStr) {
|
||||
static SourceAndTextAndTotal compareStuAndTestFiles(List<ExamQuestionAnswer> answerList, Map<String, String> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定内容追加写入到指定文件中。
|
||||
*
|
||||
|
||||
@@ -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<String> 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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -15,10 +15,5 @@ public interface StuPaperScoreService {
|
||||
List<StuPaperScoreDO> 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);
|
||||
|
||||
}
|
||||
@@ -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<ExamQuestionAnswer> answerList, Map<String, String> 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<ExamQuestionAnswer> answerList, Map<String, String> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,8 +10,6 @@ import java.io.IOException;
|
||||
public interface IFileServerice {
|
||||
|
||||
|
||||
|
||||
|
||||
SourceAndText Judgement(double score, File file, ExamQuestion question, String judgementStr) throws IOException;
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<WpsXlsxInfoVo> 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<String> 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<JudgementXlsxVO> 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;
|
||||
}
|
||||
|
||||
@@ -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 结果
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<WpsSlideInfoVo> judgementReq = new ArrayList<>();
|
||||
// 3、获取答案得组成
|
||||
List<ExamQuestionAnswer> answerList = examQuestion.getAnswerList();
|
||||
List<ExamQuestionAnswer> 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<JudgementSlidesVO> judgementDtos = SlideMaster.slideMaster(judgementReq, new File(path));
|
||||
MultipartFile multipartFile = new CustomMultipartFile(new File(path));
|
||||
List<JudgementSlidesVO> 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;
|
||||
}
|
||||
|
||||
@@ -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 结果
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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<Object> 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<Object> objects, List<Object> 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<String> 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<Object> 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<Object> 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<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "delay");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
/// 形状动作,鼠标单机-动作
|
||||
}
|
||||
@@ -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<SlideDataInfoVO> SlideDataInfos(MultipartFile file) throws Exception {
|
||||
List<SlideDataInfoVO> 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<SlideDataInfoVO> 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);
|
||||
}
|
||||
}
|
||||
@@ -21,15 +21,14 @@ import java.util.List;
|
||||
|
||||
public class SlideMaster {
|
||||
|
||||
public static List<JudgementSlidesVO> slideMaster(List<WpsSlideInfoVo> wpsSlideInfoVos, File file) throws IOException, Docx4JException {
|
||||
public static List<JudgementSlidesVO> slideMaster(List<WpsSlideInfoVo> wpsSlideInfoVos, MultipartFile file) throws IOException, Docx4JException {
|
||||
// File files = new File("E:\\Project\\Exam\\Software\\Temp\\1.pptx");
|
||||
List<JudgementSlidesVO> 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<SlidePart> slideParts = ppt.getMainPresentationPart().getSlideParts();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<WpsDocxInfoVo> wpsDocxInfos = new ArrayList<>();
|
||||
|
||||
boolean isAllTrue = true; // 判断考点是否全对标识
|
||||
// 日志:开始判分
|
||||
judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "✅ 开始WPS_Word判分");
|
||||
double wps_word_sorce = 0;
|
||||
|
||||
// 获取答案组成
|
||||
List<ExamQuestionAnswer> 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<JudgementWordsVO> 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user