Procházet zdrojové kódy

新方案原卷导出

xiatian před 5 roky
rodič
revize
6d2415bf94
23 změnil soubory, kde provedl 1417 přidání a 0 odebrání
  1. 12 0
      examcloud-core-questions-api-provider/src/main/java/cn/com/qmth/examcloud/core/questions/api/controller/ExportPaperController.java
  2. 76 0
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/FileDisposeUtil.java
  3. 72 0
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/dto/ExportTempDataDto.java
  4. 55 0
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/json/DocxImage.java
  5. 17 0
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/json/JSection.java
  6. 213 0
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/json/JsonExportUtil.java
  7. 30 0
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/json/SectionElementParams.java
  8. 2 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/_rels/.rels
  9. 2 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/docProps/app.xml
  10. 2 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/docProps/core.xml
  11. 2 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/word/endnotes.xml
  12. 2 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/word/fontTable.xml
  13. 2 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/word/footnotes.xml
  14. 1 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/word/settings.xml
  15. 1 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/word/styles.xml
  16. 1 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/word/theme/theme1.xml
  17. 2 0
      examcloud-core-questions-base/src/main/resources/export_template/docx/word/webSettings.xml
  18. 33 0
      examcloud-core-questions-base/src/main/resources/export_template/origin_paper/content_types.ftl
  19. 593 0
      examcloud-core-questions-base/src/main/resources/export_template/origin_paper/document.ftl
  20. 33 0
      examcloud-core-questions-base/src/main/resources/export_template/origin_paper/document_rel.ftl
  21. 75 0
      examcloud-core-questions-base/src/main/resources/export_template/origin_paper/question_section.ftl
  22. 2 0
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/ExportPaperService.java
  23. 189 0
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExportPaperServiceImpl.java

+ 12 - 0
examcloud-core-questions-api-provider/src/main/java/cn/com/qmth/examcloud/core/questions/api/controller/ExportPaperController.java

@@ -133,4 +133,16 @@ public class ExportPaperController extends ControllerSupport {
         }
         log.info("开始导出原始导入的试卷");
     }
+
+    @ApiOperation(value = "导出原始导入的试卷", notes = "导出原始导入的试卷")
+    @GetMapping(value = "/originalPaper/exportPlus/{paperId}/{loginName}")
+    public void downOriginalPaperPlus(HttpServletResponse response, @PathVariable String paperId,
+            @PathVariable String loginName) {
+        try {
+            exportPaperService.downOriginalPaperPlus(paperId, loginName, response);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        log.info("开始导出原始导入的试卷");
+    }
 }

+ 76 - 0
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/FileDisposeUtil.java

@@ -225,4 +225,80 @@ public class FileDisposeUtil {
         }
     }
 
+    public static File createZip(String sourceFilePath, String targetFilePath) throws IOException {
+        OutputStream fos = null;
+        ZipOutputStream zos = null;
+        try {
+            File zipfile = new File(targetFilePath);
+            zipfile.deleteOnExit();
+            fos = new FileOutputStream(zipfile);
+            zos = new ZipOutputStream(fos);
+            // zos.setEncoding("utf-8"); // Solve linxu's mess
+            writeZip(new File(sourceFilePath), null, zos);
+            return zipfile;
+        } finally {
+            if (zos != null) {
+                zos.close();
+            }
+            if (fos != null) {
+                fos.close();
+            }
+        }
+    }
+
+    private static void writeZip(File file, String parentPath, ZipOutputStream zos) throws IOException {
+        if (file.exists()) {
+            ZipEntry ze = null;
+            if (file.isDirectory()) {// Processing folder
+                if (parentPath == null) {
+                    parentPath = "";
+                } else {
+                    parentPath += file.getName() + File.separator;
+                }
+                File[] files = file.listFiles();
+                if (files != null) {
+                    for (File f : files) {
+                        writeZip(f, parentPath, zos);
+                    }
+                } else { // An empty directory creates the current directory
+                    try {
+                        ze = new ZipEntry(parentPath);
+                        // ze.setUnixMode(755);// Solve Linux mess file Settings
+                        // 644 directory Settings 755
+                        zos.putNextEntry(ze);
+
+                        zos.flush();
+                    } finally {
+                        if (zos != null) {
+                            zos.closeEntry();
+                        }
+                    }
+                }
+            } else {
+                FileInputStream fis = null;
+                try {
+                    fis = new FileInputStream(file);
+                    ze = new ZipEntry(parentPath + file.getName());
+                    // ze.setUnixMode(644);// Solve Linux mess file Settings 644
+                    // directory Settings 755
+                    zos.putNextEntry(ze);
+                    byte[] content = new byte[1024];
+                    int len;
+                    while ((len = fis.read(content)) != -1) {
+                        zos.write(content, 0, len);
+                        zos.flush();
+                    }
+
+                } finally {
+                    if (fis != null) {
+                        fis.close();
+                    }
+                    if (zos != null) {
+                        zos.closeEntry();
+                    }
+                }
+            }
+        }
+    }
+
 }

+ 72 - 0
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/dto/ExportTempDataDto.java

