Просмотр исходного кода

1、富文本输入框换行 2、选词填空改为富文本

dsy 3 дней назад
Родитель
Сommit
7955b68a39

+ 1 - 5
src/api/pinyinCorrection.js

@@ -1,7 +1,5 @@
 import { http } from '@/utils/http';
 
-
-
 // 添加拼音校正
 export function toolAddPinyinCorrection(data) {
   return http.post(`${process.env.VUE_APP_EepServer}?MethodName=tool-AddPinyinCorrection`, data);
@@ -19,7 +17,7 @@ export function toolGetCXList() {
 
 // 复制拼音校正到指定库
 export function toolCopyPinyinCorrectionToStorage(data) {
-  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=tool-CopyPinyinCorrectionToStorage`,data);
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=tool-CopyPinyinCorrectionToStorage`, data);
 }
 
 // 编辑拼音校正
@@ -31,5 +29,3 @@ export function toolUpdatePinyinCorrection(data) {
 export function toolGetWordPinyinCorrectionList(data) {
   return http.post(`${process.env.VUE_APP_EepServer}?MethodName=tool-GetWordPinyinCorrectionList`, data);
 }
-
-

+ 12 - 0
src/utils/common.js

@@ -166,3 +166,15 @@ export function getScrollbarWidth() {
   document.body.removeChild(el);
   return width;
 }
+
+/**
+ * 将富文本内容转换为纯文本
+ * @param {string} html 富文本内容
+ * @returns {string} 纯文本内容
+ */
+export function getPlainText(html) {
+  if (typeof html !== 'string') return '';
+  const parser = new DOMParser();
+  const doc = parser.parseFromString(html, 'text/html');
+  return doc.body.textContent || '';
+}

+ 51 - 23
src/views/book/courseware/create/components/question/fill/Fill.vue

@@ -1,3 +1,4 @@
+<!-- eslint-disable vue/no-v-html -->
 <template>
   <ModuleBase ref="base" :type="data.type">
     <template #content>
@@ -14,14 +15,13 @@
           :font-family="data?.unified_attrib?.font"
           :font-color="data?.unified_attrib?.text_color"
         />
-        <el-input
-          v-if="data.property.fill_type === fillTypeList[1].value"
-          v-model="data.vocabulary"
-          type="textarea"
-          :autosize="{ minRows: 2, maxRows: 4 }"
-          resize="none"
-          placeholder="请输入词汇,用于选词填空"
-        />
+        <div v-if="data.property.fill_type === fillTypeList[1].value" class="select-vocabulary">
+          <h5 class="title">选词列表:</h5>
+          <el-button size="mini" @click="openAddWord">添加词汇</el-button>
+          <ul class="word-list">
+            <li v-for="item in data.word_list" :key="item.mark" v-html="sanitizeHTML(item.content)"></li>
+          </ul>
+        </div>
 
         <span class="tips">在需要加空的内容处插入 3 个或以上的下划线“_”。</span>
         <div v-if="data.audio_file_id">
@@ -95,6 +95,7 @@
         @updateAnswerAnalysisFileList="updateAnswerAnalysisFileList"
         @deleteAnswerAnalysis="deleteAnswerAnalysis"
       />
+      <AddWord :visible.sync="visibleWord" @add-word="addWord" />
     </template>
   </ModuleBase>
 </template>
@@ -104,11 +105,13 @@ import ModuleMixin from '../../common/ModuleMixin';
 import SoundRecord from '@/views/book/courseware/create/components/question/fill/components/SoundRecord.vue';
 import UploadAudio from '@/views/book/courseware/create/components/question/fill/components/UploadAudio.vue';
 import PinyinText from '@/components/PinyinText.vue';
+import AddWord from './components/AddWord.vue';
 
 import { getFillData, arrangeTypeList, fillFontList, fillTypeList } from '@/views/book/courseware/data/fill';
 import { addTone, handleToneValue } from '@/views/book/courseware/data/common';
 import { getRandomNumber } from '@/utils';
 import { TextToAudioFile } from '@/api/app';
+import { sanitizeHTML } from '@/utils/common';
 
 export default {
   name: 'FillPage',
@@ -116,32 +119,20 @@ export default {
     SoundRecord,
     UploadAudio,
     PinyinText,
+    AddWord,
   },
   mixins: [ModuleMixin],
   data() {
     return {
       data: getFillData(),
       fillTypeList,
+      sanitizeHTML,
+      visibleWord: false,
     };
   },
   watch: {
     'data.property.arrange_type': 'handleMindMap',
     'data.property.fill_font': 'handleMindMap',
-    'data.vocabulary': {
-      handler(val) {
-        if (!val) return;
-        this.data.word_list = val
-          .split(/[\n\r]+/)
-          .map((item) => item.split(/\s+/).filter((s) => s))
-          .flat()
-          .map((content) => {
-            return {
-              content,
-              mark: getRandomNumber(),
-            };
-          });
-      },
-    },
     'data.property': {
       handler() {
         this.handleViewPinyin();
@@ -332,6 +323,20 @@ export default {
         });
       });
     },
+    openAddWord() {
+      this.visibleWord = true;
+    },
+    /**
+     * 添加词汇
+     * @param {string} word 词汇内容
+     */
+    addWord(word) {
+      if (!word) return;
+      this.data.word_list.push({
+        content: word,
+        mark: getRandomNumber(),
+      });
+    },
   },
 };
 </script>
