Kaynağa Gözat

导入试卷展示优化

zhangjie 2 yıl önce
ebeveyn
işleme
205e6c54e5

+ 0 - 3
lint-staged.config.js

@@ -1,3 +0,0 @@
-module.exports = {
-  "*.{js,jsx,vue}": "vue-cli-service lint",
-};

+ 22 - 0
src/assets/styles/pages.scss

@@ -1327,6 +1327,27 @@
     line-height: 18px;
     margin-bottom: 16px;
   }
+  &-content {
+    margin: -5px;
+    padding: 5px;
+    border-radius: 5px;
+
+    &:not(.is-active) {
+      cursor: pointer;
+      &:hover {
+        background-color: mix(#fff, #705eff, 95%);
+      }
+    }
+
+    .question-info-view {
+      padding-top: 10px;
+      border-top: 1px solid #f0f2f6;
+    }
+  }
+
+  &-subq {
+    padding: 0 15px;
+  }
 
   &-title {
     font-weight: bold;
@@ -1353,6 +1374,7 @@
       float: left;
       width: 45px;
       padding-right: 5px;
+      text-align: right;
     }
     .rich-text {
       margin-left: 45px;

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

@@ -6,7 +6,6 @@
     :close-on-press-escape="false"
     append-to-body
     fullscreen
-    destroy-on-close
     :show-close="false"
     @open="visibleChange"
   >

+ 18 - 5
src/modules/question/components/QuestionImportEdit.vue

@@ -356,7 +356,12 @@ export default {
         });
       });
       if (errInfos.length) {
-        this.$notify.error(errInfos.join("。"));
+        this.$message({
+          showClose: true,
+          message: errInfos.join("。"),
+          type: "error",
+          duration: 0,
+        });
         return;
       }
 
@@ -386,9 +391,12 @@ export default {
         });
       });
       if (errQuestions.length) {
-        this.$notify.error(
-          `请设置如下试题的分值:${errQuestions.join("、")}。`
-        );
+        this.$message({
+          showClose: true,
+          message: `请设置如下试题的分值:${errQuestions.join("、")}。`,
+          type: "error",
+          duration: 0,
+        });
         return;
       }
 
@@ -396,7 +404,12 @@ export default {
         this.data.importData.checkTotalScore &&
         totalScore !== this.data.importData.totalScore
       ) {
-        this.$notify.error("试卷总分与导入设置的总分不一致!");
+        this.$message({
+          showClose: true,
+          message: `试卷总分与导入设置的总分不一致!`,
+          type: "error",
+          duration: 0,
+        });
         return;
       }
 

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

@@ -28,7 +28,7 @@
 </template>
 
 <script>
-import { deepCopy } from "@/plugins/utils";
+import { deepCopy, randomCode } from "@/plugins/utils";
 import { structTypeToQuestionType } from "./import-edit/model";
 import BooleanQuestion from "./import-edit/BooleanQuestion.vue";
 import FillBlankQuestion from "./import-edit/FillBlankQuestion.vue";
@@ -78,6 +78,17 @@ export default {
         detail.questions.forEach((question) => {
           question.questionType = structTypeToQuestionType(question.type);
           question.courseId = this.courseId;
+          question.score = question.score || detail.questionScore || 0;
+          question.id = randomCode();
+
+          if (question.subQuestions && question.subQuestions.length) {
+            question.subQuestions.forEach((subq) => {
+              subq.id = randomCode();
+              subq.questionType = structTypeToQuestionType(subq.type);
+              subq.courseId = this.courseId;
+              subq.score = subq.score || detail.questionScore || 0;
+            });
+          }
         });
       });
       this.paperData = paperData;
@@ -92,6 +103,10 @@ export default {
       });
       return this.paperData;
     },
+    // question
+    questionActive(question) {
+      this.activeQuestionId = question.id;
+    },
   },
 };
 </script>

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