@@ -0,0 +1,72 @@
+package cn.com.qmth.examcloud.core.questions.base.dto;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import cn.com.qmth.examcloud.core.questions.base.json.SectionElement;
+
+public class ExportTempDataDto {
+
+    private int mainNum = 0;
+
+    private int subNum = 0;
+
+    private int grandNum = 0;
+
+    private int index = 0;
+
+    private Set<String> types = new HashSet<String>();
+
+    private List<SectionElement> images = new ArrayList<SectionElement>();
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    public Set<String> getTypes() {
+        return types;
+    }
+
+    public void setTypes(Set<String> types) {
+        this.types = types;
+    }
+
+    public List<SectionElement> getImages() {
+        return images;
+    }
+
+    public void setImages(List<SectionElement> images) {
+        this.images = images;
+    }
+
+    public int getMainNum() {
+        return mainNum;
+    }
+
+    public void setMainNum(int mainNum) {
+        this.mainNum = mainNum;
+    }
+
+    public int getSubNum() {
+        return subNum;
+    }
+
+    public void setSubNum(int subNum) {
+        this.subNum = subNum;
+    }
+
+    public int getGrandNum() {
+        return grandNum;
+    }
+
+    public void setGrandNum(int grandNum) {
+        this.grandNum = grandNum;
+    }
+
+}

+ 55 - 0
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/json/DocxImage.java

@@ -0,0 +1,55 @@
+package cn.com.qmth.examcloud.core.questions.base.json;
+
+public class DocxImage {
+
+    private String type;
+
+    private String data;
+
+    private int index;
+
+    private String name;
+
+    private String rid;
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getRid() {
+        return rid;
+    }
+
+    public void setRid(String rid) {
+        this.rid = rid;
+    }
+
+}

+ 17 - 0
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/json/JSection.java

@@ -0,0 +1,17 @@
+package cn.com.qmth.examcloud.core.questions.base.json;
+
+import java.util.List;
+
+public class JSection {
+
+    List<SectionElement> elements;
+
+    public List<SectionElement> getElements() {
+        return elements;
+    }
+
+    public void setElements(List<SectionElement> elements) {
+        this.elements = elements;
+    }
+
+}

+ 213 - 0
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/json/JsonExportUtil.java

