Преглед изворни кода

听后选择的选项细分

dusenyao пре 1 година
родитељ
комит
952d5ca8af

+ 86 - 12
src/views/exercise_questions/create/components/exercises/ListenSelectQuestion.vue

@@ -25,7 +25,14 @@
             <span class="question-number" title="双击切换序号类型" @dblclick="changeOptionType(data)">
             <span class="question-number" title="双击切换序号类型" @dblclick="changeOptionType(data)">
               {{ computedQuestionNumber(i, data.option_number_show_mode) }}
               {{ computedQuestionNumber(i, data.option_number_show_mode) }}
             </span>
             </span>
-            <div class="option-content">
+            <div v-if="isEnable(data.property.is_option_subdivision)" class="option-list">
+              <div v-for="li in item" :key="li.mark" class="option-content">
+                <span :class="['checkbox', { active: isAnswer(li.mark, i) }]" @click="selectAnswer(li.mark, i)"></span>
+                <RichText v-model="li.content" placeholder="输入内容" :inline="true" />
+              </div>
+            </div>
+
+            <div v-else class="option-content">
               <span :class="['checkbox', { active: isAnswer(item.mark) }]" @click="selectAnswer(item.mark)"></span>
               <span :class="['checkbox', { active: isAnswer(item.mark) }]" @click="selectAnswer(item.mark)"></span>
               <RichText v-model="item.content" placeholder="输入内容" :inline="true" />
               <RichText v-model="item.content" placeholder="输入内容" :inline="true" />
             </div>
             </div>
@@ -56,7 +63,7 @@
             {{ label }}
             {{ label }}
           </el-radio>
           </el-radio>
         </el-form-item>
         </el-form-item>
-        <el-form-item label="描述">
+        <el-form-item label="提示">
           <el-radio
           <el-radio
             v-for="{ value, label } in switchOption"
             v-for="{ value, label } in switchOption"
             :key="value"
             :key="value"
@@ -77,6 +84,27 @@
             {{ label }}
             {{ label }}
           </el-radio>
           </el-radio>
         </el-form-item>
         </el-form-item>
+        <el-form-item label="选项细分">
+          <el-radio
+            v-for="{ value, label } in switchOption"
+            :key="value"
+            v-model="data.property.is_option_subdivision"
+            :label="value"
+            @input="changeOptionSubdivision"
+          >
+            {{ label }}
+          </el-radio>
+        </el-form-item>
+        <el-form-item label-width="72px">
+          <el-input-number
+            v-model="data.property.option_number"
+            :min="2"
+            :max="5"
+            :step="1"
+            :disabled="!isEnable(data.property.is_option_subdivision)"
+            @change="changeOptionNumber"
+          />
+        </el-form-item>
         <el-form-item label="听力">
         <el-form-item label="听力">
           <el-radio
           <el-radio
             v-for="{ value, label } in switchOption"
             v-for="{ value, label } in switchOption"
@@ -114,15 +142,13 @@
 import UploadAudio from '../common/UploadAudio.vue';
 import UploadAudio from '../common/UploadAudio.vue';
 import QuestionMixin from '../common/QuestionMixin.js';
 import QuestionMixin from '../common/QuestionMixin.js';
 
 
-import { selectTypeList, scoreTypeList, changeOptionType } from '@/views/exercise_questions/data/common';
+import { selectTypeList, scoreTypeList, changeOptionType, isEnable } from '@/views/exercise_questions/data/common';
 import { getListenSelectData, getOption } from '@/views/exercise_questions/data/listenSelect';
 import { getListenSelectData, getOption } from '@/views/exercise_questions/data/listenSelect';
