Parcourir la source

听后选择选项细分修改

dusenyao il y a 1 an
Parent
commit
ffd1270d2a

+ 58 - 50
package-lock.json

@@ -48,9 +48,9 @@
       "dev": true
     },
     "@babel/core": {
-      "version": "7.23.6",
-      "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.23.6.tgz",
-      "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==",
+      "version": "7.23.7",
+      "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.23.7.tgz",
+      "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==",
       "dev": true,
       "requires": {
         "@ampproject/remapping": "^2.2.0",
@@ -58,10 +58,10 @@
         "@babel/generator": "^7.23.6",
         "@babel/helper-compilation-targets": "^7.23.6",
         "@babel/helper-module-transforms": "^7.23.3",
-        "@babel/helpers": "^7.23.6",
+        "@babel/helpers": "^7.23.7",
         "@babel/parser": "^7.23.6",
         "@babel/template": "^7.22.15",
-        "@babel/traverse": "^7.23.6",
+        "@babel/traverse": "^7.23.7",
         "@babel/types": "^7.23.6",
         "convert-source-map": "^2.0.0",
         "debug": "^4.1.0",
@@ -154,9 +154,9 @@
           "dev": true
         },
         "@babel/traverse": {
-          "version": "7.23.6",
-          "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.6.tgz",
-          "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==",
+          "version": "7.23.7",
+          "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.7.tgz",
+          "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==",
           "dev": true,
           "requires": {
             "@babel/code-frame": "^7.23.5",
@@ -195,15 +195,15 @@
           }
         },
         "caniuse-lite": {
-          "version": "1.0.30001571",
-          "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001571.tgz",
-          "integrity": "sha512-tYq/6MoXhdezDLFZuCO/TKboTzuQ/xR5cFdgXPfDtM7/kchBO3b4VWghE/OAi/DV7tTdhmLjZiZBZi1fA/GheQ==",
+          "version": "1.0.30001574",
+          "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001574.tgz",
+          "integrity": "sha512-BtYEK4r/iHt/txm81KBudCUcTy7t+s9emrIaHqjYurQ10x71zJ5VQ9x1dYPcz/b+pKSp4y/v1xSI67A+LzpNyg==",
           "dev": true
         },
         "electron-to-chromium": {
-          "version": "1.4.616",
-          "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.616.tgz",
-          "integrity": "sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==",
+          "version": "1.4.621",
+          "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.621.tgz",
+          "integrity": "sha512-MGJM6S0MuF/wTzM9NoItWXN56J1kolrHS/vzl/KlhXAbVkogTy0wzKYliQDJgNypxSCFjxdRhHYS3bffyYUGEw==",
           "dev": true
         },
         "node-releases": {
@@ -459,13 +459,13 @@
       }
     },
     "@babel/helpers": {
-      "version": "7.23.6",
-      "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.23.6.tgz",
-      "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==",
+      "version": "7.23.7",
+      "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.23.7.tgz",
+      "integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==",
       "dev": true,
       "requires": {
         "@babel/template": "^7.22.15",
-        "@babel/traverse": "^7.23.6",
+        "@babel/traverse": "^7.23.7",
         "@babel/types": "^7.23.6"
       },
       "dependencies": {
@@ -515,9 +515,9 @@
           "dev": true
         },
         "@babel/traverse": {
-          "version": "7.23.6",
-          "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.6.tgz",
-          "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==",
+          "version": "7.23.7",
+          "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.23.7.tgz",
+          "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==",
           "dev": true,
           "requires": {
             "@babel/code-frame": "^7.23.5",
@@ -2695,12 +2695,12 @@
       }
     },
     "@vue/eslint-config-prettier": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmmirror.com/@vue/eslint-config-prettier/-/eslint-config-prettier-8.0.0.tgz",
-      "integrity": "sha512-55dPqtC4PM/yBjhAr+yEw6+7KzzdkBuLmnhBrDfp4I48+wy+Giqqj9yUr5T2uD/BkBROjjmqnLZmXRdOx/VtQg==",
+      "version": "9.0.0",
+      "resolved": "https://registry.npmmirror.com/@vue/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz",
+      "integrity": "sha512-z1ZIAAUS9pKzo/ANEfd2sO+v2IUalz7cM/cTLOZ7vRFOPk5/xuRKQteOu1DErFLAh/lYGXMVZ0IfYKlyInuDVg==",
       "dev": true,
       "requires": {
-        "eslint-config-prettier": "^8.8.0",
+        "eslint-config-prettier": "^9.0.0",
         "eslint-plugin-prettier": "^5.0.0"
       }
     },