@@ -0,0 +1,213 @@
+package cn.com.qmth.examcloud.core.questions.base.json;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.nodes.TextNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+
+public class JsonExportUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(JsonExportUtil.class);
+
+    public static final String QUESOPS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    public static final String ELEMENT_TYPE_RID = "imageId";
+
+    public static final String ELEMENT_TYPE_TEXT = "text";
+
+    public static final String ELEMENT_TYPE_IMG = "image";
+
+    private static final String ENCODING = "UTF-8";
+
+    private static Configuration config;
+
+    private static Template questionSection;
+
+    private static Template contentTypes;
+
+    private static Template document;
+
+    private static Template documentRel;
+
+    private static Pattern heightRex = Pattern.compile("height:([\\s\\S]*?)px");
+
+    private static Pattern widthRex = Pattern.compile("width:([\\s\\S]*?)px");
+    static {
+
+        config = new Configuration(Configuration.VERSION_2_3_25);
+        // 设置编码
+        config.setDefaultEncoding(ENCODING);
+        // 设置ftl模板路径
+        config.setClassForTemplateLoading(JsonExportUtil.class, "/export_template/origin_paper/");
+
+        try {
+            questionSection = config.getTemplate("question_section.ftl", ENCODING);
+            contentTypes = config.getTemplate("content_types.ftl", ENCODING);
+            document = config.getTemplate("document.ftl", ENCODING);
+            documentRel = config.getTemplate("document_rel.ftl", ENCODING);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+
+    public static String getDocxBasePath() {
+        return JsonExportUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath()
+                + "export_template/docx";
+    }
+
+    public static List<JSection> getSections(String html) {
+        if (StringUtils.isBlank(html)) {
+            return null;
+        }
+        if (!html.startsWith("<p>")) {
+            html = "<p>" + html + "</p>";
+        }
+        List<JSection> ss = new ArrayList<JSection>();
+        Document doc = Jsoup.parse(html);
+        Element b = doc.body();
+        for (Node e : b.childNodes()) {
+            if ("p".equals(e.nodeName()) && e.childNodeSize() > 0) {
+                JSection s = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
+                s.setElements(ses);
+                for (Node ce : e.childNodes()) {
+                    getSectionElement(ce, ses);
+                }
+                ss.add(s);
+            }
+        }
+        return ss;
+
+    }
+
+    private static void getSectionElement(Node ce, List<SectionElement> ses) {
+        if ("span".equals(ce.nodeName()) && ce.childNodeSize() > 0) {
+            for (Node e : ce.childNodes()) {
+                getSectionElement(e, ses);
+            }
+        } else {
+            SectionElement se = new SectionElement();
+            if (ce instanceof TextNode) {
+                TextNode tn = (TextNode) ce;
+                se.setType(ELEMENT_TYPE_TEXT);
+                se.setValue(tn.text());
+            } else if (ce instanceof Element) {
+                if ("img".equals(ce.nodeName())) {
+                    se.setType(ELEMENT_TYPE_IMG);
+                    se.setValue(ce.attr("src"));
+                    SectionElementParams sep = new SectionElementParams();
+                    sep.setHeight(getHeight(ce));
+                    sep.setWidth(getWidth(ce));
+                    se.setParams(sep);
+                } else {
+                    Element el = (Element) ce;
+                    se.setType(ELEMENT_TYPE_TEXT);
+                    se.setValue(el.text());
+                }
+            }
+            ses.add(se);
+        }
+    }
+
+    private static int getWidth(Node ce) {
+        int n = 50;
+        String str = ce.attr("width");
+        if (StringUtils.isNoneBlank(str)) {
+            return getWordImgSize(str);
+        }
+        String style = ce.attr("style");
+        if (StringUtils.isNoneBlank(style)) {
+            Matcher m = widthRex.matcher(style);
+            if (m.find()) {
+                return Integer.valueOf(m.group(1)) * 9525;
+            }
+        }
+        return n;
+    }
+
+    private static int getHeight(Node ce) {
+        int n = 50;
+        String str = ce.attr("height");
+        if (StringUtils.isNoneBlank(str)) {
+            return getWordImgSize(str);
+        }
+        String style = ce.attr("style");
+        if (StringUtils.isNoneBlank(style)) {
+            Matcher m = heightRex.matcher(style);
+            if (m.find()) {
+                return Integer.valueOf(m.group(1)) * 9525;
+            }
+        }
+        return n;
+    }
+
+    private static Integer getWordImgSize(String px) {
+        if (StringUtils.isBlank(px)) {
+            return null;
+        }
+        String sizeStr = px.replace("px", "");
+        Integer size = Integer.valueOf(sizeStr) * 9525;
+        return size;
+    }
+
+    public static String getDocumentDoc(Object paperExp) {
+        StringWriter result = null;
+        try {
+            result = new StringWriter();
+            document.process(paperExp, result);
+            return result.toString();
+        } catch (Exception e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+    public static String getDocumentRelDoc(Map<String, Object> map) {
+        StringWriter result = null;
+        try {
+            result = new StringWriter();
+            documentRel.process(map, result);
+            return result.toString();
+        } catch (Exception e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+    public static String getQuestionSectionDoc(Map<String, Object> map) {
+        StringWriter result = null;
+        try {
+            result = new StringWriter();
+            questionSection.process(map, result);
+            return result.toString();
+        } catch (Exception e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+    public static String getContentTypesDoc(Map<String, Object> map) {
+        StringWriter result = null;
+        try {
+            result = new StringWriter();
+            contentTypes.process(map, result);
+            return result.toString();
+        } catch (Exception e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+}

+ 30 - 0
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/json/SectionElementParams.java

@@ -6,6 +6,12 @@ public class SectionElementParams {
 
     private Integer height;
 
+    private String rid;
+
+    private Integer index;
+
+    private String type;
+
     public Integer getWidth() {
         return width;
     }
@@ -22,4 +28,28 @@ public class SectionElementParams {
         this.height = height;
     }
 
+    public String getRid() {
+        return rid;
+    }
+
+    public void setRid(String rid) {
+        this.rid = rid;
+    }
+
+    public Integer getIndex() {
+        return index;
+    }
+
+    public void setIndex(Integer index) {
+        this.index = index;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
 }

+ 2 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/_rels/.rels

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/></Relationships>

+ 2 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/docProps/app.xml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><Template>Normal.dotm</Template><TotalTime>4</TotalTime><Pages>10</Pages><Words>366</Words><Characters>2092</Characters><Application>Microsoft Office Word</Application><DocSecurity>0</DocSecurity><Lines>17</Lines><Paragraphs>4</Paragraphs><ScaleCrop>false</ScaleCrop><Company></Company><LinksUpToDate>false</LinksUpToDate><CharactersWithSpaces>2454</CharactersWithSpaces><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>15.0000</AppVersion></Properties>

+ 2 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/docProps/core.xml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:creator>爱飞雪</dc:creator><cp:lastModifiedBy>chenken</cp:lastModifiedBy><cp:revision>3</cp:revision><dcterms:created xsi:type="dcterms:W3CDTF">2018-09-04T06:30:00Z</dcterms:created><dcterms:modified xsi:type="dcterms:W3CDTF">2019-11-04T08:42:00Z</dcterms:modified></cp:coreProperties>

+ 2 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/word/endnotes.xml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<w:endnotes xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 wp14"><w:endnote w:type="separator" w:id="-1"><w:p w:rsidR="00FB1A98" w:rsidRDefault="00FB1A98" w:rsidP="0087455D"><w:r><w:separator/></w:r></w:p></w:endnote><w:endnote w:type="continuationSeparator" w:id="0"><w:p w:rsidR="00FB1A98" w:rsidRDefault="00FB1A98" w:rsidP="0087455D"><w:r><w:continuationSeparator/></w:r></w:p></w:endnote></w:endnotes>

+ 2 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/word/fontTable.xml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<w:fonts xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15"><w:font w:name="Calibri"><w:panose1 w:val="020F0502020204030204"/><w:charset w:val="00"/><w:family w:val="swiss"/><w:pitch w:val="variable"/><w:sig w:usb0="E0002AFF" w:usb1="C000247B" w:usb2="00000009" w:usb3="00000000" w:csb0="000001FF" w:csb1="00000000"/></w:font><w:font w:name="宋体"><w:altName w:val="SimSun"/><w:panose1 w:val="02010600030101010101"/><w:charset w:val="86"/><w:family w:val="auto"/><w:pitch w:val="variable"/><w:sig w:usb0="00000003" w:usb1="288F0000" w:usb2="00000016" w:usb3="00000000" w:csb0="00040001" w:csb1="00000000"/></w:font><w:font w:name="Times New Roman"><w:panose1 w:val="02020603050405020304"/><w:charset w:val="00"/><w:family w:val="roman"/><w:pitch w:val="variable"/><w:sig w:usb0="E0002EFF" w:usb1="C000785B" w:usb2="00000009" w:usb3="00000000" w:csb0="000001FF" w:csb1="00000000"/></w:font><w:font w:name="Arial"><w:panose1 w:val="020B0604020202020204"/><w:charset w:val="00"/><w:family w:val="swiss"/><w:pitch w:val="variable"/><w:sig w:usb0="E0002EFF" w:usb1="C000785B" w:usb2="00000009" w:usb3="00000000" w:csb0="000001FF" w:csb1="00000000"/></w:font><w:font w:name="Cambria"><w:panose1 w:val="02040503050406030204"/><w:charset w:val="00"/><w:family w:val="roman"/><w:pitch w:val="variable"/><w:sig w:usb0="E00006FF" w:usb1="420024FF" w:usb2="02000000" w:usb3="00000000" w:csb0="0000019F" w:csb1="00000000"/></w:font></w:fonts>

+ 2 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/word/footnotes.xml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<w:footnotes xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 wp14"><w:footnote w:type="separator" w:id="-1"><w:p w:rsidR="00FB1A98" w:rsidRDefault="00FB1A98" w:rsidP="0087455D"><w:r><w:separator/></w:r></w:p></w:footnote><w:footnote w:type="continuationSeparator" w:id="0"><w:p w:rsidR="00FB1A98" w:rsidRDefault="00FB1A98" w:rsidP="0087455D"><w:r><w:continuationSeparator/></w:r></w:p></w:footnote></w:footnotes>

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/word/settings.xml


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/word/styles.xml


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/word/theme/theme1.xml


+ 2 - 0
examcloud-core-questions-base/src/main/resources/export_template/docx/word/webSettings.xml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<w:webSettings xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15"><w:optimizeForBrowser/><w:allowPNG/></w:webSettings>

+ 33 - 0
examcloud-core-questions-base/src/main/resources/export_template/origin_paper/content_types.ftl

@@ -0,0 +1,33 @@
+<#setting number_format="#">
+<?xml version="1.0" encoding="UTF-8"?>
+<Types
+	xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
+	<#if images?exists>
+	<#list images as image>
+	<Default Extension="${image}" ContentType="image/${image}" />
+	</#list>
+	</#if>
+	<Default Extension="rels"
+		ContentType="application/vnd.openxmlformats-package.relationships+xml" />
+	<Default Extension="xml" ContentType="application/xml" />
+	<Override PartName="/word/document.xml"
+		ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" />
+	<Override PartName="/word/styles.xml"
+		ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" />
+	<Override PartName="/word/settings.xml"
+		ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" />
+	<Override PartName="/word/webSettings.xml"
+		ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml" />
+	<Override PartName="/word/footnotes.xml"
+		ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" />
+	<Override PartName="/word/endnotes.xml"
+		ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml" />
+	<Override PartName="/word/fontTable.xml"
+		ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" />
+	<Override PartName="/word/theme/theme1.xml"
+		ContentType="application/vnd.openxmlformats-officedocument.theme+xml" />
+	<Override PartName="/docProps/core.xml"
+		ContentType="application/vnd.openxmlformats-package.core-properties+xml" />
+	<Override PartName="/docProps/app.xml"
+		ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" />
+</Types>

+ 593 - 0
examcloud-core-questions-base/src/main/resources/export_template/origin_paper/document.ftl

@@ -0,0 +1,593 @@
+<#setting number_format="#">
+<?xml version="1.0" encoding="UTF-8"?>
+<w:document
+	xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
+	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+	xmlns:o="urn:schemas-microsoft-com:office:office"
+	xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+	xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
+	xmlns:v="urn:schemas-microsoft-com:vml"
+	xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
+	xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
+	xmlns:w10="urn:schemas-microsoft-com:office:word"
+	xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
+	xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
+	xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
+	xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
+	xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk"
+	xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
+	xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
+	mc:Ignorable="w14 w15 wp14">
+	<w:body>
+		<#if paperDetails?exists>
+		<#list paperDetails as paperDetail>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967" w:rsidRPr="003A4B1C">
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>试题分类</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r w:rsidRPr="00473411">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+					<w:b />
+					<w:szCs w:val="21" />
+				</w:rPr>
+				<w:t xml:space="preserve" />
+			</w:r>
+			<w:r w:rsidRPr="00F955A6">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+					<w:b />
+					<w:szCs w:val="21" />
+				</w:rPr>
+				<w:t>${courseName?html}</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>_</w:t>
+			</w:r>
+			<w:r w:rsidR="006F4609">
+				<w:rPr>
+					<w:rFonts w:ascii="Arial" w:cs="Arial" w:hAnsi="Arial" />
+					<w:color w:val="1F2D3D" />
+					<w:sz w:val="14" />
+					<w:szCs w:val="14" />
+					<w:shd w:color="auto" w:fill="FFFFFF" w:val="clear" />
+				</w:rPr>
+				<w:t>${courseNo}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967" w:rsidRPr="003A4B1C">
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>题型</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetail.quesType}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967" w:rsidRPr="003A4B1C">
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>大题名称</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetail.name}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967" w:rsidRPr="003A4B1C">
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>题目数量</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetail.unitCount}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967" w:rsidRPr="003A4B1C">
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>分数</w:t>
+			</w:r>
+			<w:r w:rsidRPr="003A4B1C">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetail.firstScore}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967" />
+		<#if paperDetail.paperDetailUnits?exists>
+		<#list paperDetail.paperDetailUnits as paperDetailUnit>
+		<#if paperDetailUnit.question.subQuestions?exists>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>套题</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetailUnit_index+1}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>套题数量</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetailUnit.question.subQuestions?size}</w:t>
+			</w:r>
+		</w:p>
+		${paperDetailUnit.question.quesBodyWord}
+		<#list paperDetailUnit.question.subQuestions as subQuestion>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>小题型</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${subQuestion.questionType}</w:t>
+			</w:r>
+		</w:p>
+		${subQuestion.quesBodyWord}
+		<#if subQuestion.quesOptions?exists>
+		<#list subQuestion.quesOptions as subQuesOption>
+		${subQuesOption.optionBodyWord}
+		</#list>
+		</#if>
+		${subQuestion.quesAnswerWord!}
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>难度</w:t>
+			</w:r>
+			<w:r w:rsidR="00F35998">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${subQuestion.difficultyDegree!}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>一级属性</w:t>
+			</w:r>
+			<w:r w:rsidR="008978E3">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<#if subQuestion.quesProperties?? && (subQuestion.quesProperties?size
+			> 0)>
+			<w:r w:rsidR="00FC0BCE">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${subQuestion.quesProperties[0].firstProperty.name}</w:t>
+			</w:r>
+			</#if>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>二级属性</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<#if subQuestion.quesProperties?? && (subQuestion.quesProperties?size
+			> 0)>
+			<#if subQuestion.quesProperties[0].secondProperty??>
+			<w:r w:rsidR="00FC0BCE">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${subQuestion.quesProperties[0].secondProperty.name}</w:t>
+			</w:r>
+			</#if>
+			</#if>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>公开度</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<#if subQuestion.publicity??>
+			<#if subQuestion.publicity>
+			<w:r w:rsidR="004A272D">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>公开</w:t>
+			</w:r>
+			<#else>
+			<w:r w:rsidR="004A272D">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>非公开</w:t>
+			</w:r>
+			</#if>
+			</#if>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>小题分数</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r w:rsidR="004A272D">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${subQuestion.score}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidR="008C75CD" w:rsidRDefault="008C75CD" />
+		</#list>
+		<#else>
+		${paperDetailUnit.question.quesBodyWord}
+		<#if paperDetailUnit.question.quesOptions?exists>
+		<#list paperDetailUnit.question.quesOptions as quesOption>
+		${quesOption.optionBodyWord}
+		</#list>
+		</#if>
+		${paperDetailUnit.question.quesAnswerWord!}
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>难度</w:t>
+			</w:r>
+			<w:r w:rsidR="00F35998">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetailUnit.question.difficultyDegree!}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>一级属性</w:t>
+			</w:r>
+			<w:r w:rsidR="008978E3">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r w:rsidR="00FC0BCE">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetailUnit.firstName!}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>二级属性</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r w:rsidR="00FC0BCE">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetailUnit.secondName!}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>公开度</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r w:rsidR="004A272D">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetailUnit.publicity}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidP="00F62967" w:rsidR="00F62967"
+			w:rsidRDefault="00F62967">
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>[</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>小题分数</w:t>
+			</w:r>
+			<w:r>
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>]:</w:t>
+			</w:r>
+			<w:r w:rsidR="004A272D">
+				<w:rPr>
+					<w:rFonts w:hint="eastAsia" />
+				</w:rPr>
+				<w:t>${paperDetailUnit.score}</w:t>
+			</w:r>
+		</w:p>
+		<w:p w:rsidR="008C75CD" w:rsidRDefault="008C75CD" />
+		</#if>
+		</#list>
+		</#if>
+		</#list>
+		</#if>
+		<w:sectPr w:rsidR="008C75CD" w:rsidSect="001205CF">
+			<w:pgSz w:h="16838" w:w="11906" />
+			<w:pgMar w:bottom="1440" w:footer="992" w:gutter="0"
+				w:header="851" w:left="1800" w:right="1800" w:top="1440" />
+			<w:cols w:space="425" />
+			<w:docGrid w:linePitch="312" w:type="lines" />
+		</w:sectPr>
+	</w:body>
+</w:document>

