瀏覽代碼

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

黄琪勇 10 月之前
父節點
當前提交
716be3dc58

+ 2 - 2
public/flexible.js

@@ -16,8 +16,8 @@
       f.style.fontSize = c + "px", k.rem = a.rem = c
       window.fontSize = c
     } catch (error) {
-      f.style.fontSize = 64 + "px"
-      window.fontSize = 64
+      f.style.fontSize = 37.5 + "px"
+      window.fontSize = 37.5
     }
 
   }

+ 13 - 6
src/helpers/customMusicScore.ts

@@ -539,20 +539,22 @@ export const resetFormate = () => {
 
 		// 给小节添加背景色
 		if (!state.isCreateImg && !state.isPreView) {
-			staves.forEach((stave: any) => {
+			staves.forEach((stave: any,i: number) => {
 				const list = [
+					Array.from(stave?.getElementsByTagName("text") || []),
 					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");
+							if (_el.parentNode === stave) {
+								stave?.removeChild(_el)
+								_el?.style?.setProperty("display", "none");
+							}
 						});
 					}
 				} catch (error) {}
@@ -592,14 +594,19 @@ const transSinglePage = () => {
 	if (state.isSingleLine && !state.isSimplePage) {
 		const svgPage = document?.getElementById('osmdSvgPage1')?.getBoundingClientRect();
 		const staffLine = document?.querySelector('.staffline')?.getBoundingClientRect();
-		if (svgPage && staffLine && svgPage.height > 200) {
+		if (svgPage && staffLine && svgPage.height > 200 && state.platform !== 'PC') {
 			// 需要上移的距离
-			console.log('need',svgPage.height,staffLine.height)
+			// console.log('need',svgPage.height,staffLine.height)
 			const rate = svgPage.height > 400 ? 1.2 : 2;
 			const needTransTop = (svgPage.height - staffLine.height) / rate;
 			// @ts-ignore
 			document.getElementById('osmdSvgPage1').style.transform = `translateY(-${needTransTop}px)`;
 			// document.querySelector('.staffline').style.transform = `translateY(-${needTransTop}px)`;
+			// const musicLine =  document.querySelector('.staffline').querySelector('.vf-measure').querySelector('.vf-custom-bg').getBoundingClientRect();
+			// const needTransDistance = svgPage.height / 2 - (musicLine.top - svgPage.top)
+			// console.log('svg移动距离',needTransDistance)
+			// // @ts-ignore
+			// document.getElementById('osmdSvgPage1').style.transform = `translateY(${needTransDistance}px)`
 		}
 	}
 }

+ 16 - 4
src/page-instrument/evaluat-model/index.tsx

@@ -43,6 +43,8 @@ let calculateInfo: any = {};
 let checkErjiTimer: any = null
 
 export const reCheckDelay = () => {
+  evaluatingData.onceErjiPopShow = false;
+  evaluatingData.needCheckErjiStatus = true;
   headTopData.settingMode = false
   state.setting.soundEffect = false
   api_startDelayCheck({});
@@ -140,8 +142,14 @@ export default defineComponent({
         // const erji = await checkUseEarphone();
         const res = await getEarphone();
         const erji = res?.content?.checkIsWired || false;
-        console.log("耳机状态111", res);
-        evaluatingData.earphoneMode = true;
+        // 是否已经提示过耳机弹窗,重新进入评测页面,重置该状态为false,手动关掉耳机弹窗,改变该状态为true,本次评测都不在提示耳机状态弹窗
+        if (!evaluatingData.onceErjiPopShow) {
+          evaluatingData.earphoneMode = true;
+        } else {
+          clearTimeout(checkErjiTimer);
+          checkErjiTimer = null;
+          return;
+        }
         evaluatingData.earPhoneType = res?.content?.type || "";
         if (evaluatingData.earPhoneType === "有线耳机") {
           clearTimeout(checkErjiTimer);
@@ -303,7 +311,7 @@ export default defineComponent({
         speed: evaluatSpeed,
         heardLevel: state.setting.evaluationDifficulty,
         // beatLength: Math.round((state.fixtime * 1000) / rate),
-        beatLength: actualBeatLength,
+        beatLength: actualBeatLength / rate,
         evaluationCriteria: state.evaluationStandard,
         speedRate: parseFloat(rate.toFixed(2)), // 播放倍率
       };
@@ -506,7 +514,10 @@ export default defineComponent({
         await api_startDelayCheck({});
       } else {
         evaluatingData.checkEnd = true;
-        checkEarphoneStatus();
+        // 点击评测模式进入评测模块的需要检测耳机状态,通过返回按钮进入评测模块的,不检测耳机状态
+        if (evaluatingData.needCheckErjiStatus) {
+          checkEarphoneStatus();
+        }
       }
       evaluatingData.isDisabledPlayMusic = true;
       // handlePerformDetection();
@@ -587,6 +598,7 @@ export default defineComponent({
           <Earphone
             earphoneType={evaluatingData.earPhoneType}
             onClose={() => {
+              evaluatingData.onceErjiPopShow = true;
               clearTimeout(checkErjiTimer);
               checkErjiTimer = null;
               // #11035,可能刚好关闭耳机弹窗的时候,第二次又出现了弹窗

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

@@ -268,13 +268,13 @@
         }
     }
     &.playLeftButton {
-        left: 46px !important;
+        left: 30px !important;
         right: auto !important;
         bottom: 12px !important;
     }
 
     &.playRightButton {
-        right: 46px !important;
+        right: 30px !important;
         left: auto !important;
         bottom: 12px !important;
     }
@@ -302,13 +302,13 @@
     }
 
     &.pauseLeftButton {
-        left: 108px !important;
+        left: 102px !important;
         right: auto !important;
         bottom: 12px !important;
     }
 
     &.pauseRightButton {
-        right: 108px !important;
+        right: 102px !important;
         left: auto !important;
         bottom: 12px !important;
     }

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

@@ -390,7 +390,7 @@ export default defineComponent({
     /** 播放类型按钮 */
     const playTypeBtn = computed(() => {
       // 选择模式,跟练模式,评测模式 不显示
-      if (headTopData.modeType !== "show" || state.modeType === "follow" || state.modeType === "evaluating") return { display: false, disabled: false };
+      if (headTopData.modeType !== "show" || state.modeType === "follow" || state.modeType === "evaluating" || query.workRecord) return { display: false, disabled: false };
       if (!state.isAppPlay) {
         let index = 0;
         state.music && index++;

+ 7 - 1
src/page-instrument/header-top/modeView.tsx

@@ -110,6 +110,8 @@ export default defineComponent({
             smoothAnimationState.isShow.value = state.melodyLine;
             // 返回的时候 跳转到之前记录的模式
             if(headTopData.oldModeType !== "practise"){
+              // 点击评测模式进入评测模块的需要检测耳机状态,通过返回按钮进入评测模块的,不检测耳机状态
+              evaluatingData.needCheckErjiStatus = false;
               headTopData.handleChangeModeType(headTopData.oldModeType)
             }
             headTopData.modeType = "show";
@@ -122,7 +124,11 @@ export default defineComponent({
             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>}
+          {state.enableEvaluation && <Vue3Lottie ref={modeImgDom3} class={styles.modeImg} animationData={pcMode} autoPlay={false} loop={true} onClick={() => {
+            // 点击评测模式进入评测模块的需要检测耳机状态,通过返回按钮进入评测模块的,不检测耳机状态
+            evaluatingData.needCheckErjiStatus = true;
+            headTopData.handleChangeModeType("evaluating")
+          }}></Vue3Lottie>}
         </div>
         {data.showVip && <TheVip />}
         {/** 延迟检测中途,socket出错,网络提示弹窗 */}

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

@@ -254,13 +254,13 @@
     width: 52px;
     height: 125px;
     position: absolute;
-    left: 0;
+    left: -1px;
     top: 0;
 }
 .bg2Right {
     width: 52px;
     height: 125px;
     position: absolute;
-    right: 0;
+    right: -1px;
     top: 0;
 }

+ 12 - 10
src/page-instrument/view-detail/index.tsx

@@ -86,6 +86,8 @@ const setNoteHalfTone = (list: any[]) => {
 
 export const musicScoreRef = ref();
 
+export const headerColumnHide = ref(false); // 是否隐藏功能按钮,播放时自动隐藏
+
 export default defineComponent({
   name: "music-list",
   setup() {
@@ -296,7 +298,7 @@ export default defineComponent({
         if (state.fingeringInfo.direction === "transverse") {
           return {
             container: {
-              paddingBottom: detailData.headerHide ? state.fingeringInfo.height : state.fingeringInfo.scaleData?.offset
+              paddingBottom: headerColumnHide.value ? state.fingeringInfo.height : state.fingeringInfo.scaleData?.offset
             },
             // 横向指法,跟练&评测模式,默认展示贴底展示
             fingerBox: (state.modeType === 'follow' || state.modeType === 'evaluating') ? 
@@ -306,7 +308,7 @@ export default defineComponent({
               bottom: 0,
               width: '100%'
             } : 
-            detailData.headerHide ? {
+            headerColumnHide.value ? {
               height: state.fingeringInfo.height
             } : {
               height: state.fingeringInfo.height,
@@ -328,7 +330,7 @@ export default defineComponent({
                 height: state.fingeringInfo.name === "hulusi-flute" ? "86%" : "80%",
                 right: state.playBtnDirection === "right" ? "initial" : 0,
                 left: state.playBtnDirection === "right" ? 0 : "initial",
-                top: state.fingeringInfo.name === "ocarina" ? "60px" : 0,
+                top: (state.fingeringInfo.name === "ocarina" || state.fingeringInfo.name === "whistling") ? "60px" : state.fingeringInfo.name === "hulusi-flute" ? "10px" : (state.fingeringInfo.name === "baroque-recorder" || state.fingeringInfo.name === "piccolo") ? "40px" : 0,
               },
             };
           } else {
@@ -341,7 +343,7 @@ export default defineComponent({
                 width: state.fingeringInfo.width,
                 height: state.fingeringInfo.name === "hulusi-flute" ? "86%" : "80%",
                 left: 0,
-                top: state.fingeringInfo.name === "ocarina" ? "60px" : 0,
+                top: (state.fingeringInfo.name === "ocarina" || state.fingeringInfo.name === "whistling") ? "60px" : state.fingeringInfo.name === "hulusi-flute" ? "10px" : (state.fingeringInfo.name === "baroque-recorder" || state.fingeringInfo.name === "piccolo") ? "40px" : 0,
               },
             };
           }
@@ -389,9 +391,9 @@ export default defineComponent({
       () => state.playState,
       () => {
         // if (state.platform != IPlatform.PC) {
-        //   detailData.headerHide = state.playState === "play" ? true : false;
+        //   headerColumnHide.value = state.playState === "play" ? true : false;
         // }
-        detailData.headerHide = state.playState === "play" ? true : false;
+        headerColumnHide.value = state.playState === "play" ? true : false;
         sendParentMessage(state.playState);
       }
     );
@@ -399,7 +401,7 @@ export default defineComponent({
     watch(
       () => followData.start,
       () => {
-        detailData.headerHide = followData.start;
+        headerColumnHide.value = followData.start;
       }
     );
     /** 指法预览切换 */
@@ -494,7 +496,7 @@ export default defineComponent({
         {/** 功能按钮 */}
         {
           !state.isPreView && 
-          <div class={[styles.headHeight, detailData.headerHide && styles.headHide]}>{state.musicRendered && <HeaderTop />}</div>
+          <div class={[styles.headHeight, headerColumnHide.value && styles.headHide]}>{state.musicRendered && <HeaderTop />}</div>
         }
         <div
           id="scrollContainer"
@@ -503,11 +505,11 @@ export default defineComponent({
           onClick={(e: Event) => {
             e.stopPropagation();
             // if (state.playState === "play" && state.platform != IPlatform.PC) {
-            //   detailData.headerHide = !detailData.headerHide;
+            //   headerColumnHide.value = !headerColumnHide.value;
             // }
             // 点击谱面跟练也需要切换显示按钮栏
             if (state.playState === "play" || followData.start) {
-              detailData.headerHide = !detailData.headerHide;
+              headerColumnHide.value = !headerColumnHide.value;
             }
           }}
         >

+ 1 - 1
src/page-instrument/view-evaluat-report/component/share-top/index.tsx

@@ -229,7 +229,7 @@ export default defineComponent({
               {/* <div class={styles.lcName}>{state.examSongName}</div> */}
               <Title class={styles.lcName} text={state.examSongName} rightView={false} />
               <div class={styles.lcScore}>
-                {level[scoreData.value.heardLevel]}|速度:{Math.floor(scoreData.value.speed)}|综合分数:{scoreData.value.score}分
+                {level[scoreData.value.heardLevel]}|速度:{Math.floor(scoreData.value.speed)}|综合分数:{scoreData.value.score}分
               </div>
             </div>
           </div>

+ 2 - 2
src/page-instrument/view-evaluat-report/index.module.less

@@ -192,13 +192,13 @@
   width: 52px;
   height: 125px;
   position: absolute;
-  left: 0;
+  left: -1px;
   top: 0;
 }
 .bg2Right {
   width: 52px;
   height: 125px;
   position: absolute;
-  right: 0;
+  right: -1px;
   top: 0;
 }

+ 24 - 11
src/state.ts

@@ -18,7 +18,7 @@ import { changeSongSourceByBate } from "/src/view/audio-list"
 import { moveSmoothAnimation, smoothAnimationState, moveSmoothAnimationByPlayTime, moveTranslateXNum, destroySmoothAnimation, calcClientWidth } from "/src/page-instrument/view-detail/smoothAnimation"
 import { storeData } from "/src/store";
 import { downloadXmlStr } from "./view/music-score"
-import { musicScoreRef } from "/src/page-instrument/view-detail/index"
+import { musicScoreRef, headerColumnHide } from "/src/page-instrument/view-detail/index"
 import { headTopData } from "/src/page-instrument/header-top/index";
 
 const query: any = getQuery();
@@ -637,11 +637,18 @@ export const onEnded = () => {
 
 // 根据当前小节动态设置,右上角展示的速度
 const dynamicShowPlaySpeed = (index: number) => {
-  const item: any = state.times[index];
-  if (item && item.measureSpeed ) {
-    // console.log('速度1',item.measureSpeed)
-    state.speed = Math.floor(state.basePlayRate * item.measureSpeed)
+  if (!headerColumnHide.value) {
+    console.log('动态计算速度')
+    const item: any = state.times[index];
+    if (item && item.measureSpeed ) {
+      // console.log('速度1',item.measureSpeed)
+      const newSpeed = Math.floor(state.basePlayRate * item.measureSpeed)
+      if (state.speed !== newSpeed) {
+        state.speed = newSpeed;
+      }
+    }
   }
+
 }
 
 // 开始播放时,计算mp3的播放倍率
@@ -1332,10 +1339,11 @@ const getMusicInfo = async (res: any) => {
   downloadXmlStr.value = xmlString //给musice-score 赋值xmlString 以免加载2次
   const tracks = xmlToTracks(xmlString) //获取声轨列表
   // 设置音源  track 为当前的声轨 index为当前的
-  const { track, index } = state.isSimplePage ? { track:tracks[0], index:0} : initMusicSource(res.data, tracks, partIndex)
+  const { track, index, musicalInstrumentId } = state.isSimplePage ? { track:tracks[0], index:0, musicalInstrumentId: '' } : initMusicSource(res.data, tracks, partIndex)
+  const realTrack = musicalInstrumentId && res.data?.musicalInstruments?.length ? res.data?.musicalInstruments.find((item: any) => item?.id == musicalInstrumentId)?.code?.split(',')?.[0] : '';
   const musicInfo = {
     ...res.data,
-    track
+    track: res.data.musicSheetType === 'CONCERT' ? track : realTrack
   };
   console.log("🚀 ~ musicInfo:", musicInfo);
   setState(musicInfo, index);
@@ -1354,7 +1362,7 @@ function xmlToTracks(xmlString: string) {
 }
 // 设置音源
 function initMusicSource(data: any, tracks: string[], partIndex: number) {
-  let track:string,index:number
+  let track:string,index:number, musicalInstrumentId: string
   const instrumentId = query.instrumentId || storeData.user?.instrumentId
   let { musicSheetType, isAllSubject, musicSheetSoundList, musicSheetAccompanimentList } = data
   musicSheetSoundList || (musicSheetSoundList = [])
@@ -1383,6 +1391,7 @@ function initMusicSource(data: any, tracks: string[], partIndex: number) {
     index = tracks.findIndex(item => {
       return item === track
     })
+    musicalInstrumentId = musicObj?.musicalInstrumentId
   } else {
     /* 合奏 */
     // 支持总谱 并且当前是总谱。partIndex是999时候,或者默认是总谱并且partIndex为-1时候  -1就是partIndex没有值
@@ -1410,6 +1419,7 @@ function initMusicSource(data: any, tracks: string[], partIndex: number) {
         }
         track = "总谱"
         index = 999
+        musicalInstrumentId = ''
     }else{
       // 合奏只显示一个声轨
       track = tracks[partIndex===-1?0:partIndex]
@@ -1429,6 +1439,7 @@ function initMusicSource(data: any, tracks: string[], partIndex: number) {
       index = tracks.findIndex(item => {
         return item === track
       })
+      musicalInstrumentId = musicObj?.musicalInstrumentId
     }
   }
   // 当没有任何曲目的时候报错
@@ -1473,7 +1484,8 @@ function initMusicSource(data: any, tracks: string[], partIndex: number) {
   }
   return {
     index,
-    track
+    track,
+    musicalInstrumentId
   }
 }
 const setState = (data: any, index: number) => {
@@ -1589,7 +1601,8 @@ const setState = (data: any, index: number) => {
    * 各平台的乐器声部id不统一,为了兼容处理老的数据,加上乐器code码,此码唯一
    * 获取指法code
    */
-  const code = state.isConcert ? matchVoicePart(state.trackId, "CONCERT") : matchVoicePart(state.musicalCodeId, "SINGLE");
+  // const code = state.isConcert ? matchVoicePart(state.trackId, "CONCERT") : matchVoicePart(state.musicalCodeId, "SINGLE");
+  const code = matchVoicePart(state.trackId, "CONCERT")
   state.fingeringInfo = subjectFingering(code);
   console.log("🚀 ~ state.fingeringInfo:", code, state.fingeringInfo, state.trackId, state.track);
   state.musicalCodeId = state.fingeringInfo?.id || 0
@@ -1871,7 +1884,7 @@ watch(
     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)) ) {
+      if (measureNum >= 0 && (measureNum === state.activeMeasureIndex || (measureNum < state.activeMeasureIndex && nextMeasureNum > state.activeMeasureIndex)) || (measureNum < state.activeMeasureIndex && nextMeasureNum == -1) ) {
         item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
         item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
         // 预备小节

+ 3 - 3
src/view/audio-list/index.tsx

@@ -269,9 +269,9 @@ export default defineComponent({
 			const time = currentTime / 1000;
 			audioData.progress = time;
 			tickAnimate(time);
-			audioData.songEle && (audioData.songEle.currentTime = time);
-			audioData.backgroundEle && (audioData.backgroundEle.currentTime = time);
-			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.duration = total / 1000;
 			if (
 				res?.content?.totalDuration > 1000 &&

+ 13 - 5
src/view/evaluating/index.tsx

@@ -114,6 +114,8 @@ export const evaluatingData = reactive({
   needReplayEvaluat: false, // 手动取消评测,需要自动开始评测
   needPlayTick: false, // 评测时,mp3节拍器需要等待音频开始播放后再执行播放节拍器的圆点动画
   tipErjiShow: false, // 评测提示弹窗
+  onceErjiPopShow: false, // 是否已经提示过耳机弹窗,重新进入评测页面,重置该状态为false,手动关掉耳机弹窗,改变该状态为true,本次评测都不在提示耳机状态弹窗
+  needCheckErjiStatus: true, // 点击评测模式进入评测模块的需要检测耳机状态,通过返回按钮进入评测模块的,不检测耳机状态
 });
 
 const sendOffsetTime = async (offsetTime: number) => {
@@ -409,7 +411,11 @@ export const handleStartBegin = async (preTimes?: number) => {
 		evaluatingData.isBeginMask = false
 		onPlay();
 	}
-	if (evaluatingData.isErrorState) return
+	if (evaluatingData.isErrorState) {
+    state.playState = 'paused';
+    evaluatingData.startBegin = false;
+    return
+  }
 	//开始录音
 	// await api_startRecording({
 	// 	accompanimentState: state.setting.enableAccompaniment ? 1 : 0,
@@ -644,6 +650,8 @@ const handleAccompanyError = (res?: IPostMessage) => {
   console.log("异常信息返回", res);
   if (res?.content) {
     const { type, reson } = res.content;
+    state.playState = 'paused'
+    evaluatingData.startBegin = false
     switch (type) {
       case "enterBackground":
       // App退到后台
@@ -729,8 +737,8 @@ export default defineComponent({
     /** 记录状态 */
     const hanlde_record = () => {
       // 取消指法
-      record_old_data.finger = state.setting.displayFingering;
-      state.setting.displayFingering = false;
+      // record_old_data.finger = state.setting.displayFingering;
+      // state.setting.displayFingering = false;
       // 切换为伴奏
       record_old_data.play_mode = state.playSource;
       record_old_data.enableAccompaniment = state.setting.enableAccompaniment;
@@ -743,7 +751,7 @@ export default defineComponent({
     /** 还原状态 */
     const handle_reduction = () => {
       // 还原指法
-      state.setting.displayFingering = record_old_data.finger;
+      // state.setting.displayFingering = record_old_data.finger;
       state.playSource = record_old_data.play_mode;
 
       // 如果关闭伴奏, 结束评测取消静音
@@ -785,7 +793,7 @@ export default defineComponent({
       // evaluatingData.resulstMode = true;
       // evaluatingData.resultData = {...getLeveByScore(10), score: 10, intonation: 10, cadence: 30, integrity: 40}
       // console.log("🚀 ~ evaluatingData.resultData:", evaluatingData.resultData)
-
+      evaluatingData.onceErjiPopShow = false;
       evaluatingData.evaluatings = {};
       evaluatingData.soundEffectFrequency = 0;
       evaluatingData.checkStep = 0;

+ 1 - 1
src/view/fingering/fingering-config.ts

@@ -338,7 +338,7 @@ export const matchVoicePart = (id: number | string, type: "SINGLE" | "CONCERT"):
       code = code.toLocaleLowerCase().replace(/ /g, "");
       for (let sKey in subject) {
         let pitchKey = sKey;
-        if (typeof sKey === "string") {
+        if (typeof sKey === "string" && isNaN(Number(sKey)) ) {
           pitchKey = pitchKey.toLocaleLowerCase().replace(/ /g, "");
           pitchKey = pitchKey.replace(/[_0-9]+$/, '');
         }

+ 4 - 4
src/view/selection/index.module.less

@@ -83,8 +83,8 @@
 
 .scoreItem {
     position: absolute;
-    left: 50%;
-    top: -90%;
+    left: 80%;
+    top: -120%;
     transform: translateX(-50%);
     font-size: 16px;
     font-family: "Roboto", sans-serif;
@@ -161,7 +161,7 @@
 .followTipUp, .followTipDown {
     display: flex;
     align-items: center;
-    background: rgba(0,0,0,0.6);
+    background: rgba(0,0,0,0.7);
     position: relative;
     padding: 6px 10px;
     border-radius: 16px;
@@ -186,7 +186,7 @@
         content: "";
         position: absolute;
         left: 50%;
-        bottom: -8PX;
+        bottom: -9PX;
         transform: translateX(-50%);
         width: 13Px;
         height: 9Px;

+ 135 - 162
src/view/selection/index.tsx

@@ -145,21 +145,16 @@ const calcNoteData = () => {
 				MeasureNumberXMLList.push(item.MeasureNumberXML);
 			} else {
 				if (item.multipleRestMeasures) {
-					console.log(111111)
 					if (state.isCombineRender) {
-						state.vfmeasures.forEach((item: any, idx: number) => {
-							const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : -1;
-							
-						})
 						let currentItem = null;
 						for (let index = 0; index < state.vfmeasures.length; index++) {
 							const element = state.vfmeasures[index];
 							const measureNum = element.getAttribute('data-num') ? Number(element.getAttribute('data-num')) : -1;
-							if (measureNum === item.MeasureNumberXML) {
+							const nextMeasureNum = state.vfmeasures[index+1]?.getAttribute('data-num') ? Number(state.vfmeasures[index+1]?.getAttribute('data-num')) : -1;
+							if (measureNum === item.MeasureNumberXML || item.MeasureNumberXML < nextMeasureNum || nextMeasureNum == -1) {
 								currentItem = element
 								break;
 							}
-							
 						}
 						const staveBbox = currentItem?.querySelector('.vf-stave')?.getBoundingClientRect() || { x: 0, width: 0, y: 0, height: 0 };
 						if (currentItem) {
@@ -260,167 +255,145 @@ export default defineComponent({
 			} catch (error) {}
 		});
 		return () => (
-			<>
-				<div class={styles.staveBgContainer}>
-					{
-						selectData.staves.map((item: any) => {
-							return (
-								<>
-									{
-										item.staveBox && item.multipleRestMeasures <= 1 && 
+			<div
+				id="selectionBox"
+				class={[
+					styles.selectionContainer,
+				]}
+				onClick={(e: Event) => e.stopPropagation()}
+			>
+				{selectData.staves.map((item: any) => {
+					// 评测得分
+					const scoreItem = item.id && evaluatingData.evaluatings[item.measureListIndex];
+					// for(let idx in evaluatingData.evaluatings) {
+					// 	const { show, measureIndex } = evaluatingData.evaluatings[idx]
+					// 	if (show && measureIndex !== item.measureListIndex) {
+					// 		evaluatingData.evaluatings[idx].show = false
+					// 	}
+					// }
+					// 高级模式下,显示节拍线
+					// 不是报告模式
+					// 不是多小节休止符
+					// 节拍线开关
+					// 当前小节
+					// 当前小节
+					const lineShow =
+						!state.isReport &&
+						metronomeData.cursorMode === 2 &&
+						item.MeasureNumberXML === metronomeData.activeMetro?.measureNumberXML &&
+						state.times[state.activeNoteIndex].MeasureNumberXML === item.MeasureNumberXML;
+					return (
+						<>
+							{item.staveBox && (
+								<div
+									class={[
+										styles.position,
+										// scoreItem ? `scoreItemLeve${scoreItem.leve}` : "", // 去掉评测小节得分的背景色
+										item.multipleRestMeasures <= 1 ? styles.staveBg : "",
+										(state.platform === IPlatform.PC && state.zoom > 0.8) ? styles.linePC : '',
+									]}
+									style={item.staveBox}
+									onClick={() => handleSelection(item)}
+								>
+									{lineShow && (
+										<div style={{height: selectData.measureHeight + 'px', position: 'relative'}}>
 											<div 
-												style={{
-													left:item.staveBox.left,
-													top:`calc(${item.staveBox.top} + ${item.staveBox.height})`,
-													width:item.staveBox.width
-												}}
-												class={[styles.staveBg]}
-											></div>
-									}
-								</>
-							)
-						})
-					}
-				</div>
-				<div
-					id="selectionBox"
-					class={[
-						styles.selectionContainer,
-					]}
-					onClick={(e: Event) => e.stopPropagation()}
-				>
-					{selectData.staves.map((item: any) => {
-						// 评测得分
-						const scoreItem = item.id && evaluatingData.evaluatings[item.measureListIndex];
-						// for(let idx in evaluatingData.evaluatings) {
-						// 	const { show, measureIndex } = evaluatingData.evaluatings[idx]
-						// 	if (show && measureIndex !== item.measureListIndex) {
-						// 		evaluatingData.evaluatings[idx].show = false
-						// 	}
-						// }
-						// 高级模式下,显示节拍线
-						// 不是报告模式
-						// 不是多小节休止符
-						// 节拍线开关
-						// 当前小节
-						// 当前小节
-						const lineShow =
-							!state.isReport &&
-							metronomeData.cursorMode === 2 &&
-							item.MeasureNumberXML === metronomeData.activeMetro?.measureNumberXML &&
-							state.times[state.activeNoteIndex].MeasureNumberXML === item.MeasureNumberXML;
-						return (
-							<>
-								{item.staveBox && (
-									<div
-										class={[
-											styles.position,
-											// scoreItem ? `scoreItemLeve${scoreItem.leve}` : "", // 去掉评测小节得分的背景色
-											(state.platform === IPlatform.PC && state.zoom > 0.8) ? styles.linePC : '',
-										]}
-										style={item.staveBox}
-										onClick={() => handleSelection(item)}
+											class={[
+												styles.line,
+												state.setting.eyeProtection ? styles.eyeLine : '',
+												state.musicRenderType == EnumMusicRenderType.staff ? styles.lineStaff : styles.lineJianPu,
+											]} 
+											style={{ left: metronomeData.activeMetro.left }}></div>
+										</div>
+									)}
+									{!state.isReport &&
+										!!item.multipleRestMeasures &&
+										state.activeMeasureIndex == item.MeasureNumberXML && (
+											<div class={styles.dotWrap}>{item.multipleRestMeasures}</div>
+										)}
+									<Transition
+										name="centerTop"
+										onAfterEnter={() => {
+											scoreItem.show = false;
+										}}
 									>
-										{lineShow && (
-											<div style={{height: selectData.measureHeight + 'px', position: 'relative'}}>
-												<div 
-												class={[
-													styles.line,
-													state.setting.eyeProtection ? styles.eyeLine : '',
-													state.musicRenderType == EnumMusicRenderType.staff ? styles.lineStaff : styles.lineJianPu,
-												]} 
-												style={{ left: metronomeData.activeMetro.left }}></div>
+										{scoreItem?.show && (
+											<div
+												class={styles.scoreItem}
+												style={{ color: leveByScoreMeasureIcons[scoreItem.leve]?.color || "" }}
+											>
+												<img src={leveByScoreMeasureIcons[scoreItem.leve]?.icon} />
+												<span>{scoreItem.score}</span>
 											</div>
 										)}
-										{!state.isReport &&
-											!!item.multipleRestMeasures &&
-											state.activeMeasureIndex == item.MeasureNumberXML && (
-												<div class={styles.dotWrap}>{item.multipleRestMeasures}</div>
-											)}
-										<Transition
-											name="centerTop"
-											onAfterEnter={() => {
-												scoreItem.show = false;
-											}}
-										>
-											{scoreItem?.show && (
-												<div
-													class={styles.scoreItem}
-													style={{ color: leveByScoreMeasureIcons[scoreItem.leve]?.color || "" }}
-												>
-													<img src={leveByScoreMeasureIcons[scoreItem.leve]?.icon} />
-													<span>{scoreItem.score}</span>
-												</div>
-											)}
-										</Transition>
-									</div>
-								)}
-							</>
-						);
-					})}
-					{selectData.notes.map((item: any) => {
+									</Transition>
+								</div>
+							)}
+						</>
+					);
+				})}
+				{selectData.notes.map((item: any) => {
+					return (
+						<div
+							class={[styles.position, disableClickNote.value && styles.disable, styles.note, `noteIndex_${item.index}`]}
+							style={item.bbox}
+							onClick={() => skipNotePlay(item.index)}
+						>
+							{/* <div class={styles.noteFollow} data-vf={"vf" + item.id}>
+								<Icon name="success" />
+								<Icon name="cross" />
+							</div> */}
+							<div class={styles.noteFollow} data-vf={"vf" + item.id}>
+								{/* <Icon name="success" />
+								<Icon name="cross" /> */}
+								<div class={[styles.followTipUp, 'tip-up']}>
+									<img src={IntonationUp} />
+									<span>音准<i>高了</i></span>
+								</div>
+								<div class={[styles.followTipDown, 'tip-down']}>
+									<img src={IntonationDown} />
+									<span>音准<i>低了</i></span>
+								</div>
+							</div>							
+							<div class={[styles.noteDot, 'node-dot']}></div>
+						</div>
+					);
+				})}
+				{/* 选段 */}
+				{
+					sectionPosData.value.map((item,index) =>{
 						return (
-							<div
-								class={[styles.position, disableClickNote.value && styles.disable, styles.note, `noteIndex_${item.index}`]}
-								style={item.bbox}
-								onClick={() => skipNotePlay(item.index)}
-							>
-								{/* <div class={styles.noteFollow} data-vf={"vf" + item.id}>
-									<Icon name="success" />
-									<Icon name="cross" />
-								</div> */}
-								<div class={styles.noteFollow} data-vf={"vf" + item.id}>
-									{/* <Icon name="success" />
-									<Icon name="cross" /> */}
-									<div class={[styles.followTipUp, 'tip-up']}>
-										<img src={IntonationUp} />
-										<span>音准<i>高了</i></span>
-									</div>
-									<div class={[styles.followTipDown, 'tip-down']}>
-										<img src={IntonationDown} />
-										<span>音准<i>低了</i></span>
-									</div>
-								</div>							
-								<div class={[styles.noteDot, 'node-dot']}></div>
+							item && <div class={styles.selectBox} style={item}>
+								<div class={[styles.selectHandle,index>0&&styles.selectHandleRight,(state.playState==="play" || query.workRecord)&&styles.playIng]} onClick={()=>{
+									// 如果选择了2个 删除左边的时候
+									if(state.section.length===2&&index === 0){
+										state.section = []
+										// 重置速度和播放倍率
+										resetBaseRate(state.activeNoteIndex);
+										showToast({
+											message: "请选择开始小节",
+											duration: 0,
+											position: "top",
+											className: "selectionToast",
+										});
+									}else{
+										state.section.splice(index,1)
+										state.section = [...state.section]  // 触发 watch
+										showToast({
+											message: state.section.length?"请选择结束小节":"请选择开始小节",
+											duration: 0,
+											position: "top",
+											className: "selectionToast",
+										});
+									}
+								}}></div>
 							</div>
-						);
-					})}
-					{/* 选段 */}
-					{
-						sectionPosData.value.map((item,index) =>{
-							return (
-								item && <div class={styles.selectBox} style={item}>
-									<div class={[styles.selectHandle,index>0&&styles.selectHandleRight,(state.playState==="play" || query.workRecord)&&styles.playIng]} onClick={()=>{
-										// 如果选择了2个 删除左边的时候
-										if(state.section.length===2&&index === 0){
-											state.section = []
-											// 重置速度和播放倍率
-											resetBaseRate(state.activeNoteIndex);
-											showToast({
-												message: "请选择开始小节",
-												duration: 0,
-												position: "top",
-												className: "selectionToast",
-											});
-										}else{
-											state.section.splice(index,1)
-											state.section = [...state.section]  // 触发 watch
-											showToast({
-												message: state.section.length?"请选择结束小节":"请选择开始小节",
-												duration: 0,
-												position: "top",
-												className: "selectionToast",
-											});
-										}
-									}}></div>
-								</div>
-							)
-						})
-					}
-					{/* 移动模块 */}
-					{query.isMove == "1" && <MoveMusicScore />}
-				</div>
-			</>
+						)
+					})
+				}
+				{/* 移动模块 */}
+				{query.isMove == "1" && <MoveMusicScore />}
+			</div>
 		);
 	},
 });