【新增】生成笔试试卷,细节修改
This commit is contained in:
@@ -127,7 +127,61 @@
|
|||||||
<groupId>org.apache.tika</groupId>
|
<groupId>org.apache.tika</groupId>
|
||||||
<artifactId>tika-core</artifactId> <!-- 文件客户端:文件类型的识别 -->
|
<artifactId>tika-core</artifactId> <!-- 文件客户端:文件类型的识别 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Apache POI 相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi</artifactId>
|
||||||
|
<version>4.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-ooxml</artifactId>
|
||||||
|
<version>4.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>ooxml-schemas</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.afterturn</groupId>
|
||||||
|
<artifactId>easypoi-base</artifactId>
|
||||||
|
<version>4.4.0</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi</artifactId>
|
||||||
|
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-ooxml</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>ooxml-schemas</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-imaging</artifactId>
|
||||||
|
<version>1.0-alpha3</version> <!-- 使用最新版本 -->
|
||||||
|
</dependency>
|
||||||
|
<!-- Adobe 官方 XMPCore 库 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.adobe.xmp</groupId>
|
||||||
|
<artifactId>xmpcore</artifactId>
|
||||||
|
<version>6.1.11</version> <!-- 最新稳定版 -->
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -123,12 +123,12 @@ public class EducationPaperController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据方案获取试卷
|
* 根据方案获取试卷下拉
|
||||||
*/
|
*/
|
||||||
@GetMapping(value = "/getPaperByTaskId")
|
@GetMapping(value = "/getPaperByTaskId")
|
||||||
public CommonResult getPaperByTaskId(@RequestParam(value = "taskId") String taskId)
|
public CommonResult getPaperByTaskId(@RequestParam(value = "taskId") String taskId)
|
||||||
{
|
{
|
||||||
return CommonResult.success(educationPaperService.selectPaperByTaskId(taskId));
|
return CommonResult.success(educationPaperService.selectPaperIdAndNumByTaskId(taskId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -216,4 +216,17 @@ public class EducationPaperController
|
|||||||
return CommonResult.success(pageResult);
|
return CommonResult.success(pageResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载试卷
|
||||||
|
* @param paperIds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("/addUpload/{paperIds}")
|
||||||
|
public void downLoad(@PathVariable String[] paperIds, HttpServletResponse response) throws Exception {
|
||||||
|
educationPaperService.downloadWord(paperIds,response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package pc.exam.pp.module.exam.controller.admin.paper.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class PaperIdAndNum {
|
||||||
|
private String num;
|
||||||
|
private String paperId;
|
||||||
|
}
|
||||||
@@ -73,6 +73,11 @@ public class EducationPaperScheme
|
|||||||
// @Excel(name = "小计分数")
|
// @Excel(name = "小计分数")
|
||||||
private String subtotalScore;
|
private String subtotalScore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 试卷呆鹅题号
|
||||||
|
*/
|
||||||
|
@TableField(exist = false)
|
||||||
|
private String upperCase;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package pc.exam.pp.module.exam.dal.mysql.paper;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
@@ -9,6 +10,7 @@ import pc.exam.pp.framework.common.pojo.PageResult;
|
|||||||
import pc.exam.pp.framework.mybatis.core.mapper.BaseMapperX;
|
import pc.exam.pp.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import pc.exam.pp.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import pc.exam.pp.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.dto.EducationPaperStuDto;
|
import pc.exam.pp.module.exam.controller.admin.paper.dto.EducationPaperStuDto;
|
||||||
|
import pc.exam.pp.module.exam.controller.admin.paper.dto.PaperIdAndNum;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperPageVo;
|
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperPageVo;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperTaskPageVo;
|
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperTaskPageVo;
|
||||||
import pc.exam.pp.module.exam.dal.dataobject.EducationPaper;
|
import pc.exam.pp.module.exam.dal.dataobject.EducationPaper;
|
||||||
@@ -93,7 +95,7 @@ public interface EducationPaperMapper extends BaseMapperX<EducationPaper>
|
|||||||
|
|
||||||
String selectTaskIdByPaperId(String paperId);
|
String selectTaskIdByPaperId(String paperId);
|
||||||
|
|
||||||
List<String> selectPaperByTaskId(String taskId);
|
List<String> selectPaperByTaskId(String taskId);
|
||||||
|
|
||||||
public int updateEducationByids(@Param("strings")List<String> strings);
|
public int updateEducationByids(@Param("strings")List<String> strings);
|
||||||
|
|
||||||
@@ -129,5 +131,8 @@ public interface EducationPaperMapper extends BaseMapperX<EducationPaper>
|
|||||||
.eq(EducationPaper::getStatus, 0)
|
.eq(EducationPaper::getStatus, 0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<PaperIdAndNum> selectPaperIdAndNumByTaskId(String taskId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package pc.exam.pp.module.exam.service.paper;
|
package pc.exam.pp.module.exam.service.paper;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.afterturn.easypoi.word.WordExportUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||||
import org.checkerframework.checker.units.qual.A;
|
import org.checkerframework.checker.units.qual.A;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -9,6 +12,7 @@ import pc.exam.pp.framework.security.core.util.SecurityFrameworkUtils;
|
|||||||
import pc.exam.pp.framework.tenant.core.aop.TenantIgnore;
|
import pc.exam.pp.framework.tenant.core.aop.TenantIgnore;
|
||||||
import pc.exam.pp.framework.tenant.core.context.TenantContextHolder;
|
import pc.exam.pp.framework.tenant.core.context.TenantContextHolder;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.dto.EducationPaperStuDto;
|
import pc.exam.pp.module.exam.controller.admin.paper.dto.EducationPaperStuDto;
|
||||||
|
import pc.exam.pp.module.exam.controller.admin.paper.dto.PaperIdAndNum;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.ExamPaperVo;
|
import pc.exam.pp.module.exam.controller.admin.paper.vo.ExamPaperVo;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperPageVo;
|
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperPageVo;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.StuInfoPaper;
|
import pc.exam.pp.module.exam.controller.admin.paper.vo.StuInfoPaper;
|
||||||
@@ -18,6 +22,10 @@ import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionMapper;
|
|||||||
import pc.exam.pp.module.exam.dal.mysql.question.SysFileMapper;
|
import pc.exam.pp.module.exam.dal.mysql.question.SysFileMapper;
|
||||||
import pc.exam.pp.module.exam.utils.uuid.IdUtils;
|
import pc.exam.pp.module.exam.utils.uuid.IdUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.sql.Time;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static pc.exam.pp.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
import static pc.exam.pp.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
@@ -456,6 +464,70 @@ public class EducationPaperServiceImpl implements IEducationPaperService
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void downloadWord(String[] paperIds, HttpServletResponse response) throws Exception {
|
||||||
|
|
||||||
|
String paperId1 = paperIds[0];
|
||||||
|
EducationPaper educationPaper = educationPaperMapper.selectEducationPaperByPaperId(paperId1);
|
||||||
|
String taskId = educationPaper.getTaskId();
|
||||||
|
EducationPaperParam educationPaperParam = educationPaperParamMapper.selectEducationPaperParamByTaskId(taskId);
|
||||||
|
List<EducationPaperScheme> educationPaperSchemes = educationPaperSchemeMapper.selectEducationPaperTaskByTaskId(taskId);
|
||||||
|
|
||||||
|
String[] chineseNumbers = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十","十一","十二","十三","十四","十五","十六","十七","十八","十九","二十"};
|
||||||
|
|
||||||
|
for (int i = 0; i < educationPaperSchemes.size(); i++) {
|
||||||
|
if (i < chineseNumbers.length) {
|
||||||
|
educationPaperSchemes.get(i).setUpperCase((chineseNumbers[i]));
|
||||||
|
} else {
|
||||||
|
// 超过十个后可以追加逻辑,比如用“第十一”、“第十二”……
|
||||||
|
educationPaperSchemes.get(i).setUpperCase("第" + (i + 1) + "项");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//获取模板文档
|
||||||
|
String wordpath="/word/试卷1.docx";
|
||||||
|
String homeDir = System.getProperty("user.dir");
|
||||||
|
String wordrealpath=homeDir +wordpath;
|
||||||
|
File realPath = new File(wordrealpath);
|
||||||
|
//准备数据
|
||||||
|
Map<String,Object> params =new HashMap<>();
|
||||||
|
|
||||||
|
params.put("paperNum",educationPaper.getNum());
|
||||||
|
//获得考试时常
|
||||||
|
Time time = educationPaperParam.getExamTime();
|
||||||
|
int hours = time.getHours();
|
||||||
|
int minutes = time.getMinutes();
|
||||||
|
int totalMinutes = hours * 60 + minutes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
params.put("paperTime",totalMinutes);
|
||||||
|
params.put("paperScore",educationPaper.getPaperScore());
|
||||||
|
params.put("Schemes",educationPaperSchemes);
|
||||||
|
XWPFDocument word = WordExportUtil.exportWord07(realPath.getPath(),params);
|
||||||
|
System.out.println("wordxwpdf"+word);
|
||||||
|
String filename = educationPaper.getNum()+".docx";
|
||||||
|
|
||||||
|
response.setHeader("Content-disposition","attachment;filename:"+new String(filename.getBytes(),"UTF-8"));
|
||||||
|
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
System.out.println("文件"+filename);
|
||||||
|
word.write(response.getOutputStream());
|
||||||
|
|
||||||
|
}catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.out.println("错误"+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PaperIdAndNum> selectPaperIdAndNumByTaskId(String taskId) {
|
||||||
|
return educationPaperMapper.selectPaperIdAndNumByTaskId(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
package pc.exam.pp.module.exam.service.paper;
|
package pc.exam.pp.module.exam.service.paper;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import pc.exam.pp.framework.common.pojo.PageResult;
|
import pc.exam.pp.framework.common.pojo.PageResult;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.dto.EducationPaperStuDto;
|
import pc.exam.pp.module.exam.controller.admin.paper.dto.EducationPaperStuDto;
|
||||||
|
import pc.exam.pp.module.exam.controller.admin.paper.dto.PaperIdAndNum;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.ExamPaperVo;
|
import pc.exam.pp.module.exam.controller.admin.paper.vo.ExamPaperVo;
|
||||||
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperPageVo;
|
import pc.exam.pp.module.exam.controller.admin.paper.vo.PaperPageVo;
|
||||||
import pc.exam.pp.module.exam.dal.dataobject.PaperListResponseVo;
|
import pc.exam.pp.module.exam.dal.dataobject.PaperListResponseVo;
|
||||||
import pc.exam.pp.module.exam.dal.dataobject.EducationPaper;
|
import pc.exam.pp.module.exam.dal.dataobject.EducationPaper;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 试卷Service接口
|
* 试卷Service接口
|
||||||
@@ -92,5 +96,11 @@ public interface IEducationPaperService
|
|||||||
PageResult<EducationPaperStuDto> selectStuEducationPaperList(PaperPageVo paperPageVo);
|
PageResult<EducationPaperStuDto> selectStuEducationPaperList(PaperPageVo paperPageVo);
|
||||||
|
|
||||||
ExamPaperVo stuInfoPaper(String taskid);
|
ExamPaperVo stuInfoPaper(String taskid);
|
||||||
|
|
||||||
|
void downloadWord(String[] paperIds, HttpServletResponse response) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
|
List<PaperIdAndNum> selectPaperIdAndNumByTaskId(String taskId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,11 @@
|
|||||||
<result property="tenantId" column="tenant_id" />
|
<result property="tenantId" column="tenant_id" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
|
<resultMap type="EducationPaper" id="PaperIdAndNumResult">
|
||||||
|
<result property="paperId" column="paper_id" />
|
||||||
|
<result property="num" column="num" />
|
||||||
|
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
<resultMap type="ExamQuestion" id="ExamQuestionResult">
|
<resultMap type="ExamQuestion" id="ExamQuestionResult">
|
||||||
<result property="quId" column="qu_id" />
|
<result property="quId" column="qu_id" />
|
||||||
@@ -119,6 +124,9 @@ select task_id from education_paper where paper_id=#{paperId}
|
|||||||
<select id="selectCountPaperList" resultType="java.lang.Integer">
|
<select id="selectCountPaperList" resultType="java.lang.Integer">
|
||||||
select count(*) from education_paper
|
select count(*) from education_paper
|
||||||
</select>
|
</select>
|
||||||
|
<select id="selectPaperIdAndNumByTaskId" resultMap="PaperIdAndNumResult">
|
||||||
|
select paper_id ,num from education_paper where task_id=#{taskId} and deleted ='0'
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<insert id="insertEducationPaper" parameterType="EducationPaper">
|
<insert id="insertEducationPaper" parameterType="EducationPaper">
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
where scheme_id = #{schemeId}
|
where scheme_id = #{schemeId}
|
||||||
</select>
|
</select>
|
||||||
<select id="selectEducationPaperTaskByTaskId" resultMap="EducationPaperSchemeResult">
|
<select id="selectEducationPaperTaskByTaskId" resultMap="EducationPaperSchemeResult">
|
||||||
select * from education_paper_scheme where task_id =#{taskid}
|
select * from education_paper_scheme where task_id =#{taskid} order by sort asc
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<insert id="insertEducationPaperScheme" parameterType="EducationPaperScheme">
|
<insert id="insertEducationPaperScheme" parameterType="EducationPaperScheme">
|
||||||
|
|||||||
@@ -75,4 +75,11 @@ public class WordController {
|
|||||||
return success(BeanUtils.toBean(word, WordRespVO.class));
|
return success(BeanUtils.toBean(word, WordRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/listInfo")
|
||||||
|
@Operation(summary = "获取wps_word子数据列表")
|
||||||
|
public CommonResult<List<WordRespVO>> getWordInfoList(WordListReqVO reqVO) {
|
||||||
|
List<WpsWordLinkDO> list = wpsWordLinkService.getWordInfoList(reqVO);
|
||||||
|
return success(BeanUtils.toBean(list, WordRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
import pc.exam.pp.framework.common.pojo.CommonResult;
|
import pc.exam.pp.framework.common.pojo.CommonResult;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordJudgementDto;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordReqDto;
|
||||||
import pc.exam.pp.module.judgement.service.wps_excel.JudgementWpsExcelService;
|
import pc.exam.pp.module.judgement.service.wps_excel.JudgementWpsExcelService;
|
||||||
import pc.exam.pp.module.judgement.service.wps_pptx.JudgementWpsPptxService;
|
import pc.exam.pp.module.judgement.service.wps_pptx.JudgementWpsPptxService;
|
||||||
import pc.exam.pp.module.judgement.service.wps_word.JudgementWpsWordService;
|
import pc.exam.pp.module.judgement.service.wps_word.JudgementWpsWordService;
|
||||||
@@ -16,6 +16,7 @@ import pc.exam.pp.module.judgement.utils.wps_excel.vo.xlsx_all.XlsxAllDataReqVo;
|
|||||||
import pc.exam.pp.module.judgement.utils.wps_excel.vo.xlsx_drawing.XlsxInfoVo;
|
import pc.exam.pp.module.judgement.utils.wps_excel.vo.xlsx_drawing.XlsxInfoVo;
|
||||||
import pc.exam.pp.module.judgement.utils.wps_excel.vo.xlsx_style.XlsxStyleVO;
|
import pc.exam.pp.module.judgement.utils.wps_excel.vo.xlsx_style.XlsxStyleVO;
|
||||||
import pc.exam.pp.module.judgement.utils.wps_pptx.vo.PptxVO;
|
import pc.exam.pp.module.judgement.utils.wps_pptx.vo.PptxVO;
|
||||||
|
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordInfoReqVo;
|
||||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -28,7 +29,7 @@ import java.util.List;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/tool/wps")
|
@RequestMapping("/tool/wps")
|
||||||
@Tag( name = "wps相关操作")
|
@Tag( name = "测试判分 - wps相关操作")
|
||||||
@Validated
|
@Validated
|
||||||
public class WpsController {
|
public class WpsController {
|
||||||
|
|
||||||
@@ -42,25 +43,26 @@ public class WpsController {
|
|||||||
* wps word
|
* wps word
|
||||||
* @return 判分
|
* @return 判分
|
||||||
*/
|
*/
|
||||||
@GetMapping("/run_wps_word")
|
@PostMapping("/runWpsWordInfo")
|
||||||
public CommonResult<List<WordVO>> run_wps_word(String path) throws Exception {
|
public CommonResult<List<WpsWordJudgementDto>> runWpsWordInfo(@RequestBody List<WpsWordReqDto> wordReqDto) throws Exception {
|
||||||
return CommonResult.success(judgementWpsWordService.programmingWpsWord(path));
|
return CommonResult.success(judgementWpsWordService.programmingInfo(wordReqDto));
|
||||||
}
|
|
||||||
/**
|
|
||||||
* wps pptx
|
|
||||||
* @return 判分
|
|
||||||
*/
|
|
||||||
@GetMapping("/run_wps_pptx")
|
|
||||||
public CommonResult<List<PptxVO>> run_wps_pptx(String path) throws Exception {
|
|
||||||
return CommonResult.success(judgementWpsPptxService.programmingWpsPptx(path));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* wps xlsx
|
|
||||||
* @return 判分
|
|
||||||
*/
|
|
||||||
@GetMapping("/run_wps_xlsx")
|
|
||||||
public CommonResult<List<XlsxInfoVo>> run_wps_xlsx(String path) throws Exception {
|
|
||||||
return CommonResult.success(judgementWpsExcelService.programmingWpsExcel(path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wps word
|
||||||
|
* @return 判分
|
||||||
|
*/
|
||||||
|
@GetMapping("/runWpsWord")
|
||||||
|
public CommonResult<List<WordInfoReqVo>> runWpsWord(String path) throws Exception {
|
||||||
|
return CommonResult.success(judgementWpsWordService.programmingWpsWord(path));
|
||||||
|
}
|
||||||
|
// /**
|
||||||
|
// * wps xlsx
|
||||||
|
// * @return 判分
|
||||||
|
// */
|
||||||
|
// @GetMapping("/run_wps_xlsx")
|
||||||
|
// public CommonResult<List<XlsxInfoVo>> run_wps_xlsx(String path) throws Exception {
|
||||||
|
// return CommonResult.success(judgementWpsExcelService.programmingWpsExcel(path));
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package pc.exam.pp.module.judgement.controller.admin.Wps.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author REN
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class WpsWordChineseFunctionDto {
|
||||||
|
|
||||||
|
private String chineseName;
|
||||||
|
private String function;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package pc.exam.pp.module.judgement.controller.admin.Wps.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author REN
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class WpsWordJudgementDto {
|
||||||
|
private String function;
|
||||||
|
private String contentIn;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package pc.exam.pp.module.judgement.controller.admin.Wps.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author REN
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class WpsWordReqDto {
|
||||||
|
|
||||||
|
private String chineseName;
|
||||||
|
private String englishName;
|
||||||
|
private String filePath;
|
||||||
|
private String type;
|
||||||
|
private List<WpsWordChineseFunctionDto> function;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,5 +17,7 @@ public class WordListReqVO {
|
|||||||
*/
|
*/
|
||||||
private Integer type;
|
private Integer type;
|
||||||
|
|
||||||
|
private String nodeFunction;
|
||||||
|
|
||||||
private Integer belongTo;
|
private Integer belongTo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ import pc.exam.pp.module.judgement.service.wps_word.JudgementWpsWordService;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author REN
|
||||||
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/tool")
|
@RequestMapping("/tool")
|
||||||
@Tag( name = "测试判分")
|
@Tag( name = "测试判分")
|
||||||
@@ -53,7 +56,7 @@ public class AutoToolsController {
|
|||||||
@GetMapping("/getTest")
|
@GetMapping("/getTest")
|
||||||
public double gets(StuPaperReqVo stuPaperReqVo) throws Exception {
|
public double gets(StuPaperReqVo stuPaperReqVo) throws Exception {
|
||||||
ExamQuestion examQuestion = examQuestionService.selectExamQuestionByQuId(stuPaperReqVo.getPaperId());
|
ExamQuestion examQuestion = examQuestionService.selectExamQuestionByQuId(stuPaperReqVo.getPaperId());
|
||||||
return judgementWpsWordService.judgementWpsWord(15.0, "D:\\", "D:\\文档.docx", examQuestion);
|
return judgementWpsWordService.judgementWpsWord(15.0, "D:\\", "D:\\stu\\wps_word\\9f7d8f5d7c68cc2bfd03a23c19045efe7ba13a4bebeb833abece146908bcd0c6.docx", examQuestion);
|
||||||
}
|
}
|
||||||
@GetMapping("/getTests")
|
@GetMapping("/getTests")
|
||||||
public double getss(StuPaperReqVo stuPaperReqVo) throws Exception {
|
public double getss(StuPaperReqVo stuPaperReqVo) throws Exception {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public interface WpsWordLinkMapper extends BaseMapperX<WpsWordLinkDO> {
|
|||||||
return selectList(new LambdaQueryWrapperX<WpsWordLinkDO>()
|
return selectList(new LambdaQueryWrapperX<WpsWordLinkDO>()
|
||||||
.likeIfPresent(WpsWordLinkDO::getName, reqVO.getName())
|
.likeIfPresent(WpsWordLinkDO::getName, reqVO.getName())
|
||||||
.eq(reqVO.getBelongTo() != null, WpsWordLinkDO::getBelongTo, reqVO.getBelongTo())
|
.eq(reqVO.getBelongTo() != null, WpsWordLinkDO::getBelongTo, reqVO.getBelongTo())
|
||||||
|
.eq(reqVO.getNodeFunction() != null, WpsWordLinkDO::getNodeFunction, reqVO.getNodeFunction())
|
||||||
.eqIfPresent(WpsWordLinkDO::getStatus, reqVO.getStatus()));
|
.eqIfPresent(WpsWordLinkDO::getStatus, reqVO.getStatus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +25,15 @@ public interface WpsWordLinkMapper extends BaseMapperX<WpsWordLinkDO> {
|
|||||||
return selectOne(WpsWordLinkDO::getParentId, parentId, WpsWordLinkDO::getName, name);
|
return selectOne(WpsWordLinkDO::getParentId, parentId, WpsWordLinkDO::getName, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default WpsWordLinkDO selectByNodeFunction(String nodeFunction) {
|
||||||
|
return selectOne(WpsWordLinkDO::getNodeFunction, nodeFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
default List<WpsWordLinkDO> selectInfoList(Long id) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<WpsWordLinkDO>()
|
||||||
|
.eqIfPresent(WpsWordLinkDO::getParentId, id));
|
||||||
|
}
|
||||||
|
|
||||||
default Long selectCountByParentId(Long parentId) {
|
default Long selectCountByParentId(Long parentId) {
|
||||||
return selectCount(WpsWordLinkDO::getParentId, parentId);
|
return selectCount(WpsWordLinkDO::getParentId, parentId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class JudgementServiceImpl implements JudgementService
|
|||||||
// 如果使用程序编译,进行程序编译
|
// 如果使用程序编译,进行程序编译
|
||||||
LogFileUtils.writeLine("✅ 正在使用-std=c99进行编译...");
|
LogFileUtils.writeLine("✅ 正在使用-std=c99进行编译...");
|
||||||
// 使用C99 运行并得出结果
|
// 使用C99 运行并得出结果
|
||||||
String code_return = JudgementCUtils.run_code(code,null,"-std=c99", "编译通过运行");
|
String code_return = JudgementCUtils.run_code(pathC,code,null,"-std=c99", "编译通过运行");
|
||||||
if (!code_return.contains("error")) {
|
if (!code_return.contains("error")) {
|
||||||
// 编译没有报错,加上编译分数
|
// 编译没有报错,加上编译分数
|
||||||
totalScore += pass_score;
|
totalScore += pass_score;
|
||||||
@@ -133,7 +133,7 @@ public class JudgementServiceImpl implements JudgementService
|
|||||||
LogFileUtils.writeLine("✅ 使用测试用例进行判分...");
|
LogFileUtils.writeLine("✅ 使用测试用例进行判分...");
|
||||||
for (ExamQuestionAnswer examQuestionAnswer : examQuestion.getAnswerList()) {
|
for (ExamQuestionAnswer examQuestionAnswer : examQuestion.getAnswerList()) {
|
||||||
// 使用C99 运行并得出结果
|
// 使用C99 运行并得出结果
|
||||||
String code_return = JudgementCUtils.run_code(code, examQuestionAnswer.getContentIn(),"-std=c99",null);
|
String code_return = JudgementCUtils.run_code(pathC,code, examQuestionAnswer.getContentIn(),"-std=c99",null);
|
||||||
String actual = code_return.trim();
|
String actual = code_return.trim();
|
||||||
String expected = examQuestionAnswer.getContent().trim();
|
String expected = examQuestionAnswer.getContent().trim();
|
||||||
if (actual.equals(expected)) {
|
if (actual.equals(expected)) {
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package pc.exam.pp.module.judgement.service.wps_word;
|
|||||||
|
|
||||||
|
|
||||||
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestion;
|
import pc.exam.pp.module.exam.dal.dataobject.ExamQuestion;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordJudgementDto;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordReqDto;
|
||||||
|
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordInfoReqVo;
|
||||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -21,8 +24,9 @@ public interface JudgementWpsWordService {
|
|||||||
* @return 文件内得考点及描述
|
* @return 文件内得考点及描述
|
||||||
* @throws Exception 异常
|
* @throws Exception 异常
|
||||||
*/
|
*/
|
||||||
List<WordVO> programmingWpsWord(String path) throws Exception;
|
List<WordInfoReqVo> programmingWpsWord(String path) throws Exception;
|
||||||
|
|
||||||
|
List<WpsWordJudgementDto> programmingInfo(List<WpsWordReqDto> wpsWordReqDtos) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,14 +9,19 @@ import pc.exam.pp.module.exam.dal.dataobject.ExamQuestionAnswer;
|
|||||||
import pc.exam.pp.module.exam.utils.file.LogFileUtils;
|
import pc.exam.pp.module.exam.utils.file.LogFileUtils;
|
||||||
import pc.exam.pp.module.infra.dal.dataobject.config.ConfigDO;
|
import pc.exam.pp.module.infra.dal.dataobject.config.ConfigDO;
|
||||||
import pc.exam.pp.module.infra.service.config.ConfigService;
|
import pc.exam.pp.module.infra.service.config.ConfigService;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordChineseFunctionDto;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordJudgementDto;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordReqDto;
|
||||||
import pc.exam.pp.module.judgement.controller.admin.Wps.vo.WordListReqVO;
|
import pc.exam.pp.module.judgement.controller.admin.Wps.vo.WordListReqVO;
|
||||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||||
import pc.exam.pp.module.judgement.dal.mysql.wpsword.WpsWordLinkMapper;
|
import pc.exam.pp.module.judgement.dal.mysql.wpsword.WpsWordLinkMapper;
|
||||||
import pc.exam.pp.module.judgement.service.auto_tools.AutoToolsService;
|
import pc.exam.pp.module.judgement.service.auto_tools.AutoToolsService;
|
||||||
import pc.exam.pp.module.judgement.utils.wps_word.WpsWordUtils;
|
import pc.exam.pp.module.judgement.utils.wps_word.WpsWordUtils;
|
||||||
|
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordInfoReqVo;
|
||||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -32,61 +37,82 @@ public class JudgementWpsWordServiceImpl implements JudgementWpsWordService {
|
|||||||
ConfigService configService;
|
ConfigService configService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<WordVO> programmingWpsWord(String path) throws Exception {
|
public List<WordInfoReqVo> programmingWpsWord(String path) throws Exception {
|
||||||
|
|
||||||
// 1、获取文件临时下载路径
|
// 1、获取文件临时下载路径
|
||||||
ConfigDO config = configService.getConfigByKey("file_down_path");
|
ConfigDO config = configService.getConfigByKey("file_down_wps_word_path");
|
||||||
// 2、下载文件并返回文件完整路径
|
// 2、下载文件并返回文件完整路径
|
||||||
String pathName = autoToolsService.downloadStudentFile(path, config.getValue());
|
String pathName = autoToolsService.downloadStudentFile(path, config.getValue());
|
||||||
// 3、创建word考点tree
|
// 3、创建word考点tree
|
||||||
WordListReqVO wordListReqVO = new WordListReqVO();
|
// WordListReqVO wordListReqVO = new WordListReqVO();
|
||||||
wordListReqVO.setBelongTo(0);
|
// wordListReqVO.setBelongTo(0);
|
||||||
// 3-1、查询段落的标签
|
// // 3-1、查询段落的标签
|
||||||
List<WpsWordLinkDO> paragraphList = wpsWordLinkMapper.selectList(wordListReqVO);
|
// List<WpsWordLinkDO> paragraphList = wpsWordLinkMapper.selectList(wordListReqVO);
|
||||||
// 3-2、查询锚点的标签
|
// // 3-2、查询锚点的标签
|
||||||
wordListReqVO.setBelongTo(3);
|
// wordListReqVO.setBelongTo(3);
|
||||||
List<WpsWordLinkDO> anchorList = wpsWordLinkMapper.selectList(wordListReqVO);
|
// List<WpsWordLinkDO> anchorList = wpsWordLinkMapper.selectList(wordListReqVO);
|
||||||
// 4、docx文件读取并返回考点及说明信息
|
// 4、docx文件读取并返回考点及说明信息
|
||||||
List<WordVO> margins = WpsWordUtils.wps_word(pathName, paragraphList, anchorList);
|
List<WordInfoReqVo> margins = WpsWordUtils.wpWord(pathName);
|
||||||
// 5、已经读取完得考点删除源文件
|
// 5、已经读取完得考点删除源文件
|
||||||
File file = new File(pathName);
|
// File file = new File(pathName);
|
||||||
file.delete();
|
// file.delete();
|
||||||
return margins;
|
return margins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<WpsWordJudgementDto> programmingInfo(List<WpsWordReqDto> wordReqDto) throws Exception {
|
||||||
|
// List<WpsWordChineseFunctionDto> functionList = new ArrayList<>();
|
||||||
|
// for (String function : wordReqDto.getFunction()) {
|
||||||
|
// WpsWordChineseFunctionDto functionDto = new WpsWordChineseFunctionDto();
|
||||||
|
// functionDto.setFunction(function);
|
||||||
|
// WpsWordLinkDO wpsWordLinkDO = wpsWordLinkMapper.selectByNodeFunction(function);
|
||||||
|
// functionDto.setChineseName(wpsWordLinkDO.getToChinese());
|
||||||
|
// functionList.add(functionDto);
|
||||||
|
// }
|
||||||
|
List<WpsWordJudgementDto> judgementDtos = WpsWordUtils.getWordInfo(wordReqDto);
|
||||||
|
return judgementDtos;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double judgementWpsWord(double sorce, String pathC, String path, ExamQuestion examQuestion) throws Exception {
|
public double judgementWpsWord(double sorce, String pathC, String path, ExamQuestion examQuestion) throws Exception {
|
||||||
// 创建log文件txt,用于记录
|
// 创建log文件txt,用于记录
|
||||||
File pathCDir = new File(pathC);
|
LogFileUtils.createFile(pathC + "/WPS_Word判分过程.txt");
|
||||||
File parentDir = pathCDir.getParentFile();
|
|
||||||
|
|
||||||
// 拼接同级目录下的目标文件路径
|
|
||||||
String targetFilePath = new File(parentDir, "WPS_Word判分过程.txt").getPath();
|
|
||||||
LogFileUtils.createFile(targetFilePath);
|
|
||||||
LogFileUtils.writeLine("✅ 开始WPS_Word判分");
|
LogFileUtils.writeLine("✅ 开始WPS_Word判分");
|
||||||
double wps_word_sorce = 0;
|
double wps_word_sorce = 0;
|
||||||
// 1、查询Word考点tree
|
|
||||||
WordListReqVO wordListReqVO = new WordListReqVO();
|
|
||||||
wordListReqVO.setBelongTo(0);
|
|
||||||
// 3-1、查询段落的标签
|
|
||||||
List<WpsWordLinkDO> paragraphList = wpsWordLinkMapper.selectList(wordListReqVO);
|
|
||||||
// 3-2、查询锚点的标签
|
|
||||||
wordListReqVO.setBelongTo(3);
|
|
||||||
List<WpsWordLinkDO> anchorList = wpsWordLinkMapper.selectList(wordListReqVO);
|
|
||||||
// 2、docx文件读取并返回考点及说明信息
|
// 2、docx文件读取并返回考点及说明信息
|
||||||
List<WordVO> margins = WpsWordUtils.wps_word(path, paragraphList, anchorList);
|
// List<WordVO> margins = WpsWordUtils.wps_word(path);
|
||||||
// 3、获取答案得组成
|
// 3、获取答案得组成
|
||||||
List<ExamQuestionAnswer> answerList = examQuestion.getAnswerList();
|
List<ExamQuestionAnswer> answerList = examQuestion.getAnswerList();
|
||||||
// 4、进行关联判断
|
// 4、进行关联判断
|
||||||
for (ExamQuestionAnswer examQuestionAnswer : answerList) {
|
for (ExamQuestionAnswer examQuestionAnswer : answerList) {
|
||||||
|
// 拆分数据、
|
||||||
|
String[] wordInfos = examQuestionAnswer.getContent().split("-/");
|
||||||
|
String[] chineseName = examQuestionAnswer.getContentIn().split("-");
|
||||||
|
// 创建拼接数据
|
||||||
|
// 只取三层结构
|
||||||
|
List<WpsWordReqDto> wordReqDto = new ArrayList<>();
|
||||||
|
WpsWordReqDto wpsWordReqDto = new WpsWordReqDto();
|
||||||
|
wpsWordReqDto.setChineseName(chineseName[0]);
|
||||||
|
wpsWordReqDto.setEnglishName(wordInfos[0]);
|
||||||
|
wpsWordReqDto.setType(wordInfos[0]);
|
||||||
|
wpsWordReqDto.setFilePath(path);
|
||||||
|
List<WpsWordChineseFunctionDto> functionList = new ArrayList<>();
|
||||||
|
for (int i = 1; i < 3; i++) {
|
||||||
|
WpsWordChineseFunctionDto functionDto = new WpsWordChineseFunctionDto();
|
||||||
|
functionDto.setFunction("/" + wordInfos[i]);
|
||||||
|
functionDto.setChineseName(chineseName[i]);
|
||||||
|
functionList.add(functionDto);
|
||||||
|
}
|
||||||
|
wpsWordReqDto.setFunction(functionList);
|
||||||
|
wordReqDto.add(wpsWordReqDto);
|
||||||
|
List<WpsWordJudgementDto> judgementDtos = WpsWordUtils.getWordInfo(wordReqDto);
|
||||||
boolean flag = false;
|
boolean flag = false;
|
||||||
double one_sorce = 0;
|
double one_sorce = 0;
|
||||||
for (WordVO wordVO : margins) {
|
for (WpsWordJudgementDto wordJudgementDto : judgementDtos) {
|
||||||
if (wordVO.getExamKeynote() != null) {
|
if (wordJudgementDto.getFunction() != null) {
|
||||||
|
// for (String str : wordJudgementDto.getFunction()) {
|
||||||
for (String str : wordVO.getExamKeynote()) {
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
if ((index+str).equals(examQuestionAnswer.getContent())) {
|
if (wordJudgementDto.getFunction().equals(examQuestionAnswer.getContent())) {
|
||||||
flag = true;
|
flag = true;
|
||||||
|
|
||||||
// 得分 根据权重进行得分 每个选项分值 = 总分 / 总权重
|
// 得分 根据权重进行得分 每个选项分值 = 总分 / 总权重
|
||||||
@@ -98,7 +124,7 @@ public class JudgementWpsWordServiceImpl implements JudgementWpsWordService {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wps_word_sorce += one_sorce;
|
wps_word_sorce += one_sorce;
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ public interface WpsWordLinkService {
|
|||||||
*/
|
*/
|
||||||
List<WpsWordLinkDO> getWordList(WordListReqVO reqVO);
|
List<WpsWordLinkDO> getWordList(WordListReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 筛选节点列表
|
||||||
|
*
|
||||||
|
* @param reqVO 筛选条件请求 VO
|
||||||
|
* @return 节点列表
|
||||||
|
*/
|
||||||
|
List<WpsWordLinkDO> getWordInfoList(WordListReqVO reqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得指定编号的节点 Map
|
* 获得指定编号的节点 Map
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -170,6 +170,27 @@ public class WpsWordLinkServiceImpl implements WpsWordLinkService {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<WpsWordLinkDO> getWordInfoList(WordListReqVO reqVO) {
|
||||||
|
List<WpsWordLinkDO> wordList = new ArrayList<>();
|
||||||
|
WpsWordLinkDO data = wpsWordLinkMapper.selectByNodeFunction(reqVO.getNodeFunction());
|
||||||
|
if (data == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<WpsWordLinkDO> wpsWordLinkDOS = wpsWordLinkMapper.selectInfoList(data.getId());
|
||||||
|
// 在依次判断是否还有子数据
|
||||||
|
for (WpsWordLinkDO wpsWordLinkDO : wpsWordLinkDOS) {
|
||||||
|
wordList.add(wpsWordLinkDO);
|
||||||
|
List<WpsWordLinkDO> datas = wpsWordLinkMapper.selectInfoList(wpsWordLinkDO.getId());
|
||||||
|
if (datas != null) {
|
||||||
|
for (WpsWordLinkDO wpsWordLinkDO1 : datas) {
|
||||||
|
wordList.add(wpsWordLinkDO1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wordList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<WpsWordLinkDO> getChildWordList(Collection<Long> ids) {
|
public List<WpsWordLinkDO> getChildWordList(Collection<Long> ids) {
|
||||||
List<WpsWordLinkDO> children = new LinkedList<>();
|
List<WpsWordLinkDO> children = new LinkedList<>();
|
||||||
|
|||||||
@@ -66,18 +66,20 @@ public class JudgementCUtils
|
|||||||
* @param standard 编译版本 C99
|
* @param standard 编译版本 C99
|
||||||
* @return 运行结果
|
* @return 运行结果
|
||||||
*/
|
*/
|
||||||
public static String run_code(String code, String input, String standard, String text) {
|
public static String run_code(String pathC, String code, String input, String standard, String text) {
|
||||||
try {
|
try {
|
||||||
boolean hasInput = code.contains("scanf") || code.contains("fgets") || code.contains("getchar");
|
boolean hasInput = code.contains("scanf") || code.contains("fgets") || code.contains("getchar");
|
||||||
System.out.println(System.getenv("PATH"));
|
System.out.println(System.getenv("PATH"));
|
||||||
|
String programC = pathC + "/program.c";
|
||||||
|
String programOut = pathC + "/program.out";
|
||||||
// 写入 C 源码到文件
|
// 写入 C 源码到文件
|
||||||
File file = new File("program.c");
|
File file = new File(programC);
|
||||||
try (FileWriter writer = new FileWriter(file)) {
|
try (FileWriter writer = new FileWriter(file)) {
|
||||||
writer.write(code);
|
writer.write(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 编译代码
|
// 编译代码
|
||||||
ProcessBuilder compileBuilder = new ProcessBuilder("gcc", standard, "program.c", "-o", "program.out");
|
ProcessBuilder compileBuilder = new ProcessBuilder("gcc", standard, programC, "-o", programOut);
|
||||||
compileBuilder.redirectErrorStream(true);
|
compileBuilder.redirectErrorStream(true);
|
||||||
Process compileProcess = compileBuilder.start();
|
Process compileProcess = compileBuilder.start();
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@ public class JudgementCUtils
|
|||||||
|
|
||||||
int compileResult = compileProcess.waitFor();
|
int compileResult = compileProcess.waitFor();
|
||||||
String outputLower = compileOutput.toString().toLowerCase();
|
String outputLower = compileOutput.toString().toLowerCase();
|
||||||
if (outputLower.contains("error:") || !Files.exists(Paths.get("program.out"))) {
|
if (outputLower.contains("error:") || !Files.exists(Paths.get(programOut))) {
|
||||||
// LogFileUtils.writeLine("❌ 编译失败:");
|
// LogFileUtils.writeLine("❌ 编译失败:");
|
||||||
// LogFileUtils.writeLine(compileOutput.toString());
|
// LogFileUtils.writeLine(compileOutput.toString());
|
||||||
return "编译失败,输出:\n" + compileOutput.toString();
|
return "编译失败,输出:\n" + compileOutput.toString();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package pc.exam.pp.module.judgement.utils.tree;
|
|||||||
import pc.exam.pp.module.judgement.dal.dataobject.wpspptx.WpsPptxLinkDO;
|
import pc.exam.pp.module.judgement.dal.dataobject.wpspptx.WpsPptxLinkDO;
|
||||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsxlsx.WpsXlsxLinkDO;
|
import pc.exam.pp.module.judgement.dal.dataobject.wpsxlsx.WpsXlsxLinkDO;
|
||||||
|
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordInfoReqVo;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -11,6 +12,28 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class TreeUtils {
|
public class TreeUtils {
|
||||||
|
|
||||||
|
// public static List<WordInfoReqVo> buildTreeWordInfo(List<WordInfoReqVo> flatList) {
|
||||||
|
// Map<Integer, WordInfoReqVo> nodeMap = new HashMap<>();
|
||||||
|
// List<WordInfoReqVo> roots = new ArrayList<>();
|
||||||
|
// // 先放入 map
|
||||||
|
// for (WordInfoReqVo node : flatList) {
|
||||||
|
// nodeMap.put(Math.toIntExact(node.getId()), node);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 构建树关系
|
||||||
|
// for (WordInfoReqVo node : flatList) {
|
||||||
|
// if (node.getParentId() == 0) {
|
||||||
|
// roots.add(node);
|
||||||
|
// } else {
|
||||||
|
// WordInfoReqVo parent = nodeMap.get(node.getParentId().intValue());
|
||||||
|
// if (parent != null) {
|
||||||
|
// parent.getChildren().add(node);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return roots;
|
||||||
|
// }
|
||||||
|
|
||||||
public static List<WpsWordLinkDO> buildTree(List<WpsWordLinkDO> flatList) {
|
public static List<WpsWordLinkDO> buildTree(List<WpsWordLinkDO> flatList) {
|
||||||
Map<Integer, WpsWordLinkDO> nodeMap = new HashMap<>();
|
Map<Integer, WpsWordLinkDO> nodeMap = new HashMap<>();
|
||||||
List<WpsWordLinkDO> roots = new ArrayList<>();
|
List<WpsWordLinkDO> roots = new ArrayList<>();
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package pc.exam.pp.module.judgement.utils.wps_word;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public class WpsWordNameSpaces {
|
||||||
|
|
||||||
|
public static String getNameSpace(String xmlString) {
|
||||||
|
// 2、创建最全的命名空间
|
||||||
|
Pattern pattern = Pattern.compile("xmlns:(\\w+)=\"([^\"]+)\"");
|
||||||
|
Matcher matcher = pattern.matcher(xmlString);
|
||||||
|
Map<String, String> namespaces = new HashMap<>();
|
||||||
|
while (matcher.find()) {
|
||||||
|
// 如 w, wp, a
|
||||||
|
String prefix = matcher.group(1);
|
||||||
|
// 如 http://schemas.openxmlformats.org/...
|
||||||
|
String uri = matcher.group(2);
|
||||||
|
namespaces.put(prefix, uri);
|
||||||
|
}
|
||||||
|
StringBuilder xpathBuilder = new StringBuilder();
|
||||||
|
namespaces.forEach((prefix, uri) ->
|
||||||
|
xpathBuilder.append("declare namespace ")
|
||||||
|
.append(prefix)
|
||||||
|
.append("='")
|
||||||
|
.append(uri)
|
||||||
|
.append("' ")
|
||||||
|
);
|
||||||
|
// 2-1、获取出来最全的命名空间
|
||||||
|
String allPathx = xpathBuilder.toString();
|
||||||
|
return allPathx;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,272 @@
|
|||||||
package pc.exam.pp.module.judgement.utils.wps_word;
|
package pc.exam.pp.module.judgement.utils.wps_word;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.apache.poi.xwpf.usermodel.*;
|
import org.apache.poi.xwpf.usermodel.*;
|
||||||
import org.apache.xmlbeans.XmlCursor;
|
import org.apache.xmlbeans.XmlCursor;
|
||||||
import org.apache.xmlbeans.XmlObject;
|
import org.apache.xmlbeans.XmlObject;
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
|
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordChineseFunctionDto;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordJudgementDto;
|
||||||
|
import pc.exam.pp.module.judgement.controller.admin.Wps.dto.WpsWordReqDto;
|
||||||
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||||
import pc.exam.pp.module.judgement.utils.tree.TreeUtils;
|
import pc.exam.pp.module.judgement.utils.wps_word.vo.*;
|
||||||
import pc.exam.pp.module.judgement.utils.wps_word.vo.WordVO;
|
import pc.exam.pp.module.judgement.utils.zipfile.ZipXmlUtils;
|
||||||
|
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author REN
|
||||||
|
*/
|
||||||
public class WpsWordUtils {
|
public class WpsWordUtils {
|
||||||
|
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 List<WpsWordJudgementDto> getWordInfo(List<WpsWordReqDto> wpsWordReqDtos) throws Exception {
|
||||||
|
// 创建返回数组
|
||||||
|
List<WpsWordJudgementDto> judgementList = new ArrayList<>();
|
||||||
|
// 创建文件路径数组
|
||||||
|
List<Map<String, String>> filePathList = new ArrayList<>();
|
||||||
|
for (WpsWordReqDto wpsWordReqDto : wpsWordReqDtos) {
|
||||||
|
try (ZipFile zipFile = new ZipFile(wpsWordReqDto.getFilePath())) {
|
||||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = entries.nextElement();
|
||||||
|
String entryName = entry.getName();
|
||||||
|
if (entryName.startsWith("word/_rels") && entryName.endsWith(".xml.rels")) {
|
||||||
|
String xmlContent = ZipXmlUtils.readZipEntry(zipFile, entryName);
|
||||||
|
XmlObject xmlObject = XmlObject.Factory.parse(xmlContent);
|
||||||
|
XmlCursor cursor = xmlObject.newCursor();
|
||||||
|
cursor.selectPath("declare namespace r='http://schemas.openxmlformats.org/package/2006/relationships' .//r:Relationships/r:Relationship");
|
||||||
|
// 存放数据
|
||||||
|
while (cursor.toNextSelection()) {
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
String rId = cursor.getAttributeText(new QName("Id"));
|
||||||
|
String target = cursor.getAttributeText(new QName("Target"));
|
||||||
|
map.put(rId, target);
|
||||||
|
filePathList.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XWPFDocument document = new XWPFDocument(new FileInputStream(wpsWordReqDto.getFilePath()));
|
||||||
|
XmlObject docXml = document.getDocument();
|
||||||
|
XmlCursor cursor = docXml.newCursor();
|
||||||
|
String nameSpace = WpsWordNameSpaces.getNameSpace(cursor.xmlText());
|
||||||
|
// 需要联合查询数据,查询位置xml来获取准确的文件
|
||||||
|
// 开始查询标签
|
||||||
|
// 1、段落
|
||||||
|
if (wpsWordReqDto.getEnglishName().contains("w:p")) {
|
||||||
|
StringBuilder function = new StringBuilder();
|
||||||
|
StringBuilder functionAll = new StringBuilder();
|
||||||
|
StringBuilder chineseName = new StringBuilder();
|
||||||
|
for (WpsWordChineseFunctionDto functions : wpsWordReqDto.getFunction()) {
|
||||||
|
function.append(functions.getFunction());
|
||||||
|
functionAll.append("-").append(functions.getFunction());
|
||||||
|
chineseName.append(functions.getChineseName()).append("-");
|
||||||
|
}
|
||||||
|
WpsWordJudgementDto judgement = new WpsWordJudgementDto();
|
||||||
|
// 1-1、创建新的数据组
|
||||||
|
XmlCursor wpCursor = cursor.newCursor();
|
||||||
|
wpCursor.selectPath(nameSpace + "(//" + wpsWordReqDto.getEnglishName() + function);
|
||||||
|
if (wpCursor.toNextSelection()) {
|
||||||
|
String value = wpCursor.getTextValue();
|
||||||
|
judgement.setContentIn(wpsWordReqDto.getChineseName() + "-" + chineseName + value);
|
||||||
|
judgement.setFunction(wpsWordReqDto.getEnglishName() + functionAll + "-/" + value);
|
||||||
|
// 查询指定值,返回固定的文本
|
||||||
|
judgementList.add(judgement);
|
||||||
|
} else {
|
||||||
|
System.out.println("没有找到:" + chineseName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<XWPFHeader> headers = document.getHeaderList();
|
||||||
|
List<XWPFFooter> footers = document.getFooterList();
|
||||||
|
// 2、节
|
||||||
|
if (wpsWordReqDto.getType().contains("sectPr")) {
|
||||||
|
// 先要获取ID
|
||||||
|
XmlCursor sectPrCursor = docXml.newCursor();
|
||||||
|
String[] strTypes = new String[]{"/w:headerReference","/w:footerReference"};
|
||||||
|
boolean exists = Arrays.asList(strTypes).contains(wpsWordReqDto.getFunction().get(0).getFunction());
|
||||||
|
if (exists) {
|
||||||
|
sectPrCursor.selectPath(nameSpace + "//" + wpsWordReqDto.getEnglishName() + wpsWordReqDto.getFunction().get(0).getFunction());
|
||||||
|
String rId = "";
|
||||||
|
String type = "";
|
||||||
|
List<WordHeaderFooterVo> headerFooterVos = new ArrayList<>();
|
||||||
|
while (sectPrCursor.toNextSelection()) {
|
||||||
|
rId = sectPrCursor.getAttributeText(new QName("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id"));
|
||||||
|
type = sectPrCursor.getAttributeText(new QName("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "type"));
|
||||||
|
WordHeaderFooterVo headerFooterVo = new WordHeaderFooterVo();
|
||||||
|
headerFooterVo.setRid(rId);
|
||||||
|
headerFooterVo.setType(type);
|
||||||
|
headerFooterVo.setXmlType(wpsWordReqDto.getFunction().get(0).getFunction());
|
||||||
|
headerFooterVos.add(headerFooterVo);
|
||||||
|
}
|
||||||
|
String fileName = "";
|
||||||
|
for (Map<String, String> str : filePathList) {
|
||||||
|
// 页眉页脚
|
||||||
|
for (WordHeaderFooterVo headerVo : headerFooterVos) {
|
||||||
|
if (str.containsKey(headerVo.getRid())) {
|
||||||
|
fileName = str.get(headerVo.getRid());
|
||||||
|
if (headerVo.getXmlType().contains("headerReference")) {
|
||||||
|
for (XWPFHeader header : headers) {
|
||||||
|
if (header.getPackagePart().getPartName().getName().contains(fileName)) {
|
||||||
|
// 2-1、针对不同的进行排查
|
||||||
|
String chineseType = Objects.equals(headerVo.getType(), "default") ? "奇数页" : Objects.equals(headerVo.getType(), "even") ? "偶数页" : "";
|
||||||
|
WpsWordJudgementDto judgement = new WpsWordJudgementDto();
|
||||||
|
List<XWPFParagraph> headerpar = header.getParagraphs();
|
||||||
|
XmlCursor headerXml = headerpar.get(0).getCTP().newCursor();
|
||||||
|
headerXml.selectPath(nameSpace + "./" + wpsWordReqDto.getFunction().get(1).getFunction());
|
||||||
|
if (headerXml.toNextSelection()) {
|
||||||
|
String value = headerXml.getTextValue();
|
||||||
|
judgement.setContentIn(wpsWordReqDto.getChineseName()+"-"+wpsWordReqDto.getFunction().get(0).getChineseName()+ "-"+ chineseType +"-" +wpsWordReqDto.getFunction().get(1).getChineseName()+"-"+value);
|
||||||
|
judgement.setFunction(wpsWordReqDto.getEnglishName()+"-"+wpsWordReqDto.getFunction().get(0).getFunction()+"-" +wpsWordReqDto.getFunction().get(1).getFunction()+"-/"+value+ "-"+ headerVo.getType());
|
||||||
|
judgementList.add(judgement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (headerVo.getXmlType().contains("footerReference")) {
|
||||||
|
for (XWPFFooter footer : footers) {
|
||||||
|
if (footer.getPackagePart().getPartName().getName().contains(fileName)) {
|
||||||
|
// 2-1、针对不同的进行排查
|
||||||
|
String chineseType = Objects.equals(headerVo.getType(), "default") ? "奇数页" : Objects.equals(headerVo.getType(), "even") ? "偶数页" : "";
|
||||||
|
WpsWordJudgementDto judgement = new WpsWordJudgementDto();
|
||||||
|
List<XWPFParagraph> foorerpar = footer.getParagraphs();
|
||||||
|
XmlCursor headerXml = foorerpar.get(0).getCTP().newCursor();
|
||||||
|
headerXml.selectPath(nameSpace + "./" + wpsWordReqDto.getFunction().get(1).getFunction());
|
||||||
|
if (headerXml.toNextSelection()) {
|
||||||
|
String value = headerXml.getTextValue();
|
||||||
|
judgement.setContentIn(wpsWordReqDto.getChineseName()+"-"+wpsWordReqDto.getFunction().get(0).getChineseName()+ "-"+ chineseType +"-" +wpsWordReqDto.getFunction().get(1).getChineseName()+"-"+value);
|
||||||
|
judgement.setFunction(wpsWordReqDto.getEnglishName()+"-"+wpsWordReqDto.getFunction().get(0).getFunction()+"-" +wpsWordReqDto.getFunction().get(1).getFunction()+"-/"+value+ "-"+ headerVo.getType());
|
||||||
|
judgementList.add(judgement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 需要查询主页面的方法
|
||||||
|
XmlCursor sectPrXsml = docXml.newCursor();
|
||||||
|
sectPrXsml.selectPath(nameSpace + "(//" + wpsWordReqDto.getEnglishName() + wpsWordReqDto.getFunction().get(0).getFunction() + wpsWordReqDto.getFunction().get(1).getFunction());
|
||||||
|
if (sectPrXsml.toNextSelection()) {
|
||||||
|
String value = sectPrXsml.getTextValue();
|
||||||
|
WpsWordJudgementDto judgement = new WpsWordJudgementDto();
|
||||||
|
judgement.setContentIn(wpsWordReqDto.getChineseName()+"-"+wpsWordReqDto.getFunction().get(0).getChineseName() +"-" +wpsWordReqDto.getFunction().get(1).getChineseName()+"-/"+value);
|
||||||
|
judgement.setFunction(wpsWordReqDto.getEnglishName()+"-"+wpsWordReqDto.getFunction().get(0).getFunction()+"-" +wpsWordReqDto.getFunction().get(1).getFunction()+"-/" + value);
|
||||||
|
judgementList.add(judgement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//尾注
|
||||||
|
|
||||||
|
// endnoteReference
|
||||||
|
// 查询所有对应的中文
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return judgementList;
|
||||||
|
}
|
||||||
|
public static void setWordInfo(String chineseName, String englishName, String selectName, String filePath, String id, String parentId, List<WordInfoReqVo> wordInfoReqVos) throws Exception {
|
||||||
|
WordInfoReqVo wordInfos = new WordInfoReqVo();
|
||||||
|
wordInfos.setName(chineseName);
|
||||||
|
wordInfos.setEnglishName(englishName);
|
||||||
|
wordInfos.setFilePath(filePath);
|
||||||
|
wordInfos.setId(id);
|
||||||
|
wordInfos.setSelectName(selectName);
|
||||||
|
wordInfos.setParentId(parentId);
|
||||||
|
wordInfoReqVos.add(wordInfos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<WordInfoReqVo> wpWord(String filePath) throws Exception {
|
||||||
|
List<WordInfoReqVo> wordInfoReqVos = new ArrayList<>();
|
||||||
|
XWPFDocument document = new XWPFDocument(new FileInputStream(filePath));
|
||||||
|
String xmlString = XmlUtil.getDocumentXml(document);
|
||||||
|
String namespace = WpsWordNameSpaces.getNameSpace(xmlString);
|
||||||
|
XmlObject docXml = document.getDocument();
|
||||||
|
// 1、获取文档段落W:P标签得数量,判断出一个有多少段
|
||||||
|
XmlCursor wpCursor = docXml.newCursor();
|
||||||
|
String wpPath = namespace + "/w:document/w:body/w:p";
|
||||||
|
wpCursor.selectPath(wpPath);
|
||||||
|
int wpIndex = 0;
|
||||||
|
// 段落
|
||||||
|
String firstIdWp = getStringRandom();
|
||||||
|
setWordInfo("段落", "w:p", "w:p", filePath, firstIdWp, "0", wordInfoReqVos);
|
||||||
|
List<WordSecondInfoVo> wordSecondWp = new ArrayList<>();
|
||||||
|
while (wpCursor.toNextSelection()) {
|
||||||
|
wpIndex ++;
|
||||||
|
// 段落属性
|
||||||
|
if (!wpCursor.xmlText().contains("w:sectPr")) {
|
||||||
|
|
||||||
|
// 获取文本
|
||||||
|
XmlCursor wpTextXml = wpCursor.newCursor();
|
||||||
|
wpTextXml.selectPath(namespace + ".//w:r/w:t");
|
||||||
|
if (wpTextXml.toNextSelection()) {
|
||||||
|
String secondIdWp = getStringRandom();
|
||||||
|
String text = wpTextXml.getTextValue();
|
||||||
|
setWordInfo("段落" + wpIndex + ":" + text, "w:p)[" + wpIndex + "]", "w:pPr", filePath, secondIdWp, firstIdWp, wordInfoReqVos);
|
||||||
|
// 使用 。 判断句子
|
||||||
|
String[] texts = text.split("。");
|
||||||
|
int textsIndex = 0;
|
||||||
|
for (String s : texts) {
|
||||||
|
String thirdIdWp = getStringRandom();
|
||||||
|
textsIndex ++;
|
||||||
|
setWordInfo("句子" + textsIndex + ":" + s, "w:p)[" + wpIndex + "]", "w:r", filePath, thirdIdWp, secondIdWp, wordInfoReqVos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2、页面
|
||||||
|
XmlCursor wSectPrCursor = docXml.newCursor();
|
||||||
|
String wSectPrPath = namespace + "//w:sectPr";
|
||||||
|
wSectPrCursor.selectPath(wSectPrPath);
|
||||||
|
int wSectPrIndex = 0;
|
||||||
|
String firstIdSectPr = getStringRandom();
|
||||||
|
setWordInfo("页面", "w:sectPr", "w:sectPr", filePath, firstIdSectPr, "", wordInfoReqVos);
|
||||||
|
List<WordSecondInfoVo> wordSecondWSectPr = new ArrayList<>();
|
||||||
|
while (wSectPrCursor.toNextSelection()) {
|
||||||
|
wSectPrIndex ++;
|
||||||
|
String secondIdSectPr = getStringRandom();
|
||||||
|
setWordInfo("节" + wSectPrIndex, "w:sectPr)[" + wSectPrIndex + "]", "w:sectPr", filePath, secondIdSectPr, firstIdSectPr, wordInfoReqVos);
|
||||||
|
}
|
||||||
|
// 3、图形
|
||||||
|
XmlCursor wDrawingCursor = docXml.newCursor();
|
||||||
|
String wDrawingPath = namespace + "//w:drawing";
|
||||||
|
wDrawingCursor.selectPath(wDrawingPath);
|
||||||
|
int wDrawingIndex = 0;
|
||||||
|
String firstIdDrawing = getStringRandom();
|
||||||
|
setWordInfo("图形", "w:drawing", "w:drawing", filePath, firstIdDrawing, "", wordInfoReqVos);
|
||||||
|
while (wDrawingCursor.toNextSelection()) {
|
||||||
|
wDrawingIndex ++;
|
||||||
|
String secondIdDrawing = getStringRandom();
|
||||||
|
XmlCursor wDrawingXml = wDrawingCursor.newCursor();
|
||||||
|
System.out.println(wDrawingXml.xmlText());
|
||||||
|
wDrawingXml.selectPath(namespace + ".//wp:anchor/wp:docPr/@name");
|
||||||
|
if (wDrawingXml.toNextSelection()) {
|
||||||
|
setWordInfo("图形" + wDrawingIndex + ":" + wDrawingXml.getTextValue(), "w:drawing)[" + wDrawingIndex + "]", "w:drawing", filePath, secondIdDrawing, firstIdDrawing, wordInfoReqVos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wordInfoReqVos;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取文档段落W:P标签得数量,判断出一个有多少段
|
* 获取文档段落W:P标签得数量,判断出一个有多少段
|
||||||
* @param filePath 文件路径
|
* @param filePath 文件路径
|
||||||
@@ -23,7 +275,7 @@ public class WpsWordUtils {
|
|||||||
* @return List<WordVO>
|
* @return List<WordVO>
|
||||||
* @throws Exception Exception
|
* @throws Exception Exception
|
||||||
*/
|
*/
|
||||||
public static List<WordVO> wps_word(String filePath, List<WpsWordLinkDO> paragraphList, List<WpsWordLinkDO> anchorList) throws Exception {
|
public static List<WordVO> wps_word(String filePath) throws Exception {
|
||||||
List<WordVO> wordVO = new ArrayList<>();
|
List<WordVO> wordVO = new ArrayList<>();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
// 1、路径初始化
|
// 1、路径初始化
|
||||||
@@ -39,7 +291,7 @@ public class WpsWordUtils {
|
|||||||
// 如 w, wp, a
|
// 如 w, wp, a
|
||||||
String prefix = matcher.group(1);
|
String prefix = matcher.group(1);
|
||||||
// 如 http://schemas.openxmlformats.org/...
|
// 如 http://schemas.openxmlformats.org/...
|
||||||
String uri = matcher.group(2);
|
String uri = matcher.group(2);
|
||||||
namespaces.put(prefix, uri);
|
namespaces.put(prefix, uri);
|
||||||
}
|
}
|
||||||
StringBuilder xpathBuilder = new StringBuilder();
|
StringBuilder xpathBuilder = new StringBuilder();
|
||||||
@@ -55,135 +307,138 @@ public class WpsWordUtils {
|
|||||||
// 3、获取CTDocument对象
|
// 3、获取CTDocument对象
|
||||||
XmlObject docXml = document.getDocument();
|
XmlObject docXml = document.getDocument();
|
||||||
// 3-1、段落的树数据
|
// 3-1、段落的树数据
|
||||||
List<WpsWordLinkDO> paragraphTree = TreeUtils.buildTree(paragraphList);
|
// List<WpsWordLinkDO> paragraphTree = TreeUtils.buildTree(paragraphList);
|
||||||
// 3-2、锚点的树数据
|
// 3-2、锚点的树数据
|
||||||
List<WpsWordLinkDO> anchorTree = TreeUtils.buildTree(anchorList);
|
// List<WpsWordLinkDO> anchorTree = TreeUtils.buildTree(anchorList);
|
||||||
// Word XML document
|
// Word XML document
|
||||||
XmlObject xmlObject = document.getDocument();
|
XmlObject xmlObject = document.getDocument();
|
||||||
for (WpsWordLinkDO anchor : anchorTree) {
|
// for (WpsWordLinkDO anchor : anchorTree) {
|
||||||
String xpathAnchor = allPathx + "//" + anchor.getName();
|
// String xpathAnchor = allPathx + "//" + anchor.getName();
|
||||||
XmlCursor cursorAnchor = docXml.newCursor();
|
// XmlCursor cursorAnchor = docXml.newCursor();
|
||||||
int index = 0;
|
// int index = 0;
|
||||||
cursorAnchor.selectPath(xpathAnchor);
|
// cursorAnchor.selectPath(xpathAnchor);
|
||||||
while (cursorAnchor.toNextSelection()) {
|
// while (cursorAnchor.toNextSelection()) {
|
||||||
type = "图片";
|
// type = "图片";
|
||||||
index += 1;
|
// index += 1;
|
||||||
XmlCursor cursorAnchorXml = cursorAnchor.getObject().newCursor();
|
// XmlCursor cursorAnchorXml = cursorAnchor.getObject().newCursor();
|
||||||
XmlCursor cursorAnchorText = cursorAnchor.getObject().newCursor();
|
// XmlCursor cursorAnchorText = cursorAnchor.getObject().newCursor();
|
||||||
// 首先:判断类型 1 :图片,2:文本框
|
// // 首先:判断类型 1 :图片,2:文本框
|
||||||
cursorAnchorXml.selectPath(allPathx + ".//wp:anchor/wp:docPr/@id");
|
// cursorAnchorXml.selectPath(allPathx + ".//wp:anchor/wp:docPr/@id");
|
||||||
String typeValue = "";
|
// String typeValue = "";
|
||||||
while (cursorAnchorXml.toNextSelection()) {
|
// while (cursorAnchorXml.toNextSelection()) {
|
||||||
typeValue = cursorAnchorXml.getTextValue();
|
// typeValue = cursorAnchorXml.getTextValue();
|
||||||
}
|
// }
|
||||||
String anchorName = "图片";
|
// String anchorName = "图片";
|
||||||
if (Objects.equals(typeValue, "2")) {
|
// if (Objects.equals(typeValue, "2")) {
|
||||||
type = "文本框";
|
// type = "文本框";
|
||||||
System.out.println(cursorAnchorText.xmlText());
|
// System.out.println(cursorAnchorText.xmlText());
|
||||||
// 要获取文本框的文本
|
// // 要获取文本框的文本
|
||||||
cursorAnchorText.selectPath(allPathx + ".//wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:txbx");
|
// cursorAnchorText.selectPath(allPathx + ".//wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:txbx");
|
||||||
while (cursorAnchorText.toNextSelection()) {
|
// while (cursorAnchorText.toNextSelection()) {
|
||||||
System.out.println(cursorAnchorText.getObject().xmlText());
|
// System.out.println(cursorAnchorText.getObject().xmlText());
|
||||||
anchorName = cursorAnchorText.getTextValue();
|
// anchorName = cursorAnchorText.getTextValue();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
cursorAnchorText.dispose();
|
// cursorAnchorText.dispose();
|
||||||
cursorAnchorXml.dispose();
|
// cursorAnchorXml.dispose();
|
||||||
XmlObject paraObj = cursorAnchor.getObject();
|
// XmlObject paraObj = cursorAnchor.getObject();
|
||||||
for (WpsWordLinkDO root : anchor.getChildren()) {
|
// for (WpsWordLinkDO root : anchor.getChildren()) {
|
||||||
traverseTreeAndQueryXml(type, wordVO, anchor.getName(), anchorName, allPathx, root, paraObj, new ArrayList<>(), new ArrayList<>(), index,1);
|
// traverseTreeAndQueryXml(type, wordVO, anchor.getName(), anchorName, allPathx, root, paraObj, new ArrayList<>(), new ArrayList<>(), index,1);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
cursorAnchor.dispose();
|
// cursorAnchor.dispose();
|
||||||
}
|
// }
|
||||||
// 创建一个list,存放word读取的数据(段落数据)
|
// 创建一个list,存放word读取的数据(段落数据)
|
||||||
for (WpsWordLinkDO paragraph : paragraphTree) {
|
// for (WpsWordLinkDO paragraph : paragraphTree) {
|
||||||
type = "段落";
|
type = "段落";
|
||||||
// 段落划分 根据w:p标签
|
// 段落划分 根据w:p标签
|
||||||
// 到达参数节点,构造 XPath 路径查询它的值
|
// 到达参数节点,构造 XPath 路径查询它的值
|
||||||
String wpPath = allPathx + "/w:document/w:body/" + paragraph.getName();
|
String wpPath = allPathx + "/w:document/w:body/w:p";
|
||||||
XmlCursor cursor = docXml.newCursor();
|
XmlCursor cursor = docXml.newCursor();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
cursor.selectPath(wpPath);
|
cursor.selectPath(wpPath);
|
||||||
while (cursor.toNextSelection()) {
|
while (cursor.toNextSelection()) {
|
||||||
String rTextName = "";
|
String rTextName = "";
|
||||||
index += 1;
|
index += 1;
|
||||||
// 每一段进行赋值,进行判断
|
System.out.println(index);
|
||||||
|
// // 每一段进行赋值,进行判断
|
||||||
XmlObject paraObj = cursor.getObject();
|
XmlObject paraObj = cursor.getObject();
|
||||||
String paraText = paraObj.xmlText();
|
String paraText = paraObj.xmlText();
|
||||||
XmlCursor rCursor = paraObj.newCursor();
|
System.out.println(paraText);
|
||||||
// 想要查询指定的path
|
// XmlCursor rCursor = paraObj.newCursor();
|
||||||
rCursor.selectPath(allPathx + ".//w:r/w:t");
|
// // 想要查询指定的path
|
||||||
while (rCursor.toNextSelection()) {
|
// rCursor.selectPath(allPathx + ".//w:r/w:t");
|
||||||
XmlCursor rsCursor = rCursor.getObject().newCursor();
|
// while (rCursor.toNextSelection()) {
|
||||||
rTextName = rsCursor.getTextValue();
|
// XmlCursor rsCursor = rCursor.getObject().newCursor();
|
||||||
rsCursor.dispose();
|
// rTextName = rsCursor.getTextValue();
|
||||||
}
|
// rsCursor.dispose();
|
||||||
rCursor.dispose();
|
// }
|
||||||
// 创建新的
|
// rCursor.dispose();
|
||||||
for (WpsWordLinkDO root : paragraph.getChildren()) {
|
// // 创建新的
|
||||||
traverseTreeAndQueryXml(type, wordVO, paragraph.getName(), rTextName, allPathx, root, paraObj, new ArrayList<>(), new ArrayList<>(), index,1);
|
// for (WpsWordLinkDO root : paragraph.getChildren()) {
|
||||||
}
|
// traverseTreeAndQueryXml(type, wordVO, paragraph.getName(), rTextName, allPathx, root, paraObj, new ArrayList<>(), new ArrayList<>(), index,1);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
// 读取页眉的方法(需要通过页眉查询,水印,页眉文字等信息)
|
// 读取页眉的方法(需要通过页眉查询,水印,页眉文字等信息)
|
||||||
List<XWPFHeader> headers = document.getHeaderList();
|
// List<XWPFHeader> headers = document.getHeaderList();
|
||||||
for (XWPFHeader header : headers) {
|
// for (XWPFHeader header : headers) {
|
||||||
if (!Objects.equals(header.getText(), "")) {
|
// if (!Objects.equals(header.getText(), "")) {
|
||||||
headerAndFooter(header, null, wordVO);
|
// headerAndFooter(header, null, wordVO);
|
||||||
}
|
// }
|
||||||
// 获取底层 XML 对象
|
// // 获取底层 XML 对象
|
||||||
CTHdrFtr ctHdrFtr = header._getHdrFtr(); // ✅ 正确方法
|
// CTHdrFtr ctHdrFtr = header._getHdrFtr(); // ✅ 正确方法
|
||||||
String xpath = allPathx + "//w:hdr/w:p/w:r/w:pict";
|
// String xpath = allPathx + "//w:hdr/w:p/w:r/w:pict";
|
||||||
XmlCursor cursor = ctHdrFtr.newCursor();
|
// XmlCursor cursor = ctHdrFtr.newCursor();
|
||||||
cursor.selectPath(xpath);
|
// cursor.selectPath(xpath);
|
||||||
while (cursor.toNextSelection()) {
|
// while (cursor.toNextSelection()) {
|
||||||
// 查询 v:textpath 节点
|
// // 查询 v:textpath 节点
|
||||||
cursor.selectPath(
|
// cursor.selectPath(
|
||||||
allPathx +
|
// allPathx +
|
||||||
".//v:textpath"
|
// ".//v:textpath"
|
||||||
);
|
// );
|
||||||
while (cursor.toNextSelection()) {
|
// while (cursor.toNextSelection()) {
|
||||||
XmlObject textpathObj = cursor.getObject();
|
// XmlObject textpathObj = cursor.getObject();
|
||||||
String xml = textpathObj.xmlText();
|
// String xml = textpathObj.xmlText();
|
||||||
WordVO attr_word = new WordVO();
|
// WordVO attr_word = new WordVO();
|
||||||
|
//
|
||||||
// 提取属性值
|
// // 提取属性值
|
||||||
String stringAttr = cursor.getAttributeText(new javax.xml.namespace.QName("string"));
|
// String stringAttr = cursor.getAttributeText(new javax.xml.namespace.QName("string"));
|
||||||
String styleAttr = cursor.getAttributeText(new javax.xml.namespace.QName("style"));
|
// String styleAttr = cursor.getAttributeText(new javax.xml.namespace.QName("style"));
|
||||||
attr_word.setWordText("水印");
|
// attr_word.setWordText("水印");
|
||||||
List<String> attr = new ArrayList<>();
|
// List<String> attr = new ArrayList<>();
|
||||||
attr.add("水印文字 string 属性: " + stringAttr);
|
// attr.add("水印文字 string 属性: " + stringAttr);
|
||||||
attr.add("水印 style 属性: " + styleAttr);
|
// attr.add("水印 style 属性: " + styleAttr);
|
||||||
attr_word.setKeynoteChinese(attr);
|
// attr_word.setKeynoteChinese(attr);
|
||||||
List<String> path = new ArrayList<>();
|
// List<String> path = new ArrayList<>();
|
||||||
path.add("name:"+stringAttr);
|
// path.add("name:"+stringAttr);
|
||||||
path.add("style:"+styleAttr);
|
// path.add("style:"+styleAttr);
|
||||||
attr_word.setExamKeynote(path);
|
// attr_word.setExamKeynote(path);
|
||||||
attr_word.setType("水印");
|
// attr_word.setType("水印");
|
||||||
wordVO.add(attr_word);
|
// wordVO.add(attr_word);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
cursor.close();
|
// cursor.close();
|
||||||
}
|
// }
|
||||||
// 获取页脚
|
// // 获取页脚
|
||||||
List<XWPFFooter> footers = document.getFooterList();
|
// List<XWPFFooter> footers = document.getFooterList();
|
||||||
for (XWPFFooter footer : footers) {
|
// for (XWPFFooter footer : footers) {
|
||||||
if (!Objects.equals(footer.getText(), "")) {
|
// if (!Objects.equals(footer.getText(), "")) {
|
||||||
headerAndFooter(null, footer, wordVO);
|
// headerAndFooter(null, footer, wordVO);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
// 邮件合并
|
// // 邮件合并
|
||||||
List<String> email = getMailMergeFields(document);
|
// List<String> email = getMailMergeFields(document);
|
||||||
if (!email.isEmpty()) {
|
// if (!email.isEmpty()) {
|
||||||
// 使用了邮件合并功能
|
// // 使用了邮件合并功能
|
||||||
WordVO email_word = new WordVO();
|
// WordVO email_word = new WordVO();
|
||||||
email_word.setWordText("邮件合并");
|
// email_word.setWordText("邮件合并");
|
||||||
email_word.setExamKeynote(email);
|
// email_word.setExamKeynote(email);
|
||||||
email_word.setKeynoteChinese(email);
|
// email_word.setKeynoteChinese(email);
|
||||||
email_word.setType("邮件合并");
|
// email_word.setType("邮件合并");
|
||||||
wordVO.add(email_word);
|
// wordVO.add(email_word);
|
||||||
}
|
// }
|
||||||
return wordVO;
|
return wordVO;
|
||||||
}
|
}
|
||||||
// 页眉页脚
|
// 页眉页脚
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package pc.exam.pp.module.judgement.utils.wps_word.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class WordHeaderFooterVo {
|
||||||
|
|
||||||
|
private String rid;
|
||||||
|
private String type;
|
||||||
|
private String xmlType;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package pc.exam.pp.module.judgement.utils.wps_word.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.apache.xmlbeans.XmlCursor;
|
||||||
|
import pc.exam.pp.module.judgement.dal.dataobject.wpsword.WpsWordLinkDO;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author REN
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class WordInfoReqVo {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String englishName;
|
||||||
|
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
|
private String parentId;
|
||||||
|
|
||||||
|
private String selectName;
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private List<WordInfoReqVo> children = new ArrayList<>();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package pc.exam.pp.module.judgement.utils.wps_word.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class WordSecondInfoVo {
|
||||||
|
|
||||||
|
private String englishName;
|
||||||
|
private String chineseName;
|
||||||
|
private List<WordThirdInfoVo> wordThirdInfoVos;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package pc.exam.pp.module.judgement.utils.wps_word.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author REN
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class WordThirdInfoVo {
|
||||||
|
|
||||||
|
private String englishName;
|
||||||
|
private String chineseName;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package pc.exam.pp.module.judgement.utils.zipfile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
public class ZipXmlUtils {
|
||||||
|
public static String readZipEntry(ZipFile zipFile, String entryName) throws IOException {
|
||||||
|
ZipEntry entry = zipFile.getEntry(entryName);
|
||||||
|
if (entry == null) return null;
|
||||||
|
try (InputStream is = zipFile.getInputStream(entry)) {
|
||||||
|
return new String(is.readAllBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
word/试卷.docx
Normal file
BIN
word/试卷.docx
Normal file
Binary file not shown.
Reference in New Issue
Block a user