+ 33 - 0
examcloud-core-questions-base/src/main/resources/export_template/origin_paper/document_rel.ftl

@@ -0,0 +1,33 @@
+<#setting number_format="#">
+<?xml version="1.0" encoding="UTF-8"?>
+<Relationships
+	xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
+	<#if images?exists>
+	<#list images as image>
+	<Relationship Id="${image.params.rid}"
+		Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
+		Target="media/image${image.params.index}.${image.params.type}" />
+	</#list>
+	</#if>
+	<Relationship Id="rId5"
+		Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes"
+		Target="endnotes.xml" />
+	<Relationship Id="rId3"
+		Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings"
+		Target="webSettings.xml" />
+	<Relationship Id="rId91"
+		Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable"
+		Target="fontTable.xml" />
+	<Relationship Id="rId1"
+		Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
+		Target="styles.xml" />
+	<Relationship Id="rId4"
+		Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes"
+		Target="footnotes.xml" />
+	<Relationship Id="rId92"
+		Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
+		Target="theme/theme1.xml" />
+	<Relationship Id="rId2"
+		Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"
+		Target="settings.xml" />
+</Relationships>

+ 75 - 0
examcloud-core-questions-base/src/main/resources/export_template/origin_paper/question_section.ftl

@@ -0,0 +1,75 @@
+
+<#setting number_format="#">
+<#list sections as section>
+<w:p w:rsidR="00F62967" w:rsidRPr="003A4B1C"
+	w:rsidRDefault="00F62967" w:rsidP="00F62967">
+	<#if section_index != 0>
+	<w:pPr>
+		<w:autoSpaceDE w:val="false" />
+		<w:autoSpaceDN w:val="false" />
+		<w:adjustRightInd w:val="false" />
+		<w:ind w:firstLine="424" w:firstLineChars="202" />
+		<w:jc w:val="left" />
+	</w:pPr>
+	</#if>
+	<#list section.elements as element>
+	<#if element.type="image">
+	<w:r>
+		<w:rPr>
+			<w:noProof />
+		</w:rPr>
+		<w:drawing>
+			<wp:inline distT="0" distB="0" distL="0" distR="0">
+				<wp:extent cx="${element.params.width}"
+					cy="${element.params.height}" />
+				<wp:effectExtent l="0" t="0" r="0" b="0" />
+				<wp:docPr id="${element.params.index}"
+					name="图片 ${element.params.index}" />
+				<wp:cNvGraphicFramePr>
+					<a:graphicFrameLocks
+						xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
+						noChangeAspect="1" />
+				</wp:cNvGraphicFramePr>
+				<a:graphic
+					xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
+					<a:graphicData
+						uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
+						<pic:pic
+							xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
+							<pic:nvPicPr>
+								<pic:cNvPr id="1" name="" />
+								<pic:cNvPicPr />
+							</pic:nvPicPr>
+							<pic:blipFill>
+								<a:blip r:embed="${element.params.rid}" />
+								<a:stretch>
+									<a:fillRect />
+								</a:stretch>
+							</pic:blipFill>
+							<pic:spPr>
+								<a:xfrm>
+									<a:off x="0" y="0" />
+									<a:ext cx="${element.params.width}"
+										cy="${element.params.height}" />
+								</a:xfrm>
+								<a:prstGeom prst="rect">
+									<a:avLst />
+								</a:prstGeom>
+							</pic:spPr>
+						</pic:pic>
+					</a:graphicData>
+				</a:graphic>
+			</wp:inline>
+		</w:drawing>
+	</w:r>
+	<#else>
+	<w:r w:rsidRPr="003A4B1C">
+		<w:rPr>
+			<w:rFonts w:hint="eastAsia" />
+		</w:rPr>
+		<w:t>${element.value}</w:t>
+	</w:r>
+	</#if>
+	</#list>
+</w:p>
+</#list>

