Просмотр исходного кода

Merge branch 'iteration-20240912' into ponline

lex-xin 10 месяцев назад
Родитель
Сommit
9e80dd05f0

BIN
src/teacher/music/upload/images/audio-bg.png


BIN
src/teacher/music/upload/images/audio-pause.png


BIN
src/teacher/music/upload/images/audio-play.png


BIN
src/teacher/music/upload/images/top_bg.png


BIN
src/teacher/music/upload/images/top_line.png


+ 14 - 2
src/teacher/music/upload/index.module.less

@@ -348,7 +348,7 @@
     }
 
     .van-tag--default {
-      color: var(--van-tag-text-default-color);
+      color: #777;
     }
 
     .van-tag--primary {
@@ -369,6 +369,7 @@
   padding-top: 0 !important;
   padding-bottom: 0 !important;
   border: 1px solid #9FE2DE !important;
+  user-select: none;
 }
 
 .file {
@@ -394,7 +395,7 @@
 .upbtn {
   border: 1px solid #cfcfcf;
   width: 100%;
-  color: #666666;
+  color: #aaa;
   height: 48px;
   background: #F6F8F9;
   border-radius: 6px;
@@ -445,3 +446,14 @@
   margin-top: 0 !important;
   position: relative;
 }
+
+.listenAudioShow {
+  overflow: hidden;
+  border-radius: 20px !important;
+  :global {
+    .van-popup__close-icon {
+      color: #6F7F7C;
+      top: 20px;
+    }
+  }
+}

+ 60 - 11
src/teacher/music/upload/index.tsx

@@ -35,6 +35,7 @@ import ColHeader from '@/components/col-header'
 import ColSticky from '@/components/col-sticky'
 import MessageTip from './message-tip'
 import SelectTag from './select-tag'
+import ListenAudio from './listen-audio'
 
 export type BackgroundMp3 = {
   url?: string
@@ -88,6 +89,7 @@ export default defineComponent({
       tagsNames: [] as Array<{ [id in string]: string }>,
       formated: {} as FormatXMLInfo,
       tagVisibility: false,
+      listenAudioShow: false,
       // subjectListres: [] as any[],
       // subjectListNames: {} as any,
       // selectedSubjectList: null as any,
@@ -105,7 +107,11 @@ export default defineComponent({
       messageTipType: 'upload' as 'upload' | 'error' | 'origin',
       cbsInstrumentList: [] as any,
       tagList: [] as any,
-      musicSheetAuthRecordId: null as any
+      musicSheetAuthRecordId: null as any,
+      fileInfo: {
+        url: '',
+        name: '' as any
+      }
     }
   },
   watch: {
@@ -568,13 +574,20 @@ export default defineComponent({
                         loading={this.mp3Loading}
                         disabled={this.auditDisabled}
                         onClick={() => {
-                          if (this.mp3Url) return
+                          if (this.mp3Url) {
+                            this.listenAudioShow = true
+                            this.fileInfo = {
+                              url: this.mp3Url,
+                              name: this.fileName(this.mp3Url)
+                            }
+                            return
+                          }
                           this.naiveMp3File()
                         }}
                       >
                         {this.mp3Url
-                          ? this.fileName(this.mp3Url)
-                          : '上传伴奏文件'}
+                          ? <span style='text-decoration-line: underline;color: #14BC9C;'>{this.fileName(this.mp3Url)}</span>
+                          : <span style='text-decoration-line: underline;color: #14BC9C;'>上传伴奏文件</span>}
                       </Button>
 
                       {this.mp3Url && !this.auditDisabled && (
@@ -589,11 +602,22 @@ export default defineComponent({
                   ) : (
                     <>
                       <Upload
-                        onUpdate:modelValue={val => (this.mp3Url = val)}
+                        onUpdate:modelValue={val => {
+                          this.mp3Url = val
+                        }}
                         accept=".mp3"
                         disabled={this.auditDisabled}
                       />
-                      <div style={{ marginLeft: '8px' }}>
+                      <div
+                        style={{ marginLeft: '8px' }}
+                        onClick={() => {
+                          this.listenAudioShow = true
+                          this.fileInfo = {
+                            url: this.mp3Url,
+                            name: this.fileName(this.mp3Url)
+                          }
+                        }}
+                      >
                         {this.fileName(this.mp3Url)}
                       </div>
                     </>
@@ -633,7 +657,7 @@ export default defineComponent({
                       >
                         {this.midiFileUrl
                           ? this.fileName(this.midiFileUrl)
-                          : '上传MIDI文件'}
+                          : <span style='text-decoration-line: underline;color: #14BC9C;'>上传MIDI文件</span>}
                       </Button>
 
                       {this.midiFileUrl && !this.auditDisabled && (
@@ -692,7 +716,7 @@ export default defineComponent({
                     >
                       {this.xmlFileUrl
                         ? this.fileName(this.xmlFileUrl)
-                        : '上传XML文件'}
+                        : <span style='text-decoration-line: underline;color: #14BC9C;'>上传XML文件</span>}
                     </Button>
 
                     {this.xmlFileUrl && !this.auditDisabled && (
@@ -770,11 +794,18 @@ export default defineComponent({
                             loading={mp3.loading}
                             disabled={this.auditDisabled}
                             onClick={() => {
-                              if (mp3.url) return
+                              if (mp3.url) {
+                                this.listenAudioShow = true
+                                this.fileInfo = {
+                                  url: mp3.url,
+                                  name: this.fileName(mp3.url)
+                                }
+                                return
+                              }
                               this.naiveBGMp3File(index)
                             }}
                           >
-                            {mp3.url ? this.fileName(mp3.url) : '上传原声文件'}
+                            {mp3.url ? <span style='text-decoration-line: underline;color: #14BC9C;'>{this.fileName(mp3.url)}</span> : <span style='text-decoration-line: underline;color: #14BC9C;'>上传原声文件</span>}
                           </Button>
 
                           {mp3.url && !this.auditDisabled && (
@@ -793,7 +824,14 @@ export default defineComponent({
                             accept=".mp3"
                             disabled={this.auditDisabled}
                           />
-                          <div style={{ marginLeft: '8px' }}>
+                          <div style={{ marginLeft: '8px' }}
+                            onClick={() => {
+                              this.listenAudioShow = true
+                              this.fileInfo = {
+                                url: mp3.url as any,
+                                name: this.fileName(mp3.url)
+                              }
+                          }}>
                             {this.fileName(mp3.url)}
                           </div>
                         </>
@@ -1059,6 +1097,17 @@ export default defineComponent({
           />
         </Popup>
 
+        <Popup
+          show={this.listenAudioShow}
+          round
+          closeable
+          teleport="body"
+          class={styles.listenAudioShow}
+          onUpdate:show={val => (this.listenAudioShow = val)}
+        >
+          {this.listenAudioShow && <ListenAudio fileInfo={this.fileInfo} />}
+        </Popup>
+
         <MessageTip
           title={this.messageTipTitle}
           type={this.messageTipType}

+ 125 - 0
src/teacher/music/upload/listen-audio/index.module.less

@@ -0,0 +1,125 @@
+.listenAudio {
+  background: url('../images/top_bg.png') no-repeat top center;
+  background-size: contain;
+  width: 315px;
+  min-height: 200px;
+
+  .title {
+    padding-top: 20px;
+    padding-bottom: 24px;
+    font-weight: 600;
+    font-size: 18px;
+    color: #000000;
+    text-align: center;
+
+    span {
+      display: inline-block;
+      position: relative;
+      span {
+        position: relative;
+        z-index: 5;
+      }
+      &::after {
+        content: '';
+        display: inline-block;
+        width: 100%;
+        height: 8px;
+        background: url('../images/top_line.png') no-repeat center;
+        background-size: contain;
+        position: absolute;
+        bottom: -2px;
+        left: 0;
+        z-index: -1;
+      }
+    }
+  }
+
+  .container {
+    .img {
+      position: relative;
+      width: 200px;
+      height: 200px;
+      margin: 0 auto;
+      cursor: pointer;
+
+      .audioBg {
+        width: inherit;
+        height: inherit;
+      }
+
+      .iconImg {
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        width: 50px;
+        height: 50px;
+      }
+    }
+
+    .slider {
+      // width: 100%;
+      padding: 17px 0 10px;
+      --van-slider-bar-height: 3px;
+      --van-slider-button-width: 13px !important;
+      --van-slider-button-height: 13px !important;
+      --van-slider-active-background-color: #2cc4a8 !important;
+
+      :global {
+        // .n-slider {
+        //   --n-handle-size: 13px !important;
+        //   --n-fill-color: var(--van-primary-color) !important;
+        //   --n-fill-color-hover: var(--van-primary-color) !important;
+        // }
+
+        .van-slider {
+          z-index: 9;
+        }
+
+        .van-loading {
+          width: 100%;
+          height: 100%;
+        }
+
+        .van-slider__button {
+          background: #2CC4A8;
+          box-shadow: none;
+        }
+      }
+    }
+
+    .audioInfo {
+      padding: 24px 20px 20px;
+      .name {
+        font-weight: 600;
+        font-size: 16px;
+        color: #131415;
+        line-height: 22px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+
+      .time {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        font-size: 14px;
+        color: #777777;
+        line-height: 20px;
+      }
+      audio {
+        visibility: hidden;
+        position: absolute;
+        z-index: -2;
+      }
+      :global {
+        .plyr {
+          visibility: hidden;
+          position: absolute;
+          z-index: -2;
+        }
+      }
+    }
+  }
+}

+ 126 - 0
src/teacher/music/upload/listen-audio/index.tsx

@@ -0,0 +1,126 @@
+import {
+  defineComponent,
+  onMounted,
+  onUnmounted,
+  PropType,
+  reactive,
+  ref
+} from 'vue'
+import styles from './index.module.less'
+import iconPause from '../images/audio-pause.png'
+import iconPlay from '../images/audio-play.png'
+import audioBg from '../images/audio-bg.png'
+import { Slider } from 'vant'
+import { getSecondRPM } from '@/helpers/utils'
+import Plyr from 'plyr'
+
+type fileType = {
+  url: string
+  name: string
+}
+
+export default defineComponent({
+  name: 'listen-audio',
+  props: {
+    fileInfo: {
+      type: Object as PropType<fileType>
+    }
+  },
+  setup(props) {
+    const audioRef = ref()
+    const audioProtoType = reactive({
+      audioPause: true,
+      duration: 0.01,
+      currentTime: 0
+    })
+
+    const onChangePlay = () => {
+      if(!audioRef.value) return
+      if (audioProtoType.audioPause) {
+        audioRef.value?.play()
+      } else {
+        audioRef.value?.pause()
+      }
+      audioProtoType.audioPause = audioRef.value.paused
+    }
+
+    const handleChangeTime = (val: any) => {
+      audioRef.value.currentTime = val
+    }
+
+    onMounted(() => {
+      if (!props.fileInfo?.url) return
+      audioRef.value = new Plyr('#audioSrc', {
+        controls: [
+          'play-large',
+          'play',
+          'progress',
+          'current-time',
+          'duration'
+        ],
+        fullscreen: { enabled: false }
+      })
+      audioRef.value.on('loadedmetadata', () => {
+        audioProtoType.duration = audioRef.value.duration
+      })
+      audioRef.value.on('timeupdate', () => {
+        audioProtoType.currentTime = audioRef.value.currentTime || 0
+      })
+      audioRef.value.on('ended', () => {
+        audioProtoType.currentTime = 0
+        audioRef.value.currentTime = 0
+        audioProtoType.audioPause = true
+      })
+    })
+
+    onUnmounted(() => {
+      audioRef.value?.destroy()
+    })
+    return () => (
+      <div class={styles.listenAudio}>
+        <h2 class={styles.title}>
+          <span>
+            <span>预览音频</span>
+          </span>
+        </h2>
+
+        <div class={styles.container}>
+          <div class={styles.img} onClick={onChangePlay}>
+            <img src={audioBg} class={styles.audioBg} />
+            <img
+              src={audioProtoType.audioPause ? iconPause : iconPlay}
+              class={styles.iconImg}
+            />
+          </div>
+
+          <div class={styles.audioInfo}>
+            <audio
+              crossorigin="anonymous"
+              id="audioSrc"
+              src={props.fileInfo?.url}
+              controls="false"
+              preload="metadata"
+              playsinline
+            />
+            <div class={styles.name}>{props.fileInfo?.name}</div>
+            <div class={styles.slider}>
+              <Slider
+                step={0.01}
+                class={styles.timeProgress}
+                v-model={audioProtoType.currentTime}
+                max={audioProtoType.duration}
+                onUpdate:modelValue={val => {
+                  handleChangeTime(val)
+                }}
+              />
+            </div>
+            <div class={styles.time}>
+              <div>{getSecondRPM(audioProtoType.currentTime)}</div>
+              <div>{getSecondRPM(audioProtoType.duration)}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    )
+  }
+})

+ 1 - 1
src/tenant/music/coursewarePlay/component/video.module.less

@@ -308,7 +308,7 @@
 .sliderPopup {
   position: absolute;
   z-index: 9999;
-  left: 104px;
+  left: 93px;
   bottom: 46px;
   display: flex;
   align-items: center;

+ 1 - 1
src/tenant/music/lessonCourseware/index.module.less

@@ -27,7 +27,7 @@
 
 
     .van-search {
-      padding-bottom: 0;
+      // padding-bottom: 0;
       align-items: flex-start;
     }