@@ -347,6 +352,29 @@ export default {
     width: 100%;
   }
 
+  .select-vocabulary {
+    .title {
+      margin: 0 0 8px;
+    }
+
+    .word-list {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 8px;
+      margin-top: 8px;
+
+      li {
+        padding: 4px 6px;
+        border: $border;
+        border-radius: 4px;
+
+        :deep p {
+          margin: 0;
+        }
+      }
+    }
+  }
+
   .tips {
     font-size: 12px;
     color: #999;

+ 62 - 0
src/views/book/courseware/create/components/question/fill/components/AddWord.vue

@@ -0,0 +1,62 @@
+<template>
+  <el-dialog
+    :visible="visible"
+    title="添加词汇"
+    custom-class="add-word"
+    width="740px"
+    :close-on-click-modal="false"
+    @close="closeDialog"
+  >
+    <RichText
+      v-if="visible"
+      v-model="content"
+      toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
+      :wordlimit-num="false"
+      placeholder="请输入词汇"
+    />
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="closeDialog">取 消</el-button>
+      <el-button type="primary" @click="addWord">确 定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import RichText from '@/components/RichText';
+
+export default {
+  name: 'AddWord',
+  components: {
+    RichText,
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      content: '',
+    };
+  },
+  watch: {
+    visible(newVal) {
+      if (!newVal) {
+        this.content = '';
+      }
+    },
+  },
+  methods: {
+    closeDialog() {
+      this.$emit('update:visible', false);
+    },
+    addWord() {
+      this.$emit('add-word', this.content);
+      this.closeDialog();
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 17 - 13
src/views/book/courseware/preview/components/fill/FillPreview.vue

@@ -29,9 +29,12 @@
                 <el-input
                   :key="j"
                   v-model="li.content"
+                  type="textarea"
+                  :autosize="{ minRows: 1, maxRows: 5 }"
+                  resize="none"
                   :disabled="disabled"
                   :class="[data.property.fill_font, ...computedAnswerClass(li.mark)]"
-                  :style="[{ width: Math.max(data.property.input_default_width, li.content.length * 21.3) + 'px' }]"
+                  :style="[{ width: data.property.input_default_width + 'px' }]"
                 />
               </template>
 
@@ -43,8 +46,8 @@
                       :key="mark"
                       class="word-item"
                       @click="handleSelectWord(content, mark, li)"
+                      v-html="sanitizeHTML(content)"
                     >
-                      {{ content }}
                     </span>
                   </div>
 
@@ -54,7 +57,7 @@
                     :readonly="true"
                     :class="[data.property.fill_font, ...computedAnswerClass(li.mark)]"
                     class="pinyin"
-                    :style="[{ width: Math.max(data.property.input_default_width, li.content.length * 21.3) + 'px' }]"
+                    :style="[{ width: data.property.input_default_width + 'px' }]"
                   />
                 </el-popover>
               </template>
@@ -139,6 +142,12 @@
 </template>
 
 <script>
+import PreviewMixin from '../common/PreviewMixin';
+import AudioFill from './components/AudioFillPlay.vue';
+import SoundRecord from '../../common/SoundRecord.vue';
+import SoundRecordBox from '@/views/book/courseware/preview/components/record_input/SoundRecord.vue';
+import WriteDialog from './components/WriteDialog.vue';
+
 import {
   getFillData,
   fillFontList,
@@ -146,12 +155,7 @@ import {
   arrangeTypeList,
   audioPositionList,
 } from '@/views/book/courseware/data/fill';
-
-import PreviewMixin from '../common/PreviewMixin';
-import AudioFill from './components/AudioFillPlay.vue';
-import SoundRecord from '../../common/SoundRecord.vue';
-import SoundRecordBox from '@/views/book/courseware/preview/components/record_input/SoundRecord.vue';
-import WriteDialog from './components/WriteDialog.vue';
+import { getPlainText } from '@/utils/common';
 
 export default {
   name: 'FillPreview',
@@ -281,7 +285,7 @@ export default {
     handleSelectWord(content, mark, li) {
       if (!content || !mark || !li) return;
 
-      li.content = content;
+      li.content = getPlainText(content);
       this.selectedWordList.push(mark);
     },
     /**
@@ -464,7 +468,7 @@ export default {
       }
     }
 
-    .el-input {
+    .el-textarea {
       display: inline-flex;
       align-items: center;
       width: 120px;
@@ -495,11 +499,11 @@ export default {
         }
       }
 
-      :deep input.el-input__inner {
+      :deep .el-textarea__inner {
         padding: 0;
         font-size: 16pt;
         color: $font-color;
-        text-align: center;
+        text-align: left;
         background-color: #fff;
         border-width: 0;
         border-bottom: 1px solid $font-color;