Selaa lähdekoodia

填表题修改

dusenyao 1 vuosi sitten
vanhempi
commit
ffcdc8959c

+ 1 - 1
src/utils/index.js

@@ -1,4 +1,4 @@
-// 生成随机数的函数
+// 生成八位随机数的函数
 export function getRandomNumber() {
   return Math.random().toString(36).substring(2, 10); // 生成一个随机字符串
 }

+ 216 - 50
src/views/exercise_questions/create/components/exercises/TableFillQuestion.vue

@@ -17,11 +17,8 @@
           <template v-for="i in data.property.column_number">
             <div :key="i" class="fill-form">
               <!-- 头部 -->
-              <span
-                v-if="isEnable(data.property.is_enable_table_header)"
-                class="form-header"
-                :style="{ paddingLeft: isEnable(data.property.is_enable_number_column) && i === 1 ? '40px' : '0' }"
-              >
+              <span v-if="isEnable(data.property.is_enable_table_header)" class="form-header">
+                <span v-if="isEnable(data.property.is_enable_number_column) && i === 1" class="serial-number"></span>
                 <el-input v-model="data.option_header_list[i - 1].text" placeholder="请输入" />
               </span>
 
@@ -45,13 +42,50 @@
           </template>
         </div>
 
-        <el-input
-          v-if="isEnable(data.property.is_enable_reference_answer)"
-          v-model="data.reference_answer"
-          type="textarea"
-          rows="3"
-          placeholder="输入参考答案"
-        />
+        <template v-if="isEnable(data.property.is_enable_reference_answer)">
+          <span class="reference-title">参考答案:</span>
+          <div class="form-wrapper">
+            <div class="form" :style="{ width: `${data.property.form_width}px` }">
+              <div v-if="isEnable(data.property.is_enable_table_header)" class="form-header">
+                <div
+                  v-for="(item, i) in data.reference_answer_option_header_list"
+                  :key="i"
+                  :style="{
+                    borderLeft: isEnable(data.property.is_enable_number_column) || i > 0 ? '1px solid #e0e0e0' : 'none',
+                    width:
+                      isEnable(data.property.is_enable_number_column) && i === 0
+                        ? `calc(${item.width}% - 39px)`
+                        : `${item.width}%`,
+                    marginLeft: isEnable(data.property.is_enable_number_column) && i === 0 ? '39px' : '0',
+                  }"
+                  class="header-item"
+                >
+                  <el-input v-model="item.text" placeholder="请输入" />
+                </div>
+              </div>
+              <div v-for="(item, i) in data.reference_answer_option_list" :key="i" class="form-content">
+                <div
+                  v-for="(li, j) in item"
+                  :key="li.mark"
+                  :style="{ width: `${data.reference_answer_option_header_list[j].width}%` }"
+                  class="form-item"
+                >
+                  <span v-if="j === 0 && isEnable(data.property.is_enable_number_column)" class="serial-number">
+                    {{ i + 1 }}
+                  </span>
+                  <div class="item-content">
+                    <el-input
+                      v-model="li.text"
+                      class="fill"
+                      placeholder="请输入"
+                      @blur="handleTone(li.text, i, j, 'reference')"
+                    />
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </template>
       </div>
     </template>
 
