Parcourir la source

Merge branch 'lhd'

natasha il y a 1 semaine
Parent
commit
e0d034df1d

+ 89 - 0
src/components/CommonPreview.vue

@@ -97,6 +97,13 @@
 
         <main :class="['preview-main', { 'no-audit': !isShowAudit }]">
           <div class="preview-left"></div>
+          <!-- <div
+            id="selectable-area-preview"
+            @mousedown="startSelection"
+            @mousemove="updateSelection"
+            @mouseup="endSelection"
+            @mouseleave="endSelection"
+          > -->
           <CoursewarePreview
             v-if="courseware_info.book_name"
             ref="courserware"
@@ -116,6 +123,19 @@
             @editNote="handEditNote"
             @saveCollect="saveCollect"
           />
+          <!-- <div
+              v-if="isSelecting"
+              :style="{
+                position: 'absolute',
+                top: `${menuPosition.startY}px`,
+                left: `${menuPosition.startX}px`,
+                width: `${menuPosition.endX - menuPosition.startX}px`,
+                height: `${menuPosition.endY - menuPosition.startY}px`,
+                border: '2px solid #165DFF',
+              }"
+            ></div>
+          </div> -->
+
           <div class="preview-right"></div>
         </main>
 
@@ -572,7 +592,13 @@ export default {
         x: -1,
         y: -1,
         componentId: 'WHOLE',
+        startX: null,
+        startY: null,
+        endX: null,
+        endY: null,
       },
+      isSelecting: false,
+
       curToolbarIcon: this.isShowAudit ? 'audit' : '',
       sidebarIconList,
       twoSidebarList: [],
@@ -1468,6 +1494,69 @@ export default {
     computedSelectedGroupCoursewareInfo() {
       return this.$refs.courserware.computedSelectedGroupCoursewareInfo();
     },
+    startSelection(event) {
+      if (
+        this.isTrue(this.courseware_info.is_my_audit_task) &&
+        this.isTrue(this.courseware_info.is_can_add_audit_remark)
+      ) {
+        this.isSelecting = true;
+
+        let clientRect = document.getElementById(`selectable-area-preview`).getBoundingClientRect();
+        this.menuPosition.startX = event.clientX - clientRect.left;
+        this.menuPosition.startY = event.clientY - clientRect.top;
+      }
+    },
+    updateSelection(event) {
+      if (!this.isSelecting) return;
+      let clientRect = document.getElementById(`selectable-area-preview`).getBoundingClientRect();
+
+      this.menuPosition.endX = event.clientX - clientRect.left;
+      this.menuPosition.endY = event.clientY - clientRect.top;
+    },
+    endSelection() {
+      console.log('this.startX' + this.menuPosition.startX);
+      console.log('this.endX' + this.menuPosition.endX);
+      console.log('this.startY' + this.menuPosition.startY);
+      console.log('this.endY' + this.menuPosition.endY);
+
+      if (!this.isSelecting || this.menuPosition.startX === this.menuPosition.endX || !this.menuPosition.endX) return;
+      this.isSelecting = false;
+      const width = Math.abs(this.menuPosition.endX - this.menuPosition.startX);
+      const height = Math.abs(this.menuPosition.endY - this.menuPosition.startY);
+      const x =
+        this.menuPosition.endX > this.menuPosition.startX
+          ? `${this.menuPosition.startX}px`
+          : `${this.menuPosition.endX}px`;
+      const y =
+        this.menuPosition.endY > this.menuPosition.startY
+          ? `${this.menuPosition.startY}px`
+          : `${this.menuPosition.endY}px`;
+      let obj = {
+        id: Math.random().toString(36).substring(2, 10),
+        width: `${width}px`,
+        height: `${height}px`,
+        x,
+        y,
+        text: '',
+      };
+      this.menuPosition.startX = null;
+      this.menuPosition.endX = null;
+      this.menuPosition.startY = null;
+      this.menuPosition.endY = null;
+      if (width && height && this.isText) {
+        this.data.text_list.push(obj);
+        this.activeType = 'text';
+        this.activeIndex = this.data.text_list.length - 1;
+
+        this.hotspotsActiveIndex = this.data.text_list.length - 1;
+      } else if (width && height && !this.isText) {
+        this.data.input_list.push(obj);
+        this.activeType = 'input';
+        this.activeIndex = this.data.input_list.length - 1;
+
+        this.inputActiveIndex = this.data.input_list.length - 1;
+      }
+    },
   },
 };
 </script>

