Bladeren bron

修改问题,新增活动题,问答题、填表题增加拼音

dusenyao 1 jaar geleden
bovenliggende
commit
ad154f7b12
25 gewijzigde bestanden met toevoegingen van 311 en 104 verwijderingen
  1. 1 1
      .vscode/settings.json
  2. 16 16
      package-lock.json
  3. 4 4
      package.json
  4. 0 1
      src/styles/index.scss
  5. 1 0
      src/views/exercise_questions/answer/answer.js
  6. 2 0
      src/views/exercise_questions/create/components/create.vue
  7. 80 0
      src/views/exercise_questions/create/components/exercises/ActivityQuestion.vue
  8. 2 2
      src/views/exercise_questions/create/components/exercises/FillQuestion.vue
  9. 2 2
      src/views/exercise_questions/create/components/exercises/ListenFillQuestion.vue
  10. 19 5
      src/views/exercise_questions/create/components/exercises/TableFillQuestion.vue
  11. 2 0
      src/views/exercise_questions/data/PreviewQuestionTypeMixin.js
  12. 19 0
      src/views/exercise_questions/data/activity.js
  13. 20 0
      src/views/exercise_questions/data/common.js
  14. 0 20
      src/views/exercise_questions/data/fill.js
  15. 0 20
      src/views/exercise_questions/data/listenFill.js
  16. 6 0
      src/views/exercise_questions/data/questionType.js
  17. 63 0
      src/views/exercise_questions/preview/ActivityPreview.vue
  18. 18 2
      src/views/exercise_questions/preview/EssayQuestionPreview.vue
  19. 1 2
      src/views/exercise_questions/preview/FillPreview.vue
  20. 1 2
      src/views/exercise_questions/preview/ListenFillPreview.vue
  21. 5 5
      src/views/exercise_questions/preview/ReadAloudPreview.vue
  22. 6 2
      src/views/exercise_questions/preview/ReadPreview.vue
  23. 40 17
      src/views/exercise_questions/preview/TableFillPreview.vue
  24. 1 1
      src/views/exercise_questions/preview/TalkPictruePreview.vue
  25. 2 2
      src/views/exercise_questions/preview/components/common/Strockplayredline.vue

+ 1 - 1
.vscode/settings.json

@@ -1,3 +1,3 @@
 {
-  "cSpell.words": ["cascader", "GCLS", "tinymce"]
+  "cSpell.words": ["cascader", "GCLS", "hanzi", "tinymce"]
 }

+ 16 - 16
package-lock.json

@@ -5026,9 +5026,9 @@
       "dev": true
     },
     "eslint-plugin-prettier": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.2.tgz",
