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

Merge branch 'hqyDevNewVersion' of http://git.dayaedu.com/liushengqiang/music-score into feature-tianyong-newVersion

TIANYONG 11 месяцев назад
Родитель
Сommit
2f0a8be78b

+ 4 - 0
src/page-instrument/header-top/index.module.less

@@ -93,6 +93,7 @@
     }
 }
 .modeChangeBox{
+    cursor: pointer;
     position: fixed;
     top: 20px;
     right: 30px;
@@ -264,6 +265,7 @@
 }
 
 .playBtn {
+    cursor: pointer;
     position: fixed;
     right: 30px;
     bottom: 12px;
@@ -301,6 +303,7 @@
 }
 
 .resetBtn {
+    cursor: pointer;
     position: fixed;
     right: 100px;
     bottom: 12px;
@@ -387,6 +390,7 @@
             }
         }
         > .modeImg {
+            cursor: pointer;
             width: calc((100% - 2*40px)/3);
             max-width: 220px;
         }

+ 6 - 2
src/page-instrument/header-top/modeView.tsx

@@ -107,7 +107,9 @@ export default defineComponent({
           src={backImg}
           class={styles.back}
           onClick={() => {
-            smoothAnimationState.isShow.value = state.melodyLine;
+            if(state.isSingleLine){
+              smoothAnimationState.isShow.value = state.melodyLine;
+            }
             // 返回的时候 跳转到之前记录的模式
             if(headTopData.oldModeType !== "practise"){
               // 点击评测模式进入评测模块的需要检测耳机状态,通过返回按钮进入评测模块的,不检测耳机状态
@@ -120,7 +122,9 @@ export default defineComponent({
         <img src={nameImg} class={styles.name} />
         <div class={[styles.modeBox, ((!state.isPercussion && !state.enableEvaluation) || (state.isPercussion && state.enableEvaluation) || (state.isPercussion && !state.enableEvaluation)) && styles.twoModeBox]}>
           <Vue3Lottie ref={modeImgDom1} class={styles.modeImg} animationData={lxMode} autoPlay={false} loop={true} onClick={() => {
-            smoothAnimationState.isShow.value = state.melodyLine;
+            if(state.isSingleLine){
+              smoothAnimationState.isShow.value = state.melodyLine;
+            }
             headTopData.handleChangeModeType("practise")
             } }></Vue3Lottie>
           {!state.isPercussion && <Vue3Lottie ref={modeImgDom2} class={styles.modeImg} animationData={glMode} autoPlay={false} loop={true} onClick={() => headTopData.handleChangeModeType("follow")}></Vue3Lottie>}

+ 28 - 0
src/page-instrument/view-detail/index.module.less

@@ -221,6 +221,14 @@
     }
 }
 
+@keyframes rotate {
+    from {
+        transform: rotate(0deg);
+    }
+    to {
+        transform: rotate(360deg);
+    }
+}
 .loadingPop {
     position: fixed;
     left: 0;
@@ -241,6 +249,26 @@
             color: #999;
         }
     }
+    .loadingCssBox{
+        width: 27px;
+        height: 27px;
+        display: flex;
+        justify-content: space-between;
+        flex-wrap: wrap;
+        align-content: space-between;
+        margin-bottom: 24px;
+        animation: rotate 1.5s linear infinite;
+        .loadingCssItem{
+            width: 11px;
+            height: 11px;
+            border-radius: 50%;
+            background: #20BDFF;
+            opacity: 0.5;
+            &:nth-child(2){
+                opacity:1;
+            }
+        }
+    }
     .lottie{
         width: 120px;
     }

+ 17 - 1
src/page-instrument/view-detail/index.tsx

@@ -38,6 +38,7 @@ import { initSmoothAnimation } from "./smoothAnimation"
 import EmptyMusic, { isEmptyMusicShow } from "./emptyMusic"
 import { position } from "html2canvas/dist/types/css/property-descriptors/position";
 import Loading from "./loading"
+import LoadingCss from "./loadingCss"
 // import bgJson from "./images/index.json";
 import bg2Left from "./images/bg2_left_zs.png";
 import bg2Right from "./images/bg2_right_zs.png";
@@ -308,6 +309,20 @@ export default defineComponent({
       // pushAppMusic();
       // console.timeEnd("渲染加载耗时");
     };
+    function handleOnRendered(osmd: any) {
+      try{
+        handleRendered(osmd)
+      }catch(err){
+        console.log("webApi_beatTimes",err)
+        window.parent.postMessage(
+          {
+            api: "webApi_beatTimes",
+            data: "-1"
+          },
+          "*"
+        );
+      }
+    }
     /** 指法配置 */
     const fingerConfig = computed<any>(() => {
       if (state.setting.displayFingering && state.fingeringInfo?.name) {
@@ -541,7 +556,7 @@ export default defineComponent({
               ref={musicScoreRef}
               musicColor={state.isPreView ? '#000000' : '#FFFFFF'}
               showPartNames={state.isCombineRender}
-              onRendered={handleRendered} 
+              onRendered={handleOnRendered} 
             > 
               {/* 旋律线关闭时候的 标题和作者 */}
               <AuthorName></AuthorName>
@@ -610,6 +625,7 @@ export default defineComponent({
           </>
         )}
         <Loading tipText={state.loadingText} />
+        <LoadingCss />
         <Popup
           zIndex={5050}
           teleport="body"

+ 21 - 0
src/page-instrument/view-detail/loadingCss.tsx

@@ -0,0 +1,21 @@
+import { defineComponent, ref} from "vue"
+import styles from "./index.module.less"
+import state from "/src/state"
+
+export const isLoadingCss = ref(false)
+export default defineComponent({
+   name: "loadingCss",
+   setup() {
+      return () => (
+         <div class={[styles.loadingPop, state.isPreView && styles.isPreView]} style={{ display: isLoadingCss.value ? "flex" : "none" }}>
+            <div class={styles.loadingCssBox}>
+                <div class={styles.loadingCssItem}></div>
+                <div class={styles.loadingCssItem}></div>
+                <div class={styles.loadingCssItem}></div>
+                <div class={styles.loadingCssItem}></div>
+            </div>
+            <div class={styles.loadingTip}>正在加载中,请稍等…</div>
+         </div>
+      )
+   }
+})

+ 19 - 6
src/state.ts

@@ -1893,9 +1893,15 @@ watch(
     // const matchMeasureNum = state.activeMeasureIndex - needReduceMultipleRestNum - 1
     // console.log('选中的小节',matchMeasureNum,'需要减去的小节',needReduceMultipleRestNum,'当前的小节',state.activeMeasureIndex)
     state.vfmeasures.forEach((item: any, idx: number) => {
-      const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : -1;
-      const nextMeasureNum = state.vfmeasures[idx+1]?.getAttribute('data-num') ? Number(state.vfmeasures[idx+1]?.getAttribute('data-num')) : -1;
-      if (measureNum >= 0 && (measureNum === state.activeMeasureIndex || (measureNum < state.activeMeasureIndex && nextMeasureNum > state.activeMeasureIndex)) || (measureNum < state.activeMeasureIndex && nextMeasureNum == -1) ) {
+      const dataNum = item.getAttribute('data-num')  // 值可能为字符串类型的undefined
+      const measureNum = (dataNum && dataNum !== "undefined") ? Number(dataNum) : -1;
+      let nextDataNum = state.vfmeasures[idx+1]?.getAttribute('data-num')
+      // 当有换行小节,下个小节的nextDataNum是undefined,所以这里需要往后找一个
+      if(!(nextDataNum && nextDataNum !== "undefined")){
+        nextDataNum = state.vfmeasures[idx + 2]?.getAttribute('data-num')
+      }
+      const nextMeasureNum = Number(nextDataNum)
+      if (measureNum >= 0 && (measureNum === state.activeMeasureIndex || (measureNum < state.activeMeasureIndex && nextMeasureNum > state.activeMeasureIndex))) {
         item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
         item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
         // 预备小节
@@ -1945,7 +1951,8 @@ watch(
         rightMeasureNumberXML = state.section[0].MeasureNumberXML
       }
       state.vfmeasures.forEach((item: any, idx: number) => {
-        const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : 1;
+        const dataNum = item.getAttribute('data-num')  // 值可能为字符串类型的undefined
+        const measureNum = (dataNum && dataNum !== "undefined") ? Number(dataNum) : -1;
         // 小于选中置灰
         if (measureNum < leftMeasureNumberXML) {
           item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(96,159,207,0.5)")
@@ -1965,8 +1972,14 @@ watch(
     }else{
       // 恢复选段前
       state.vfmeasures.forEach((item: any, idx: number) => {
-        const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : -1;
-        const nextMeasureNum = state.vfmeasures[idx+1]?.getAttribute('data-num') ? Number(state.vfmeasures[idx+1]?.getAttribute('data-num')) : -1;
+        const dataNum = item.getAttribute('data-num')  // 值可能为字符串类型的undefined
+        const measureNum = (dataNum && dataNum !== "undefined") ? Number(dataNum) : -1;
+        let nextDataNum = state.vfmeasures[idx+1]?.getAttribute('data-num')
+        // 当有换行小节,下个小节的nextDataNum是undefined,所以这里需要往后找一个
+        if(!(nextDataNum && nextDataNum !== "undefined")){
+          nextDataNum = state.vfmeasures[idx + 2]?.getAttribute('data-num')
+        }
+        const nextMeasureNum = Number(nextDataNum)
         if (measureNum >= 0 && (measureNum === state.activeMeasureIndex || (measureNum < state.activeMeasureIndex && nextMeasureNum > state.activeMeasureIndex)) ) {
           item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
           item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")

+ 26 - 4
src/view/audio-list/index.tsx

@@ -119,9 +119,11 @@ export const setAudioCurrentTime = (time: number, index = 0) => {
 		setMidiCurrentTime(index);
 		return;
 	}
+	if(state.playSource === "mingSong") {
+		audioData.mingSongEle && (audioData.mingSongEle.currentTime = time);
+	}
 	audioData.songEle && (audioData.songEle.currentTime = time);
 	audioData.backgroundEle && (audioData.backgroundEle.currentTime = time);
-	audioData.mingSongEle && (audioData.mingSongEle.currentTime = time);
 	audioData.progress = time;
 };
 
@@ -145,7 +147,13 @@ export const toggleMutePlayAudio = (source: IPlayState, muted: boolean) => {
 /** 切换节拍器音源 */
 export const changeSongSourceByBate = (isDisBate:boolean) => {
 	// isDisBate 为true 切换到不带节拍的,为false 切换到带节拍的
-	const currentTime = audioData.songEle?.currentTime || audioData.backgroundEle?.currentTime || audioData.mingSongEle?.currentTime || audioData.progress || 0
+	let currentTime
+	if(state.playSource === "mingSong"){
+		currentTime = audioData.mingSongEle?.currentTime
+	}else{
+		currentTime = audioData.songEle?.currentTime || audioData.backgroundEle?.currentTime
+	}
+	currentTime || (currentTime = audioData.progress || 0)
 	if (isDisBate) {
 		if(state.playType === "play"){
 			audioData.songEle = audioData.songCollection.songEle
@@ -168,7 +176,10 @@ export const changeSongSourceByBate = (isDisBate:boolean) => {
 	}
 	audioData.songEle && (audioData.songEle.currentTime = currentTime)
 	audioData.backgroundEle && (audioData.backgroundEle.currentTime = currentTime)
-	audioData.mingSongEle && (audioData.mingSongEle.currentTime = currentTime)
+	// 当前是唱名才设置时间
+	if(state.playSource === "mingSong") {
+		audioData.mingSongEle && (audioData.mingSongEle.currentTime = currentTime)
+	}
 	// 设置静音与取消静音
 	if (state.playSource === "music") {
 		audioData.songEle && (audioData.songEle.muted = false);
@@ -234,13 +245,24 @@ export default defineComponent({
 			}
 			return new Promise((resolve) => {
 				const a = new Audio(src + '?v=' + Date.now());
-				a.load();
 				a.onloadedmetadata = () => {
 					resolve(a);
 				};
 				a.onerror = () => {
 					resolve(null);
 				};
+				// 当未加载 资源之前 切换到其他浏览器标签,浏览器可能会禁止资源加载所以无法触发onloadedmetadata事件,导致一直在加载中,这里做个兼容
+				if (document.visibilityState === 'visible') {
+					a.load();
+				} else {
+					const onVisibilityChange = () => {
+						if (document.visibilityState === 'visible') {
+							document.removeEventListener('visibilitychange', onVisibilityChange);
+							a.load();
+						}
+					};
+					document.addEventListener('visibilitychange', onVisibilityChange);
+				}
 			});
 		};
 

+ 1 - 1
src/view/fingering/index.tsx

@@ -37,7 +37,7 @@ export default defineComponent({
 
     const doubeClick = () => {
       // 如果在评测和跟练中,双击指法不跳转
-      if ((state.modeType === 'evaluating' && evaluatingData.startBegin) || (state.modeType === 'follow' && followData.start)) {
+      if ((state.modeType === 'evaluating' && evaluatingData.startBegin) || (state.modeType === 'follow' && followData.start) || state.playState === "play") {
         return;
       }
       const nowTime = Date.now();

+ 3 - 3
src/view/music-score/index.tsx

@@ -11,6 +11,7 @@ import { resetFormate, resetGivenFormate, setGlobalMusicSheet, limitSingleSvgPag
 import { setGlobalData } from "/src/utils";
 import Loading from "/src/view/audio-list/loading"
 import { storeData } from "/src/store";
+import { isLoadingCss } from "/src/page-instrument/view-detail/loadingCss"
 
 export const musicRenderTypeKey = "musicRenderType";
 let osmd: any = null;
@@ -199,6 +200,7 @@ export default defineComponent({
 		/** 刷新曲谱 */
 		const refreshMusicScore = async () => {
 			console.log('刷新谱面123')
+			isLoadingCss.value = true
 			const container = document.getElementById('musicAndSelection'), svgDom = document.getElementById('osmdCanvasPage1'), selectionBox = document.getElementById('selectionBox');
 			if (container && svgDom) {
 				container?.removeChild(svgDom)
@@ -209,8 +211,6 @@ export default defineComponent({
 			state.osmd.clear();
 			musicData.isRenderLoading = true;
 			musicData.isRefreshLoading = true;
-			state.loadingText = '正在加载中,请稍等…'
-			state.isLoading = true;
 			// 在下一帧再执行,确保出现loading
 			requestAnimationFrame(async ()=>{
 				getContainerWidth();
@@ -219,8 +219,8 @@ export default defineComponent({
 				await init();
 				musicData.isRenderLoading = false;
 				musicData.isRefreshLoading = false;
-				state.isLoading = false;
 				musicData.showSelection = true;
+				isLoadingCss.value = false
 			})
 		}
 		expose({