@@ -179,41 +213,15 @@ export default {
   watch: {
     'data.property.row_number': {
       handler(val) {
-        if (val > this.data.option_list.length) {
-          this.data.option_list.push(Array.from({ length: this.data.property.column_number }, () => getOption()));
-        } else if (val < this.data.option_list.length) {
-          this.data.option_list.pop();
-        }
+        this.handleRowNumber(val, 'option');
+        this.handleRowNumber(val, 'reference');
       },
       immediate: true,
     },
     'data.property.column_number': {
       handler(val) {
-        // 列数变化时,需要重新计算每列的宽度
-        if (val > this.data.option_header_list.length) {
-          let width = 0;
-          this.data.option_header_list.forEach((item) => {
-            // 平均分配宽度,最小宽度为10
-            let w = Math.max((item.width / val) * this.data.option_header_list.length, 10);
-            width += item.width - w;
-            item.width = w;
-          });
-          this.data.option_header_list.push({ mark: getRandomNumber(), text: '', width });
-        } else if (val < this.data.option_header_list.length) {
-          let width = this.data.option_header_list[val].width;
-          this.data.option_header_list.pop();
-          this.data.option_header_list.forEach((item) => {
-            item.width += width / val;
-          });
-        }
-
-        this.data.option_list = this.data.option_list.map((item) => {
-          const arr = [];
-          for (let i = 0; i < val; i++) {
-            arr.push(item[i] || getOption());
-          }
-          return arr;
-        });
+        this.handleColumnNumber(val, 'option');
+        this.handleColumnNumber(val, 'reference');
       },
       immediate: true,
     },
@@ -264,6 +272,16 @@ export default {
         list[i - 1].width = Math.min(Math.max(10, list[i - 1].width + w), list[i - 1].width + list[i].width - 10);
         list[i].width = Math.min(Math.max(10, list[i].width - w), list[i - 1].width + list[i].width - 10);
 
+        let referenceList = this.data.reference_answer_option_header_list;
+        referenceList[i - 1].width = Math.min(
+          Math.max(10, referenceList[i - 1].width + w),
+          referenceList[i - 1].width + referenceList[i].width - 10,
+        );
+        referenceList[i].width = Math.min(
+          Math.max(10, referenceList[i].width - w),
+          referenceList[i - 1].width + referenceList[i].width - 10,
+        );
+
         startX = endX;
       };
 
@@ -277,8 +295,10 @@ export default {
       target.setCapture && target.setCapture(); // 该函数在属于当前线程的指定窗口里设置鼠标捕获
       return false;
     },
-    handleTone(value, i, j) {
-      this.data.option_list[j - 1][i - 1].text = value
+    handleTone(value, i, j, type = 'option') {
+      let option =
+        type === 'reference' ? this.data.reference_answer_option_list[i][j] : this.data.option_list[j - 1][i - 1];
+      let text = value
         .trim()
         .split(/\s+/)
         .map((item) => {
@@ -289,6 +309,46 @@ export default {
         )
         .filter((item) => item.length > 0)
         .join(' ');
+      this.$set(option, 'text', text);
+    },
+
+    handleRowNumber(val, type = 'option') {
+      let option = type === 'reference' ? this.data.reference_answer_option_list : this.data.option_list;
+      if (val > option.length) {
+        option.push(Array.from({ length: this.data.property.column_number }, () => getOption(type)));
+      } else if (val < option.length) {
+        option.pop();
+      }
+    },
+    handleColumnNumber(val, type) {
+      let header_list =
+        type === 'reference' ? this.data.reference_answer_option_header_list : this.data.option_header_list;
+      // 列数变化时,需要重新计算每列的宽度
+      if (val > header_list.length) {
+        let width = 0;
+        header_list.forEach((item) => {
+          // 平均分配宽度,最小宽度为10
+          let w = Math.max((item.width / val) * header_list.length, 10);
+          width += item.width - w;
+          item.width = w;
+        });
+        header_list.push({ mark: getRandomNumber(), text: '', width });
+      } else if (val < header_list.length) {
+        let width = header_list[val].width;
+        header_list.pop();
+        header_list.forEach((item) => {
+          item.width += width / val;
+        });
+      }
+
+      let listName = type === 'reference' ? 'reference_answer_option_list' : 'option_list';
+      this.data[listName] = this.data[listName].map((item) => {
+        const arr = [];
+        for (let i = 0; i < val; i++) {
+          arr.push(item[i] || getOption(type));
+        }
+        return arr;
+      });
     },
     // 计算选项样式
     computedOptionStyle() {
@@ -309,6 +369,8 @@ export default {
 </script>
 
 <style lang="scss" scoped>
+$table-border: 1px solid #e0e0e0;
+
 .mask {
   position: absolute;
   top: 0;
@@ -320,13 +382,16 @@ export default {
 }
 
 .content {
+  display: flex;
+  flex-direction: column;
+  row-gap: 8px;
   width: calc(100vw - 645px);
   overflow: auto;
 
   .option-wrapper {
     display: grid;
     grid-auto-flow: column;
-    margin-bottom: 8px;
+    border: $table-border;
 
     .fill-form {
       display: flex;
@@ -336,16 +401,23 @@ export default {
         display: flex;
         align-items: center;
         height: 40px;
-        background-color: $fill-color;
+        background-color: #eaeffb;
+        border-bottom: $table-border;
 
-        .header-serial-number {
-          padding: 8px 16px;
-          font-weight: bold;
+        .serial-number {
+          width: 41px;
+          min-width: 41px;
+          height: 40px;
+          color: #000;
+          border-right: $table-border;
         }
 
         :deep .el-input__inner {
           font-size: 16px;
           font-weight: bold;
+          color: $main-color;
+          text-align: center;
+          background-color: #eaeffb;
         }
       }
 
@@ -362,11 +434,17 @@ export default {
         }
 
         .el-input {
+          border-bottom-width: 0;
+
           :deep &__inner {
             height: 54px;
             font-size: 16px;
             line-height: 54px;
+            color: $font-color;
+            text-align: left;
             background-color: #fff;
+            border-bottom-width: 0;
+            border-radius: 0;
 
             &:focus {
               border-color: #c0c4cc;
@@ -384,10 +462,98 @@ export default {
       width: 2px;
       height: 100%;
       cursor: col-resize;
-      background-color: #165dff;
+      background-color: #e0e0e0;
       border-radius: 4px;
     }
   }
+
+  .reference-title {
+    font-size: 14px;
+    color: #000;
+  }
+
+  .form-wrapper {
+    .form {
+      border: $table-border;
+
+      &-header {
+        display: flex;
+        font-weight: bold;
+        color: $main-color;
+        background-color: #eaeffb;
+
+        .header-item {
+          min-height: 40px;
+          padding: 8px 12px;
+          font-size: 16px;
+          text-align: center;
+
+          :deep .el-input__inner {
+            font-size: 16px;
+            font-weight: bold;
+            color: $main-color;
+            text-align: center;
+            background-color: #eaeffb;
+          }
+        }
+      }
+
+      &-header + .form-content {
+        border-top: $table-border;
+      }
+
+      &-content:not(:last-child) {
+        border-bottom: $table-border;
+      }
+
+      &-content {
+        display: flex;
+
+        .form-item:not(:first-child) {
+          border-left: $table-border;
+        }
+
+        .form-item {
+          display: flex;
+          align-items: center;
+          min-height: 48px;
+          overflow: auto;
+
+          .item-content {
+            flex: 1;
+            padding: 8px 12px;
+          }
+
+          .el-input.fill {
+            display: inline-flex;
+            align-items: center;
+            margin: 0 2px;
+
+            :deep input.el-input__inner {
+              padding: 0;
+              font-size: 16px;
+              color: $font-color;
+              text-align: left;
+              background-color: #fff;
+              border-width: 0;
+              border-radius: 0;
+            }
+          }
+        }
+      }
+
+      .serial-number {
+        display: flex;
+        align-items: center;
+        width: 40px;
+        min-width: 40px;
+        max-width: 40px;
+        height: 100%;
+        padding: 8px 12px;
+        border-right: $table-border;
+      }
+    }
+  }
 }
 
 .property {

+ 16 - 1
src/views/exercise_questions/data/tableFill.js

@@ -2,7 +2,12 @@ import { getRandomNumber } from '@/utils';
 import { stemTypeList, questionNumberTypeList, scoreTypeList, switchOption, fontSizeList } from './common';
 import { Message } from 'element-ui';
 
-export function getOption(text = '') {
+export function getOption(type = 'option', text = '') {
+  if (type === 'reference') {
+    return {
+      text,
+    };
+  }
   return {
     mark: getRandomNumber(),
     text,
@@ -76,6 +81,16 @@ export function getTableFillData() {
     stem: '', // 题干
     description: '', // 描述
     reference_answer: '', // 参考答案
+    // 参考答案表头
+    reference_answer_option_header_list: [
+      { mark: getRandomNumber(), text: '', width: 50 },
+      { mark: getRandomNumber(), text: '', width: 50 },
+    ],
+    // 参考答案列表
+    reference_answer_option_list: [
+      Array.from({ length: 2 }, () => getOption('reference')),
+      Array.from({ length: 2 }, () => getOption('reference')),
+    ],
     option_header_list: [
       { mark: getRandomNumber(), text: '', width: 50 },
       { mark: getRandomNumber(), text: '', width: 50 },

+ 34 - 32
src/views/exercise_questions/preview/TableFillPreview.vue

@@ -63,7 +63,40 @@
 
     <div v-if="isEnable(data.property.is_enable_reference_answer) && isShowRightAnswer" class="reference-box">
       <h5 class="reference-title">参考答案</h5>
-      <div class="reference-answer">{{ data.reference_answer }}</div>
+      <div class="form-wrapper">
+        <div class="form" :style="{ width: `${data.property.form_width}px`, backgroundColor: '#fff' }">
+          <div v-if="isEnable(data.property.is_enable_table_header)" class="form-header">
+            <div
+              v-for="({ text, mark, width }, i) in data.reference_answer_option_header_list"
+              :key="mark"
+              :style="{
+                borderLeft: isEnable(data.property.is_enable_number_column) || i > 0 ? '1px solid #e0e0e0' : 'none',
+                width:
+                  isEnable(data.property.is_enable_number_column) && i === 0 ? `calc(${width}% - 39.5px)` : `${width}%`,
+                marginLeft: isEnable(data.property.is_enable_number_column) && i === 0 ? '39.5px' : '0',
+              }"
+              class="header-item"
+            >
+              <span>{{ text }}</span>
+            </div>
+          </div>
+          <div v-for="(item, i) in data.reference_answer_option_list" :key="i" class="form-content">
+            <div
+              v-for="(li, j) in item"
+              :key="li.mark"
+              :style="{ width: `${data.reference_answer_option_header_list[j].width}%` }"
+              class="form-item"
+            >
+              <span v-if="j === 0 && isEnable(data.property.is_enable_number_column)" class="serial-number">
+                {{ i + 1 }}
+              </span>
+              <div class="item-content">
+                <span>{{ li.text }}</span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
     </div>
   </div>
 </template>
@@ -207,37 +240,6 @@ $table-border: 1px solid #e0e0e0;
             width: 120px;
             margin: 0 2px;
 
-            &.right {
-              :deep input.el-input__inner {
-                color: $right-color;
-              }
-            }
-
-            &.wrong {
-              :deep input.el-input__inner {
-                color: $error-color;
-              }
-            }
-
-            & + .right-answer-fill {
-              position: relative;
-              left: -4px;
-              display: inline-block;
-              height: 32px;
-              line-height: 28px;
-              vertical-align: bottom;
-              border-bottom: $table-border;
-            }
-
-            & + .right-answer-content {
-              position: relative;
-              left: -4px;
-              display: inline-block;
-              height: 32px;
-              line-height: 28px;
-              vertical-align: bottom;
-            }
-
             :deep input.el-input__inner {
               padding: 0;
               font-size: 16px;