|  | @@ -541,22 +541,184 @@ export const onlyVisible = (xml: string, partIndex: number, resourceType?: strin
 | 
	
		
			
				|  |  |  	return new XMLSerializer().serializeToString(appoggianceFormate(xmlParse));
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -export const onlyVisible2 = (xml: string): string => {
 | 
	
		
			
				|  |  | +export const onlyVisible2 = (xml: string, partIndexs: Array<any>, resourceType?: string): string => {
 | 
	
		
			
				|  |  |  	if (!xml) return "";
 | 
	
		
			
				|  |  |  	// console.log('原始xml')
 | 
	
		
			
				|  |  | -	//const detailId = state.examSongId + "";
 | 
	
		
			
				|  |  | -	console.time('解析xml 耗时5')
 | 
	
		
			
				|  |  | -	const xmlParse = new DOMParser().parseFromString(xml, "text/xml");
 | 
	
		
			
				|  |  | -	console.timeEnd('解析xml 耗时5')
 | 
	
		
			
				|  |  | +	const detailId = state.examSongId + "";
 | 
	
		
			
				|  |  | +	//console.time('解析xml 耗时4')
 | 
	
		
			
				|  |  | +	// const xmlParse = new DOMParser().parseFromString(xml, "text/xml");
 | 
	
		
			
				|  |  | +	const xmlParse = xmlDocRef.value ? xmlDocRef.value : new DOMParser().parseFromString(xml, "text/xml");
 | 
	
		
			
				|  |  | +	//console.timeEnd('解析xml 耗时4')
 | 
	
		
			
				|  |  |  	const partList = xmlParse.getElementsByTagName("part-list")?.[0]?.getElementsByTagName("score-part") || [];
 | 
	
		
			
				|  |  | -	//const partListNames = Array.from(partList).map((item) => item.getElementsByTagName("part-name")?.[0]?.textContent?.trim() || "");
 | 
	
		
			
				|  |  | +	const partListNames = Array.from(partList).map((item) => item.getElementsByTagName("part-name")?.[0]?.textContent?.trim() || "");
 | 
	
		
			
				|  |  | +	const parts: any = xmlParse.getElementsByTagName("part");
 | 
	
		
			
				|  |  | +	// const firstTimeInfo = parts[0]?.getElementsByTagName('metronome')[0]?.parentElement?.parentElement?.cloneNode(true)
 | 
	
		
			
				|  |  | +	const hasMeasureIdx = Array.from(parts).findIndex((item: any) => item.getElementsByTagName("measure").length) || 0;
 | 
	
		
			
				|  |  | +	const firstMeasures = [...parts[hasMeasureIdx]?.getElementsByTagName("measure")];
 | 
	
		
			
				|  |  | +	state.totalMeasureNumber = firstMeasures.length || [...parts[1]?.getElementsByTagName("measure")]?.length
 | 
	
		
			
				|  |  | +	const metronomes = [...parts[0]?.getElementsByTagName("metronome")];
 | 
	
		
			
				|  |  | +	const words = [...parts[0]?.getElementsByTagName("words")];
 | 
	
		
			
				|  |  | +	const codas = [...parts[0]?.getElementsByTagName("coda")];
 | 
	
		
			
				|  |  | +	const rehearsals = [...parts[0]?.getElementsByTagName("rehearsal")];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/** 第一分谱如果是约定的配置分谱则跳过 */
 | 
	
		
			
				|  |  | +	if (partListNames[0]?.toLocaleUpperCase?.() === "COMMON") {
 | 
	
		
			
				|  |  | +		partIndexs = partIndexs.map(item => item + 1)
 | 
	
		
			
				|  |  | +		//partListNames.shift();
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	const visiblePartInfo = partList[partIndexs[0]];
 | 
	
		
			
				|  |  | +	const ids = partIndexs.map(item => partList[item].getAttribute("id"))
 | 
	
		
			
				|  |  | +	// console.log(visiblePartInfo, partIndex)
 | 
	
		
			
				|  |  | +	// 根据后台已选择的分轨筛选出能切换的声轨
 | 
	
		
			
				|  |  |  	//state.partListNames = partListNames;
 | 
	
		
			
				|  |  | -	Array.from(partList).forEach((part) => {
 | 
	
		
			
				|  |  | -		let partListName = part.getElementsByTagName("part-name")?.[0]?.textContent?.trim();
 | 
	
		
			
				|  |  | -		if (!state.canSelectTracks.includes(partListName)) {
 | 
	
		
			
				|  |  | -			part.parentNode?.removeChild(part);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	});
 | 
	
		
			
				|  |  | +	// console.log('分轨名称',state.partListNames)
 | 
	
		
			
				|  |  | +	if (visiblePartInfo) {
 | 
	
		
			
				|  |  | +		const id = visiblePartInfo.getAttribute("id");
 | 
	
		
			
				|  |  | +		Array.from(parts).forEach((part: any) => {
 | 
	
		
			
				|  |  | +			if (part && !ids.includes(part.getAttribute("id")) ) {
 | 
	
		
			
				|  |  | +				part.parentNode?.removeChild(part);
 | 
	
		
			
				|  |  | +				// 不等于第一行才添加避免重复添加
 | 
	
		
			
				|  |  | +			} else if (part && part.getAttribute("id") !== "P1") {
 | 
	
		
			
				|  |  | +				if (part && part.getAttribute("id") === id) {
 | 
	
		
			
				|  |  | +					// 速度标记仅保留最后一个
 | 
	
		
			
				|  |  | +					const metronomeData: {
 | 
	
		
			
				|  |  | +						[key in string]: Element;
 | 
	
		
			
				|  |  | +					} = {};
 | 
	
		
			
				|  |  | +					for (let i = 0; i < metronomes.length; i++) {
 | 
	
		
			
				|  |  | +						const metronome = metronomes[i];
 | 
	
		
			
				|  |  | +						const metronomeContainer = metronome.parentElement?.parentElement?.parentElement;
 | 
	
		
			
				|  |  | +						if (metronomeContainer) {
 | 
	
		
			
				|  |  | +							const index = firstMeasures.indexOf(metronomeContainer);
 | 
	
		
			
				|  |  | +							metronomeData[index] = metronome;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					Object.values(metronomeData).forEach((metronome) => {
 | 
	
		
			
				|  |  | +						const metronomeContainer: any = metronome.parentElement?.parentElement;
 | 
	
		
			
				|  |  | +						const parentMeasure: any = metronomeContainer?.parentElement;
 | 
	
		
			
				|  |  | +						const measureMetronomes = [...(parentMeasure?.childNodes || [])];
 | 
	
		
			
				|  |  | +						const metronomesIndex = metronomeContainer ? measureMetronomes.indexOf(metronomeContainer) : -1;
 | 
	
		
			
				|  |  | +						// console.log(parentMeasure)
 | 
	
		
			
				|  |  | +						if (parentMeasure && metronomesIndex > -1) {
 | 
	
		
			
				|  |  | +							const index = firstMeasures.indexOf(parentMeasure);
 | 
	
		
			
				|  |  | +							const activeMeasure = part.getElementsByTagName("measure")[index];
 | 
	
		
			
				|  |  | +							setElementNoteBefore(metronomeContainer, parentMeasure, activeMeasure);
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					});
 | 
	
		
			
				|  |  | +					/** word比较特殊需要精确到note位置 */
 | 
	
		
			
				|  |  | +					words.forEach((word) => {
 | 
	
		
			
				|  |  | +						let text = word.textContent || "";
 | 
	
		
			
				|  |  | +						text = ["cresc."].includes(text) ? "" : text;
 | 
	
		
			
				|  |  | +						if ((isSpecialMark(text) || isSpeedKeyword(text) || isGradientWords(text) || isRepeatWord(text) || GRADIENT_SPEED_RESET_TAG) && text) {
 | 
	
		
			
				|  |  | +							const wordContainer = word.parentElement?.parentElement;
 | 
	
		
			
				|  |  | +							const parentMeasure = wordContainer?.parentElement;
 | 
	
		
			
				|  |  | +							const measureWords = [...(parentMeasure?.childNodes || [])];
 | 
	
		
			
				|  |  | +							const wordIndex = wordContainer ? measureWords.indexOf(wordContainer) : -1;
 | 
	
		
			
				|  |  | +							if (wordContainer && parentMeasure && wordIndex > -1) {
 | 
	
		
			
				|  |  | +								const index = firstMeasures.indexOf(parentMeasure);
 | 
	
		
			
				|  |  | +								const activeMeasure = part.getElementsByTagName("measure")[index];
 | 
	
		
			
				|  |  | +								// 找当前小节是否包含word标签
 | 
	
		
			
				|  |  | +								const _words = Array.from(activeMeasure?.getElementsByTagName("words") || []);
 | 
	
		
			
				|  |  | +								// 遍历word标签,检查是否和第一小节重复,如果有重复则不平移word
 | 
	
		
			
				|  |  | +								const total = _words.reduce((total: any, _word: any) => {
 | 
	
		
			
				|  |  | +									if (_word.textContent?.includes(text)) {
 | 
	
		
			
				|  |  | +										total++;
 | 
	
		
			
				|  |  | +									}
 | 
	
		
			
				|  |  | +									return total;
 | 
	
		
			
				|  |  | +								}, 0);
 | 
	
		
			
				|  |  | +								if (total === 0) {
 | 
	
		
			
				|  |  | +									if (["12280"].includes(detailId)) {
 | 
	
		
			
				|  |  | +										activeMeasure?.insertBefore(wordContainer.cloneNode(true), activeMeasure?.childNodes[wordIndex]);
 | 
	
		
			
				|  |  | +									} else {
 | 
	
		
			
				|  |  | +										setElementNoteBefore(wordContainer, parentMeasure, activeMeasure);
 | 
	
		
			
				|  |  | +									}
 | 
	
		
			
				|  |  | +								}
 | 
	
		
			
				|  |  | +							}
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					});
 | 
	
		
			
				|  |  | +					/** word比较特殊需要精确到note位置 */
 | 
	
		
			
				|  |  | +					codas.forEach((coda) => {
 | 
	
		
			
				|  |  | +						const wordContainer = coda.parentElement?.parentElement;
 | 
	
		
			
				|  |  | +						const parentMeasure = wordContainer?.parentElement;
 | 
	
		
			
				|  |  | +						const measureWords = [...(parentMeasure?.childNodes || [])];
 | 
	
		
			
				|  |  | +						const wordIndex = wordContainer ? measureWords.indexOf(wordContainer) : -1;
 | 
	
		
			
				|  |  | +						if (wordContainer && parentMeasure && wordIndex > -1) {
 | 
	
		
			
				|  |  | +							const index = firstMeasures.indexOf(parentMeasure);
 | 
	
		
			
				|  |  | +							const activeMeasure = part.getElementsByTagName("measure")[index];
 | 
	
		
			
				|  |  | +							if (["12280"].includes(detailId)) {
 | 
	
		
			
				|  |  | +								activeMeasure?.insertBefore(wordContainer.cloneNode(true), activeMeasure?.childNodes[wordIndex]);
 | 
	
		
			
				|  |  | +							} else {
 | 
	
		
			
				|  |  | +								setElementNoteBefore(wordContainer, parentMeasure, activeMeasure);
 | 
	
		
			
				|  |  | +							}
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					});
 | 
	
		
			
				|  |  | +					rehearsals.forEach((rehearsal) => {
 | 
	
		
			
				|  |  | +						const container = rehearsal.parentElement?.parentElement;
 | 
	
		
			
				|  |  | +						const parentMeasure = container?.parentElement;
 | 
	
		
			
				|  |  | +						// console.log(rehearsal)
 | 
	
		
			
				|  |  | +						if (parentMeasure) {
 | 
	
		
			
				|  |  | +							const index = firstMeasures.indexOf(parentMeasure);
 | 
	
		
			
				|  |  | +							part.getElementsByTagName("measure")[index]?.appendChild(container.cloneNode(true));
 | 
	
		
			
				|  |  | +							// console.log(index, parentMeasure, firstMeasures.indexOf(parentMeasure))
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					});
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			} else {
 | 
	
		
			
				|  |  | +				if (part && part.getAttribute("id") === id) {
 | 
	
		
			
				|  |  | +					words.forEach((word, idx) => {
 | 
	
		
			
				|  |  | +						const text = word.textContent || "";
 | 
	
		
			
				|  |  | +						// if (idx == 0 && text) {
 | 
	
		
			
				|  |  | +						// 	word.textContent = '测试一下'
 | 
	
		
			
				|  |  | +						// 	word.setAttribute('default-y',60)
 | 
	
		
			
				|  |  | +						// 	word.setAttribute('margin-left',300)
 | 
	
		
			
				|  |  | +						// 	word.setAttribute('y',300)
 | 
	
		
			
				|  |  | +						// 	word.outerHTML = '<words default-x="155" default-y="100" justify="right" valign="middle" font-family="SimHei" font-style="normal" font-size="11.9365" font-weight="normal">哈哈哈哈哈</words>'
 | 
	
		
			
				|  |  | +						// }
 | 
	
		
			
				|  |  | +						if (isSpeedKeyword(text) && text) {
 | 
	
		
			
				|  |  | +							const wordContainer = word.parentElement?.parentElement?.parentElement;
 | 
	
		
			
				|  |  | +							if (wordContainer && wordContainer.firstElementChild && wordContainer.firstElementChild !== word) {
 | 
	
		
			
				|  |  | +								const wordParent = word.parentElement?.parentElement;
 | 
	
		
			
				|  |  | +								const fisrt = wordContainer.firstElementChild;
 | 
	
		
			
				|  |  | +								wordContainer.insertBefore(wordParent, fisrt);
 | 
	
		
			
				|  |  | +							}
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					});
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			// 最后一个小节的结束线元素不在最后 调整
 | 
	
		
			
				|  |  | +			if (part && part.getAttribute("id") === id) {
 | 
	
		
			
				|  |  | +				if (!resourceType) {
 | 
	
		
			
				|  |  | +					const backups = Array.from(part.getElementsByTagName('backup')) || []
 | 
	
		
			
				|  |  | +					for (let backup of backups) {
 | 
	
		
			
				|  |  | +						// @ts-ignore
 | 
	
		
			
				|  |  | +						if (backup && backup?.getElementsByTagName('duration')?.length) {
 | 
	
		
			
				|  |  | +							state.isSingleMutliTrack = true;
 | 
	
		
			
				|  |  | +							break;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +				const barlines = part.getElementsByTagName("barline");
 | 
	
		
			
				|  |  | +				const lastParent = barlines[barlines.length - 1]?.parentElement;
 | 
	
		
			
				|  |  | +				if (lastParent?.lastElementChild?.tagName !== "barline") {
 | 
	
		
			
				|  |  | +					const children = lastParent?.children || [];
 | 
	
		
			
				|  |  | +					for (let el of children) {
 | 
	
		
			
				|  |  | +						if (el.tagName === "barline") {
 | 
	
		
			
				|  |  | +							// 将结束线元素放到最后
 | 
	
		
			
				|  |  | +							lastParent?.appendChild(el);
 | 
	
		
			
				|  |  | +							break;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		});
 | 
	
		
			
				|  |  | +		Array.from(partList).forEach((part) => {
 | 
	
		
			
				|  |  | +			if (part && !ids.includes(part.getAttribute("id")) ) {
 | 
	
		
			
				|  |  | +				part.parentNode?.removeChild(part);
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		});
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  	// console.log(xmlParse)
 | 
	
		
			
				|  |  |  	return new XMLSerializer().serializeToString(appoggianceFormate(xmlParse));
 | 
	
		
			
				|  |  |  };
 | 
	
	
		
			
				|  | @@ -938,7 +1100,8 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 | 
	
		
			
				|  |  |  	// const firstTrackName = state.combinePartIndexs.length>1 ? state.partListNames[state.combinePartIndexs[0]] : state.canSelectTracks[0] || "";
 | 
	
		
			
				|  |  |  	const filterInstruments = state.osmd.Sheet.Instruments.filter(item => item.Name?.toLocaleLowerCase() !== 'common' )
 | 
	
		
			
				|  |  |  	const firstTrackName = state.combinePartIndexs.length>1 ? state.partListNames[state.combinePartIndexs[0]] : (filterInstruments[0].Name || filterInstruments[0].NameLabel.text || "");
 | 
	
		
			
				|  |  | -	const currentTrackIndex = state.isCombineRender && state.combinePartIndexs.length > 1 ? state.combinePartIndexs[0] : 0;
 | 
	
		
			
				|  |  | +	// const currentTrackIndex = state.isCombineRender && state.combinePartIndexs.length > 1 ? state.combinePartIndexs[0] : 0;
 | 
	
		
			
				|  |  | +	const currentTrackIndex = 0;
 | 
	
		
			
				|  |  |  	while (!iterator.EndReached) {
 | 
	
		
			
				|  |  |  		// console.log({ ...iterator });
 | 
	
		
			
				|  |  |  		/** 多声轨合并显示,当前音符的时值取所有声轨中的最小值 */
 |