zhangjie 2 سال پیش
والد
کامیت
3b8b7d9ebe

+ 4 - 0
src/modules/question/components/QuestionImportEdit.vue

@@ -338,6 +338,10 @@ export default {
     getRichTextGroup() {
       let groupSetList = [];
       this.paperData.forEach((detail) => {
+        groupSetList.push({
+          id: randomCode(),
+          indexs: detail.detailIndex,
+        });
         detail.questions.forEach((question) => {
           groupSetList.push({
             id: randomCode(),

+ 0 - 970
src/modules/question/components/QuestionImportEdit1.vue

@@ -1,970 +0,0 @@
-<template>
-  <div class="question-import-edit">
-    <el-dialog
-      custom-class="question-import-edit-dialog"
-      :visible.sync="modalIsShow"
-      :close-on-click-modal="false"
-      :close-on-press-escape="false"
-      append-to-body
-      fullscreen
-      destroy-on-close
-      :show-close="false"
-      @opened="visibleChange"
-      @closed="initData"
-    >
-      <div slot="title" class="box-justify">
-        <div>
-          <h2>文件上传</h2>
-        </div>
-        <div>
-          <upload-button
-            btn-content="重新上传文件"
-            btn-icon="icon icon-import"
-            :disabled="loading"
-            :upload-data="uploadData"
-            :upload-url="uploadUrl"
-            :format="importFileTypes"
-            @valid-error="uploadError"
-            @upload-error="uploadError"
-            @upload-success="uploaded"
-          ></upload-button>
-          <el-button
-            size="small"
-            type="danger"
-            icon="icon icon-back-white"
-            @click="cancel"
-            >返回</el-button
-          >
-        </div>
-      </div>
-      <div class="qe-body">
-        <div class="qe-part qe-part-edit">
-          <div class="qe-part-main">
-            <div class="qe-part-head">
-              <h3>题目编辑</h3>
-              <div>
-                <i class="icon icon-tips"></i>
-                提示:若识别有误,可点击左侧题目按格式进行修改后重新识别
-              </div>
-            </div>
-            <div class="qe-part-body">
-              <v-editor
-                ref="RichTextEditor"
-                v-model="paperRichJson"
-                :enable-formula="false"
-                :enable-audio="false"
-                custom-emit-input
-                :custom-render-action="renderRichText"
-                :custom-tojson-action="richTextToJSON"
-              ></v-editor>
-            </div>
-          </div>
-        </div>
-        <div class="qe-part qe-part-view">
-          <div class="qe-part-main">
-            <div class="qe-part-head">
-              <h3>题目阅览</h3>
-              <div>
-                <el-button
-                  size="small"
-                  type="primary"
-                  plain
-                  icon="icon icon-export-answer"
-                  @click="toImportAnswer"
-                  >导入答案属性</el-button
-                >
-                <el-button
-                  size="small"
-                  type="primary"
-                  icon="icon icon-save-white"
-                  :loading="loading"
-                  @click="confirm"
-                  >识别无误,加入题库</el-button
-                >
-              </div>
-            </div>
-            <div id="qe-part-paper" class="qe-part-body">
-              <question-import-paper-edit
-                v-if="paperData.length"
-                ref="QuestionImportPaperEdit"
-                :key="questionKey"
-                :paper="paperData"
-                :course-id="data.importData.courseId"
-              ></question-import-paper-edit>
-            </div>
-          </div>
-        </div>
-        <div class="qe-middle">
-          <div class="qe-middle-arrow"></div>
-          <el-button
-            size="small"
-            type="primary"
-            :loading="loading"
-            @click="toParse"
-            >识别</el-button
-          >
-        </div>
-      </div>
-    </el-dialog>
-
-    <!-- 上传答案文件 -->
-    <import-file-dialog
-      ref="ImportAnswerDialog"
-      dialog-title="导入答案"
-      :template-download-handle="answerTemplateDownload"
-      :upload-url="uploadAnswerUrl"
-      :upload-data="uploadAnswerData"
-      add-file-param="dataFile"
-      @uploaded="answerUploaded"
-    ></import-file-dialog>
-  </div>
-</template>
-
-<script>
-// import paperRichTextJson from "../datas/paperRichText.json";
-// import paperParseData from "../datas/paperParseData.json";
-
-import { calcSum, deepCopy, objTypeOf, randomCode } from "@/plugins/utils";
-import QuestionImportPaperEdit from "./QuestionImportPaperEdit.vue";
-import UploadButton from "@/components/UploadButton.vue";
-import { isAnEmptyRichText } from "@/utils/utils";
-import {
-  questionImportPaperSave,
-  questionImportParseRichText,
-  questionImportDownloadTemplate,
-} from "../api";
-import ImportFileDialog from "@/components/ImportFileDialog.vue";
-import { QUESTION_API } from "@/constants/constants";
-import { propertyNameQueryApi } from "@/modules/question/api";
-import { downloadByApi } from "@/plugins/download";
-import { richTextToJSON, renderRichText } from "./import-edit/richText";
-
-const questionInfoField = [
-  "courseId",
-  "difficulty",
-  "quesProperties",
-  "score",
-  "publicity",
-  "control",
-  "answerAnalysis",
-  "quesAnswer",
-];
-
-export default {
-  name: "QuestionExportEdit",
-  components: { QuestionImportPaperEdit, ImportFileDialog, UploadButton },
-  props: {
-    data: {
-      type: Object,
-      default() {
-        return {
-          richText: { sections: [] },
-          detailInfo: [],
-          importData: {
-            courseId: "",
-            courseName: "",
-            name: "",
-            checkTotalScore: false,
-            useOriginalPaper: false,
-            totalScore: 0,
-          },
-        };
-      },
-    },
-  },
-  data() {
-    return {
-      modalIsShow: false,
-      loading: false,
-      questionKey: "",
-      paperData: [],
-      paperRichJson: { sections: [] },
-      richTextToJSON,
-      renderRichText,
-      lastPaperScrollTop: 0,
-      lastRichTextScrollTop: 0,
-      richTextIndexList: [],
-      scrollType: "",
-      // upload answer
-      uploadAnswerUrl: `${QUESTION_API}/word/parse/import`,
-      uploadAnswerData: {},
-      // word upload
-      uploadData: {},
-      importFileTypes: ["docx", "doc"],
-      uploadUrl: `${QUESTION_API}/word/parse/struct`,
-    };
-  },
-  methods: {
-    async visibleChange() {
-      await this.getCourseProperty();
-
-      // this.resetData({
-      //   richText: paperRichTextJson,
-      //   detailInfo: paperParseData,
-      // });
-      this.resetData(this.data);
-
-      this.$nextTick(() => {
-        this.registScrollEvent();
-      });
-    },
-    resetData({ richText, detailInfo }) {
-      this.paperData = deepCopy(detailInfo);
-      this.paperRichJson = this.transformRichText(deepCopy(richText));
-      this.uploadData = { courseId: this.data.importData.courseId };
-      this.transformDataInfo();
-      this.questionKey = randomCode();
-
-      this.$nextTick(() => {
-        this.getRichTextIndexList();
-      });
-    },
-    getRichTextIndexList() {
-      const richTextBodyDom =
-        this.$refs.RichTextEditor.$el.querySelector(".v-editor-body");
-      let richTextIndexList = [];
-      richTextBodyDom.childNodes.forEach((sectionNode) => {
-        const id = sectionNode.getAttribute("id");
-        if (!id) return;
-        if (
-          sectionNode.className &&
-          sectionNode.className.includes("section-error")
-        )
-          return;
-
-        const index = id.replace("section-", "") * 1;
-        richTextIndexList.push([index, sectionNode.offsetTop]);
-      });
-      this.richTextIndexList = richTextIndexList;
-    },
-    transformRichText(richText) {
-      let nsections = [];
-      richText.sections.forEach((section) => {
-        nsections.push({
-          blocks: section.blocks,
-          attributes: { id: `section-${section.remark.index}` },
-        });
-        if (section.remark && !section.remark.status) {
-          nsections.push({
-            blocks: [
-              {
-                type: "text",
-                value: section.remark.cause,
-              },
-            ],
-            attributes: {
-              id: `section-error-${section.remark.index}`,
-              class: "section-error",
-            },
-          });
-        }
-      });
-      return { sections: nsections };
-    },
-    async getCourseProperty() {
-      const res = await propertyNameQueryApi(this.data.importData.courseId, "");
-      const optionList = res.data || [];
-      window.sessionStorage.setItem(
-        "coursePropertys",
-        JSON.stringify({ optionList, courseId: this.data.importData.courseId })
-      );
-    },
-    transformDataInfo() {
-      this.transformRichImg(this.paperRichJson);
-      this.paperData.forEach((detail) => {
-        detail.questions.forEach((question) => {
-          this.transformQuestion(question);
-          if (question.subQuestions && question.subQuestions.length) {
-            question.subQuestions.forEach((subq) => {
-              this.transformQuestion(subq);
-            });
-          }
-        });
-      });
-    },
-    transformQuestion(question) {
-      this.transformRichImg(question.body);
-      this.transformRichImg(question.answerRichTexts);
-      if (question.options && question.options.length) {
-        question.options.forEach((item) => {
-          this.transformRichImg(item.body);
-        });
-      }
-      question.quesAnswer = this.transformQuestionAnser(question.quesAnswer);
-    },
-    transformRichImg(richText) {
-      if (isAnEmptyRichText(richText)) return;
-
-      const rate = 96 / 300;
-      richText.sections.forEach((section) => {
-        section.blocks.forEach((block) => {
-          if (block.type !== "image" || !block.param) return;
-          block.param.width = block.param.width * rate;
-          block.param.height = block.param.height * rate;
-        });
-      });
-    },
-    transformQuestionAnser(quesAnswer) {
-      let qAnswer = null;
-      try {
-        qAnswer = quesAnswer ? JSON.parse(quesAnswer) : null;
-      } catch (error) {
-        console.log(error);
-      }
-      if (!qAnswer || objTypeOf(qAnswer) !== "array") return quesAnswer;
-
-      qAnswer.forEach((item) => {
-        this.transformRichImg(item);
-      });
-      return JSON.stringify(qAnswer);
-    },
-    initData() {
-      this.paperData = [];
-      this.paperRichJson = { sections: [] };
-      window.sessionStorage.removeItem("coursePropertys");
-      this.$message.closeAll();
-      this.removeScrollEvent();
-    },
-    cancel() {
-      this.modalIsShow = false;
-    },
-    open() {
-      this.modalIsShow = true;
-    },
-    async toParse() {
-      if (isAnEmptyRichText(this.paperRichJson)) {
-        this.$message.error("请输入试卷内容!");
-        return;
-      }
-
-      if (this.loading) return;
-      this.loading = true;
-
-      let richText = this.$refs.RichTextEditor.emitJsonAction();
-      richText.sections = richText.sections.filter(
-        (item) =>
-          !item.attributes || item.attributes["class"] !== "section-error"
-      );
-
-      const res = await questionImportParseRichText({
-        richText,
-        courseId: this.data.importData.courseId,
-      }).catch(() => {});
-      this.loading = false;
-      if (!res) return;
-
-      const cacheData = this.getCachePaperInfo(
-        this.getImportPaperData(),
-        questionInfoField
-      );
-      // console.log(cacheData);
-      this.paperData = this.assignCachePaperData(
-        res.data.detailInfo,
-        cacheData
-      );
-      this.paperRichJson = this.transformRichText(deepCopy(res.data.richText));
-      this.questionKey = randomCode();
-
-      this.$nextTick(() => {
-        this.getRichTextIndexList();
-      });
-    },
-    getCachePaperInfo(paperData, cacheFields = []) {
-      let cachePaperInfo = {};
-      paperData.forEach((detail, dIndex) => {
-        detail.questionInfo.forEach((question, qIndex) => {
-          let info = {};
-          let k = `${dIndex + 1}_${qIndex + 1}`;
-          if (cacheFields.length) {
-            cacheFields.forEach((field) => {
-              info[field] = question[field];
-            });
-          } else {
-            info = { ...question };
-          }
-
-          cachePaperInfo[k] = info;
-
-          if (question.subQuestions && question.subQuestions.length) {
-            question.subQuestions.forEach((subq, subqIndex) => {
-              let info = {};
-              let k = `${dIndex + 1}_${qIndex + 1}_${subqIndex + 1}`;
-              if (cacheFields.length) {
-                cacheFields.forEach((field) => {
-                  info[field] = subq[field];
-                });
-              } else {
-                info = { ...subq };
-              }
-
-              cachePaperInfo[k] = info;
-            });
-          }
-        });
-      });
-      // console.log(cachePaperInfo);
-      return cachePaperInfo;
-    },
-    assignCachePaperData(paperData, cacheData, mergeReverse = false) {
-      return paperData.map((detail, dIndex) => {
-        detail.questions = detail.questions.map((question, qIndex) => {
-          let k = `${dIndex + 1}_${qIndex + 1}`;
-          let nq = this.mergeObjData(
-            question,
-            cacheData[k] || {},
-            mergeReverse
-          );
-          if (question.subQuestions && question.subQuestions.length) {
-            nq.subQuestions = question.subQuestions.map((subq, subqIndex) => {
-              let k = `${dIndex + 1}_${qIndex + 1}_${subqIndex + 1}`;
-              return this.mergeObjData(subq, cacheData[k] || {}, mergeReverse);
-            });
-          }
-          return nq;
-        });
-        return detail;
-      });
-    },
-    isNull(val) {
-      if (val) {
-        if (val === "[]") return true;
-        if (objTypeOf(val) === "array" && !val.length) return true;
-      }
-      return val === null || val === "" || val === undefined;
-    },
-    mergeObjData(targetObj, cacheObj, mergeReverse) {
-      let data = { ...targetObj };
-      Object.keys(cacheObj).forEach((k) => {
-        if (mergeReverse) {
-          data[k] = this.isNull(cacheObj[k]) ? targetObj[k] : cacheObj[k];
-        } else {
-          data[k] = this.isNull(targetObj[k]) ? cacheObj[k] : targetObj[k];
-        }
-      });
-      return data;
-    },
-    getImportPaperData() {
-      if (!this.$refs.QuestionImportPaperEdit) return [];
-      let paperData = deepCopy(this.$refs.QuestionImportPaperEdit.getData());
-      const transformFieldMap = { body: "quesBody", options: "quesOptions" };
-      const fields = Object.keys(transformFieldMap);
-      const course = {
-        id: this.data.importData.courseId,
-        name: this.data.importData.courseName,
-      };
-
-      const transformQuestion = (question) => {
-        question.id = null;
-        question.course = course;
-        fields.forEach((field) => {
-          question[transformFieldMap[field]] = question[field];
-          delete question[field];
-        });
-        if (question.quesOptions && question.quesOptions.length) {
-          question.quesOptions = question.quesOptions.map((option) => {
-            option.optionBody = option.body;
-            delete option.body;
-            return option;
-          });
-        }
-        return question;
-      };
-
-      const detailInfo = paperData.map((detail) => {
-        const questionInfo = detail.questions.map((question) => {
-          transformQuestion(question);
-
-          if (question.subQuestions && question.subQuestions.length) {
-            question.subQuestions = question.subQuestions.map((subq) =>
-              transformQuestion(subq)
-            );
-            question.score = calcSum(
-              question.subQuestions.map((q) => q.score || 0)
-            );
-          }
-          return question;
-        });
-
-        return {
-          name: detail.name,
-          number: detail.number,
-          questionCount: questionInfo.length,
-          questionInfo,
-          questionScore: detail.questionScore,
-          totalScore: calcSum(questionInfo.map((q) => q.score || 0)),
-        };
-      });
-      // console.log(detailInfo);
-      return detailInfo;
-    },
-    checkImportPaperData(paperData) {
-      this.$message.closeAll();
-
-      // 题目内容校验
-      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",
-        "LISTENING_QUESTION",
-      ];
-      const ALLOW_EMPTY_BODY_QUESTION = [
-        "LISTENING_QUESTION",
-        ...MATCHING_QUESTION,
-      ];
-      let errInfos = [];
-      paperData.forEach((detail) => {
-        detail.questionInfo.forEach((question) => {
-          const { questionType, quesBody } = question;
-          const questionTitle = `第${detail.number}大题第${question.number}小题`;
-          let qErrInfo = [];
-          // 题干
-          if (
-            !ALLOW_EMPTY_BODY_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.optionBody)
-              )
-            ) {
-              qErrInfo.push(`有选择内容为空`);
-            }
-          }
-
-          // 小题数
-          if (
-            NESTED_QUESTION.includes(questionType) &&
-            !question.subQuestions.length
-          ) {
-            qErrInfo.push(`没有小题`);
-          }
-
-          if (qErrInfo.length) {
-            errInfos.push(`${questionTitle}${qErrInfo.join("、")}`);
-            qErrInfo = [];
-          }
-
-          // 选词填空、段落匹配,单用模式时校验输入答案是否重复
-          if (
-            MATCHING_QUESTION.includes(questionType) &&
-            question.quesParam.matchingMode === 1
-          ) {
-            let selectedAnswer = [],
-              errorQuestionIndexs = [];
-            question.subQuestions.forEach((subq, sindex) => {
-              if (selectedAnswer.includes(subq.quesAnswer)) {
-                errorQuestionIndexs.push(`${question.number}-${sindex + 1}`);
-              } else {
-                if (subq.quesAnswer !== "[]")
-                  selectedAnswer.push(subq.quesAnswer);
-              }
-            });
-            if (errorQuestionIndexs.length) {
-              errInfos.push(
-                `第${
-                  detail.number
-                }大题${errorQuestionIndexs.join()}小题答案重复!`
-              );
-            }
-          }
-
-          if (!NESTED_QUESTION.includes(questionType)) return;
-
-          // 套题小题校验
-          question.subQuestions.forEach((subq, sindex) => {
-            const subqTitle = `第${detail.number}大题第${question.number}-${
-              sindex + 1
-            }小题`;
-            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.optionBody)
-                )
-              ) {
-                qErrInfo.push(`有选择内容为空`);
-              }
-            }
-
-            if (qErrInfo.length) {
-              errInfos.push(`${subqTitle}${qErrInfo.join("、")}`);
-              qErrInfo = [];
-            }
-          });
-        });
-      });
-      if (errInfos.length) {
-        this.$message({
-          showClose: true,
-          message: errInfos.join("。"),
-          type: "error",
-          duration: 0,
-        });
-        return;
-      }
-
-      if (!this.data.importData.useOriginalPaper) return true;
-
-      let detailNumbers = paperData.map((detail) => detail.number);
-      // 大题号重复性校验
-      let repeatDetaiNumbers = [];
-      let detailNums = [];
-      for (let i = 0; i < detailNumbers.length; i++) {
-        const num = detailNumbers[i];
-        if (detailNums.includes(num)) {
-          if (!repeatDetaiNumbers.includes(num)) repeatDetaiNumbers.push(num);
-        } else {
-          detailNums.push(num);
-        }
-      }
-      if (repeatDetaiNumbers.length) {
-        this.$message({
-          showClose: true,
-          message: `大题号${repeatDetaiNumbers.join("、")}重复`,
-          type: "error",
-          duration: 0,
-        });
-        return;
-      }
-      // 大题号连续性校验
-      for (let i = 0; i < detailNumbers.length; i++) {
-        if (detailNumbers[i] - 1 !== i) {
-          this.$message({
-            showClose: true,
-            message: "大题号不连续",
-            type: "error",
-            duration: 0,
-          });
-          return;
-        }
-      }
-
-      // 答案、分数校验
-      let totalScore = calcSum(paperData.map((d) => d.totalScore));
-      let errQuestions = [];
-      paperData.forEach((detail) => {
-        detail.questionInfo.forEach((question) => {
-          if (question.subQuestions && question.subQuestions.length) {
-            let subIndexs = [];
-            question.subQuestions.forEach((subq, sind) => {
-              if (!subq.score)
-                subIndexs.push(question.number + "-" + (sind + 1));
-            });
-            if (subIndexs.length)
-              errQuestions.push(
-                `第${detail.number}大题第${subIndexs.join()}小题`
-              );
-          } else {
-            if (!question.score) {
-              errQuestions.push(
-                `第${detail.number}大题第${question.number}小题`
-              );
-            }
-          }
-        });
-      });
-      if (errQuestions.length) {
-        this.$message({
-          showClose: true,
-          message: `请设置如下试题的分值:${errQuestions.join("、")}。`,
-          type: "error",
-          duration: 0,
-        });
-        return;
-      }
-
-      if (
-        this.data.importData.checkTotalScore &&
-        totalScore !== this.data.importData.totalScore
-      ) {
-        this.$message({
-          showClose: true,
-          message: `试卷总分与导入设置的总分不一致!`,
-          type: "error",
-          duration: 0,
-        });
-        return;
-      }
-
-      return true;
-    },
-    async confirm() {
-      const confirm = await this.$confirm("确认加入题库吗?", "提示", {
-        type: "warning",
-      }).catch(() => {});
-      if (confirm !== "confirm") return;
-
-      const detailInfo = this.getImportPaperData();
-      if (!this.checkImportPaperData(detailInfo)) return;
-
-      if (this.loading) return;
-      this.loading = true;
-
-      const res = await questionImportPaperSave({
-        ...this.data.importData,
-        detailInfo,
-      }).catch(() => {});
-
-      this.loading = false;
-      if (!res) return;
-
-      this.$message.success("提交成功!");
-      this.$emit("modified");
-      this.cancel();
-    },
-    // 导入答案属性
-    toImportAnswer() {
-      const detailInfo = this.getImportPaperData();
-      this.uploadAnswerData = {
-        detailInfo: JSON.stringify(detailInfo),
-        ...this.data.importData,
-      };
-      this.$refs.ImportAnswerDialog.open();
-    },
-    async answerTemplateDownload() {
-      const detailInfo = this.getImportPaperData();
-
-      const res = await downloadByApi(() => {
-        return questionImportDownloadTemplate({
-          detailInfo,
-          ...this.data.importData,
-        });
-      }).catch((e) => {
-        this.$message.error(e || "下载失败,请重新尝试!");
-      });
-
-      if (!res) return;
-      this.$message.success("下载成功!");
-    },
-    answerUploaded(res) {
-      const cacheData = this.getCachePaperInfo(
-        res.data.detailInfo,
-        questionInfoField
-      );
-      this.paperData = this.assignCachePaperData(
-        this.paperData,
-        cacheData,
-        true
-      );
-      this.questionKey = randomCode();
-    },
-    // word upload
-    uploaded(res) {
-      this.$message.success("上传成功!");
-      this.paperRichJson = deepCopy(res.data.richText);
-      this.paperData = deepCopy(res.data.detailInfo);
-      this.transformDataInfo();
-      this.questionKey = randomCode();
-    },
-    uploadError(error) {
-      this.$message.error(error.message);
-    },
-    // scroll
-    registScrollEvent() {
-      document
-        .getElementById("qe-part-paper")
-        .addEventListener("scroll", this.paperScrollEvent);
-      this.$refs.RichTextEditor.$el
-        .querySelector(".v-editor-container")
-        .addEventListener("scroll", this.richTextScrollEvent);
-    },
-    removeScrollEvent() {
-      document
-        .getElementById("qe-part-paper")
-        .removeEventListener("scroll", this.paperScrollEvent);
-      this.$refs.RichTextEditor.$el
-        .querySelector(".v-editor-container")
-        .removeEventListener("scroll", this.richTextScrollEvent);
-    },
-    paperScrollEvent(e) {
-      // e.preventDefault();
-      // e.stopPropagation();
-      if (this.scrollType === "rich-text") {
-        this.lastPaperScrollTop =
-          document.getElementById("qe-part-paper").scrollTop;
-        return;
-      }
-      this.scrollType = "paper";
-      setTimeout(() => {
-        this.scrollType = "";
-      }, 100);
-      const questionContIndexList =
-        this.$refs.QuestionImportPaperEdit.questionContIndexList;
-
-      const scrollTop = e.target.scrollTop;
-      const isScrollDown = scrollTop > this.lastPaperScrollTop;
-      this.lastPaperScrollTop = scrollTop;
-      const targeContIndex = questionContIndexList.findIndex(
-        (item) => scrollTop < item[3]
-      );
-      let targeContPercent = 0;
-      let targeCont = null;
-      let nextTargetCont = null;
-      if (targeContIndex !== -1) {
-        targeCont = questionContIndexList[targeContIndex - 1];
-        nextTargetCont = questionContIndexList[targeContIndex];
-        targeContPercent =
-          (scrollTop - targeCont[3]) / (nextTargetCont[3] - targeCont[3]);
-      } else {
-        targeCont = questionContIndexList.slice(-1)[0];
-        const textHeight = this.$refs.QuestionImportPaperEdit.$el.offsetHeight;
-        targeContPercent =
-          (scrollTop - targeCont[3]) / (textHeight - targeCont[3]);
-      }
-
-      const richTextSectionDom = document.getElementById(
-        `section-${targeCont[2][0]}`
-      );
-      if (!richTextSectionDom) return;
-
-      const richTextContainerDom = this.$refs.RichTextEditor.$el.querySelector(
-        ".v-editor-container"
-      );
-      const richTextMainDom =
-        this.$refs.RichTextEditor.$el.querySelector(".v-editor-main");
-      const sectionOffsetTop = richTextSectionDom.offsetTop;
-      let nextSectionOffsetTop = richTextMainDom.offsetHeight;
-
-      if (nextTargetCont) {
-        const nextRichTextSectionDom = document.getElementById(
-          `section-${nextTargetCont[2][0]}`
-        );
-        if (nextRichTextSectionDom) {
-          nextSectionOffsetTop = nextRichTextSectionDom.offsetTop;
-        } else {
-          nextSectionOffsetTop =
-            richTextSectionDom.offsetTop + richTextSectionDom.offsetHeight;
-        }
-      }
-
-      const textScrollTop =
-        sectionOffsetTop +
-        targeContPercent * (nextSectionOffsetTop - sectionOffsetTop);
-      // console.log(
-      //   targeCont[2],
-      //   textScrollTop,
-      //   targeContPercent,
-      //   nextSectionOffsetTop,
-      //   sectionOffsetTop
-      // );
-      richTextContainerDom.scrollTop = isScrollDown
-        ? Math.max(textScrollTop, richTextContainerDom.scrollTop)
-        : Math.min(textScrollTop, richTextContainerDom.scrollTop);
-    },
-    richTextScrollEvent(e) {
-      if (this.scrollType === "paper") {
-        this.lastRichTextScrollTop =
-          this.$refs.RichTextEditor.$el.querySelector(
-            ".v-editor-container"
-          ).scrollTop;
-        return;
-      }
-      this.scrollType = "rich-text";
-      setTimeout(() => {
-        this.scrollType = "";
-      }, 100);
-
-      const isScrollDown = e.target.scrollTop > this.lastRichTextScrollTop;
-      // console.log(isScrollDown, e.target.scrollTop, this.lastRichTextScrollTop);
-      this.lastRichTextScrollTop = e.target.scrollTop;
-      const offsetH = isScrollDown ? 150 : 0;
-      const scrollTop = e.target.scrollTop + offsetH;
-
-      const richTextMainDom =
-        this.$refs.RichTextEditor.$el.querySelector(".v-editor-main");
-      const questionContIndexList =
-        this.$refs.QuestionImportPaperEdit.questionContIndexList;
-
-      const findQuestionItemDom = (sectionIndex) => {
-        const questionCont = questionContIndexList.find((item) =>
-          item[2].includes(sectionIndex)
-        );
-        if (!questionCont) return;
-        const [id, type] = questionCont;
-        let itemDom = document.getElementById(id);
-        if (type === "body") {
-          itemDom = itemDom.querySelector(".ep-question-title");
-        } else if (type === "option") {
-          itemDom = itemDom.querySelector(".ep-question-body");
-        } else if (type === "answer") {
-          itemDom =
-            itemDom.querySelector(".question-info-view") ||
-            itemDom.querySelector(".ep-question-props");
-        }
-        return itemDom;
-      };
-
-      const targeContIndex = this.richTextIndexList.findIndex(
-        (item) => scrollTop < item[1]
-      );
-      if (!targeContIndex) return;
-      let targeContPercent = 0;
-      let targeCont = null;
-      let nextTargetCont = null;
-      if (targeContIndex !== -1) {
-        targeCont = this.richTextIndexList[targeContIndex - 1];
-        nextTargetCont = this.richTextIndexList[targeContIndex];
-        targeContPercent =
-          (scrollTop - targeCont[1]) / (nextTargetCont[1] - targeCont[1]);
-      } else {
-        targeCont = this.richTextIndexList.slice(-1)[0];
-        const textHeight = richTextMainDom.offsetHeight;
-        targeContPercent =
-          (scrollTop - targeCont[1]) / (textHeight - targeCont[1]);
-      }
-
-      const questionContDom = findQuestionItemDom(targeCont[0]);
-      if (!questionContDom) return;
-      const questionListDom = this.$refs.QuestionImportPaperEdit.$el;
-      const elPos = questionListDom.getBoundingClientRect();
-      const questionPos = questionContDom.getBoundingClientRect();
-      const questionContOffsetTop = questionPos.y - elPos.y;
-      let nextQuestionContOffsetTop = questionListDom.offsetHeight;
-
-      if (nextTargetCont) {
-        const nextQuestionContDom = findQuestionItemDom(nextTargetCont[0]);
-        if (nextQuestionContDom) {
-          const nextQuestionPos = nextQuestionContDom.getBoundingClientRect();
-          nextQuestionContOffsetTop = nextQuestionPos.y - elPos.y;
-        } else {
-          nextQuestionContOffsetTop =
-            questionContOffsetTop + questionContDom.offsetHeight;
-        }
-      }
-
-      const questionScrollTop =
-        questionContOffsetTop +
-        targeContPercent * (nextQuestionContOffsetTop - questionContOffsetTop);
-      const questionContainerDom = document.getElementById("qe-part-paper");
-      questionContainerDom.scrollTop = isScrollDown
-        ? Math.max(questionScrollTop, questionContainerDom.scrollTop)
-        : Math.min(questionScrollTop, questionContainerDom.scrollTop);
-    },
-  },
-};
-</script>

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

