|  | @@ -1,4 +1,4 @@
 | 
	
		
			
				|  |  | -import { closeToast, showToast } from "vant";
 | 
	
		
			
				|  |  | +import { closeToast, showToast, showConfirmDialog } from "vant";
 | 
	
		
			
				|  |  |  import { nextTick, reactive, watch } from "vue";
 | 
	
		
			
				|  |  |  import { OpenSheetMusicDisplay } from "../osmd-extended/src";
 | 
	
		
			
				|  |  |  import { metronomeData } from "./helpers/metronome";
 | 
	
	
		
			
				|  | @@ -20,6 +20,8 @@ import { storeData } from "/src/store";
 | 
	
		
			
				|  |  |  import { downloadXmlStr } from "./view/music-score"
 | 
	
		
			
				|  |  |  import { musicScoreRef, headerColumnHide } from "/src/page-instrument/view-detail/index"
 | 
	
		
			
				|  |  |  import { headTopData } from "/src/page-instrument/header-top/index";
 | 
	
		
			
				|  |  | +import { api_lessonTrainingTrainingStudentDetail } from "/src/page-instrument/api"
 | 
	
		
			
				|  |  | +import { undoData, moveData } from "/src/view/plugins/move-music-score"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const query: any = getQuery();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1355,13 +1357,23 @@ const getMusicInfo = async (res: any) => {
 | 
	
		
			
				|  |  |    if (state.isEvaluatReport) {
 | 
	
		
			
				|  |  |      partIndex = state.partIndex;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  // 布置作业 取作业的乐器id
 | 
	
		
			
				|  |  | +  const workRecord = query.workRecord
 | 
	
		
			
				|  |  | +  let workRecordInstrumentId:undefined | string
 | 
	
		
			
				|  |  | +  if(workRecord){
 | 
	
		
			
				|  |  | +    const res = await api_lessonTrainingTrainingStudentDetail(workRecord);
 | 
	
		
			
				|  |  | +    if (res?.code === 200) {
 | 
	
		
			
				|  |  | +      workRecordInstrumentId = res.data?.instrumentId
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    /* 获取声轨列表 */
 | 
	
		
			
				|  |  |    let xmlString = await fetch(res.data.xmlFileUrl).then((response) => response.text());
 | 
	
		
			
				|  |  |    xmlString = xmlAddPartName(xmlString);
 | 
	
		
			
				|  |  |    downloadXmlStr.value = xmlString //给musice-score 赋值xmlString 以免加载2次
 | 
	
		
			
				|  |  |    const tracks = xmlToTracks(xmlString) //获取声轨列表
 | 
	
		
			
				|  |  |    // 设置音源  track 为当前的声轨 index为当前的
 | 
	
		
			
				|  |  | -  const { track, index, musicalInstrumentId } = state.isSimplePage ? { track:tracks[0], index:0, musicalInstrumentId: '' } : initMusicSource(res.data, tracks, partIndex)
 | 
	
		
			
				|  |  | +  const { track, index, musicalInstrumentId } = state.isSimplePage ? { track:tracks[0], index:0, musicalInstrumentId: '' } : initMusicSource(res.data, tracks, partIndex, workRecordInstrumentId)
 | 
	
		
			
				|  |  | +  // 这里返回的track可能和实际的对不上,所以重新筛选一下
 | 
	
		
			
				|  |  |    const realTrack = musicalInstrumentId && res.data?.musicalInstruments?.length ? res.data?.musicalInstruments.find((item: any) => item?.id == musicalInstrumentId)?.code?.split(',')?.[0] : '';
 | 
	
		
			
				|  |  |    const musicInfo = {
 | 
	
		
			
				|  |  |      ...res.data,
 | 
	
	
		
			
				|  | @@ -1383,9 +1395,9 @@ function xmlToTracks(xmlString: string) {
 | 
	
		
			
				|  |  |    }, []);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  // 设置音源
 | 
	
		
			
				|  |  | -function initMusicSource(data: any, tracks: string[], partIndex: number) {
 | 
	
		
			
				|  |  | +function initMusicSource(data: any, tracks: string[], partIndex: number, workRecordInstrumentId?: string) {
 | 
	
		
			
				|  |  |    let track:string,index:number, musicalInstrumentId: string
 | 
	
		
			
				|  |  | -  const instrumentId = query.instrumentId || storeData.user?.instrumentId
 | 
	
		
			
				|  |  | +  const instrumentId = workRecordInstrumentId || query.instrumentId || storeData.user?.instrumentId
 | 
	
		
			
				|  |  |    let { musicSheetType, isAllSubject, musicSheetSoundList, musicSheetAccompanimentList } = data
 | 
	
		
			
				|  |  |    musicSheetSoundList || (musicSheetSoundList = [])
 | 
	
		
			
				|  |  |    musicSheetAccompanimentList || (musicSheetAccompanimentList = [])
 | 
	
	
		
			
				|  | @@ -1395,27 +1407,15 @@ function initMusicSource(data: any, tracks: string[], partIndex: number) {
 | 
	
		
			
				|  |  |      accompanyObj = musicSheetAccompanimentList.find((item: any) => {
 | 
	
		
			
				|  |  |        return item.audioPlayType === "PLAY"
 | 
	
		
			
				|  |  |      })
 | 
	
		
			
				|  |  | -    // 适用声部(isAllSubject)为true 时候没有乐器只有一个原音;当前用户有乐器就匹配  不然取第一个原音
 | 
	
		
			
				|  |  | +    // 是否全声部(isAllSubject)为true 时候没有乐器只有一个原音(比如节奏练习,这个曲子全部乐器都支持);当前用户有乐器就匹配  不然取第一个原音
 | 
	
		
			
				|  |  |      musicObj = musicSheetSoundList.find((item: any) => {
 | 
	
		
			
				|  |  | -      return (isAllSubject || !instrumentId) ? item.audioPlayType === "PLAY" : (item.audioPlayType === "PLAY" && item.musicalInstrumentId == instrumentId)
 | 
	
		
			
				|  |  | +      return isAllSubject ? item.audioPlayType === "PLAY" : (item.audioPlayType === "PLAY" && item.musicalInstrumentId == instrumentId)
 | 
	
		
			
				|  |  |      })
 | 
	
		
			
				|  |  | -    // 因为可能根据学生的乐器id也找不到曲目所以尝试取第一个
 | 
	
		
			
				|  |  | -    if(!musicObj){
 | 
	
		
			
				|  |  | +    // 当没有找到原音的时候,并且instrumentId没有值的时候,取默认第一个乐器
 | 
	
		
			
				|  |  | +    if(!musicObj && !instrumentId){
 | 
	
		
			
				|  |  |        musicObj = musicSheetSoundList.find((item: any) => {
 | 
	
		
			
				|  |  |          return item.audioPlayType === "PLAY"
 | 
	
		
			
				|  |  |        })
 | 
	
		
			
				|  |  | -      // 取第一个时候,不播放演奏文件切换为演唱模式  总控平台排除这个逻辑
 | 
	
		
			
				|  |  | -      if(!query.isCbs){
 | 
	
		
			
				|  |  | -        state.playType = "sing"
 | 
	
		
			
				|  |  | -        if(musicObj) {
 | 
	
		
			
				|  |  | -          musicObj.audioFileUrl = null
 | 
	
		
			
				|  |  | -          musicObj.audioBeatMixUrl = null
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if(accompanyObj) {
 | 
	
		
			
				|  |  | -          accompanyObj.audioFileUrl = null
 | 
	
		
			
				|  |  | -          accompanyObj.audioBeatMixUrl = null
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      fanSongObj = musicSheetSoundList.find((item: any) => {
 | 
	
		
			
				|  |  |        return item.audioPlayType === "SING"
 | 
	
	
		
			
				|  | @@ -1435,14 +1435,16 @@ function initMusicSource(data: any, tracks: string[], partIndex: number) {
 | 
	
		
			
				|  |  |          // 总谱渲染
 | 
	
		
			
				|  |  |          state.isCombineRender = true
 | 
	
		
			
				|  |  |          state.partListNames = tracks
 | 
	
		
			
				|  |  | -        // 总谱演唱模式是 范唱,取scoreAudioFileUrl字段
 | 
	
		
			
				|  |  | -        fanSongObj = musicSheetAccompanimentList.find((item: any) => {
 | 
	
		
			
				|  |  | +        banSongObj = musicSheetAccompanimentList.find((item: any) => {
 | 
	
		
			
				|  |  |            return item.audioPlayType === "SING"
 | 
	
		
			
				|  |  |          })
 | 
	
		
			
				|  |  | +        // 总谱演唱模式是 范唱,取banSongObj 里面的scoreAudioFileUrl字段
 | 
	
		
			
				|  |  |          // 先取scoreAudioFileUrl的值 如果 没有就是空
 | 
	
		
			
				|  |  | -        if(fanSongObj){
 | 
	
		
			
				|  |  | -          fanSongObj.audioFileUrl = fanSongObj.scoreAudioFileUrl
 | 
	
		
			
				|  |  | -          fanSongObj.audioBeatMixUrl = fanSongObj.scoreAudioBeatMixUrl
 | 
	
		
			
				|  |  | +        if(banSongObj){
 | 
	
		
			
				|  |  | +          fanSongObj = {
 | 
	
		
			
				|  |  | +            audioFileUrl: banSongObj.scoreAudioFileUrl,
 | 
	
		
			
				|  |  | +            audioBeatMixUrl: banSongObj.scoreAudioBeatMixUrl
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          // 总谱演奏模式是 伴奏
 | 
	
		
			
				|  |  |          accompanyObj = musicSheetAccompanimentList.find((item: any) => {
 | 
	
	
		
			
				|  | @@ -1524,44 +1526,56 @@ const setState = (data: any, index: number) => {
 | 
	
		
			
				|  |  |    const localStoragePlayType = localStorage.getItem("musicScorePlayType")
 | 
	
		
			
				|  |  |    if(localStoragePlayType) {
 | 
	
		
			
				|  |  |      localStorage.removeItem("musicScorePlayType")
 | 
	
		
			
				|  |  | -    state.playType = localStoragePlayType as any
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -    // 根据当前文件有没有 设置当前的播放模式
 | 
	
		
			
				|  |  | -  if(state.playType === "play"){
 | 
	
		
			
				|  |  | -    if(state.music){
 | 
	
		
			
				|  |  | -      state.playSource = "music"
 | 
	
		
			
				|  |  | -    }else if(state.accompany){
 | 
	
		
			
				|  |  | -      state.playSource = "background"
 | 
	
		
			
				|  |  | +    const fields = localStoragePlayType.split(',')
 | 
	
		
			
				|  |  | +    state.playType = fields[0] as any
 | 
	
		
			
				|  |  | +    state.playSource = fields[1] as any
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  // 根据当前文件有没有 设置当前的播放模式
 | 
	
		
			
				|  |  | +  const playObj = {
 | 
	
		
			
				|  |  | +    "play_music":"music",
 | 
	
		
			
				|  |  | +    "play_background":"accompany",
 | 
	
		
			
				|  |  | +    "sing_music":"fanSong",
 | 
	
		
			
				|  |  | +    "sing_background":"banSong",
 | 
	
		
			
				|  |  | +    "sing_mingSong":"mingSong",
 | 
	
		
			
				|  |  | +  } as any
 | 
	
		
			
				|  |  | +  // 当前缓存 有值的时候 用这个,没有的时候 走筛选
 | 
	
		
			
				|  |  | +  // @ts-ignore
 | 
	
		
			
				|  |  | +  if(!state[playObj[`${state.playType}_${state.playSource}`]]){
 | 
	
		
			
				|  |  | +    if(state.playType === "play"){
 | 
	
		
			
				|  |  | +      if(state.music){
 | 
	
		
			
				|  |  | +        state.playSource = "music"
 | 
	
		
			
				|  |  | +      }else if(state.accompany){
 | 
	
		
			
				|  |  | +        state.playSource = "background"
 | 
	
		
			
				|  |  | +      }else{
 | 
	
		
			
				|  |  | +        if(state.fanSong){
 | 
	
		
			
				|  |  | +          state.playType = "sing"
 | 
	
		
			
				|  |  | +          state.playSource = "music"
 | 
	
		
			
				|  |  | +        }else if(state.banSong){
 | 
	
		
			
				|  |  | +          state.playType = "sing"
 | 
	
		
			
				|  |  | +          state.playSource = "background"
 | 
	
		
			
				|  |  | +        }else if(state.mingSong){
 | 
	
		
			
				|  |  | +          state.playType = "sing"
 | 
	
		
			
				|  |  | +          state.playSource = "mingSong"
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      }else{
 | 
	
		
			
				|  |  |        if(state.fanSong){
 | 
	
		
			
				|  |  | -        state.playType = "sing"
 | 
	
		
			
				|  |  |          state.playSource = "music"
 | 
	
		
			
				|  |  |        }else if(state.banSong){
 | 
	
		
			
				|  |  | -        state.playType = "sing"
 | 
	
		
			
				|  |  |          state.playSource = "background"
 | 
	
		
			
				|  |  |        }else if(state.mingSong){
 | 
	
		
			
				|  |  | -        state.playType = "sing"
 | 
	
		
			
				|  |  |          state.playSource = "mingSong"
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }else{
 | 
	
		
			
				|  |  | -    if(state.fanSong){
 | 
	
		
			
				|  |  | -      state.playSource = "music"
 | 
	
		
			
				|  |  | -    }else if(state.banSong){
 | 
	
		
			
				|  |  | -      state.playSource = "background"
 | 
	
		
			
				|  |  | -    }else if(state.mingSong){
 | 
	
		
			
				|  |  | -      state.playSource = "mingSong"
 | 
	
		
			
				|  |  | -    }else{
 | 
	
		
			
				|  |  | -      if(state.music){
 | 
	
		
			
				|  |  | -        state.playType = "play"
 | 
	
		
			
				|  |  | -        state.playSource = "music"
 | 
	
		
			
				|  |  | -      }else if(state.accompany){
 | 
	
		
			
				|  |  | -        state.playType = "play"
 | 
	
		
			
				|  |  | -        state.playSource = "background"
 | 
	
		
			
				|  |  | +      }else{
 | 
	
		
			
				|  |  | +        if(state.music){
 | 
	
		
			
				|  |  | +          state.playType = "play"
 | 
	
		
			
				|  |  | +          state.playSource = "music"
 | 
	
		
			
				|  |  | +        }else if(state.accompany){
 | 
	
		
			
				|  |  | +          state.playType = "play"
 | 
	
		
			
				|  |  | +          state.playSource = "background"
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    state.appName = "COLEXIU";
 | 
	
		
			
				|  |  |    state.detailId = data.bizId;
 | 
	
		
			
				|  |  |    state.xmlUrl = data.xmlFileUrl;
 | 
	
	
		
			
				|  | @@ -1576,12 +1590,12 @@ const setState = (data: any, index: number) => {
 | 
	
		
			
				|  |  |    /**
 | 
	
		
			
				|  |  |     * 单曲,指法根据用户当前的乐器来显示,如果没有则取musicSheetSoundList第一个track
 | 
	
		
			
				|  |  |     */
 | 
	
		
			
				|  |  | -  const currentInstrumentId = query.instrumentId || storeData.user?.instrumentId;
 | 
	
		
			
				|  |  | -  let musicalCode = !currentInstrumentId ? data.musicSheetSoundList?.find((item:any)=>{ return item.audioPlayType === "PLAY" })?.track || '' : data.musicSheetSoundList?.find((item: any) => item?.musicalInstrumentId == currentInstrumentId && item.audioPlayType === "PLAY")?.track || '';
 | 
	
		
			
				|  |  | -  const pitchSubject = musicalInstrumentCodeInfo.find((n) => n.code.toLocaleLowerCase() === subjectCode.toLocaleLowerCase())
 | 
	
		
			
				|  |  | -  const pitchMusical = musicalInstrumentCodeInfo.find((n) => n.code.toLocaleLowerCase() === musicalCode.toLocaleLowerCase())
 | 
	
		
			
				|  |  | -  state.subjectCodeId = pitchSubject ? pitchSubject.id : 0
 | 
	
		
			
				|  |  | -  state.musicalCodeId = pitchMusical ? pitchMusical.id : 0
 | 
	
		
			
				|  |  | +  // const currentInstrumentId = query.instrumentId || storeData.user?.instrumentId;
 | 
	
		
			
				|  |  | +  // let musicalCode = !currentInstrumentId ? data.musicSheetSoundList?.find((item:any)=>{ return item.audioPlayType === "PLAY" })?.track || '' : data.musicSheetSoundList?.find((item: any) => item?.musicalInstrumentId == currentInstrumentId && item.audioPlayType === "PLAY")?.track || '';
 | 
	
		
			
				|  |  | +  // const pitchSubject = musicalInstrumentCodeInfo.find((n) => n.code.toLocaleLowerCase() === subjectCode.toLocaleLowerCase())
 | 
	
		
			
				|  |  | +  // const pitchMusical = musicalInstrumentCodeInfo.find((n) => n.code.toLocaleLowerCase() === musicalCode.toLocaleLowerCase())
 | 
	
		
			
				|  |  | +  // state.subjectCodeId = pitchSubject ? pitchSubject.id : 0
 | 
	
		
			
				|  |  | +  // state.musicalCodeId = pitchMusical ? pitchMusical.id : 0
 | 
	
		
			
				|  |  |    state.categoriesId = data.musicCategoryId;
 | 
	
		
			
				|  |  |    state.categoriesName = data.musicTagNames;
 | 
	
		
			
				|  |  |    // state.enableEvaluation = data.isEvaluated ? true : false;
 | 
	
	
		
			
				|  | @@ -1685,13 +1699,13 @@ const setState = (data: any, index: number) => {
 | 
	
		
			
				|  |  |     * 能否转谱:先取isConvertibleScore字段,如果isConvertibleScore为true,则取musicalInstruments字段匹配的当前分轨的transferFlag,都为true则可以转谱
 | 
	
		
			
				|  |  |     * 
 | 
	
		
			
				|  |  |     */
 | 
	
		
			
				|  |  | -  let pitchTrack = null
 | 
	
		
			
				|  |  | -  if (state.isConcert) {
 | 
	
		
			
				|  |  | -    musicalCode = musicalInstrumentCodeInfo.find((item: any) => item.id === state.musicalCodeId)?.code
 | 
	
		
			
				|  |  | -    pitchTrack = data.musicalInstruments?.find((item: any) => item.code?.split(',')[0] === musicalCode)
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    pitchTrack = data.musicalInstruments?.find((item: any) => item.code?.split(',')[0] === musicalCode)
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +  // let pitchTrack = null
 | 
	
		
			
				|  |  | +  // if (state.isConcert) {
 | 
	
		
			
				|  |  | +  //   musicalCode = musicalInstrumentCodeInfo.find((item: any) => item.id === state.musicalCodeId)?.code
 | 
	
		
			
				|  |  | +  //   pitchTrack = data.musicalInstruments?.find((item: any) => item.code?.split(',')[0] === musicalCode)
 | 
	
		
			
				|  |  | +  // } else {
 | 
	
		
			
				|  |  | +  //   pitchTrack = data.musicalInstruments?.find((item: any) => item.code?.split(',')[0] === musicalCode)
 | 
	
		
			
				|  |  | +  // }
 | 
	
		
			
				|  |  |    let musicalRenderType = ''
 | 
	
		
			
				|  |  |    // if (pitchTrack?.defaultScore) {
 | 
	
		
			
				|  |  |    //   musicalRenderType = pitchTrack?.defaultScore === 'STAVE' ? 'staff' : pitchTrack?.defaultScore === 'JIAN' ? 'fixedTone' : pitchTrack?.defaultScore === 'FIRST' ? 'firstTone' : ''
 | 
	
	
		
			
				|  | @@ -2086,8 +2100,38 @@ watch(
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// 后台编辑谱面模式,切换谱面时,如果有操作没有保存,需要给出提示
 | 
	
		
			
				|  |  | +export const checkMoveNoSave = async () => {
 | 
	
		
			
				|  |  | +  return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | +    if (query.isMove) {
 | 
	
		
			
				|  |  | +      if (moveData.open && undoData.undoList.length) {
 | 
	
		
			
				|  |  | +        showConfirmDialog({
 | 
	
		
			
				|  |  | +          className: "noSaveModal",
 | 
	
		
			
				|  |  | +          title: "温馨提示",
 | 
	
		
			
				|  |  | +          message: "您有新的修改还未保存,切换谱面后本次编辑的内容将不会保存",
 | 
	
		
			
				|  |  | +        }).then(() => {
 | 
	
		
			
				|  |  | +          moveData.open = false
 | 
	
		
			
				|  |  | +          resolve(true)
 | 
	
		
			
				|  |  | +        }).catch(() => {
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        moveData.open = false
 | 
	
		
			
				|  |  | +        undoData.undoList = []
 | 
	
		
			
				|  |  | +        resolve(true)
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      resolve(true)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** 刷新谱面 */
 | 
	
		
			
				|  |  |  export const refreshMusicSvg = () => {
 | 
	
		
			
				|  |  | +  moveData.modelList = []
 | 
	
		
			
				|  |  |    clearSelection();
 | 
	
		
			
				|  |  |    resetBaseRate();
 | 
	
		
			
				|  |  |    state.activeMeasureIndex = -1;
 |