Browse Source

生词组件

natasha 1 year ago
parent
commit
bc08923f7c

+ 3 - 0
src/views/book/courseware/create/components/base/common/UploadFile.vue

@@ -200,6 +200,9 @@ export default {
       } else if (this.type === 'video') {
       } else if (this.type === 'video') {
         fileType = ['mp4'];
         fileType = ['mp4'];
         typeTip = '视频文件只能是 mp4 格式!';
         typeTip = '视频文件只能是 mp4 格式!';
+      } else if (this.type === 'upload_preview') {
+        fileType = ['png', 'jpg', 'pdf'];
+        typeTip = '文件只能是图片或者pdf';
       }
       }
       const isNeedType = fileType.includes(suffix);
       const isNeedType = fileType.includes(suffix);
       if (!isNeedType) {
       if (!isNeedType) {

+ 6 - 2
src/views/book/courseware/create/components/question/fill/components/UploadAudio.vue

@@ -37,6 +37,10 @@ export default {
       type: Boolean,
       type: Boolean,
       default: true,
       default: true,
     },
     },
+    itemIndex: {
+      type: Number,
+      default: null,
+    },
   },
   },
   data() {
   data() {
     return {
     return {
@@ -79,7 +83,7 @@ export default {
           this.file_id = file_id;
           this.file_id = file_id;
           this.file_url = file_url;
           this.file_url = file_url;
           this.file_name = file_name;
           this.file_name = file_name;
-          this.$emit('upload', file_id);
+          this.$emit('upload', file_id, this.itemIndex);
         }
         }
       });
       });
     },
     },
