|
@@ -0,0 +1,348 @@
|
|
|
+<template>
|
|
|
+ <ModuleBase :type="data.type">
|
|
|
+ <template #content>
|
|
|
+ <div style="text-align: left">
|
|
|
+ <label>标题:</label>
|
|
|
+ <RichText
|
|
|
+ v-model="data.title_con"
|
|
|
+ :inline="true"
|
|
|
+ :placeholder="'输入标题'"
|
|
|
+ toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <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">
|
|
|
+ <el-input v-model="scope.row.new_word" @blur="handleBlurCon(scope.row)"></el-input>
|
|
|
+ </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">
|
|
|
+ <el-input v-model="scope.row.pinyin"></el-input>
|
|
|
+ </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 prop="header_con" label="页眉" width="100">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-input v-model="scope.row.header_con"></el-input>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="label" label="标签" width="100">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-input v-model="scope.row.label"></el-input>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column 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 { getNewWordData, getOption } from '@/views/book/courseware/data/newWord';
|
|
|
+import SelectUpload from '@/views/book/courseware/create/components/common/SelectUpload.vue';
|
|
|
+import { GetStaticResources } from '@/api/app';
|
|
|
+import cnchar from 'cnchar';
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'NewWordPage',
|
|
|
+ components: {
|
|
|
+ SelectUpload,
|
|
|
+ SoundRecord,
|
|
|
+ UploadAudio,
|
|
|
+ },
|
|
|
+ mixins: [ModuleMixin],
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ data: getNewWordData(),
|
|
|
+ };
|
|
|
+ },
|
|
|
+ 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 }) => {
|
|
|
+ let lrc_list_res = [];
|
|
|
+ lrc_list.forEach((item) => {
|
|
|
+ let obj = {
|
|
|
+ bg: item.begin_time,
|
|
|
+ ed: item.end_time,
|
|
|
+ };
|
|
|
+ lrc_list_res.push(obj);
|
|
|
+ });
|
|
|
+ this.data.lrc_arr = lrc_list_res;
|
|
|
+ loading.close();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ uploadLrcSuccess(fileList) {
|
|
|
+ if (fileList.length > 0) {
|
|
|
+ const { file_name: name, file_url: url, file_id } = fileList[0];
|
|
|
+ this.data.lrc_data = {
|
|
|
+ name,
|
|
|
+ url,
|
|
|
+ id: file_id,
|
|
|
+ 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: file_id,
|
|
|
+ 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: '',
|
|
|
+ };
|
|
|
+ }
|
|
|
+ this.data.lrc_arr = [];
|
|
|
+ },
|
|
|
+ uploads(file_id, index) {
|
|
|
+ this.data.option[index].mp3_list = file_id;
|
|
|
+ },
|
|
|
+ deleteFiles(file_id, index) {
|
|
|
+ this.data.option[index].mp3_list = '';
|
|
|
+ },
|
|
|
+ uploadPic(file_id, index) {
|
|
|
+ this.data.option[index].file_list[0] = file_id;
|
|
|
+ },
|
|
|
+ deletePic(file_id, index) {
|
|
|
+ this.data.option[index].file_list[0] = '';
|
|
|
+ },
|
|
|
+ // 自动生成音频
|
|
|
+ handleMatic(index) {
|
|
|
+ GetStaticResources('tool-TextToVoiceFile', {
|
|
|
+ text: this.data.option[index].new_word.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());
|
|
|
+ },
|
|
|
+ // 获取数据
|
|
|
+ handleBlurCon(row) {
|
|
|
+ let cons = row.new_word.trim();
|
|
|
+ let MethodName = 'hz_resource_manager-GetMultHZStrokesContent';
|
|
|
+ let data = {
|
|
|
+ hz_str: cons,
|
|
|
+ };
|
|
|
+ GetStaticResources(MethodName, data)
|
|
|
+ .then((res) => {
|
|
|
+ for (let key in res) {
|
|
|
+ if (key != 'status' && key != ',' && res[key]) {
|
|
|
+ res[key] = JSON.parse(res[key]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let hzDetailList = res;
|
|
|
+ let hz_list = [];
|
|
|
+ cons.split('').forEach((items) => {
|
|
|
+ let res = JSON.parse(JSON.stringify(hzDetailList[items]));
|
|
|
+ let obj = {
|
|
|
+ con: items,
|
|
|
+ hzDetail: {
|
|
|
+ hz_json: res,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ hz_list.push(obj);
|
|
|
+ });
|
|
|
+ row.hz_info = hz_list;
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ this.loading = false;
|
|
|
+ });
|
|
|
+
|
|
|
+ row.pinyin = cnchar.spell(cons, 'array', 'low', 'tone').join(' ');
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</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>
|