|
@@ -1,49 +1,307 @@
|
|
|
<template>
|
|
|
<ModuleBase :type="data.type">
|
|
|
<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>
|
|
|
</ModuleBase>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
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 {
|
|
|
- name: 'RecordInputPage',
|
|
|
- components: {},
|
|
|
+ name: 'NewWordPage',
|
|
|
+ components: {
|
|
|
+ SelectUpload,
|
|
|
+ SoundRecord,
|
|
|
+ UploadAudio,
|
|
|
+ },
|
|
|
mixins: [ModuleMixin],
|
|
|
data() {
|
|
|
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>
|
|
|
+<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>
|