@@ -18,7 +18,7 @@
       <el-form-item label="难度" class="question-info-inline">
         <el-select
           v-model="modalForm.difficulty"
-          placeholder="请选择难度"
+          placeholder="请选择"
           @change="emitChange"
         >
           <el-option
@@ -53,7 +53,7 @@
       >
         <el-select
           v-model="modalForm.publicity"
-          placeholder="请选择公开度"
+          placeholder="请选择"
           @change="emitChange"
         >
           <el-option

+ 11 - 17
src/modules/question/components/import-edit/BankedClozeQuestion.vue

@@ -30,23 +30,17 @@
       </el-form-item>
     </el-form>
 
-    <el-collapse v-model="activeNames">
-      <el-collapse-item
-        v-for="(subq, index) in question.subQuestions"
-        :key="subq.questionKey"
-        :name="subq.questionKey"
-      >
-        <div slot="title" class="subq-header">
-          <h3>第{{ index + 1 }}小题</h3>
-        </div>
-
-        <match-question
-          ref="MatchQuestion"
-          :question="subq"
-          :parent-question="question"
-        ></match-question>
-      </el-collapse-item>
-    </el-collapse>
+    <div
+      v-for="subq in question.subQuestions"
+      :key="subq.id"
+      class="op-question-subq"
+    >
+      <match-question
+        ref="MatchQuestion"
+        :question="subq"
+        :parent-question="question"
+      ></match-question>
+    </div>
   </div>
 </template>
 

+ 27 - 5
src/modules/question/components/import-edit/BooleanQuestion.vue

@@ -1,10 +1,20 @@
 <template>
   <div class="boolean-question">
-    <div class="ep-question-title">
-      <span class="ep-question-title-number">{{ question.number }}.</span>
-      <rich-text :text-json="question.body"></rich-text>
+    <div
+      :class="['ep-question-content', { 'is-active': isActive }]"
+      @click="activeQuestion"
+    >
+      <div class="ep-question-title">
+        <span class="ep-question-title-number">{{ question.number }}.</span>
+        <rich-text :text-json="question.body"></rich-text>
+      </div>
+      <question-info-view
+        v-if="!isActive"
+        :question="getData()"
+        label-width="72px"
+      ></question-info-view>
     </div>
-    <div class="ep-question-props">
+    <div v-if="isActive" class="ep-question-props">
       <el-form ref="modalFormComp" :model="modalForm" label-width="72px">
         <el-form-item prop="quesAnswer" label="答案">
           <el-radio-group v-model="modalForm.quesAnswer" @change="answerChange">
@@ -38,10 +48,12 @@
 <script>
 import { getInitQuestionModel } from "./model";
 import QuestionInfoEdit from "../QuestionInfoEdit.vue";
