浏览代码

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

TIANYONG 11 月之前
父节点
当前提交
9041c2b6b5

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

@@ -54,24 +54,18 @@
     .title{
         width: 216px;
         margin-left: 10px;
-        &.isMusicList{
-            :global{
-                .van-notice-bar{
-                    &::after{
-                        max-width: calc(216px + 16px);
-                        position: absolute;
-                        top: 0;
-                        left: 0;
-                        content: "";
-                        width: calc(var(--noticeBarWidth,100%) + 16px);
-                        height: 100%;
-                        background: url("./image/sj.png") no-repeat;
-                        background-size: 9px 6px;
-                        background-position: center right;                   
-                    }
-                    
-                }
-            }
+        position: relative;
+        .symbolNote{
+            max-width: calc(216px + 16px);
+            position: absolute;
+            top: 0;
+            left: 0;
+            content: "";
+            width: calc(var(--noticeBarWidth,100%) + 16px);
+            height: 100%;
+            background: url("./image/sj.png") no-repeat;
+            background-size: 9px 6px;
+            background-position: center right;                   
         }
         :global{
             .van-notice-bar{

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

@@ -645,10 +645,13 @@ export default defineComponent({
                           "--noticeBarWidth":noticeBarWidth.value + "px"
                         } : {}
                       }
-                      class={[styles.title,isMusicList.value && styles.isMusicList, "driver-8"]} 
+                      class={[styles.title, "driver-8"]} 
                       onClick={()=>{
                         isMusicList.value && (musicListShow.value = true)
                       }}>
+                        {
+                          isMusicList.value && <div class={styles.symbolNote}></div>
+                        }
                         <NoticeBar
                           text={state.examSongName}
                           background="none"

+ 20 - 0
src/page-instrument/header-top/settting/index.tsx

@@ -11,6 +11,7 @@ import { resetRenderMusicScore } from "/src/view/music-score";
 import ScreenModel from "../../custom-plugins/helper-model/screen-model";
 import { getQuery } from "/src/utils/queryString";
 import { reCheckDelay } from "/src/page-instrument/evaluat-model"
+import { audioData, changeMingSongType } from "/src/view/audio-list"
 
 export default defineComponent({
 	name: "settting",
@@ -61,6 +62,25 @@ export default defineComponent({
                                     <div class={styles.tit}>循环播放</div>
                                     <Switch v-model={state.setting.repeatAutoPlay}></Switch>
                                 </div>
+                        }                        
+                        {
+                            state.modeType === 'practise' && state.mingSong && state.mingSongGirl &&
+                            <div class={styles.cellBox}>
+                                <div class={styles.tit}>唱名类型</div>
+                                <div class={styles.radioBox}>
+                                    {
+                                        [{name:'男生',value:1}, {name:'女生',value:0}].map(item=>{
+                                            return <div class={ audioData.mingSongType===item.value && styles.active } onClick={ ()=>{ 
+                                                if(audioData.mingSongType === item.value){
+                                                    return
+                                                }
+                                                audioData.mingSongType = item.value as 0|1
+                                                changeMingSongType()
+                                            } }>{item.name}</div>
+                                        })
+                                    }
+                                </div>
+                            </div>                     
                         }
                         {
                             state.isSingleLine && state.modeType === "practise" && !state.isCombineRender && !state.isPercussion && 

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

@@ -118,7 +118,8 @@ export default defineComponent({
       api_setStatusBarVisibility();
       const settting = store.get("musicscoresetting");
       if (settting) {
-        state.setting = settting;
+        //state.setting = settting;
+        Object.assign(state.setting, settting)
         //state.setting.beatVolume = state.setting.beatVolume || 50
         state.setting.beatVolume = 50
         if (state.setting.camera) {

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

@@ -227,7 +227,7 @@
     box-shadow: inset 4px -3px 6px 0px #B2E8FF;
     border-radius: 20px;
     padding: 14px;
-
+    overflow: hidden;
     :global {
         .plyr {
             border-radius: 16px;

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

@@ -42,9 +42,6 @@ export default defineComponent({
       isInitPlyr: false,
       _plrl: null as any,
     });
-    const lottieDom = ref<any>();
-    const lottieDom1 = ref<any>();
-    const lottieDom2 = ref<any>();
     const level: any = {
       BEGINNER: "入门级",
       ADVANCED: "进阶级",
@@ -100,15 +97,9 @@ export default defineComponent({
 						const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
 						const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
 						shareData._plrl.on('play', () => {
-							lottieDom.value?.play()
-							lottieDom1.value?.play()
-							lottieDom2.value?.play()
 							playVisualDraw()
 						});
 						shareData._plrl.on('pause', () => {
-							lottieDom.value?.pause()
-							lottieDom1.value?.pause()
-							lottieDom2.value?.pause()
 							pauseVisualDraw()
 						});
 					}, 300); // 弹窗动画是0.25秒 这里用定时器 确保canvas 能获取到宽高
@@ -444,9 +435,9 @@ export default defineComponent({
               {mediaType.value === "audio" ? (
                 <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>
+                  <Vue3Lottie class={styles.audioBga} animationData={audioBga} autoPlay={false} loop={true}></Vue3Lottie>
+                  <Vue3Lottie class={styles.audioBga1} animationData={audioBga1} autoPlay={false} loop={true}></Vue3Lottie>
+                  <Vue3Lottie class={styles.audioBga2} animationData={audioBga2} autoPlay={false} loop={true}></Vue3Lottie>
                   <audio crossorigin="anonymous" id="audioSrc" src={scoreData.value.videoFilePath} controls="false" preload="metadata" playsinline />
                 </div>
               ) : (

+ 104 - 30
src/state.ts

@@ -333,13 +333,16 @@ const state = reactive({
   banSong: "",
   /** 唱名 */
   mingSong: "",
+  /** 唱名女 如果有男唱名的情况下*/
+  mingSongGirl:"",
   /** 节拍器音乐资源 */
   beatSong: {
     music: "",
     accompany: "",
     fanSong: "",
     banSong: "",
-    mingSong: ""
+    mingSong: "",
+    mingSongGirl: ""
   },
   /** midiURL */
   midiUrl: "",
@@ -481,7 +484,13 @@ const state = reactive({
   /** 乐器code,用于评测传参 */
   musicalCode: '' as any,
   /** 合奏曲目是否合并展示 */
-  isCombineRender: false,
+  isCombineRender: false,  
+  /** 是否支持总谱 */
+  isScoreRender: false,  
+  /** 是否默认显示总谱 */
+  defaultScoreRender: false,
+  /** 没有音源字段 */
+  noMusicSource: false,
   /** 小节的持续时长,以后台设置的播放速度计算 */
   measureTime: 0,
   /** 跟练模式,节拍器播放的时间 */
@@ -1313,17 +1322,20 @@ export const getMusicDetail = async (id: string, type?: string) => {
 
 
 const getMusicInfo = async (res: any) => {
+  // 是否支持总谱
+  state.isScoreRender = res.data?.isScoreRender
+  // 是否默认显示总谱
+  state.defaultScoreRender = res.data?.defaultScoreRender
+  const partIndex = query["part-index"] ? parseInt(query["part-index"]) : -1 // -1为partIndex没有值的时候
+  /* 获取声轨列表 */
   const xmlString = await fetch(res.data.xmlFileUrl).then((response) => response.text());
   downloadXmlStr.value = xmlString //给musice-score 赋值xmlString 以免加载2次
   const tracks = xmlToTracks(xmlString) //获取声轨列表
-  let index = query["part-index"] ? parseInt(query["part-index"]) : 0
-  const musicObj = state.isSimplePage ? {} : initMusicSource(res.data, tracks[index]) //当前part-index找不到声源的时候以第一个为准
-  index = tracks.findIndex(item => {  // 筛选出当前的index
-    return item === musicObj?.track
-  })
+  // 设置音源  track 为当前的声轨 index为当前的
+  const { track, index } = state.isSimplePage ? { track:tracks[0], index:0} : initMusicSource(res.data, tracks, partIndex)
   const musicInfo = {
     ...res.data,
-    track: musicObj?.track
+    track
   };
   console.log("🚀 ~ musicInfo:", musicInfo);
   setState(musicInfo, index);
@@ -1341,15 +1353,16 @@ function xmlToTracks(xmlString: string) {
   }, []);
 }
 // 设置音源
-function initMusicSource(data: any, track?: string) {
+function initMusicSource(data: any, tracks: string[], partIndex: number) {
+  let track:string,index:number
   const { instrumentId } = storeData.user
   let { musicSheetType, isAllSubject, musicSheetSoundList, musicSheetAccompanimentList } = data
   musicSheetSoundList || (musicSheetSoundList = [])
   musicSheetAccompanimentList || (musicSheetAccompanimentList = [])
   let musicObj, accompanyObj, fanSongObj, banSongObj
-  // 独奏
+   /* 独奏 */
   if (musicSheetType === "SINGLE") {
-    // 适用声部(instrumentId)为true 时候没有乐器只有一个原音;当前用户有乐器就匹配  不然取第一个原音
+    // 适用声部(isAllSubject)为true 时候没有乐器只有一个原音;当前用户有乐器就匹配  不然取第一个原音
     musicObj = musicSheetSoundList.find((item: any) => {
       return (isAllSubject || !instrumentId) ? item.audioPlayType === "PLAY" : (item.audioPlayType === "PLAY" && item.musicalInstrumentId == instrumentId)
     })
@@ -1363,22 +1376,70 @@ function initMusicSource(data: any, track?: string) {
     banSongObj = musicSheetAccompanimentList.find((item: any) => {
       return item.audioPlayType === "SING"
     })
+    accompanyObj = musicSheetAccompanimentList.find((item: any) => {
+      return item.audioPlayType === "PLAY"
+    })
+    track = musicObj.track   //没有原音的时候track为空 不显示指法
+    index = tracks.findIndex(item => {
+      return item === track
+    })
   } else {
-    // 合奏  合奏根据声轨来区分原音
-    musicObj = track ? musicSheetSoundList.find((item: any) => {
-      return item.track === track
-    }) : musicSheetSoundList[0]
+    /* 合奏 */
+    // 支持总谱 并且当前是总谱。partIndex是999时候,或者默认是总谱并且partIndex为-1时候  -1就是partIndex没有值
+    if(state.isScoreRender && (partIndex===999 || (state.defaultScoreRender && partIndex===-1))){
+        // 总谱渲染
+        state.isCombineRender = true
+        state.partListNames = tracks
+        banSongObj = musicSheetAccompanimentList.find((item: any) => {
+          return item.audioPlayType === "SING"
+        })
+        // 先取scoreAudioFileUrl的值
+        if(banSongObj?.scoreAudioFileUrl){
+          banSongObj.audioFileUrl = banSongObj.scoreAudioFileUrl
+          banSongObj.audioBeatMixUrl = banSongObj.scoreAudioBeatMixUrl
+        }
+        accompanyObj = musicSheetAccompanimentList.find((item: any) => {
+          return item.audioPlayType === "PLAY"
+        })
+        // 先取scoreAudioFileUrl的值
+        if(accompanyObj?.scoreAudioFileUrl){
+          accompanyObj.audioFileUrl = accompanyObj.scoreAudioFileUrl
+          accompanyObj.audioBeatMixUrl = accompanyObj.scoreAudioBeatMixUrl
+        }
+        track = "总谱"
+        index = 999
+    }else{
+      // 合奏只显示一个声轨
+      track = tracks[partIndex===-1?0:partIndex]
+      // 根据当前的声轨 取数据
+      musicObj = musicSheetSoundList.find((item: any) => {
+        return item.audioPlayType === "PLAY" && item.track === track
+      })
+      fanSongObj = musicSheetSoundList.find((item: any) => {
+        return item.audioPlayType === "SING" && item.track === track
+      })
+      banSongObj = musicSheetAccompanimentList.find((item: any) => {
+        return item.audioPlayType === "SING"
+      })
+      accompanyObj = musicSheetAccompanimentList.find((item: any) => {
+        return item.audioPlayType === "PLAY"
+      })
+      index = tracks.findIndex(item => {
+        return item === track
+      })
+    }
   }
-  accompanyObj = musicSheetAccompanimentList.find((item: any) => {
-    return item.audioPlayType === "PLAY"
-  })
   // 当没有任何曲目的时候报错
-  if (!musicObj?.audioFileUrl && !accompanyObj?.audioFileUrl && !fanSongObj?.audioFileUrl && !banSongObj?.audioFileUrl && !fanSongObj?.solmizationFileUrl) {
-    // 并且是midi没有midi文件的时候
-    if(data.playMode === "MIDI" && !data.midiFileUrl) {
-      // 是预览的时候 不报错
-      if(!query.isPreView){
-        throw new Error("该曲目无任何音源");
+  if (!musicObj?.audioFileUrl && !accompanyObj?.audioFileUrl && !fanSongObj?.audioFileUrl && !banSongObj?.audioFileUrl && !fanSongObj?.solmizationFileUrl && !fanSongObj?.femaleSolmizationFileUrl) {
+    state.noMusicSource = true // 没有音源文件
+    // 独奏的时候
+    if(musicSheetType === "SINGLE"){
+      // 并且是midi没有midi文件的时候
+      if(data.playMode === "MIDI" && !data.midiFileUrl) {
+        // 是预览的时候 不报错
+        if(!query.isPreView){
+          throw new Error("该曲目无任何音源");
+        }
       }
     }
   }
@@ -1387,16 +1448,31 @@ function initMusicSource(data: any, track?: string) {
     accompany: accompanyObj?.audioFileUrl,
     fanSong: fanSongObj?.audioFileUrl,
     banSong: banSongObj?.audioFileUrl,
-    mingSong: fanSongObj?.solmizationFileUrl
   })
+  // 如果没有男唱名
+  if(!fanSongObj?.solmizationFileUrl){
+    state.mingSong = fanSongObj?.femaleSolmizationFileUrl
+  }else{
+    state.mingSong = fanSongObj?.solmizationFileUrl
+    state.mingSongGirl = fanSongObj?.femaleSolmizationFileUrl
+  }
   Object.assign(state.beatSong, {
     music: musicObj?.audioBeatMixUrl,
     accompany: accompanyObj?.audioBeatMixUrl,
     fanSong: fanSongObj?.audioBeatMixUrl,
-    banSong: banSongObj?.audioBeatMixUrl,
-    mingSong: fanSongObj?.solmizationBeatUrl
+    banSong: banSongObj?.audioBeatMixUrl
   })
-  return musicObj
+  // 如果没有男唱名
+  if(!fanSongObj?.solmizationBeatUrl){
+    state.beatSong.mingSong = fanSongObj?.femaleSolmizationBeatUrl
+  }else{
+    state.beatSong.mingSong = fanSongObj?.solmizationBeatUrl
+    state.beatSong.mingSongGirl = fanSongObj?.femaleSolmizationBeatUrl
+  }
+  return {
+    index,
+    track
+  }
 }
 const setState = (data: any, index: number) => {
   // 根据当前文件有没有 设置当前的播放模式
@@ -1443,8 +1519,6 @@ const setState = (data: any, index: number) => {
   state.cbsExamSongId = data.id + "";
   state.examSongName = data.name;
   state.coverImg = data.musicCover ?? "";
-  // 单声部多声轨合并展示
-  state.isCombineRender = data.musicSheetType === "SINGLE" && data.musicSheetSoundList?.length > 1
   // 如果是simple页面,只显示单轨
   if (state.isSimplePage) {
     state.isCombineRender = false;

+ 3 - 1
src/store.ts

@@ -22,7 +22,9 @@ type IUser = {
   phone?: string;
   schoolInfos?: any[];
   // 当前用户 绑定 的乐器
-  instrumentId: string 
+  instrumentId?: string;
+  // 性别
+  gender?: 1|0;
 };
 type IStatus = "init" | "login" | "logout" | "error";
 type IPlatformType = "STUDENT" | "TEACHER" | "WEB" | "";

+ 50 - 7
src/view/audio-list/index.tsx

@@ -33,7 +33,14 @@ export const audioData = reactive({
 	},
 	midiRender: false,
 	progress: 0, // midi播放进度(单位:秒)
-	duration: 0 // 音频总时长(单位:秒)
+	duration: 0, // 音频总时长(单位:秒)
+	mingSongType: 1 as 0 | 1,
+	mingSongTypeCollection: {
+		mingSongEle: null as HTMLAudioElement | null,
+		mingSongGirlEle: null as HTMLAudioElement | null,
+		beatMingSongEle: null as HTMLAudioElement | null,
+		beatMingSongGirlEle: null as HTMLAudioElement | null
+	}
 });
 const midiRef = ref();
 /** 播放或暂停 */
@@ -183,6 +190,16 @@ export const changeSongSourceByBate = (isDisBate:boolean) => {
 		audioData.mingSongEle && (audioData.mingSongEle.muted = false);
 	}
 }
+/** 切换男生女生唱名  */
+export const changeMingSongType = () =>{
+	// 当有男声女声都有值时候才能切换 
+	const { mingSongEle, mingSongGirlEle, beatMingSongEle, beatMingSongGirlEle } = audioData.mingSongTypeCollection
+	if(mingSongEle&&mingSongGirlEle){
+		const mingSongType = audioData.mingSongType
+		audioData.songCollection.mingSongEle = mingSongType === 1 ? mingSongEle : mingSongGirlEle
+		audioData.songCollection.betaMingSongEle = mingSongType === 1 ? beatMingSongEle : beatMingSongGirlEle
+	}
+}
 export default defineComponent({
 	name: "audio-list",
 	setup() {
@@ -299,11 +316,11 @@ export default defineComponent({
 		}
 		// 加载音源
 		function loadAudio(){
-			return Promise.all([createAudio(state.music), createAudio(state.accompany), createAudio(state.fanSong), createAudio(state.banSong), createAudio(state.mingSong)])
+			return Promise.all([createAudio(state.music), createAudio(state.accompany), createAudio(state.fanSong), createAudio(state.banSong), createAudio(state.mingSong), createAudio(state.mingSongGirl)])
 		}
 		// 加载节拍器音源
 		function loadBeatAudio(){
-			return Promise.all([createAudio(state.beatSong.music), createAudio(state.beatSong.accompany), createAudio(state.beatSong.fanSong), createAudio(state.beatSong.banSong), createAudio(state.beatSong.mingSong)])
+			return Promise.all([createAudio(state.beatSong.music), createAudio(state.beatSong.accompany), createAudio(state.beatSong.fanSong), createAudio(state.beatSong.banSong), createAudio(state.beatSong.mingSong), createAudio(state.beatSong.mingSongGirl)])
 		}
 		onMounted(async () => {
 			// 预览的时候不走音频加载逻辑
@@ -314,7 +331,7 @@ export default defineComponent({
 			if (state.playMode !== "MIDI") {
 				console.time("音频加载时间")
 				// 处理音源
-				const [music, accompany, fanSong, banSong, mingSong] = await loadAudio()
+				const [music, accompany, fanSong, banSong, mingSong, mingSongGirl] = await loadAudio()
 				audioData.backgroundEle = accompany;
 				audioData.songEle = music;
 				Object.assign(audioData.songCollection, {
@@ -324,6 +341,10 @@ export default defineComponent({
 					banSongEle:banSong,
 					mingSongEle:mingSong
 				})
+				Object.assign(audioData.mingSongTypeCollection, {
+					mingSongEle: mingSong,
+					mingSongGirlEle:mingSongGirl
+				})
 				if (music) {
 					music.addEventListener("play", onPlay);
 					music.addEventListener("ended", onEnded);
@@ -346,14 +367,22 @@ export default defineComponent({
 					mingSong.addEventListener("play", onPlay);
 					mingSong.addEventListener("ended", onEnded);
 				}
+				if(mingSongGirl){
+					mingSongGirl.addEventListener("play", onPlay);
+					mingSongGirl.addEventListener("ended", onEnded);
+				}
 				// 处理带节拍器的音源
-				const [beatMusic, beatAccompany, beatFanSong, beatBanSong, beatMingSong] = await loadBeatAudio()
+				const [beatMusic, beatAccompany, beatFanSong, beatBanSong, beatMingSong, beatMingSongGirl] = await loadBeatAudio()
 				Object.assign(audioData.songCollection, {
 					beatSongEle:beatMusic,
 					betaBackgroundEle:beatAccompany,
 					betaFanSongEle:beatFanSong,
 					betaBanSongEle:beatBanSong,
-					betaMingSongEle:beatMingSong
+					beatMingSongEle:beatMingSong
+				})
+				Object.assign(audioData.mingSongTypeCollection, {
+					beatMingSongEle: beatMingSong,
+					beatMingSongGirlEle: beatMingSongGirl
 				})
 				if (beatMusic) {
 					beatMusic.addEventListener("play", onPlay);
@@ -372,10 +401,24 @@ export default defineComponent({
 					beatBanSong.addEventListener("play", onPlay);
 					beatBanSong.addEventListener("ended", onEnded);
 					beatMingSong && (beatMingSong.muted = true);
-				} else if(beatMingSong){
+				} 
+				if(beatMingSong){
 					beatMingSong.addEventListener("play", onPlay);
 					beatMingSong.addEventListener("ended", onEnded);
+				}				
+				if(beatMingSongGirl){
+					beatMingSongGirl.addEventListener("play", onPlay);
+					beatMingSongGirl.addEventListener("ended", onEnded);
 				}
+				// 给男声女声赋值
+				const userGender = storeData.user.gender
+				// 当不为null 和undefined的时候 取userGender的值
+				if(userGender!==undefined && userGender!==null){
+					audioData.mingSongType = userGender
+				}
+				// 重新根据性别赋值
+				changeMingSongType()
+
 				state.audioDone = true;
 				state.isLoading = false
 				console.timeEnd("音频加载时间")

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

@@ -148,7 +148,7 @@ export default defineComponent({
 			await osmd.load(musicData.score);
 			// 对外暴露 一行谱时候 缩小谱面
 			if(state.isSimplePage){
-				state.zoom = 0.6
+				state.zoom = 0.5
 			}
 			// 需要渲染总谱的云教练页面
 			if (!state.isSimplePage && state.isCombineRender) {

+ 2 - 0
src/view/plugins/toggleMusicSheet/index.tsx

@@ -38,6 +38,8 @@ export default defineComponent({
           canselect
         }
       }).filter((item: any) => item.canselect).sort((a: any, b: any) => a.sortId - b.sortId)
+      // 支持总谱渲染的时候 加上总谱字段
+      state.isScoreRender && arr.unshift({canselect:true, sortId:999, text: "总谱", value: 999})
       return arr
     })