Browse Source

音频改版

zq 11 months ago
parent
commit
b6fdd111db

+ 3 - 0
src/icons/svg/components/bluepaused.svg

@@ -0,0 +1,3 @@
+<svg width="6" height="8" viewBox="0 0 6 8" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.07325 4.17337L0.657148 7.11746C0.561415 7.18129 0.432064 7.15541 0.368239 7.05966C0.345427 7.02546 0.333252 6.98525 0.333252 6.94412V1.05599C0.333252 0.940931 0.426527 0.847656 0.541585 0.847656C0.582714 0.847656 0.622927 0.859831 0.657148 0.882648L5.07325 3.82671C5.16896 3.89054 5.19484 4.01987 5.131 4.11562C5.11575 4.1385 5.09613 4.15812 5.07325 4.17337Z" fill="#076AFF"/>
+</svg>

+ 2 - 2
src/icons/svg/components/next.svg

@@ -1,3 +1,3 @@
-<svg width="21" height="22" viewBox="0 0 21 22" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M8.80975 11.0015L0.821533 18.9896L3.17855 21.3466L13.5237 11.0015L3.17855 0.65625L0.821533 3.01327L8.80975 11.0015ZM20.3334 1.00143V21.0015H17.0001V1.00143H20.3334Z" fill="black"/>
+<svg width="9" height="10" viewBox="0 0 9 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.33341 5.38761L1.3702 9.36308C1.23618 9.45239 1.05509 9.41622 0.965731 9.28217C0.933793 9.23428 0.916748 9.17799 0.916748 9.12036V0.877016C0.916748 0.715935 1.04733 0.58535 1.20841 0.58535C1.266 0.58535 1.32229 0.602395 1.3702 0.634332L7.33341 4.60979V0.915365C7.33341 0.593201 7.59457 0.332031 7.91675 0.332031C8.23892 0.332031 8.50008 0.593201 8.50008 0.915365V9.08203C8.50008 9.40421 8.23892 9.66537 7.91675 9.66537C7.59457 9.66537 7.33341 9.40421 7.33341 9.08203V5.38761Z" fill="black"/>
 </svg>

+ 2 - 2
src/icons/svg/components/pre.svg

@@ -1,3 +1,3 @@
-<svg width="21" height="22" viewBox="0 0 21 22" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M12.1904 11.0015L20.1786 3.01327L17.8216 0.65625L7.47641 11.0015L17.8216 21.3466L20.1786 18.9896L12.1904 11.0015ZM0.666748 21.0015V1.00143H4.00008V21.0015H0.666748Z" fill="black"/>
+<svg width="9" height="10" viewBox="0 0 9 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1.66667 4.60979L7.62991 0.634332C7.7639 0.544983 7.94497 0.581196 8.03433 0.715229C8.0663 0.763138 8.08333 0.819435 8.08333 0.877016V9.12036C8.08333 9.28147 7.95272 9.41202 7.79167 9.41202C7.73409 9.41202 7.6778 9.39499 7.62991 9.36308L1.66667 5.38761V9.08203C1.66667 9.40421 1.4055 9.66537 1.08333 9.66537C0.76117 9.66537 0.5 9.40421 0.5 9.08203V0.915365C0.5 0.593201 0.76117 0.332031 1.08333 0.332031C1.4055 0.332031 1.66667 0.593201 1.66667 0.915365V4.60979Z" fill="black"/>
 </svg>

+ 3 - 0
src/icons/svg/components/writepaused.svg

@@ -0,0 +1,3 @@
+<svg width="12" height="16" viewBox="0 0 12 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.376 8.41536L0.77735 15.4811C0.54759 15.6343 0.23715 15.5722 0.0839701 15.3425C0.0292201 15.2603 0 15.1638 0 15.0651V0.933594C0 0.657444 0.22386 0.433594 0.5 0.433594C0.59871 0.433594 0.69522 0.462814 0.77735 0.517564L11.376 7.58326C11.6057 7.73646 11.6678 8.04696 11.5146 8.27666C11.478 8.33156 11.4309 8.37876 11.376 8.41536Z" fill="white"/>
+</svg>

+ 99 - 36
src/views/book/courseware/preview/components/audio/AudioPreview.vue

