dusenyao 1 год назад
Родитель
Сommit
f9f99b002f

+ 68 - 13
src/views/exercise_questions/create/components/exercises/SelectQuestion.vue

@@ -18,7 +18,14 @@
             <span class="question-number" title="双击切换序号类型" @dblclick="changeOptionType(data)">
               {{ computedQuestionNumber(i, data.option_number_show_mode) }}
             </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>
               <RichText v-model="item.content" placeholder="输入内容" :inline="true" />
             </div>
@@ -70,14 +77,13 @@
             {{ label }}
           </el-radio>
         </el-form-item>
-        <!-- TODO 选项细分 -->
-        <!-- <el-form-item label="选项细分">
+        <el-form-item label="选项细分">
           <el-radio
             v-for="{ value, label } in switchOption"
             :key="value"
             v-model="data.property.is_option_subdivision"
             :label="value"
-            @input="changeSelectType"
+            @input="changeOptionSubdivision"
           >
             {{ label }}
           </el-radio>
@@ -89,8 +95,9 @@
             :max="5"
             :step="1"
             :disabled="!isEnable(data.property.is_option_subdivision)"
+            @change="changeOptionNumber"
           />
-        </el-form-item> -->
+        </el-form-item>
         <el-form-item label="分值">
           <el-radio
             v-for="{ value, label } in scoreTypeList"
@@ -117,7 +124,7 @@
 <script>
 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 { getSelectData, getOption } from '@/views/exercise_questions/data/select';
 
 export default {
@@ -148,38 +155,86 @@ export default {
     },
     changeSelectType(val) {
       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) {
         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);
     },
-    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) {
-        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 (index === -1) {
-          this.data.answer.answer_list.push(mark);
+          answer_list.push(mark);
         } else {
-          this.data.answer.answer_list.splice(index, 1);
+          answer_list.splice(index, 1);
         }
       }
     },
     addOption() {
       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>
 
 <style lang="scss" scoped>
 .content {
+  .option-list {
+    display: flex;
+    flex: 1;
+    column-gap: 4px;
+  }
+
   .option-content {
     .checkbox {
       display: inline-flex;

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

@@ -34,6 +34,8 @@ export function getSelectData() {
       question_number: '1', // 题号
       is_enable_description: switchOption[0].value, // 描述
       select_type: selectTypeList[0].value, // 选择类型
+      is_option_subdivision: switchOption[1].value, // 选项细分
+      option_number: 2, // 选项数
       score: 1, // 分值
       score_type: scoreTypeList[0].value, // 分值类型
     },

+ 83 - 12
src/views/exercise_questions/preview/SelectPreview.vue

@@ -11,7 +11,23 @@
       v-html="sanitizeHTML(data.description)"
     ></div>
 
-    <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
         v-for="({ content, mark }, i) in data.option_list"
         :key="mark"
@@ -28,7 +44,7 @@
 </template>
 
 <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';
 
@@ -40,35 +56,61 @@ export default {
       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: {
-    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);
     },
-    selectAnswer(mark) {
+    selectAnswer(mark, i) {
       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;
+      let index = answer_list.indexOf(mark);
       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 (index === -1) {
-          this.answer.answer_list.push(mark);
+          answer_list.push(mark);
         } else {
-          this.answer.answer_list.splice(index, 1);
+          answer_list.splice(index, 1);
         }
       }
     },
-    computedAnswerClass(mark) {
+    computedAnswerClass(mark, i) {
       if (!this.isJudgingRightWrong && !this.isShowRightAnswer) {
         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) {
-        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) {
-        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 [];
     },
@@ -82,6 +124,7 @@ export default {
 .select-preview {
   @include preview;
 
+  %option-list,
   .option-list {
     display: flex;
     flex-direction: column;
@@ -99,7 +142,9 @@ export default {
 
       .selectionbox {
         width: 14px;
+        min-width: 14px;
         height: 14px;
+        min-height: 14px;
         margin-right: 8px;
         border: 2px solid #dcdbdd;
         border-radius: 50%;
@@ -156,5 +201,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>