|
@@ -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";
|
|
@@ -10,16 +10,18 @@ import { audioListStart, getAudioCurrentTime, getAudioDuration, setAudioCurrentT
|
|
|
import { toggleFollow } from "./view/follow-practice";
|
|
|
import { browser, setStorageSpeed, setGlobalData } from "./utils";
|
|
|
import { api_cloudGetMediaStatus, api_createMusicPlayer, api_cloudChangeSpeed, api_cloudSuspend, api_cloudSetCurrentTime, api_cloudDestroy } from "./helpers/communication";
|
|
|
-import { verifyCanRepeat, getDuration } from "./helpers/formateMusic";
|
|
|
+import { verifyCanRepeat, getDuration, xmlAddPartName } from "./helpers/formateMusic";
|
|
|
import { getMusicSheetDetail } from "./utils/baseApi"
|
|
|
import { getQuery } from "/src/utils/queryString";
|
|
|
import { followData, skipNotePractice } from "/src/view/follow-practice/index"
|
|
|
-import { changeSongSourceByBate } from "/src/view/audio-list"
|
|
|
+import { changeSongSourceByBeat } 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, 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();
|
|
|
|
|
@@ -317,6 +319,8 @@ const state = reactive({
|
|
|
extConfigJson: {} as any,
|
|
|
/** 扩展样式字段 */
|
|
|
extStyleConfigJson: {} as any,
|
|
|
+ /** 简谱扩展样式字段 */
|
|
|
+ extJianStyleConfigJson: {} as any,
|
|
|
/** 是否开启节拍器(mp3节拍器) */
|
|
|
isOpenMetronome: false,
|
|
|
/** 演唱模式是否开启节拍器(mp3节拍器) */
|
|
@@ -368,6 +372,8 @@ const state = reactive({
|
|
|
needTick: false,
|
|
|
/** 演唱模式是否需要节拍器 */
|
|
|
needSingTick: false,
|
|
|
+ /** 是否能使用节拍器 */
|
|
|
+ isMixBeat: true,
|
|
|
/** 曲谱实例 */
|
|
|
osmd: null as unknown as OpenSheetMusicDisplay,
|
|
|
/**是否是特殊乐谱类型, 主要针对管乐迷 */
|
|
@@ -439,6 +445,12 @@ const state = reactive({
|
|
|
secondEvXmlBeginTime: 0,
|
|
|
/** evxml等待播放的时间集合,多遍反复播放,会有多个timegap(前奏)时间 */
|
|
|
evXmlBeginArr: [] as any,
|
|
|
+ /** evxml的曲子是否有times */
|
|
|
+ xmlHasTimes: false,
|
|
|
+ /** evxml的曲子是否有timeGap */
|
|
|
+ xmlHasTimeGap: false,
|
|
|
+ /** 有timeGap的曲子,是从哪个小节开始循环的,默认从第一小节开始循环 */
|
|
|
+ timegapRepeatMeasureIndex: 1,
|
|
|
/** 指法信息 */
|
|
|
fingeringInfo: {} as IFingering,
|
|
|
/** 滚动容器的ID */
|
|
@@ -497,6 +509,8 @@ const state = reactive({
|
|
|
beatStartTime: 0,
|
|
|
/** 是否为详情预览模式 */
|
|
|
isPreView: false,
|
|
|
+ /** 是否为内容平台预览模式 */
|
|
|
+ isCbsView: false,
|
|
|
/** 是否为评测报告模式 */
|
|
|
isEvaluatReport: false,
|
|
|
/** midi播放器是否初始化中 */
|
|
@@ -512,7 +526,7 @@ const state = reactive({
|
|
|
/** 音频文件是否加载完成 */
|
|
|
audioDone: false,
|
|
|
/** 是否为单行谱渲染模式 */
|
|
|
- isSingleLine: true,
|
|
|
+ isSingleLine: false,
|
|
|
/** 是否是evxml */
|
|
|
isEvxml: false,
|
|
|
noTimes: [] as any,
|
|
@@ -560,6 +574,11 @@ const state = reactive({
|
|
|
workSectionNeedReset: false,
|
|
|
/** 旋律线开关 */
|
|
|
melodyLine: true,
|
|
|
+ /** 是否是C调,切换到唱名时,只有C调所有的谱面类型都可以播放唱名文件;其它调的只有首调可以播放唱名,因为唱名是按照C调制作的,没有其它调的唱名文件 */
|
|
|
+ isCTone: false,
|
|
|
+ evxmlAddPartName: false, // 妙极客的部分曲子没有part-name,需要自行添加的part-name
|
|
|
+ /** 乐器id */
|
|
|
+ instrumentId: null,
|
|
|
});
|
|
|
const browserInfo = browser();
|
|
|
let offset_duration = 0;
|
|
@@ -607,6 +626,7 @@ const autoResetPlay = () => {
|
|
|
skipNotePlay(0, true);
|
|
|
// 没有开启自动重播, 不是练习模式
|
|
|
if (!state.setting.repeatAutoPlay) return;
|
|
|
+ offsetTop = 0;
|
|
|
scrollViewNote();
|
|
|
setTimeout(() => {
|
|
|
togglePlay("play");
|
|
@@ -638,7 +658,7 @@ export const onEnded = () => {
|
|
|
// 根据当前小节动态设置,右上角展示的速度
|
|
|
const dynamicShowPlaySpeed = (index: number) => {
|
|
|
if (!headerColumnHide.value) {
|
|
|
- console.log('动态计算速度')
|
|
|
+ // console.log('动态计算速度')
|
|
|
const item: any = state.times[index];
|
|
|
if (item && item.measureSpeed ) {
|
|
|
// console.log('速度1',item.measureSpeed)
|
|
@@ -751,6 +771,7 @@ const handlePlaying = () => {
|
|
|
};
|
|
|
/** 跳转到指定音符开始播放 */
|
|
|
export const skipNotePlay = async (itemIndex: number, isStart = false) => {
|
|
|
+ if (state.isPreView) return;
|
|
|
console.log('点击音符')
|
|
|
const item = state.times[itemIndex];
|
|
|
let itemTime = item.time;
|
|
@@ -795,7 +816,11 @@ export const togglePlay = async (playState: "play" | "paused", isForceCLoseToast
|
|
|
// 播放之前 当为评测模式和不为MIDI时候按 是否禁用节拍器 切换音源
|
|
|
if (playState === 'play' && state.modeType === "practise" && state.playMode !== "MIDI") {
|
|
|
console.log("设置音源")
|
|
|
- changeSongSourceByBate(metronomeData.disable)
|
|
|
+ changeSongSourceByBeat(metronomeData.disable)
|
|
|
+ }
|
|
|
+ if (playState === 'play') {
|
|
|
+ offsetTop = 0;
|
|
|
+ scrollViewNote();
|
|
|
}
|
|
|
// midi播放
|
|
|
if (state.isAppPlay) {
|
|
@@ -1000,13 +1025,16 @@ export const gotoNext = (note: any, skipNote?: boolean) => {
|
|
|
const num = note.i;
|
|
|
|
|
|
if (state.activeNoteIndex === note.i) {
|
|
|
- try {
|
|
|
- setCursorPosition(note, state.osmd.cursor, 'init');
|
|
|
- } catch (error) {
|
|
|
- console.log(error);
|
|
|
- }
|
|
|
+ /* 没有光标了 这里就算加上光标也要性能优化 */
|
|
|
+ // try {
|
|
|
+ // setCursorPosition(note, state.osmd.cursor, 'init');
|
|
|
+ // } catch (error) {
|
|
|
+ // console.log(error);
|
|
|
+ // }
|
|
|
// 重置 或者切换演奏演唱的时候 可能出现 state.activeNoteIndex === note.i的情况 执行
|
|
|
- fillWordColor();
|
|
|
+ if(state.playState === "paused"){
|
|
|
+ fillWordColor();
|
|
|
+ }
|
|
|
if (state.isSingleLine && state.playState === "paused") {
|
|
|
moveSvgDom(skipNote);
|
|
|
}
|
|
@@ -1035,14 +1063,15 @@ export const gotoNext = (note: any, skipNote?: boolean) => {
|
|
|
} else {
|
|
|
gotoCustomNote(num);
|
|
|
}
|
|
|
- try {
|
|
|
- setCursorPosition(note, state.osmd.cursor, 'refresh');
|
|
|
- } catch (error) {
|
|
|
- console.log(error);
|
|
|
- }
|
|
|
+ /* 取消光标了 */
|
|
|
+ // try {
|
|
|
+ // setCursorPosition(note, state.osmd.cursor, 'refresh');
|
|
|
+ // } catch (error) {
|
|
|
+ // console.log(error);
|
|
|
+ // }
|
|
|
fillWordColor();
|
|
|
// 一行谱,需要滚动小节
|
|
|
- if (state.isSingleLine) {
|
|
|
+ if (state.isSingleLine && state.playState === "paused") {
|
|
|
moveSvgDom(skipNote);
|
|
|
}
|
|
|
scrollViewNote();
|
|
@@ -1053,7 +1082,7 @@ export const getNote = (currentTime: number) => {
|
|
|
const len = state.times.length;
|
|
|
/** 播放超过了最后一个音符的时间,直接结束, 2秒误差 */
|
|
|
if (currentTime > times[len - 1].endtime + 2 && !state.isAppPlay && !state.isSimplePage) {
|
|
|
- onEnded();
|
|
|
+ // onEnded();
|
|
|
return;
|
|
|
}
|
|
|
let _item = null as any;
|
|
@@ -1093,9 +1122,12 @@ export const handleResetPlay = () => {
|
|
|
audioData.progress = 0
|
|
|
}
|
|
|
// 如果是作业模式,不还原速度
|
|
|
- if (!query.workRecord) {
|
|
|
- resetBaseRate();
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * #TODO:2024.09.14,业务需求变更,重播不还原用户设置的速度
|
|
|
+ */
|
|
|
+ // if (!query.workRecord) {
|
|
|
+ // resetBaseRate();
|
|
|
+ // }
|
|
|
resetPlaybackToStart();
|
|
|
// 如果是暂停, 直接播放
|
|
|
togglePlay("play");
|
|
@@ -1263,14 +1295,26 @@ let offsetTop = 0;
|
|
|
* @param isScroll 可选: 强制滚动到顶部, 默认: false
|
|
|
* @returns void
|
|
|
*/
|
|
|
-export const scrollViewNote = () => {
|
|
|
- const cursorElement = document.getElementById("cursorImg-0")!;
|
|
|
+export const scrollViewNote = (resetTop?: boolean) => {
|
|
|
+ // const cursorElement = document.getElementById("cursorImg-0")!;
|
|
|
+ const noteId = state.times[state.activeNoteIndex].id;
|
|
|
+ if (state.isSingleLine) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (state.activeNoteIndex <= 1 || resetTop) {
|
|
|
+ offsetTop = 0;
|
|
|
+ }
|
|
|
+ const domId = "vf" + noteId;
|
|
|
+ const cursorElement: any = noteId ? document.querySelector(`[data-vf=${domId}]`)?.parentElement : document.getElementById('restDot')?.parentElement;
|
|
|
const musicAndSelection = document.getElementById(state.scrollContainer)!;
|
|
|
- if (!cursorElement || !musicAndSelection || offsetTop === cursorElement.offsetTop) return;
|
|
|
- offsetTop = cursorElement.offsetTop;
|
|
|
- if (offsetTop > 50) {
|
|
|
+ // offsetTop = musicAndSelection.scrollTop || offsetTop;
|
|
|
+ const noteCenterOffsetTop = cursorElement ? cursorElement?.offsetTop + (cursorElement?.offsetHeight/2) : 0;
|
|
|
+ // console.log('滑动',offsetTop, noteCenterOffsetTop)
|
|
|
+ if (!cursorElement || !noteCenterOffsetTop || !musicAndSelection || offsetTop === noteCenterOffsetTop || Math.abs(offsetTop - noteCenterOffsetTop) < 30) return;
|
|
|
+ offsetTop = noteCenterOffsetTop;
|
|
|
+ if (offsetTop > 100) {
|
|
|
musicAndSelection.scrollTo({
|
|
|
- top: (offsetTop - 50) * state.musicZoom,
|
|
|
+ top: (offsetTop - 100) * state.musicZoom,
|
|
|
behavior: "smooth",
|
|
|
});
|
|
|
} else {
|
|
@@ -1333,13 +1377,30 @@ 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没有值的时候
|
|
|
+ // 是否显示节拍器
|
|
|
+ state.isMixBeat = res.data?.isMixBeat
|
|
|
+ let partIndex = query["part-index"] ? parseInt(query["part-index"]) : -1 // -1为partIndex没有值的时候
|
|
|
+ // 如果是评测报告,会有默认的分轨index
|
|
|
+ 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
|
|
|
+ }
|
|
|
+ }
|
|
|
/* 获取声轨列表 */
|
|
|
- const xmlString = await fetch(res.data.xmlFileUrl).then((response) => response.text());
|
|
|
+ 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,
|
|
@@ -1361,32 +1422,35 @@ 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
|
|
|
+ state.instrumentId = instrumentId;
|
|
|
let { musicSheetType, isAllSubject, musicSheetSoundList, musicSheetAccompanimentList } = data
|
|
|
musicSheetSoundList || (musicSheetSoundList = [])
|
|
|
musicSheetAccompanimentList || (musicSheetAccompanimentList = [])
|
|
|
let musicObj, accompanyObj, fanSongObj, banSongObj
|
|
|
/* 独奏 */
|
|
|
if (musicSheetType === "SINGLE") {
|
|
|
- // 适用声部(isAllSubject)为true 时候没有乐器只有一个原音;当前用户有乐器就匹配 不然取第一个原音
|
|
|
+ accompanyObj = musicSheetAccompanimentList.find((item: any) => {
|
|
|
+ return item.audioPlayType === "PLAY"
|
|
|
+ })
|
|
|
+ // 是否全声部(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也找不到曲目所以尝试取第一个
|
|
|
- musicObj || (musicObj = musicSheetSoundList.find((item: any) => {
|
|
|
- return item.audioPlayType === "PLAY"
|
|
|
- }))
|
|
|
+ // 当没有找到原音的时候,并且instrumentId没有值的时候,取默认第一个乐器
|
|
|
+ if(!musicObj && !instrumentId){
|
|
|
+ musicObj = musicSheetSoundList.find((item: any) => {
|
|
|
+ return item.audioPlayType === "PLAY"
|
|
|
+ })
|
|
|
+ }
|
|
|
fanSongObj = musicSheetSoundList.find((item: any) => {
|
|
|
return item.audioPlayType === "SING"
|
|
|
})
|
|
|
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
|
|
@@ -1399,24 +1463,21 @@ function initMusicSource(data: any, tracks: string[], partIndex: number) {
|
|
|
// 总谱渲染
|
|
|
state.isCombineRender = true
|
|
|
state.partListNames = tracks
|
|
|
- // 总谱演唱模式是 范唱
|
|
|
- fanSongObj = musicSheetAccompanimentList.find((item: any) => {
|
|
|
+ banSongObj = musicSheetAccompanimentList.find((item: any) => {
|
|
|
return item.audioPlayType === "SING"
|
|
|
})
|
|
|
- // 先取scoreAudioFileUrl的值
|
|
|
- if(fanSongObj?.scoreAudioFileUrl){
|
|
|
- fanSongObj.audioFileUrl = fanSongObj.scoreAudioFileUrl
|
|
|
- fanSongObj.audioBeatMixUrl = fanSongObj.scoreAudioBeatMixUrl
|
|
|
+ // 总谱演唱模式是 范唱,取banSongObj 里面的scoreAudioFileUrl字段
|
|
|
+ // 先取scoreAudioFileUrl的值 如果 没有就是空
|
|
|
+ if(banSongObj){
|
|
|
+ fanSongObj = {
|
|
|
+ audioFileUrl: banSongObj.scoreAudioFileUrl,
|
|
|
+ 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
|
|
|
musicalInstrumentId = ''
|
|
@@ -1469,18 +1530,21 @@ function initMusicSource(data: any, tracks: string[], partIndex: number) {
|
|
|
state.mingSong = fanSongObj?.solmizationFileUrl
|
|
|
state.mingSongGirl = fanSongObj?.femaleSolmizationFileUrl
|
|
|
}
|
|
|
- Object.assign(state.beatSong, {
|
|
|
- music: musicObj?.audioBeatMixUrl,
|
|
|
- accompany: accompanyObj?.audioBeatMixUrl,
|
|
|
- fanSong: fanSongObj?.audioBeatMixUrl,
|
|
|
- banSong: banSongObj?.audioBeatMixUrl
|
|
|
- })
|
|
|
- // 如果没有男唱名
|
|
|
- if(!fanSongObj?.solmizationBeatUrl){
|
|
|
- state.beatSong.mingSong = fanSongObj?.femaleSolmizationBeatUrl
|
|
|
- }else{
|
|
|
- state.beatSong.mingSong = fanSongObj?.solmizationBeatUrl
|
|
|
- state.beatSong.mingSongGirl = fanSongObj?.femaleSolmizationBeatUrl
|
|
|
+ // 当使用节拍器的时候才加载节拍器音频
|
|
|
+ if(state.isMixBeat) {
|
|
|
+ Object.assign(state.beatSong, {
|
|
|
+ music: musicObj?.audioBeatMixUrl,
|
|
|
+ accompany: accompanyObj?.audioBeatMixUrl,
|
|
|
+ fanSong: fanSongObj?.audioBeatMixUrl,
|
|
|
+ banSong: banSongObj?.audioBeatMixUrl
|
|
|
+ })
|
|
|
+ // 如果没有男唱名
|
|
|
+ if(!fanSongObj?.solmizationBeatUrl){
|
|
|
+ state.beatSong.mingSong = fanSongObj?.femaleSolmizationBeatUrl
|
|
|
+ }else{
|
|
|
+ state.beatSong.mingSong = fanSongObj?.solmizationBeatUrl
|
|
|
+ state.beatSong.mingSongGirl = fanSongObj?.femaleSolmizationBeatUrl
|
|
|
+ }
|
|
|
}
|
|
|
return {
|
|
|
index,
|
|
@@ -1489,20 +1553,57 @@ function initMusicSource(data: any, tracks: string[], partIndex: number) {
|
|
|
}
|
|
|
}
|
|
|
const setState = (data: any, index: number) => {
|
|
|
+ // 获取当前模式 声部切换用
|
|
|
+ const localStoragePlayType = localStorage.getItem("musicScorePlayType")
|
|
|
+ if(localStoragePlayType) {
|
|
|
+ localStorage.removeItem("musicScorePlayType")
|
|
|
+ const fields = localStoragePlayType.split(',')
|
|
|
+ state.playType = fields[0] as any
|
|
|
+ state.playSource = fields[1] as any
|
|
|
+ }
|
|
|
// 根据当前文件有没有 设置当前的播放模式
|
|
|
- if(!state.music){
|
|
|
- if(state.accompany){
|
|
|
- state.playSource = "background"
|
|
|
+ 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.music){
|
|
|
+ state.playType = "play"
|
|
|
+ state.playSource = "music"
|
|
|
+ }else if(state.accompany){
|
|
|
+ state.playType = "play"
|
|
|
+ state.playSource = "background"
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1520,12 +1621,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;
|
|
@@ -1579,9 +1680,11 @@ const setState = (data: any, index: number) => {
|
|
|
state.isConcert = data.musicSheetType === "CONCERT" ? true : false;
|
|
|
// multiTracksSelection 返回为空,默认代表全部分轨
|
|
|
state.canSelectTracks = data.multiTracksSelection === "null" || data.multiTracksSelection === "" || data.multiTracksSelection === null ? [] : data.multiTracksSelection?.split(',');
|
|
|
+ state.canSelectTracks = state.canSelectTracks.map((item: any)=>item.trim())
|
|
|
// 开启预备小节
|
|
|
state.isOpenPrepare = true;
|
|
|
state.extStyleConfigJson = data.extStyleConfigJson || {}
|
|
|
+ state.extJianStyleConfigJson = data.extJianStyleConfigJson || {}
|
|
|
// console.log("🚀 ~ state.subjectId:", state.subjectId, state.track as any , state.subjectId)
|
|
|
// 是否打击乐
|
|
|
/**
|
|
@@ -1620,7 +1723,9 @@ const setState = (data: any, index: number) => {
|
|
|
// 如果是PC端,放大曲谱
|
|
|
state.platform = query.platform?.toLocaleUpperCase() || "";
|
|
|
if (state.platform === IPlatform.PC) {
|
|
|
- state.zoom = query.zoom || 1.5;
|
|
|
+ if (query.zoom <= 1) {
|
|
|
+ state.zoom = query.zoom || state.zoom;
|
|
|
+ }
|
|
|
state.enableEvaluation = false;
|
|
|
}
|
|
|
/**
|
|
@@ -1629,13 +1734,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' : ''
|
|
@@ -1778,22 +1883,49 @@ export const addNoteBBox = (list: any[]) => {
|
|
|
}
|
|
|
|
|
|
// 给歌词和音符添加动态颜色
|
|
|
+let prevActiveNoteIndex = -1 // 上一个激活的
|
|
|
export const fillWordColor = () => {
|
|
|
- // console.log('当前音符',state.activeNoteIndex)
|
|
|
- state.times.forEach((item: any, idx: number) => {
|
|
|
- const svgEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}`)
|
|
|
- const stemEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}-stem`)
|
|
|
- const stemLine = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}-lines`)
|
|
|
- if ((item.i === state.activeNoteIndex || item.id === state.times[state.activeNoteIndex].id) && item.svgElement) {
|
|
|
- svgEl?.classList.add('noteActive')
|
|
|
- stemEl?.classList.add('noteActive')
|
|
|
- stemLine?.classList.add('noteActive')
|
|
|
- } else {
|
|
|
- svgEl?.classList.remove('noteActive')
|
|
|
- stemEl?.classList.remove('noteActive')
|
|
|
- stemLine?.classList.remove('noteActive')
|
|
|
+ // console.log('当前音符',state.activeNoteIndex,prevActiveNoteIndex)
|
|
|
+ if(prevActiveNoteIndex !== -1) {
|
|
|
+ const prevActiveNoteId = state.times[prevActiveNoteIndex]?.svgElement?.attrs?.id
|
|
|
+ const svgEl = document.getElementById(`vf-${prevActiveNoteId}`)
|
|
|
+ const stemEl = document.getElementById(`vf-${prevActiveNoteId}-stem`)
|
|
|
+ const stemLine = document.getElementById(`vf-${prevActiveNoteId}-lines`)
|
|
|
+ svgEl?.classList.remove('noteActive')
|
|
|
+ stemEl?.classList.remove('noteActive')
|
|
|
+ // stemLine?.classList.remove('noteActive')
|
|
|
+ svgEl?.parentElement?.classList.remove('voiceActive')
|
|
|
+ const si = state.times[prevActiveNoteIndex].si || 0;
|
|
|
+ svgEl?.parentElement?.querySelectorAll('rect')?.forEach((item: any) => {
|
|
|
+ item?.classList.remove('rectActive');
|
|
|
+ })
|
|
|
+ // svgEl?.parentElement?.querySelectorAll('rect')?.[si]?.classList.remove('rectActive');
|
|
|
+ }
|
|
|
+ const activeNoteId = state.times[state.activeNoteIndex]?.svgElement?.attrs?.id
|
|
|
+ const svgEl = document.getElementById(`vf-${activeNoteId}`)
|
|
|
+ const stemEl = document.getElementById(`vf-${activeNoteId}-stem`)
|
|
|
+ const stemLine = document.getElementById(`vf-${activeNoteId}-lines`)
|
|
|
+ svgEl?.classList.add('noteActive')
|
|
|
+ stemEl?.classList.add('noteActive')
|
|
|
+ // stemLine?.classList.add('noteActive')
|
|
|
+ // 如果是简谱、固定调,需要把音符后面跟着的"-"也添加颜色
|
|
|
+ if (state.musicRenderType === EnumMusicRenderType.firstTone || state.musicRenderType === EnumMusicRenderType.fixedTone) {
|
|
|
+ // const parentVoice = svgEl?.parentElement;
|
|
|
+ // 简谱模式下,二分音符和全音符才显示音符右侧的"-"
|
|
|
+ if (state.times[state.activeNoteIndex].noteElement?.length?.realValue >= 0.5) {
|
|
|
+ // 如果是二分音符,只亮该音符后面那个"-",本小节其它的"-"不亮
|
|
|
+ if (state.times[state.activeNoteIndex].noteElement?.length?.realValue === 0.5) {
|
|
|
+ const si = state.times[state.activeNoteIndex].si || 0;
|
|
|
+ const halfNotes = state.times[state.activeNoteIndex].measures.filter((item: any) => item?.noteElement?.length?.realValue === 0.5) || [];
|
|
|
+ const sIdx = halfNotes?.findIndex((item: any) => item?.noteElement === state.times[state.activeNoteIndex]?.noteElement);
|
|
|
+ const filterRects = svgEl?.parentElement?.querySelectorAll('rect')?.length ? Array.from(svgEl?.parentElement?.querySelectorAll('rect')).filter(item => item.parentElement === svgEl?.parentElement) : [];
|
|
|
+ filterRects?.[sIdx]?.classList.add('rectActive');
|
|
|
+ } else {
|
|
|
+ svgEl?.parentElement?.classList.add('voiceActive');
|
|
|
+ }
|
|
|
}
|
|
|
- })
|
|
|
+ }
|
|
|
+ prevActiveNoteIndex = state.activeNoteIndex
|
|
|
|
|
|
// 给当前匹配到的歌词添加颜色
|
|
|
const currentNote = state.times[state.activeNoteIndex];
|
|
@@ -1808,6 +1940,10 @@ export const fillWordColor = () => {
|
|
|
const onlyOneLyric = currentNote.measures?.every((item: any) => item?.formatLyricsEntries?.length <= 1);
|
|
|
if ((index === currentNote.repeatIdx && currentNote.repeatIdx + 1 == lyricIndex) || (currentNote.repeatIdx != index && !onlyOneLyric && currentNote.repeatIdx + 1 == lyricIndex) || (currentNote.repeatIdx > 0 && currentNote.formatLyricsEntries?.length === 1 && onlyOneLyric)) {
|
|
|
lyric?.classList.add('lyricActive')
|
|
|
+ }
|
|
|
+ // bug: #11189,兼容处理需要唱4遍,但是只打了2遍歌词的情况,1、3唱一样的歌词,2、4唱一样的歌词
|
|
|
+ if ( currentNote.formatLyricsEntries.length == 2 && currentNote.repeatIdx >= 2 && index === (currentNote.repeatIdx - 2) ) {
|
|
|
+ lyric?.classList.add('lyricActive')
|
|
|
}
|
|
|
// if ((index === currentNote.repeatIdx && currentNote.repeatIdx + 1 == lyricIndex)) {
|
|
|
// lyric?.classList.add('lyricActive')
|
|
@@ -1828,9 +1964,7 @@ export const moveSvgDom = (skipNote?: boolean) => {
|
|
|
// 移动小鸟的位置
|
|
|
moveSmoothAnimation(0, state.activeNoteIndex, false)
|
|
|
// 移动谱面当当前音符的位置
|
|
|
- const noteWidth = state.times[state.activeNoteIndex].bbox?.originWidth || state.times[state.activeNoteIndex].bbox?.width;
|
|
|
- const firstNoteWidth = state.times[0].bbox?.originWidth || state.times[0].bbox?.width;
|
|
|
- const distance = state.times[state.activeNoteIndex].bbox?.x - state.times[0].bbox?.x + noteWidth / 2 - firstNoteWidth / 2;
|
|
|
+ const distance = state.times[state.activeNoteIndex].bbox?.x - state.times[0].bbox?.x
|
|
|
smoothAnimationState.osdmScrollDom!.scrollTo({
|
|
|
left: distance,
|
|
|
behavior: "smooth",
|
|
@@ -1882,15 +2016,33 @@ watch(
|
|
|
// const matchMeasureNum = state.activeMeasureIndex - needReduceMultipleRestNum - 1
|
|
|
// console.log('选中的小节',matchMeasureNum,'需要减去的小节',needReduceMultipleRestNum,'当前的小节',state.activeMeasureIndex)
|
|
|
state.vfmeasures.forEach((item: any, idx: number) => {
|
|
|
- const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : -1;
|
|
|
- const nextMeasureNum = state.vfmeasures[idx+1]?.getAttribute('data-num') ? Number(state.vfmeasures[idx+1]?.getAttribute('data-num')) : -1;
|
|
|
- if (measureNum >= 0 && (measureNum === state.activeMeasureIndex || (measureNum < state.activeMeasureIndex && nextMeasureNum > state.activeMeasureIndex)) || (measureNum < state.activeMeasureIndex && nextMeasureNum == -1) ) {
|
|
|
- item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
|
|
|
- item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
|
|
|
+ const dataNum = item.getAttribute('data-num') // 值可能为字符串类型的undefined
|
|
|
+ let measureNum = (dataNum && dataNum !== "undefined") ? Number(dataNum) : -1;
|
|
|
+ let nextDataNum = state.vfmeasures[idx+1]?.getAttribute('data-num')
|
|
|
+ // 当有换行小节,下个小节的nextDataNum是undefined,所以这里需要往后找一个
|
|
|
+ if(!(nextDataNum && nextDataNum !== "undefined")){
|
|
|
+ nextDataNum = state.vfmeasures[idx + 2]?.getAttribute('data-num')
|
|
|
+ }
|
|
|
+ const nextMeasureNum = Number(nextDataNum)
|
|
|
+ // 当measureNum 为undefined 则是下一个小节的换行小节,所以这里等于下一个小节
|
|
|
+ if(measureNum === -1) {
|
|
|
+ measureNum = nextMeasureNum
|
|
|
+ }
|
|
|
+ if (measureNum >= 0 && (measureNum === state.activeMeasureIndex || (measureNum < state.activeMeasureIndex && nextMeasureNum > state.activeMeasureIndex))) {
|
|
|
+ if (state.isCbsView) {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#FFF6E1")
|
|
|
+ } else {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
|
|
|
+ item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
|
|
|
+ }
|
|
|
// 预备小节
|
|
|
if(state.sectionFirst && measureNum === state.sectionFirst.MeasureNumberXML && state.section.length === 2){
|
|
|
- item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
|
|
|
- item?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
|
|
|
+ if (state.isCbsView) {
|
|
|
+ item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#E3F1FF")
|
|
|
+ } else {
|
|
|
+ item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
|
|
|
+ item?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
|
|
|
+ }
|
|
|
}
|
|
|
} else {
|
|
|
// 有选段只清除选段处的
|
|
@@ -1903,17 +2055,34 @@ watch(
|
|
|
rightMeasureNumberXML = state.section[0].MeasureNumberXML
|
|
|
}
|
|
|
if(measureNum >= leftMeasureNumberXML && measureNum <= rightMeasureNumberXML){
|
|
|
- item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
|
|
|
- item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
|
|
|
+ if (!state.isCbsView) {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
|
|
|
+ item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
|
|
|
+ } else {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", 'transparent')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (measureNum >= leftMeasureNumberXML && measureNum <= rightMeasureNumberXML) {
|
|
|
+ if (state.isCbsView) {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(255,246,225,0.5)")
|
|
|
+ }
|
|
|
}
|
|
|
// 预备小节
|
|
|
if(state.sectionFirst && measureNum === state.sectionFirst.MeasureNumberXML){
|
|
|
- item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
|
|
|
- item?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
|
|
|
+ if (state.isCbsView) {
|
|
|
+ item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#E3F1FF")
|
|
|
+ } else {
|
|
|
+ item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
|
|
|
+ item?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
|
|
|
+ }
|
|
|
}
|
|
|
} else {
|
|
|
- item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
|
|
|
- item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
|
|
|
+ if (!state.isCbsView) {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
|
|
|
+ item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
|
|
|
+ } else {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", 'transparent')
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
})
|
|
@@ -1934,42 +2103,120 @@ watch(
|
|
|
rightMeasureNumberXML = state.section[0].MeasureNumberXML
|
|
|
}
|
|
|
state.vfmeasures.forEach((item: any, idx: number) => {
|
|
|
- const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : 1;
|
|
|
+ const dataNum = item.getAttribute('data-num') // 值可能为字符串类型的undefined
|
|
|
+ let measureNum = (dataNum && dataNum !== "undefined") ? Number(dataNum) : -1;
|
|
|
+ let nextDataNum = state.vfmeasures[idx+1]?.getAttribute('data-num')
|
|
|
+ // 当有换行小节,下个小节的nextDataNum是undefined,所以这里需要往后找一个
|
|
|
+ if(!(nextDataNum && nextDataNum !== "undefined")){
|
|
|
+ nextDataNum = state.vfmeasures[idx + 2]?.getAttribute('data-num')
|
|
|
+ }
|
|
|
+ const nextMeasureNum = Number(nextDataNum)
|
|
|
+ // 当measureNum 为undefined 则是下一个小节的换行小节,所以这里等于下一个小节
|
|
|
+ if(measureNum === -1) {
|
|
|
+ measureNum = nextMeasureNum
|
|
|
+ }
|
|
|
// 小于选中置灰
|
|
|
if (measureNum < leftMeasureNumberXML) {
|
|
|
- item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(96,159,207,0.5)")
|
|
|
- item.querySelector('.vf-custom-bot')?.setAttribute("fill", "rgba(43,112,165,0.5)")
|
|
|
+ if (!state.isCbsView) {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(96,159,207,0.5)")
|
|
|
+ item.querySelector('.vf-custom-bot')?.setAttribute("fill", "rgba(43,112,165,0.5)")
|
|
|
+ } else {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", 'transparent')
|
|
|
+ }
|
|
|
}
|
|
|
// 大于选中置灰
|
|
|
if(measureNum > rightMeasureNumberXML){
|
|
|
- item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(96,159,207,0.5)")
|
|
|
- item.querySelector('.vf-custom-bot')?.setAttribute("fill", "rgba(43,112,165,0.5)")
|
|
|
+ if (!state.isCbsView) {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(96,159,207,0.5)")
|
|
|
+ item.querySelector('.vf-custom-bot')?.setAttribute("fill", "rgba(43,112,165,0.5)")
|
|
|
+ } else {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", 'transparent')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (measureNum >= leftMeasureNumberXML && measureNum <= rightMeasureNumberXML) {
|
|
|
+ if (state.isCbsView) {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(255,246,225,0.5)")
|
|
|
+ }
|
|
|
}
|
|
|
// 预备小节
|
|
|
if(state.sectionFirst && measureNum === state.sectionFirst.MeasureNumberXML){
|
|
|
- item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
|
|
|
- item?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
|
|
|
+ if (state.isCbsView) {
|
|
|
+ item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#E3F1FF")
|
|
|
+ } else {
|
|
|
+ item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
|
|
|
+ item?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
|
|
|
+ }
|
|
|
}
|
|
|
})
|
|
|
}else{
|
|
|
// 恢复选段前
|
|
|
state.vfmeasures.forEach((item: any, idx: number) => {
|
|
|
- const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : -1;
|
|
|
- const nextMeasureNum = state.vfmeasures[idx+1]?.getAttribute('data-num') ? Number(state.vfmeasures[idx+1]?.getAttribute('data-num')) : -1;
|
|
|
+ const dataNum = item.getAttribute('data-num') // 值可能为字符串类型的undefined
|
|
|
+ let measureNum = (dataNum && dataNum !== "undefined") ? Number(dataNum) : -1;
|
|
|
+ let nextDataNum = state.vfmeasures[idx+1]?.getAttribute('data-num')
|
|
|
+ // 当有换行小节,下个小节的nextDataNum是undefined,所以这里需要往后找一个
|
|
|
+ if(!(nextDataNum && nextDataNum !== "undefined")){
|
|
|
+ nextDataNum = state.vfmeasures[idx + 2]?.getAttribute('data-num')
|
|
|
+ }
|
|
|
+ const nextMeasureNum = Number(nextDataNum)
|
|
|
+ // 当measureNum 为undefined 则是下一个小节的换行小节,所以这里等于下一个小节
|
|
|
+ if(measureNum === -1) {
|
|
|
+ measureNum = nextMeasureNum
|
|
|
+ }
|
|
|
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.isCbsView) {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "transparent")
|
|
|
+ } else {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
|
|
|
+ item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
|
|
|
+ }
|
|
|
} else {
|
|
|
- item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
|
|
|
- item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
|
|
|
+ if (state.isCbsView) {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "transparent")
|
|
|
+ } else {
|
|
|
+ item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
|
|
|
+ item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
)
|
|
|
|
|
|
+// 后台编辑谱面模式,切换谱面时,如果有操作没有保存,需要给出提示
|
|
|
+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.noteCoords = []
|
|
|
+ moveData.modelList = []
|
|
|
clearSelection();
|
|
|
resetBaseRate();
|
|
|
state.activeMeasureIndex = -1;
|