-import RichText from '@/components/common/RichText.vue';
 
 
 export default {
 export default {
   name: 'ListenSelectQuestion',
   name: 'ListenSelectQuestion',
   components: {
   components: {
     UploadAudio,
     UploadAudio,
-    RichText,
   },
   },
   mixins: [QuestionMixin],
   mixins: [QuestionMixin],
   data() {
   data() {
@@ -150,38 +176,86 @@ export default {
     },
     },
     changeSelectType(val) {
     changeSelectType(val) {
       if (val === selectTypeList[0].value && this.data.answer.answer_list.length > 1) {
       if (val === selectTypeList[0].value && this.data.answer.answer_list.length > 1) {
-        this.data.answer.answer_list = [this.data.answer.answer_list[0]];
+        if (isEnable(this.data.property.is_option_subdivision)) {
+          this.data.answer.answer_list = Array.from({ length: this.data.option_list.length }, () => []);
+        } else {
+          this.data.answer.answer_list = [this.data.answer.answer_list[0]];
+        }
       }
       }
       // 当多选题切换到单选题时,分值类型切换为总分
       // 当多选题切换到单选题时,分值类型切换为总分
       if (val === selectTypeList[0].value && this.data.property.score_type === scoreTypeList[1].value) {
       if (val === selectTypeList[0].value && this.data.property.score_type === scoreTypeList[1].value) {
         this.data.property.score_type = scoreTypeList[0].value;
         this.data.property.score_type = scoreTypeList[0].value;
       }
       }
     },
     },
-    isAnswer(mark) {
+    isAnswer(mark, i) {
+      if (isEnable(this.data.property.is_option_subdivision)) {
+        return this.data.answer.answer_list?.[i].includes(mark);
+      }
       return this.data.answer.answer_list.includes(mark);
       return this.data.answer.answer_list.includes(mark);
     },
     },
-    selectAnswer(mark) {
-      let index = this.data.answer.answer_list.indexOf(mark);
+    selectAnswer(mark, i) {
+      let is_option_subdivision = isEnable(this.data.property.is_option_subdivision);
+      let answer_list = is_option_subdivision ? this.data.answer.answer_list[i] : this.data.answer.answer_list;
+      let index = answer_list.indexOf(mark);
       if (this.data.property.select_type === selectTypeList[0].value) {
       if (this.data.property.select_type === selectTypeList[0].value) {
-        this.data.answer.answer_list = [mark];
+        if (is_option_subdivision) {
+          this.$set(this.data.answer.answer_list, i, [mark]);
+        } else {
+          this.$set(this.data.answer, 'answer_list', [mark]);
+        }
       }
       }
       if (this.data.property.select_type === selectTypeList[1].value) {
       if (this.data.property.select_type === selectTypeList[1].value) {
         if (index === -1) {
         if (index === -1) {
-          this.data.answer.answer_list.push(mark);
+          answer_list.push(mark);
         } else {
         } else {
-          this.data.answer.answer_list.splice(index, 1);
+          answer_list.splice(index, 1);
         }
         }
       }
       }
     },
     },
     addOption() {
     addOption() {
       this.data.option_list.push(getOption());
       this.data.option_list.push(getOption());
     },
     },
+    /**
+     * 修改是否选项细分
+     * @param {'true'|'false'} val
+     */
+    changeOptionSubdivision(val) {
+      if (isEnable(val)) {
+        // 创建与当前 option_list 相同数量的选项,选项内的细分数量与 property.option_number 数量一样
+        this.data.answer.answer_list = Array.from({ length: this.data.option_list.length }, () => []);
+        this.data.option_list = Array.from({ length: this.data.option_list.length }, () => {
+          return Array.from({ length: this.data.property.option_number }, getOption);
+        });
+      } else {
+        this.data.answer.answer_list = [];
+        this.data.option_list = Array.from({ length: this.data.option_list.length }, getOption);
+      }
+    },
+    /**
+     * 修改选项细分数量,并尽量保留以前的数据
+     * @param {Number} val
+     */
+    changeOptionNumber(val) {
+      this.data.answer.answer_list = Array.from({ length: this.data.option_list.length }, () => []);
+      this.data.option_list = this.data.option_list.map((item) => {
+        if (item.length < val) {
+          return [...item, ...Array.from({ length: val - item.length }, getOption)];
+        }
+        return item.slice(0, val);
+      });
+    },
   },
   },
 };
 };
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 .content {
 .content {
+  .option-list {
+    display: flex;
+    flex: 1;
+    column-gap: 4px;
+  }
+
   .option-content {
   .option-content {
     .checkbox {
     .checkbox {
       display: inline-flex;
       display: inline-flex;

+ 2 - 0
src/views/exercise_questions/data/listenSelect.js

@@ -35,6 +35,8 @@ export function getListenSelectData() {
       is_enable_description: switchOption[0].value, // 描述
       is_enable_description: switchOption[0].value, // 描述
       select_type: selectTypeList[0].value, // 选择类型
       select_type: selectTypeList[0].value, // 选择类型
       is_enable_listening: switchOption[0].value, // 是否听力
       is_enable_listening: switchOption[0].value, // 是否听力
+      is_option_subdivision: switchOption[1].value, // 选项细分
+      option_number: 2, // 选项数
       score: 1, // 分值
       score: 1, // 分值
       score_type: scoreTypeList[0].value, // 分值类型
       score_type: scoreTypeList[0].value, // 分值类型
     },
     },

+ 85 - 12
src/views/exercise_questions/preview/ListenSelectPreview.vue

@@ -13,8 +13,26 @@
     <AudioPlay
     <AudioPlay
       v-if="isEnable(data.property.is_enable_listening) && data.file_id_list.length > 0"
       v-if="isEnable(data.property.is_enable_listening) && data.file_id_list.length > 0"
       :file-id="data.file_id_list[0]"
       :file-id="data.file_id_list[0]"
+      :show-slider="true"
     />
     />
-    <ul class="option-list">
+
+    <div v-if="isEnable(data.property.is_option_subdivision)" class="option-subdivision">
+      <ul v-for="(item, i) in data.option_list" :key="i" class="option-subdivision-list">
+        <span class="serial-number">{{ computeOptionMethods[data.option_number_show_mode](i) }} </span>
+        <li
+          v-for="{ content, mark } in item"
+          :key="mark"
+          :style="{ cursor: disabled ? 'not-allowed' : 'pointer' }"
+          :class="['option-item', { active: isAnswer(mark, i) }, ...computedAnswerClass(mark, i)]"
+          @click="selectAnswer(mark, i)"
+        >
+          <span class="selectionbox"></span>
+          <span class="content rich-text" v-html="sanitizeHTML(content)"></span>
+        </li>
+      </ul>
+    </div>
+
+    <ul v-else class="option-list">
       <li
       <li
         v-for="({ content, mark }, i) in data.option_list"
         v-for="({ content, mark }, i) in data.option_list"
         :key="mark"
         :key="mark"
@@ -31,7 +49,7 @@
 </template>
 </template>
 
 
 <script>
 <script>
-import { computeOptionMethods, selectTypeList } from '@/views/exercise_questions/data/common';
+import { computeOptionMethods, isEnable, selectTypeList } from '@/views/exercise_questions/data/common';
 
 
 import PreviewMixin from './components/PreviewMixin';
 import PreviewMixin from './components/PreviewMixin';
 
 
@@ -43,35 +61,61 @@ export default {
       computeOptionMethods,
       computeOptionMethods,
     };
     };
   },
   },
+  computed: {
+    isSubdivision() {
+      return isEnable(this.data.property.is_option_subdivision);
+    },
+  },
+  created() {
+    if (isEnable(this.data.property.is_option_subdivision)) {
+      this.answer.answer_list = this.data.option_list.map(() => []);
+    }
+  },
   methods: {
   methods: {
-    isAnswer(mark) {
+    isAnswer(mark, i) {
+      if (isEnable(this.data.property.is_option_subdivision)) {
+        return this.answer.answer_list?.[i]?.includes(mark);
+      }
       return this.answer.answer_list.includes(mark);
       return this.answer.answer_list.includes(mark);
     },
     },
-    selectAnswer(mark) {
+    selectAnswer(mark, i) {
       if (this.disabled) return;
       if (this.disabled) return;
-      const index = this.answer.answer_list.indexOf(mark);
+      let answer_list = this.isSubdivision ? this.answer.answer_list[i] : this.answer.answer_list;
       if (this.data.property.select_type === selectTypeList[0].value) {
       if (this.data.property.select_type === selectTypeList[0].value) {
-        this.answer.answer_list = [mark];
+        if (this.isSubdivision) {
+          this.$set(this.answer.answer_list, i, [mark]);
+        } else {
+          this.$set(this.answer, 'answer_list', [mark]);
+        }
       }
       }
       if (this.data.property.select_type === selectTypeList[1].value) {
       if (this.data.property.select_type === selectTypeList[1].value) {
+        let index = answer_list.indexOf(mark);
         if (index === -1) {
         if (index === -1) {
-          this.answer.answer_list.push(mark);
+          answer_list.push(mark);
         } else {
         } else {
-          this.answer.answer_list.splice(index, 1);
+          answer_list.splice(index, 1);
         }
         }
       }
       }
     },
     },
-    computedAnswerClass(mark) {
+    computedAnswerClass(mark, i) {
       if (!this.isJudgingRightWrong && !this.isShowRightAnswer) {
       if (!this.isJudgingRightWrong && !this.isShowRightAnswer) {
         return [];
         return [];
       }
       }
-      let isHas = this.answer.answer_list.includes(mark); // 是否已选中的选项
+      let isHas = this.isSubdivision
+        ? this.answer.answer_list[i].includes(mark)
+        : this.answer.answer_list.includes(mark); // 是否已选中的选项
       if (!isHas && this.isShowRightAnswer) {
       if (!isHas && this.isShowRightAnswer) {
-        return this.data.answer.answer_list.includes(mark) ? ['answer-right'] : [];
+        let isRight = this.isSubdivision
+          ? this.data.answer.answer_list[i].includes(mark)
+          : this.data.answer.answer_list.includes(mark); // 是否是正确答案
+        return isRight ? ['answer-right'] : [];
       }
       }
       // 判断是否是正确答案
       // 判断是否是正确答案
       if (this.isJudgingRightWrong) {
       if (this.isJudgingRightWrong) {
-        return this.data.answer.answer_list.includes(mark) ? ['right'] : ['wrong'];
+        let isRight = this.isSubdivision
+          ? this.data.answer.answer_list[i].includes(mark)
+          : this.data.answer.answer_list.includes(mark); // 是否是正确答案
+        return isRight ? ['right'] : ['wrong'];
       }
       }
       return [];
       return [];
     },
     },
@@ -85,6 +129,7 @@ export default {
 .select-preview {
 .select-preview {
   @include preview;
   @include preview;
 
 
+  %option-list,
   .option-list {
   .option-list {
     display: flex;
     display: flex;
     flex-direction: column;
     flex-direction: column;
@@ -102,7 +147,9 @@ export default {
 
 
       .selectionbox {
       .selectionbox {
         width: 14px;
         width: 14px;
+        min-width: 14px;
         height: 14px;
         height: 14px;
+        min-height: 14px;
         margin-right: 8px;
         margin-right: 8px;
         border: 2px solid #dcdbdd;
         border: 2px solid #dcdbdd;
         border-radius: 50%;
         border-radius: 50%;
@@ -159,5 +206,31 @@ export default {
       }
       }
     }
     }
   }
   }
+
+  .option-subdivision {
+    display: flex;
+    flex-direction: column;
+    row-gap: 24px;
+
+    &-list {
+      @extend %option-list;
+
+      .serial-number {
+        font-size: 16pt;
+      }
+
+      flex-direction: row;
+      column-gap: 24px;
+      align-items: center;
+
+      .option-item {
+        flex: 1;
+      }
+
+      :deep p {
+        margin: 0;
+      }
+    }
+  }
 }
 }
 </style>
 </style>

+ 1 - 1
src/views/exercise_questions/preview/SelectPreview.vue

@@ -76,7 +76,6 @@ export default {
     selectAnswer(mark, i) {
     selectAnswer(mark, i) {
       if (this.disabled) return;
       if (this.disabled) return;
       let answer_list = this.isSubdivision ? this.answer.answer_list[i] : this.answer.answer_list;
       let answer_list = this.isSubdivision ? this.answer.answer_list[i] : this.answer.answer_list;
-      let index = answer_list.indexOf(mark);
       if (this.data.property.select_type === selectTypeList[0].value) {
       if (this.data.property.select_type === selectTypeList[0].value) {
         if (this.isSubdivision) {
         if (this.isSubdivision) {
           this.$set(this.answer.answer_list, i, [mark]);
           this.$set(this.answer.answer_list, i, [mark]);
@@ -85,6 +84,7 @@ export default {
         }
         }
       }
       }
       if (this.data.property.select_type === selectTypeList[1].value) {
       if (this.data.property.select_type === selectTypeList[1].value) {
+        let index = answer_list.indexOf(mark);
         if (index === -1) {
         if (index === -1) {
           answer_list.push(mark);
           answer_list.push(mark);
         } else {
         } else {