瀏覽代碼

答案导出pdf功能

刘洋 1 年之前
父節點
當前提交
80774f03af

+ 1 - 0
src/directives/directives.js

@@ -1 +1,2 @@
 import "../modules/questions/directives/directives";
+import "./domObserver";

+ 29 - 0
src/directives/domObserver.js

@@ -0,0 +1,29 @@
+import Vue from "vue";
+// function getElementToPageTop(el) {
+//   if (el.parentElement) {
+//     return getElementToPageTop(el.parentElement) + el.offsetTop;
+//   }
+//   return el.offsetTop;
+// }
+
+Vue.directive("domObserver", {
+  bind(el, binding) {
+    let top = "";
+    let height = "";
+    function isResize() {
+      // let toPageTop = getElementToPageTop(el);
+      let toPageTop = el.getBoundingClientRect().top;
+      let elHeight = el.getBoundingClientRect().height;
+      if (toPageTop != top || elHeight != height) {
+        binding.value({ top: toPageTop, height: elHeight });
+      }
+      top = toPageTop;
+      height = elHeight;
+    }
+    el.__vueSetInterval__ = setInterval(isResize, 300);
+  },
+  unbind(el) {
+    console.log(el, "解绑");
+    clearInterval(el.__vueSetInterval__);
+  },
+});

+ 14 - 0
src/modules/paper-export/assets/styles/answer-temp-preview.scss

@@ -3,6 +3,13 @@
     &-A4{
       width: 793px;
       height: 1122px;
+      &.origin-view{
+        position:absolute;
+        top:0;
+        left:0;
+        z-index:-100;
+        opacity:0;
+      }
       .page-main {
         &-inner {
           padding: 60px 45px 86px;
@@ -12,6 +19,13 @@
             overflow: hidden;
             padding-bottom: 5px;
           }
+          .page-number{
+            position: absolute;
+            width: 100%;
+            text-align: center;
+            bottom: 13px;
+            left:0;
+          }
         }
       }
     }

+ 185 - 64
src/modules/paper-export/components/AnswerTemplateView.vue

@@ -1,60 +1,87 @@
 <template>
   <div class="paper-template-view answer-template-view card-view paper-page">
-    <div class="page-box page-box-A4 page-box-answer">
-      <div class="page-main-inner" style="font-size: 12px">
+    <div v-for="(singlePageData, index) in flatData" :key="index">
+      <div class="page-box page-box-A4 page-box-answer">
+        <div class="page-main-inner">
+          <div v-for="(row, i) in singlePageData || []" :key="i">
+            <div v-if="row.type == 'bigTitle'" class="is-detail-title">
+              {{ row.number | numberToChaineseFilter }}、{{ row.name }}
+              {{ row.title }}
+            </div>
+            <div v-else>
+              <span>{{ row.questionSeq + ". " }}</span>
+              <question-answer :data="row"></question-answer>
+            </div>
+          </div>
+          <page-number
+            type="text"
+            :rule="getPageNumberCont(index + 1)"
+          ></page-number>
+        </div>
+      </div>
+    </div>
+
+    <div class="page-box page-box-A4 page-box-answer origin-view">
+      <div class="page-main-inner">
+        <!-- {{ flatData }} -->
         <div v-for="(big, index) in paperDetails" :key="index">
-          <div class="is-detail-title">
+          <div
+            class="is-detail-title"
+            v-domObserver="
+              (top) => {
+                getDomTop(top, index);
+              }
+            "
+          >
             {{ big.number | numberToChaineseFilter }}、{{ big.name }}
             {{ big.title }}
           </div>
           <div v-for="(small, i) in big.paperDetailUnits" :key="i">
-            <span>{{ small.question.questionSeq + ". " }}</span>
-            <question-answer :data="small.question"></question-answer>
+            <div
+              v-if="!small.question.subQuestions"
+              v-domObserver="
+                (top) => {
+                  getDomTop(top, index, i);
+                }
+              "
+            >
+              <span>{{ small.question.questionSeq + ". " }}</span>
+              <question-answer :data="small.question"></question-answer>
+            </div>
+
+            <template v-if="small.question.subQuestions">
+              <div
+                v-for="(innerQuestion, innerIndex) in small.question
+                  .subQuestions"
+                :key="innerIndex"
+                v-domObserver="
+                  (top) => {
+                    getDomTop(top, index, i, innerIndex);
+                  }
+                "
+              >
+                <span>{{ innerQuestion.questionSeq + ". " }}</span>
+                <question-answer :data="innerQuestion"></question-answer>
+              </div>
+            </template>
           </div>
         </div>
       </div>
     </div>
