|
@@ -9,7 +9,8 @@
|
|
fullscreen
|
|
fullscreen
|
|
destroy-on-close
|
|
destroy-on-close
|
|
:show-close="false"
|
|
:show-close="false"
|
|
- @open="visibleChange"
|
|
|
|
|
|
+ @opened="visibleChange"
|
|
|
|
+ @closed="initData"
|
|
>
|
|
>
|
|
<div slot="title" class="box-justify">
|
|
<div slot="title" class="box-justify">
|
|
<div>
|
|
<div>
|
|
@@ -73,10 +74,11 @@
|
|
</div>
|
|
</div>
|
|
<div class="qe-part-body">
|
|
<div class="qe-part-body">
|
|
<question-import-paper-edit
|
|
<question-import-paper-edit
|
|
|
|
+ v-if="paperData.length"
|
|
ref="QuestionImportPaperEdit"
|
|
ref="QuestionImportPaperEdit"
|
|
:key="questionKey"
|
|
:key="questionKey"
|
|
:paper="paperData"
|
|
:paper="paperData"
|
|
- :course-id="data.courseId"
|
|
|
|
|
|
+ :course-id="data.importData.courseId"
|
|
></question-import-paper-edit>
|
|
></question-import-paper-edit>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@@ -124,6 +126,7 @@ import { isAnEmptyRichText } from "@/utils/utils";
|
|
import { questionImportPaperSave, questionImportParseRichText } from "../api";
|
|
import { questionImportPaperSave, questionImportParseRichText } from "../api";
|
|
import ImportFileDialog from "@/components/ImportFileDialog.vue";
|
|
import ImportFileDialog from "@/components/ImportFileDialog.vue";
|
|
import { QUESTION_API } from "@/constants/constants";
|
|
import { QUESTION_API } from "@/constants/constants";
|
|
|
|
+import { propertyNameQueryApi } from "@/modules/question/api";
|
|
|
|
|
|
const questionInfoField = [
|
|
const questionInfoField = [
|
|
"courseId",
|
|
"courseId",
|
|
@@ -145,7 +148,13 @@ export default {
|
|
return {
|
|
return {
|
|
paperRichText: { sections: [] },
|
|
paperRichText: { sections: [] },
|
|
paperData: [],
|
|
paperData: [],
|
|
- courseId: "",
|
|
|
|
|
|
+ importData: {
|
|
|
|
+ courseId: "",
|
|
|
|
+ name: "",
|
|
|
|
+ checkTotalScore: false,
|
|
|
|
+ useOriginalPaper: false,
|
|
|
|
+ totalScore: 0,
|
|
|
|
+ },
|
|
};
|
|
};
|
|
},
|
|
},
|
|
},
|
|
},
|
|
@@ -155,22 +164,38 @@ export default {
|
|
modalIsShow: true,
|
|
modalIsShow: true,
|
|
loading: false,
|
|
loading: false,
|
|
questionKey: "",
|
|
questionKey: "",
|
|
- paperData: deepCopy(paperParseData),
|
|
|
|
- paperRichJson: deepCopy(paperRichTextJson),
|
|
|
|
- // paperData: [],
|
|
|
|
- // paperRichJson: { sections: [] },
|
|
|
|
|
|
+ paperData: [],
|
|
|
|
+ paperRichJson: { sections: [] },
|
|
// upload answer
|
|
// upload answer
|
|
uploadAnswerUrl: `${QUESTION_API}/paper/answer/import/`,
|
|
uploadAnswerUrl: `${QUESTION_API}/paper/answer/import/`,
|
|
// upload prop
|
|
// upload prop
|
|
uploadPropUrl: `${QUESTION_API}/paper/answer/import/`,
|
|
uploadPropUrl: `${QUESTION_API}/paper/answer/import/`,
|
|
};
|
|
};
|
|
},
|
|
},
|
|
|
|
+ beforeDestroy() {
|
|
|
|
+ window.sessionStorage.removeItem("coursePropertys");
|
|
|
|
+ },
|
|
methods: {
|
|
methods: {
|
|
- visibleChange() {
|
|
|
|
|
|
+ async visibleChange() {
|
|
|
|
+ await this.getCourseProperty();
|
|
|
|
+ this.paperData = deepCopy(paperParseData);
|
|
|
|
+ this.paperRichJson = deepCopy(paperRichTextJson);
|
|
// this.paperRichJson = deepCopy(this.data.paperRichText);
|
|
// this.paperRichJson = deepCopy(this.data.paperRichText);
|
|
// this.paperData = deepCopy(this.data.paperData);
|
|
// this.paperData = deepCopy(this.data.paperData);
|
|
this.questionKey = randomCode();
|
|
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() {
|
|
cancel() {
|
|
this.modalIsShow = false;
|
|
this.modalIsShow = false;
|
|
},
|
|
},
|
|
@@ -186,7 +211,7 @@ export default {
|
|
if (this.loading) return;
|
|
if (this.loading) return;
|
|
this.loading = true;
|
|
this.loading = true;
|
|
|
|
|
|
- const res = questionImportParseRichText(this.paperRichJson).catch(
|
|
|
|
|
|
+ const res = await questionImportParseRichText(this.paperRichJson).catch(
|
|
() => {}
|
|
() => {}
|
|
);
|
|
);
|
|
this.loading = false;
|
|
this.loading = false;
|
|
@@ -241,20 +266,139 @@ export default {
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
+ console.log(paperData);
|
|
return 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() {
|
|
async confirm() {
|
|
const confirm = await this.$confirm("确认加入题库吗?", "提示", {
|
|
const confirm = await this.$confirm("确认加入题库吗?", "提示", {
|
|
type: "warning",
|
|
type: "warning",
|
|
}).catch(() => {});
|
|
}).catch(() => {});
|
|
if (confirm !== "confirm") return;
|
|
if (confirm !== "confirm") return;
|
|
|
|
|
|
|
|
+ const paperData = this.getImportPaperData();
|
|
|
|
+ if (!this.checkImportPaperData(paperData)) return;
|
|
|
|
+
|
|
if (this.loading) return;
|
|
if (this.loading) return;
|
|
this.loading = true;
|
|
this.loading = true;
|
|
|
|
|
|
- const paperData = this.getImportPaperData();
|
|
|
|
- console.log(paperData);
|
|
|
|
-
|
|
|
|
const res = await questionImportPaperSave({
|
|
const res = await questionImportPaperSave({
|
|
courseId: this.courseId,
|
|
courseId: this.courseId,
|
|
paperData,
|
|
paperData,
|