Переглянути джерело

Merge remote-tracking branch 'origin/master'

Feick 5 роки тому
батько
коміт
d9c0d33493
63 змінених файлів з 2871 додано та 1210 видалено
  1. 2 2
      deploy.sh
  2. 0 841
      doc/OnlinePapers_online.sql
  3. 1384 0
      doc/OnlinePapers_prod.sql
  4. BIN
      doc/sub.docx
  5. BIN
      doc/table.docx
  6. BIN
      doc/topic_table.docx
  7. BIN
      doc/中考专项诊断考试说明.pdf
  8. BIN
      doc/化学中考专项诊断.docx
  9. BIN
      doc/化学中考专项诊断知识点列表.xlsx
  10. BIN
      doc/数学中考专项诊断.docx
  11. BIN
      doc/数学中考专项诊断思维过程.xlsx
  12. BIN
      doc/数学中考专项诊断报告.pdf
  13. BIN
      doc/数学中考专项诊断知识点列表.xlsx
  14. 0 0
      doc/数学小升初专项诊断.docx
  15. 0 0
      doc/数学小升初专项诊断知识点列表.xlsx
  16. BIN
      doc/物理中考专项诊断.docx
  17. BIN
      doc/物理中考专项诊断知识点列表.xlsx
  18. 14 1
      src/main/java/com/yaoxiang/diagnosis/config/Constants.java
  19. 1 1
      src/main/java/com/yaoxiang/diagnosis/config/Swagger2Config.java
  20. 34 6
      src/main/java/com/yaoxiang/diagnosis/controller/ExcelController.java
  21. 46 6
      src/main/java/com/yaoxiang/diagnosis/controller/PaperController.java
  22. 1 1
      src/main/java/com/yaoxiang/diagnosis/controller/PaperResultController.java
  23. 10 8
      src/main/java/com/yaoxiang/diagnosis/controller/QuestionController.java
  24. 8 7
      src/main/java/com/yaoxiang/diagnosis/controller/ReportController.java
  25. 1 4
      src/main/java/com/yaoxiang/diagnosis/controller/SpecialDiagnosisController.java
  26. 36 3
      src/main/java/com/yaoxiang/diagnosis/controller/SpecialReportController.java
  27. 12 0
      src/main/java/com/yaoxiang/diagnosis/controller/TestController.java
  28. 2 6
      src/main/java/com/yaoxiang/diagnosis/controller/UserInfoController.java
  29. 1 1
      src/main/java/com/yaoxiang/diagnosis/dao/PaperCommitRepo.java
  30. 1 1
      src/main/java/com/yaoxiang/diagnosis/dao/PaperResultRepo.java
  31. 2 0
      src/main/java/com/yaoxiang/diagnosis/dao/SpecialKnowledgeRepo.java
  32. 14 0
      src/main/java/com/yaoxiang/diagnosis/dao/SpecialMindRepo.java
  33. 12 0
      src/main/java/com/yaoxiang/diagnosis/entity/Authority.java
  34. 11 0
      src/main/java/com/yaoxiang/diagnosis/entity/PaperResult.java
  35. 9 0
      src/main/java/com/yaoxiang/diagnosis/entity/Role.java
  36. 30 5
      src/main/java/com/yaoxiang/diagnosis/entity/SpecialKnowledge.java
  37. 121 0
      src/main/java/com/yaoxiang/diagnosis/entity/SpecialMind.java
  38. 9 0
      src/main/java/com/yaoxiang/diagnosis/model/PaperResultVo.java
  39. 10 0
      src/main/java/com/yaoxiang/diagnosis/model/PaperVo.java
  40. 8 0
      src/main/java/com/yaoxiang/diagnosis/model/SpecialKnowledgeVo.java
  41. 59 0
      src/main/java/com/yaoxiang/diagnosis/model/SpecialMindVo.java
  42. 13 2
      src/main/java/com/yaoxiang/diagnosis/service/CommitService.java
  43. 4 2
      src/main/java/com/yaoxiang/diagnosis/service/OptionService.java
  44. 17 9
      src/main/java/com/yaoxiang/diagnosis/service/PaperResultService.java
  45. 156 99
      src/main/java/com/yaoxiang/diagnosis/service/PaperService.java
  46. 17 12
      src/main/java/com/yaoxiang/diagnosis/service/QuestionService.java
  47. 178 19
      src/main/java/com/yaoxiang/diagnosis/service/SpecialKnowledgeService.java
  48. 29 0
      src/main/java/com/yaoxiang/diagnosis/service/SpecialMindService.java
  49. 199 35
      src/main/java/com/yaoxiang/diagnosis/service/SpecialReportService.java
  50. 117 41
      src/main/java/com/yaoxiang/diagnosis/word/KnowledgeUtil.java
  51. 93 39
      src/main/java/com/yaoxiang/diagnosis/word/WordService.java
  52. 11 3
      src/main/java/com/yaoxiang/diagnosis/word/WordUtil.java
  53. 0 15
      src/main/resources/application-cloud.properties
  54. 0 9
      src/main/resources/application-dev.properties
  55. 0 8
      src/main/resources/application-docker.properties
  56. 18 0
      src/main/resources/application-pre.properties
  57. 0 11
      src/main/resources/application-prod.properties
  58. 0 4
      src/main/resources/application.properties
  59. 1 1
      src/test/java/com/yaoxiang/diagnosis/service/KnowledgeTest.java
  60. 45 0
      src/test/java/com/yaoxiang/diagnosis/service/StringTest.java
  61. 79 1
      src/test/java/com/yaoxiang/diagnosis/service/UploadTest.java
  62. 22 7
      src/test/java/com/yaoxiang/diagnosis/service/WordServiceTest.java
  63. 34 0
      src/test/java/com/yaoxiang/diagnosis/service/WordTest.java

+ 2 - 2
deploy.sh

@@ -4,6 +4,6 @@ docker build -t feick/diagnosis:$date .
 echo "backend current tag is $date"
 sed -i "s/\${date}/$(echo $date)/g" deployment.yaml
 kubectl apply -f deployment.yaml
-sed -i "s/\${date}/$(echo $date)/g" deployment-prod.yaml
-kubectl apply -f deployment-prod.yaml
+#sed -i "s/\${date}/$(echo $date)/g" deployment-prod.yaml
+#kubectl apply -f deployment-prod.yaml
 echo "build finish."

Різницю між файлами не показано, бо вона завелика
+ 0 - 841
doc/OnlinePapers_online.sql


Різницю між файлами не показано, бо вона завелика
+ 1384 - 0
doc/OnlinePapers_prod.sql



BIN
doc/table.docx


BIN
doc/topic_table.docx


BIN
doc/中考专项诊断考试说明.pdf


BIN
doc/化学中考专项诊断.docx


BIN
doc/化学中考专项诊断知识点列表.xlsx


BIN
doc/数学中考专项诊断.docx


BIN
doc/数学中考专项诊断思维过程.xlsx


BIN
doc/数学中考专项诊断报告.pdf


BIN
doc/数学中考专项诊断知识点列表.xlsx


+ 0 - 0
doc/fast6to7.docx → doc/数学小升初专项诊断.docx


+ 0 - 0
doc/小升初专项诊断知识点列表.xlsx → doc/数学小升初专项诊断知识点列表.xlsx


BIN
doc/物理中考专项诊断.docx


BIN
doc/物理中考专项诊断知识点列表.xlsx


+ 14 - 1
src/main/java/com/yaoxiang/diagnosis/config/Constants.java