+ 94 - 54
src/views/book/courseware/create/components/question/article/NewWord.vue

@@ -201,13 +201,16 @@
       </div>
     </div>
     <el-button icon="el-icon-plus" style="margin: 24px 0" @click="addElement">增加一个</el-button>
-    <SelectUpload
-      label="生词音频"
-      type="audio"
-      width="500px"
-      :style="{ marginBottom: data.audio_data.url.length === 0 ? '5px' : '' }"
-      @uploadSuccess="uploadAudioSuccess"
-    />
+    <div class="btn-box">
+      <SelectUpload
+        label="生词音频"
+        type="audio"
+        width="500px"
+        :style="{ marginBottom: data.audio_data.url.length === 0 ? '5px' : '' }"
+        @uploadSuccess="uploadAudioSuccess"
+      />
+      <el-button :loading="autoLoading" @click="handleAutoAudio">自动生成音频</el-button>
+    </div>
     <div v-if="data.audio_data.url.length > 0" class="upload-file">
       <div class="file-name">
         <span>
@@ -264,28 +267,26 @@
         </el-select>
       </el-form-item>
 
-      <template v-if="data.property.audio_generation_method === 'auto'">
-        <el-form-item label="音色">
-          <el-select v-model="data.property.voice_type" placeholder="请选择">
-            <el-option
-              v-for="{ voice_type, name } in voice_type_list"
-              :key="voice_type"
-              :label="name"
-              :value="voice_type"
-            />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="风格情感">
-          <el-select v-model="data.property.emotion">
-            <el-option v-for="{ emotion, name } in emotion_list" :key="emotion" :label="name" :value="emotion" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="语速">
-          <el-select v-model="data.property.speed_ratio">
-            <el-option v-for="{ value, label } in speedRatioList" :key="value" :label="label" :value="value" />
-          </el-select>
-        </el-form-item>
-      </template>
+      <el-form-item label="音色">
+        <el-select v-model="data.property.voice_type" placeholder="请选择">
+          <el-option
+            v-for="{ voice_type, name } in voice_type_list"
+            :key="voice_type"
+            :label="name"
+            :value="voice_type"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="风格情感">
+        <el-select v-model="data.property.emotion">
+          <el-option v-for="{ emotion, name } in emotion_list" :key="emotion" :label="name" :value="emotion" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="语速">
+        <el-select v-model="data.property.speed_ratio">
+          <el-option v-for="{ value, label } in speedRatioList" :key="value" :label="label" :value="value" />
+        </el-select>
+      </el-form-item>
 
       <el-form-item label="拼音位置">
         <el-radio-group v-model="data.property.pinyin_position">