@@ -93,7 +97,7 @@ export default {
         type: 'warning',
         type: 'warning',
       })
       })
         .then(() => {
         .then(() => {
-          this.$emit('deleteFile', this.file_id);
+          this.$emit('deleteFile', this.file_id, this.itemIndex);
           this.file_id = '';
           this.file_id = '';
           this.file_url = '';
           this.file_url = '';
           this.file_name = '';
           this.file_name = '';

+ 288 - 30
src/views/book/courseware/create/components/question/new_word/NewWord.vue

@@ -1,49 +1,307 @@
 <template>
 <template>
   <ModuleBase :type="data.type">
   <ModuleBase :type="data.type">
     <template #content>
     <template #content>
-      <el-form :model="data" label-width="72px" label-position="left">
-        <el-form-item label="控件规格">
-          <el-radio-group v-model="data.size">
-            <el-radio v-for="{ value, label } in sizeList" :key="value" :label="value">
-              {{ label }}
-            </el-radio>
-          </el-radio-group>
-        </el-form-item>
-        <el-form-item label="录音评分">
-          <el-radio-group v-model="data.is_enable_score">
-            <el-radio v-for="{ value, label } in switchOption" :key="value" :label="value">
-              {{ label }}
-            </el-radio>
-          </el-radio-group>
-        </el-form-item>
-        <el-form-item label="输入">
-          <el-radio-group v-model="data.is_enable_input">
-            <el-radio v-for="{ value, label } in switchOption" :key="value" :label="value">
-              {{ label }}
-            </el-radio>
-          </el-radio-group>
-        </el-form-item>
-      </el-form>
+      <el-table :data="data.option" border style="width: 100%">
+        <el-table-column fixed prop="number" label="序号" width="70">
+          <template slot-scope="scope">
+            <el-input v-model="scope.row.number"></el-input>
+          </template>
+        </el-table-column>
+        <el-table-column fixed prop="new_word" label="生词/短语" width="110">
+          <template slot-scope="scope">
+            <RichText
+              v-model="scope.row.new_word"
+              :inline="true"
+              toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column prop="mp3_list" label="读音" width="200">
+          <template slot-scope="scope">
+            <div v-if="scope.row.mp3_list">
+              <SoundRecord :wav-blob.sync="scope.row.mp3_list" />
+            </div>
+            <template v-else>
+              <div :class="['upload-audio-play']">
+                <UploadAudio
+                  v-if="data.property.audio_generation_method === 'upload'"
+                  :file-id="scope.row.mp3_list"
+                  :item-index="scope.$index"
+                  :show-upload="!scope.row.mp3_list"
+                  @upload="uploads"
+                  @deleteFile="deleteFiles"
+                />
+                <div
+                  v-else-if="data.property.audio_generation_method === 'auto'"
+                  class="auto-matic"
+                  @click="handleMatic(scope.$index)"
+                >
+                  <SvgIcon icon-class="voiceprint-line" class="record" />
+                  <span class="auto-btn">{{ scope.row.mp3_list ? '已生成' : '生成音频' }}</span
+                  >{{ scope.row.mp3_list ? '成功' : '' }}
+                </div>
+                <SoundRecord v-else :wav-blob.sync="scope.row.mp3_list" />
+              </div>
+            </template>
+          </template>
+        </el-table-column>
+        <el-table-column prop="pinyin" label="拼音" width="110">
+          <template slot-scope="scope">
+            <RichText
+              v-model="scope.row.pinyin"
+              :inline="true"
+              toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column prop="cixing" label="词性" width="110">
+          <template slot-scope="scope">
+            <RichText
+              v-model="scope.row.cixing"
+              :inline="true"
+              toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column prop="definition_list" label="释义" width="200">
+          <template slot-scope="scope">
+            <RichText
+              v-model="scope.row.definition_list"
+              :inline="true"
+              :placeholder="'多个释义用;隔开'"
+              toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column prop="collocation" label="搭配" width="200">
+          <template slot-scope="scope">
+            <RichText
+              v-model="scope.row.collocation"
+              :inline="true"
+              toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column prop="liju_list" label="例句" width="300">
+          <template slot-scope="scope">
+            <RichText
+              v-model="scope.row.liju_list"
+              :inline="true"
+              :placeholder="'多条例句用回车'"
+              toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column fixed="right" label="操作" width="150">
+          <template slot-scope="scope">
+            <el-button size="mini" type="text" @click="handleDelete(scope.$index)">删除</el-button>
+            <el-button size="mini" type="text" @click="moveElement(scope.row, scope.$index, 'up')">上移</el-button>
+            <el-button size="mini" type="text" @click="moveElement(scope.row, scope.$index, 'down')">下移</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-button icon="el-icon-plus" style="margin: 24px 0" @click="addElement">增加一个</el-button>
+      <SelectUpload label="生词音频" type="audio" width="500px" @uploadSuccess="uploadAudioSuccess" />
+      <div v-if="data.audio_data.url.length > 0" class="upload-file">
+        <div class="file-name">
+          <span>
+            <SvgIcon icon-class="note" size="12" />
+            <span>{{ data.audio_data.name }}</span>
+          </span>
+        </div>
+        <SvgIcon icon-class="delete-black" size="12" @click="removeFile('audio')" />
+      </div>
+      <SelectUpload label="lrc 文件" :limit="1" type="lrc" width="500px" @uploadSuccess="uploadLrcSuccess" />
+      <div v-if="data.lrc_data.url.length > 0" class="upload-file">
+        <div class="file-name">
+          <span>
+            <SvgIcon icon-class="note" size="12" />
+            <span>{{ data.lrc_data.name }}</span>
+          </span>
+        </div>
+        <SvgIcon icon-class="delete-black" size="12" @click="removeFile('lrc')" />
+      </div>
     </template>
     </template>
   </ModuleBase>
   </ModuleBase>
 </template>
 </template>
 
 
 <script>
 <script>
 import ModuleMixin from '../../common/ModuleMixin';
 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 { getRecordInputData, sizeList, switchOption } from '@/views/book/courseware/data/recordInput';
+import { getNewWordData, getOption } from '@/views/book/courseware/data/newWord';
+import SelectUpload from '@/views/book/courseware/create/components/common/SelectUpload.vue';
+import { GetStaticResources } from '@/api/app';
 
 
 export default {
 export default {
-  name: 'RecordInputPage',
-  components: {},
+  name: 'NewWordPage',
+  components: {
+    SelectUpload,
+    SoundRecord,
+    UploadAudio,
+  },
   mixins: [ModuleMixin],
   mixins: [ModuleMixin],
   data() {
   data() {
     return {
     return {
-      data: getRecordInputData(),
-      sizeList,
-      switchOption,
+      data: getNewWordData(),
     };
     };
   },
   },
-  methods: {},
+  methods: {
+    /**
+     * 解析lrc文件
+     */
+    parseLrcFile() {
+      if (this.data.lrc_data.file_id.length === 0) {
+        return this.$message.warning('请先上传lrc文件');
+      }
+      const loading = this.$loading({ text: '解析lrc文件中' });
+      GetStaticResources('tool-ParseLRCFile', {
+        content_type: 'FILE',
+        file_id: this.data.lrc_data.file_id,
+      }).then(({ lrc_list }) => {
+        this.data.lrc_arr = lrc_list;
+        this.distribution();
+        loading.close();
+      });
+    },
+    /**
+     * 分配标记
+     */
+    distribution() {
+      const lrcArr = this.data.lrc_arr;
+      if (lrcArr.length === 0) {
+        return this.$message.warning('没有标记可分配');
+      }
+      let curIndex = 0;
+      this.data.option_list.forEach((row) => {
+        row.forEach((item, i) => {
+          const lrcData = lrcArr[curIndex];
+          if (lrcData) {
+            row[i].lrc_data = lrcData;
+            curIndex += 1;
+          }
+        });
+      });
+    },
+    uploadLrcSuccess(fileList) {
+      if (fileList.length > 0) {
+        const { file_name: name, file_url: url, file_id } = fileList[0];
+        this.data.lrc_data = {
+          name,
+          url,
+          id: `[FID##${file_id}##FID]`,
+          file_id,
+        };
+        this.parseLrcFile();
+      }
+    },
+    uploadAudioSuccess(fileList) {
+      if (fileList.length > 0) {
+        const { file_name: name, file_url: temporary_url, file_id, media_duration } = fileList[0];
+        this.data.audio_data = {
+          name,
+          media_duration,
+          temporary_url,
+          url: `[FID##${file_id}##FID]`,
+          file_id,
+        };
+      }
+    },
+    /**
+     * 删除文件
+     * @param {'audio' | 'lrc'} type
+     */
+    removeFile(type) {
+      if (type === 'audio') {
+        this.data.audio_data = {
+          name: '',
+          media_duration: 0,
+          temporary_url: '',
+          url: '',
+          file_id: '',
+        };
+      } else if (type === 'lrc') {
+        this.data.lrc_data = {
+          name: '',
+          url: '',
+          id: '',
+          file_id: '',
+        };
+      }
+    },
+    uploads(file_id, index) {
+      this.data.option[index].mp3_list = file_id;
+    },
+    deleteFiles(file_id, index) {
+      this.data.option[index].mp3_list = '';
+    },
+    // 自动生成音频
+    handleMatic(index) {
+      GetStaticResources('tool-TextToVoiceFile', {
+        text: this.data.content.replace(/<[^>]+>/g, ''),
+      })
+        .then(({ status, file_id }) => {
+          if (status === 1) {
+            this.data.option[index].mp3_list = file_id;
+          }
+        })
+        .catch(() => {});
+    },
+    // 删除行
+    handleDelete(index) {
+      this.data.option.splice(index, 1);
+    },
+    // 上移下移
+    moveElement(dItem, index, type) {
+      let obj = JSON.parse(JSON.stringify(dItem));
+      if (type == 'up' && index > 0) {
+        this.data.option.splice(index - 1, 0, obj);
+        this.data.option.splice(index + 1, 1);
+      }
+      if (type == 'down' && index < this.data.option.length - 1) {
+        this.data.option[index] = this.data.option.splice(index + 1, 1, this.data.option[index])[0];
+      }
+    },
+    // 增加
+    addElement() {
+      this.data.option.push(getOption());
+    },
+  },
 };
 };
 </script>
 </script>
+<style lang="scss" scoped>
+.upload-file {
+  display: flex;
+  column-gap: 12px;
+  align-items: center;
+  margin: 8px 0;
+
+  .file-name {
+    display: flex;
+    column-gap: 14px;
+    align-items: center;
+    justify-content: space-between;
+    max-width: 360px;
+    padding: 8px 12px;
+    font-size: 14px;
+    color: #1d2129;
+    background-color: #f7f8fa;
+
+    span {
+      display: flex;
+      column-gap: 14px;
+      align-items: center;
+    }
+  }
+
+  .svg-icon {
+    cursor: pointer;
+  }
+}
+</style>
+<style lang="scss">
+.tox .tox-editor-header {
+  z-index: 3;
+}
+</style>

+ 19 - 12
src/views/book/courseware/create/components/question/new_word/NewWordSetting.vue

@@ -2,6 +2,19 @@
   <div>
   <div>
     <el-form :model="property" label-width="72px" label-position="left">
     <el-form :model="property" label-width="72px" label-position="left">
       <SerailNumber :property="property" />
       <SerailNumber :property="property" />
+      <el-form-item label="读音">
+        <el-select v-model="property.audio_generation_method" placeholder="请选择">
+          <el-option v-for="{ value, label } in audioGenerationMethodList" :key="value" :label="label" :value="value" />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="拼音位置">
+        <el-radio-group v-model="property.pinyin_position">
+          <el-radio v-for="{ value, label } in pinyinPositionList" :key="value" :label="value">
+            {{ label }}
+          </el-radio>
+        </el-radio-group>
+      </el-form-item>
     </el-form>
     </el-form>
   </div>
   </div>
 </template>
 </template>
@@ -10,25 +23,19 @@
 import SettingMixin from '@/views/book/courseware/create/components/common/SettingMixin';
 import SettingMixin from '@/views/book/courseware/create/components/common/SettingMixin';
 
 
 import {
 import {
-  getRecordInputProperty,
-  arrangeTypeList,
-  audioPositionList,
+  getNewWordProperty,
   audioGenerationMethodList,
   audioGenerationMethodList,
-  fillFontList,
-  switchOption,
-} from '@/views/book/courseware/data/recordInput';
+  pinyinPositionList,
+} from '@/views/book/courseware/data/newWord';
 
 
 export default {
 export default {
-  name: 'RecordInputSetting',
+  name: 'NewWordSetting',
   mixins: [SettingMixin],
   mixins: [SettingMixin],
   data() {
   data() {
     return {
     return {
-      property: getRecordInputProperty(),
-      arrangeTypeList,
-      audioPositionList,
+      property: getNewWordProperty(),
       audioGenerationMethodList,
       audioGenerationMethodList,
-      fillFontList,
-      switchOption,
+      pinyinPositionList,
     };
     };
   },
   },
   methods: {},
   methods: {},

+ 1 - 1
src/views/book/courseware/create/components/question/write/Write.vue

@@ -11,7 +11,7 @@
           <UploadFile
           <UploadFile
             :courseware-id="courseware_id"
             :courseware-id="courseware_id"
             :component-id="id"
             :component-id="id"
-            :type="data.type"
+            :type="'picture'"
             :single-size="data.single_size"
             :single-size="data.single_size"
             :total-size="data.total_size"
             :total-size="data.total_size"
             :file-list="data.file_list"
             :file-list="data.file_list"

+ 6 - 3
src/views/book/courseware/data/bookType.js

@@ -38,6 +38,8 @@ import Character from '../create/components/question/character/Character.vue';
 import CharacterSetting from '../create/components/question/character/CharacterSetting.vue';
 import CharacterSetting from '../create/components/question/character/CharacterSetting.vue';
 import Write from '../create/components/question/write/Write.vue';
 import Write from '../create/components/question/write/Write.vue';
 import WriteSetting from '../create/components/question/write/WriteSetting.vue';
 import WriteSetting from '../create/components/question/write/WriteSetting.vue';
+import NewWord from '../create/components/question/new_word/NewWord.vue';
+import NewWordSetting from '../create/components/question/new_word/NewWordSetting.vue';
 
 
 import AudioPreview from '@/views/book/courseware/preview/components/audio/AudioPreview.vue';
 import AudioPreview from '@/views/book/courseware/preview/components/audio/AudioPreview.vue';
 import DividerPreview from '@/views/book/courseware/preview/components/divider/DividerPreview.vue';
 import DividerPreview from '@/views/book/courseware/preview/components/divider/DividerPreview.vue';
@@ -59,6 +61,7 @@ import PinyinBasePreview from '../preview/components/pinyin_base/PinyinBasePrevi
 import CharacterBasePreview from '../preview/components/character_base/CharacterBasePreview.vue';
 import CharacterBasePreview from '../preview/components/character_base/CharacterBasePreview.vue';
 import CharacterPreview from '../preview/components/character/CharacterPreview.vue';
 import CharacterPreview from '../preview/components/character/CharacterPreview.vue';
 import WritePreview from '../preview/components/write/WritePreview.vue';
 import WritePreview from '../preview/components/write/WritePreview.vue';
+import NewWordPreview from '../preview/components/new_word/NewWordPreview.vue';
 
 
 export const bookTypeOption = [
 export const bookTypeOption = [
   {
   {
@@ -220,9 +223,9 @@ export const bookTypeOption = [
         value: 'new_word',
         value: 'new_word',
         label: '生词组件',
         label: '生词组件',
         icon: '',
         icon: '',
-        component: RecordInput,
-        set: RecordInputSetting,
-        preview: RecordInputPreview,
+        component: NewWord,
+        set: NewWordSetting,
+        preview: NewWordPreview,
       },
       },
       {
       {
         value: 'character',
         value: 'character',

+ 87 - 0
src/views/book/courseware/data/newWord.js

@@ -0,0 +1,87 @@
+import {
+  displayList,
+  serialNumberTypeList,
+  serialNumberPositionList,
+  arrangeTypeList,
+  switchOption,
+  isEnable,
+} from '@/views/book/courseware/data/common';
+
+export { arrangeTypeList, switchOption, isEnable };
+  
+// 拼音位置
+export const pinyinPositionList = [
+  { value: 'front', label: '前面' },
+  { value: 'back', label: '后面' },
+  { value: 'top', label: '上面' },
+  { value: 'bottom', label: '下面' },
+];
+  
+// 读音生成方式
+export const audioGenerationMethodList = [
+  {
+    value: 'upload',
+    label: '上传',
+  },
+  {
+    value: 'auto',
+    label: '自动生成',
+  },
+  {
+    value: 'record',
+    label: '录音',
+  },
+];
+
+export function getOption() {
+  return {
+    number:'',
+    new_word: "",
+    cixing: "", //词性
+    definition_list: "", //需要增加词性
+    pinyin: "",
+    mp3_list: '',
+    collocation: '', // 搭配
+    liju_list: '', // 例句
+  }
+}
+export function getNewWordProperty() {
+  return {
+    serial_number: 1,
+    sn_type: serialNumberTypeList[0].value,
+    sn_position: serialNumberPositionList[0].value,
+    sn_display_mode: displayList[0].value,
+    audio_generation_method: audioGenerationMethodList[0].value,
+    pinyin_position: pinyinPositionList[0].value
+  };
+}
+
+export function getNewWordData() {
+  return {
+    type: 'new_word',
+    title: '生词组件',
+    property: getNewWordProperty(),
+    option: [
+      getOption()
+    ],
+    lrc_arr: [], // lrc 文件解析后的数据
+    // lrc 文件数据
+    lrc_data: {
+      name: '',
+      url: '',
+      id: '',
+      file_id: '',
+    },
+    // 音频文件数据
+    audio_data: {
+      name: '',
+      media_duration: 0,
+      temporary_url: '',
+      url: '',
+      file_id: '',
+    },
+    answer: {
+      answer_list: [],
+    },
+  };
+}

+ 34 - 34
src/views/book/courseware/preview/components/character/CharacterPreview.vue

@@ -37,43 +37,43 @@ export default {
     },
     },
   },
   },
   created() {
   created() {
-    this.answer.answer_list = this.data.model_essay
-      .map((item) => {
-        return item
-          .map(({ type, content, mark }) => {
-            if (type === 'input') {
-              return {
-                value: content,
-                mark,
-              };
-            }
-          })
-          .filter((item) => item);
-      })
-      .flat();
+    // this.answer.answer_list = this.data.model_essay
+    //   .map((item) => {
+    //     return item
+    //       .map(({ type, content, mark }) => {
+    //         if (type === 'input') {
+    //           return {
+    //             value: content,
+    //             mark,
+    //           };
+    //         }
+    //       })
+    //       .filter((item) => item);
+    //   })
+    //   .flat();
   },
   },
   methods: {
   methods: {
     getMainStyle() {
     getMainStyle() {
-      const isRow = this.data.property.arrange_type === arrangeTypeList[0].value;
-      const isFront = this.data.property.audio_position === audioPositionList[0].value;
-      const isEnableVoice = this.data.property.is_enable_voice_answer === 'true';
-      let _list = [
-        { name: 'audio', value: '24px' },
-        { name: 'fill', value: '1fr' },
-      ];
-      if (!isFront) {
-        _list = _list.reverse();
-      }
-      let grid = isRow
-        ? `"${_list[0].name} ${_list[1].name}${isEnableVoice ? ' record' : ''}" auto / ${_list[0].value} ${_list[1].value}${isEnableVoice ? ' 160px' : ''}`
-        : `"${_list[0].name}" ${_list[0].value} "${_list[1].name}" ${_list[1].value}${isEnableVoice ? `" record" 32px ` : ''} / 1fr`;
-      let style = {
-        'grid-auto-flow': isRow ? 'column' : 'row',
-        'column-gap': isRow ? '16px' : undefined,
-        'row-gap': isRow ? undefined : '8px',
-        grid,
-      };
-      return style;
+      // const isRow = this.data.property.arrange_type === arrangeTypeList[0].value;
+      // const isFront = this.data.property.audio_position === audioPositionList[0].value;
+      // const isEnableVoice = this.data.property.is_enable_voice_answer === 'true';
+      // let _list = [
+      //   { name: 'audio', value: '24px' },
+      //   { name: 'fill', value: '1fr' },
+      // ];
+      // if (!isFront) {
+      //   _list = _list.reverse();
+      // }
+      // let grid = isRow
+      //   ? `"${_list[0].name} ${_list[1].name}${isEnableVoice ? ' record' : ''}" auto / ${_list[0].value} ${_list[1].value}${isEnableVoice ? ' 160px' : ''}`
+      //   : `"${_list[0].name}" ${_list[0].value} "${_list[1].name}" ${_list[1].value}${isEnableVoice ? `" record" 32px ` : ''} / 1fr`;
+      // let style = {
+      //   'grid-auto-flow': isRow ? 'column' : 'row',
+      //   'column-gap': isRow ? '16px' : undefined,
+      //   'row-gap': isRow ? undefined : '8px',
+      //   grid,
+      // };
+      // return style;
     },
     },
   },
   },
 };
 };

+ 109 - 0
src/views/book/courseware/preview/components/new_word/NewWordPreview.vue

@@ -0,0 +1,109 @@
+<!-- eslint-disable vue/no-v-html -->
+<template>
+  <div class="select-preview" :style="getAreaStyle()">
+    <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
+
+    <div class="main">预览开发中</div>
+  </div>
+</template>
+
+<script>
+import { getNewWordData } from '@/views/book/courseware/data/newWord';
+
+import PreviewMixin from '../common/PreviewMixin';
+import AudioFill from '../fill/components/AudioFillPlay.vue';
+import SoundRecord from '../../common/SoundRecord.vue';
+
+export default {
+  name: 'NewWordPreview',
+  components: {
+    AudioFill,
+    SoundRecord,
+  },
+  mixins: [PreviewMixin],
+  data() {
+    return {
+      data: getNewWordData(),
+    };
+  },
+  computed: {},
+  created() {
+    // this.answer.answer_list = this.data.model_essay
+    //   .map((item) => {
+    //     return item
+    //       .map(({ type, content, mark }) => {
+    //         if (type === 'input') {
+    //           return {
+    //             value: content,
+    //             mark,
+    //           };
+    //         }
+    //       })
+    //       .filter((item) => item);
+    //   })
+    //   .flat();
+  },
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped>
+@use '@/styles/mixin.scss' as *;
+
+.select-preview {
+  @include preview-base;
+
+  .main {
+    display: grid;
+    align-items: center;
+  }
+
+  .fill-wrapper {
+    grid-area: fill;
+    font-size: 16pt;
+
+    p {
+      margin: 0;
+    }
+
+    .el-input {
+      display: inline-flex;
+      align-items: center;
+      width: 120px;
+      margin: 0 2px;
+
+      &.pinyin :deep input.el-input__inner {
+        font-family: 'PINYIN-B', sans-serif;
+      }
+
+      &.chinese :deep input.el-input__inner {
+        font-family: 'arial', sans-serif;
+      }
+
+      &.english :deep input.el-input__inner {
+        font-family: 'arial', sans-serif;
+      }
+
+      :deep input.el-input__inner {
+        padding: 0;
+        font-size: 16pt;
+        color: $font-color;
+        text-align: center;
+        background-color: #fff;
+        border-width: 0;
+        border-bottom: 1px solid $font-color;
+        border-radius: 0;
+      }
+    }
+  }
+
+  .record-box {
+    padding: 6px 12px;
+    background-color: $fill-color;
+
+    :deep .record-time {
+      width: 100px;
+    }
+  }
+}
+</style>