zhangjie hace 2 años
padre
commit
a220a7072b

+ 28 - 0
src/components/selection/PropertySelect.vue

@@ -36,6 +36,7 @@ export default {
       type: [String, Number],
       default: "",
     },
+    useCache: { type: Boolean, default: false },
   },
   data() {
     return {
@@ -68,10 +69,21 @@ export default {
         this.optionList = [];
         return;
       }
+
+      if (this.useCache) {
+        const optionList = this.getCacheData();
+        if (optionList && optionList.length) {
+          this.optionList = optionList;
+          return;
+        }
+      }
+
       this.loading = true;
       const res = await propertyNameQueryApi(this.courseId, query);
       this.optionList = res.data || [];
       this.loading = false;
+
+      if (this.useCache) this.setCacheData();
     },
     select() {
       this.$emit("input", this.selected);
@@ -85,6 +97,22 @@ export default {
       this.selected = "";
       this.select();
     },
+    // cache
+    setCacheData() {
+      if (!this.optionList.length) return;
+      window.sessionStorage.setItem(
+        "coursePropertys",
+        JSON.stringify({ optionList: this.optionList, courseId: this.courseId })
+      );
+    },
+    getCacheData() {
+      const coursePropertys = window.sessionStorage.getItem("coursePropertys");
+      if (coursePropertys) {
+        let { optionList, courseId } = JSON.parse(coursePropertys);
+        if (courseId === this.courseId) return optionList;
+        return [];
+      }
+    },
   },
 };
 </script>

+ 4 - 1
src/modules/question/components/QuestionImportDialog.vue

@@ -216,7 +216,10 @@ export default {
       if (!res) return;
 
       this.$message.success("导入成功!");
-      this.$emit("modified");
+      this.$emit("modified", {
+        ...res.data,
+        importData: this.modalForm,
+      });
       this.cancel();
     },
   },

+ 156 - 12
src/modules/question/components/QuestionImportEdit.vue

@@ -9,7 +9,8 @@
       fullscreen
       destroy-on-close
       :show-close="false"
-      @open="visibleChange"
+      @opened="visibleChange"
+      @closed="initData"
     >
       <div slot="title" class="box-justify">
         <div>
@@ -73,10 +74,11 @@
             </div>
             <div class="qe-part-body">
               <question-import-paper-edit
+                v-if="paperData.length"
                 ref="QuestionImportPaperEdit"
                 :key="questionKey"
                 :paper="paperData"
-                :course-id="data.courseId"
+                :course-id="data.importData.courseId"
               ></question-import-paper-edit>
             </div>
           </div>
@@ -124,6 +126,7 @@ import { isAnEmptyRichText } from "@/utils/utils";
 import { questionImportPaperSave, questionImportParseRichText } from "../api";
 import ImportFileDialog from "@/components/ImportFileDialog.vue";
 import { QUESTION_API } from "@/constants/constants";
+import { propertyNameQueryApi } from "@/modules/question/api";
 
 const questionInfoField = [
   "courseId",
@@ -145,7 +148,13 @@ export default {
         return {
           paperRichText: { sections: [] },
           paperData: [],
-          courseId: "",
+          importData: {
+            courseId: "",
+            name: "",
+            checkTotalScore: false,
+            useOriginalPaper: false,
+            totalScore: 0,
+          },
         };
       },
     },
@@ -155,22 +164,38 @@ export default {
       modalIsShow: true,
       loading: false,
       questionKey: "",
-      paperData: deepCopy(paperParseData),
-      paperRichJson: deepCopy(paperRichTextJson),
-      // paperData: [],
-      // paperRichJson: { sections: [] },
+      paperData: [],
+      paperRichJson: { sections: [] },
       // upload answer
       uploadAnswerUrl: `${QUESTION_API}/paper/answer/import/`,
       // upload prop
       uploadPropUrl: `${QUESTION_API}/paper/answer/import/`,
     };
   },