@@ -2,16 +2,23 @@
   <div class="audio_area" :style="getAreaStyle()">
     <SerialNumberPosition :property="data.property" />
 
-    <div class="main">
-      <ul v-if="'list' === data.property.view_method" class="view_list">
+    <div ref="audioArea" class="main">
+      <ul v-if="'independent' === data.property.view_method" class="view-independent">
         <li v-for="(file, i) in data.file_list" :key="i">
-          <AudioPlay view-size="small" :file-id="file.file_id" :audio-index="i" view-method="list" />
+          <AudioPlay
+            view-size="middle"
+            :file-id="file.file_id"
+            :file-name="file.file_name.slice(0, file.file_name.lastIndexOf('.'))"
+            :audio-index="i"
+          />
         </li>
       </ul>
-      <div
-        v-if="'independent' === data.property.view_method || 'icon' === data.property.view_method"
-        class="view_independent"
-      >
+      <ul v-else-if="'icon' === data.property.view_method" class="view-icon">
+        <li v-for="(file, i) in data.file_list" :key="i">
+          <AudioPlay view-size="small" :file-id="file.file_id" :audio-index="i" />
+        </li>
+      </ul>
+      <div v-else class="view-list">
         <el-carousel
           ref="audio_carousel"
           indicator-position="none"
@@ -23,23 +30,27 @@
             <AudioPlay
               view-size="big"
               :file-id="file.file_id"
+              :file-name="file.file_name.slice(0, file.file_name.lastIndexOf('.'))"
               :show-slider="true"
               :cur-audio-index="curAudioIndex"
               @changeFile="changeFile"
             />
           </el-carousel-item>
         </el-carousel>
-        <ul class="view_independent_list">
-          <li v-for="(file, i) in data.file_list" :key="i" @click="handleAudioClick(i)">
-            <AudioPlay
-              view-size="small"
-              :file-id="file.file_id"
-              :show-slider="false"
-              :audio-index="i"
-              :cur-audio-index="curAudioIndex"
-            />
-          </li>
-        </ul>
+        <div :style="{ height: elementHeight - 140 + 'px', overflowY: viewScroll }">
+          <ul class="view-list-bottom">
+            <li v-for="(file, i) in data.file_list" :key="i" @click="handleAudioClick(i)">
+              <AudioPlay
+                view-size="list"
+                :file-id="file.file_id"
+                :file-name="file.file_name.slice(0, file.file_name.lastIndexOf('.'))"
+                :show-slider="false"
+                :audio-index="i"
+                :cur-audio-index="curAudioIndex"
+              />
+            </li>
+          </ul>
+        </div>
       </div>
     </div>
   </div>
@@ -59,10 +70,53 @@ export default {
     return {
       data: getAudioData(),
       curAudioIndex: 0,
+      elementWidth: 0,
+      elementHeight: 0,
+      fileLen: 0,
+      resizeObserver: null, // ResizeObserver 实例,用于监听元素大小变化
+      viewScroll: 'hidden',
     };
   },
+  watch: {
+    data: {
+      handler(val) {
+        this.fileLen = val.file_list.length;
+        if (this.fileLen > 0 && this.data.property.view_method === 'list') {
+          const ele = this.$refs.audioArea;
+          this.elementWidth = ele.clientWidth;
+          this.elementHeight = ele.clientHeight;
+
+          window.addEventListener('resize', this.handleResize);
+        }
+      },
+      deep: true,
+    },
+    elementWidth(newWidth, oldWidth) {
+      this.elementWidth = newWidth;
+    },
+    elementHeight(newHeight, oldHeight) {
+      this.elementHeight = newHeight;
+      this.isViewScroll();
+    },
+  },
+  mounted() {
+    this.$nextTick(() => {
+      let _class = document.querySelector('.canvas');
+      if (_class === null) return;
+      if (_class.classList.contains('canvas')) {
+        this.resizeObserver = new ResizeObserver((entries) => {
+          for (let entry of entries) {
+            this.elementWidth = entry.contentRect.width;
+            this.elementHeight = entry.contentRect.height;
+          }
+        });
+        this.resizeObserver.observe(this.$el);
+      }
+    });
+  },
   methods: {
     handleAudioClick(index) {
+      console.log(this.data.file_list);
       // 获取 Carousel 实例
       const carousel = this.$refs.audio_carousel;
       // 切换到对应索引的文件
@@ -87,6 +141,14 @@ export default {
         this.curAudioIndex = this.data.file_id_list.length - 1;
       }
     },
+    isViewScroll() {
+      const ulHeight = this.fileLen * 44;
+      if (ulHeight > this.elementHeight - 140) {
+        this.viewScroll = 'scroll';
+      } else {
+        this.viewScroll = 'hidden';
+      }
+    },
   },
 };
 </script>