+ 2 - 0
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/ExportPaperService.java

@@ -41,4 +41,6 @@ public interface ExportPaperService {
      */
     public void downOriginalPaper(String paperId, String loginName, HttpServletResponse response) throws Exception;
 
+    public void downOriginalPaperPlus(String paperId, String loginName, HttpServletResponse response) throws Exception;
+
 }

+ 189 - 0
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExportPaperServiceImpl.java

@@ -42,9 +42,14 @@ import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
 import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
 import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
 import cn.com.qmth.examcloud.core.questions.base.FileDisposeUtil;
+import cn.com.qmth.examcloud.core.questions.base.IdUtils;
 import cn.com.qmth.examcloud.core.questions.base.Model;
 import cn.com.qmth.examcloud.core.questions.base.SpringContextUtils;
+import cn.com.qmth.examcloud.core.questions.base.dto.ExportTempDataDto;
 import cn.com.qmth.examcloud.core.questions.base.enums.ExamFileType;
+import cn.com.qmth.examcloud.core.questions.base.json.JSection;
+import cn.com.qmth.examcloud.core.questions.base.json.JsonExportUtil;
+import cn.com.qmth.examcloud.core.questions.base.json.SectionElement;
 import cn.com.qmth.examcloud.core.questions.base.question.enums.QuesStructType;
 import cn.com.qmth.examcloud.core.questions.base.word.DocxProcessUtil;
 import cn.com.qmth.examcloud.core.questions.dao.CoursePropertyRepo;