-
-    <!-- <template v-for="(page, pageNo) in pages"> -->
-    <!-- <div
-        :key="pageNo"
-        :class="[
-          'page-box',
-          `page-box-${page.pageSize}`,
-          `page-box-${pageTypeType(page.pageType)}`,
-        ]"
-      >
-        <div
-          :class="[
-            'page-main-inner',
-            {
-              'page-main-noside': !page.showSide || page.pageType === 'cover',
-            },
-          ]"
-        ></div>
-      </div> -->
-    <!-- </template> -->
   </div>
 </template>
 
 <script>
-// import TopicElementPreview from "./TopicElementPreview";
-// import PageNumber from "./PageNumber";
+import PageNumber from "./PageNumber";
 import QuestionAnswer from "../../question/components/QuestionAnswer.vue";
+import { cloneDeep } from "lodash";
 export default {
   name: "AnswerTemplateView",
   components: {
-    // TopicElementPreview,
-    // PageNumber,
+    PageNumber,
     QuestionAnswer,
   },
   props: {
-    // pages: {
-    //   type: Array,
-    //   default() {
-    //     return [];
-    //   },
-    // },
     pageConfig: {
       type: Object,
       default() {
@@ -67,45 +94,139 @@ export default {
         return {};
       },
     },
+    pageCountMode: {
+      type: String,
+    },
   },
   computed: {
     paperDetails() {
       return this.answerData?.paperDetails || [];
     },
+    //数据扁平化,便于高度计算
+    flatData() {
+      let arr = [[]];
+      const limitHeight = 976;
+      let usedPageIndex = 0;
+      let computedHeight = 0;
+      let paperDetailsWithTop = cloneDeep(this.paperDetailsWithTop);
+      for (let i = 0; i < paperDetailsWithTop.length; i++) {
+        let cloneBig = cloneDeep(paperDetailsWithTop[i]);
+        let { top, height } = cloneBig; //大题标题的尺寸数据
+        if (computedHeight + top + height > limitHeight) {
+          usedPageIndex++;
+          arr[usedPageIndex] = [];
+          computedHeight = top + height;
+        } else {
+          computedHeight += top + height;
+        }
+        arr[usedPageIndex].push({
+          type: "bigTitle",
+          name: cloneBig.name,
+          title: cloneBig.title,
+          number: cloneBig.number,
+        });
+        if (cloneBig.paperDetailUnits?.length) {
+          for (let j = 0; j < cloneBig.paperDetailUnits.length; j++) {
+            let unit = cloneBig.paperDetailUnits[j];
+            let question = unit.question;
+            let { top, height } = unit; //大题标题的尺寸数据
+            if (!question.subQuestions) {
+              //无套题的小题尺寸数据
+              if (computedHeight + top + height > limitHeight) {
+                usedPageIndex++;
+                arr[usedPageIndex] = [];
+                computedHeight = top + height;
+              } else {
+                computedHeight += top + height;
+              }
+              arr[usedPageIndex].push({
+                type: "subQuestion",
+                ...cloneDeep(question),
+              });
+            } else {
+              for (let x = 0; x < question.subQuestions.length; x++) {
+                let innerQuestion = question.subQuestions[x];
+                let { top, height } = innerQuestion;
+                if (computedHeight + top + height > limitHeight) {
+                  usedPageIndex++;
+                  arr[usedPageIndex] = [];
+                  computedHeight = top + height;
+                } else {
+                  computedHeight += top + height;
+                }
+                arr[usedPageIndex].push({
+                  type: "innerQuestion",
+                  ...cloneDeep(innerQuestion),
+                });
+              }
+            }
+          }
+        }
+      }
+      if (arr.length % 2 != 0 && this.pageCountMode === "DOUBLE") {
+        arr.push([]);
+      }
+      return arr;
+    },
   },
   data() {
-    return {};
+    return {
+      paperDetailsWithTop: [],
+      // computedPages: [],
+    };
   },
-  methods: {
-    pageTypeType(pageType) {
-      const types = {
-        cover: 0,
-        front: 0,
-        back: 1,
-      };
-      return types[pageType];
+  watch: {
+    answerData(val) {
+      let arr = cloneDeep(val?.paperDetails || []);
+      this.paperDetailsWithTop = arr.map((detail) => {
+        detail.position = { top: 0, height: 0 };
+        if (detail.paperDetailUnits?.length) {
+          detail.paperDetailUnits = detail.paperDetailUnits.map((unit) => {
+            unit.position = { top: 0, height: 0 };
+            let question = unit.question;
+            if (question.subQuestions?.length) {
+              question.subQuestions = question.subQuestions.map((subQues) => {
+                subQues.position = { top: 0, height: 0 };
+                return subQues;
+              });
+            }
+            return unit;
+          });
+        }
+        return detail;
+      });
     },
-    getPageNumber(curPageNo, columnNo) {
-      const coverPageCount = this.pages.filter(
-        (p) => p.pageType === "cover"
-      ).length;
-      let pageNo = this.pageConfig.showCover
-        ? curPageNo - coverPageCount
-        : curPageNo;
-      return pageNo * this.pageConfig.columnNumber + columnNo + 1;
-    },
-    getTotalPage() {
-      const pageCount = this.pages.filter((p) => p.pageType !== "cover").length;
-      return pageCount * this.pageConfig.columnNumber;
+  },
+  methods: {
+    created() {},
+    mounted() {},
+    getDomTop(position, index, subIndex, innerIndex) {
+      let arr = cloneDeep(this.paperDetailsWithTop);
+      if (subIndex == undefined && innerIndex == undefined) {
+        arr[index].position = {
+          top: position.top - 40,
+          height: position.height,
+        };
+      }
+      if (subIndex) {
+        if (innerIndex == undefined) {
+          arr[index]["paperDetailUnits"][subIndex].position = {
+            top: position.top - 40,
+            height: position.height,
+          };
+        } else {
+          arr[index]["paperDetailUnits"][subIndex]["question"]["subQuestions"][
+            innerIndex
+          ].position = {
+            top: position.top - 40,
+            height: position.height,
+          };
+        }
+      }
+      this.paperDetailsWithTop = arr;
     },
-    getPageNumberCont(pageNumberRule, curPageNo, columnNo) {
-      const pageCont = `第${this.getPageNumber(
-        curPageNo,
-        columnNo
-      )}页(共${this.getTotalPage()}页)`;
-      return pageNumberRule
-        ? pageNumberRule.replace("${pageNumber}", pageCont)
-        : pageCont;
+    getPageNumberCont(pageNo) {
+      return `第${pageNo}页 共${this.flatData.length}页`;
     },
   },
 };

文件差異過大導致無法顯示
+ 2 - 0
src/modules/paper-export/previewAnswer.js


+ 17 - 13
src/modules/paper-export/views/AnswerTemplateBuild.vue

@@ -21,6 +21,7 @@
         ref="AnswerTemplateView"
         class="preview-body"
         :answerData="paperJson"
+        :pageCountMode="pageCountMode"
       ></answer-template-view>
     </div>
   </div>
@@ -31,7 +32,7 @@
 // import PaperTemplateView from "../components/PaperTemplateView.vue";
 import AnswerTemplateView from "../components/AnswerTemplateView.vue";
 // import { deepCopy } from "../../card/plugins/utils";
-// import previewTemp from "../previewTemp";
+import previewTemp from "../previewTemp";
 import { paperDetailInfoApi } from "../../paper/api";
 // import { paperTemplateListApi, paperPdfDownloadApi } from "../api";
 import { paperPdfDownloadApi } from "../api";
@@ -67,6 +68,7 @@ export default {
       },
       configSources: [],
       prepareDownloadPdf: false,
+      pageCountMode: "SIMPLE",
     };
   },
   mounted() {
@@ -85,8 +87,9 @@ export default {
         }
 
         this.seqMode = answerSet.seqMode;
-        this.curPaperTemp = answerSet.paperTemp;
-        this.configModalForm = answerSet.configModalForm;
+        this.pageCountMode = answerSet.pageCountMode;
+        // this.curPaperTemp = answerSet.paperTemp;
+        // this.configModalForm = answerSet.configModalForm;
 
         await this.getPaperJson();
       } catch (error) {
@@ -98,15 +101,16 @@ export default {
       });
     },
     emitFrameResult(success = true, errorMsg = "", htmlCont = "") {
-      alert("success:" + success, errorMsg, htmlCont);
-      // window.parent &&
-      //   window.parent.submitPaperTemp &&
-      //   window.parent.submitPaperTemp({
-      //     success,
-      //     errorMsg,
-      //     htmlCont,
-      //     templateId: this.curPaperTemp.id,
-      //   });
+      console.log("htmlC", htmlCont);
+      window.parent &&
+        window.parent.submitPaperTemp &&
+        window.parent.submitPaperTemp({
+          success,
+          errorMsg,
+          htmlCont,
+          // templateId: this.curPaperTemp.id,
+          templateId: null,
+        });
     },
     async getPaperJson() {
       const res = await paperDetailInfoApi({
@@ -190,7 +194,7 @@ export default {
     // img ------ end >
     // download ------ start >
     getPreviewTemp() {
-      // return previewTemp(this.$refs.PaperTemplateView.$el.outerHTML);
+      return previewTemp(this.$refs.AnswerTemplateView.$el.outerHTML);
     },
     async downloadPaperPdf() {
       const htmlCont = this.getPreviewTemp();

+ 45 - 25
src/modules/questions/views/GenPaper.vue

@@ -288,7 +288,7 @@
             </el-option>
           </el-select>
         </el-form-item>
-        <el-form-item
+        <!-- <el-form-item
           v-if="exportModel.exportContent === 'ANSWER'"
           label="答案模板"
         >
@@ -309,6 +309,15 @@
             >
             </el-option>
           </el-select>
+        </el-form-item> -->
+        <el-form-item
+          v-if="exportModel.exportContent === 'ANSWER'"
+          label="页数模式"
+        >
+          <el-radio-group v-model="pageCountMode" style="width: 160px">
+            <el-radio-button label="SIMPLE">单页</el-radio-button>
+            <el-radio-button label="DOUBLE">双页</el-radio-button>
+          </el-radio-group>
         </el-form-item>
       </el-form>
       <paper-build-config
@@ -484,6 +493,7 @@ export default {
         exportContent: "",
         seqMode: "MODE3",
       },
+      pageCountMode: "SIMPLE",
       isShow: true,
       examList: [],
       dialogModel: false,
@@ -902,13 +912,13 @@ export default {
         return;
       }
       if (this.exportModel.exportContent === "ANSWER") {
-        if (!this.exportModel.templateId) {
-          this.$notify({
-            message: "请选择答案模板",
-            type: "error",
-          });
-          return;
-        }
+        // if (!this.exportModel.templateId) {
+        //   this.$notify({
+        //     message: "请选择答案模板",
+        //     type: "error",
+        //   });
+        //   return;
+        // }
         this.toDownloadAnswerPdf();
         return;
       }
@@ -1082,7 +1092,8 @@ export default {
       if (this.downloading) return;
       this.downloading = true;
       window.answerSet = {
-        answerTemplateId: this.exportModel.templateId,
+        // answerTemplateId: this.exportModel.templateId,
+        pageCountMode: this.pageCountMode,
         seqMode: this.exportModel.seqMode,
       };
       const { href } = this.$router.resolve({
@@ -1106,29 +1117,38 @@ export default {
       }) => {
         if (!success) {
           this.downloading = false;
-          delete window.paperSet;
-          this.paperPreviewUrl = "";
+          if (templateId) {
+            delete window.paperSet;
+            this.paperPreviewUrl = "";
+          } else {
+            delete window.answerSet;
+            this.answerPreviewUrl = "";
+          }
+
           this.$message.error(errorMsg);
           this.exportDialog = false;
           return;
         }
         // this.paperPreviewUrl = "";
-
-        const res = await downloadByApi(() => {
-          return paperPdfDownloadApi({
-            content: htmlCont,
-            templateId,
-            paperId: this.exportModel.id,
+        if (templateId) {
+          const res = await downloadByApi(() => {
+            return paperPdfDownloadApi({
+              content: htmlCont,
+              templateId,
+              paperId: this.exportModel.id,
+            });
+          }).catch((e) => {
+            this.$message.error(e || "下载失败,请重新尝试!");
           });
-        }).catch((e) => {
-          this.$message.error(e || "下载失败,请重新尝试!");
-        });
-        this.exportDialog = false;
-        this.downloading = false;
+          this.exportDialog = false;
+          this.downloading = false;
 
-        if (!res) return;
-        this.$message.success("下载成功!");
-        delete window.paperSet;
+          if (!res) return;
+          this.$message.success("下载成功!");
+          delete window.paperSet;
+        } else {
+          alert("答案");
+        }
       };
     },
   },

部分文件因文件數量過多而無法顯示