Procházet zdrojové kódy

修改阅读题数据格式

dusenyao před 1 rokem
rodič
revize
b70c64770b

+ 3 - 0
src/main.js

@@ -24,5 +24,8 @@ Vue.config.productionTip = false;
 new Vue({
   router,
   store,
+  beforeCreate() {
+    Vue.prototype.$bus = this; // 安装全局事件总线
+  },
   render: (h) => h(App),
 }).$mount('#app');

+ 46 - 0
src/views/exercise_questions/create/components/common/QuestionMixin.js

@@ -3,6 +3,7 @@ import QuestionBase from './QuestionBase.vue';
 import RichText from '@/components/common/RichText.vue';
 import AudioPlay from '@/views/exercise_questions/create/components/common/AudioPlay.vue';
 
+import { GetQuestionInfo, SaveQuestion } from '@/api/exercise';
 import {
   stemTypeList,
   scoreTypeList,
@@ -23,11 +24,48 @@ const mixin = {
       computedQuestionNumber,
     };
   },
+  provide: ['refreshPreviewData'],
+  props: {
+    questionId: {
+      type: String,
+      default: '',
+    },
+    isChild: {
+      type: Boolean,
+      default: false,
+    },
+    isChange: {
+      type: Boolean,
+      default: false,
+    },
+  },
   components: {
     QuestionBase,
     RichText,
     AudioPlay,
   },
