소스 검색

编辑器,素材选择界面,音频可播放

任一存 2 년 전
부모
커밋
016e16844a

+ 1 - 1
packages/qjkankan-editor/src/components/audio/audioForEditor.vue

@@ -15,7 +15,7 @@
  
 <script>
 export default {
-  name: "myAudioForEditor",
+  name: "audioButton",
   props: [
     "myAudioUrl",
     "backgroundColor",

+ 318 - 0
packages/qjkankan-editor/src/components/audio/indexForEditor.vue

@@ -0,0 +1,318 @@
+<template>
+  <div class="audio-wrapper" :key="vkey">
+    <audio ref="audio" :key="vkey">
+      <source :src="myAudioUrl+`?_=${idleft}`" type="audio/mp3" />
+    </audio>
+    <div class="UI-wrapper" :class="{'UI-wrapper--playing': !notPlaying}" @click="myPlay">
+      <div class="UI" :ref="`_${vkey}`">
+        <div :id="idleft" class="left"></div>
+        <div :id="idright" class="right"></div>
+        <div class="circle"></div>
+        <img v-if="notPlaying" :src="require('@/assets/images/icons/play.svg')" />
+        <img v-if="!notPlaying" :src="require('@/assets/images/icons/pause.svg')" />
+      </div>
+    </div>
+    <div v-if="showTime" class="namecon">
+      <div class="audio-name">{{name}}</div>
+      <div class="audio-right">
+        <div class="audio-time">
+          <span class="audio-length-current" ref="audioCurTime">00:00</span>
+          <span class="hang">/</span>
+          <span class="audio-length-total" ref="duration">00:00</span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+ 
+<script>
+export default {
+  name: "myAudio",
+  props: ["myAudioUrl","autoplay", "showTime","name", "idleft", "idright","vkey",'bofang'],
+  data() {
+    return {
+      audio: "",
+      notPlaying: true,
+      progress: 0,
+    };
+  },
+  mounted() {
+    this.init();
+    this.$bus.on('pausedAudio',data=>{
+      if (this.audio == data) {
+        this.notPlaying = true;
+      }
+    })
+    // 因为本组件是放到table组件的slot里的,table组件各个slot又是用v-for从数组渲染出来的,所以数组里删除某一项并不会导致本组件被销毁,只会导致props变化,此时要重新初始化组件。
+    this.$bus.on('deletedAudio', () => {
+      this.init()
+    })
+  },
+  methods: {
+    loadCircle() {
+      let leftEl = document.querySelector(`#${this.idleft}`);
+      let rightEl = document.querySelector(`#${this.idright}`);
+      if (!rightEl && !leftEl) {
+        return
+      }
+      if (this.progress) {
+        if (this.progress > 0 && this.progress < 50) {
+          rightEl.style.transform = "rotate(" + 3.6 * this.progress + "deg)";
+        } else {
+          rightEl.style.transform = "rotate(0)";
+          rightEl.style.background = "#FF9F2B";
+          leftEl.style.transform =
+            "rotate(" + 3.6 * (this.progress - 50) + "deg)";
+        }
+      } else {
+        rightEl.style.transform = "rotate(0deg)";
+        leftEl.style.transform = "rotate(0deg)";
+        rightEl.style.background = "#fff";
+      }
+    },
+    init() {
+      this.$nextTick(() => { // props的变化并不会立刻反映到html element的attribute上
+        if (this.$refs.audio) {
+          this.audio = this.$refs.audio;
+          this.audio.load();
+          this.audio.pause();
+          this.updateProgress();
+          this.notPlaying = true;
+        }
+      })
+    },
+    stopOtherAudio() {
+      Array.from($("audio")).forEach((item) => {
+        if (this.audio != item) {
+          if (!item.paused) {
+            item.pause();
+            this.$bus.emit('pausedAudio',item)
+          }
+        }
+      });
+    },
+    // 点击播放/暂停图片时,控制音乐的播放与暂停
+    myPlay() {
+      this.stopOtherAudio()
+      setTimeout(() => {
+        if (this.audio.paused) {
+          // 开始播放当前点击的音频
+          this.audio.play();
+          this.notPlaying = false;
+        } else {
+          this.audio.pause();
+          this.notPlaying = true;
+        }
+        this.updateProgress();
+      });
+    },
+    // 更新进度条与当前播放时间
+    updateProgress() {
+      let value = this.audio.currentTime / this.audio.duration;
+      this.progress = value * 100;
+      // 初始时间
+      this.$refs.audioCurTime &&
+        (this.$refs.audioCurTime.innerHTML = this.transTime(
+          this.audio.currentTime
+        ));
+      // 总共时长
+      let audioElement = new Audio(this.myAudioUrl);
+      this.loadCircle();
+      let self = this;
+      audioElement.addEventListener("loadedmetadata", function () {
+        let duration2 = (audioElement.duration / 60)
+          .toFixed(2)
+          .replace(".", ":");
+        self.$refs.duration &&
+          (self.$refs.duration.innerHTML = self.formatTime(duration2));
+      });
+    },
+    // 播放结束时
+    audioEnded() {
+      this.progress = 0;
+      this.notPlaying = true;
+      this.$emit('audioEnded')
+      this.loadCircle();
+    },
+    // 播放时间换算
+    transTime(value) {
+      let time = "";
+      let h = parseInt(value / 3600);
+      value %= 3600;
+      let m = parseInt(value / 60);
+      let s = parseInt(value % 60);
+      if (h > 0) {
+        time = this.formatTime(h + ":" + m + ":" + s);
+      } else {
+        time = this.formatTime(m + ":" + s);
+      }
+      return time;
+    },
+    //  * 格式化时间显示,补零对齐
+    //  * eg:2:4  -->  02:04
+    formatTime(value) {
+      let time = "";
+      let s = value.split(":");
+      let i = 0;
+      for (; i < s.length - 1; i++) {
+        time += s[i].length == 1 ? "0" + s[i] : s[i];
+        time += ":";
+      }
+      time += s[i].length == 1 ? "0" + s[i] : s[i];
+      return time;
+    },
+    // 点击进度条跳到指定点播放
+    handledown() {
+      // 只有音乐开始播放后才可以调节,已经播放过但暂停了的也可以
+      if (!this.audio.paused || this.audio.currentTime != 0) {
+        let pgsWidth = this.$refs.progressBarBg.offsetWidth;
+        let rate = event.offsetX / pgsWidth;
+        this.audio.currentTime = this.audio.duration * rate;
+        this.updateProgress();
+      }
+    },
+  },
+  watch: {
+    autoplay:{
+      deep:true,
+      immediate:true,
+      handler:function (newVal) {
+        if (newVal) {
+          this.myPlay()
+        }
+      }
+    },
+    bofang:{
+      deep:true,
+      handler:function () {
+        this.myPlay()
+      }
+    },
+    audio: {
+      deep: true,
+      handler: function () {
+        let self = this;
+        self.audio.addEventListener(
+          "timeupdate",
+          function () {
+            self.updateProgress();
+          },
+          false
+        );
+        self.audio.addEventListener(
+          "ended",
+          function () {
+            self.audioEnded();
+          },
+          false
+        );
+      },
+    },
+  },
+};
+</script>
+ 
+<style lang="less" scoped>
+.audio-wrapper {
+  display: flex;
+  margin-left: 4px;
+  align-items: center;
+}
+
+.audio-name {
+  font-size: 14px;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  flex: 3;
+  margin-right: 10px;
+}
+
+.audio-right {
+  height: 100%;
+  flex: 2;
+
+}
+
+.audio-time {
+  .hang {
+    display: inline-block;
+    margin: 0 4px;
+    color: #000;
+    font-size: 12px;
+  }
+}
+
+.audio-length-total {
+  font-size: 12px;
+}
+
+.audio-length-current {
+  font-size: 12px;
+}
+
+@raduiW: 18px;
+@pcolor: #fff;
+@rW: 14px;
+
+.UI-wrapper {
+  position: relative;
+  background-repeat: no-repeat;
+  background-position: center;
+  background-size: contain;
+  background-image: url('~@/assets/images/icons/icon-music@2x.png');
+  width: 100%;
+  height: 100%;
+  cursor: pointer;
+  &:hover, &--playing {
+    background-image: url('~@/assets/images/icons/icon-music-hover@2x.png');
+    .UI {
+      display: block;
+    }
+  }
+}
+
+.UI {
+  display: none;
+  position: absolute;
+  top: 40%;
+  left: 25%;
+  width: @raduiW;
+  height: @raduiW;
+  min-width: @raduiW;
+  background: #FF9F2B;
+  border-radius: 50%;
+  .left {
+    border-radius: 50%;
+    background: @pcolor;
+    clip: rect(0, @raduiW / 2, @raduiW, 0);
+  }
+  .right {
+    border-radius: 50%;
+    background: @pcolor;
+    clip: rect(0, @raduiW, @raduiW, @raduiW / 2);
+  }
+  .circle {
+    width: @rW;
+    height: @rW;
+    background: rgb(199, 100, 63);
+    border-radius: 50%;
+  }
+  * {
+    position: absolute;
+    left: 0;
+    top: 0;
+    bottom: 0;
+    right: 0;
+    margin: auto;
+  }
+}
+
+.namecon {
+  margin-left: 20px;
+  display: flex;
+  width: calc(100% - 60px);
+  justify-content: space-between;
+  align-items: center;
+}
+</style>

+ 21 - 5
packages/qjkankan-editor/src/components/materialSelectorForEditor.vue

@@ -214,11 +214,18 @@
             </span>
             <span class="table-data" v-for="(tableItemStructure, idx) in tableHeadersForAudio" :key="idx">
               <div v-if="tableItemStructure.type=='audio'" class="list-img">
-                <img
+                <!-- <img
                   :src="require('@/assets/images/icons/upload-file-type-icon-audio@2x.png')"
                   style="object-fit: contain;"
                   alt=""
-                >
+                > -->
+                <AudioIconCanPlay
+                  class="icon"
+                  :vKey="item.successInfo.id"
+                  :idleft="`_${$randomWord(true, 8, 8)}`"
+                  :idright="`_${$randomWord(true, 8, 8)}`"
+                  :myAudioUrl="item.successInfo.ossPath"
+                ></AudioIconCanPlay>
               </div>
               <span  v-else class="ellipsis" v-title="tableItemStructure.key === 'name' ? item.successInfo[tableItemStructure.key] : ''">{{ item.successInfo[tableItemStructure.key] }}</span>
             </span>
@@ -283,11 +290,18 @@
           </span>
           <span class="table-data" v-for="(sub,idx) in tableHeadersForAudio" :key="idx">
             <div v-if="sub.type=='audio'" class="list-img">
-              <img
+              <!-- <img
                 :src="require('@/assets/images/icons/upload-file-type-icon-audio@2x.png')"
                 style="object-fit: contain;"
                 alt=""
-              >
+              > -->
+              <AudioIconCanPlay
+                class="audio-player"
+                :vKey="item.id"
+                :idleft="`_${$randomWord(true, 8, 8)}`"
+                :idright="`_${$randomWord(true, 8, 8)}`"
+                :myAudioUrl="item.ossPath"
+              ></AudioIconCanPlay>
             </div>
             <span class="ellipsis" v-else v-title="sub.key === 'name' ? item[sub.key] : ''">{{item[sub.key]}}</span>
           </span>
@@ -516,6 +530,7 @@ import config from "@/config";
 import { debounce } from "@/utils/other.js"
 import FileInput from "@/components/shared/uploads/UploadMultiple.vue";
 import { mapState } from "vuex";
+import AudioIconCanPlay from "@/components/audio/indexForEditor.vue";
 
 export default {
   props:{
@@ -549,6 +564,7 @@ export default {
   },
   components:{
     FileInput,
+    AudioIconCanPlay,
   },
   watch:{
     searchKey: {
@@ -1458,7 +1474,7 @@ export default {
           height: 100%;
           display: inline-block;
           width: 100%;
-          > img {
+          > img, .audio-player {
             position: absolute;
             top: 50%;
             transform: translateY(-50%);

+ 1 - 1
packages/qjkankan-editor/src/utils/request.js

@@ -242,7 +242,7 @@ export const http = {
           done(result, result.code == 0);
         }
       } else {
-        console.error('ajax返回数据里咋没有code?')
+        console.log('ajax返回数据里没有code.')
         done(result);
       }
     });

+ 1 - 1
packages/qjkankan-editor/src/views/base/backgroundMusicSettings.vue

@@ -33,7 +33,7 @@
 <script>
 import { mapGetters } from "vuex";
 import MaterialSelectorForEditor from "@/components/materialSelectorForEditor.vue";
-import Audio from "@/components/audio/audioForEditor.vue";
+import Audio from "@/components/audio/audioButton.vue";
 
 export default {
   components: {

+ 1 - 1
packages/qjkankan-editor/src/views/explanation/explanationSettings.vue

@@ -45,7 +45,7 @@
 import { mapGetters } from "vuex";
 import Switcher from "@/components/shared/Switcher";
 import MaterialSelectorForEditor from "@/components/materialSelectorForEditor.vue";
-import Audio from "@/components/audio/audioForEditor.vue";
+import Audio from "@/components/audio/audioButton.vue";
 
 export default {
   components: {

+ 1 - 1
packages/qjkankan-editor/src/views/hotspot/hotspotType/audio.vue

@@ -31,7 +31,7 @@
 
 <script>
 import MaterialSelectorForEditor from "@/components/materialSelectorForEditor.vue";
-import Audio from "@/components/audio/audioForEditor.vue";
+import Audio from "@/components/audio/audioButton.vue";
 
 
 export default {