+  beforeDestroy() {
+    window.sessionStorage.removeItem("coursePropertys");
+  },
   methods: {
-    visibleChange() {
+    async visibleChange() {
+      await this.getCourseProperty();
+      this.paperData = deepCopy(paperParseData);
+      this.paperRichJson = deepCopy(paperRichTextJson);
       // this.paperRichJson = deepCopy(this.data.paperRichText);
       // this.paperData = deepCopy(this.data.paperData);
       this.questionKey = randomCode();
     },
+    async getCourseProperty() {
+      const res = await propertyNameQueryApi(this.courseId, "");
+      const optionList = res.data || [];
+      window.sessionStorage.setItem(
+        "coursePropertys",
+        JSON.stringify({ optionList, courseId: this.data.importData.courseId })
+      );
+    },
+    initData() {
+      this.paperData = [];
+      this.paperRichJson = { sections: [] };
+    },
     cancel() {
       this.modalIsShow = false;
     },
@@ -186,7 +211,7 @@ export default {
       if (this.loading) return;
       this.loading = true;
 
-      const res = questionImportParseRichText(this.paperRichJson).catch(
+      const res = await questionImportParseRichText(this.paperRichJson).catch(
         () => {}
       );
       this.loading = false;
@@ -241,20 +266,139 @@ export default {
           });
         });
       });
+      console.log(paperData);
       return paperData;
     },