@@ -3,7 +3,9 @@ package com.yaoxiang.diagnosis.config;
 
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class Constants {
@@ -114,5 +116,16 @@ public class Constants {
     public static final int PAPER_STATUS_INVALIDATE = 2;
 
     public static final String SPECIAL_KNOWLEDGE_MASTER = "掌握";
-    public static final String SPECIAL_KNOWLEDGE_UNMASTER  = "未掌握";
+    public static final String SPECIAL_KNOWLEDGE_UNMASTER = "未掌握";
+
+    public static final String SPECIAL_MASTER_STATUS_KNOW = "认识";
+    public static final String SPECIAL_MASTER_STATUS_UNDERSTAND = "理解";
+    public static final String SPECIAL_MASTER_STATUS_USAGE = "应用";
+
+    public static final List<String> SPECIAL_MASTER_STATUS = new ArrayList<String>() {{
+        add(SPECIAL_MASTER_STATUS_KNOW);
+        add(SPECIAL_MASTER_STATUS_UNDERSTAND);
+        add(SPECIAL_MASTER_STATUS_USAGE);
+    }};
+
 }

+ 1 - 1
src/main/java/com/yaoxiang/diagnosis/config/Swagger2Config.java

@@ -37,7 +37,7 @@ public class Swagger2Config {
     private ApiInfo apiInfo() {
         return new ApiInfoBuilder()
                 //自定义信息可按需求填写
-                .title("Spring Boot中使用Swagger构建restful apis")
+                .title("YaoXiang Diagnosis Rest API")
                 .description("对接")
                 .version("1.0")
                 .build();

+ 34 - 6
src/main/java/com/yaoxiang/diagnosis/controller/ExcelController.java

@@ -2,12 +2,14 @@ package com.yaoxiang.diagnosis.controller;
 
 import com.yaoxiang.diagnosis.config.Constants;
 import com.yaoxiang.diagnosis.entity.SpecialKnowledge;
+import com.yaoxiang.diagnosis.entity.SpecialMind;
 import com.yaoxiang.diagnosis.entity.SubjectKnowledge;
 import com.yaoxiang.diagnosis.model.MatterVo;
 import com.yaoxiang.diagnosis.model.Result;
 import com.yaoxiang.diagnosis.service.KnowledgeService;
 import com.yaoxiang.diagnosis.service.MatterService;
 import com.yaoxiang.diagnosis.service.SpecialKnowledgeService;
+import com.yaoxiang.diagnosis.service.SpecialMindService;
 import com.yaoxiang.diagnosis.word.KnowledgeUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -28,6 +30,8 @@ public class ExcelController {
     private SpecialKnowledgeService specialKnowledgeService;
     @Resource
     private MatterService matterService;
+    @Resource
+    private SpecialMindService specialMindService;
 
     @PostMapping("/uploadAll")
     public Result uploadAll() {
@@ -50,20 +54,44 @@ public class ExcelController {
                                @RequestBody MultipartFile file) throws Exception {
         byte[] data = file.getBytes();
         List<MatterVo> list = KnowledgeUtil.importMatter(subjectId, grade, data);
-        matterService.addBase(Constants.MATTER_EMOTION,"emotion");
-        matterService.addBase(Constants.MATTER_STUDY,"study");
+        matterService.addBase(Constants.MATTER_EMOTION, "emotion");
+        matterService.addBase(Constants.MATTER_STUDY, "study");
         matterService.addAll(list);
         return Result.ok(list);
     }
 
     @PostMapping("/uploadSpecial")
-    @ApiOperation("上传专项诊断知识点")
+    @ApiOperation("上传小学专项诊断知识点")
     public Result uploadSpecial(@RequestParam(defaultValue = "2") Long subjectId,
-        @RequestParam(defaultValue = "6Y") String grade,
-        @RequestBody MultipartFile file) throws Exception{
+                                @RequestParam(defaultValue = "6Y") String grade,
+                                @RequestBody MultipartFile file) throws Exception {
         byte[] data = file.getBytes();
-        List<SpecialKnowledge> list = KnowledgeUtil.importSpecialKnowledge1(subjectId,grade,data);
+        List<SpecialKnowledge> list = KnowledgeUtil.importSpecialKnowledge1(subjectId, grade, data);
         boolean result = specialKnowledgeService.add(list);
         return new Result(result);
     }
+
+    @PostMapping("/uploadSpecialMiddle")
+    @ApiOperation("上传中考专项诊断知识点")
+    public Result uploadSpecialChem(@RequestParam(defaultValue = "4") Long subjectId,
+                                    @RequestParam(defaultValue = "9Y") String grade,
+                                    @RequestParam(defaultValue = "5") Long pid,
+                                    @RequestBody MultipartFile file) throws Exception {
+        byte[] data = file.getBytes();
+        List<SpecialKnowledge> list = KnowledgeUtil.importSpecialKnowledge2(subjectId, grade, data, pid);
+        specialKnowledgeService.add(list);
+        return Result.ok(list);
+    }
+
+    @PostMapping("/uploadSpecialMind")
+    @ApiOperation("上传中考专项诊断思维过程")
+    public Result uploadSpecialMind(@RequestParam(defaultValue = "2") Long subjectId,
+                                    @RequestParam(defaultValue = "9Y") String grade,
+                                    @RequestParam(defaultValue = "5") Long pid,
+                                    @RequestBody MultipartFile file) throws Exception {
+        byte[] data = file.getBytes();
+        List<SpecialMind> list = KnowledgeUtil.importSpecialMind(subjectId, grade, data, pid);
+        specialMindService.add(list);
+        return Result.ok(list);
+    }
 }

+ 46 - 6
src/main/java/com/yaoxiang/diagnosis/controller/PaperController.java

@@ -54,7 +54,7 @@ public class PaperController {
     @ApiOperation(value = "查询单个试卷  ")
     @RequestMapping(value = "/getOnePaper/{id}", method = RequestMethod.GET)
     public Paper getOnePaper(@PathVariable Long id) {
-        return paperService.getOnePaper(id);
+        return paperService.getOneWithAuth(id);
     }
 
     //    @PreAuthorize("hasRole('ROLE_ADMIN')")
@@ -65,12 +65,27 @@ public class PaperController {
     }
 
     //    @PreAuthorize("hasRole('ROLE_ADMIN')")
-    @ApiOperation(value = "编辑试卷")
-    @RequestMapping(value = "/update", method = RequestMethod.POST)
-    public Result update(@RequestBody Paper paper) {
+//    @ApiOperation(value = "编辑试卷")
+//    @RequestMapping(value = "/update", method = RequestMethod.POST)
+//    public Result update(@RequestBody Paper paper) {
+//        return paperService.update(paper);
+//    }
+
+    @ApiOperation("更新试卷参数")
+    @PostMapping("/updateParams")
+    public Result updateParams(Long pid, String name, String grade, String sectionNums,
+                               String sectionDurations, String sectionRests, String remark) {
+        Paper paper = paperService.getOnePaper(pid);
+        paper.setName(name);
+        paper.setGrade(grade);
+        paper.setSectionNums(sectionNums);
+        paper.setSectionDurations(sectionDurations);
+        paper.setSectionRests(sectionRests);
+        paper.setRemark(remark);
         return paperService.update(paper);
     }
 
+
     @PostMapping("/invalidate")
     @ApiOperation(value = "作废试卷")
     public Result invalidate(Long pid) {
@@ -80,7 +95,7 @@ public class PaperController {
     }
 
     //    @PreAuthorize("hasRole('ROLE_ADMIN')")
-    @ApiOperation(value = "删除试卷")
+    @ApiOperation(value = "删除试卷 假删除")
     @RequestMapping(value = "/delete", method = RequestMethod.POST)
     public void delete(@RequestParam Long id) {
         paperService.delete(id);
@@ -89,7 +104,9 @@ public class PaperController {
     //    @PreAuthorize("hasRole('ROLE_ADMIN')")
     @ApiOperation(value = "上传试卷")
     @PostMapping("uploadPaper")
-    @ApiImplicitParam(name = "paperTemplateId", value = "试卷模板Id 默认1")
+    @ApiImplicitParams({@ApiImplicitParam(name = "paperTemplateId", paramType = "query", value = "试卷模板Id 默认1"),
+            @ApiImplicitParam(name = "useAbility", paramType = "query", defaultValue = "false")
+    })
     public Result uploadPaper(PaperVo paperVo,
                               @RequestParam(defaultValue = "1") Long paperTemplateId,
                               @RequestBody MultipartFile file) throws IOException {
@@ -107,4 +124,27 @@ public class PaperController {
         }
         return paperService.uploadPaper(paperVo, paperTemplateId, url, data);
     }
+
+    @ApiOperation(value = "测试上传试卷,不会保存试卷")
+    @PostMapping("uploadPaperTest")
+    @ApiImplicitParams({@ApiImplicitParam(name = "paperTemplateId", paramType = "query", value = "试卷模板Id 默认1"),
+            @ApiImplicitParam(name = "useAbility", paramType = "query", defaultValue = "false")
+    })
+    public Result uploadPaperTest(PaperVo paperVo,
+                                  @RequestParam(defaultValue = "1") Long paperTemplateId,
+                                  @RequestBody MultipartFile file) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        FileCopyUtils.copy(file.getInputStream(), baos);
+        int suffixIndex = file.getOriginalFilename().lastIndexOf(".");
+        String suffix = file.getOriginalFilename().substring(suffixIndex);
+        String saveName = CommonUtil.randomUUID() + suffix;
+        byte[] data = baos.toByteArray();
+//        byte[] clone = data.clone();
+//        String url = fileService.upload(data, UploadProperties.DOC_PATH, saveName);
+//        String url = fileService.upload(data, saveName);
+//        if (StringUtils.isEmpty(url)) {
+//            return Result.fail("文件上传失败,请重试");
+//        }
+        return paperService.uploadPaperTest(paperVo, paperTemplateId, "", data);
+    }
 }

+ 1 - 1
src/main/java/com/yaoxiang/diagnosis/controller/PaperResultController.java

@@ -46,7 +46,7 @@ public class PaperResultController {
     @GetMapping("/rebuildByPidAndUid")
     @ApiOperation("重新生成报告结果,方便测试")
     public Result rebuild(Long pid, Long uid) {
-        PaperCommit commit = paperCommitRepo.findByPidAndUid(pid, uid);
+        PaperCommit commit = paperCommitRepo.findByPidAndUidOrderByCreatetimeDesc(pid, uid).get(0);
         Paper paper = paperService.getOnePaper(commit.getPid());
         paperResultService.checkAndDelete(paper.getId(), commit.getUid());
         return paperResultService.parseResult(commit, paper);

+ 10 - 8
src/main/java/com/yaoxiang/diagnosis/controller/QuestionController.java

@@ -31,25 +31,25 @@ public class QuestionController {
     @Resource
     private ExecutorService executorService;
 
-    @ApiOperation(value = "增加 题")
+    @ApiOperation(value = "增加 题")
     @RequestMapping(value = "/addQuestionForPaper", method = RequestMethod.POST)
     public Result addQuestionForPaper(@RequestBody Question question) {
         return questionService.addQuestion(question);
     }
 
-    @ApiOperation(value = "修改 题")
+    @ApiOperation(value = "修改 题")
     @RequestMapping(value = "/updateQuestionForPaper", method = RequestMethod.POST)
     public Result updateQuestionForPaper(@RequestBody Question question) {
         return questionService.updateQuestion(question);
     }
 
-    @ApiOperation(value = "查询 题  ")
+    @ApiOperation(value = "查询 题  ")
     @RequestMapping(value = "/getQuestion", method = RequestMethod.GET)
     public Question getQuestion(@RequestParam Long id) {
         return questionService.getQuestion(id);
     }
 
-    @ApiOperation(value = "删除 题  ")
+    @ApiOperation(value = "删除 题  ")
     @RequestMapping(value = "/deleteQuestion", method = RequestMethod.GET)
     public void deleteQuestion(@RequestParam Long id) {
         questionService.deleteQuestion(id);
@@ -75,9 +75,11 @@ public class QuestionController {
 //                e.printStackTrace();
 //            }
 //        });
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        FileCopyUtils.copy(file.getInputStream(), baos);
-        byte[] data = baos.toByteArray();
-        return questionService.parseQuestion(pid, section, number, data);
+//        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+//        FileCopyUtils.copy(file.getInputStream(), baos);
+//        byte[] data = file.getBytes();
+        //暂时不上传题库
+        return Result.fail("暂时不支持只上传题目");
+//        return questionService.parseQuestion(pid, section, number, data);
     }
 }

+ 8 - 7
src/main/java/com/yaoxiang/diagnosis/controller/ReportController.java

@@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 @Api(tags = "报告管理")
@@ -58,18 +59,18 @@ public class ReportController {
         if (paper == null) {
             return Result.fail("未找到试卷");
         }
-        PaperResult paperResult = paperResultService.findByPidAndUid(pid, uid);
-        if (paperResult == null) {
+        List<PaperResult> paperResults = paperResultService.findByPidAndUid(pid, uid);
+        if (paperResults == null) {
             logger.info("正在生成结果");
-            paperResult = (PaperResult) paperResultService.parseResult(pid, uid).getT();
+            paperResults = (List<PaperResult>) paperResultService.parseResult(pid, uid).getT();
         }
         Map<String, Object> result = new HashMap<>();
         result.put("name", info.getName());
         result.put("grade", paper.getGrade());
         result.put("subject", subjectService.get(paper.getSubjectId()).getName());
-        result.put("diagnosisTime", paperResult.getCreatetime());
-        result.put("code", paperResult.getCode());
-        result.put("paperResultId", paperResult.getId());
+        result.put("diagnosisTime", paperResults.get(0).getCreatetime());
+        result.put("code", paperResults.get(0).getCode());
+        result.put("paperResultId", paperResults.get(0).getId());
         return Result.ok(result);
 
     }
@@ -90,7 +91,7 @@ public class ReportController {
     @GetMapping("useTime")
     @ApiOperation("获取作答时间及平均作答时间")
     public Result useTime(Long pid, Long uid) {
-        PaperResult paperResult = paperResultService.findByPidAndUid(pid, uid);
+        List<PaperResult> paperResult = paperResultService.findByPidAndUid(pid, uid);
         if (paperResult == null) {
             return new Result<>(false, "未找到诊断结果");
         }

+ 1 - 4
src/main/java/com/yaoxiang/diagnosis/controller/SpecialDiagnosisController.java

@@ -3,10 +3,7 @@ package com.yaoxiang.diagnosis.controller;
 import com.yaoxiang.diagnosis.entity.SpecialKnowledge;
 import com.yaoxiang.diagnosis.service.SpecialKnowledgeService;
 import io.swagger.annotations.Api;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import java.util.List;

+ 36 - 3
src/main/java/com/yaoxiang/diagnosis/controller/SpecialReportController.java

@@ -1,15 +1,20 @@
 package com.yaoxiang.diagnosis.controller;
 
+import com.yaoxiang.diagnosis.entity.SpecialMind;
 import com.yaoxiang.diagnosis.entity.SpecialResult;
+import com.yaoxiang.diagnosis.model.SpecialMindVo;
 import com.yaoxiang.diagnosis.service.SpecialReportService;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
+import java.util.Comparator;
+import java.util.List;
 
-@Api(tags="专项诊断报告")
+@Api(tags = "专项诊断报告")
 @RestController
 @RequestMapping("/specialReport")
 public class SpecialReportController {
@@ -18,7 +23,35 @@ public class SpecialReportController {
     private SpecialReportService specialReportService;
 
     @GetMapping("/generate")
-    public SpecialResult generate(Long pid,Long uid){
-        return specialReportService.generate(pid,uid);
+    @ApiOperation("学生端 生成专项诊断第一页知识点报告 ")
+    public SpecialResult generate(Long pid, Long uid) {
+        return specialReportService.generate(pid, uid);
     }
+
+    @GetMapping("/generate1")
+    @ApiOperation("管理端 生成专项诊断第一页知识点报告")
+    public SpecialResult generate(Long resultId) {
+        return specialReportService.generate(resultId);
+    }
+
+    @GetMapping("/generateMind")
+    @ApiOperation("生成专项诊断第二页思维过程报告")
+    public List<SpecialMindVo> generateMind(Long pid, Long uid) {
+        List<SpecialMindVo> list = specialReportService.generateMind(pid, uid);
+        list.sort(Comparator.comparingInt(SpecialMindVo::getSort));
+        return list;
+    }
+
+    @GetMapping("/generateMind1")
+    @ApiOperation("管理端 生成专项诊断第二页思维过程报告")
+    public List<SpecialMindVo> generateMind(Long resultId) {
+        List<SpecialMindVo> list = specialReportService.generateMind(resultId);
+        list.sort(Comparator.comparingInt(SpecialMindVo::getSort));
+        return list;
+    }
+
+//    @GetMapping("/generate2")
+//    public SpecialResult generate2(Long pid,Long uid){
+//        return specialReportService.generate2(pid,uid);
+//    }
 }

+ 12 - 0
src/main/java/com/yaoxiang/diagnosis/controller/TestController.java

@@ -6,6 +6,7 @@ import com.yaoxiang.diagnosis.file.FileService;
 import com.yaoxiang.diagnosis.entity.Question;
 import com.yaoxiang.diagnosis.model.AuthUser;
 import com.yaoxiang.diagnosis.model.Result;
+import com.yaoxiang.diagnosis.service.SpecialKnowledgeService;
 import com.yaoxiang.diagnosis.util.SecurityUtil;
 import io.swagger.annotations.Api;
 import org.slf4j.Logger;
@@ -33,11 +34,18 @@ public class TestController {
     private QuestionRepo questionRepo;
     @Resource
     private FileService fileService;
+    @Resource
+    private SpecialKnowledgeService specialKnowledgeService;
 
     private AtomicLong visitCount = new AtomicLong();
 
     private static final Logger logger = LoggerFactory.getLogger(TestController.class);
 
+    @GetMapping("/")
+    public String index(){
+        return "hello";
+    }
+
     @PreAuthorize("hasRole('ROLE_USER')")
     @RequestMapping(value = "/test", method = RequestMethod.GET)
     public String test() {
@@ -111,4 +119,8 @@ public class TestController {
         return Result.ok();
     }
 
+    @PostMapping("syncKnowledgeToSpecial")
+    public boolean syncKnowledgeToSpecial(Long subjectId,String grade,Long pid){
+        return specialKnowledgeService.syncKnowledgeToSpecial(subjectId,grade,pid);
+    }
 }

+ 2 - 6
src/main/java/com/yaoxiang/diagnosis/controller/UserInfoController.java

@@ -28,12 +28,8 @@ public class UserInfoController {
     @GetMapping("/authority")
     public List<String> getAuthorities() {
         AuthUser user = SecurityUtil.getCurrentUser();
-//        if (user.getAuthorities().contains(ConfigConstants.ROLE_ADMIN)) {
-//            return ConfigConstants.ADMIN_AUTHORITY;
-//        } else if (user.getAuthorities().contains(ConfigConstants.ROLE_USER)) {
-//            return ConfigConstants.USER_AUTHORITY;
-//        }
-        return new ArrayList<>();
+        UserInfo userInfo = user.getUser();
+        return userInfo.getAuthorities();
     }
 
     /**

+ 1 - 1
src/main/java/com/yaoxiang/diagnosis/dao/PaperCommitRepo.java

@@ -20,7 +20,7 @@ public interface PaperCommitRepo extends JpaRepository<PaperCommit, Long> {
 
     boolean existsByPidAndUid(Long pid, Long uid);
 
-    PaperCommit findByPidAndUid(Long pid, Long uid);
+    List<PaperCommit> findByPidAndUidOrderByCreatetimeDesc(Long pid, Long uid);
 
     boolean existsByCode(String code);
 }

+ 1 - 1
src/main/java/com/yaoxiang/diagnosis/dao/PaperResultRepo.java

@@ -15,7 +15,7 @@ import java.util.List;
 @Repository
 public interface PaperResultRepo extends JpaRepository<PaperResult, Long> {
 
-    PaperResult findByPidAndUid(Long pid, Long uid);
+    List<PaperResult> findByPidAndUidOrderByCreatetimeDesc(Long pid, Long uid);
 
     int deleteByPidAndUid(Long pid, Long uid);
 

+ 2 - 0
src/main/java/com/yaoxiang/diagnosis/dao/SpecialKnowledgeRepo.java

@@ -12,4 +12,6 @@ public interface SpecialKnowledgeRepo extends JpaRepository<SpecialKnowledge,Lon
     List<SpecialKnowledge> findByGrade(String grade);
 
     List<SpecialKnowledge> findBySubjectIdAndGrade(Long subjectId,String grade);
+
+    List<SpecialKnowledge> findByPid(Long pid);
 }

+ 14 - 0
src/main/java/com/yaoxiang/diagnosis/dao/SpecialMindRepo.java

@@ -0,0 +1,14 @@
+package com.yaoxiang.diagnosis.dao;
+
+import com.yaoxiang.diagnosis.entity.SpecialMind;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+public interface SpecialMindRepo extends JpaRepository<SpecialMind,Long> {
+
+    List<SpecialMind> findBySubjectIdAndGrade(Long subjectId,String grade);
+
+    List<SpecialMind> findByPid(Long pid);
+
+}

+ 12 - 0
src/main/java/com/yaoxiang/diagnosis/entity/Authority.java

@@ -1,5 +1,7 @@
 package com.yaoxiang.diagnosis.entity;
 
+import io.swagger.annotations.ApiModelProperty;
+
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
@@ -11,6 +13,8 @@ public class Authority {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
     private String name;
+    @ApiModelProperty("权限类型 function business ")
+    private String type;
     private String des;
 
     public Long getId() {
@@ -29,6 +33,14 @@ public class Authority {
         this.name = name;
     }
 
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
     public String getDes() {
         return des;
     }

+ 11 - 0
src/main/java/com/yaoxiang/diagnosis/entity/PaperResult.java

@@ -4,6 +4,7 @@ import com.yaoxiang.diagnosis.model.AbilityEvaluateVo;
 import com.yaoxiang.diagnosis.model.AnswerContrast;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
 import org.hibernate.annotations.CreationTimestamp;
 
 import javax.persistence.*;
@@ -29,6 +30,8 @@ public class PaperResult {
     private Long uid;
     @Column(nullable = false)
     private Long pid;
+    @ApiModelProperty("commitId")
+    private Long cid;
 
     @ApiModelProperty("试卷编号")
     private String code;
@@ -257,6 +260,14 @@ public class PaperResult {
         this.pid = pid;
     }
 
+    public Long getCid() {
+        return cid;
+    }
+
+    public void setCid(Long cid) {
+        this.cid = cid;
+    }
+
     public Date getCreatetime() {
         return createtime;
     }

+ 9 - 0
src/main/java/com/yaoxiang/diagnosis/entity/Role.java

@@ -14,6 +14,7 @@ public class Role {
     private Long id;
     @Column(unique = true, nullable = false)
     private String name;
+    private String code;
     //预留
     private String type;
 
@@ -34,6 +35,14 @@ public class Role {
         this.id = id;
     }
 
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
     public String getName() {
         return name;
     }

+ 30 - 5
src/main/java/com/yaoxiang/diagnosis/entity/SpecialKnowledge.java

@@ -35,7 +35,7 @@ public class SpecialKnowledge {
     @ApiModelProperty("知识点内容")
     private String content;
 
-    @ApiModelProperty("掌握等级 掌握 理解 应用")
+    @ApiModelProperty("认识等级 red yellow green")
     private String masterLevel;
 
     @ApiModelProperty("父Id")
@@ -57,7 +57,7 @@ public class SpecialKnowledge {
     @ApiModelProperty("掌握率")
     private Double master = 100.0;
     @Transient
-    @ApiModelProperty("掌握情况")
+    @ApiModelProperty("掌握情况 掌握 未掌握 ")
     private String masterStatus = Constants.SPECIAL_KNOWLEDGE_MASTER;
 
     @Transient
@@ -74,6 +74,13 @@ public class SpecialKnowledge {
     @Transient
     private List<SpecialKnowledge> children;
 
+//    @Transient
+    @ApiModelProperty("该知识点所在的试卷")
+    private Long pid;
+//    @Transient
+    @ApiModelProperty("该知识点指向的题号 以,隔开")
+    private String qids;
+
     public Long getId() {
         return id;
     }
@@ -194,13 +201,31 @@ public class SpecialKnowledge {
         this.collectNum = collectNum;
     }
 
+    public Long getPid() {
+        return pid;
+    }
+
+    public void setPid(Long pid) {
+        this.pid = pid;
+    }
+
+    public String getQids() {
+        return qids;
+    }
+
+    public void setQids(String qids) {
+        this.qids = qids;
+    }
+
     @Override
     public String toString() {
         return "SpecialKnowledge{" +
-                "level=" + level +
-                ", code='" + code + '\'' +
+                "id=" + id +
+                ", level=" + level +
                 ", content='" + content + '\'' +
-                ", parentId=" + parentId +
+                ", questionNum=" + questionNum +
+                ", collectNum=" + collectNum +
+                ", qids='" + qids + '\'' +
                 '}';
     }
 }

+ 121 - 0
src/main/java/com/yaoxiang/diagnosis/entity/SpecialMind.java

@@ -0,0 +1,121 @@
+package com.yaoxiang.diagnosis.entity;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.persistence.*;
+
+@Entity
+@ApiModel
+public class SpecialMind {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @ApiModelProperty("跟第几步对应,排序用")
+    private Integer sort;
+    @ApiModelProperty("第几步")
+    private String step;
+    @ApiModelProperty("问题")
+    private String content;
+    private Long pid;
+    private Long subjectId;
+    private String grade;
+    private String qids;
+    @Transient
+    @ApiModelProperty("是否有错题")
+    private Boolean mistake;
+    @Transient
+    private Integer collectNum;
+    @Transient
+    private Integer questionNum;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Integer getSort() {
+        return sort;
+    }
+
+    public void setSort(Integer sort) {
+        this.sort = sort;
+    }
+
+    public String getStep() {
+        return step;
+    }
+
+    public void setStep(String step) {
+        this.step = step;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public Long getPid() {
+        return pid;
+    }
+
+    public void setPid(Long pid) {
+        this.pid = pid;
+    }
+
+    public Long getSubjectId() {
+        return subjectId;
+    }
+
+    public void setSubjectId(Long subjectId) {
+        this.subjectId = subjectId;
+    }
+
+    public String getGrade() {
+        return grade;
+    }
+
+    public void setGrade(String grade) {
+        this.grade = grade;
+    }
+
+    public String getQids() {
+        return qids;
+    }
+
+    public void setQids(String qids) {
+        this.qids = qids;
+    }
+
+    public Boolean getMistake() {
+        return mistake;
+    }
+
+    public void setMistake(Boolean mistake) {
+        this.mistake = mistake;
+    }
+
+    public Integer getCollectNum() {
+        return collectNum;
+    }
+
+    public void setCollectNum(Integer collectNum) {
+        this.collectNum = collectNum;
+    }
+
+    public Integer getQuestionNum() {
+        return questionNum;
+    }
+
+    public void setQuestionNum(Integer questionNum) {
+        this.questionNum = questionNum;
+    }
+}

+ 9 - 0
src/main/java/com/yaoxiang/diagnosis/model/PaperResultVo.java

@@ -17,6 +17,7 @@ public class PaperResultVo {
     private String uname;
     private String username;
     private String region;
+    private Long cid;
 
     public Long getId() {
         return id;
@@ -121,4 +122,12 @@ public class PaperResultVo {
     public void setRegion(String region) {
         this.region = region;
     }
+
+    public Long getCid() {
+        return cid;
+    }
+
+    public void setCid(Long cid) {
+        this.cid = cid;
+    }
 }

+ 10 - 0
src/main/java/com/yaoxiang/diagnosis/model/PaperVo.java

@@ -20,6 +20,8 @@ public class PaperVo {
     private Long typeId;
     @ApiModelProperty("科目类别Id 2")
     private Long subjectId;
+    @ApiModelProperty
+    private Boolean useAbility;
 
     public String getName() {
         return name;
@@ -84,4 +86,12 @@ public class PaperVo {
     public void setSubjectId(Long subjectId) {
         this.subjectId = subjectId;
     }
+
+    public Boolean getUseAbility() {
+        return useAbility;
+    }
+
+    public void setUseAbility(Boolean useAbility) {
+        this.useAbility = useAbility;
+    }
 }

+ 8 - 0
src/main/java/com/yaoxiang/diagnosis/model/SpecialKnowledgeVo.java

@@ -0,0 +1,8 @@
+package com.yaoxiang.diagnosis.model;
+
+public class SpecialKnowledgeVo {
+
+    private Long id;
+    private Integer collectNum;
+    private Integer questionNum;
+}

+ 59 - 0
src/main/java/com/yaoxiang/diagnosis/model/SpecialMindVo.java

@@ -0,0 +1,59 @@
+package com.yaoxiang.diagnosis.model;
+
+import com.yaoxiang.diagnosis.entity.SpecialMind;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.List;
+
+@ApiModel
+public class SpecialMindVo {
+    @ApiModelProperty("达成率")
+    private Double master;
+    private Integer sort;
+    @ApiModelProperty("第几部")
+    private String step;
+    private List<SpecialMind> minds;
+    @ApiModelProperty("涂色 yellow green red")
+    private String masterStatus;
+
+    public Double getMaster() {
+        return master;
+    }
+
+    public void setMaster(Double master) {
+        this.master = master;
+    }
+
+    public Integer getSort() {
+        return sort;
+    }
+
+    public void setSort(Integer sort) {
+        this.sort = sort;
+    }
+
+    public String getStep() {
+        return step;
+    }
+
+    public void setStep(String step) {
+        this.step = step;
+    }
+
+    public List<SpecialMind> getMinds() {
+        return minds;
+    }
+
+    public void setMinds(List<SpecialMind> minds) {
+        this.minds = minds;
+    }
+
+    public String getMasterStatus() {
+        return masterStatus;
+    }
+
+    public void setMasterStatus(String masterStatus) {
+        this.masterStatus = masterStatus;
+    }
+}

+ 13 - 2
src/main/java/com/yaoxiang/diagnosis/service/CommitService.java

@@ -5,12 +5,14 @@ import com.yaoxiang.diagnosis.dao.PaperCommitRepo;
 import com.yaoxiang.diagnosis.dao.QuestionRepo;
 import com.yaoxiang.diagnosis.dao.ReportRepo;
 import com.yaoxiang.diagnosis.entity.*;
+import com.yaoxiang.diagnosis.model.AuthUser;
 import com.yaoxiang.diagnosis.util.CodeUtil;
 import com.yaoxiang.diagnosis.util.CommonUtil;
 import com.yaoxiang.diagnosis.util.ObjectUtil;
 import com.yaoxiang.diagnosis.model.Answer;
 import com.yaoxiang.diagnosis.model.QuestionDetail;
 import com.yaoxiang.diagnosis.model.Result;
+import com.yaoxiang.diagnosis.util.SecurityUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -165,11 +167,20 @@ public class CommitService {
         return paperCommitRepo.findByPidOrNameContaining(pid, name);
     }
 
-    public PaperCommit getPaperCommit(Long pid, Long uid) {
-        return paperCommitRepo.findByPidAndUid(pid, uid);
+    public List<PaperCommit> getPaperCommit(Long pid, Long uid) {
+        return paperCommitRepo.findByPidAndUidOrderByCreatetimeDesc(pid, uid);
+    }
+
+    public PaperCommit findByCommit(Long commitId) {
+        return paperCommitRepo.getOne(commitId);
     }
 
     public boolean hasCommit(Long pid, Long uid) {
+        //增加权限校验
+        AuthUser user = SecurityUtil.getCurrentUser();
+        if (user.getUser().getAuthorities().contains("重复提交")) {
+            return false;
+        }
         return paperCommitRepo.existsByPidAndUid(pid, uid);
     }
 

+ 4 - 2
src/main/java/com/yaoxiang/diagnosis/service/OptionService.java

@@ -31,7 +31,8 @@ public class OptionService {
         }
         option.setUpdatetime(new Date());
         option.setCreatetime(new Date());
-        return new Result(optionRepo.save(option) != null);
+        optionRepo.save(option);
+        return Result.ok();
     }
 
     public Result updateOption(QuestionOption option) {
@@ -42,7 +43,8 @@ public class OptionService {
             return new Result(false, "编辑选项不能没有题目id");
         }
         option.setUpdatetime(new Date());
-        return new Result(optionRepo.saveAndFlush(option) != null);
+        optionRepo.saveAndFlush(option);
+        return Result.ok();
     }
 
     public List<QuestionOption> listOptionByQuestion(Question question) {

+ 17 - 9
src/main/java/com/yaoxiang/diagnosis/service/PaperResultService.java

@@ -56,9 +56,9 @@ public class PaperResultService {
     private static final Logger logger = LoggerFactory.getLogger(PaperResultService.class);
 
     public Result parseResult(Long pid, Long uid) {
-        PaperCommit commit = paperCommitRepo.findByPidAndUid(pid, uid);
+        List<PaperCommit> commit = paperCommitRepo.findByPidAndUidOrderByCreatetimeDesc(pid, uid);
         Paper paper = paperService.getOnePaper(pid);
-        return parseResult(commit, paper);
+        return parseResult(commit.get(0), paper);
     }
 
     @SuppressWarnings("unchecked")
@@ -69,10 +69,12 @@ public class PaperResultService {
         Map<Integer, Answer> mapAnswers = answers.stream().collect(Collectors.toMap(Answer::getNumber, Function.identity()));
         List<Integer> collectQuestion = new ArrayList<>();
         PaperResult result = new PaperResult();
+        result.setCid(paperCommit.getId());
         result.setPid(paperCommit.getPid());
         result.setName(paperCommit.getName());
         result.setUid(paperCommit.getUid());
         result.setCode(paperCommit.getCode());
+        logger.info("commit paper,pid={},uid={},answer={}", paperCommit.getPid(), paperCommit.getUid(), paperCommit.getJsonAns());
 //        result.setScore(0d);
 //        result.setJsonScore("");
 //        result.setCollectQuestion("");
@@ -92,6 +94,7 @@ public class PaperResultService {
 //            Answer a = answers.stream().filter(answer -> answer.getNumber() == q.getNumber())
 //                    .findFirst().orElse(null);
             Answer a = mapAnswers.getOrDefault(q.getNumber(), null);
+            logger.info("number={},answer={},options={}", q.getNumber(), ans, a.getOptions());
             if (a == null || StringUtils.isBlank(a.getOptions())) {
                 String options = a == null ? "" : a.getOptions();
                 Long useTime = a == null ? 0L : a.getUseTime() == null ? 0L : a.getUseTime();
@@ -119,17 +122,24 @@ public class PaperResultService {
         }
         //对的选项进行升序排序
         collectQuestion.sort(Integer::compareTo);
+        logger.info("collect question={}", collectQuestion);
+        logger.info("answer contrasts={}", contrasts);
         result.setWrongAnswerContrast(ObjectUtil.object2Json(contrasts));
         result.setCollectQuestion(StringUtils.join(collectQuestion, ","));
         //错误选项
         List<Integer> wrongQuestions = generateWrongQuestion(paper, collectQuestion);
+        logger.info("wrong question={}", wrongQuestions);
         result.setWrongQuestion(StringUtils.join(wrongQuestions, ","));
         result.setJsonScore(ObjectUtil.object2Json(pData));
         //转换分数为百分制
         double totalScore = paper.getTotalScore();
+        if (totalScore == 0) {
+            logger.error("总分数为0,请检查试卷");
+            return Result.fail("提交失败,请重试");
+        }
         double s = NumberUtil.format(score * 100 / totalScore);
         result.setScore(totalScore == 0 ? score : s);
-        result.setTotalScore(totalScore);
+        result.setTotalScore(100.0d);
         paperResultRepo.save(result);
         logger.info("答案分析保存成功,pid={},uid={},name={},score={},collectQuestion={}", paper.getId(),
                 paperCommit.getUid(), paperCommit.getName(), result.getScore(), result.getCollectQuestion());
@@ -144,8 +154,8 @@ public class PaperResultService {
         return paperResultRepo.getOne(resultId);
     }
 
-    public PaperResult findByPidAndUid(Long pid, Long uid) {
-        return paperResultRepo.findByPidAndUid(pid, uid);
+    public List<PaperResult> findByPidAndUid(Long pid, Long uid) {
+        return paperResultRepo.findByPidAndUidOrderByCreatetimeDesc(pid, uid);
     }
 
     public int delete(Long pid, Long uid) {
@@ -160,7 +170,7 @@ public class PaperResultService {
     }
 
     public void globalResult(PaperResult r) {
-        PaperCommit commit = paperCommitRepo.findByPidAndUid(r.getPid(), r.getUid());
+        PaperCommit commit = paperCommitRepo.findByPidAndUidOrderByCreatetimeDesc(r.getPid(), r.getUid()).get(0);
         Paper paper = paperService.getOnePaper(r.getPid());
         //知识点掌握率
         r.setKnowledgeRate(knowledgeRate(r, paper));
@@ -681,9 +691,7 @@ public class PaperResultService {
             return paperResultRepo.findByUidOrderByCreatetimeDesc(uid);
         }
         if (uid != null) {
-            return new ArrayList<PaperResult>() {{
-                add(paperResultRepo.findByPidAndUid(pid, uid));
-            }};
+            return paperResultRepo.findByPidAndUidOrderByCreatetimeDesc(pid, uid);
         }
         return paperResultRepo.findByPidOrderByCreatetimeDesc(pid);
     }

+ 156 - 99
src/main/java/com/yaoxiang/diagnosis/service/PaperService.java

@@ -5,11 +5,13 @@ import com.yaoxiang.diagnosis.dao.PaperRepo;
 import com.yaoxiang.diagnosis.dao.QuestionRepo;
 import com.yaoxiang.diagnosis.dao.RemarkTemplateRepo;
 import com.yaoxiang.diagnosis.entity.*;
+import com.yaoxiang.diagnosis.model.AuthUser;
 import com.yaoxiang.diagnosis.util.CommonUtil;
 import com.yaoxiang.diagnosis.util.ObjectUtil;
 import com.yaoxiang.diagnosis.config.Constants;
 import com.yaoxiang.diagnosis.model.PaperVo;
 import com.yaoxiang.diagnosis.model.Result;
+import com.yaoxiang.diagnosis.util.SecurityUtil;
 import com.yaoxiang.diagnosis.word.WordService;
 import com.yaoxiang.diagnosis.word.WordUtil;
 import org.apache.commons.lang3.StringUtils;
@@ -66,8 +68,13 @@ public class PaperService {
     private static final Logger logger = LoggerFactory.getLogger(PaperService.class);
 
     public List<Paper> listPapers(Long subjectId, Integer status) {
+        AuthUser user = SecurityUtil.getCurrentUser();
         Sort sort = new Sort(Sort.Direction.DESC, "updatetime");
         List<Paper> papers = paperRepo.findAll(sort);
+        if (Constants.USER_TYPE_STUDENT.equals(user.getUser().getUserType())
+                && !user.getUser().getAuthorities().contains("重复提交")) {
+            papers = papers.stream().filter(p -> p.getGrade().contains(user.getUser().getGrade())).collect(Collectors.toList());
+        }
         if (subjectId != null) {
             papers = papers.stream().filter(p -> p.getSubjectId() == subjectId.longValue())
                     .collect(Collectors.toList());
@@ -89,43 +96,57 @@ public class PaperService {
         return papers;
     }
 
-    public Paper getOnePaper(Long id) {
-        Paper paper = paperRepo.getOne(id);
+    public Paper getOneWithAuth(Long id) {
+        AuthUser user = SecurityUtil.getCurrentUser();
+        boolean student = Constants.USER_TYPE_STUDENT.equals(user.getUser().getUserType());
+        Paper paper = paperRepo.findById(id).orElse(null);
         if (paper == null || paper.getStatus() == Constants.NOTREADY) {
             return null;
         }
         List<Question> questions = questionRepo.findByPidOrderBySectionAscNumberAsc(id);
         List<Section> sections = sectionService.findByPid(id);
         paper.setSections(sections);
-//        questions.sort((q1, q2) -> {
-//            if (q1.getSection() < q2.getSection()) {
-//                return -1;
-//            } else if (q1.getSection() > q2.getSection()) {
-//                return 1;
-//            }
-//            if (q1.getNumber() < q2.getNumber()) {
-//                return -1;
-//            } else if (q1.getNumber() > q2.getNumber()) {
-//                return 1;
-//            }
-//            return 0;
-//        });
-        paper.setQuestions(questions);
+//        paper.setQuestions(questions);
         List<Long> qids = questions.stream().map(Question::getId).collect(Collectors.toList());
         //一次查出该试卷所有的选项
         List<QuestionOption> options = optionRepo.findByQidIn(qids);
         //然后根据Id进行分组
+        List<Question> qs = new ArrayList<>();
         Map<Long, List<QuestionOption>> group = options.stream().collect(Collectors.groupingBy(QuestionOption::getQid));
         for (Question question : questions) {
-//            List<QuestionOption> options = optionRepo.findByQid(question.getId());
-//            for (QuestionOption option : options) {
-            //todo 判断是否考生,如是  将答案设为null
-//               option.setCorrect(null);
-//                option.setUpdatetime(null);
-//                option.setCreatetime(null);
-//            }
-            question.setOptions(group.get(question.getId()));
+            Question q = ObjectUtil.convert(question, Question.class);
+            List<QuestionOption> optionList = group.get(question.getId());
+            List<QuestionOption> os = new ArrayList<>();
+            //学生要去掉答案
+            if (student) {
+                q.setCorrectNum(0);
+                q.setAnswer(null);
+                //避免自动持久化
+                for (QuestionOption o : optionList) {
+                    QuestionOption option = new QuestionOption();
+                    option.setId(o.getId());
+                    option.setContent(o.getContent());
+                    option.setOindex(o.getOindex());
+                    option.setQid(o.getQid());
+                    os.add(option);
+                }
+                q.setOptions(os);
+            } else {
+                q.setOptions(optionList);
+            }
+            qs.add(q);
+        }
+        paper.setQuestions(qs);
+        return paper;
+    }
+
+    public Paper getOnePaper(Long id) {
+        Paper paper = paperRepo.findById(id).orElse(null);
+        if (paper == null || paper.getStatus() == Constants.NOTREADY) {
+            return null;
         }
+        List<Question> questions = questionRepo.findByPidOrderBySectionAscNumberAsc(id);
+        paper.setQuestions(questions);
         return paper;
     }
 
@@ -155,10 +176,6 @@ public class PaperService {
         }
         //init json score
         Map<String, Double> data = new HashMap<>();
-        List<SubjectAbility> abilities = subjectAbilityService.list(paper.getSubjectId());
-        //初始化数据
-        abilities.forEach(a -> data.put(a.getCode(), 0d));
-        data.put("A0", 0d);
         double totalScore = 0;
         for (Question question : save.getQuestions()) {
             question.setPid(save.getId());
@@ -176,18 +193,21 @@ public class PaperService {
                 abilityScoreService.add(score);
             }
         }
+
         for (Section section : save.getSections()) {
             section.setPid(save.getId());
             //保存段落
             sectionService.add(section);
         }
         //不使用能力计分,并且能力数量大于0
-        if (!paper.getUseAbility() && abilities.size() > 0) {
-            //put第一个能力进去
-            data.put(abilities.get(0).getCode(), (double) paper.getQuestions().size());
+        if (!paper.getUseAbility()) {
+            //put一个A0能力进去
+            data.put("A0", (double) paper.getQuestions().size());
+            paper.setTotalScore(paper.getQuestionNum());
+        } else {
+            paper.setTotalScore((int) totalScore);
         }
         String jsonScore = ObjectUtil.object2Json(data);
-        paper.setTotalScore((int) totalScore);
         paper.setJsonScore(jsonScore);
         paperRepo.saveAndFlush(paper);
         logger.info("试卷增加成功");
@@ -206,7 +226,8 @@ public class PaperService {
 
     public Result update(Paper paper) {
         paper.setUpdatetime(new Date());
-        return new Result(paperRepo.saveAndFlush(paper) != null);
+        paperRepo.saveAndFlush(paper);
+        return Result.ok();
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -254,72 +275,43 @@ public class PaperService {
 //        return Result.ok(paper);
     }
 
-    private Map<String, List<XWPFParagraph>> initSections(Paper paper, String sectionPattern, String questionPattern, String picturePattern, List<XWPFParagraph> paragraphs) {
-        //保证顺序
-        Map<String, List<XWPFParagraph>> sections = new LinkedHashMap<>();
-        String tag = "";
-        boolean betweenSectionAndQuestion = false;
-        StringBuilder material = new StringBuilder();
-        int section = 0;
-        List<Section> sectionList = new ArrayList<>();
-        logger.info("initSections start");
-        boolean hasFormula = false;
-        for (XWPFParagraph paragraph : paragraphs) {
-            String text = paragraph.getText();
-            //此处应判断下是否有照片跟图片
-            if (WordUtil.notContent(paragraph, text)) {
-                continue;
-            }
-            //下一个section
-            if (text.matches(sectionPattern)) {
-                logger.info("match section: text is {} sectionPattern is {}", text, sectionPattern);
-                Matcher matcher = Pattern.compile("\\d+").matcher(text);
-                //获取到section编号
-                if (matcher.find()) {
-                    section = Integer.parseInt(matcher.group());
-                }
-                //1 2 3
-                tag = String.valueOf(section);
-                betweenSectionAndQuestion = true;
-                continue;
-            }
-            if (betweenSectionAndQuestion && text.matches(questionPattern)) {
-                Section s = initSection(section, material.toString());
-                sectionList.add(s);
-                //清空背景材料
-                material = new StringBuilder();
-                betweenSectionAndQuestion = false;
-            }
-            //Session后面可能有背景材料,背景材料里面可能有图片和公式,这个放后面来处理
-            if (betweenSectionAndQuestion) {
-                //解析背景材料的图片和公式
-                wordService.parsePicture(paragraph, picturePattern);
-                hasFormula = wordService.parseFormula(paragraph);
-                material.append("<p>").append(paragraph.getText()).append("</p>");
-            }
-            //此处可能是第一段
-            if (StringUtils.isNotBlank(tag)) {
-                List<XWPFParagraph> list = sections.getOrDefault(tag, new ArrayList<>());
-                list.add(paragraph);
-                sections.put(tag, list);
-            }
+    @Transactional(rollbackFor = Exception.class)
+    public Result uploadPaperTest(PaperVo paperVo, Long templateId, String url, byte[] data) {
+        Paper paper = init(paperVo, url);
+        paper.setRemark(remarkTemplateRepo.getOne(paperVo.getRemarkId()).getRemark());
+        XWPFDocument document = WordUtil.open(data);
+        PaperTemplate template = paperTemplateService.getOrDefault(templateId);
+        if (template == null) {
+            return Result.fail(String.format("未找到试卷模板Id为 %s 的模板", templateId));
         }
-        paper.setSections(sectionList);
-        logger.info("initSections end,sections num is {}", sectionList.size());
-        return sections;
+        logger.info("parsing paper,url is {}", url);
+        parsePaper(paper, template, document);
+        logger.info("parse paper finished,url is {}", url);
+        paper.setStatus(1);
+        paper.setTotalScore(100);
+        paper.setQuestionNum(paper.getQuestions().size());
+        paper.setDuration(paper.getQuestionNum() * 2);
+        //TODO 这里要根据实际情况改
+//        paper.setSectionDurations("100,20,20");
+//        paper.setSectionRests("2,2,2");
+//        paper.setSectionNums("50,10,10");
+        WordUtil.close(document);
+        //TODO due ability score
+        //TODO convert parse exception to reason
+        //TODO use parallel
+//        Result<Paper> paperResult = add(paper);
+//        return addWithQuestion(paper);
+        paper.getQuestions().sort(Comparator.comparingInt(Question::getNumber));
+        return Result.ok(paper);
     }
 
     private void parsePaper(Paper paper, PaperTemplate template, XWPFDocument document) {
-        String tagPattern = template.getSection();
-        String questionPattern = template.getQuestion();
-        String picturePattern = template.getPicturePattern();
         List<XWPFParagraph> paragraphs = document.getParagraphs();
         Assert.notEmpty(paragraphs, "未检测到段落,请检查上传的文档");
         String name = paragraphs.get(0).getText();
-        //TODO check name of paper
         parsePaperName(paper, name, template);
         //获取模块,根据模块,给段落分组
-        Map<String, List<XWPFParagraph>> sections = initSections(paper, tagPattern, questionPattern, picturePattern, paragraphs);
+        Map<String, List<XWPFParagraph>> sections = initSections(paper, template, paragraphs);
         Assert.notEmpty(sections, "未检测到模块,请检查上传的文档");
 //        List<String> topics = paperTemplateService.getTopic(template);
         Map<String, String> topic = paperTemplateService.getMapTopic(template);
@@ -338,9 +330,9 @@ public class PaperService {
 //            Section current = ss.stream().filter(section -> s.contains(section.getNumber().toString())).findFirst().orElse(null);
             Section current = sectionMap.get(s);
             //根据题目标签,给题目分组
-            Map<String, List<XWPFParagraph>> questions = initQuestions(current, questionPattern, ps);
+            Map<String, List<XWPFParagraph>> questions = initQuestions(current, template, ps);
             current.setStartNumber(currentNumber);
-            List<Question> list = parseQuestions(questions, current, template, topic, abilities);
+            List<Question> list = parseQuestions(questions, current, template, topic, paper.getUseAbility(), abilities);
             current.setNums(list.size());
             currentNumber = currentNumber + list.size();
             qs.put(s, list);
@@ -369,12 +361,69 @@ public class PaperService {
             paper.setGrade(g + (first ? "X" : "Y"));
             sb.append(g).append("年级").append(first ? "上学期" : "下学期");
         }
-        boolean A = name.endsWith("A");
-        sb.append(A ? "A卷" : "B卷");
+        //取最后一个字为卷,一般为A、B卷
+        sb.append(name.substring(name.length() - 1)).append("卷");
         paper.setName(sb.toString());
     }
 
-    private List<Question> parseQuestions(Map<String, List<XWPFParagraph>> questions, Section section, PaperTemplate template, Map<String, String> topic, List<String> abilities) {
+    private Map<String, List<XWPFParagraph>> initSections(Paper paper, PaperTemplate template, List<XWPFParagraph> paragraphs) {
+        //保证顺序
+        Map<String, List<XWPFParagraph>> sections = new LinkedHashMap<>();
+        String tag = "";
+        boolean betweenSectionAndQuestion = false;
+        logger.info("sectionPattern is {},questionPattern is {}", template.getSection(), template.getQuestion());
+        StringBuilder material = new StringBuilder();
+        int section = 0;
+        List<Section> sectionList = new ArrayList<>();
+        logger.info("initSections start");
+        boolean hasFormula = false;
+        for (XWPFParagraph paragraph : paragraphs) {
+            String text = paragraph.getText();
+            //此处应判断下是否有图片、文字或者公式
+            if (WordUtil.notContent(paragraph, text)) {
+                continue;
+            }
+            //下一个section
+            if (text.matches(template.getSection())) {
+                logger.info("match section: text is {} sectionPattern is {}", text, template.getSection());
+                Matcher matcher = Pattern.compile("\\d+").matcher(text);
+                //获取到section编号
+                if (matcher.find()) {
+                    section = Integer.parseInt(matcher.group());
+                }
+                //1 2 3
+                tag = String.valueOf(section);
+                betweenSectionAndQuestion = true;
+                continue;
+            }
+            if (betweenSectionAndQuestion && text.matches(template.getQuestion())) {
+                Section s = initSection(section, material.toString());
+                sectionList.add(s);
+                //清空背景材料
+                material = new StringBuilder();
+                betweenSectionAndQuestion = false;
+            }
+            //Session后面可能有背景材料,背景材料里面可能有图片和公式,这个放后面来处理
+            if (betweenSectionAndQuestion) {
+                //解析背景材料的图片和公式
+                wordService.parseSubScript(paragraph);
+                wordService.parsePicture(paragraph, template.getPicturePattern());
+                hasFormula = wordService.parseFormula(paragraph);
+                material.append("<p>").append(paragraph.getText()).append("</p>");
+            }
+            //此处可能是第一段
+            if (StringUtils.isNotBlank(tag)) {
+                List<XWPFParagraph> list = sections.getOrDefault(tag, new ArrayList<>());
+                list.add(paragraph);
+                sections.put(tag, list);
+            }
+        }
+        paper.setSections(sectionList);
+        logger.info("initSections end,sections num is {}", sectionList.size());
+        return sections;
+    }
+
+    private List<Question> parseQuestions(Map<String, List<XWPFParagraph>> questions, Section section, PaperTemplate template, Map<String, String> topic, Boolean useAbility, List<String> abilities) {
         List<Question> list = new ArrayList<>();
         //问题合集
         Pattern pattern = Pattern.compile("\\d+");
@@ -382,15 +431,15 @@ public class PaperService {
             Matcher matcher = pattern.matcher(k);
             if (k.matches(template.getQuestion()) && matcher.find()) {
                 String code = matcher.group();
-                Question question = questionService.initQuestion(section.getNumber(), section.getStartNumber(), Integer.valueOf(code));
-                wordService.parseQuestion(question, v, topic, template, abilities);
+                Question question = questionService.initQuestion(section.getNumber(), section.getStartNumber(), Integer.valueOf(code), useAbility);
+                wordService.parseQuestion(question, v, topic, template, useAbility);
                 list.add(question);
             }
         });
         return list;
     }
 
-    private Map<String, List<XWPFParagraph>> initQuestions(Section section, String questionPattern, List<XWPFParagraph> ps) {
+    private Map<String, List<XWPFParagraph>> initQuestions(Section section, PaperTemplate paperTemplate, List<XWPFParagraph> ps) {
         Map<String, List<XWPFParagraph>> questions = new ConcurrentHashMap<>();
         String tag = "";
         for (XWPFParagraph paragraph : ps) {
@@ -398,9 +447,17 @@ public class PaperService {
             if (WordUtil.notContent(paragraph, text)) {
                 continue;
             }
+            //识别上下标
+            wordService.parseSubScript(paragraph);
+            //识别图片
+            wordService.parsePicture(paragraph, paperTemplate.getPicturePattern());
+            //识别公式
+            wordService.parseFormula(paragraph);
+            //重新获取text
+            text = paragraph.getText();
             //下一个question
             // questionPattern ^#[A-Z]#(.*)
-            if (text.matches(questionPattern)) {
+            if (text.matches(paperTemplate.getQuestion())) {
                 tag = text;
             }
             logger.info("initQuestions,current tag is {},current text is {}", tag, text);

+ 17 - 12
src/main/java/com/yaoxiang/diagnosis/service/QuestionService.java

@@ -49,7 +49,7 @@ public class QuestionService {
     public Result updateQuestion(Question question) {
         Long id = question.getId();
         if (id == null) {
-            return new Result(false);
+            return Result.fail("未找到该题目Id");
         }
         question.setUpdatetime(new Date());
         for (QuestionOption option : question.getOptions()) {
@@ -65,7 +65,8 @@ public class QuestionService {
                 }
             }
         }
-        return new Result(questionRepo.saveAndFlush(question) != null);
+        questionRepo.saveAndFlush(question);
+        return Result.ok();
     }
 
     public List<Question> listQuestionByPaper(Paper paper) {
@@ -109,13 +110,13 @@ public class QuestionService {
         return question == null ? 0 : question.getNumber();
     }
 
-    @Transactional(rollbackFor = Exception.class)
-    public Result parseQuestion(Long pid, Integer section, Integer number, byte[] data) {
-        Question question = initQuestion(pid, section, number);
-        wordService.parseQuestion(question, data);
-        addQuestion(question);
-        return Result.ok(question);
-    }
+//    @Transactional(rollbackFor = Exception.class)
+//    public Result parseQuestion(Long pid, Integer section, Integer number, byte[] data) {
+//        Question question = initQuestion(pid, section, number);
+//        wordService.parseQuestion(question, data);
+//        addQuestion(question);
+//        return Result.ok(question);
+//    }
 
     private Question initQuestion(Long pid, Integer section, Integer number) {
         Question question = new Question();
@@ -131,12 +132,16 @@ public class QuestionService {
         return question;
     }
 
-    public Question initQuestion(Integer section,Integer startNumber, Integer number) {
+    public Question initQuestion(Integer section,Integer startNumber, Integer number,Boolean useAbility) {
         Question question = new Question();
         question.setCreatetime(new Date());
         question.setScore(1D);
-        question.setNumber(startNumber + number);
-        question.setCode(number);
+        question.setNumber(number);
+        if(useAbility == null || !useAbility){
+            question.setJsonScore("{\"A0\":1.0}");
+        }
+        //更改code
+        question.setCode(number - startNumber);
         question.setDuration(60);
         question.setSection(section);
         return question;

+ 178 - 19
src/main/java/com/yaoxiang/diagnosis/service/SpecialKnowledgeService.java

@@ -1,7 +1,10 @@
 package com.yaoxiang.diagnosis.service;
 
 import com.yaoxiang.diagnosis.config.Constants;
+import com.yaoxiang.diagnosis.dao.PaperRepo;
 import com.yaoxiang.diagnosis.dao.SpecialKnowledgeRepo;
+import com.yaoxiang.diagnosis.entity.Paper;
+import com.yaoxiang.diagnosis.entity.Question;
 import com.yaoxiang.diagnosis.entity.SpecialKnowledge;
 import com.yaoxiang.diagnosis.model.Result;
 import com.yaoxiang.diagnosis.util.NumberUtil;
@@ -11,10 +14,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -23,6 +23,8 @@ public class SpecialKnowledgeService {
 
     @Resource
     private SpecialKnowledgeRepo specialKnowledgeRepo;
+    @Resource
+    private PaperService paperService;
 
     private static final Logger logger = LoggerFactory.getLogger(SpecialKnowledgeService.class);
 
@@ -47,6 +49,10 @@ public class SpecialKnowledgeService {
         return specialKnowledgeRepo.findBySubjectId(subjectId);
     }
 
+    public List<SpecialKnowledge> listByPid(Long pid) {
+        return specialKnowledgeRepo.findByPid(pid);
+    }
+
     public List<SpecialKnowledge> toTree(List<SpecialKnowledge> list) {
         List<SpecialKnowledge> treeList = new ArrayList<>();
         for (SpecialKnowledge tree : list) {
@@ -69,45 +75,198 @@ public class SpecialKnowledgeService {
     }
 
     public void calcCount(List<SpecialKnowledge> list) {
-        Map<Integer,List<SpecialKnowledge>> group = list.stream().collect(Collectors.groupingBy(SpecialKnowledge::getLevel));
-        Map<Long,SpecialKnowledge> knowledgeMap = list.stream().collect(Collectors.toMap(SpecialKnowledge::getId,Function.identity()));
+        logger.info("specialKnowledge size = {}", list.size());
+        //根据知识点所在层级分组
+        Map<Integer, List<SpecialKnowledge>> group = list.stream().collect(Collectors.groupingBy(SpecialKnowledge::getLevel));
+        //将list根据Id变成map
+        Map<Long, SpecialKnowledge> knowledgeMap = list.stream().collect(Collectors.toMap(SpecialKnowledge::getId, Function.identity()));
+        //找出最大层级
         int max = group.keySet().stream().max(Comparator.naturalOrder()).orElse(0);
-        if(max ==0){
-            logger.warn("最大层级为0,请检查数据");
+//        Map<Long,>
+        //根据同一个parentId的进行分组
+//        Map<Long, List<SpecialKnowledge>> parentMap = list.stream().filter(k->k.getParentId() != null)
+//                .collect(Collectors.groupingBy(SpecialKnowledge::getParentId));
+
+        if (max == 0) {
+            logger.error("最大层级为0,请检查数据");
+            return;
         }
-        for (int i = max; i>1 ;i--){
+        for (int i = max; i > 1; i--) {
             //全是同一级的
             List<SpecialKnowledge> ss = group.get(i);
-            //找出同一个parentId的
-            Map<Long,List<SpecialKnowledge>> map = ss.stream().collect(Collectors.groupingBy(SpecialKnowledge::getParentId));
+            Map<Long, List<SpecialKnowledge>> parentMap = ss.stream().filter(k -> k.getParentId() != null)
+                    .collect(Collectors.groupingBy(SpecialKnowledge::getParentId));
+
             double rate = 0;
-            for (Map.Entry<Long,List<SpecialKnowledge>> entry:map.entrySet()){
+            for (Map.Entry<Long, List<SpecialKnowledge>> entry : parentMap.entrySet()) {
                 int collectCount = 0;
                 int questionNum = 0;
                 List<SpecialKnowledge> specialKnowledges = entry.getValue();
-                for (SpecialKnowledge s:specialKnowledges){
-                    collectCount+= s.getCollectNum();
+                //如果有值,说明已经统计过了
+                for (SpecialKnowledge s : specialKnowledges) {
+                    collectCount += s.getCollectNum();
                     questionNum += s.getQuestionNum();
                 }
                 //parent 不为null
-                if(specialKnowledges.size() > 0){
+                if (specialKnowledges.size() > 0) {
                     SpecialKnowledge parent = knowledgeMap.get(entry.getKey());
                     parent.setCollectNum(collectCount);
                     parent.setQuestionNum(questionNum);
                     //小于等于层级3
-                    if(i <= 4 && questionNum > 0){
+                    if (i <= 4 && questionNum > 0) {
                         double master = collectCount * 100.0 / questionNum;
+                        logger.info("parent content={},level={},master={},masterStatus={}",
+                                parent.getContent(), parent.getLevel(), parent.getMaster(), parent.getMasterStatus());
                         parent.setMaster(NumberUtil.format(master));
-                        if(master < 0.8){
+                        if (master < 80) {
                             parent.setMasterStatus(Constants.SPECIAL_KNOWLEDGE_UNMASTER);
                         }
                     }
                 }
             }
 
-            if(i >= 3){
-                ss.forEach(s->s.setChildren(null));
+            if (i >= 3) {
+                //剪枝
+                ss.forEach(s -> s.setChildren(null));
+            }
+        }
+    }
+
+    public boolean syncKnowledgeToSpecial(Long subjectId, String grade, Long pid) {
+        List<SpecialKnowledge> list = list(subjectId, grade);
+        Paper paper = paperService.getOnePaper(pid);
+        Map<String, List<Question>> group = paper.getQuestions().stream().collect(Collectors.groupingBy(Question::getTag));
+
+        for (SpecialKnowledge s : list) {
+            s.setPid(pid);
+            //编号不为null 并且 这个知识点有考
+            if (s.getCode() != null && group.get(s.getCode()) != null) {
+                List<Integer> numbers = group.get(s.getCode()).stream().map(Question::getNumber).collect(Collectors.toList());
+                s.setQids(StringUtils.join(numbers, ","));
+            }
+            specialKnowledgeRepo.save(s);
+        }
+        return true;
+    }
+
+    public void calcComplex(List<SpecialKnowledge> list) {
+        int max = list.stream().map(SpecialKnowledge::getLevel).max(Comparator.naturalOrder()).orElse(0);
+        if (max == 0) {
+            logger.error("最大层级为0,请检查数据");
+            return;
+        }
+        Map<Long, SpecialKnowledge> mapper = list.stream().collect(Collectors.toMap(SpecialKnowledge::getId, Function.identity()));
+        List<SpecialKnowledge> ks = list.stream().filter(s -> s.getLevel() == max).collect(Collectors.toList());
+        Map<Long, List<SpecialKnowledge>> parentMap = ks.stream().collect(Collectors.groupingBy(SpecialKnowledge::getParentId));
+        for (Map.Entry<Long, List<SpecialKnowledge>> entry : parentMap.entrySet()) {
+            List<SpecialKnowledge> s = entry.getValue();
+            SpecialKnowledge parent = mapper.get(entry.getKey());
+            //TODO 后续优化这个排序
+            SpecialKnowledge know = null, under = null, usage = null;
+            for (SpecialKnowledge k : s) {
+                switch (k.getContent()) {
+                    case Constants.SPECIAL_MASTER_STATUS_KNOW:
+                        know = k;
+                        break;
+                    case Constants.SPECIAL_MASTER_STATUS_UNDERSTAND:
+                        under = k;
+                        break;
+                    case Constants.SPECIAL_MASTER_STATUS_USAGE:
+                        usage = k;
+                        break;
+                }
             }
+            int weight = calcWeight(know, under, usage,parent);
+            logger.info("当前知识点为parent={}", parent);
+            switch (weight) {
+                case 0:
+                    logger.error("unexpected error,当前知识点没有考试题");
+                    break;
+                case 1:
+                    logger.info("当前知识点只考了认识");
+                    break;
+                case 6:
+                    logger.info("当前知识点考了理解和应用");
+                    if (usage.getMaster() >= 50) {
+                        parent.setMasterLevel("应用");
+                        if (parent.getMaster() >= 75) {
+                            parent.setMasterStatus("green");
+                        } else {
+                            parent.setMasterStatus("yellow");
+                        }
+                        break;
+                    }
+                    //应用小于50
+                    if (under.getMaster() >= 50) {
+                        parent.setMasterLevel("理解");
+                        int collect = under.getCollectNum() + know.getCollectNum();
+                        int questionNum = under.getQuestionNum() + know.getQuestionNum();
+                        if (questionNum == 0) {
+                            logger.error("unexpected error,题目数量为0,认识和理解未考题目");
+                        }
+                        double master = collect * 100.0 / questionNum;
+                        if (master >= 75) {
+                            parent.setMasterStatus("yellow");
+                        } else {
+                            parent.setMasterStatus("red");
+                        }
+                    } else {
+                        //最低评价 理解红色
+                        parent.setMasterLevel("理解");
+                        parent.setMasterStatus("red");
+                    }
+                    break;
+                case 7:
+                    logger.info("当前知识点考了所有题目");
+                    if (usage.getMaster() >= 50) {
+                        parent.setMasterLevel("应用");
+                        if (parent.getMaster() >= 75) {
+                            parent.setMasterStatus("green");
+                        } else {
+                            parent.setMasterStatus("yellow");
+                        }
+                        break;
+                    }
+                    //应用小于50
+                    if (under.getMaster() >= 50) {
+                        parent.setMasterLevel("理解");
+                        int collect = under.getCollectNum() + know.getCollectNum();
+                        int questionNum = under.getQuestionNum() + know.getQuestionNum();
+                        if (questionNum == 0) {
+                            logger.error("unexpected error,题目数量为0,认识和理解未考题目");
+                        }
+                        double master = collect * 100.0 / questionNum;
+                        if (master >= 75) {
+                            parent.setMasterStatus("yellow");
+                        } else {
+                            parent.setMasterStatus("red");
+                        }
+                        break;
+                    }
+                    parent.setMasterLevel("认识");
+                    if (know.getMaster() >= 75) {
+                        parent.setMasterStatus("yellow");
+                    } else {
+                        parent.setMasterStatus("red");
+                    }
+            }
+        }
+    }
+
+    private int calcWeight(SpecialKnowledge know, SpecialKnowledge under, SpecialKnowledge usage,SpecialKnowledge parent) {
+        int a = 1, b = 2, c = 4;
+        if (know == null || StringUtils.isBlank(know.getQids())) {
+            a = 0;
+            logger.warn("未找到认识层级,parent={}", parent.getContent());
+        }
+        if (under == null || StringUtils.isBlank(under.getQids())) {
+            b = 0;
+            logger.warn("未找到理解层级,parent={}", parent.getContent());
+        }
+        if (usage == null || StringUtils.isBlank(usage.getQids())) {
+            c = 0;
+            logger.warn("未找到应用层级,parent={}", parent.getContent());
         }
+        return a + b + c;
     }
 }

+ 29 - 0
src/main/java/com/yaoxiang/diagnosis/service/SpecialMindService.java

@@ -0,0 +1,29 @@
+package com.yaoxiang.diagnosis.service;
+
+import com.yaoxiang.diagnosis.dao.SpecialMindRepo;
+import com.yaoxiang.diagnosis.entity.SpecialMind;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.transaction.Transactional;
+import java.util.List;
+
+@Service
+public class SpecialMindService {
+
+    @Resource
+    private SpecialMindRepo specialMindRepo;
+
+    @Transactional(rollbackOn = Exception.class)
+    public boolean add(List<SpecialMind> list) {
+        for (SpecialMind s : list) {
+            specialMindRepo.save(s);
+        }
+        return true;
+    }
+
+    public List<SpecialMind> findByPid(Long pid){
+        return specialMindRepo.findByPid(pid);
+    }
+
+}

+ 199 - 35
src/main/java/com/yaoxiang/diagnosis/service/SpecialReportService.java

@@ -1,18 +1,22 @@
 package com.yaoxiang.diagnosis.service;
 
+import com.google.gson.reflect.TypeToken;
+import com.yaoxiang.diagnosis.config.Constants;
 import com.yaoxiang.diagnosis.entity.*;
+import com.yaoxiang.diagnosis.model.AnswerContrast;
+import com.yaoxiang.diagnosis.model.SpecialMindVo;
 import com.yaoxiang.diagnosis.util.CommonUtil;
-import io.swagger.models.auth.In;
+import com.yaoxiang.diagnosis.util.NumberUtil;
+import com.yaoxiang.diagnosis.util.ObjectUtil;
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import javax.transaction.Transactional;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 @Service
@@ -30,15 +34,19 @@ public class SpecialReportService {
     @Resource
     private SpecialKnowledgeService specialKnowledgeService;
 
+    @Resource
+    private SpecialMindService specialMindService;
+
     private static final Logger logger = LoggerFactory.getLogger(SpecialReportService.class);
 
     public SpecialResult generate(Long pid, Long uid) {
+        logger.info("正在生成专项诊断报告");
         Paper paper = paperService.getOnePaper(pid);
         if (paper == null) {
             logger.error("未找到试卷 pid={}", pid);
             return null;
         }
-        PaperCommit commit = commitService.getPaperCommit(pid, uid);
+        PaperCommit commit = commitService.getPaperCommit(pid, uid).get(0);
         if (commit == null) {
             logger.error("用户未提交 pid={},uid={}", pid, uid);
             return null;
@@ -46,41 +54,74 @@ public class SpecialReportService {
         return generate(commit, paper);
     }
 
-    @Transactional(rollbackOn = Exception.class)
+    public SpecialResult generate(Long resultId) {
+        logger.info("正在生成专项诊断报告");
+        PaperResult result = paperResultService.get(resultId);
+        if (result == null) {
+            logger.error("未找到报告 paperResultId={}", resultId);
+            return null;
+        }
+        Paper paper = paperService.getOnePaper(result.getPid());
+        if (paper == null) {
+            logger.error("未找到试卷 pid={}", result.getPid());
+            return null;
+        }
+        PaperCommit commit = commitService.findByCommit(result.getCid());
+        if (commit == null) {
+            logger.error("用户未提交 pid={},uid={}", result.getPid(), result.getUid());
+            return null;
+        }
+        return generate(commit, paper);
+    }
+
     public SpecialResult generate(PaperCommit commit, Paper paper) {
-        PaperResult result = paperResultService.findByPidAndUid(commit.getPid(), commit.getUid());
-        List<SpecialKnowledge> list = specialKnowledgeService.list(paper.getSubjectId(), paper.getGrade());
-        //找出叶子节点
-        Map<String, SpecialKnowledge> map = list.stream().filter(s -> s.getCode() != null)
-                .collect(Collectors.toMap(SpecialKnowledge::getCode, Function.identity()));
+        PaperResult result = paperResultService.findByPidAndUid(commit.getPid(), commit.getUid()).get(0);
+        List<SpecialKnowledge> list = specialKnowledgeService.listByPid(paper.getId());
+
         if (CommonUtil.isEmpty(list)) {
             logger.error("未上传专项诊断知识点,subjectId={},grade={}", paper.getSubjectId(), paper.getGrade());
             return null;
         }
         if (result == null) {
+            //重新生成PaperResult
             result = (PaperResult) paperResultService.parseResult(commit, paper).getT();
         }
         String collect = result.getCollectQuestion();
-        List<Integer> collects = Arrays.stream(collect.split(","))
-                .map(Integer::parseInt).collect(Collectors.toList());
-//        String wrong = result.getWrongQuestion();
-//        String wrongs[] = wrong.split(",");
-        List<Question> questions = paper.getQuestions();
-        Map<String, List<Question>> group = questions.stream().collect(Collectors.groupingBy(Question::getTag));
-        for (Map.Entry<String, List<Question>> entry : group.entrySet()) {
-            String code = entry.getKey();
-            List<Question> qs = entry.getValue();
-            SpecialKnowledge knowledge = map.get(code);
-            if (knowledge == null) {
+        //答对的选项
+        List<Long> collects = new ArrayList<>();
+        if (StringUtils.isNotBlank(collect)) {
+            collects = Arrays.stream(collect.split(","))
+                    .map(Long::parseLong).collect(Collectors.toList());
+        }
+        boolean complexMaster = list.stream().anyMatch(s -> Constants.SPECIAL_MASTER_STATUS.contains(s.getContent()));
+
+        for (SpecialKnowledge knowledge : list) {
+            //过滤掉非叶子节点,或者叶子节点为null的知识点
+            if (StringUtils.isBlank(knowledge.getQids())) {
                 continue;
             }
-            knowledge.setQuestionNum(qs.size());
-            knowledge.setCollectNum(getCount(qs, collects));
+            //这个知识点对应的题号
+            Set<Long> number = Arrays.stream(knowledge.getQids().split(","))
+                    .map(Long::parseLong).collect(Collectors.toSet());
+            //该知识点的题目数量
+            knowledge.setQuestionNum(number.size());
+            number.retainAll(collects);
+            knowledge.setCollectNum(number.size());
+            if (knowledge.getQuestionNum() > 0) {
+                double master = knowledge.getCollectNum() * 100.0 / knowledge.getQuestionNum();
+                knowledge.setMaster(NumberUtil.format(master));
+                if (master < 80) {
+                    knowledge.setMasterStatus(Constants.SPECIAL_KNOWLEDGE_UNMASTER);
+                }
+            }
         }
-
-        List<SpecialKnowledge> tree = specialKnowledgeService.toTree(list);
-        //统计结果并且剪枝,剪掉>3的层级
         specialKnowledgeService.calcCount(list);
+        if (complexMaster) {
+            logger.info("计算认识理解应用情况,pid={},grade={},subjectId={}", paper.getId(), paper.getGrade(), paper.getSubjectId());
+            specialKnowledgeService.calcComplex(list);
+        }
+        //统计结果并且剪枝,剪掉>3的层级
+        List<SpecialKnowledge> tree = specialKnowledgeService.toTree(list);
 
         logger.info(tree.toString());
         SpecialResult r = new SpecialResult();
@@ -95,14 +136,137 @@ public class SpecialReportService {
         return r;
     }
 
-    private Integer getCount(List<Question> qs, List<Integer> collects) {
-        int count = 0;
-        for (Question q : qs) {
-            if (collects.contains(q.getNumber())) {
-                count++;
+    public List<SpecialMindVo> generateMind(Long pid, Long uid) {
+        logger.info("正在生成专项诊断报告");
+        Paper paper = paperService.getOnePaper(pid);
+        if (paper == null) {
+            logger.error("未找到试卷 pid={}", pid);
+            return null;
+        }
+        PaperCommit commit = commitService.getPaperCommit(pid, uid).get(0);
+        if (commit == null) {
+            logger.error("用户未提交 pid={},uid={}", pid, uid);
+            return null;
+        }
+        return generateMind(commit, paper);
+    }
+
+    public List<SpecialMindVo> generateMind(Long resultId) {
+        logger.info("正在生成专项诊断报告");
+        PaperResult result = paperResultService.get(resultId);
+        if (result == null) {
+            logger.error("未找到报告 paperResultId={}", resultId);
+            return null;
+        }
+        Paper paper = paperService.getOnePaper(result.getPid());
+        if (paper == null) {
+            logger.error("未找到试卷 pid={}", result.getPid());
+            return null;
+        }
+        PaperCommit commit = commitService.findByCommit(result.getCid());
+        if (commit == null) {
+            logger.error("用户未提交 pid={},uid={}", result.getPid(), result.getUid());
+            return null;
+        }
+        return generateMind(commit, paper);
+    }
+
+    public List<SpecialMindVo> generateMind(PaperCommit commit, Paper paper) {
+        PaperResult result = paperResultService.findByPidAndUid(commit.getPid(), commit.getUid()).get(0);
+        List<SpecialMind> list = specialMindService.findByPid(paper.getId());
+        if (CommonUtil.isEmpty(list)) {
+            logger.error("未上传专项诊断思维过程,subjectId={},grade={}", paper.getSubjectId(), paper.getGrade());
+            return null;
+        }
+        String contrast = result.getWrongAnswerContrast();
+        String correct = result.getCollectQuestion();
+        logger.info("correct={}", correct);
+        Set<Integer> collects = new HashSet<>();
+        if (StringUtils.isNotBlank(correct)) {
+            collects = Arrays.stream(correct.split(",")).map(Integer::parseInt).collect(Collectors.toSet());
+        }
+        List<AnswerContrast> contrasts = convertAnswerContrast(contrast);
+        if (CommonUtil.isEmpty(contrasts)) {
+            logger.info("没有错题");
+        }
+        Map<Integer, String> map = contrasts.stream().collect(Collectors.toMap(AnswerContrast::getNumber, AnswerContrast::getOptions));
+        //答对的选项
+        Pattern pattern = Pattern.compile("(\\d+)");
+
+        Map<String, Set<Integer>> stepNumbers = new HashMap<>();
+
+        for (SpecialMind mind : list) {
+            String qids = mind.getQids();
+            if (StringUtils.isBlank(qids)) {
+                logger.error("该问题没有考,请检查,pid={},content={}", paper.getId(), mind.getContent());
+                continue;
+            }
+            String[] qidss = qids.split(",");
+            Set<Integer> numbers = new HashSet<>();
+            boolean mistake = false;
+            for (String s : qidss) {
+                int number = 0;
+                if (s.matches("\\d+[A-E]")) {
+                    Matcher matcher = pattern.matcher(s);
+                    if (matcher.find()) {
+                        number = Integer.parseInt(matcher.group());
+                    } else {
+                        logger.error("未检测到题号,qids={}", qids);
+                        continue;
+                    }
+                } else {
+                    number = Integer.parseInt(s);
+                }
+                numbers.add(number);
+                if (map.containsKey(number) && StringUtils.isBlank(map.get(number))) {
+                    //没做题
+                    mistake = true;
+                } else if (map.containsKey(number)) {
+                    String options = map.get(number);
+                    if (!s.contains(options)) {
+                        //做错题
+                        mistake = true;
+                    }
+                }
             }
+            Set<Integer> nums = stepNumbers.getOrDefault(mind.getStep(),new HashSet<>());
+            nums.addAll(numbers);
+            stepNumbers.put(mind.getStep(), nums);
+            //设置这个问题有没有错误
+            mind.setMistake(mistake);
         }
-        return count;
+        Map<String, List<SpecialMind>> group = list.stream().collect(Collectors.groupingBy(SpecialMind::getStep));
+        List<SpecialMindVo> vos = new ArrayList<>();
+        for (Map.Entry<String, List<SpecialMind>> entry : group.entrySet()) {
+            String step = entry.getKey();
+            List<SpecialMind> minds = entry.getValue();
+            Set<Integer> numbers = stepNumbers.getOrDefault(entry.getKey(), new HashSet<>());
+            int questionNum = numbers.size();
+            numbers.retainAll(collects);
+            int collectNum = numbers.size();
+            if (questionNum == 0) {
+                logger.error("一整个步骤都没考,step={}", step);
+                continue;
+            }
+            SpecialMindVo vo = new SpecialMindVo();
+            double master = collectNum * 100.0 / questionNum;
+            vo.setMasterStatus("red");
+            if (master >= 85) {
+                vo.setMasterStatus("green");
+            } else if (master >= 50) {
+                vo.setMasterStatus("yellow");
+            }
+            vo.setMaster(NumberUtil.format(master));
+            vo.setMinds(minds);
+            vo.setStep(step);
+            vo.setSort(minds.get(0).getSort());
+            vos.add(vo);
+        }
+        return vos;
     }
 
+    private List<AnswerContrast> convertAnswerContrast(String json) {
+        return ObjectUtil.getGson().fromJson(json, new TypeToken<List<AnswerContrast>>() {
+        }.getType());
+    }
 }

+ 117 - 41
src/main/java/com/yaoxiang/diagnosis/word/KnowledgeUtil.java

@@ -1,13 +1,12 @@
 package com.yaoxiang.diagnosis.word;
 
 import com.yaoxiang.diagnosis.entity.SpecialKnowledge;
+import com.yaoxiang.diagnosis.entity.SpecialMind;
 import com.yaoxiang.diagnosis.entity.SubjectKnowledge;
 import com.yaoxiang.diagnosis.model.MatterVo;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.poi.xssf.usermodel.XSSFCell;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.xssf.usermodel.*;
 
 import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
@@ -15,6 +14,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static com.yaoxiang.diagnosis.config.Constants.SPECIAL_MASTER_STATUS;
+
 public class KnowledgeUtil {
 
     public static final int START_ROW = 2;
@@ -177,7 +178,7 @@ public class KnowledgeUtil {
             XSSFRow row = sheet.getRow(i);
             for (int j = 0; j < row.getLastCellNum() - 1; j++) {
                 String content = row.getCell(j).getStringCellValue();
-                if(map.containsKey(content)){
+                if (map.containsKey(content)) {
                     continue;
                 }
                 SpecialKnowledge k = new SpecialKnowledge();
@@ -188,50 +189,125 @@ public class KnowledgeUtil {
                 if (j == row.getLastCellNum() - 2) {
                     k.setCode(row.getCell(j + 1).getStringCellValue());
                 }
-//                if(j > 0){
-//                    k.setRoot1(row.getCell(0).getStringCellValue());
-//                }
-//                if(j > 1){
-//                    k.setRoot2(row.getCell(1).getStringCellValue());
-//                }
-//                if(j > 2){
-//                    k.setRoot3(row.getCell(2).getStringCellValue());
-//                }
-                k.setLevel(j);
+                //层级从第一级开始
+                k.setLevel(j + 1);
                 k.setGrade(grade);
                 k.setSubjectId(subjectId);
                 k.setContent(content);
-                map.put(content,k);
+                map.put(content, k);
                 result.add(k);
             }
         }
 
-        //一列一列来读取
-//        int colNum = sheet.getRow(3).getLastCellNum();
-//        for (int j = 0;j < colNum -1 ;j++){
-//            SpecialKnowledge p = queue.poll();
-//            for (int i=3;i<sheet.getLastRowNum();i++){
-//                String content = sheet.getRow(i).getCell(j).getStringCellValue();
-////                if(p != null && a != null && i == a + 1){
-////                    p = queue.poll();
-////                    a = index.poll();
-////                }
-//                if(StringUtils.isNotBlank(content)){
-//                    SpecialKnowledge k = new SpecialKnowledge();
-//                    k.setParent(p);
-//                    k.setLevel(j);
-//                    k.setGrade(grade);
-//                    k.setSubjectId(subjectId);
-//                    k.setContent(content);
-//                    result.add(k);
-//                    queue.add(k);
-//                    index.put(content,k);
-//                }
-//
-//            }
-//
-//        }
         return result;
     }
 
+    public static List<SpecialKnowledge> importSpecialKnowledge2(Long subjectId, String grade, byte[] data, Long pid) throws Exception {
+        XSSFWorkbook book = new XSSFWorkbook(new ByteArrayInputStream(data));
+        XSSFSheet sheet = book.getSheetAt(0);
+        List<SpecialKnowledge> result = new ArrayList<>();
+        for (int i = 3; i <= sheet.getLastRowNum(); i++) {
+            XSSFRow row = sheet.getRow(i);
+            for (int j = 0; j < row.getLastCellNum() - 1; j++) {
+                XSSFCell cell = row.getCell(j);
+                String content = cell.getStringCellValue();
+                if (StringUtils.isBlank(content)) {
+                    cell.setCellValue(sheet.getRow(i - 1).getCell(j).getStringCellValue());
+                }
+            }
+        }
+        Map<String, SpecialKnowledge> map = new HashMap<>();
+        for (int i = 3; i <= sheet.getLastRowNum(); i++) {
+            XSSFRow row = sheet.getRow(i);
+            for (int j = 0; j < row.getLastCellNum() - 1; j++) {
+                String content = row.getCell(j).getStringCellValue();
+                String rawContent = content;
+                //对有认识、理解和应用的特色处理
+                if (SPECIAL_MASTER_STATUS.contains(content)) {
+                    content = row.getCell(j - 1).getStringCellValue() + content;
+                }
+                if (map.containsKey(content)) {
+                    continue;
+                }
+                SpecialKnowledge k = new SpecialKnowledge();
+                if (j > 0) {
+                    String parentContent = row.getCell(j - 1).getStringCellValue();
+                    k.setParent(map.get(parentContent));
+                }
+                if (j == row.getLastCellNum() - 2) {
+                    XSSFCell cell = row.getCell(j + 1);
+                    if (CellType.BLANK == cell.getCellTypeEnum()) {
+                        k.setQids("");
+                    } else if (CellType.NUMERIC == cell.getCellTypeEnum()) {
+                        k.setQids(String.valueOf((int) cell.getNumericCellValue()));
+                    } else {
+                        k.setQids(cell.getStringCellValue());
+                    }
+                }
+                k.setLevel(j + 1);
+                k.setGrade(grade);
+                k.setPid(pid);
+                k.setSubjectId(subjectId);
+                k.setContent(rawContent);
+                map.put(content, k);
+                result.add(k);
+            }
+        }
+        return result;
+    }
+
+    public static List<SpecialMind> importSpecialMind(Long subjectId, String grade, byte[] data, Long pid) throws Exception {
+        XSSFWorkbook book = new XSSFWorkbook(new ByteArrayInputStream(data));
+        XSSFSheet sheet = book.getSheetAt(0);
+        List<SpecialMind> result = new ArrayList<>();
+        //先来做个填充
+        for (int i = 1; i < sheet.getLastRowNum(); i++) {
+            XSSFRow row = sheet.getRow(i);
+            XSSFCell cell = row.getCell(0);
+            String content = cell.getStringCellValue();
+            if (StringUtils.isBlank(content)) {
+                cell.setCellValue(sheet.getRow(i - 1).getCell(0).getStringCellValue());
+            }
+        }
+        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
+            XSSFRow row = sheet.getRow(i);
+            SpecialMind mind = new SpecialMind();
+            String step = row.getCell(0).getStringCellValue();
+            mind.setSort(toSort(step));
+            mind.setStep(step);
+            mind.setContent(row.getCell(1).getStringCellValue());
+            XSSFCell cell = row.getCell(2);
+            String qids = "";
+            if (cell.getCellTypeEnum() == CellType.NUMERIC) {
+                qids = String.valueOf((int) cell.getNumericCellValue());
+            } else {
+                qids = cell.getStringCellValue();
+            }
+            mind.setQids(qids);
+            mind.setPid(pid);
+            mind.setGrade(grade);
+            mind.setSubjectId(subjectId);
+            result.add(mind);
+        }
+        return result;
+    }
+
+    private static Integer toSort(String step) {
+        //有点蠢
+        switch (step) {
+            case "第一步":
+                return 1;
+            case "第二步":
+                return 2;
+            case "第三步":
+                return 3;
+            case "第四步":
+                return 4;
+            case "第五步":
+                return 5;
+            case "第六步":
+                return 6;
+        }
+        return 0;
+    }
 }

+ 93 - 39
src/main/java/com/yaoxiang/diagnosis/word/WordService.java

@@ -13,6 +13,7 @@ import org.apache.poi.xwpf.usermodel.*;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlObject;
 import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMath;
+import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMathPara;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,42 +50,42 @@ public class WordService {
         topicTypes = Arrays.asList(topicType);
     }
 
-    public Question parseQuestion(Question question, byte[] data) {
-        XWPFDocument document = WordUtil.open(data);
-        Map<String, List<XWPFParagraph>> group = initMap(document.getParagraphs());
-        List<XWPFPictureData> pictures = document.getAllPictures();
-        pictures.forEach(d -> {
-            logger.debug("check sum " + d.getChecksum());
-            logger.debug("file name " + d.getFileName());
-        });
-        parseQuestion(question, group);
-        WordUtil.close(document);
-        return question;
-    }
-
-    public Question parseQuestion(Question q, List<XWPFParagraph> ps, Map<String, String> topic, PaperTemplate template, List<String> abilities) {
+//    public Question parseQuestion(Question question, byte[] data) {
+//        XWPFDocument document = WordUtil.open(data);
+//        Map<String, List<XWPFParagraph>> group = initMap(document.getParagraphs());
+//        List<XWPFPictureData> pictures = document.getAllPictures();
+//        pictures.forEach(d -> {
+//            logger.debug("check sum " + d.getChecksum());
+//            logger.debug("file name " + d.getFileName());
+//        });
+//        parseQuestion(question, group);
+//        WordUtil.close(document);
+//        return question;
+//    }
+
+    public Question parseQuestion(Question q, List<XWPFParagraph> ps, Map<String, String> topic, PaperTemplate template, Boolean useAbility) {
         logger.info("parsing question,pid={},section={},number={}", q.getPid(), q.getSection(), q.getNumber());
         Map<String, List<XWPFParagraph>> group = initGroup(ps, topic, template);
         //此次是否还需再处理一下?
         parseQuestion(q, group.get(topic.get(Constants.TOPIC_QUESTION)), template.getOptionPattern(), template.getPicturePattern());
         parseAnswer(q, group.get(topic.get(Constants.TOPIC_ANSWER)));
         parseTag(q, group.get(topic.get(Constants.TOPIC_TAG)));
-        parseAbility(q, group.get(topic.get(Constants.TOPIC_ABILITY)), abilities);
+        parseAbility(q, group.get(topic.get(Constants.TOPIC_ABILITY)), useAbility);
         logger.info("parse question finish,pid={},section={},number={}", q.getPid(), q.getSection(), q.getNumber());
         return q;
     }
 
-    private void parseQuestion(Question q, Map<String, List<XWPFParagraph>> group) {
-        logger.info("parsing question,pid={},section={},number={}", q.getPid(), q.getSection(), q.getNumber());
-        String[] a = {"A1", "A2", "A3", "A4", "A5"};
-        parseQuestion(q, group.get(Constants.TOPIC_QUESTION), "^[A-Z]\\.(.*)", "^#(Small|Middle|Large)#");
-        parseAnswer(q, group.get(Constants.TOPIC_ANSWER));
-        parseTag(q, group.get(Constants.TOPIC_TAG));
-        parseAbility(q, group.get(Constants.TOPIC_ABILITY), Arrays.asList(a));
-        parseCollect(q, group.get(Constants.TOPIC_EVALUATE_CORRECT));
-        parseWrong(q, group.get(Constants.TOPIC_EVALUATE_WRONG));
-        logger.info("parse question finish,pid={},section={},number={}", q.getPid(), q.getSection(), q.getNumber());
-    }
+//    private void parseQuestion(Question q, Map<String, List<XWPFParagraph>> group) {
+//        logger.info("parsing question,pid={},section={},number={}", q.getPid(), q.getSection(), q.getNumber());
+//        String[] a = {"A1", "A2", "A3", "A4", "A5"};
+//        parseQuestion(q, group.get(Constants.TOPIC_QUESTION), "^[A-Z]\\.(.*)", "^#(Small|Middle|Large)#");
+//        parseAnswer(q, group.get(Constants.TOPIC_ANSWER));
+//        parseTag(q, group.get(Constants.TOPIC_TAG));
+//        parseAbility(q, group.get(Constants.TOPIC_ABILITY), Arrays.asList(a));
+//        parseCollect(q, group.get(Constants.TOPIC_EVALUATE_CORRECT));
+//        parseWrong(q, group.get(Constants.TOPIC_EVALUATE_WRONG));
+//        logger.info("parse question finish,pid={},section={},number={}", q.getPid(), q.getSection(), q.getNumber());
+//    }
 
     private void parseQuestion(Question question, List<XWPFParagraph> ps, String optionPattern, String picturePattern) {
         List<QuestionOption> options = new ArrayList<>();
@@ -92,16 +93,14 @@ public class WordService {
         StringBuilder content = new StringBuilder();
         boolean hasFormula = false;
         for (XWPFParagraph p : ps) {
-            parsePicture(p, picturePattern);
-            //TODO 图片丢失
-            hasFormula = parseFormula(p);
+
             String text = p.getText();
             //清除掉#Small#
             text = text.replaceAll(picturePattern, "");
             if (text.matches(optionPattern)) {
                 //匹配到选项,至少有2个字符
                 QuestionOption option = initOption(i++, text);
-                String optionNoContent = String.format("parseQuestion,题号为%s的题目选项 %s 未检测到内容,题目内容为“%s”,请检查", question.getNumber(), text.charAt(0), content);
+                String optionNoContent = String.format("parseQuestion,题号为%s的题目选项 %s 未检测到内容,题目内容为“%s”,请检查选项结构", question.getNumber(), text, content);
                 Assert.hasText(option.getContent(), optionNoContent);
                 options.add(option);
             } else {
@@ -110,7 +109,7 @@ public class WordService {
         }
         String noContent = String.format("parseQuestion,题号为 %s 的题目未检测到题干,题目内容为 “%s” ,请检查", question.getNumber(), content);
         String noOptions = String.format("parseQuestion,题号为 %s 的题目未检测到选项,题目内容为 “%s” ,请检查", question.getNumber(), content);
-        String lostOptions = String.format("parseQuestion,题号为 %s 的题目检测到选项数量为 %s ,题目内容为 “%s” ,请检查", question.getNumber(), options.size(), content);
+        String lostOptions = String.format("parseQuestion,题号为 %s 的题目检测到选项数量为 %s ,题目内容为 “%s” ,请检查选项换行情况", question.getNumber(), options.size(), content);
         Assert.hasText(content.toString(), noContent);
         Assert.notEmpty(options, noOptions);
         //TODO 选项数量可能不止5个?
@@ -144,7 +143,7 @@ public class WordService {
         ps.stream().filter(p -> StringUtils.isNotBlank(p.getText())).forEach(p -> question.setTag(p.getText()));
     }
 
-    private void parseAbility(Question question, List<XWPFParagraph> ps, List<String> abilities) {
+    private void parseAbility(Question question, List<XWPFParagraph> ps, Boolean useAbility) {
         List<AbilityScore> list = new ArrayList<>();
         Map<String, Double> json = new HashMap<>();
         //先手动设置1分
@@ -176,7 +175,9 @@ public class WordService {
 //                question.setConversion(score);
 //            }
         }
-        question.setJsonScore(ObjectUtil.object2Json(json));
+        if (useAbility != null && useAbility) {
+            question.setJsonScore(ObjectUtil.object2Json(json));
+        }
         question.setScores(list);
 
     }
@@ -256,7 +257,7 @@ public class WordService {
         QuestionOption option = new QuestionOption();
         option.setOindex(index);
         //去掉选项中的#A#
-        option.setContent(content.substring(3));
+        option.setContent("<p>" + content.substring(3) + "</p>");
         option.setCreatetime(new Date());
         option.setCorrect(false);
         return option;
@@ -269,12 +270,21 @@ public class WordService {
     public void parsePicture(XWPFParagraph p, String picturePattern) {
         String text = p.getText();
         Matcher matcher = Pattern.compile(picturePattern).matcher(text);
-        if (!matcher.find()) {
+        //如果没有图片 并且 没有标签 直接跳过
+        boolean hasPicture = WordUtil.hasPicture(p);
+        if (!hasPicture && !matcher.find()) {
             logger.info("parsePicture,before parse run ,no picture: {}", text);
             return;
+        } else if (!hasPicture && matcher.find()) {
+            String msg = "parsePicture error,find tag but not picture: " + text;
+            logger.error(msg, new RuntimeException(msg));
+            return;
+        }
+        //图片默认最大宽度
+        String size = Constants.PICTURE_SIZE_LARGE;
+        if (matcher.find()) {
+            size = matcher.group().replaceAll("#", "");
         }
-        String size = matcher.group().replaceAll("#", "");
-
         logger.info("parsePicture,before parse run: " + text);
         List<XWPFRun> runs = p.getRuns();
         int i = 0;
@@ -284,13 +294,16 @@ public class WordService {
             logger.debug("run pos " + (i++) + " embed picture size " + pictures.size());
 //            String img = "<img src=\"%s\" style=\"width: %spt;height: %spt\" />";
             //图片水平居中
-            String img = "<p style=\"text-align:center\"><img src=\"%s\" style=\"max-width: %spx;center\" /></p>";
+            String img = "<p style=\"text-align:center\"><img src=\"%s\" style=\"max-width:100%%; width:%spx; center\" /></p>";
             if (CommonUtil.notEmpty(pictures)) {
                 //只处理第一张图片
                 XWPFPicture pp = pictures.get(0);
                 String pName = pp.getPictureData().getFileName();
                 //想办法加上长跟宽
                 String suffix = pName.substring(pName.lastIndexOf("."));
+                if (".emf".equals(suffix)) {
+                    logger.error("检测到emf文件,段落内容为{}", p.getText());
+                }
                 String saveName = CommonUtil.randomUUID() + suffix;
                 byte[] pData = pp.getPictureData().getData();
                 int width = getWidth(pData);
@@ -355,12 +368,17 @@ public class WordService {
 
     public boolean parseFormula(XWPFParagraph p) {
         List<CTOMath> maths = p.getCTP().getOMathList();
-        if (CommonUtil.isEmpty(maths)) {
+        List<CTOMathPara> paras = p.getCTP().getOMathParaList();
+        if (CommonUtil.isEmpty(maths) && CommonUtil.isEmpty(paras)) {
             return false;
         }
+
         //CTOMath 在CTP下面
         XmlCursor c = p.getCTP().newCursor();
         c.selectPath("./*");
+        if (CommonUtil.notEmpty(paras)) {
+            c.toNextSibling();
+        }
         int i = 0;
         Map<Integer, String> insert = new HashMap<>();
         while (c.toNextSelection()) {
@@ -378,6 +396,18 @@ public class WordService {
                     e.printStackTrace();
                 }
                 logger.debug("CTOMath i = " + i + " " + o.getClass());
+            } else if (o instanceof CTOMathPara) {
+//                CTOMathPara m = (CTOMathPara) o;
+                c.toLastChild();
+                XmlObject xmlObject = c.getObject();
+                CTOMath m = (CTOMath) xmlObject;
+                try {
+                    String mml = formulaService.getMathML(m);
+                    insert.put(i, mml);
+                    i++;
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
             }
         }
 
@@ -389,4 +419,28 @@ public class WordService {
 
     }
 
+    public void parseSubScript(XWPFParagraph paragraph) {
+        Map<Integer, String> insert = new HashMap<>();
+        List<XWPFRun> runs = paragraph.getRuns();
+        for (int i = 0; i < runs.size(); i++) {
+            switch (runs.get(i).getSubscript()) {
+                case BASELINE:
+                    break;
+                case SUBSCRIPT:
+                    insert.put(i, "<sub>");
+                    insert.put(i + 1, "</sub>");
+                    break;
+                case SUPERSCRIPT:
+                    insert.put(i, "<sup>");
+                    insert.put(i + 1, "</sup>");
+                    break;
+            }
+        }
+        int i = 0;
+        for (Map.Entry<Integer, String> entry : insert.entrySet()) {
+            XWPFRun run = paragraph.insertNewRun(entry.getKey() + i++);
+            run.setText(entry.getValue());
+        }
+    }
+
 }

+ 11 - 3
src/main/java/com/yaoxiang/diagnosis/word/WordUtil.java

@@ -134,16 +134,24 @@ public class WordUtil {
         }
     }
 
-    public static boolean hasContent(XWPFParagraph paragraph, String text) {
+    public static boolean hasContent(XWPFParagraph p, String text) {
         if (StringUtils.isNotBlank(text)) {
             return true;
         }
-        for (XWPFRun run : paragraph.getRuns()) {
+        return hasPicture(p) || hasFormula(p);
+    }
+
+    public static boolean hasPicture(XWPFParagraph p) {
+        for (XWPFRun run : p.getRuns()) {
             if (run.getEmbeddedPictures().size() > 0) {
                 return true;
             }
         }
-        return paragraph.getCTP().getOMathList().size() > 0;
+        return false;
+    }
+
+    public static boolean hasFormula(XWPFParagraph p) {
+        return p.getCTP().getOMathList().size() > 0 || p.getCTP().getOMathParaList().size() > 0;
     }
 
     public static boolean notContent(XWPFParagraph paragraph, String text) {

+ 0 - 15
src/main/resources/application-cloud.properties

@@ -1,16 +1,6 @@
 server.port=8080
-#serverAddress=172.18.129.124
-#serverAddress=119.23.22.31
-#serverOutsideAddress=www.yaoxiangedu.com
-
-#uploadPattern=/upload/**
-#baseLocation=/opt/diagnosis/${server.port}
-#baseLocation=/tmp/diagnosis/data
-#uploadLocation=${baseLocation}/upload/
-#spring.servlet.multipart.location=${baseLocation}/uploadTemp/
 spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/
 
-#spring.datasource.url=jdbc:mysql://47.104.200.54:3306/OnlinePapers?useUnicode=true&characterEncoding=utf-8
 spring.datasource.url=jdbc:mysql://mysql:3306/OnlinePapers?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
 spring.datasource.username=onlinepapers
 spring.datasource.password=134679258Aa_
@@ -20,11 +10,6 @@ spring.redis.password=134679258Aa_
 spring.redis.host=redis-master
 spring.redis.port=6379
 
-#不使用localFileService
-#docpath=/root/doc/
-#local.uploadUrl=http://${serverOutsideAddress}:9000/file/upload
-#local.downloadUrl=http://${serverOutsideAddress}:9000/file/download/
-
 #外部要使用,所以不能为内部地址
 minio.url=https://minio.yaoxiangedu.com/
 minio.secure=true

+ 0 - 9
src/main/resources/application-dev.properties

@@ -1,12 +1,6 @@
 server.port=8085
 serverAddress=119.23.22.31
 
-#uploadPattern=/upload/**
-#baseLocation=diagnosis
-#baseLocation=/Users/feick/IdeaProjects/yaoxiang/diagnosis
-#baseLocation=/d:/diagnosis
-#uploadLocation=${baseLocation}/upload/
-#spring.servlet.multipart.location=${baseLocation}/uploadTemp/
 spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/
 
 
@@ -31,11 +25,8 @@ spring.redis.database=0
 spring.redis.password=134679258Aa_
 spring.redis.host=${serverAddress}
 spring.redis.port=32578
-#local.uploadUrl=http://${serverAddress}:9001/file/upload
-#local.downloadUrl=http://${serverAddress}:9001/file/download/
 
 minio.url=http://${serverAddress}:30240/
-#minio.url=https://minio.yaoxiangedu.com/
 minio.secure=false
 minio.buckets=dev
 minio.defaultBucket=dev

+ 0 - 8
src/main/resources/application-docker.properties

@@ -1,13 +1,8 @@
 server.port=8080
 serverAddress=119.23.22.31
 
-#uploadPattern=/upload/**
-#baseLocation=/tmp/diagnosis/data
-#uploadLocation=${baseLocation}/upload/
-#spring.servlet.multipart.location=${baseLocation}/uploadTemp/
 spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/
 
-#spring.datasource.url=jdbc:mysql://47.104.200.54:3306/OnlinePapers?useUnicode=true&characterEncoding=utf-8
 spring.datasource.url=jdbc:mysql://${serverAddress}:30875/OnlinePapers?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
 spring.datasource.username=onlinepapers
 spring.datasource.password=134679258Aa_
@@ -16,9 +11,6 @@ spring.redis.database=0
 spring.redis.password=134679258Aa_
 spring.redis.host=redis-master
 spring.redis.port=6379
-#local.uploadUrl=http://${serverAddress}:9001/file/upload
-#local.downloadUrl=http://${serverAddress}:9001/file/download/
-
 
 minio.url=http://${serverAddress}:30240/
 minio.secure=false

+ 18 - 0
src/main/resources/application-pre.properties

@@ -0,0 +1,18 @@
+server.port=8080
+spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/
+
+spring.datasource.url=jdbc:mysql://mysql:3306/OnlinePapers?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
+spring.datasource.username=onlinepapers
+spring.datasource.password=134679258Aa_
+
+spring.redis.database=0
+spring.redis.password=134679258Aa_
+spring.redis.host=redis-master
+spring.redis.port=6379
+
+minio.url=https://minio.yaoxiangedu.com/
+minio.secure=true
+minio.buckets=prod
+minio.defaultBucket=prod
+minio.accessKey=admin
+minio.secretKey=#admin123!

+ 0 - 11
src/main/resources/application-prod.properties

@@ -1,16 +1,9 @@
 server.port=8080
-#serverAddress=172.18.129.124
 serverAddress=119.23.22.31
 serverOutsideAddress=www.yaoxiangedu.com
 
-#uploadPattern=/upload/**
-#baseLocation=/opt/diagnosis/${server.port}
-#baseLocation=d:/diagnosis
-#uploadLocation=${baseLocation}/upload/
-#spring.servlet.multipart.location=${baseLocation}/uploadTemp/
 spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/
 
-#spring.datasource.url=jdbc:mysql://47.104.200.54:3306/OnlinePapers?useUnicode=true&characterEncoding=utf-8
 spring.datasource.url=jdbc:mysql://${serverAddress}:3306/OnlinePapers?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
 spring.datasource.username=root
 spring.datasource.password=134679258Aa_
@@ -20,10 +13,6 @@ spring.redis.password=134679258Aa_
 spring.redis.host=${serverAddress}
 spring.redis.port=6379
 
-#docpath=/root/doc/
-local.uploadUrl=http://${serverOutsideAddress}:9000/file/upload
-local.downloadUrl=http://${serverOutsideAddress}:9000/file/download/
-
 minio.url=http://${serverAddress}:30240/
 minio.secure=false
 minio.buckets=prod

+ 0 - 4
src/main/resources/application.properties

@@ -1,8 +1,6 @@
 spring.profiles.active=dev
 logging.level.* = info
 logging.file=log/log.log
-#logging.pattern.console= %d{yyyy-MM-dd HH:mm:ss} - %msg%n
-#logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
 
 spring.servlet.multipart.enabled=true
 spring.servlet.multipart.max-file-size=50MB
@@ -37,7 +35,5 @@ spring.data.redis.repositories.enabled=false
 #server.tomcat.accesslog.suffix=.log
 
 #ÆôÓÃswagger
-swagger.enabled=true
 web.loginPage=/login
 web.logoutUrl=/logout
-#web.permitUrls=/login,/logout,/**/*.js,/**/*.png,/**/*.jpg,/**/*.css

+ 1 - 1
src/test/java/com/yaoxiang/diagnosis/service/KnowledgeTest.java

@@ -12,7 +12,7 @@ public class KnowledgeTest {
 
     @Test
     public void test() throws Exception{
-        File file = new File("doc/小升初专项诊断知识点列表.xlsx");
+        File file = new File("doc/数学小升初专项诊断知识点列表.xlsx");
         byte[] data = FileCopyUtils.copyToByteArray(file);
         //有点问题,最底层的第二个以后的parentId不对
         List<SpecialKnowledge> list = KnowledgeUtil.importSpecialKnowledge1(2L,"6Y",data);

+ 45 - 0
src/test/java/com/yaoxiang/diagnosis/service/StringTest.java

@@ -1,8 +1,13 @@
 package com.yaoxiang.diagnosis.service;
 
+import io.swagger.models.auth.In;
 import org.junit.Test;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public class StringTest {
 
@@ -29,4 +34,44 @@ public class StringTest {
         String t = "您的%s处于有待开发的阶段。对%s进行专项训练可以帮助您快速提高%s成绩。";
         System.out.println(String.format(t, (Object[]) a));
     }
+
+    @Test
+    public void testString3(){
+        String text = "asdf";
+        System.out.println(text.substring(text.length()));
+    }
+
+    @Test
+    public void testList(){
+        List<Integer> a = new ArrayList<>();
+        a.add(1);
+        a.add(2);
+        a.add(3);
+        a.add(4);
+
+        List<Integer> b = new ArrayList<>();
+        b.add(1);
+        b.add(3);
+        b.add(5);
+        b.add(6);
+        a.retainAll(b);
+        System.out.println(a);
+        System.out.println(b);
+    }
+
+    @Test
+    public void test1(){
+        String a = "65C";
+        String b = "65ABC";
+        String c = "65ABEF";
+        System.out.println(a.matches("\\d+[A-E]"));
+        System.out.println(b.matches("\\d+[A-E]+"));
+        System.out.println(c.matches("\\d+[A-E]+"));
+
+        Pattern pattern = Pattern.compile("\\d+");
+        Matcher matcher = pattern.matcher(a);
+        System.out.println(matcher.find());
+        System.out.println(matcher.group());
+
+    }
 }

+ 79 - 1
src/test/java/com/yaoxiang/diagnosis/service/UploadTest.java

@@ -1,9 +1,18 @@
 package com.yaoxiang.diagnosis.service;
 
 
+import com.microsoft.schemas.office.office.OLEObjectDocument;
 import com.yaoxiang.diagnosis.entity.Paper;
 import com.yaoxiang.diagnosis.entity.PaperTemplate;
 import com.yaoxiang.diagnosis.util.CommonUtil;
+import com.yaoxiang.diagnosis.util.ObjectUtil;
+import com.yaoxiang.diagnosis.word.WordUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.poi.xwpf.usermodel.VerticalAlign;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
 import org.junit.Test;
 import org.springframework.core.io.ByteArrayResource;
 import org.springframework.http.HttpEntity;
@@ -14,7 +23,8 @@ import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
 import org.springframework.web.client.RestTemplate;
 
-import java.io.File;
+import java.io.*;
+import java.util.*;
 
 public class UploadTest {
 
@@ -67,4 +77,72 @@ public class UploadTest {
         System.out.println(paper.getCode());
         System.out.println(paper.getGrade());
     }
+
+    @Test
+    public void test3() throws Exception {
+        XWPFDocument document = WordUtil.open("doc/sub.docx");
+        List<XWPFParagraph> paragraphs = document.getParagraphs();
+        for (XWPFParagraph paragraph : paragraphs) {
+            List<XWPFRun> runs = paragraph.getRuns();
+
+            System.out.println("before parse " + paragraph.getText());
+            System.out.println("runs size " + runs.size());
+
+            Map<Integer, String> insert = new HashMap<>();
+            for (int i = 0; i < runs.size(); i++) {
+                switch (runs.get(i).getSubscript()) {
+                    case BASELINE:
+                        break;
+                    case SUBSCRIPT:
+                        insert.put(i, "<sub>");
+                        insert.put(i + 1, "</sub>");
+                        break;
+                    case SUPERSCRIPT:
+                        insert.put(i, "<sup>");
+                        insert.put(i + 1, "</sup>");
+                        break;
+                }
+            }
+            int i = 0;
+            for (Map.Entry<Integer, String> entry : insert.entrySet()) {
+                XWPFRun run = paragraph.insertNewRun(entry.getKey() + i++);
+                run.setText(entry.getValue());
+            }
+
+            System.out.println("after parse " + paragraph.getText());
+            System.out.println("runs size " + runs.size());
+
+        }
+        //OLEObject
+//        OLEObjectDocument
+    }
+
+    @Test
+    public void test4() throws Exception {
+        XWPFDocument document = WordUtil.open("doc/sub.docx");
+        List<XWPFParagraph> paragraphs = document.getParagraphs();
+        for (XWPFParagraph paragraph : paragraphs) {
+            List<XWPFRun> runs = paragraph.getRuns();
+            int i = 0;
+            for (XWPFRun run : runs) {
+                System.out.println("run = " + i + " " + run.getText(0));
+                i++;
+            }
+//            paragraph.insertNewRun(0).setText("asdf");
+            System.out.println(paragraph.getText());
+        }
+    }
+
+
+    public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
+        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(byteOut);
+        out.writeObject(src);
+
+        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(byteIn);
+        @SuppressWarnings("unchecked")
+        List<T> dest = (List<T>) in.readObject();
+        return dest;
+    }
 }

+ 22 - 7
src/test/java/com/yaoxiang/diagnosis/service/WordServiceTest.java

@@ -3,11 +3,11 @@ package com.yaoxiang.diagnosis.service;
 import com.yaoxiang.diagnosis.config.Constants;
 import com.yaoxiang.diagnosis.util.CommonUtil;
 import com.yaoxiang.diagnosis.word.WordUtil;
+import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLConverter;
+import fr.opensagres.poi.xwpf.converter.xhtml.internal.XHTMLMapper;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFPicture;
-import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.apache.poi.POIXMLDocumentPart;
+import org.apache.poi.xwpf.usermodel.*;
 import org.apache.xmlbeans.SchemaType;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlObject;
@@ -82,9 +82,24 @@ public class WordServiceTest {
     }
 
     @Test
-    public void test222() {
-        XWPFDocument document = WordUtil.open("topic_table.docx");
-        for (XWPFParagraph paragraph : document.getParagraphs()) {
+    public void test222() throws Exception{
+        XWPFDocument document = WordUtil.open("doc/table.docx");
+        List<XWPFParagraph> list = document.getParagraphs();
+        List<IBodyElement> bodyElements = document.getBodyElements();
+        int i=0;
+//        XHTMLMapper mapper = new XHTMLMapper(document,null,null);
+//        mapper.start();
+
+        for (IBodyElement element:bodyElements){
+            if (element instanceof XWPFParagraph){
+                System.out.println(i+"par " + ((XWPFParagraph) element).getText());
+            }else if(element instanceof XWPFTable){
+                XWPFTable table = (XWPFTable) element;
+                System.out.println(i+"table " + table.getText());
+            }
+            i++;
+        }
+        for (XWPFParagraph paragraph : list) {
             System.out.println(paragraph.getText());
         }
     }

+ 34 - 0
src/test/java/com/yaoxiang/diagnosis/service/WordTest.java

@@ -0,0 +1,34 @@
+package com.yaoxiang.diagnosis.service;
+
+import com.yaoxiang.diagnosis.word.WordUtil;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.junit.Test;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+
+public class WordTest {
+
+    @Test
+    public void test() throws Exception{
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        File file = new File("doc/table.docx");
+        InputStream is = new FileInputStream(file);
+        FileCopyUtils.copy(is, baos);
+        is.close();
+        byte[] data = baos.toByteArray();
+        XWPFDocument document = WordUtil.open(data);
+        List<XWPFParagraph> paragraphs = document.getParagraphs();
+        for (XWPFParagraph paragraph:paragraphs){
+            System.out.println(paragraph.getCTP().xmlText());
+            System.out.println(paragraph.getCTP().isImmutable());
+            System.out.println(paragraph.toString());
+        }
+
+    }
+}

Деякі файли не було показано, через те що забагато файлів було змінено