@@ -354,6 +355,7 @@ export default {
       voice_type_list: [],
       emotion_list: [],
       speedRatioList,
+      autoLoading: false,
     };
   },
   methods: {
@@ -423,30 +425,30 @@ export default {
           file_id,
         };
         this.data.file_id_list.push(file_id);
-        let _this = this;
-        _this.loading = true;
-        let data = {
-          file_id,
-        };
-        fileToBase64Text(data)
-          .then((res) => {
-            let taskIddata = {
-              fileName: name,
-              speechBase64: res.base64_text,
-              language: 'ch',
-            };
-            prepareTranscribe(taskIddata)
-              .then((reses) => {
-                _this.loading = false;
-                _this.$set(_this.data, 'taskId', reses.data.taskId);
-              })
-              .catch(() => {
-                _this.loading = false;
-              });
-          })
-          .catch(() => {
-            _this.loading = false;
-          });
+        // let _this = this;
+        // _this.loading = true;
+        // let data = {
+        //   file_id,
+        // };
+        // fileToBase64Text(data)
+        //   .then((res) => {
+        //     let taskIddata = {
+        //       fileName: name,
+        //       speechBase64: res.base64_text,
+        //       language: 'ch',
+        //     };
+        //     prepareTranscribe(taskIddata)
+        //       .then((reses) => {
+        //         _this.loading = false;
+        //         _this.$set(_this.data, 'taskId', reses.data.taskId);
+        //       })
+        //       .catch(() => {
+        //         _this.loading = false;
+        //       });
+        //   })
+        //   .catch(() => {
+        //     _this.loading = false;
+        //   });
       }
     },
     getBase64(file) {
@@ -588,7 +590,7 @@ export default {
       row.pinyin = cnchar.spell(cons, 'array', 'low', 'tone').join(' ');
     },
     createWordTimes() {
-      if (this.data.taskId) {
+      if (this.data.audio_data.file_id) {
         let text = '';
         this.data.new_word_list.forEach((sItem, index) => {
           // item.forEach((sItem, sIndex) => {
@@ -696,6 +698,38 @@ export default {
         })
         .catch(() => {});
     },
+    // 自动生成音频
+    handleAutoAudio() {
+      this.autoLoading = true;
+      let text = '';
+      this.data.new_word_list.forEach((sItem, index) => {
+        // item.forEach((sItem, sIndex) => {
+        text += `${sItem.new_word}。`;
+        // });
+      });
+      TextToAudioFile({
+        text: text,
+        voice_type: this.data.property.voice_type,
+        emotion: this.data.property.emotion,
+        speed_ratio: this.data.property.speed_ratio,
+      })
+        .then(({ status, file_id, file_url }) => {
+          this.autoLoading = false;
+          if (status === 1) {
+            this.data.audio_data = {
+              name: '自动生成课文音频.mp3',
+              media_duration: 0,
+              temporary_url: file_url,
+              url: file_id,
+              file_id,
+            };
+            this.data.file_id_list.push(file_id);
+          }
+        })
+        .catch(() => {
+          this.autoLoading = false;
+        });
+    },
   },
   created() {
     this.getTextToAudioConfParamList();
@@ -783,6 +817,12 @@ export default {
     margin: 0;
   }
 }
+
+.btn-box {
+  display: flex;
+  flex-flow: wrap;
+  gap: 10px;
+}
 </style>
 <style lang="scss">
 .tox .tox-editor-header {

+ 75 - 32
src/views/book/courseware/create/components/question/new_word/NewWord.vue

@@ -346,13 +346,17 @@
       </div>
 
       <el-button icon="el-icon-plus" style="margin: 24px 0" @click="addElement">增加一个</el-button>
-      <SelectUpload
-        label="生词音频"
-        type="audio"
-        width="500px"
-        :style="{ marginBottom: data.audio_data.url.length === 0 ? '5px' : '' }"
-        @uploadSuccess="uploadAudioSuccess"
-      />
+      <div class="btn-box">
+        <SelectUpload
+          label="生词音频"
+          type="audio"
+          width="500px"
+          :style="{ marginBottom: data.audio_data.url.length === 0 ? '5px' : '' }"
+          @uploadSuccess="uploadAudioSuccess"
+        />
+        <el-button :loading="autoLoading" @click="handleAutoAudio">自动生成音频</el-button>
+      </div>
+
       <div v-if="data.audio_data.url.length > 0" class="upload-file">
         <div class="file-name">
           <span>
@@ -439,6 +443,7 @@ export default {
       multilingualText: '',
       visible: false,
       subtitleList: [],
+      autoLoading: false,
     };
   },
   watch: {
@@ -496,30 +501,30 @@ export default {
           file_id,
         };
         this.data.file_id_list.push(file_id);
-        let _this = this;
-        _this.loading = true;
-        let data = {
-          file_id,
-        };
-        fileToBase64Text(data)
-          .then((res) => {
-            let taskIddata = {
-              fileName: name,
-              speechBase64: res.base64_text,
-              language: 'ch',
-            };
-            prepareTranscribe(taskIddata)
-              .then((reses) => {
-                _this.loading = false;
-                _this.$set(_this.data, 'taskId', reses.data.taskId);
-              })
-              .catch(() => {
-                _this.loading = false;
-              });
-          })
-          .catch(() => {
-            _this.loading = false;
-          });
+        // let _this = this;
+        // _this.loading = true;
+        // let data = {
+        //   file_id,
+        // };
+        // fileToBase64Text(data)
+        //   .then((res) => {
+        //     let taskIddata = {
+        //       fileName: name,
+        //       speechBase64: res.base64_text,
+        //       language: 'ch',
+        //     };
+        //     prepareTranscribe(taskIddata)
+        //       .then((reses) => {
+        //         _this.loading = false;
+        //         _this.$set(_this.data, 'taskId', reses.data.taskId);
+        //       })
+        //       .catch(() => {
+        //         _this.loading = false;
+        //       });
+        //   })
+        //   .catch(() => {
+        //     _this.loading = false;
+        //   });
       }
     },
     getBase64(file) {
@@ -718,7 +723,7 @@ export default {
       this.data.source_courseware_id = val[val.length - 1];
     },
     createWordTimes() {
-      if (this.data.taskId) {
+      if (this.data.audio_data.file_id) {
         let text = '';
         this.data.new_word_list.forEach((sItem, index) => {
           // item.forEach((sItem, sIndex) => {
@@ -838,6 +843,38 @@ export default {
         .filter((item) => item.length > 0)
         .join(' ');
     },
+    // 自动生成音频
+    handleAutoAudio() {
+      this.autoLoading = true;
+      let text = '';
+      this.data.new_word_list.forEach((sItem, index) => {
+        // item.forEach((sItem, sIndex) => {
+        text += `${sItem.new_word}。`;
+        // });
+      });
+      TextToAudioFile({
+        text: text,
+        voice_type: this.data.property.voice_type,
+        emotion: this.data.property.emotion,
+        speed_ratio: this.data.property.speed_ratio,
+      })
+        .then(({ status, file_id, file_url }) => {
+          this.autoLoading = false;
+          if (status === 1) {
+            this.data.audio_data = {
+              name: '自动生成课文音频.mp3',
+              media_duration: 0,
+              temporary_url: file_url,
+              url: file_id,
+              file_id,
+            };
+            this.data.file_id_list.push(file_id);
+          }
+        })
+        .catch(() => {
+          this.autoLoading = false;
+        });
+    },
   },
 };
 </script>
@@ -927,6 +964,12 @@ export default {
     margin: 0;
   }
 }
+
+.btn-box {
+  display: flex;
+  flex-flow: wrap;
+  gap: 10px;
+}
 </style>
 <style lang="scss">
 .tox .tox-editor-header {

+ 20 - 22
src/views/book/courseware/create/components/question/new_word/NewWordSetting.vue

@@ -21,28 +21,26 @@
           <el-option v-for="{ value, label } in audioGenerationMethodList" :key="value" :label="label" :value="value" />
         </el-select>
       </el-form-item>
-      <template v-if="property.audio_generation_method === 'auto'">
-        <el-form-item label="音色">
-          <el-select v-model="property.voice_type" placeholder="请选择">
-            <el-option
-              v-for="{ voice_type, name } in voice_type_list"
-              :key="voice_type"
-              :label="name"
-              :value="voice_type"
-            />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="风格情感">
-          <el-select v-model="property.emotion">
-            <el-option v-for="{ emotion, name } in emotion_list" :key="emotion" :label="name" :value="emotion" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="语速">
-          <el-select v-model="property.speed_ratio">
-            <el-option v-for="{ value, label } in speedRatioList" :key="value" :label="label" :value="value" />
-          </el-select>
-        </el-form-item>
-      </template>
+      <el-form-item label="音色">
+        <el-select v-model="property.voice_type" placeholder="请选择">
+          <el-option
+            v-for="{ voice_type, name } in voice_type_list"
+            :key="voice_type"
+            :label="name"
+            :value="voice_type"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="风格情感">
+        <el-select v-model="property.emotion">
+          <el-option v-for="{ emotion, name } in emotion_list" :key="emotion" :label="name" :value="emotion" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="语速">
+        <el-select v-model="property.speed_ratio">
+          <el-option v-for="{ value, label } in speedRatioList" :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">