@@ -211,6 +211,7 @@ export default {
       const questionCont = this.questionContIndexList.find((item) =>
         indexs.some((ind) => item[2].includes(ind))
       );
+      if (!questionCont) return;
       const questionContDom = document.getElementById(questionCont[0]);
       const elPos = this.$el.getBoundingClientRect();
       const itemPos = questionContDom.getBoundingClientRect();

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

@@ -42,6 +42,7 @@
       v-for="subq in question.subQuestions"
       :key="subq.id"
       class="ep-question-subq"
+      :id="`question-${subq.id}`"
     >
       <match-question
         ref="MatchQuestion"

+ 4 - 0
src/modules/question/components/import-edit/scrollMixins.js

@@ -29,6 +29,8 @@ export default {
         this.scrollType = "";
       }, 100);
 
+      if (!this.$refs.QuestionImportPaperEdit) return;
+
       const questionContIndexList =
         this.$refs.QuestionImportPaperEdit.questionContIndexList;
 
@@ -105,6 +107,8 @@ export default {
         this.scrollType = "";
       }, 100);
 
+      if (!this.$refs.QuestionImportPaperEdit) return;
+
       const isScrollDown = e.target.scrollTop > this.lastRichTextScrollTop;
       // console.log(isScrollDown, e.target.scrollTop, this.lastRichTextScrollTop);
       this.lastRichTextScrollTop = e.target.scrollTop;