@@ -109,32 +171,33 @@ export default {
     grid-area: main;
     width: 100%;
 
-    .view_list {
+    .view-independent {
       display: flex;
       flex-wrap: wrap;
-      gap: 20px 2%;
-      width: 100%;
+      gap: 16px;
 
       > li {
-        flex: 0 0 23%;
-        min-width: 120px;
-        height: 46px;
+        min-width: 280px;
       }
     }
 
-    .view_independent {
+    .view-icon {
       display: flex;
-      flex: 1;
-      column-gap: 2%;
+      flex-wrap: wrap;
+      gap: 16px 50px;
+    }
+
+    .view-list {
+      display: flex;
+      flex-direction: column;
 
       :deep .el-carousel {
         flex: 1;
-        padding: 20%;
-        background-color: #d9d9d9;
+        background-color: #f8f8f8;
+        border-radius: 4px;
 
         &__container {
-          height: 100px;
-          margin: 0 auto;
+          height: 128px;
         }
 
         &__item {
@@ -142,13 +205,13 @@ export default {
         }
       }
 
-      .view_independent_list {
+      .view-list-bottom {
         display: flex;
         flex-direction: column;
-        row-gap: 2px;
-        min-width: 200px;
-        max-height: 500px;
-        overflow: auto;
+
+        li {
+          border-top: 1px solid #ccc;
+        }
       }
     }
   }

+ 118 - 45
src/views/book/courseware/preview/components/common/AudioPlay.vue

@@ -1,35 +1,50 @@
 <template>
   <div class="audio-wrapper">
-    <template v-if="'big' === viewSize">
-      <div class="audio-icon">
-        <SvgIcon icon-class="pre" @click="changeFile('prev')" />
-        <SvgIcon :icon-class="iconClass" size="30" @click="playAudio" />
-        <SvgIcon icon-class="next" @click="changeFile('next')" />
-        <SvgIcon icon-class="1x" size="12" />
-      </div>
+    <div v-if="'big' === viewSize" class="audio-big">
+      <div class="audio-name">{{ audioIndex + 1 }}. {{ fileName }}</div>
       <div v-if="showSlider" class="slider-area">
-        <span class="audio-time">{{ secondFormatConversion(audio.current_time) }} / {{ audio_allTime }}</span>
+        <span class="audio-time">{{ secondFormatConversion(audio.current_time) }}</span>
         <el-slider
           v-model="play_value"
           class="audio-slider"
           :format-tooltip="formatProcessToolTip"
           @change="changeCurrentTime"
         />
+        <span class="audio-time">{{ audio_allTime }}</span>
       </div>
-    </template>
-    <div v-else>
-      <div class="audio-small" :style="{ cursor: 'list' === viewMethod ? 'default' : 'pointer' }">
-        <span>{{ audioIndex + 1 }}.</span>
-        <SvgIcon
-          v-if="audioIndex === curAudioIndex && 'list' != viewMethod"
-          :icon-class="iconClass"
-          size="14"
-          style="cursor: default"
+      <div class="audio-icon">
+        <SvgIcon icon-class="pre" size="12" @click="changeFile('prev')" />
+        <SvgIcon :icon-class="iconClass" size="26" @click="playAudio" />
+        <SvgIcon icon-class="next" size="12" @click="changeFile('next')" />
+      </div>
+    </div>
+    <div v-else-if="'middle' === viewSize" class="audio-middle">
+      <div class="audio-name">{{ audioIndex + 1 }}. {{ fileName }}</div>
+      <div class="slider-area">
+        <SvgIcon :icon-class="iconClass" size="18" @click="playAudio" />
+        <span class="audio-time">{{ secondFormatConversion(audio.current_time) }}</span>
+        <el-slider
+          v-model="play_value"
+          class="audio-slider"
+          :format-tooltip="formatProcessToolTip"
+          @change="changeCurrentTime"
         />
-        <SvgIcon v-if="'list' === viewMethod" :icon-class="iconClass" size="14" @click="playAudio" />
         <span class="audio-time">{{ audio_allTime }}</span>
       </div>
     </div>
+    <div v-else-if="'small' === viewSize" class="audio-icons">
+      <span>{{ audioIndex + 1 }}.</span>
+      <span class="icon-box">
+        <SvgIcon :icon-class="audio.paused ? 'writepaused' : 'playing'" size="14" @click="playAudio" />
+      </span>
+    </div>
+    <div v-else :class="['audio-list', audioIndex === curAudioIndex ? 'active' : '']">
+      <div class="active-mark">
+        <SvgIcon v-if="audioIndex === curAudioIndex" icon-class="bluepaused" size="12" style="cursor: default" />
+      </div>
+      <span class="audio-name">{{ audioIndex + 1 }}. {{ fileName }}</span>
+      <span class="audio-time">{{ audio_allTime }}</span>
+    </div>
 
     <audio
       :id="fileId"
@@ -54,6 +69,10 @@ export default {
       type: String,
       required: true,
     },
+    fileName: {
+      type: String,
+      default: '',
+    },
     viewSize: {
       type: String,
       required: true,
@@ -197,31 +216,102 @@ export default {
 
 <style lang="scss" scoped>
 .audio-wrapper {
-  display: flex;
-  flex-direction: column;
-  row-gap: 38px;
+  .audio-big {
+    display: flex;
+    flex-direction: column;
+    padding: 12px 16px;
+    text-align: center;
+
+    .audio-name {
+      padding: 8px;
+      margin-bottom: 8px;
+      font-size: 14px;
+      background-color: #eee;
+      border-radius: 4px;
+    }
+
+    .audio-icon {
+      display: flex;
+      column-gap: 32px;
+      align-items: center;
+      justify-content: center;
 
-  .audio-icon {
+      .svg-icon {
+        cursor: pointer;
+      }
+    }
+  }
+
+  .audio-middle {
+    width: 280px;
+    padding: 12px 16px;
+    background-color: #f8f8f8;
+    border: 1px solid #e7e7e7;
+    border-radius: 4px;
+
+    .audio-name {
+      padding: 8px;
+      margin-bottom: 8px;
+      font-size: 14px;
+      text-align: center;
+      background-color: #eee;
+      border-radius: 4px;
+    }
+  }
+
+  .audio-icons {
     display: flex;
-    column-gap: 15%;
+    column-gap: 10px;
     align-items: center;
-    justify-content: end;
 
-    .svg-icon {
+    .icon-box {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: 40px;
+      height: 40px;
       cursor: pointer;
+      background-color: #076aff;
+      border-radius: 20px;
+
+      .svg-icon {
+        // color: red;
+      }
+    }
+  }
+
+  .audio-list {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 8px 24px 8px 16px;
+
+    &.active {
+      background-color: #f4f9ff;
+    }
+
+    .active-mark {
+      width: 20px;
+      height: 28px;
+    }
+
+    .audio-name {
+      flex: 1;
     }
   }
 
   .slider-area {
+    display: flex;
+    column-gap: 16px;
+    align-items: center;
+    justify-content: space-between;
     font-size: 14px;
-    text-align: left;
 
     .audio-slider {
-      width: 100%;
+      width: 90%;
 
       :deep .el-slider__runway {
         height: 4px;
-        margin-top: 4px;
         background-color: #fff;
       }
 
@@ -235,23 +325,6 @@ export default {
         height: 4px;
         background-color: #076aff;
       }
-
-      :deep .el-slider__button-wrapper {
-        top: -16px;
-      }
-    }
-  }
-
-  .audio-small {
-    display: flex;
-    column-gap: 8px;
-    align-items: center;
-    min-width: 110px;
-    padding: 13px;
-    background-color: #d9d9d9;
-
-    .svg-icon {
-      cursor: pointer;
     }
   }
 }