@@ -3176,13 +3176,20 @@
       }
     },
     "axios": {
-      "version": "1.6.3",
-      "resolved": "https://registry.npmmirror.com/axios/-/axios-1.6.3.tgz",
-      "integrity": "sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==",
+      "version": "1.6.4",
+      "resolved": "https://registry.npmmirror.com/axios/-/axios-1.6.4.tgz",
+      "integrity": "sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==",
       "requires": {
-        "follow-redirects": "^1.15.0",
+        "follow-redirects": "^1.15.4",
         "form-data": "^4.0.0",
         "proxy-from-env": "^1.1.0"
+      },
+      "dependencies": {
+        "follow-redirects": {
+          "version": "1.15.4",
+          "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.4.tgz",
+          "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw=="
+        }
       }
     },
     "babel-helper-vue-jsx-merge-props": {
@@ -4045,9 +4052,9 @@
       }
     },
     "core-js": {
-      "version": "3.34.0",
-      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.34.0.tgz",
-      "integrity": "sha512-aDdvlDder8QmY91H88GzNi9EtQi2TjvQhpCX6B1v/dAZHU1AuLgHvRh54RiOerpEhEW46Tkf+vgAViB/CWC0ag=="
+      "version": "3.35.0",
+      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.35.0.tgz",
+      "integrity": "sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg=="
     },
     "core-js-compat": {
       "version": "3.33.0",
@@ -4636,9 +4643,9 @@
       }
     },
     "dompurify": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.0.6.tgz",
