瀏覽代碼

Merge remote-tracking branch 'origin/hqyDev' into dev

lex 1 年之前
父節點
當前提交
a76ff40a2a

二進制
src/components/m-empty/images/icon_empty2.png


+ 4 - 1
src/components/m-empty/index.tsx

@@ -5,6 +5,7 @@ import iconEmpty from './images/empty.png';
 import iconNetwork from './images/network.png';
 import icon404 from './images/404.png';
 import icon_empty from './images/icon_empty.png';
+import icon_empty2 from './images/icon_empty2.png';
 import icon_list_emtry from './images/icon_list_emtry.png';
 
 export default defineComponent({
@@ -16,7 +17,7 @@ export default defineComponent({
     },
     image: {
       type: String as PropType<
-        'empty' | 'network' | '404' | 'icon_empty' | 'list'
+        'empty' | 'network' | '404' | 'icon_empty' | 'list' | "empty2"
       >,
       default: 'icon_empty'
     },
@@ -42,6 +43,8 @@ export default defineComponent({
         forms.image = icon404;
       } else if (props.image === 'list') {
         forms.image = icon_list_emtry;
+      } else if( props.image === "empty2"){
+        forms.image = icon_empty2;
       }
     });
     return () => (

+ 10 - 0
src/views/co-ai/index.module.less

@@ -648,15 +648,25 @@
 }
 
 .empty {
+  margin: 0 auto;
+  width: 60%;
   :global {
+    .van-empty{
+      padding: 0;
+      .van-empty__bottom{
+        margin-top: 0;
+      }
+    }
     .van-empty__image {
       width: 100%;
       height: initial;
     }
 
     .van-empty__description {
+      margin-top: 0;
       color: #fff;
       padding: 0;
+      font-size: 14px;
     }
   }
 }

+ 98 - 0
src/views/creation/audioVisualDraw.ts

@@ -0,0 +1,98 @@
+    /**
+     * 音频可视化
+     * @param audioDom
+     * @param canvasDom
+     * @param fftSize  2的幂数,最小为32
+     * 注意   由于ios低版本必须在用户操作之后才能初始化 createMediaElementSource 所以必须在用户操作之后初始化
+     */
+    export default function audioVisualDraw(audioDom: HTMLAudioElement, canvasDom: HTMLCanvasElement, fftSize = 128) {
+      type propsType = { canvWidth: number; canvHeight: number; canvFillColor: string; lineColor: string; lineGap: number }
+      // canvas
+      const canvasCtx = canvasDom.getContext("2d")!
+      const { width, height } = canvasDom.getBoundingClientRect()
+      canvasDom.width = width
+      canvasDom.height = height
+      // audio
+      const audioCtx = new AudioContext()
+      const source = audioCtx.createMediaElementSource(audioDom)
+      const analyser = audioCtx.createAnalyser()
+      analyser.fftSize = fftSize
+      source?.connect(analyser)
+      analyser.connect(audioCtx.destination)
+      const dataArray = new Uint8Array(fftSize / 2)
+      const draw = (data: Uint8Array, ctx: CanvasRenderingContext2D, { lineGap, canvWidth, canvHeight, canvFillColor, lineColor }: propsType) => {
+        if (!ctx) return
+        const w = canvWidth
+        const h = canvHeight
+        fillCanvasBackground(ctx, w, h, canvFillColor)
+          // 可视化
+        const dataLen = data.length
+        let step = (w / 2 - lineGap * dataLen) / dataLen
+        step < 1 && (step = 1)
+        const midX = w / 2
+        const midY = h / 2
+        let xLeft = midX
+        for (let i = 0; i < dataLen; i++) {
+          const value = data[i]
+          const percent = value / 255 // 最大值为255
+          const barHeight = percent * midY
+          canvasCtx.fillStyle = lineColor
+          // 中间加间隙
+          if (i === 0) {
+            xLeft -= lineGap / 2
+          }
+          canvasCtx.fillRect(xLeft - step, midY - barHeight, step, barHeight)
+          canvasCtx.fillRect(xLeft - step, midY, step, barHeight)
+          xLeft -= step + lineGap
+        }
+        let xRight = midX
+        for (let i = 0; i < dataLen; i++) {
+          const value = data[i]
+          const percent = value / 255 // 最大值为255
+          const barHeight = percent * midY
+          canvasCtx.fillStyle = lineColor
+          if (i === 0) {
+            xRight += lineGap / 2
+          }
+          canvasCtx.fillRect(xRight, midY - barHeight, step, barHeight)
+          canvasCtx.fillRect(xRight, midY, step, barHeight)
+          xRight += step + lineGap
+        }
+      }
+      const fillCanvasBackground = (ctx: CanvasRenderingContext2D, w: number, h: number, colors: string) => {
+        ctx.clearRect(0, 0, w, h)
+        ctx.fillStyle = colors
+        ctx.fillRect(0, 0, w, h)
+      }
+      const requestAnimationFrameFun = () => {
+        requestAnimationFrame(() => {
+          analyser?.getByteFrequencyData(dataArray)
+          draw(dataArray, canvasCtx, {
+            lineGap: 2,
+            canvWidth: width,
+            canvHeight: height,
+            canvFillColor: "transparent",
+            lineColor: "rgba(255, 255, 255, 0.7)"
+          })
+          if (!isPause) {
+            requestAnimationFrameFun()
+          }
+        })
+      }
+      let isPause = true
+      const playVisualDraw = () => {
+        //audioCtx.resume()  // 重新更新状态   加了暂停和恢复音频音质发生了变化  所以这里取消了
+        isPause = false
+        requestAnimationFrameFun()
+      }
+      const pauseVisualDraw = () => {
+        isPause = true
+        //audioCtx?.suspend()  // 暂停   加了暂停和恢复音频音质发生了变化  所以这里取消了
+        // source?.disconnect()
+        // analyser?.disconnect()
+      }
+      return {
+        playVisualDraw,
+        pauseVisualDraw
+      }
+    }

+ 5 - 0
src/views/creation/edit/index.module.less

@@ -152,6 +152,11 @@
       border-radius: 0 0 8px 8px;
       pointer-events: none;
     }
+    :global{
+      .van-uploader .van-image{
+        border-radius: 8px !important;
+      }
+    }
   }
 
   .uploadImg {

File diff suppressed because it is too large
+ 0 - 0
src/views/creation/images/audioBga.json


二進制
src/views/creation/images/btn.png


File diff suppressed because it is too large
+ 0 - 0
src/views/creation/images/leftCloud.json


File diff suppressed because it is too large
+ 0 - 0
src/views/creation/images/loading.json


File diff suppressed because it is too large
+ 0 - 0
src/views/creation/images/rightCloud.json


二進制
src/views/creation/images/videobg.png


+ 151 - 189
src/views/creation/index-share.tsx

@@ -4,7 +4,8 @@ import {
   onUnmounted,
   reactive,
   ref,
-  watch
+  watch,
+  nextTick
 } from 'vue';
 // import WaveSurfer from 'wavesurfer.js';
 // import Regions from 'wavesurfer.js/dist/plugins/regions.js';
@@ -24,7 +25,7 @@ import videoLabel from './share-model/images/videoLabel.png';
 import musicBg from './share-model/images/music-bg.png';
 import playImg from './images/play.png';
 import { browser, getGradeCh, getSecondRPM, vaildMusicScoreUrl } from '@/helpers/utils';
-import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
+import { onBeforeRouteUpdate, useRoute, useRouter, onBeforeRouteLeave } from 'vue-router';
 import {
   api_openUserMusicDetail,
   api_openUserMusicPage,
@@ -32,7 +33,6 @@ import {
   api_verification
 } from './api';
 import MEmpty from '@/components/m-empty';
-import { nextTick } from 'process';
 import MVideo from '@/components/m-video';
 import LoginModel from './login-model';
 import { removeAuth } from '../student-register/layout/utils';
@@ -40,15 +40,20 @@ import { setLogout } from '@/state';
 import { storage } from '@/helpers/storage';
 import { ACCESS_TOKEN } from '@/store/mutation-types';
 import MWxTip from '@/components/m-wx-tip';
-import { usePageVisibility, useEventListener } from '@vant/use';
-import videoBg from './images/video-bg.png';
+import { usePageVisibility, useEventListener, useWindowSize } from '@vant/use';
 import LoginChangeModel from './login-change-model';
 import MSticky from '@/components/m-sticky';
 import "plyr/dist/plyr.css";
 import Plyr from "plyr";
 import { Vue3Lottie } from "vue3-lottie";
 import audioBga from "./images/audioBga.json";
+import audioBga1 from "./images/leftCloud.json";
+import audioBga2 from "./images/rightCloud.json";
 import videobg from "./images/videobg.png";
+import btnImg from './images/btn.png';
+import audioVisualDraw from "./audioVisualDraw"
+import playProgressData from "./playCreation/playProgress"
+import Loading from './loading';
 
 export default defineComponent({
   name: 'creation-detail',
@@ -56,7 +61,10 @@ export default defineComponent({
     const route = useRoute();
     const router = useRouter();
     const isScreenScroll = ref(false)
+    const creationHeight = ref(0)
     const lottieDom = ref()
+    const lottieDom1 = ref()
+    const lottieDom2 = ref()
     const state = reactive({
       id: route.query.id,
       isEmpty:false,
@@ -75,7 +83,7 @@ export default defineComponent({
       },
       params: {
         page: 1,
-        rows: 20
+        rows: 4
       },
       messageStatus: false,
       message: '',
@@ -94,10 +102,14 @@ export default defineComponent({
     const staffState = reactive({
       staffSrc: "",
       isShow: false,
-      height:"initial"
+      height:"initial",
+      speedRate:1,
+      musicRenderType:"staff",
+      partIndex:0
     })
     const staffDom= ref<HTMLIFrameElement>()
     const {playStaff, pauseStaff, updateProgressStaff} = staffMoveInstance()
+    let isInitAudioVisualDraw =false
     // 点赞
     const onStarChange = async () => {
       await checkLogin();
@@ -140,7 +152,7 @@ export default defineComponent({
         if (state.list.length > 0 && result.current === 1) {
           return;
         }
-        state.list = state.list.concat(result.rows || []);
+        state.list = result.rows || [];
         state.listState.finished = result.current >= result.pages;
         state.params.page = result.current + 1;
         state.listState.dataShow = state.list.length > 0;
@@ -153,6 +165,8 @@ export default defineComponent({
     };
 
     const onDetail = (item: any) => {
+      playProgressData.playProgress = 0
+      playProgressData.playState = false
       router.push({
         path: '/shareCreation',
         query: {
@@ -168,23 +182,10 @@ export default defineComponent({
         fullscreen: { enabled: false },
       });
       const player = state._plrl
-        // 创建音波数据
-      if(state.playType === "Audio"){
-        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
-        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
-        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
-        player.on('play', () => {
-          lottieDom.value.play()
-          playVisualDraw()
-        });
-        player.on('pause', () => {
-          lottieDom.value.pause()
-          pauseVisualDraw()
-        });
-      }
       // 在微信中运行的时候,微信没有开放自动加载资源的权限,所以要等播放之后才显示播放控制器
       player.on('loadedmetadata', () => {
         plyrState.loaded = true
+        player.currentTime = playProgressData.playProgress
       });
       player.on("timeupdate", ()=>{
         plyrState.currentTime = player.currentTime
@@ -218,123 +219,48 @@ export default defineComponent({
     }
     //点击改变播放状态
     function handlerClickPlay(){
-      if (state._plrl.playing) {
-        state._plrl.pause();
-      } else {
-        state._plrl.play();
-      }
-    }
-    /**
-     * 音频可视化
-     * @param audioDom
-     * @param canvasDom
-     * @param fftSize  2的幂数,最小为32
-     */
-    function audioVisualDraw(audioDom: HTMLAudioElement, canvasDom: HTMLCanvasElement, fftSize = 128) {
-      type propsType = { canvWidth: number; canvHeight: number; canvFillColor: string; lineColor: string; lineGap: number }
-      // canvas
-      const canvasCtx = canvasDom.getContext("2d")!
-      const { width, height } = canvasDom.getBoundingClientRect()
-      canvasDom.width = width
-      canvasDom.height = height
-      // audio
-      let audioCtx : AudioContext | null = null
-      let analyser : AnalyserNode | null = null
-      let source : MediaElementAudioSourceNode | null = null
-      const dataArray = new Uint8Array(fftSize / 2)
-      const draw = (data: Uint8Array, ctx: CanvasRenderingContext2D, { lineGap, canvWidth, canvHeight, canvFillColor, lineColor }: propsType) => {
-        if (!ctx) return
-        const w = canvWidth
-        const h = canvHeight
-        fillCanvasBackground(ctx, w, h, canvFillColor)
-          // 可视化
-        const dataLen = data.length
-        let step = (w / 2 - lineGap * dataLen) / dataLen
-        step < 1 && (step = 1)
-        const midX = w / 2
-        const midY = h / 2
-        let xLeft = midX
-        for (let i = 0; i < dataLen; i++) {
-          const value = data[i]
-          const percent = value / 255 // 最大值为255
-          const barHeight = percent * midY
-          canvasCtx.fillStyle = lineColor
-          // 中间加间隙
-          if (i === 0) {
-            xLeft -= lineGap / 2
-          }
-          canvasCtx.fillRect(xLeft - step, midY - barHeight, step, barHeight)
-          canvasCtx.fillRect(xLeft - step, midY, step, barHeight)
-          xLeft -= step + lineGap
-        }
-        let xRight = midX
-        for (let i = 0; i < dataLen; i++) {
-          const value = data[i]
-          const percent = value / 255 // 最大值为255
-          const barHeight = percent * midY
-          canvasCtx.fillStyle = lineColor
-          if (i === 0) {
-            xRight += lineGap / 2
-          }
-          canvasCtx.fillRect(xRight, midY - barHeight, step, barHeight)
-          canvasCtx.fillRect(xRight, midY, step, barHeight)
-          xRight += step + lineGap
-        }
-      }
-      const fillCanvasBackground = (ctx: CanvasRenderingContext2D, w: number, h: number, colors: string) => {
-        ctx.clearRect(0, 0, w, h)
-        ctx.fillStyle = colors
-        ctx.fillRect(0, 0, w, h)
-      }
-      const requestAnimationFrameFun = () => {
-        requestAnimationFrame(() => {
-          analyser?.getByteFrequencyData(dataArray)
-          draw(dataArray, canvasCtx, {
-            lineGap: 2,
-            canvWidth: width,
-            canvHeight: height,
-            canvFillColor: "transparent",
-            lineColor: "rgba(255, 255, 255, 0.7)"
-          })
-          if (!isPause) {
-            requestAnimationFrameFun()
-          }
-        })
-      }
-      let isPause = true
-      const playVisualDraw = () => {
-        if (!audioCtx) {
-          audioCtx = new AudioContext()
-          source = audioCtx.createMediaElementSource(audioDom)
-          analyser = audioCtx.createAnalyser()
-          analyser.fftSize = fftSize
-          source?.connect(analyser)
-          analyser.connect(audioCtx.destination)
-        }
-        //audioCtx.resume()  // 重新更新状态   加了暂停和恢复音频音质发生了变化  所以这里取消了
-        isPause = false
-        requestAnimationFrameFun()
-      }
-      const pauseVisualDraw = () => {
-        isPause = true
-        //audioCtx?.suspend()  // 暂停   加了暂停和恢复音频音质发生了变化  所以这里取消了
-        // source?.disconnect()
-        // analyser?.disconnect()
+      const player = state._plrl;
+      // 由于ios低版本必须在用户操作之后才能初始化 createMediaElementSource 所以必须在用户操作之后初始化
+      if(!isInitAudioVisualDraw && state.playType === "Audio"){
+        isInitAudioVisualDraw = true
+        // 创建音波数据
+        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
+        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
+        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
+        player.on('play', () => {
+          lottieDom.value?.play()
+          lottieDom1.value?.play()
+          lottieDom2.value?.play()
+          playVisualDraw()
+        });
+        player.on('pause', () => {
+          lottieDom.value?.pause()
+          lottieDom1.value?.pause()
+          lottieDom2.value?.pause()
+          pauseVisualDraw()
+        });
       }
-      return {
-        playVisualDraw,
-        pauseVisualDraw
+      if (player.playing) {
+        player.pause();
+      } else {
+        player.play();
       }
     }
     function handlerLandscapeScreen(event:any){
       event.stopPropagation()
+      playProgressData.playState = !!state._plrl?.playing
+      playProgressData.playProgress = state._plrl?.currentTime || 0
       router.push({
         path:"/playCreation",
         query:{
           resourceUrl:encodeURIComponent(state.musicDetail?.videoUrl),
+          videoBgUrl:encodeURIComponent(state.musicDetail?.videoImg || ""),
           musicSheetName:encodeURIComponent(state.musicDetail?.musicSheetName),
           username:encodeURIComponent(state.musicDetail?.username),
-          musicSheetId:encodeURIComponent(state.musicDetail?.musicSheetId)
+          musicSheetId:encodeURIComponent(state.musicDetail?.musicSheetId),
+          speedRate:encodeURIComponent(staffState.speedRate),
+          musicRenderType:encodeURIComponent(staffState.musicRenderType),
+          partIndex:encodeURIComponent(staffState.partIndex),
         }
       })
     }
@@ -371,6 +297,13 @@ export default defineComponent({
           return;
         } else {
           state.musicDetail = res.data;
+          try{
+            const jsonConfig = JSON.parse(res.data.jsonConfig)
+            jsonConfig.speedRate && (staffState.speedRate = jsonConfig.speedRate)
+            jsonConfig.musicRenderType && (staffState.musicRenderType = jsonConfig.musicRenderType)
+            jsonConfig.partIndex && (staffState.partIndex = jsonConfig.partIndex)
+          }catch{
+          }
           // 五线谱
           initStaff()
           getList();
@@ -384,7 +317,7 @@ export default defineComponent({
           nextTick(() => {
             initMediaPlay();
           });
-}
+        }
       } catch (err:any) {
         // 没有的时候显示缺省页
         state.message = err;
@@ -417,17 +350,19 @@ export default defineComponent({
     });
     // 初始化五线谱
     function initStaff(){
-      const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=staff`;
-      //const src = `http://192.168.3.68:3000/instrument.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=staff`;
+      const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
+      //const src = `http://192.168.3.122:3000/instrument.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
       staffState.staffSrc = src
       window.addEventListener('message', (event) => {
         const { api, height } = event.data;
         if (api === 'api_musicPage') {
           staffState.isShow = true
           staffState.height = height + "px"
-          // 如果是播放中自动开始 播放
-          if(state._plrl.playing){
-            playStaff()
+          // 如果是播放中自动开始播放  不是播放 自动跳转到当前位置
+          if(playProgressData.playState){
+            handlerClickPlay()
+          }else{
+            updateProgressStaff(state._plrl.currentTime)
           }
         }
       });
@@ -440,7 +375,7 @@ export default defineComponent({
             {
               api: 'api_playProgress',
               content: {
-                currentTime: state._plrl.currentTime
+                currentTime: state._plrl.currentTime * staffState.speedRate
               }
             },
             "*"
@@ -473,14 +408,14 @@ export default defineComponent({
           "*"
         )
       }
-      const updateProgressStaff = (currentTime: string) => {
+      const updateProgressStaff = (currentTime: number) => {
         // 没渲染不执行
         if(!staffState.isShow) return
         staffDom.value?.contentWindow?.postMessage(
           {
             api: 'api_updateProgress',
             content: {
-              currentTime: state._plrl.currentTime
+              currentTime: currentTime * staffState.speedRate
             }
           },
           "*"
@@ -492,12 +427,17 @@ export default defineComponent({
         updateProgressStaff
       }
     }
+    function setFullHeight(){
+      creationHeight.value = window.innerHeight
+    }
     onMounted(async () => {
       __init();
+      window.addEventListener('resize', setFullHeight)
     });
 
     onUnmounted(() => {
       cleanScrollEvent()
+      window.removeEventListener('resize', setFullHeight)
     });
 
     onBeforeRouteUpdate((to: any) => {
@@ -505,19 +445,29 @@ export default defineComponent({
       state.playType = '';
       state.params.page = 1;
       state.list = [];
+      isInitAudioVisualDraw = false
       if(state._plrl){
         state._plrl.destroy()
       }
+      plyrState.playIngShow = true
       staffState.staffSrc = ""
       staffState.isShow = false
       staffState.height = "initial"
       __init();
     });
+    onBeforeRouteLeave((to, from, next)=>{
+      if(to.path !== "/playCreation"){
+        playProgressData.playProgress = 0
+        playProgressData.playState = false
+      }
+      next()
+    })
     return () => (
       <div
         style={
           {
-            '--barheight':state.heightV + "px"
+            '--barheight':state.heightV + "px",
+            "--creationHeight":creationHeight.value ? creationHeight.value+"px" : "100vh"
           }
         }
         class={[
@@ -540,7 +490,7 @@ export default defineComponent({
         {
           state.isEmpty ?
           <div class={styles.isEmpty}>
-            <MEmpty description="作品已删除~" />
+            <MEmpty image={"empty2"} description="作品已删除~" />
           </div> :
           <>
             <div class={styles.singerBox}>
@@ -561,6 +511,8 @@ export default defineComponent({
                       <div class={styles.audioBox}>
                         <canvas class={styles.audioVisualizer} id="audioVisualizer"></canvas>
                         <Vue3Lottie ref={lottieDom} class={styles.audioBga} animationData={audioBga} autoPlay={false} loop={true}></Vue3Lottie>
+                        <Vue3Lottie ref={lottieDom1} class={styles.audioBga1} animationData={audioBga1} autoPlay={false} loop={true}></Vue3Lottie>
+                        <Vue3Lottie ref={lottieDom2} class={styles.audioBga2} animationData={audioBga2} autoPlay={false} loop={true}></Vue3Lottie>
                         <audio
                           crossorigin="anonymous"
                           id="audioMediaSrc"
@@ -577,7 +529,7 @@ export default defineComponent({
                         id="videoMediaSrc"
                         class={styles.videoBox}
                         src={state.musicDetail?.videoUrl}
-                        data-poster={videobg}
+                        data-poster={ state.musicDetail?.videoImg || videobg}
                         preload="metadata"
                         playsinline
                       />
@@ -644,57 +596,65 @@ export default defineComponent({
             <div class={styles.likeSection}>
               <div class={styles.likeTitle}>推荐作品</div>
               {state.listState.dataShow ? (
-                <List
-                  finished={state.listState.finished}
-                  finishedText=" "
-                  class={[styles.container, styles.containerInformation]}
-                  onLoad={getList}
-                  immediateCheck={false}>
-                  {state.list.map((item: any, index: number) => (
-                    <Cell
-                      class={[styles.likeShareItem, index===state.list.length-1&&styles.likeShareItemLast]}
-                      border={false}
-                      onClick={() => onDetail(item)}
-                    >
-                      {{
-                        icon: () => (
-                          <div class={styles.audioImgBox}>
-                            <img
-                              src={audioPan}
-                              class={styles.audioPan}
-                              crossorigin="anonymous"
-                            />
-                            <img
-                              src={
-                                item.img || musicBg
-                              }
-                              class={styles.muploader}
-                              crossorigin="anonymous"
-                            />
-                            <img class={styles.imgLabel} src={item.videoUrl?.lastIndexOf('mp4') !== -1 ? videoLabel : audioLabel} />
-                          </div>
-                        ),
-                        title: () => (
-                          <div class={styles.userInfo}>
-                            <div class={[styles.musicSheetName,'van-ellipsis']}>{item.musicSheetName}</div>
-                            <div class={styles.usernameCon}>
-                              <div class={styles.likeNum}>
-                                <img src={iconZanActive} />
-                                <span>{item.likeNum}</span>
+                <>
+                  <List
+                    finished={true}
+                    finishedText=" "
+                    class={[styles.container, styles.containerInformation]}
+                    //onLoad={getList}
+                    immediateCheck={false}>
+                    {state.list.map((item: any, index:number) => (
+                      <Cell
+                        class={[styles.likeShareItem, index===state.list.length-1&&styles.likeShareItemLast]}
+                        border={false}
+                        onClick={() => onDetail(item)}
+                      >
+                        {{
+                          icon: () => (
+                            <div class={styles.audioImgBox}>
+                              <img
+                                src={audioPan}
+                                class={styles.audioPan}
+                                crossorigin="anonymous"
+                              />
+                              <img
+                                src={
+                                  item.img || musicBg
+                                }
+                                class={styles.muploader}
+                                crossorigin="anonymous"
+                              />
+                              <img class={styles.imgLabel} src={item.videoUrl?.lastIndexOf('mp4') !== -1 ? videoLabel : audioLabel} />
+                            </div>
+                          ),
+                          title: () => (
+                            <div class={styles.userInfo}>
+                              <div class={[styles.musicSheetName,'van-ellipsis']}>{item.musicSheetName}</div>
+                              <div class={styles.usernameCon}>
+                                <div class={styles.likeNum}>
+                                  <img src={iconZanActive} />
+                                  <span>{item.likeNum}</span>
+                                </div>
+                                <div class={styles.username}>{item.username}</div>
                               </div>
-                              <div class={styles.username}>{item.username}</div>
                             </div>
-                          </div>
-                        ),
-                        value: () => (
-                          <img src={playImg} class={styles.playImg} />
-                        )
-                      }}
-                    </Cell>
-                  ))}
-                </List>
+                          ),
+                          value: () => (
+                            <img src={playImg} class={styles.playImg} />
+                          )
+                        }}
+                      </Cell>
+                    ))}
+                  </List>
+                  {
+                    !state.listState.finished &&
+                      <div class={styles.btnImg}>
+                        <img onClick={getList} src={btnImg} />
+                    </div>
+                  }
+                </>
               ) : (
-                <MEmpty description="暂无数据" />
+                <MEmpty image={"empty2"} description="暂无作品" />
               )}
             </div>
             {
@@ -711,7 +671,6 @@ export default defineComponent({
           v-model:show={state.loginStatus}
           style={{ background: 'transparent', overflow: 'inherit' }}>
           <LoginModel
-            isRegister
             onClose={() => (state.loginStatus = false)}
             onConfirm={async (val: any) => {
               if (val.loginTag) {
@@ -749,6 +708,9 @@ export default defineComponent({
           message={state.message}
           showButton={false}
         />
+        {
+          !staffState.isShow && <Loading></Loading>
+        }
       </div>
     );
   }

+ 85 - 12
src/views/creation/index.module.less

@@ -2,7 +2,8 @@
   position: fixed;
   z-index: -1;
   width: 100vw;
-  height: 100vh;
+  height: var(--creationHeight, 100vh);
+  min-height: 100vh;
   top: 0;
   left: 0;
   background: url("./images/bg.png") no-repeat;
@@ -38,9 +39,10 @@
       .plyr {
           width: 100%;
           height: 100%;
+          z-index: initial;
           .plyr__controls{
               background: initial;
-              padding: 0 12px;
+              padding: 0 12px 2px;
               opacity: 1 !important;
               transform: translateY(0) !important;
               pointer-events: initial !important;
@@ -53,9 +55,10 @@
                       height: 2px;
                   }
                   input[type="range"]::-webkit-slider-thumb {
-                      width: 8px;
-                      height: 8px;
-                      margin-top: -3px;
+                      width: 6px;
+                      height: 6px;
+                      margin-top: -2px;
+                      box-shadow: initial;
                   }
                   .plyr__progress__buffer{
                       height: 2px;
@@ -77,12 +80,27 @@
       background: url("./images/audioBg.png") no-repeat;
       background-size: 100% 100%;
       position: relative;
-      .audioBga{
+      overflow: hidden;
+      .audioBga {
         position: absolute;
         left: 0;
-        bottom: 0;
+        top: 0;
         width: 100%;
-        height: 100%;
+        height: 82%;
+      }
+
+      .audioBga1 {
+          position: absolute;
+          left: 0;
+          top: 16px;
+          width: 94px;
+      }
+
+      .audioBga2 {
+          width: 192px;
+          position: absolute;
+          right: -24px;
+          top: 0;
       }
       :global {
           .plyr {
@@ -90,6 +108,7 @@
               height: initial;
               left: 0;
               bottom: 0;
+              z-index: 2;
           }
       }
       .audioVisualizer{
@@ -155,10 +174,13 @@
   }
   .staffBox{
     width: 100%;
-    height: var(--staffBoxHeight);
+    height: calc(var(--staffBoxHeight) + 12px);
     position: absolute;
-    bottom: 10px;
+    bottom: 0;
+    padding-bottom: 12px;
     visibility: hidden;
+    background: linear-gradient( 180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.7) 100%);
+    z-index: 1;
     &.staffBoxShow{
       visibility: initial;
     }
@@ -260,6 +282,7 @@
   background: rgba(255,255,255,.09);
   border-radius: 10px;
   padding: 12px 12px 0 12px;
+  overflow: hidden;
   .likeTitle {
     display: flex;
     align-items: center;
@@ -318,6 +341,19 @@
   .mEmpty{
     padding: 0;
   }
+  .btnImg{
+    display: flex;
+    justify-content: center;
+    margin-top: 3px;
+    margin-bottom: 12px;
+    &>img{
+      width: 88px;
+      height: 31px;
+      &:active{
+        opacity: 0.8;
+      }
+    }
+  }
 }
 
 .upward{
@@ -515,7 +551,7 @@
       z-index: 1;
       width: 100%;
       height: 100%;
-      border-radius: 6px;
+      border-radius: 8px;
     }
     .imgLabel{
       position: absolute;
@@ -540,6 +576,7 @@
       margin-top: 6px;
       .likeNum{
         display: flex;
+        align-items: center;
         border-radius: 3px;
         background-color: rgba(255,255,255,.22);
         padding: 1px 2px 1px 1px;
@@ -551,7 +588,7 @@
           font-weight: 400;
           font-size: 10px;
           color: #FFFFFF;
-          line-height: 14px;
+          line-height: 1;
           margin-left: 2px;
         }
       }
@@ -586,3 +623,39 @@
 .creationTablet{
 
 }
+
+.loadingPop {
+  position: fixed;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  width: 100vw;
+  height: var(--creationHeight, 100vh);
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  z-index: 999;
+  background: rgba(0, 0, 0, .5);
+  .loadingBox{
+    width: 98px;
+    height: 98px;
+    border-radius: 10px;
+    background-color: #fff;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    .lottie{
+      margin-top: -6px;
+      width: 52px;
+    }
+    .loadingTip {
+        margin-top: 4px;
+        font-size: 12px;
+        color: #333333;
+    }
+  }
+}

+ 66 - 17
src/views/creation/index.tsx

@@ -38,7 +38,7 @@ import iconPlay from './images/icon-play.png';
 import iconPause from './images/icon-pause.png';
 import { postMessage, promisefiyPostMessage } from '@/helpers/native-message';
 import { browser, getGradeCh, getSecondRPM, vaildMusicScoreUrl } from '@/helpers/utils';
-import { useRoute, useRouter } from 'vue-router';
+import { useRoute, useRouter, onBeforeRouteLeave } from 'vue-router';
 import {
   api_userMusicDetail,
   api_userMusicRemove,
@@ -53,7 +53,11 @@ import "plyr/dist/plyr.css";
 import Plyr from "plyr";
 import { Vue3Lottie } from "vue3-lottie";
 import audioBga from "./images/audioBga.json";
+import audioBga1 from "./images/leftCloud.json";
+import audioBga2 from "./images/rightCloud.json";
 import videobg from "./images/videobg.png";
+import playProgressData from "./playCreation/playProgress"
+import Loading from './loading';
 
 export default defineComponent({
   name: 'creation-detail',
@@ -62,6 +66,10 @@ export default defineComponent({
     const router = useRouter();
     const isScreenScroll = ref(false)
     const lottieDom = ref()
+    const lottieDom1 = ref()
+    const lottieDom2 = ref()
+    const mStickyBottom = ref()
+    const mStickyUpward = ref()
     const state = reactive({
       id: route.query.id,
       deleteStatus: false,
@@ -93,7 +101,10 @@ export default defineComponent({
     const staffState = reactive({
       staffSrc: "",
       isShow: false,
-      height:"initial"
+      height:"initial",
+      speedRate:1,
+      musicRenderType:"staff",
+      partIndex: 0
     })
     const staffDom= ref<HTMLIFrameElement>()
     const {playStaff, pauseStaff, updateProgressStaff} = staffMoveInstance()
@@ -191,14 +202,21 @@ export default defineComponent({
         const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
         const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
         player.on('play', () => {
-          lottieDom.value.play()
+          lottieDom.value?.play()
+          lottieDom1.value?.play()
+          lottieDom2.value?.play()
           playVisualDraw()
         });
         player.on('pause', () => {
-          lottieDom.value.pause()
+          lottieDom.value?.pause()
+          lottieDom1.value?.pause()
+          lottieDom2.value?.pause()
           pauseVisualDraw()
         });
       }
+      player.on('loadedmetadata', () => {
+        player.currentTime = playProgressData.playProgress
+      });
       player.on("timeupdate", ()=>{
         plyrState.currentTime = player.currentTime
       })
@@ -341,29 +359,37 @@ export default defineComponent({
     }
     function handlerLandscapeScreen(event:any){
       event.stopPropagation()
+      playProgressData.playState = !!state._plrl?.playing
+      playProgressData.playProgress = state._plrl?.currentTime || 0
       router.push({
         path:"/playCreation",
         query:{
           resourceUrl:encodeURIComponent(state.musicDetail?.videoUrl),
+          videoBgUrl:encodeURIComponent(state.musicDetail?.videoImg || ""),
           musicSheetName:encodeURIComponent(state.musicDetail?.musicSheetName),
           username:encodeURIComponent(state.musicDetail?.username),
-          musicSheetId:encodeURIComponent(state.musicDetail?.musicSheetId)
+          musicSheetId:encodeURIComponent(state.musicDetail?.musicSheetId),
+          speedRate:encodeURIComponent(staffState.speedRate),
+          musicRenderType:encodeURIComponent(staffState.musicRenderType),
+          partIndex:encodeURIComponent(staffState.partIndex),
         }
       })
     }
     // 初始化五线谱
     function initStaff(){
-      const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=staff`;
-      //const src = `http://192.168.3.68:3000/instrument.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=staff`;
+      const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
+      //const src = `http://192.168.3.122:3000/instrument.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
       staffState.staffSrc = src
       window.addEventListener('message', (event) => {
         const { api, height } = event.data;
         if (api === 'api_musicPage') {
           staffState.isShow = true
           staffState.height = height + "px"
-          // 如果是播放中自动开始 播放
-          if(state._plrl.playing){
-            playStaff()
+          // 如果是播放中自动开始播放  不是播放 自动跳转到当前位置
+          if(playProgressData.playState){
+            handlerClickPlay()
+          }else{
+            updateProgressStaff(state._plrl.currentTime)
           }
         }
       });
@@ -376,7 +402,7 @@ export default defineComponent({
             {
               api: 'api_playProgress',
               content: {
-                currentTime: state._plrl.currentTime
+                currentTime: state._plrl.currentTime * staffState.speedRate
               }
             },
             "*"
@@ -409,14 +435,14 @@ export default defineComponent({
           "*"
         )
 			}
-      const updateProgressStaff = (currentTime: string) => {
+      const updateProgressStaff = (currentTime: number) => {
         // 没渲染不执行
         if(!staffState.isShow) return
         staffDom.value?.contentWindow?.postMessage(
           {
             api: 'api_updateProgress',
             content: {
-              currentTime: state._plrl.currentTime
+              currentTime: currentTime * staffState.speedRate
             }
           },
           "*"
@@ -451,6 +477,13 @@ export default defineComponent({
           return;
         }
         state.musicDetail = res.data || {};
+        try{
+          const jsonConfig = JSON.parse(res.data.jsonConfig)
+          jsonConfig.speedRate && (staffState.speedRate = jsonConfig.speedRate)
+          jsonConfig.musicRenderType && (staffState.musicRenderType = jsonConfig.musicRenderType)
+          jsonConfig.partIndex && (staffState.partIndex = jsonConfig.partIndex)
+        }catch{
+        }
         // 五线谱
         initStaff()
         getStarList();
@@ -466,12 +499,23 @@ export default defineComponent({
       } catch {
         //
       }
+      requestAnimationFrame(()=>{
+        mStickyBottom.value?.onChnageHeight()
+        mStickyBottom.value?.onChnageHeight()
+      })
     });
 
     onUnmounted(() => {
       setStatusBarTextColor(false)
       cleanScrollEvent()
     });
+    onBeforeRouteLeave((to, from, next)=>{
+      if(to.path !== "/playCreation"){
+        playProgressData.playProgress = 0
+        playProgressData.playState = false
+      }
+      next()
+    })
     return () => (
       <div
         style={
@@ -509,6 +553,8 @@ export default defineComponent({
               <div class={styles.audioBox}>
                 <canvas class={styles.audioVisualizer} id="audioVisualizer"></canvas>
                 <Vue3Lottie ref={lottieDom} class={styles.audioBga} animationData={audioBga} autoPlay={false} loop={true}></Vue3Lottie>
+                <Vue3Lottie ref={lottieDom1} class={styles.audioBga1} animationData={audioBga1} autoPlay={false} loop={true}></Vue3Lottie>
+                <Vue3Lottie ref={lottieDom2} class={styles.audioBga2} animationData={audioBga2} autoPlay={false} loop={true}></Vue3Lottie>
                 <audio
                   crossorigin="anonymous"
                   id="audioMediaSrc"
@@ -525,7 +571,7 @@ export default defineComponent({
                 id="videoMediaSrc"
                 class={styles.videoBox}
                 src={state.musicDetail?.videoUrl}
-                data-poster={videobg}
+                data-poster={ state.musicDetail?.videoImg || videobg}
                 preload="metadata"
                 playsinline
               />
@@ -624,18 +670,18 @@ export default defineComponent({
               ))}
             </List>
           ) : (
-            <MEmpty class={styles.mEmpty} description="暂无数据" />
+            <MEmpty class={styles.mEmpty} image={"empty2"} description="暂无点赞记录" />
           )}
         </div>
         {
           !isScreenScroll.value &&
-          <MSticky position="bottom" offsetBottom={state.heightB - 1 + "px"} >
+          <MSticky ref={mStickyUpward} position="bottom" offsetBottom={state.heightB - 1 + "px"} >
             <div class={styles.upward}>
               <img src={iconUpward} />
             </div>
           </MSticky>
         }
-        <MSticky position="bottom" onBarHeight={(height: any) => {
+        <MSticky ref={mStickyBottom} position="bottom" onBarHeight={(height: any) => {
             console.log(height, 'height', height)
             state.heightB = height
         }}>
@@ -697,6 +743,9 @@ export default defineComponent({
             onClose={() => (state.shareStatus = false)}
           />
         </Popup>
+        {
+          !staffState.isShow && <Loading></Loading>
+        }
       </div>
     );
   }

+ 27 - 0
src/views/creation/loading.tsx

@@ -0,0 +1,27 @@
+import { defineComponent, ref, watch } from 'vue';
+import styles from './index.module.less';
+import { Vue3Lottie } from 'vue3-lottie';
+import loadingBg from './images/loading.json';
+
+export default defineComponent({
+  name: 'loading',
+  props: {
+    /** 提示文案 */
+    tipText: {
+      type: String,
+      default: '资源加载中...'
+    }
+  },
+  setup(props) {
+    return () => (
+      <div class={[styles.loadingPop,"osmdLoadingPop"]}>
+        <div class={styles.loadingBox}>
+          <Vue3Lottie
+            class={styles.lottie}
+            animationData={loadingBg}></Vue3Lottie>
+          <div class={styles.loadingTip}>{props.tipText}</div>
+        </div>
+      </div>
+    );
+  }
+});

+ 0 - 1
src/views/creation/login-model/index.tsx

@@ -199,7 +199,6 @@ export default defineComponent({
               zIndex={9999}
               v-model:value={state.imgCodeStatus}
               phone={state.username}
-              type="REGISTER"
               onClose={() => {
                 state.imgCodeStatus = false;
               }}

+ 38 - 7
src/views/creation/playCreation/index.module.less

@@ -14,6 +14,11 @@
       .plyr .plyr__controls__item.plyr__progress__container input{
         pointer-events: none;
       }
+      .osmdLoadingPop{
+        width: 100vh !important;
+        height: 100vw !important;
+        min-height: 100vw !important;
+      }
     }
   }
   &.notLoaded{
@@ -27,9 +32,13 @@
       .plyr {
           width: 100%;
           height: 100%;
+          z-index: initial;
           .plyr__controls{
               background: initial;
               padding: 0 20px 20px;
+              opacity: 1 !important;
+              transform: translateY(0) !important;
+              pointer-events: initial !important;
               .plyr__controls__item.plyr__control{
                   padding: 0;
                   width: 18px;
@@ -69,6 +78,7 @@
                       width: 12px;
                       height: 12px;
                       margin-top: -4px;
+                      box-shadow: initial;
                   }
                   .plyr__progress__buffer{
                       height: 4px;
@@ -103,17 +113,35 @@
       background: url("../images/audioBg.png") no-repeat;
       background-size: 100% 100%;
       position: relative;
-      .audioBga{
-          width: 100%;
-          height: 100%;
-          overflow: hidden;
-      }
+      overflow: hidden;
+      .audioBga {
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 100%;
+        height: 82%;
+    }
+
+    .audioBga1 {
+        position: absolute;
+        left: 0;
+        top: 60px;
+        width: 146px;
+    }
+
+    .audioBga2 {
+        width: 268px;
+        position: absolute;
+        right: -24px;
+        top: 0;
+    }
       :global {
           .plyr {
               position: absolute;
               height: initial;
               left: 0;
               bottom: 0;
+              z-index: 2;
           }
       }
       .audioVisualizer{
@@ -170,10 +198,13 @@
   }
   .staffBox{
     width: 100%;
-    height: var(--staffBoxHeight);
+    height: calc(var(--staffBoxHeight) + 44px);
     position: absolute;
-    bottom: 44px;
+    bottom: 0;
+    padding-bottom: 44px;
     visibility: hidden;
+    background: linear-gradient( 180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.7) 100%);
+    z-index: 1;
     &.staffBoxShow{
       visibility: initial;
     }

+ 74 - 40
src/views/creation/playCreation/index.tsx

@@ -6,12 +6,16 @@ import "plyr/dist/plyr.css";
 import Plyr from "plyr";
 import { Vue3Lottie } from "vue3-lottie";
 import audioBga from "../images/audioBga.json";
+import audioBga1 from "../images/leftCloud.json";
+import audioBga2 from "../images/rightCloud.json";
 import videobg from "../images/videobg.png";
 import backImg from "../images/back.png";
 import {
   postMessage
 } from '@/helpers/native-message';
 import { usePageVisibility } from '@vant/use';
+import playProgressData from "./playProgress"
+import Loading from '../loading';
 
 export default defineComponent({
   name: 'playCreation',
@@ -23,12 +27,16 @@ export default defineComponent({
     const musicSheetName = decodeURIComponent(route.query.musicSheetName as string || '');
     const username = decodeURIComponent(route.query.username as string || '');
     const musicSheetId = decodeURIComponent(route.query.musicSheetId as string || '');
+    const videoBgUrl = decodeURIComponent(route.query.videoBgUrl as string || '');
     const playType = resourceUrl.lastIndexOf('mp4') !== -1 ? 'Video' : 'Audio'
     const lottieDom = ref()
+    const lottieDom1 = ref()
+    const lottieDom2 = ref()
     const landscapeScreen = ref(false)
     let _plrl:any
     const playIngShow = ref(true)
     const loaded = ref(false)
+    let isInitAudioVisualDraw = false
     const { registerDrag, unRegisterDrag } = landscapeScreenDrag()
     watch(landscapeScreen, ()=>{
       if(landscapeScreen.value){
@@ -41,7 +49,10 @@ export default defineComponent({
     const staffState = reactive({
       staffSrc: "",
       isShow: false,
-      height:"initial"
+      height:"initial",
+      speedRate:Number(decodeURIComponent(route.query.speedRate as string || "1")),
+      musicRenderType:decodeURIComponent(route.query.musicRenderType as string || "staff"),
+      partIndex:Number(decodeURIComponent(route.query.partIndex as string || "0"))
     })
     const staffDom= ref<HTMLIFrameElement>()
     const {playStaff, pauseStaff, updateProgressStaff} = staffMoveInstance()
@@ -53,21 +64,8 @@ export default defineComponent({
       // 在微信中运行的时候,微信没有开放自动加载资源的权限,所以要等播放之后才显示播放控制器
       _plrl.on('loadedmetadata', () => {
         loaded.value = true
+        _plrl.currentTime = playProgressData.playProgress
       });
-      // 创建音波数据
-      if(playType === "Audio"){
-        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
-        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
-        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
-        _plrl.on('play', () => {
-          lottieDom.value.play()
-          playVisualDraw()
-        });
-        _plrl.on('pause', () => {
-          lottieDom.value.pause()
-          pauseVisualDraw()
-        });
-      }
       _plrl.on('play', () => {
         playIngShow.value = false
         playStaff()
@@ -147,13 +145,22 @@ export default defineComponent({
       type propsType = { canvWidth: number; canvHeight: number; canvFillColor: string; lineColor: string; lineGap: number }
       // canvas
       const canvasCtx = canvasDom.getContext("2d")!
-      const { width, height } = canvasDom.getBoundingClientRect()
+      let { width, height } = canvasDom.getBoundingClientRect()
+      // 这里横屏的时候需要旋转,所以宽高变化一下
+      if(landscapeScreen.value){
+        const _width = width
+        width = height
+        height = _width
+      }
       canvasDom.width = width
       canvasDom.height = height
       // audio
-      let audioCtx : AudioContext | null = null
-      let analyser : AnalyserNode | null = null
-      let source : MediaElementAudioSourceNode | null = null
+      const audioCtx = new AudioContext()
+      const source = audioCtx.createMediaElementSource(audioDom)
+      const analyser = audioCtx.createAnalyser()
+      analyser.fftSize = fftSize
+      source?.connect(analyser)
+      analyser.connect(audioCtx.destination)
       const dataArray = new Uint8Array(fftSize / 2)
       const draw = (data: Uint8Array, ctx: CanvasRenderingContext2D, { lineGap, canvWidth, canvHeight, canvFillColor, lineColor }: propsType) => {
         if (!ctx) return
@@ -216,14 +223,6 @@ export default defineComponent({
       }
       let isPause = true
       const playVisualDraw = () => {
-        if (!audioCtx) {
-          audioCtx = new AudioContext()
-          source = audioCtx.createMediaElementSource(audioDom)
-          analyser = audioCtx.createAnalyser()
-          analyser.fftSize = fftSize
-          source?.connect(analyser)
-          analyser.connect(audioCtx.destination)
-        }
         //audioCtx.resume()  // 重新更新状态   加了暂停和恢复音频音质发生了变化  所以这里取消了
         isPause = false
         requestAnimationFrameFun()
@@ -241,13 +240,35 @@ export default defineComponent({
     }
     function handlerBack(event:MouseEvent){
       event.stopPropagation()
+      playProgressData.playState = !!_plrl?.playing
+      playProgressData.playProgress = _plrl?.currentTime || 0
       router.back()
     }
     //点击改变播放状态
-    function handlerClickPlay(event:MouseEvent){
+    function handlerClickPlay(event?:MouseEvent){
+      //由于ios低版本必须在用户操作之后才能初始化 createMediaElementSource 所以必须在用户操作之后初始化
+      if(!isInitAudioVisualDraw && playType === "Audio"){
+        isInitAudioVisualDraw = true
+        // 创建音波数据
+        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
+        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
+        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
+        _plrl.on('play', () => {
+          lottieDom.value?.play()
+          lottieDom1.value?.play()
+          lottieDom2.value?.play()
+          playVisualDraw()
+        });
+        _plrl.on('pause', () => {
+          lottieDom.value?.pause()
+          lottieDom1.value?.pause()
+          lottieDom2.value?.pause()
+          pauseVisualDraw()
+        });
+      }
       // 原生 播放暂停按钮 点击的时候 不触发
       // @ts-ignore
-      if(event.target?.matches('button.plyr__control')){
+      if(event?.target?.matches('button.plyr__control')){
         return
       }
       if (_plrl.playing) {
@@ -289,17 +310,19 @@ export default defineComponent({
     });
     // 初始化五线谱
     function initStaff(){
-      const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${musicSheetId}&musicRenderType=staff`;
-      //const src = `http://192.168.3.68:3000/instrument.html#/simple-detail?id=${musicSheetId}&musicRenderType=staff`;
+      const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
+      //const src = `http://192.168.3.122:3000/instrument.html#/simple-detail?id=${musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
       staffState.staffSrc = src
       window.addEventListener('message', (event) => {
         const { api, height } = event.data;
         if (api === 'api_musicPage') {
           staffState.isShow = true
           staffState.height = height + "px"
-          // 如果是播放中自动开始 播放
-          if(_plrl.playing){
-            playStaff()
+          // 如果是播放中自动开始播放  不是播放 自动跳转到当前位置
+          if(playProgressData.playState){
+            handlerClickPlay()
+          }else{
+            updateProgressStaff(_plrl.currentTime)
           }
         }
       });
@@ -312,7 +335,7 @@ export default defineComponent({
             {
               api: 'api_playProgress',
               content: {
-                currentTime: _plrl.currentTime
+                currentTime: _plrl.currentTime * staffState.speedRate
               }
             },
             "*"
@@ -345,14 +368,14 @@ export default defineComponent({
           "*"
         )
       }
-      const updateProgressStaff = (currentTime: string) => {
+      const updateProgressStaff = (currentTime: number) => {
         // 没渲染不执行
         if(!staffState.isShow) return
         staffDom.value?.contentWindow?.postMessage(
           {
             api: 'api_updateProgress',
             content: {
-              currentTime
+              currentTime: currentTime * staffState.speedRate
             }
           },
           "*"
@@ -383,12 +406,18 @@ export default defineComponent({
       }
     })
     return () =>
-    <div id="landscapeScreenPlay" class={[styles.playCreation,landscapeScreen.value && styles.landscapeScreen,!loaded.value && styles.notLoaded]} onClick={handlerClickPlay}>
+    <div id="landscapeScreenPlay" class={[styles.playCreation,landscapeScreen.value && styles.landscapeScreen,!loaded.value && styles.notLoaded]}
+      onClick={
+        (event)=>{
+          staffState.isShow && handlerClickPlay(event)
+        }
+      }
+    >
       <div class={styles.backBox}>
         <img class={styles.backImg} src={backImg} onClick={handlerBack} />
         <div class={styles.musicDetail}>
           <div class={styles.musicSheetName}>{musicSheetName}</div>
-          <div class={styles.username}>{username}</div>
+          <div class={styles.username}>演奏:{username}</div>
         </div>
       </div>
       {
@@ -396,6 +425,8 @@ export default defineComponent({
           <div class={styles.audioBox}>
             <canvas class={styles.audioVisualizer} id="audioVisualizer"></canvas>
             <Vue3Lottie ref={lottieDom} class={styles.audioBga} animationData={audioBga} autoPlay={false} loop={true}></Vue3Lottie>
+            <Vue3Lottie ref={lottieDom1} class={styles.audioBga1} animationData={audioBga1} autoPlay={false} loop={true}></Vue3Lottie>
+            <Vue3Lottie ref={lottieDom2} class={styles.audioBga2} animationData={audioBga2} autoPlay={false} loop={true}></Vue3Lottie>
             <audio
               crossorigin="anonymous"
               id="audioMediaSrc"
@@ -410,7 +441,7 @@ export default defineComponent({
             id="videoMediaSrc"
             class={styles.videoBox}
             src={resourceUrl}
-            data-poster={videobg}
+            data-poster={ videoBgUrl || videobg}
             preload="metadata"
             playsinline
           />
@@ -436,6 +467,9 @@ export default defineComponent({
           </iframe>
         </div>
       }
+      {
+        !staffState.isShow && <Loading></Loading>
+      }
     </div>;
   }
 });

+ 6 - 0
src/views/creation/playCreation/playProgress.ts

@@ -0,0 +1,6 @@
+
+const playProgressData = {
+  playState: false,
+  playProgress: 0
+}
+export default playProgressData

+ 5 - 1
src/views/creation/share-model/index.module.less

@@ -51,7 +51,7 @@
     width: 56px;
     height: 56px;
     object-fit: cover;
-    border-radius: 6px;
+    border-radius: 8px;
   }
 
   .uploadImg {
@@ -118,6 +118,10 @@
     // border-image: linear-gradient(130deg, rgba(37, 156, 254, 1), rgba(68, 201, 255, 1)) 1 1;
     flex-shrink: 0;
     overflow: hidden;
+    transition: transform 0.3s ease;
+    &.animate{
+      transform: scale(1.1)
+    }
 
     .qrcodeCanvas {
       width: 100% !important;

+ 26 - 3
src/views/creation/share-model/index.tsx

@@ -194,7 +194,24 @@ export default defineComponent({
         }
       );
     });
-
+    let _time:any
+    const isAnimate = ref(false)
+    function startOpenOutLink(){
+      isAnimate.value = true
+      _time = setTimeout(() => {
+        isAnimate.value = false
+        postMessage({
+          api: 'openOutLink',
+          content : {
+            "url" : state.url
+          }
+        })
+      }, 1000);
+    }
+    function canceOpenOutLink(){
+      isAnimate.value = false
+      clearTimeout(_time)
+    }
     return () => (
       <div class={styles.shareModel}>
         <div class={styles.shareContent} id="shareContent">
@@ -233,7 +250,13 @@ export default defineComponent({
           </div>
 
           <div class={styles.downloadSection}>
-            <div class={styles.qrcode}>
+            <div class={[styles.qrcode,isAnimate.value && styles.animate]}
+                onMousedown={startOpenOutLink}
+                onTouchstart={startOpenOutLink}
+                onMouseup={canceOpenOutLink}
+                onMouseleave={canceOpenOutLink}
+                onTouchend={canceOpenOutLink}
+              >
               <canvas ref={canvasRef} class={styles.qrcodeCanvas}></canvas>
               <img src={smallLogo} class={styles.qrcodeLogo} />
             </div>
@@ -255,7 +278,7 @@ export default defineComponent({
             onClick={() => emit('close')}
           />
           <div class={styles.share__header}>海报已生成!快来分享吧!</div>
-          <Grid columnNum={5} border={false} class={styles.gridSection}>
+          <Grid columnNum={4} border={false} class={styles.gridSection}>
             <GridItem
               icon={iconDownload}
               text="保存本地"

+ 2 - 2
src/views/download/index.module.less

@@ -3,7 +3,7 @@
   background: url('./images/download_bg.png') no-repeat top center;
   background-size: cover;
   min-height: 100vh;
-  padding: 0 15px 0 23px;
+  padding: 6px 15px 0 23px;
   text-align: center;
 
   :global {
@@ -45,4 +45,4 @@
 .downImg {
   // width: 275px;
   padding-top: 25px;
-}
+}

Some files were not shown because too many files changed in this diff