+    checkImportPaperData(paperData) {
+      // 题目内容校验
+      const MATCHING_QUESTION = ["PARAGRAPH_MATCHING", "BANKED_CLOZE"];
+      const SELECT_QUESTION = [
+        "SINGLE_ANSWER_QUESTION",
+        "MULTIPLE_ANSWER_QUESTION",
+        ...MATCHING_QUESTION,
+      ];
+      const NESTED_QUESTION = [
+        ...MATCHING_QUESTION,
+        "READING_COMPREHENSION",
+        "CLOZE",
+      ];
+      let errInfos = [];
+      paperData.forEach((detail) => {
+        detail.questions.forEach((question) => {
+          const { questionType, quesBody } = question;
+          const questionTitle = `第${detail.number}大题第${question.number}小题`;
+          let qErrInfo = [];
+          if (
+            !MATCHING_QUESTION.includes(questionType) &&
+            (!quesBody || isAnEmptyRichText(quesBody))
+          ) {
+            qErrInfo.push(`没有题干`);
+          }
+
+          if (SELECT_QUESTION.includes(questionType)) {
+            if (!question.quesOptions.length) {
+              qErrInfo.push(`没有选项`);
+            }
+            if (
+              question.quesOptions.some((option) =>
+                isAnEmptyRichText(option.body)
+              )
+            ) {
+              qErrInfo.push(`有选择内容为空`);
+            }
+          }
+
+          if (
+            NESTED_QUESTION.includes(questionType) &&
+            !question.subQuestions.length
+          ) {
+            qErrInfo.push(`没有小题`);
+          }
+          if (qErrInfo.length) {
+            errInfos.push(`${questionTitle}${qErrInfo.join("、")}`);
+            qErrInfo = [];
+          }
+
+          if (!NESTED_QUESTION.includes(questionType)) return;
+
+          question.subQuestions.forEach((subq, sindex) => {
+            const subqTitle = `第${detail.number}大题第${question.number}-${sindex}小题`;
+            if (
+              questionType === "READING_COMPREHENSION" &&
+              (!subq.quesBody || isAnEmptyRichText(subq.quesBody))
+            ) {
+              qErrInfo.push(`没有题干`);
+            }
+            if (
+              SELECT_QUESTION.includes(subq.subqType) &&
+              !MATCHING_QUESTION.includes(questionType)
+            ) {
+              if (!subq.quesOptions.length) {
+                qErrInfo.push(`没有选项`);
+              }
+              if (
+                subq.quesOptions.some((option) =>
+                  isAnEmptyRichText(option.body)
+                )
+              ) {
+                qErrInfo.push(`有选择内容为空`);
+              }
+            }
+
+            if (qErrInfo.length) {
+              errInfos.push(`${subqTitle}${qErrInfo.join("、")}`);
+              qErrInfo = [];
+            }
+          });
+        });
+      });
+      if (errInfos.length) {
+        this.$notify.error(errInfos.join("。"));
+        return;
+      }
+
+      if (!this.data.importData.useOriginalPaper) return true;
+      // 答案、分数校验
+      let totalScore = 0;
+      let errQuestions = [];
+      paperData.forEach((detail) => {
+        detail.questions.forEach((question) => {
+          if (!question.score) {
+            errQuestions.push(`第${detail.number}大题第${question.number}小题`);
+          } else {
+            totalScore += question.score;
+          }
+        });
+      });
+      if (errQuestions.length) {
+        this.$notify.error(
+          `请设置如下试题的分值:${errQuestions.join("、")}。`
+        );
+        return;
+      }
+
+      if (
+        this.data.importData.checkTotalScore &&
+        totalScore !== this.data.importData.totalScore
+      ) {
+        this.$notify.error("试卷总分与导入设置的总分不一致!");
+        return;
+      }
+
+      return true;
+    },
     async confirm() {
       const confirm = await this.$confirm("确认加入题库吗?", "提示", {
         type: "warning",
       }).catch(() => {});
       if (confirm !== "confirm") return;
 
+      const paperData = this.getImportPaperData();
+      if (!this.checkImportPaperData(paperData)) return;
+
       if (this.loading) return;
       this.loading = true;
 
-      const paperData = this.getImportPaperData();
-      console.log(paperData);
-
       const res = await questionImportPaperSave({
         courseId: this.courseId,
         paperData,

+ 0 - 1
src/modules/question/components/QuestionImportPaperEdit.vue

@@ -82,7 +82,6 @@ export default {
       });
       this.paperData = paperData;
     },
-    checkData() {},
     getData() {
       this.paperData.forEach((detail, dIndex) => {
         detail.questions.forEach((question) => {

+ 2 - 0
src/modules/question/components/QuestionInfoEdit.vue

@@ -75,6 +75,7 @@
           <property-select
             v-model="properties.coursePropertyId"
             :course-id="modalForm.courseId"
+            :use-cache="useCoursePropertyCache"
             @change="coursePropertyChange"
           ></property-select>
           <span class="prop-label">一级</span>
@@ -152,6 +153,7 @@ export default {
       type: String,
       default: "100px",
     },
+    useCoursePropertyCache: { type: Boolean, default: false },
   },
   data() {
     return {

+ 1 - 0
src/modules/question/components/import-edit/BooleanQuestion.vue

@@ -28,6 +28,7 @@
         ref="QuestionInfoEdit"
         :question="modalForm"
         label-width="72px"
+        use-course-property-cache
         @change="questionInfoChange"
       ></question-info-edit>
     </div>

+ 1 - 0
src/modules/question/components/import-edit/FillBlankQuestion.vue

@@ -30,6 +30,7 @@
         ref="QuestionInfoEdit"
         :question="modalForm"
         label-width="72px"
+        use-course-property-cache
         @change="questionInfoChange"
       ></question-info-edit>
     </div>

+ 1 - 0
src/modules/question/components/import-edit/MatchQuestion.vue

@@ -33,6 +33,7 @@
         ref="QuestionInfoEdit"
         :question="modalForm"
         label-width="72px"
+        use-course-property-cache
         @change="questionInfoChange"
       ></question-info-edit>
     </div>

+ 1 - 0
src/modules/question/components/import-edit/SelectQuestion.vue

@@ -52,6 +52,7 @@
         ref="QuestionInfoEdit"
         :question="modalForm"
         label-width="72px"
+        use-course-property-cache
         @change="questionInfoChange"
       ></question-info-edit>
     </div>

+ 1 - 0
src/modules/question/components/import-edit/TextAnswerQuestion.vue

@@ -24,6 +24,7 @@
         ref="QuestionInfoEdit"
         :question="modalForm"
         label-width="72px"
+        use-course-property-cache
         @change="questionInfoChange"
       ></question-info-edit>
     </div>

+ 11 - 2
src/modules/question/views/QuestionManage.vue

@@ -208,14 +208,18 @@
     <!-- QuestionImportDialog -->
     <question-import-dialog
       ref="QuestionImportDialog"
-      @modified="toPage(1)"
+      @modified="questionImported"
     ></question-import-dialog>
     <!-- FolderQuestionManageDialog -->
     <folder-question-manage-dialog
       ref="FolderQuestionManageDialog"
     ></folder-question-manage-dialog>
     <!-- QuestionImportEdit -->
-    <question-import-edit ref="QuestionImportEdit"></question-import-edit>
+    <question-import-edit
+      ref="QuestionImportEdit"
+      :data="questionImportData"
+      @modified="toPage(1)"
+    ></question-import-edit>
   </div>
 </template>
 
@@ -269,6 +273,7 @@ export default {
       curFolder: {},
       curCourse: {},
       curMoveType: "",
+      questionImportData: {},
     };
   },
   mounted() {
@@ -398,6 +403,10 @@ export default {
     toAddFolder() {
       this.$refs.FolderQuestionManageDialog.open();
     },
+    questionImported(data) {
+      this.questionImportData = data;
+      this.$refs.QuestionImportEdit.open();
+    },
   },
 };
 </script>