-      "integrity": "sha512-dhlpWc9vOwohcWmClFcA+HjlvUpuyynYs0Rf+L/P6/0iQE6vlHW9l5bkfzN62/Stm9fbq8ku46qzde76T1xlSg==",
+      "version": "5.1.3",
+      "resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz",
+      "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==",
       "dev": true,
       "requires": {
         "prettier-linter-helpers": "^1.0.0",
@@ -5036,9 +5036,9 @@
       }
     },
     "eslint-plugin-vue": {
-      "version": "9.19.2",
-      "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.19.2.tgz",
-      "integrity": "sha512-CPDqTOG2K4Ni2o4J5wixkLVNwgctKXFu6oBpVJlpNq7f38lh9I80pRTouZSJ2MAebPJlINU/KTFSXyQfBUlymA==",
+      "version": "9.20.1",
+      "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.20.1.tgz",
+      "integrity": "sha512-GyCs8K3lkEvoyC1VV97GJhP1SvqsKCiWGHnbn0gVUYiUhaH2+nB+Dv1uekv1THFMPbBfYxukrzQdltw950k+LQ==",
       "dev": true,
       "requires": {
         "@eslint-community/eslint-utils": "^4.4.0",
@@ -5046,7 +5046,7 @@
         "nth-check": "^2.1.1",
         "postcss-selector-parser": "^6.0.13",
         "semver": "^7.5.4",
-        "vue-eslint-parser": "^9.3.1",
+        "vue-eslint-parser": "^9.4.0",
         "xml-name-validator": "^4.0.0"
       },
       "dependencies": {
@@ -8427,9 +8427,9 @@
       "dev": true
     },
     "postcss-html": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmmirror.com/postcss-html/-/postcss-html-1.5.0.tgz",
-      "integrity": "sha512-kCMRWJRHKicpA166kc2lAVUGxDZL324bkj/pVOb6RhjB0Z5Krl7mN0AsVkBhVIRZZirY0lyQXG38HCVaoKVNoA==",
+      "version": "1.6.0",
+      "resolved": "https://registry.npmmirror.com/postcss-html/-/postcss-html-1.6.0.tgz",
+      "integrity": "sha512-OWgQ9/Pe23MnNJC0PL4uZp8k0EDaUvqpJFSiwFxOLClAhmD7UEisyhO3x5hVsD4xFrjReVTXydlrMes45dJ71w==",
       "dev": true,
       "requires": {
         "htmlparser2": "^8.0.0",
@@ -8966,9 +8966,9 @@
       "dev": true
     },
     "prettier": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.1.1.tgz",
-      "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
+      "version": "3.2.2",
+      "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.2.2.tgz",
+      "integrity": "sha512-HTByuKZzw7utPiDO523Tt2pLtEyK7OibUD9suEJQrPUCYQqrHr74GGX6VidMrovbf/I50mPqr8j/II6oBAuc5A==",
       "dev": true
     },
     "prettier-linter-helpers": {
@@ -11465,9 +11465,9 @@
       }
     },
     "vue-eslint-parser": {
-      "version": "9.3.2",
-      "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz",
-      "integrity": "sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==",
+      "version": "9.4.0",
+      "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.4.0.tgz",
+      "integrity": "sha512-7KsNBb6gHFA75BtneJsoK/dbZ281whUIwFYdQxA68QrCrGMXYzUMbPDHGcOQ0OocIVKrWSKWXZ4mL7tonCXoUw==",
       "dev": true,
       "requires": {
         "debug": "^4.3.4",

+ 4 - 4
package.json

@@ -39,11 +39,11 @@
     "babel-plugin-dynamic-import-node": "^2.3.3",
     "compression-webpack-plugin": "^6.1.2",
     "eslint": "^8.56.0",
-    "eslint-plugin-prettier": "^5.1.2",
-    "eslint-plugin-vue": "^9.19.2",
+    "eslint-plugin-prettier": "^5.1.3",
+    "eslint-plugin-vue": "^9.20.1",
     "patch-package": "^8.0.0",
-    "postcss-html": "^1.5.0",
-    "prettier": "^3.1.1",
+    "postcss-html": "^1.6.0",
+    "prettier": "^3.2.2",
     "sass": "^1.69.7",
     "sass-loader": "^13.3.3",
     "stylelint": "^15.11.0",

+ 0 - 1
src/styles/index.scss

@@ -11,7 +11,6 @@
   color: $font-color;
   color-scheme: light dark;
   background-color: $main-background-color;
-  font-synthesis: none;
   text-rendering: optimizeLegibility;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;

+ 1 - 0
src/views/exercise_questions/answer/answer.js

@@ -10,4 +10,5 @@ export const subjectiveQuestionList = [
   'replace_answer',
   'essay_question',
   'table_fill',
+  'activity',
 ];

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

@@ -64,6 +64,7 @@ import ReplaceAnswerQuestion from './exercises/ReplaceAnswerQuestion.vue';
 import EssayQuestion from './exercises/EssayQuestion.vue';
 import TableFillQuestion from './exercises/TableFillQuestion.vue';
 import WordDictationQuestion from './exercises/WordDictationQuestion.vue';
+import ActivityQuestion from './exercises/ActivityQuestion.vue';
 
 export default {
   name: 'CreateMain',
@@ -119,6 +120,7 @@ export default {
         essay_question: EssayQuestion,
         table_fill: TableFillQuestion,
         word_dictation: WordDictationQuestion,
+        activity: ActivityQuestion,
       },
     };
   },

+ 80 - 0
src/views/exercise_questions/create/components/exercises/ActivityQuestion.vue

@@ -0,0 +1,80 @@
+<template>
+  <QuestionBase>
+    <template #content>
+      <div class="stem">
+        <RichText v-model="data.stem" :font-size="18" placeholder="输入题干" />
+
+        <RichText
+          v-if="isEnable(data.property.is_enable_description)"
+          v-model="data.description"
+          placeholder="输入提示"
+        />
+      </div>
+    </template>
+
+    <template #property>
+      <el-form :model="data.property" label-width="72px" label-position="left">
+        <el-form-item label="题号">
+          <el-input v-model="data.property.question_number" />
+        </el-form-item>
+        <el-form-item>
+          <el-radio
+            v-for="{ value, label } in questionNumberTypeList"
+            :key="value"
+            v-model="data.other.question_number_type"
+            :label="value"
+          >
+            {{ label }}
+          </el-radio>
+        </el-form-item>
+        <el-form-item label="提示">
+          <el-radio
+            v-for="{ value, label } in switchOption"
+            :key="value"
+            v-model="data.property.is_enable_description"
+            :label="value"
+          >
+            {{ label }}
+          </el-radio>
+        </el-form-item>
+        <el-form-item label="分值">
+          <el-radio
+            v-for="{ value, label } in scoreTypeList"
+            :key="value"
+            v-model="data.property.score_type"
+            :label="value"
+            :disabled="true"
+          >
+            {{ label }}
+          </el-radio>
+        </el-form-item>
+        <el-form-item>
+          <el-input-number
+            v-model="data.property.score"
+            :min="0"
+            :step="data.property.score_type === scoreTypeList[0].value ? 1 : 0.1"
+          />
+        </el-form-item>
+      </el-form>
+    </template>
+  </QuestionBase>
+</template>
+
+<script>
+import QuestionMixin from '../common/QuestionMixin.js';
+
+import { activityData } from '@/views/exercise_questions/data/activity';
+
+export default {
+  name: 'ActivityQuestion',
+  mixins: [QuestionMixin],
+  data() {
+    return {
+      data: JSON.parse(JSON.stringify(activityData)),
+    };
+  },
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped></style>

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

@@ -111,8 +111,8 @@
 import QuestionMixin from '../common/QuestionMixin.js';
 
 import { getRandomNumber } from '@/utils';
-import { addTone } from '@/views/exercise_questions/data/common';
-import { fillData, handleToneValue } from '@/views/exercise_questions/data/fill';
+import { addTone, handleToneValue } from '@/views/exercise_questions/data/common';
+import { fillData } from '@/views/exercise_questions/data/fill';
 
 export default {
   name: 'FillQuestion',

+ 2 - 2
src/views/exercise_questions/create/components/exercises/ListenFillQuestion.vue

@@ -139,8 +139,8 @@ import UploadAudio from '../common/UploadAudio.vue';
 import QuestionMixin from '../common/QuestionMixin.js';
 
 import { getRandomNumber } from '@/utils';
-import { addTone } from '@/views/exercise_questions/data/common';
-import { listenFillData, handleToneValue } from '@/views/exercise_questions/data/listenFill';
+import { addTone, handleToneValue } from '@/views/exercise_questions/data/common';
+import { listenFillData } from '@/views/exercise_questions/data/listenFill';
 
 export default {
   name: 'ListenFillQuestion',

+ 19 - 5
src/views/exercise_questions/create/components/exercises/TableFillQuestion.vue

@@ -29,7 +29,11 @@
                 <span v-if="i === 1 && isEnable(data.property.is_enable_number_column)" class="serial-number">
                   {{ j }}
                 </span>
-                <el-input v-model="data.option_list[j - 1][i - 1].text" placeholder="请输入" />
+                <el-input
+                  v-model="data.option_list[j - 1][i - 1].text"
+                  placeholder="请输入"
+                  @blur="handleTone(data.option_list[j - 1][i - 1].text, i, j)"
+                />
               </span>
             </div>
             <span
@@ -152,6 +156,7 @@ import QuestionMixin from '../common/QuestionMixin.js';
 
 import { getRandomNumber } from '@/utils';
 import { getTableFillData, getOption } from '@/views/exercise_questions/data/tableFill.js';
+import { addTone, handleToneValue } from '@/views/exercise_questions/data/common';
 
 export default {
   name: 'TableFillQuestion',
@@ -305,6 +310,19 @@ export default {
       target.setCapture && target.setCapture(); // 该函数在属于当前线程的指定窗口里设置鼠标捕获
       return false;
     },
+    handleTone(value, i, j) {
+      this.data.option_list[j - 1][i - 1].text = value
+        .trim()
+        .split(/\s+/)
+        .map((item) => {
+          return handleToneValue(item);
+        })
+        .map((item) =>
+          item.map(({ number, con }) => (number && con ? addTone(Number(number), con) : number || con || '')),
+        )
+        .filter((item) => item.length > 0)
+        .join(' ');
+    },
     // 计算选项样式
     computedOptionStyle() {
       let gridTemplateColumns = this.data.option_header_list.reduce((acc, { width }, i) => {
@@ -392,10 +410,6 @@ export default {
         :deep .tox-editor-header {
           display: none;
         }
-
-        :deep .tox-editor-header {
-          display: none;
-        }
       }
     }
 

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

@@ -23,6 +23,7 @@ import ReplaceAnswerPreview from '../preview/ReplaceAnswerPreview.vue';
 import EssayQuestionPreview from '../preview/EssayQuestionPreview.vue';
 import TableFillPreview from '../preview/TableFillPreview.vue';
 import WordDictationPreview from '../preview/WordDictationPreview.vue';
+import ActivityPreviewVue from '../preview/ActivityPreview.vue';
 
 const PreviewQuestionTypeMixin = {
   data() {
@@ -52,6 +53,7 @@ const PreviewQuestionTypeMixin = {
         essay_question: EssayQuestionPreview,
         table_fill: TableFillPreview,
         word_dictation: WordDictationPreview,
+        activity: ActivityPreviewVue,
       },
     };
   },

+ 19 - 0
src/views/exercise_questions/data/activity.js

@@ -0,0 +1,19 @@
+import { stemTypeList, scoreTypeList, questionNumberTypeList, switchOption } from './common';
+
+export const activityData = {
+  type: 'activity', // 题型
+  stem: '', // 题干
+  description: '',
+  answer: { answer_list: [], score: 1, score_type: scoreTypeList[0].value }, // 答案
+  property: {
+    stem_type: stemTypeList[1].value, // 题干类型
+    question_number: '1', // 题号
+    is_enable_description: switchOption[1].value,
+    score: 1, // 分值
+    score_type: scoreTypeList[0].value, // 分值类型
+  },
+  // 其他属性
+  other: {
+    question_number_type: questionNumberTypeList[1].value, // 题号类型
+  },
+};

+ 20 - 0
src/views/exercise_questions/data/common.js

@@ -150,6 +150,26 @@ export function addTone(number, con) {
   return cons;
 }
 
+export function handleToneValue(valItem) {
+  let numList = [];
+  if (/[A-Za-zü]+\d/g.test(valItem)) {
+    valItem.split('').forEach((item, i) => {
+      if (/\d/.test(item)) {
+        let numIndex = numList.length === 0 ? 0 : numList[numList.length - 1].index;
+        let con = valItem.substring(numIndex, i).replace(/\d/g, '');
+        numList.push({
+          number: item,
+          con,
+        });
+      }
+    });
+  } else {
+    numList = [];
+  }
+
+  return numList.length === 0 ? [{ con: valItem }] : numList;
+}
+
 /**
  * 输入框输入小于0的返回0 且为整数
  * @param {number|string} number

+ 0 - 20
src/views/exercise_questions/data/fill.js

@@ -1,25 +1,5 @@
 import { stemTypeList, questionNumberTypeList, scoreTypeList, switchOption, fontSizeList } from './common';
 
-export function handleToneValue(valItem) {
-  let numList = [];
-  if (/[A-Za-zü]+\d/g.test(valItem)) {
-    valItem.split('').forEach((item, i) => {
-      if (/\d/.test(item)) {
-        let numIndex = numList.length === 0 ? 0 : numList[numList.length - 1].index;
-        let con = valItem.substring(numIndex, i).replace(/\d/g, '');
-        numList.push({
-          number: item,
-          con,
-        });
-      }
-    });
-  } else {
-    numList = [];
-  }
-
-  return numList.length === 0 ? [{ con: valItem }] : numList;
-}
-
 // 填空题数据模板
 export const fillData = {
   type: 'fill', // 题型

+ 0 - 20
src/views/exercise_questions/data/listenFill.js

@@ -1,25 +1,5 @@
 import { stemTypeList, questionNumberTypeList, scoreTypeList, switchOption, fontSizeList } from './common';
 
-export function handleToneValue(valItem) {
-  let numList = [];
-  if (/[A-Za-zü]+\d/g.test(valItem)) {
-    valItem.split('').forEach((item, i) => {
-      if (/\d/.test(item)) {
-        let numIndex = numList.length === 0 ? 0 : numList[numList.length - 1].index;
-        let con = valItem.substring(numIndex, i).replace(/\d/g, '');
-        numList.push({
-          number: item,
-          con,
-        });
-      }
-    });
-  } else {
-    numList = [];
-  }
-
-  return numList.length === 0 ? [{ con: valItem }] : numList;
-}
-
 // 听后填空题数据模板
 export const listenFillData = {
   type: 'listen_fill', // 题型

+ 6 - 0
src/views/exercise_questions/data/questionType.js

@@ -21,6 +21,7 @@ import { writePictrueData } from './writePicture';
 import { readData } from './read';
 import { getTableFillData } from './tableFill';
 import { wordDictationData } from './wordDictation';
+import { activityData } from './activity';
 
 // 题型源数据
 export const questionTypeDataOption = [
@@ -82,6 +83,11 @@ export const questionTypeDataOption = [
     label: '阅读题',
     data: readData,
   },
+  {
+    value: 'activity',
+    label: '活动题',
+    data: activityData,
+  },
 ];
 
 // 题型选项

+ 63 - 0
src/views/exercise_questions/preview/ActivityPreview.vue

@@ -0,0 +1,63 @@
+<!-- eslint-disable vue/no-v-html -->
+<template>
+  <div class="activity-preview">
+    <div class="stem">
+      <span class="question-number" :style="{ fontSize: data.property.stem_question_number_font_size }">
+        {{ questionNumberEndIsBracket(data.property.question_number) }}
+      </span>
+      <span v-html="sanitizeHTML(data.stem)"></span>
+    </div>
+    <div
+      v-if="isEnable(data.property.is_enable_description)"
+      class="description rich-text"
+      v-html="sanitizeHTML(data.description)"
+    ></div>
+    <UploadFiles
+      :fille-number="999"
+      file-type-name="文件"
+      upload-type="*"
+      :file-id-list="answer.accessory_file_id_list"
+      :disabled="disabled"
+      @upload="handleUpload"
+      @deleteFile="handleDelete"
+    />
+  </div>
+</template>
+
+<script>
+import UploadFiles from './components/common/UploadFiles.vue';
+
+import PreviewMixin from './components/PreviewMixin';
+
+export default {
+  name: 'ActivityPreview',
+  components: {
+    UploadFiles,
+  },
+  mixins: [PreviewMixin],
+  data() {
+    return {};
+  },
+  created() {
+    this.$set(this.answer, 'accessory_file_id_list', []);
+  },
+  methods: {
+    // 文件上传成功
+    handleUpload(fileId) {
+      this.answer.accessory_file_id_list.push(fileId);
+    },
+    // 删除文件
+    handleDelete(fileId) {
+      this.answer.accessory_file_id_list.splice(this.answer.accessory_file_id_list.indexOf(fileId), 1);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+@use '@/styles/mixin.scss' as *;
+
+.activity-preview {
+  @include preview;
+}
+</style>

+ 18 - 2
src/views/exercise_questions/preview/EssayQuestionPreview.vue

@@ -14,8 +14,8 @@
     ></div>
 
     <el-input
-      class="write-input"
       v-model="answer.answer_list[0].text"
+      class="write-input"
       rows="12"
       resize="none"
       type="textarea"
@@ -23,8 +23,9 @@
       :maxlength="1000"
       show-word-limit
       :readonly="disabled"
-      @input="handleInput"
       :autosize="{ minRows: 12 }"
+      @input="handleInput"
+      @blur="handleTone(answer.answer_list[0].text)"
     />
 
     <div v-if="isEnable(data.property.is_enable_reference_answer) && isShowRightAnswer" class="reference-box">
@@ -37,6 +38,8 @@
 <script>
 import PreviewMixin from './components/PreviewMixin';
 
+import { addTone, handleToneValue } from '@/views/exercise_questions/data/common';
+
 export default {
   name: 'EssayQuestionPreview',
   mixins: [PreviewMixin],
@@ -71,6 +74,19 @@ export default {
         this.$message.warning(`字数达到1000字!`);
       }
     },
+    handleTone(value) {
+      this.answer.answer_list[0].text = value
+        .trim()
+        .split(/\s+/)
+        .map((item) => {
+          return handleToneValue(item);
+        })
+        .map((item) =>
+          item.map(({ number, con }) => (number && con ? addTone(Number(number), con) : number || con || '')),
+        )
+        .filter((item) => item.length > 0)
+        .join(' ');
+    },
   },
 };
 </script>

+ 1 - 2
src/views/exercise_questions/preview/FillPreview.vue

@@ -47,8 +47,7 @@
 <script>
 import PreviewMixin from './components/PreviewMixin';
 
-import { addTone } from '@/views/exercise_questions/data/common';
-import { handleToneValue } from '@/views/exercise_questions/data/fill';
+import { addTone, handleToneValue } from '@/views/exercise_questions/data/common';
 
 export default {
   name: 'FillPreview',

+ 1 - 2
src/views/exercise_questions/preview/ListenFillPreview.vue

@@ -53,8 +53,7 @@
 <script>
 import PreviewMixin from './components/PreviewMixin';
 
-import { addTone } from '@/views/exercise_questions/data/common';
-import { handleToneValue } from '@/views/exercise_questions/data/listenFill';
+import { addTone, handleToneValue } from '@/views/exercise_questions/data/common';
 
 export default {
   name: 'ListenFillPreview',

+ 5 - 5
src/views/exercise_questions/preview/ReadAloudPreview.vue

@@ -20,7 +20,7 @@
       v-html="sanitizeHTML(data.description)"
     ></div>
 
-    <div class="description rich-text" v-html="sanitizeHTML(data.text)"></div>
+    <div class="description rich-text text" v-html="sanitizeHTML(data.text)"></div>
 
     <SoundRecordPreview :wav-blob.sync="answer.answer_list[0].voice_file_id" position="center" />
   </div>
@@ -49,10 +49,10 @@ export default {
 .readaloud-preview {
   @include preview;
 
-  .reference-answer {
-    padding: 12px 24px;
-    background-color: $content-color;
-    border-radius: 8px;
+  .text {
+    :deep p {
+      margin: 0;
+    }
   }
 }
 </style>

+ 6 - 2
src/views/exercise_questions/preview/ReadPreview.vue

@@ -14,7 +14,7 @@
     ></div>
 
     <div class="container">
-      <div class="articel rich-text" v-html="sanitizeHTML(data.article)"></div>
+      <div class="article rich-text" v-html="sanitizeHTML(data.article)"></div>
       <div class="question-list">
         <template v-if="isAnswer">
           <component
@@ -170,11 +170,15 @@ export default {
     flex-direction: column;
     column-gap: 24px;
 
-    .articel {
+    .article {
       padding: 24px 40px;
       color: #2f3742;
       background-color: $content-color;
       border-radius: 16px;
+
+      :deep p {
+        margin: 0;
+      }
     }
 
     .question-list {

+ 40 - 17
src/views/exercise_questions/preview/TableFillPreview.vue

@@ -20,10 +20,10 @@
             v-for="({ text, mark, width }, i) in data.option_header_list"
             :key="mark"
             :style="{
-              borderLeft: isEnable(data.property.is_enable_number_column) || i > 0 ? '1px solid #165dff' : 'none',
+              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}% - 40px)` : `${width}%`,
-              marginLeft: isEnable(data.property.is_enable_number_column) && i === 0 ? '40px' : '0',
+                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"
           >
@@ -52,6 +52,7 @@
                     { cursor: disabled ? 'not-allowed' : 'pointer' },
                     { width: Math.max(80, li.text.length * 12) + 'pt' },
                   ]"
+                  @blur="handleTone(li.text, i, j)"
                 />
               </template>
             </div>
@@ -62,7 +63,7 @@
 
     <div v-if="isEnable(data.property.is_enable_reference_answer) && isShowRightAnswer" class="reference-box">
       <h5 class="reference-title">参考答案</h5>
-      <span class="reference-answer">{{ data.reference_answer }}</span>
+      <div class="reference-answer">{{ data.reference_answer }}</div>
     </div>
   </div>
 </template>
@@ -70,6 +71,8 @@
 <script>
 import PreviewMixin from './components/PreviewMixin';
 
+import { addTone, handleToneValue } from '@/views/exercise_questions/data/common';
+
 export default {
   name: 'TableFillPreview',
   mixins: [PreviewMixin],
@@ -126,14 +129,28 @@ export default {
       });
     },
   },
-  methods: {},
+  methods: {
+    handleTone(value, i, j) {
+      this.optionList[i][j].text = value
+        .trim()
+        .split(/\s+/)
+        .map((item) => {
+          return handleToneValue(item);
+        })
+        .map((item) =>
+          item.map(({ number, con }) => (number && con ? addTone(Number(number), con) : number || con || '')),
+        )
+        .filter((item) => item.length > 0)
+        .join(' ');
+    },
+  },
 };
 </script>
 
 <style lang="scss" scoped>
 @use '@/styles/mixin.scss' as *;
 
-$table-border: 1px solid #ebebeb;
+$table-border: 1px solid #e0e0e0;
 
 .fill-form-preview {
   @include preview;
@@ -142,6 +159,8 @@ $table-border: 1px solid #ebebeb;
     overflow: auto;
 
     .form {
+      border: $table-border;
+
       &-header {
         display: flex;
         font-weight: bold;
@@ -156,22 +175,26 @@ $table-border: 1px solid #ebebeb;
         }
       }
 
-      .form-content:first-child {
-        .form-item {
-          border-top: $table-border;
-        }
+      &-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;
-          border-bottom: $table-border;
-          border-left: $table-border;
 
           .item-content {
             padding: 8px 12px;
@@ -203,7 +226,7 @@ $table-border: 1px solid #ebebeb;
               height: 32px;
               line-height: 28px;
               vertical-align: bottom;
-              border-bottom: 1px solid $font-color;
+              border-bottom: $table-border;
             }
 
             & + .right-answer-content {
@@ -235,10 +258,6 @@ $table-border: 1px solid #ebebeb;
             }
           }
         }
-
-        .form-item:last-child {
-          border-right: $table-border;
-        }
       }
 
       .serial-number {
@@ -265,6 +284,10 @@ $table-border: 1px solid #ebebeb;
       line-height: 32px;
       color: #4e5969;
     }
+
+    .reference-answer {
+      white-space: pre-wrap;
+    }
   }
 }
 </style>

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

@@ -134,7 +134,7 @@ export default {
     .pic-info {
       margin: 0;
 
-      //font-size: 12px;
+      // font-size: 12px;
       font-weight: 400;
       line-height: 20px;
       color: #000;

+ 2 - 2
src/views/exercise_questions/preview/components/common/Strockplayredline.vue

@@ -1,11 +1,11 @@
 <template>
-  <div class="strockplay-redInner" v-if="bookText">
+  <div v-if="bookText" class="strockplay-redInner">
     <div v-if="playStorkes" :class="['strock-play-box']" @click="playHanzi">
       <SvgIcon icon-class="hanzi-strock-play" class="strock-play-btn" />
     </div>
     <div class="character-target-box">
       <SvgIcon icon-class="hanzi-writer-bg" class="character-target-bg" />
-      <div :id="targetDiv" class="character-target-div" :ref="targetDiv"></div>
+      <div :id="targetDiv" :ref="targetDiv" class="character-target-div"></div>
     </div>
   </div>
 </template>