@@ -74,12 +79,15 @@ import cn.com.qmth.examcloud.core.questions.service.ExportPaperService;
 import cn.com.qmth.examcloud.core.questions.service.PaperDetailService;
 import cn.com.qmth.examcloud.core.questions.service.PaperService;
 import cn.com.qmth.examcloud.core.questions.service.PropertyService;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailExp;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailUnitExp;
 import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperExp;
 import cn.com.qmth.examcloud.core.questions.service.bean.dto.QuestionDistributeDto;
 import cn.com.qmth.examcloud.core.questions.service.config.SysProperty;
 import cn.com.qmth.examcloud.core.questions.service.converter.PrintExamPaperService;
 import cn.com.qmth.examcloud.core.questions.service.export.ExportPaperAbstractService;
 import main.java.com.UpYun;
+import sun.misc.BASE64Decoder;
 
 @Service("exportPaperService")
 public class ExportPaperServiceImpl implements ExportPaperService {
@@ -92,6 +100,8 @@ public class ExportPaperServiceImpl implements ExportPaperService {
 
     public static final String DOCX_SUFFIX = ".docx";
 
+    public static final String ZIP_SUFFIX = ".zip";
+
     @Autowired
     private PaperRepo paperRepo;
 
@@ -1034,4 +1044,183 @@ public class ExportPaperServiceImpl implements ExportPaperService {
         }
     }
 
+    @Override
+    public void downOriginalPaperPlus(String paperId, String loginName, HttpServletResponse response) throws Exception {
+        String zipFileName = IdUtils.uuid();
+        File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
+        if (!directory.exists()) {
+            directory.mkdirs();
+        }
+        // doc固定源文件目录
+        File docxDir = new File(JsonExportUtil.getDocxBasePath());
+        // 将要生成的doc源文件目录
+        File docxTargetDir = new File(directory.getAbsolutePath() + "/docx/");
+        docxTargetDir.mkdir();
+        try {
+            // 复制docx基础文件
+            FileUtils.copyDirectory(docxDir, docxTargetDir);
+            // 生成导出的试卷对象
+            PaperExp paperExp = paperService.getDownPaperExp(paperId);
+            // 处理并生成doc源文件
+            dispose(docxTargetDir, paperExp);
+            // 压缩docx源文件
+            String paperfileName = paperExp.getName() + "_" + paperExp.getCourseNo() + "_"
+                    + ExamFileType.PAPER.getName();
+            File zipfile = new File(docxTargetDir.getParentFile().getAbsolutePath() + File.separator + "data"
+                    + File.separator + paperfileName + ZIP_SUFFIX);
+            zipfile.getParentFile().mkdir();
+            File docfile = new File(docxTargetDir.getParentFile().getAbsolutePath() + File.separator + "data"
+                    + File.separator + File.separator + paperfileName + DOCX_SUFFIX);
+            FileDisposeUtil.createZip(docxTargetDir.getAbsolutePath(), zipfile.getAbsolutePath());
+            // 修改压缩包为doc文件
+            zipfile.renameTo(docfile);
+            // doc文件加入下载包中
+            FileDisposeUtil.fileToZip(docfile.getParentFile().getAbsolutePath(),
+                    docxTargetDir.getParentFile().getAbsolutePath(), zipFileName);
+            // 下载文件
+            FileDisposeUtil.downloadFile(paperExp.getName() + "_" + paperExp.getCourse().getCode() + ".zip",
+                    docxTargetDir.getParentFile().getAbsolutePath() + File.separator + zipFileName + ".zip", response);
+        } finally {
+            FileUtils.deleteDirectory(directory);
+        }
+
+    }
+
+    private void dispose(File docxTargetDir, PaperExp paperExp) throws IOException {
+        ExportTempDataDto dto = new ExportTempDataDto();
+        if (paperExp.getPaperDetails() != null && paperExp.getPaperDetails().size() > 0) {
+            for (PaperDetailExp pde : paperExp.getPaperDetails()) {
+                dto.setMainNum(dto.getMainNum() + 1);
+                dto.setSubNum(0);
+                if (pde.getPaperDetailUnits() != null && pde.getPaperDetailUnits().size() > 0) {
+                    for (PaperDetailUnitExp pdue : pde.getPaperDetailUnits()) {
+                        Question qes = pdue.getQuestion();
+                        disposeQuestion(qes, dto);
+                    }
+                }
+            }
+        }
+        // content-type
+        writeContentType(docxTargetDir, dto);
+        // document
+        writeDocument(docxTargetDir, paperExp);
+        // document-rel
+        writeDocumentRel(docxTargetDir, dto);
+        // image file
+        writeImage(docxTargetDir, dto);
+    }
+
+    private void writeImage(File docxTargetDir, ExportTempDataDto dto) throws IOException {
+        for (SectionElement se : dto.getImages()) {
+            File file = new File(docxTargetDir.getAbsolutePath() + "/word/media/image" + se.getParams().getIndex() + "."
+                    + se.getParams().getType());
+            String base64 = se.getValue();
+            if (base64.contains("data:image")) {
+                base64 = base64.substring(base64.indexOf(",") + 1);
+            }
+            BASE64Decoder decoder = new BASE64Decoder();
+            byte[] bytes = decoder.decodeBuffer(base64);
+            FileUtils.writeByteArrayToFile(file, bytes);
+        }
+    }
+
+    private void writeDocumentRel(File docxTargetDir, ExportTempDataDto dto) throws IOException {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("images", dto.getImages());
+        String doc = JsonExportUtil.getDocumentRelDoc(map);
+        File file = new File(docxTargetDir.getAbsolutePath() + "/word/_rels/document.xml.rels");
+        FileUtils.writeStringToFile(file, doc, "utf-8");
+    }
+
+    private void writeContentType(File docxTargetDir, ExportTempDataDto dto) throws IOException {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("images", dto.getTypes());
+        String doc = JsonExportUtil.getContentTypesDoc(map);
+        File file = new File(docxTargetDir.getAbsolutePath() + "/[Content_Types].xml");
+        FileUtils.writeStringToFile(file, doc, "utf-8");
+    }
+
+    private void writeDocument(File docxTargetDir, PaperExp paperExp) throws IOException {
+        String doc = JsonExportUtil.getDocumentDoc(paperExp);
+        File file = new File(docxTargetDir.getAbsolutePath() + "/word/document.xml");
+        FileUtils.writeStringToFile(file, doc, "utf-8");
+    }
+
+    private void disposeQuestion(Question qes, ExportTempDataDto dto) {
+        if (qes != null) {
+            List<JSection> slist1 = JsonExportUtil.getSections(qes.getQuesBody());
+            if (slist1 != null && slist1.size() > 0) {
+                if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题题干不加题号
+                    dto.setSubNum(dto.getSubNum() + 1);
+                    SectionElement se = new SectionElement();
+                    se.setType(JsonExportUtil.ELEMENT_TYPE_TEXT);
+                    se.setValue(dto.getSubNum() + ".");
+                    slist1.get(0).getElements().add(0, se);
+                }
+
+                htmlToDoc(slist1, dto);
+                qes.setQuesBodyWord(getQuestionDoc(slist1));
+            }
+
+            if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
+                int index = 0;
+                for (QuesOption qo : qes.getQuesOptions()) {
+                    List<JSection> slist2 = JsonExportUtil.getSections(qo.getOptionBody());
+                    if (slist2 != null && slist2.size() > 0) {
+                        SectionElement se = new SectionElement();
+                        se.setType(JsonExportUtil.ELEMENT_TYPE_TEXT);
+                        se.setValue(JsonExportUtil.QUESOPS.charAt(index) + ".");
+                        index++;
+                        slist2.get(0).getElements().add(0, se);
+                        htmlToDoc(slist2, dto);
+                        qo.setOptionBodyWord(getQuestionDoc(slist2));
+                    }
+
+                }
+            }
+            List<JSection> slist3 = JsonExportUtil.getSections(qes.getQuesAnswer());
+            if (slist3 != null && slist3.size() > 0) {
+                SectionElement se = new SectionElement();
+                se.setType(JsonExportUtil.ELEMENT_TYPE_TEXT);
+                se.setValue("[答案]:");
+                slist3.get(0).getElements().add(0, se);
+
+                htmlToDoc(slist3, dto);
+                qes.setQuesAnswerWord(getQuestionDoc(slist3));
+            }
+
+            if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
+                dto.setSubNum(0);
+                for (Question sunqes : qes.getSubQuestions()) {
+                    disposeQuestion(sunqes, dto);// 递归处理套题
+                }
+            }
+        }
+    }
+
+    private void htmlToDoc(List<JSection> slist, ExportTempDataDto dto) {
+        for (JSection js : slist) {
+            for (SectionElement se : js.getElements()) {
+                if (JsonExportUtil.ELEMENT_TYPE_IMG.equals(se.getType())) {
+                    dto.setIndex(dto.getIndex() + 1);
+                    se.getParams().setIndex(dto.getIndex());
+                    se.getParams().setRid(JsonExportUtil.ELEMENT_TYPE_RID + dto.getIndex());
+                    se.getParams().setType(getImageType(se.getValue()));
+                    dto.getTypes().add(se.getParams().getType());
+                    dto.getImages().add(se);
+                }
+            }
+        }
+    }
+
+    private String getImageType(String base64) {
+        return base64.substring(11, base64.indexOf(";"));
+    }
+
+    private String getQuestionDoc(List<JSection> sections) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("sections", sections);
+        String doc = JsonExportUtil.getQuestionSectionDoc(map);
+        return doc;
+    }
 }

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů