瀏覽代碼

Merge branch 'feature-tianyong-newVersion' into ktyq-test-new

TIANYONG 1 年之前
父節點
當前提交
b076102d4b

+ 35 - 33
src/helpers/customMusicScore.ts

@@ -534,39 +534,41 @@ export const resetFormate = () => {
 		};
 
 		// 给小节添加背景色
-		staves.forEach((stave: any) => {
-			const list = [
-				Array.from(stave?.querySelectorAll(".vf-StaveSection") || []),
-				Array.from(stave?.querySelectorAll(".vf-Volta") || []),
-				Array.from(stave?.querySelectorAll(".vf-clef") || []),
-				Array.from(stave?.querySelectorAll(".vf-keysignature") || []),
-				Array.from(stave?.querySelectorAll(".vf-Repetition") || []),
-				Array.from(stave?.getElementsByTagName("text") || []),
-			].flat();
-			try {
-				if (list.length) {
-					list.forEach((_el: any) => {
-						stave?.removeChild(_el)
-						_el?.style?.setProperty("display", "none");
-					});
-				}
-			} catch (error) {}
-			const bbox = stave?.getBBox() || {};
-			const rect = `<rect class="vf-custom-bg" x="${bbox.x}" y="${bbox.y}" width="${bbox.width}" height="${bbox.height}" fill="#609FCF" />`
-			const rectBottom = `<rect class="vf-custom-bot" x="${bbox.x}" y="${bbox.y+bbox.height}" width="${bbox.width}" height="12" fill="#2B70A5" />`
-			const customG = `<g>${rect}${rectBottom}</g>`
-			try {
-				if (list.length) {
-					list.forEach((_el: any) => {
-						stave?.appendChild(_el)
-						_el?.style?.removeProperty("display");
-					});
-				}
-			} catch (error) {}
-			stave.innerHTML = customG + stave.innerHTML;
-		});
-		
-		state.vfmeasures = state.vfmeasures.concat(vfmeasures);
+		if (!state.isCreateImg) {
+			staves.forEach((stave: any) => {
+				const list = [
+					Array.from(stave?.querySelectorAll(".vf-StaveSection") || []),
+					Array.from(stave?.querySelectorAll(".vf-Volta") || []),
+					Array.from(stave?.querySelectorAll(".vf-clef") || []),
+					Array.from(stave?.querySelectorAll(".vf-keysignature") || []),
+					Array.from(stave?.querySelectorAll(".vf-Repetition") || []),
+					Array.from(stave?.getElementsByTagName("text") || []),
+				].flat();
+				try {
+					if (list.length) {
+						list.forEach((_el: any) => {
+							stave?.removeChild(_el)
+							_el?.style?.setProperty("display", "none");
+						});
+					}
+				} catch (error) {}
+				const bbox = stave?.getBBox() || {};
+				const rect = `<rect class="vf-custom-bg" x="${bbox.x}" y="${bbox.y}" width="${bbox.width}" height="${bbox.height}" fill="#609FCF" />`
+				const rectBottom = `<rect class="vf-custom-bot" x="${bbox.x}" y="${bbox.y+bbox.height}" width="${bbox.width}" height="12" fill="#2B70A5" />`
+				const customG = `<g>${rect}${rectBottom}</g>`
+				try {
+					if (list.length) {
+						list.forEach((_el: any) => {
+							stave?.appendChild(_el)
+							_el?.style?.removeProperty("display");
+						});
+					}
+				} catch (error) {}
+				stave.innerHTML = customG + stave.innerHTML;
+			});
+			state.vfmeasures = state.vfmeasures.concat(vfmeasures);
+		}
+
 	}
 	
 	// setTimeout(() => this.resetGlobalText());

+ 1 - 1
src/helpers/midiPlay.tsx