-      "integrity": "sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w=="
+      "version": "3.0.7",
+      "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.0.7.tgz",
+      "integrity": "sha512-BViYTZoqP3ak/ULKOc101y+CtHDUvBsVgSxIF1ku0HmK6BRf+C03MC+tArMvOPtVtZp83DDh5puywKDu4sbVjQ=="
     },
     "domready": {
       "version": "1.0.8",
@@ -5013,9 +5020,9 @@
       }
     },
     "eslint-config-prettier": {
-      "version": "8.10.0",
-      "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz",
-      "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==",
+      "version": "9.1.0",
+      "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
+      "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
       "dev": true
     },
     "eslint-plugin-prettier": {
@@ -5575,7 +5582,8 @@
     "follow-redirects": {
       "version": "1.15.3",
       "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.3.tgz",
-      "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q=="
+      "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
+      "dev": true
     },
     "for-in": {
       "version": "1.0.2",
@@ -5817,9 +5825,9 @@
       "dev": true
     },
     "hanzi-writer": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmmirror.com/hanzi-writer/-/hanzi-writer-3.6.0.tgz",
-      "integrity": "sha512-2fDdpnNq33rFihiOX2iHIKjWwNPoo6yl95wqAyhtq/PRRMwTTzKNT8JgtqwCebMJi9TjyXySBIfs3xI1FLSsvA=="
+      "version": "3.6.1",
+      "resolved": "https://registry.npmmirror.com/hanzi-writer/-/hanzi-writer-3.6.1.tgz",
+      "integrity": "sha512-8QHy1l+ggSYG7+Qvd3Sy5xSt/MLe514v31e5UR6YYnrcxd/hUcjdvavUlD68rTMilDZEoCddWLG7gl1ri3LSCA=="
     },
     "hard-rejection": {
       "version": "2.1.0",
@@ -9439,9 +9447,9 @@
       "dev": true
     },
     "sass": {
-      "version": "1.69.5",
-      "resolved": "https://registry.npmmirror.com/sass/-/sass-1.69.5.tgz",
-      "integrity": "sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==",
+      "version": "1.69.7",
+      "resolved": "https://registry.npmmirror.com/sass/-/sass-1.69.7.tgz",
+      "integrity": "sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==",
       "dev": true,
       "requires": {
         "chokidar": ">=3.0.0 <4.0.0",
@@ -10763,17 +10771,17 @@
       "dev": true
     },
     "svgo": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmmirror.com/svgo/-/svgo-3.1.0.tgz",
-      "integrity": "sha512-R5SnNA89w1dYgNv570591F66v34b3eQShpIBcQtZtM5trJwm1VvxbIoMpRYY3ybTAutcKTLEmTsdnaknOHbiQA==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmmirror.com/svgo/-/svgo-3.2.0.tgz",
+      "integrity": "sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==",
       "dev": true,
       "requires": {
         "@trysound/sax": "0.2.0",
         "commander": "^7.2.0",
         "css-select": "^5.1.0",
-        "css-tree": "^2.2.1",
+        "css-tree": "^2.3.1",
         "css-what": "^6.1.0",
-        "csso": "5.0.5",
+        "csso": "^5.0.5",
         "picocolors": "^1.0.0"
       },
       "dependencies": {

+ 9 - 9
package.json

@@ -10,11 +10,11 @@
   },
   "dependencies": {
     "@tinymce/tinymce-vue": "^3.2.8",
-    "axios": "^1.6.3",
-    "core-js": "^3.34.0",
-    "dompurify": "^3.0.6",
+    "axios": "^1.6.4",
+    "core-js": "^3.35.0",
+    "dompurify": "^3.0.7",
     "element-ui": "^2.15.14",
-    "hanzi-writer": "^3.6.0",
+    "hanzi-writer": "^3.6.1",
     "js-audio-recorder": "^1.0.7",
     "js-cookie": "^3.0.5",
     "md5": "^2.3.0",
@@ -27,14 +27,14 @@
     "vuex": "^3.6.2"
   },
   "devDependencies": {
-    "@babel/core": "^7.23.6",
+    "@babel/core": "^7.23.7",
     "@babel/eslint-parser": "^7.23.3",
     "@rushstack/eslint-patch": "^1.6.1",
     "@types/md5": "^2.3.5",
     "@vue/cli-plugin-babel": "~5.0.8",
     "@vue/cli-plugin-eslint": "~5.0.8",
     "@vue/cli-service": "~5.0.8",
-    "@vue/eslint-config-prettier": "^8.0.0",
+    "@vue/eslint-config-prettier": "^9.0.0",
     "@vue/preload-webpack-plugin": "^2.0.0",
     "babel-plugin-dynamic-import-node": "^2.3.3",
     "compression-webpack-plugin": "^6.1.2",
@@ -44,8 +44,8 @@
     "patch-package": "^8.0.0",
     "postcss-html": "^1.5.0",
     "prettier": "^3.1.1",
-    "sass": "^1.69.5",
-    "sass-loader": "^13.3.2",
+    "sass": "^1.69.7",
+    "sass-loader": "^13.3.3",
     "stylelint": "^15.11.0",
     "stylelint-config-recess-order": "^4.4.0",
     "stylelint-config-recommended-scss": "^14.0.0",
@@ -54,7 +54,7 @@
     "stylelint-declaration-block-no-ignored-properties": "^2.8.0",
     "stylelint-webpack-plugin": "^4.1.1",
     "svg-sprite-loader": "^6.0.11",
-    "svgo": "^3.1.0",
+    "svgo": "^3.2.0",
     "vue-template-compiler": "^2.6.14"
   },
   "engines": {

+ 1 - 0
src/views/exercise_questions/create/components/common/AudioPlay.vue

@@ -200,6 +200,7 @@ export default {
     height: 40px;
     color: #fff;
     cursor: pointer;
+    background-color: $main-color;
     border-radius: 20px;
 
     &.not-url {

+ 78 - 24
src/views/exercise_questions/create/components/exercises/ListenSelectQuestion.vue

@@ -22,24 +22,34 @@
       <div class="content">
         <ul>
           <li v-for="(item, i) in data.option_list" :key="i" class="content-item">
-            <span class="question-number" title="双击切换序号类型" @dblclick="changeOptionType(data)">
-              {{ computedQuestionNumber(i, data.option_number_show_mode) }}
-            </span>
-            <div v-if="isEnable(data.property.is_option_subdivision)" class="option-list">
-              <div v-for="li in item.data_list" :key="li.mark" class="option-content">
-                <span
-                  :class="['checkbox', { active: isAnswer(li.mark, item.mark) }]"
-                  @click="selectAnswer(li.mark, item.mark)"
-                ></span>
-                <RichText v-model="li.content" placeholder="输入内容" :inline="true" />
+            <template v-if="isEnable(data.property.is_option_subdivision)">
+              <div class="option-subdivision">
+                <div class="option-subdivision-top">
+                  <el-input v-model="item.question_number" />
+                  <RichText v-model="item.stem" placeholder="输入小题干" :inline="true" />
+                </div>
+                <div class="option-list">
+                  <div v-for="li in item.data_list" :key="li.mark" class="option-content">
+                    <span
+                      :class="['checkbox', { active: isAnswer(li.mark, item.mark) }]"
+                      @click="selectAnswer(li.mark, item.mark)"
+                    ></span>
+                    <RichText v-model="li.content" placeholder="输入内容" :inline="true" />
+                  </div>
+                </div>
               </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>
-            <SvgIcon icon-class="delete" class="delete pointer" @click="deleteOption(i)" />
+              <SvgIcon icon-class="delete" class="delete pointer" @click="deleteOption(i)" />
+            </template>
+            <template v-else>
+              <span class="question-number" title="双击切换序号类型" @dblclick="changeOptionType(data)">
+                {{ computedQuestionNumber(i, data.option_number_show_mode) }}
+              </span>
+              <div class="option-content">
+                <span :class="['checkbox', { active: isAnswer(item.mark) }]" @click="selectAnswer(item.mark)"></span>
+                <RichText v-model="item.content" placeholder="输入内容" :inline="true" />
+              </div>
+              <SvgIcon icon-class="delete" class="delete pointer" @click="deleteOption(i)" />
+            </template>
           </li>
         </ul>
       </div>
@@ -233,7 +243,7 @@ export default {
           if (index === -1) {
             answer_list.push({ mark: parent_mark, value_list: [mark] });
           } else {
-            let mIndex = answer_list[index].value_list.findIndex((item) => item.mark === mark);
+            let mIndex = answer_list[index].value_list.findIndex((item) => item === mark);
             if (mIndex === -1) {
               answer_list[index].value_list.push(mark);
             } else {
@@ -252,7 +262,7 @@ export default {
     addOption() {
       this.data.option_list.push(
         isEnable(this.data.property.is_option_subdivision)
-          ? getSubdivisionOption(this.data.property.option_number)
+          ? getSubdivisionOption(this.data.property.option_number, this.data.option_list.length)
           : getOption(),
       );
     },
@@ -266,8 +276,8 @@ export default {
       if (isEnable(val)) {
         // 创建与当前 option_list 相同数量的选项,选项内的细分数量与 property.option_number 数量一样
         this.data.answer.answer_list = [];
-        this.data.option_list = Array.from({ length: this.data.option_list.length }, () => {
-          return getSubdivisionOption(this.data.property.option_number);
+        this.data.option_list = Array.from({ length: this.data.option_list.length }, (el, i) => {
+          return getSubdivisionOption(this.data.property.option_number, i);
         });
       } else {
         this.data.answer.answer_list = [];
@@ -280,11 +290,11 @@ export default {
      */
     changeOptionNumber(val) {
       this.data.answer.answer_list = [];
-      this.data.option_list = this.data.option_list.map(({ data_list, mark }) => {
+      this.data.option_list = this.data.option_list.map(({ data_list, ...data }) => {
         if (data_list.length < val) {
-          return { mark, data_list: [...data_list, ...Array.from({ length: val - data_list.length }, getOption)] };
+          return { ...data, data_list: [...data_list, ...Array.from({ length: val - data_list.length }, getOption)] };
         }
-        return { mark, data_list: data_list.slice(0, val) };
+        return { ...data, data_list: data_list.slice(0, val) };
       });
     },
   },
@@ -293,6 +303,50 @@ export default {
 
 <style lang="scss" scoped>
 .content {
+  .option-subdivision {
+    display: flex;
+    flex: 1;
+    flex-direction: column;
+    row-gap: 8px;
+
+    &-top {
+      display: flex;
+      column-gap: 8px;
+
+      .el-input {
+        width: 40px;
+
+        :deep &__inner {
+          padding: 0 4px;
+          text-align: center;
+        }
+      }
+
+      .rich-wrapper {
+        flex: 1;
+        min-height: 32px;
+        padding-left: 16px;
+        background-color: $fill-color;
+
+        :deep .rich-text {
+          &.mce-content-body {
+            padding-top: 4px;
+          }
+
+          &:not(.mce-edit-focus) {
+            p {
+              margin: 0;
+            }
+          }
+
+          &.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before {
+            top: 6px;
+          }
+        }
+      }
+    }
+  }
+
   .option-list {
     display: flex;
     flex: 1;

+ 3 - 1
src/views/exercise_questions/data/listenSelect.js

@@ -17,9 +17,11 @@ export function getOption(content = '') {
  * 获取选项细分数据项
  * @param {number} number 选项数
  */
-export function getSubdivisionOption(number = 2) {
+export function getSubdivisionOption(number = 2, index) {
   return {
     mark: getRandomNumber(),
+    stem: '',
+    question_number: `${index + 1}`,
     data_list: Array.from({ length: number }, () => getOption()),
   };
 }

+ 39 - 15
src/views/exercise_questions/preview/ListenSelectPreview.vue

@@ -19,21 +19,24 @@
     />
 
     <div v-if="isEnable(data.property.is_option_subdivision)" class="option-subdivision">
-      <ul v-for="(item, i) in data.option_list" :key="item.mark" class="option-subdivision-list">
-        <span class="serial-number" :style="{ fontSize: data.property.option_question_number_font_size }">
-          {{ computeOptionMethods[data.option_number_show_mode](i) }}
-        </span>
-        <li
-          v-for="{ content, mark } in item.data_list"
-          :key="mark"
-          :style="{ cursor: disabled ? 'not-allowed' : 'pointer' }"
-          :class="['option-item', { active: isAnswer(mark, item.mark) }, ...computedAnswerClass(mark, item.mark)]"
-          @click="selectAnswer(mark, item.mark)"
-        >
-          <span class="selectionbox"></span>
-          <span class="content rich-text" v-html="sanitizeHTML(content)"></span>
-        </li>
-      </ul>
+      <div v-for="item in data.option_list" :key="item.mark" class="option-subdivision-item">
+        <div class="option-subdivision-top">
+          <span :style="{ fontSize: data.property.option_question_number_font_size }">{{ item.question_number }}.</span>
+          <span class="rich-text" v-html="sanitizeHTML(item.stem)"></span>
+        </div>
+        <ul class="option-subdivision-list">
+          <li
+            v-for="{ content, mark } in item.data_list"
+            :key="mark"
+            :style="{ cursor: disabled ? 'not-allowed' : 'pointer' }"
+            :class="['option-item', { active: isAnswer(mark, item.mark) }, ...computedAnswerClass(mark, item.mark)]"
+            @click="selectAnswer(mark, item.mark)"
+          >
+            <span class="selectionbox"></span>
+            <span class="content rich-text" v-html="sanitizeHTML(content)"></span>
+          </li>
+        </ul>
+      </div>
     </div>
 
     <ul v-else class="option-list">
@@ -231,6 +234,27 @@ export default {
     flex-direction: column;
     row-gap: 24px;
 
+    &-item {
+      display: flex;
+      flex: 1;
+      flex-direction: column;
+      row-gap: 8px;
+
+      .option-subdivision-top {
+        display: flex;
+        column-gap: 24px;
+        align-items: center;
+
+        .rich-text {
+          flex: 1;
+        }
+      }
+
+      :deep p {
+        margin: 0;
+      }
+    }
+
     &-list {
       @extend %option-list;
 

+ 1 - 1
src/views/exercise_questions/preview/components/PreviewMixin.js

@@ -54,7 +54,7 @@ const PreviewMixin = {
       if (userAnswer) this.answer = userAnswer;
     },
     /**
-     * 题目序号是否以括号结尾,如果不是则加上 '.'
+     * 题号是否有括号,如果没有则加上 '.'
      * @param {string} question_number 题目序号
      * @returns {string} 题目序号
      */