+  created() {
+    // 题目的子题目保存
+    if (this.isChild) {
+      this.$bus.$on('saveQuestion', () => {
+        SaveQuestion({
+          question_id: this.questionId,
+          type: this.data.type,
+          additional_type: this.data.property.select_type || '',
+          content: JSON.stringify(this.data),
+        }).catch(() => {});
+      });
+
+      if (this.isChange) return;
+      GetQuestionInfo({ question_id: this.questionId })
+        .then(({ question }) => {
+          if (!question.content) return;
+          this.data = JSON.parse(question.content);
+          this.refreshPreviewData();
+        })
+        .catch(() => {});
+    }
+  },
   watch: {
     'data.property.score'(val) {
       this.data.answer.score = val;
@@ -35,6 +73,14 @@ const mixin = {
     'data.property.score_type'(val) {
       this.data.answer.score_type = val;
     },
+    data: {
+      handler() {
+        if (!this.isChild) return;
+        this.$emit('updatePreviewData', this.data);
+      },
+      deep: true,
+      immediate: true,
+    },
   },
   methods: {
     upload(file_id) {

+ 2 - 1
src/views/exercise_questions/create/components/create.vue

@@ -29,7 +29,7 @@
       <SelectQuestionType v-if="indexList.length > 0" :type="exerciseTypeList[indexList[curIndex].type]" />
       <template v-for="({ id }, i) in indexList">
         <KeepAlive :key="id">
-          <component :is="curExercisePage" v-if="i === curIndex" ref="exercise" />
+          <component :is="curExercisePage" v-if="i === curIndex" ref="exercise" :question-id="id" />
         </KeepAlive>
       </template>
     </div>
@@ -189,6 +189,7 @@ export default {
     async saveQuestion() {
       if (this.indexList.length <= 0) return;
       try {
+        this.$bus.$emit('saveQuestion');
         await SaveQuestion(this.dataConversion());
         const curDate = timeFormatConversion(new Date());
         if (this.curSaveDate !== curDate) {

+ 1 - 7
src/views/exercise_questions/create/components/exercises/FillQuestion.vue

@@ -138,12 +138,6 @@ export default {
     UploadAudio,
   },
   mixins: [QuestionMixin],
-  props: {
-    externalData: {
-      type: Object,
-      default: () => JSON.parse(JSON.stringify(fillData)),
-    },
-  },
   data() {
     return {
       isShow: false,
@@ -151,7 +145,7 @@ export default {
         top: 0,
         left: 0,
       },
-      data: this.externalData,
+      data: JSON.parse(JSON.stringify(fillData)),
     };
   },
   created() {

+ 1 - 7
src/views/exercise_questions/create/components/exercises/JudgeQuestion.vue

@@ -142,17 +142,11 @@ export default {
     UploadAudio,
   },
   mixins: [QuestionMixin],
-  props: {
-    externalData: {
-      type: Object,
-      default: () => getJudgeData(),
-    },
-  },
   data() {
     return {
       option_type_list,
       changeOptionType,
-      data: this.externalData,
+      data: getJudgeData(),
     };
   },
   computed: {

+ 1 - 7
src/views/exercise_questions/create/components/exercises/MatchingQuestion.vue

@@ -122,16 +122,10 @@ import { columnNumberList, getOption, getMatchingDataTemplate } from '@/views/ex
 export default {
   name: 'MatchingQuestion',
   mixins: [QuestionMixin],
-  props: {
-    externalData: {
-      type: Object,
-      default: () => getMatchingDataTemplate(),
-    },
-  },
   data() {
     return {
       columnNumberList,
-      data: this.externalData,
+      data: getMatchingDataTemplate(),
     };
   },
   watch: {

+ 45 - 16
src/views/exercise_questions/create/components/exercises/ReadQuestion.vue

@@ -47,7 +47,16 @@
           @deleteQuestion="deleteQuestion(i)"
           @recognition="recognition(i, $event)"
         />
-        <component :is="exerciseComponents[item.type]" ref="exercise" :external-data="item" />
+        <KeepAlive>
+          <component
+            :is="exerciseComponents[item.type]"
+            ref="exercise"
+            :is-change="change"
+            :is-child="true"
+            :question-id="item.id"
+            @updatePreviewData="updatePreviewData(i, $event)"
+          />
+        </KeepAlive>
       </div>
     </template>
 
@@ -106,11 +115,7 @@
 
 <script>
 import { readData, questionTypeOption, exerciseTypeList } from '@/views/exercise_questions/data/read';
-import { getSelectData } from '@/views/exercise_questions/data/select';
-import { getJudgeData } from '@/views/exercise_questions/data/judge';
-import { getMatchingDataTemplate } from '@/views/exercise_questions/data/matching';
-import { fillData } from '@/views/exercise_questions/data/fill';
-import { curry } from '@/utils';
+import { AddQuestionToExercise, DeleteQuestion } from '@/api/exercise';
 
 import QuestionMixin from '../common/QuestionMixin.js';
 import SelectQuestionType from '@/views/exercise_questions/create/components/common/SelectQuestionType.vue';
@@ -129,11 +134,13 @@ export default {
     FillQuestion,
   },
   mixins: [QuestionMixin],
+  inject: ['exercise_id'],
   data() {
     return {
-      curry,
+      change: false, // 是否改变题目类型
       questionTypeOption,
       exerciseTypeList,
+      childPreviewData: [],
       data: JSON.parse(JSON.stringify(readData)),
       exerciseComponents: {
         select: SelectQuestion,
@@ -141,21 +148,32 @@ export default {
         matching: MatchingQuestion,
         fill: FillQuestion,
       },
-      exerciseData: {
-        select: getSelectData(),
-        judge: getJudgeData(),
-        matching: getMatchingDataTemplate(),
-        fill: fillData,
-      },
     };
   },
   methods: {
     addQuestion() {
-      this.data.question_list.push(JSON.parse(JSON.stringify(this.exerciseData['select'])));
+      AddQuestionToExercise({
+        exercise_id: this.exercise_id,
+        is_child_question: 'true',
+        parent_question_id: this.questionId,
+        type: 'select',
+        additional_type: 'single',
+        content: '',
+      }).then(({ status, question_id }) => {
+        if (status !== 1) return;
+        this.data.question_list.push({ id: question_id, type: 'select', additional_type: 'single' });
+      });
     },
 
+    /**
+     * 删除题目
+     * @param {Number} i 题目索引
+     */
     deleteQuestion(i) {
-      this.data.question_list.splice(i, 1);
+      DeleteQuestion({ question_id: this.data.question_list[i].id }).then(({ status }) => {
+        if (status !== 1) return;
+        this.data.question_list.splice(i, 1);
+      });
     },
 
     /**
@@ -167,9 +185,20 @@ export default {
       this.$refs.exercise[i]?.recognition(text);
     },
 
+    /**
+     * 更新当前题目类型
+     * @param {Number} i 题目索引
+     * @param {Array} arr 选中的题目类型
+     */
     updateCurQuestionType(i, arr) {
       let type = arr[arr.length - 1];
-      this.$set(this.data.question_list, i, JSON.parse(JSON.stringify(this.exerciseData[type])));
+      this.data.question_list[i].type = type;
+      this.change = true;
+      this.data.question_list[i].additional_type = type === 'select' ? 'single' : '';
+    },
+
+    updatePreviewData(i, data) {
+      this.$set(this.childPreviewData, i, data);
     },
   },
 };

+ 1 - 7
src/views/exercise_questions/create/components/exercises/SelectQuestion.vue

@@ -141,17 +141,11 @@ export default {
     UploadAudio,
   },
   mixins: [QuestionMixin],
-  props: {
-    externalData: {
-      type: Object,
-      default: () => getSelectData(),
-    },
-  },
   data() {
     return {
       selectTypeList,
       changeOptionType,
-      data: this.externalData,
+      data: getSelectData(),
     };
   },
   methods: {

+ 10 - 7
src/views/exercise_questions/create/index.vue

@@ -48,7 +48,7 @@
         </div>
       </div>
       <div class="preview-content">
-        <component :is="curPreviewPage" v-if="preview" :data="previewData" />
+        <component :is="curPreviewPage" v-if="preview" :data="previewData" :child-preview-data="childPreviewData" />
       </div>
     </div>
   </div>
@@ -95,6 +95,8 @@ export default {
     return {
       isSetUp: () => this.isSetUp,
       updateCurQuestionType: this.updateCurQuestionType,
+      exercise_id: this.id,
+      refreshPreviewData: this.refreshPreviewData,
     };
   },
   data() {
@@ -196,12 +198,12 @@ export default {
       if (this.index_list.length === 0) return;
       GetQuestionInfo({ question_id: this.index_list[this.curIndex].id })
         .then(({ question }) => {
-          if (question.content) {
-            this.$nextTick(() => {
-              this.$refs.createMain.$refs.exercise?.[0].setQuestion(question);
-              this.refreshPreviewData();
-            });
-          }
+          if (!question.content) return;
+
+          this.$nextTick(() => {
+            this.$refs.createMain.$refs.exercise?.[0].setQuestion(question);
+            this.refreshPreviewData();
+          });
         })
         .catch(() => {});
     },
@@ -242,6 +244,7 @@ export default {
     // 刷新预览数据
     refreshPreviewData() {
       this.previewData = this.$refs.createMain.$refs.exercise?.[0].data || {};
+      this.childPreviewData = this.$refs.createMain.$refs.exercise?.[0].childPreviewData || [];
     },
     // 预览
     setPreview() {

+ 3 - 8
src/views/exercise_questions/preview/ReadAloudPreview.vue

@@ -5,10 +5,8 @@
       <span class="question-number">{{ data.property.question_number }}.</span>
       <span v-html="sanitizeHTML(data.stem)"></span>
     </div>
-    <div v-if="isEnable(data.property.is_enable_reference_answer)" class="reference-answer">
-      {{ data.reference_answer }}
-    </div>
-    <SoundRecordPreview :wav-blob.sync="answer.voice_file_id" />
+    <el-input v-model="answer.answer_list[0].text" type="textarea" :autosize="{ minRows: 6, maxRows: 36 }" />
+    <SoundRecordPreview :wav-blob.sync="answer.answer_list[0].voice_file_id" />
   </div>
 </template>
 
@@ -22,11 +20,8 @@ export default {
     SoundRecordPreview,
   },
   mixins: [PreviewMixin],
-  data() {
-    return {};
-  },
   created() {
-    this.$set(this.answer, 'voice_file_id', '');
+    this.$set(this.answer.answer_list, 0, { text: '', voice_file_id: '' });
   },
   methods: {},
 };

+ 20 - 3
src/views/exercise_questions/preview/ReadPreview.vue

@@ -12,7 +12,7 @@
       <div class="question-list">
         <component
           :is="previewComponents[item.type]"
-          v-for="(item, i) in data.question_list"
+          v-for="(item, i) in childPreviewData"
           :key="i"
           class="preview"
           :data="item"
@@ -33,6 +33,12 @@ import FillPreview from '../preview/FillPreview.vue';
 export default {
   name: 'ReadPreview',
   mixins: [PreviewMixin],
+  props: {
+    childPreviewData: {
+      type: Array,
+      default: () => [],
+    },
+  },
   data() {
     return {
       previewComponents: {
@@ -43,9 +49,20 @@ export default {
       },
     };
   },
+  created() {
+    this.$set(
+      this.answer,
+      'question_list',
+      this.data.question_list.map((item) => {
+        return { id: item.id, type: item.type, answer_list: [] };
+      }),
+    );
+  },
   methods: {
-    changeAnswer(i, type, answer) {
-      this.answer.answer_list[i] = { type, ...answer };
+    changeAnswer(i, type, { answer_list }) {
+      console.log(answer_list);
+      this.data.question_list[i].answer_list = answer_list;
+      this.data.question_list[i].type = type;
     },
   },
 };

+ 0 - 1
src/views/exercise_questions/preview/components/common/FreewriteLettle.vue

@@ -452,7 +452,6 @@ export default {
     height: 48px;
     font-size: 16px;
     font-weight: normal;
-    line-height: 150%;
     line-height: 48px;
     color: #000;
     text-align: center;