@@ -27,7 +27,7 @@ export const initMidi = (durationNum: number, midiUrl?: string) => {
       denominator: duration.denominator,
       numerator: duration.numerator,
       originalSpeed: state.originSpeed,
-      interval: 50,
+      interval: 16,
       duration: durationNum * 1000,
     }, () => {
       state.midiPlayIniting = false

+ 3 - 3
src/page-instrument/evaluat-model/evaluat-result/index.tsx

@@ -165,10 +165,10 @@ export default defineComponent({
               <div class={styles.tips}>{evaluatingData.resultData.clxtip}</div>
               <div class={styles.ctrls}>
                 <img src={zlycImg} class={[styles.ctrlsBtn, "evaluting-result-2"]} onClick={() => emit("close", "tryagain")} />
-                {!state.isHideEvaluatReportSaveBtn && evaluatingData.resultData.recordId ? (
+                {evaluatingData.resultData.recordId ? (
                   <div class={styles.saveBtn}>
-                    <img src={noSaveTips.value ? bczpJzImg : bczpImg} class={[styles.ctrlsBtn, "evaluting-result-3"]} onClick={() => {
-                      if (!noSaveTips.value) {
+                    <img src={noSaveTips.value ? bczpJzImg : bczpImg} class={[styles.ctrlsBtn, "evaluting-result-3"]} style={{ opacity: state.isHideEvaluatReportSaveBtn ? 0.4 : 1 }} onClick={() => {
+                      if (!noSaveTips.value && !state.isHideEvaluatReportSaveBtn) {
                         saveResult()
                       }
                     }} />

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

@@ -295,4 +295,11 @@
             max-width: 220px;
         }
     }
+}
+
+.hiddenPop {
+    width: 1px;
+    height: 1px;
+    overflow: hidden;
+    opacity: 0;
 }

+ 9 - 9
src/page-instrument/header-top/index.tsx

@@ -372,12 +372,8 @@ export default defineComponent({
     });
     /** 播放类型按钮 */
     const playTypeBtn = computed(() => {
-      // 选择模式,跟练模式 不显示
-      if (headTopData.modeType !== "show" || state.modeType === "follow") return { display: false, disabled: false };
-      // 评测开始 禁用
-      if (state.modeType === "evaluating") return { display: false, disabled: true };
-      // 音频播放中 禁用
-      if (state.playState === "play") return { display: true, disabled: true };
+      // 选择模式,跟练模式,评测模式 不显示
+      if (headTopData.modeType !== "show" || state.modeType === "follow" || state.modeType === "evaluating") return { display: false, disabled: false };
       if (!state.isAppPlay) {
         let index = 0;
         state.music && index++;
@@ -388,12 +384,16 @@ export default defineComponent({
         state.mingSong && songIndex++;
         // 演唱和演奏 都有数据的时间不禁用
         if (songIndex > 0 && index > 0) {
+          // 音频播放中 禁用
+          if(state.playState === "play"){
+            return { display: true, disabled: true }
+          }
           return { display: true, disabled: false };
         }
       }
       return {
-        disabled: true,
-        display: true,
+        disabled: false,
+        display: false,
       };
     });
     /** 模式切换按钮 */
@@ -826,7 +826,7 @@ export default defineComponent({
             playBtn.value.disabled && styles.disabled,
             state.platform === IPlatform.PC && state.musicScoreBtnDirection === "left" ? styles.playLeftButton : state.platform === IPlatform.PC && state.musicScoreBtnDirection === "right" ? styles.playRightButton : "",
           ]}
-          onClick={() => togglePlay()}
+          onClick={() => togglePlay(state.playState === "play" ? "paused" : "play")}
         >
           <div class={styles.btnWrap}>
             <img style={{ display: state.playState === "play" ? "none" : "" }} class={styles.iconBtn} src={headImg("icon_play.png")} />

+ 80 - 53
src/page-instrument/header-top/modeView.tsx

@@ -13,6 +13,9 @@ import state from "/src/state";
 import { studentQueryUserInfo } from "../api";
 import { usePageVisibility } from "@vant/use";
 import { Vue3Lottie } from "vue3-lottie";
+import { popImgs, hanldeConfirmPop, hanldeClosePop, evaluatingData } from "/src/view/evaluating"
+import { Popup } from "vant";
+import AbnormalPop from "/src/view/abnormal-pop";
 
 export default defineComponent({
   name: "modeView",
@@ -54,56 +57,80 @@ export default defineComponent({
         state.isVip = false;
         openGuid();
       }
-    };
-    const pageVisible = usePageVisibility();
-    watch(
-      () => pageVisible.value,
-      (val) => {
-        if (val === "visible") {
-          if (storeData.user.vipMember) return;
-          console.log("页面显示");
-          getUserInfo();
-        }
-      }
-    );
-    watch(
-      () => headTopData.modeType,
-      (value, oldValue) => {
-        // headTopData.modeType 值 刚开始是 ""  所以 第一次切换时候不触发播放动画
-        if (!oldValue) return;
-        nextTick(() => {
-          if (value === "show") {
-            modeImgDom1.value?.pause();
-            modeImgDom2.value?.pause();
-            modeImgDom3.value?.pause();
-          } else if (value === "init") {
-            modeImgDom1.value?.play();
-            modeImgDom2.value?.play();
-            modeImgDom3.value?.play();
-          }
-        });
-      }
-    );
-    onMounted(() => {
-      openGuid();
-    });
-    return () => (
-      <div class={[styles.modeView, headTopData.modeType !== "init" && styles.hidden]}>
-        <img
-          src={backImg}
-          class={styles.back}
-          onClick={() => {
-            headTopData.modeType = "show";
-          }}
-        />
-        <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={() => headTopData.handleChangeModeType("practise")}></Vue3Lottie>
-          {!state.isPercussion && <Vue3Lottie ref={modeImgDom2} class={styles.modeImg} animationData={glMode} autoPlay={false} loop={true} onClick={() => headTopData.handleChangeModeType("follow")}></Vue3Lottie>}
-          {state.enableEvaluation && <Vue3Lottie ref={modeImgDom3} class={styles.modeImg} animationData={pcMode} autoPlay={false} loop={true} onClick={() => headTopData.handleChangeModeType("evaluating")}></Vue3Lottie>}
-        </div>
-        {data.showVip && <TheVip />}
-      </div>
-    );
-  },
-});
+      const pageVisible = usePageVisibility()
+      watch(
+         () => pageVisible.value,
+         val => {
+            if (val === "visible") {
+               if (storeData.user.vipMember) return
+               console.log("页面显示")
+               getUserInfo()
+            }
+         }
+      )
+      watch(() => headTopData.modeType, (value,oldValue) => {
+         // headTopData.modeType 值 刚开始是 ""  所以 第一次切换时候不触发播放动画
+         if(!oldValue) return
+         nextTick(()=>{
+            if(value === "show"){
+               modeImgDom1.value?.pause()
+               modeImgDom2.value?.pause()
+               modeImgDom3.value?.pause()
+            }else if(value === "init"){
+               modeImgDom1.value?.play()
+               modeImgDom2.value?.play()
+               modeImgDom3.value?.play()
+            }
+         })
+      })
+      onMounted(() => {
+         openGuid()
+      })
+      watch(
+         () => evaluatingData.socketErrorStatus,
+         () => {
+           if (evaluatingData.socketErrorStatus === 2) {
+             setTimeout(() => {
+               evaluatingData.socketErrorPop = false;
+             }, 1000);
+           }
+         }
+       );      
+      return () => (
+         <div class={[styles.modeView, headTopData.modeType !== "init" && styles.hidden]}>
+            <img
+               src={backImg}
+               class={styles.back}
+               onClick={() => {
+                  headTopData.modeType = "show"
+               }}
+            />
+            <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={() => headTopData.handleChangeModeType("practise")}></Vue3Lottie>
+               {
+                  !state.isPercussion && <Vue3Lottie ref={modeImgDom2} class={styles.modeImg} animationData={glMode} autoPlay={false} loop={true} onClick={() => headTopData.handleChangeModeType("follow")}></Vue3Lottie>
+               }
+               {
+                  state.enableEvaluation && <Vue3Lottie ref={modeImgDom3} class={styles.modeImg} animationData={pcMode} autoPlay={false} loop={true} onClick={() => headTopData.handleChangeModeType("evaluating")}></Vue3Lottie>
+               }
+            </div>
+            {data.showVip && <TheVip />}
+            {/** 延迟检测中途,socket出错,网络提示弹窗 */}
+            <div>
+               <Popup teleport="body" closeOnClickOverlay={false} class={["popup-custom", "van-scale"]} transition="van-scale" v-model:show={evaluatingData.socketErrorPop}>
+                  <AbnormalPop onConfirm={hanldeConfirmPop} onClose={hanldeClosePop} />
+               </Popup>
+            </div>            
+         </div>
+      )
+   }
+})

+ 3 - 2
src/page-instrument/view-detail/index.tsx

@@ -151,6 +151,7 @@ export default defineComponent({
         await getMusicDetail(id);
       } catch (err) {
         console.error(err)
+        state.isLoading = false;
         isEmptyMusicShow.value = true
         return
       }
@@ -336,13 +337,13 @@ export default defineComponent({
           } else {
             return {
               container: {
-                paddingRight: state.fingeringInfo.width,
+                paddingLeft: state.fingeringInfo.width,
               },
               fingerBox: {
                 position: "absolute",
                 width: state.fingeringInfo.width,
                 height: "80%",
-                right: 0,
+                left: 0,
                 top: 0,
               },
             };

+ 20 - 5
src/state.ts

@@ -545,6 +545,8 @@ const state = reactive({
   noSavePopShow: true,
   /** xml里面是否有歌词 */
   xmlHasLyric: false,
+  /** 生成图片的模式 */
+  isCreateImg: false,
 });
 const browserInfo = browser();
 let offset_duration = 0;
@@ -759,16 +761,16 @@ export const skipNotePlay = async (itemIndex: number, isStart = false) => {
 
 /**
  * 切换曲谱播放状态
- * @param playState 可选: 默认 undefined, 需要切换的状态 play:播放, paused: 暂停
+ * @param playState 需要切换的状态 play:播放, paused: 暂停
  */
-export const togglePlay = async (playState?: "play" | "paused", sourceType?: string) => {
+export const togglePlay = async (playState: "play" | "paused", sourceType?: string) => {
   // 如果mp3资源还在加载中,给出提示
   if (!state.isAppPlay && !state.audioDone) {
     if (sourceType !== 'courseware') showToast('音频资源加载中,请稍后')
     return
   }
   // 播放之前  当为评测模式和不为MIDI时候按  是否禁用节拍器  切换音源
-  if ((playState ? playState : state.playState === "paused" ? "play" : "paused") === 'play' && state.modeType === "practise" && state.playMode !== "MIDI") {
+  if (playState === 'play' && state.modeType === "practise" && state.playMode !== "MIDI") {
     console.log("设置音源")
     changeSongSourceByBate(metronomeData.disable)
   }
@@ -779,6 +781,8 @@ export const togglePlay = async (playState?: "play" | "paused", sourceType?: str
         songID: state.examSongId,
       })
       state.playState = 'paused'
+      // 当在节拍器播放期间暂停的话 就暂停节拍器
+      closeTick()
       return
     }
     skipNotePlay(state.activeNoteIndex, false);
@@ -791,7 +795,7 @@ export const togglePlay = async (playState?: "play" | "paused", sourceType?: str
     const status = cloudGetMediaStatus?.content.status === "suspend" ? "play" : "paused"
     state.playState = status
   } else {
-    state.playState = playState ? playState : state.playState === "paused" ? "play" : "paused";
+    state.playState = playState;
   }
   if (state.playState === "play" && state.sectionStatus && state.section.length == 2 && state.playProgress === 0) {
     resetPlaybackToStart();
@@ -1358,7 +1362,13 @@ function initMusicSource(data: any, track?: string) {
   })
   // 当没有任何曲目的时候报错
   if (!musicObj?.audioFileUrl && !accompanyObj?.audioFileUrl && !fanSongObj?.audioFileUrl && !banSongObj?.audioFileUrl && !fanSongObj?.solmizationFileUrl) {
-    throw new Error("该曲目无任何音源");
+    // 并且是midi没有midi文件的时候
+    if(data.playMode === "MIDI" && !data.midiFileUrl) {
+      // 是预览的时候 不报错
+      if(!query.isPreView){
+        throw new Error("该曲目无任何音源");
+      }
+    }
   }
   Object.assign(state, {
     music: musicObj?.audioFileUrl,
@@ -1748,6 +1758,11 @@ watch(
       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")
+        // 预备小节
+        if(state.sectionFirst && measureNum === state.sectionFirst.MeasureNumberXML){
+          item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
+          item?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
+        }
       } else {
         // 有选段只清除选段处的
         if (state.section.length === 2) {

+ 7 - 4
src/view/evaluating/index.tsx

@@ -653,7 +653,6 @@ const handleSocketStatus = (res?: IPostMessage) => {
     const diffTime = currentTime - socketStartTime;
     if (diffTime < 1000) {
       const remainingTime = 1000 - diffTime;
-      console.log(remainingTime, 99999);
       setTimeout(() => {
         evaluatingData.socketErrorStatus = 2;
       }, remainingTime);
@@ -662,14 +661,14 @@ const handleSocketStatus = (res?: IPostMessage) => {
 };
 
 // 评测出现异常,再试一次
-const hanldeConfirmPop = async () => {
+export const hanldeConfirmPop = async () => {
   api_checkSocketStatus();
   evaluatingData.socketErrorStatus = 1;
   socketStartTime = +new Date();
 };
 
 // 关闭异常弹窗
-const hanldeClosePop = () => {
+export const hanldeClosePop = () => {
   evaluatingData.socketErrorPop = false;
   evaluatingData.socketErrorStatus = 0;
 };
@@ -771,7 +770,11 @@ export default defineComponent({
       api_remove_recordStartTime(recordStartTimePoint);
       handle_reduction();
       removeAccompanyError(handleAccompanyError);
-      removeSocketStatus(handleSocketStatus);
+      if (evaluatingData.socketErrorPop && state.setting.soundEffect) {
+        console.log('延迟检测出错')
+      } else {
+        removeSocketStatus(handleSocketStatus);
+      }
       api_disconnectSocket();
       console.log("卸载评测模块成功");
     });

+ 6 - 4
src/view/music-score/index.module.less

@@ -43,10 +43,12 @@
             stroke: #FFC121;
         }
     }
-    .vf-stave {
-        >path {
-            fill: rgba(255,255,255,0.5);
-            stroke: rgba(255,255,255,0.5);
+    .blueMusicXml {
+        .vf-stave {
+            >path {
+                fill: rgba(255,255,255,0.5);
+                stroke: rgba(255,255,255,0.5);
+            }
         }
     }
     .vf-custom-rect {

+ 4 - 2
src/view/music-score/index.tsx

@@ -94,7 +94,8 @@ export default defineComponent({
 				defaultColorMusic: props.musicColor, // 颜色
 				// pageBackgroundColor: '#609FCF',
 				renderSingleHorizontalStaffline: state.isSingleLine ? true : false,
-				autoGenerateMultipleRestMeasuresFromRestMeasures: state.isSingleLine ? false : true, // 连续休止小节是否合并显示
+				// autoGenerateMultipleRestMeasuresFromRestMeasures: state.isSingleLine ? false : true, // 连续休止小节是否合并显示
+				autoGenerateMultipleRestMeasuresFromRestMeasures: true,
 				drawLyrics: (state.playType === 'sing' && !state.isSimplePage) ? true : false, // 演唱模式才渲染歌词,simple页面不显示歌词
 				// darkMode: true, // 暗黑模式
 				// pageFormat: 'A4_P',
@@ -217,7 +218,8 @@ export default defineComponent({
 				class={[
 					isInTheGradualRange.value && styles.inGradualRange,
 					state.musicRenderType == EnumMusicRenderType.staff ? "staff" : "jianpuTone",
-					state.isSingleLine && "singleLineMusicBox"
+					state.isSingleLine && "singleLineMusicBox",
+					!state.isCreateImg ? "blueMusicXml" : ""
 				]}
 			>
 				{slots.default?.()}

+ 2 - 3
src/view/selection/index.module.less

@@ -138,9 +138,8 @@
     width: 20px;
     height: 20px;
     border-radius: 50%;
-    background-color: rgb(255, 145, 0);
-    color: #fff;
-    font-weight: bold;
+    background-color: #FFC121;
+    color: #673207;
     font-size: 14px;
 }
 

+ 1 - 1
src/view/transfer-to-img/index.module.less

@@ -29,4 +29,4 @@
             max-height: initial !important;
         }
     }
-}
+}

+ 1 - 0
src/view/transfer-to-img/index.tsx

@@ -41,6 +41,7 @@ export default defineComponent({
 
 		onMounted(() => {
 			(window as any).appName = "colexiu";
+			state.isCreateImg = true;
 			state.isEvxml = true;
 			state.xmlUrl = decodeURIComponent(query.xmlUrl);
 			const specialXmls = ['https://oss.dayaedu.com/MECMP/1715332965751.xml','https://oss.dayaedu.com/MECMP/1715326622946.xml'];