+import QuestionInfoView from "./QuestionInfoView.vue";
+import { mapState, mapMutations } from "vuex";
 
 export default {
   name: "BooleanQuestion",
-  components: { QuestionInfoEdit },
+  components: { QuestionInfoEdit, QuestionInfoView },
   props: {
     question: {
       type: Object,
@@ -65,10 +77,17 @@ export default {
       ],
     };
   },
+  computed: {
+    ...mapState("import-edit", ["curQuestion"]),
+    isActive() {
+      return this.curQuestion.id === this.question.id;
+    },
+  },
   created() {
     this.initData();
   },
   methods: {
+    ...mapMutations("import-edit", ["setCurQuestion"]),
     initData() {
       this.modalForm = this.$objAssign(getInitQuestionModel(), this.question);
       this.modalForm.quesAnswer =
@@ -87,6 +106,9 @@ export default {
       let data = Object.assign({}, this.question, this.modalForm);
       return data;
     },
+    activeQuestion() {
+      this.setCurQuestion(this.question);
+    },
   },
 };
 </script>

+ 27 - 5
src/modules/question/components/import-edit/FillBlankQuestion.vue

@@ -1,10 +1,20 @@
 <template>
   <div class="fill-blank-question">
-    <div class="ep-question-title">
-      <span class="ep-question-title-number">{{ question.number }}.</span>
-      <rich-text :text-json="question.body"></rich-text>
+    <div
+      :class="['ep-question-content', { 'is-active': isActive }]"
+      @click="activeQuestion"
+    >
+      <div class="ep-question-title">
+        <span class="ep-question-title-number">{{ question.number }}.</span>
+        <rich-text :text-json="question.body"></rich-text>
+      </div>
+      <question-info-view
+        v-if="!isActive"
+        :question="getData()"
+        label-width="72px"
+      ></question-info-view>
     </div>
-    <div class="ep-question-props">
+    <div v-if="isActive" class="ep-question-props">
       <el-form ref="modalFormComp" :model="modalForm" label-width="72px">
         <el-form-item label="答案"></el-form-item>
         <el-form-item
@@ -40,10 +50,12 @@
 <script>
 import { getInitQuestionModel } from "./model";
 import QuestionInfoEdit from "../QuestionInfoEdit.vue";
+import QuestionInfoView from "./QuestionInfoView.vue";
+import { mapState, mapMutations } from "vuex";
 
 export default {
   name: "FillBlankQuestion",
-  components: { QuestionInfoEdit },
+  components: { QuestionInfoEdit, QuestionInfoView },
   props: {
     question: {
       type: Object,
@@ -57,10 +69,17 @@ export default {
       modalForm: {},
     };
   },
+  computed: {
+    ...mapState("import-edit", ["curQuestion"]),
+    isActive() {
+      return this.curQuestion.id === this.question.id;
+    },
+  },
   created() {
     this.initData();
   },
   methods: {
+    ...mapMutations("import-edit", ["setCurQuestion"]),
     initData() {
       this.modalForm = this.$objAssign(getInitQuestionModel(), this.question);
       this.modalForm.quesAnswer = [];
@@ -89,6 +108,9 @@ export default {
       data.quesAnswer = JSON.stringify(data.quesAnswer);
       return data;
     },
+    activeQuestion() {
+      this.setCurQuestion(this.question);
+    },
   },
 };
 </script>

+ 25 - 5
src/modules/question/components/import-edit/MatchQuestion.vue

@@ -1,10 +1,20 @@
 <template>
   <div class="match-question">
-    <div v-if="showQuesBody" class="ep-question-title">
-      <span class="ep-question-title-number">{{ question.number }}.</span>
-      <rich-text :text-json="question.body"></rich-text>
+    <div
+      :class="['ep-question-content', { 'is-active': isActive }]"
+      @click="activeQuestion"
+    >
+      <div class="ep-question-title">
+        <span class="ep-question-title-number">{{ question.number }}.</span>
+        <rich-text :text-json="question.body"></rich-text>
+      </div>
+      <question-info-view
+        v-if="!isActive"
+        :question="getData()"
+        label-width="72px"
+      ></question-info-view>
     </div>
-    <div class="ep-question-props">
+    <div v-if="isActive" class="ep-question-props">
       <el-form
         ref="modalFormComp"
         :model="modalForm"
@@ -42,11 +52,13 @@
 
 <script>
 import QuestionInfoEdit from "../QuestionInfoEdit.vue";
+import QuestionInfoView from "./QuestionInfoView.vue";
 import { getInitQuestionModel } from "./model";
+import { mapState, mapMutations } from "vuex";
 
 export default {
   name: "MatchQuestion",
-  components: { QuestionInfoEdit },
+  components: { QuestionInfoEdit, QuestionInfoView },
   props: {
     question: {
       type: Object,
@@ -84,6 +96,10 @@ export default {
     };
   },
   computed: {
+    ...mapState("import-edit", ["curQuestion"]),
+    isActive() {
+      return this.curQuestion.id === this.question.id;
+    },
     IS_PARAGRAPH_MATCHING() {
       return this.parentQuestion.questionType === "PARAGRAPH_MATCHING";
     },
@@ -92,6 +108,7 @@ export default {
     this.initData();
   },
   methods: {
+    ...mapMutations("import-edit", ["setCurQuestion"]),
     initData() {
       this.modalForm = this.$objAssign(getInitQuestionModel(), this.question);
       this.modalForm.courseId = this.parentQuestion.courseId;
@@ -114,6 +131,9 @@ export default {
       data.quesAnswer = JSON.stringify(data.quesAnswer);
       return data;
     },
+    activeQuestion() {
+      this.setCurQuestion(this.question);
+    },
   },
 };
 </script>

+ 11 - 18
src/modules/question/components/import-edit/NestedQuestion.vue

@@ -3,24 +3,17 @@
     <div class="ep-question-title">
       <rich-text :text-json="question.body"></rich-text>
     </div>
-    <el-collapse v-model="activeNames" style="margin-top: 10px">
-      <el-collapse-item
-        v-for="(subq, index) in question.subQuestions"
-        :key="subq.questionKey"
-        :name="index"
-      >
-        <h3 slot="title">
-          第{{ index + 1 }}小题({{ subq.questionType | questionType }})
-        </h3>
-
-        <component
-          :is="getStructTypeComp(subq.questionType)"
-          ref="QuestionEditDetail"
-          :question="subq"
-          :show-ques-body="!IS_CLOZE"
-        ></component>
-      </el-collapse-item>
-    </el-collapse>
+    <div
+      v-for="subq in question.subQuestions"
+      :key="subq.id"
+      class="op-question-subq"
+    >
+      <component
+        :is="getStructTypeComp(subq.questionType)"
+        ref="QuestionEditDetail"
+        :question="subq"
+      ></component>
+    </div>
   </div>
 </template>
 

+ 76 - 0
src/modules/question/components/import-edit/QuestionInfoView.vue

@@ -0,0 +1,76 @@
+<template>
+  <div class="question-info-view">
+    <el-form :label-width="labelWidth">
+      <el-form-item v-if="IS_PAPER_MODE" label="分值">
+        {{ score }}
+      </el-form-item>
+      <el-form-item label="答案">
+        <question-answer :data="question"></question-answer>
+      </el-form-item>
+      <el-form-item
+        v-if="!isAnEmptyRichText(question.answerAnalysis)"
+        label="答案解析"
+      >
+        <rich-text :text-json="question.answerAnalysis"></rich-text>
+      </el-form-item>
+      <el-form-item label="难度">
+        {{ question.difficulty || "--" }}
+      </el-form-item>
+      <el-form-item v-if="question.quesProperties" label="属性列表">
+        <el-tag
+          v-for="(content, propIndex) in question.quesProperties"
+          :key="propIndex"
+          type="info"
+          effect="dark"
+          style="margin-right: 5px; margin-bottom: 5px"
+        >
+          {{ content.courseProperty && content.courseProperty.name }}
+          <span style="margin: 0 3px">/</span>
+          {{ content.firstProperty && content.firstProperty.name }}
+          <span v-if="content.secondProperty" style="margin: 0 3px">/</span>
+          {{ content.secondProperty && content.secondProperty.name }}
+        </el-tag>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { isAnEmptyRichText } from "@/utils/utils";
+import QuestionAnswer from "../QuestionAnswer.vue";
+
+export default {
+  name: "QuestionInfoView",
+  components: {
+    QuestionAnswer,
+  },
+  props: {
+    question: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+    labelWidth: {
+      type: String,
+      default: "100px",
+    },
+  },
+  data() {
+    return {};
+  },
+  computed: {
+    IS_PAPER_MODE() {
+      return this.question.editMode === "paper";
+    },
+    score() {
+      return !this.question.score && this.question.score !== 0
+        ? "-"
+        : this.question.score;
+    },
+  },
+  methods: {
+    isAnEmptyRichText,
+  },
+};
+</script>

+ 52 - 33
src/modules/question/components/import-edit/SelectQuestion.vue

@@ -1,37 +1,50 @@
 <template>
   <div class="select-question">
-    <div v-if="showQuesBody" class="ep-question-title">
-      <span class="ep-question-title-number">{{ question.number }}.</span>
-      <rich-text :text-json="question.body"></rich-text>
-    </div>
-    <div class="ep-question-body">
-      <div
-        v-for="(option, optionIndex) in options"
-        :key="optionIndex"
-        class="ep-question-option"
-      >
-        <div class="ep-question-option-check">
-          <el-radio
-            v-if="IS_SIMPLE"
-            v-model="quesAnswer"
-            :label="option.number"
-            @change="answerChange"
-          >
-            {{ (option.number - 1) | optionOrderWordFilter }}.
-          </el-radio>
-          <el-checkbox
-            v-else
-            v-model="option.isCorrect"
-            :label="option.number"
-            @change="answerChange"
-          >
+    <div
+      :class="['ep-question-content', { 'is-active': isActive }]"
+      @click="activeQuestion"
+    >
+      <div class="ep-question-title">
+        <span class="ep-question-title-number">{{ question.number }}.</span>
+        <rich-text :text-json="question.body"></rich-text>
+      </div>
+      <div class="ep-question-body">
+        <div
+          v-for="(option, optionIndex) in options"
+          :key="optionIndex"
+          class="ep-question-option"
+        >
+          <div v-if="isActive" class="ep-question-option-check">
+            <el-radio
+              v-if="IS_SIMPLE"
+              v-model="quesAnswer"
+              :label="option.number"
+              @change="answerChange"
+            >
+              {{ (option.number - 1) | optionOrderWordFilter }}.
+            </el-radio>
+            <el-checkbox
+              v-else
+              v-model="option.isCorrect"
+              :label="option.number"
+              @change="answerChange"
+            >
+              {{ (option.number - 1) | optionOrderWordFilter }}.
+            </el-checkbox>
+          </div>
+          <div v-else class="ep-question-option-check">
             {{ (option.number - 1) | optionOrderWordFilter }}.
-          </el-checkbox>
+          </div>
+          <rich-text :text-json="option.body"></rich-text>
         </div>
-        <rich-text :text-json="option.body"></rich-text>
       </div>
+      <question-info-view
+        v-if="!isActive"
+        :question="getData()"
+        label-width="72px"
+      ></question-info-view>
     </div>
-    <div class="ep-question-props">
+    <div v-if="isActive" class="ep-question-props">
       <el-form
         ref="modalFormComp"
         :model="modalForm"
@@ -61,11 +74,13 @@
 
 <script>
 import QuestionInfoEdit from "../QuestionInfoEdit.vue";
+import QuestionInfoView from "./QuestionInfoView.vue";
 import { getInitQuestionModel } from "./model";
+import { mapState, mapMutations } from "vuex";
 
 export default {
   name: "SelectQuestion",
-  components: { QuestionInfoEdit },
+  components: { QuestionInfoEdit, QuestionInfoView },
   props: {
     question: {
       type: Object,
@@ -73,10 +88,6 @@ export default {
         return {};
       },
     },
-    showQuesBody: {
-      type: Boolean,
-      default: true,
-    },
   },
   data() {
     return {
@@ -99,6 +110,10 @@ export default {
     };
   },
   computed: {
+    ...mapState("import-edit", ["curQuestion"]),
+    isActive() {
+      return this.curQuestion.id === this.question.id;
+    },
     IS_SIMPLE() {
       return this.question.questionType === "SINGLE_ANSWER_QUESTION";
     },
@@ -114,6 +129,7 @@ export default {
     this.initData();
   },
   methods: {
+    ...mapMutations("import-edit", ["setCurQuestion"]),
     initData() {
       this.modalForm = this.$objAssign(getInitQuestionModel(), this.question);
       this.quesAnswer = this.IS_SIMPLE ? null : [];
@@ -146,6 +162,9 @@ export default {
       data.quesAnswer = JSON.stringify(this.modalForm.quesAnswer);
       return data;
     },
+    activeQuestion() {
+      this.setCurQuestion(this.question);
+    },
   },
 };
 </script>

+ 27 - 5
src/modules/question/components/import-edit/TextAnswerQuestion.vue

@@ -1,10 +1,20 @@
 <template>
   <div class="text-answer-question">
-    <div class="ep-question-title">
-      <span class="ep-question-title-number">{{ question.number }}.</span>
-      <rich-text :text-json="question.body"></rich-text>
+    <div
+      :class="['ep-question-content', { 'is-active': isActive }]"
+      @click="activeQuestion"
+    >
+      <div class="ep-question-title">
+        <span class="ep-question-title-number">{{ question.number }}.</span>
+        <rich-text :text-json="question.body"></rich-text>
+      </div>
+      <question-info-view
+        v-if="!isActive"
+        :question="getData()"
+        label-width="72px"
+      ></question-info-view>
     </div>
-    <div class="ep-question-props">
+    <div v-if="isActive" class="ep-question-props">
       <el-form ref="modalFormComp" :model="modalForm" label-width="72px">
         <el-form-item label="答案">
           <v-editor
@@ -34,10 +44,12 @@
 <script>
 import { getInitQuestionModel } from "./model";
 import QuestionInfoEdit from "../QuestionInfoEdit.vue";
+import QuestionInfoView from "./QuestionInfoView.vue";
+import { mapState, mapMutations } from "vuex";
 
 export default {
   name: "TextAnswerQuestion",
-  components: { QuestionInfoEdit },
+  components: { QuestionInfoEdit, QuestionInfoView },
   props: {
     question: {
       type: Object,
@@ -52,10 +64,17 @@ export default {
       quesAnswer: null,
     };
   },
+  computed: {
+    ...mapState("import-edit", ["curQuestion"]),
+    isActive() {
+      return this.curQuestion.id === this.question.id;
+    },
+  },
   created() {
     this.initData();
   },
   methods: {
+    ...mapMutations("import-edit", ["setCurQuestion"]),
     initData() {
       this.modalForm = this.$objAssign(getInitQuestionModel(), this.question);
       this.modalForm.quesAnswer = this.modalForm.quesAnswer || [];
@@ -79,6 +98,9 @@ export default {
       data.quesAnswer = JSON.stringify(data.quesAnswer);
       return data;
     },
+    activeQuestion() {
+      this.setCurQuestion(this.question);
+    },
   },
 };
 </script>

+ 1 - 1
src/modules/question/components/import-edit/model.js

@@ -4,7 +4,7 @@ export const getInitQuestionModel = () => {
     editMode: "paper",
     sourceDetailId: "",
     courseId: "",
-    difficulty: "",
+    difficulty: "",
     quesProperties: [],
     score: 0,
     publicity: true,

+ 14 - 0
src/modules/question/components/import-edit/store.js

@@ -0,0 +1,14 @@
+const state = {
+  curQuestion: {},
+};
+
+const mutations = {
+  setCurQuestion(state, curQuestion) {
+    state.curQuestion = curQuestion;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+};

+ 2 - 0
src/store/index.js

@@ -5,6 +5,7 @@ import currentPaths from "../modules/portal/store/currentPaths";
 import menuList from "../modules/portal/store/menuList";
 import { card } from "../modules/card/store";
 import paperExport from "../modules/paper-export/store";
+import importEdit from "../modules/question/components/import-edit/store";
 
 Vue.use(Vuex);
 
@@ -18,5 +19,6 @@ export default new Vuex.Store({
     menuList,
     card,
     "paper-export": paperExport,
+    "import-edit": importEdit,
   },
 });