Forráskód Böngészése

fix: #9405、#9404bug修复

TIANYONG 1 éve
szülő
commit
f1165a8371

+ 526 - 0
src/helpers/customMusicScore.ts

@@ -0,0 +1,526 @@
+import { ref } from "vue";
+import state from "../state"
+import { getQuery } from "/src/utils/queryString";
+const query: any = getQuery();
+
+interface IItem {
+	id?: string
+	y?: number
+	isLast?: boolean
+	childIndex?: number[]
+	
+}
+interface IItemList {
+	parts: string[],
+	tieId?: string[],
+	staveSection?: IItem[],
+	vfmodifiers?: IItem[],
+	voltas?: number
+	vfcurve?: IItem[]
+	stavenote?: IItem[]
+}
+interface IMusicList {
+	[_key: string]: IItemList[]
+}
+
+const container = ref();
+
+/** 曲谱配置: 重叠 */
+const resetGivenFormate = () => {
+	interface IItem {
+		id?: string
+		y?: number
+		isLast?: boolean
+		childIndex?: number[]
+		
+	}
+	interface IItemList {
+		parts: string[],
+		tieId?: string[],
+		staveSection?: IItem[],
+		vfmodifiers?: IItem[],
+		voltas?: number
+		vfcurve?: IItem[]
+		stavenote?: IItem[]
+	}
+	interface IMusicList {
+		[_key: string]: IItemList[]
+	}
+	const musicList: IMusicList = {
+		'12200': [
+			{parts: ['0', '1'], tieId: ['1483']},
+			{parts: ['2'], tieId: ['1463']},
+			{parts: ['10'], tieId: ['1246']},
+			{parts: ['11'], tieId: ['2455']},
+			{parts: ['13'], tieId: ['1488', '1688']},
+			{parts: ['14', '15'], tieId: ['1272']},
+			{parts: ['16'], tieId: ['1264', '1368'], staveSection: [{id: 'section-0', y: -10}]},
+		],
+		'12420': [
+			{parts: ['0'], tieId: ['1298', '1405', '1998', '2598', '3229', '2731', '2617']}
+		],
+		'7729': [
+			{parts: ['3'], tieId: ['1498', '1660']}
+		],
+		'7439': [
+			{parts: ['23'], vfmodifiers: [{id: 'modifiers-130', y: -18, isLast: true}]}
+		],
+		'12711': [
+			{ parts: ['0'], voltas: -12},
+			{ parts: ['4'],voltas: -8},
+		],
+		'3581': [
+			{ parts: ['0'], voltas: -8},
+		],
+		'6244': [
+			{ parts: ['15'], stavenote: [{id: 'vf-auto1608', y: -15}]},
+		],
+		'7473': [
+			{ parts: ['0'], voltas: -8},
+		]
+	}
+	const tieList = musicList[state.cbsExamSongId as string]
+	if (tieList) {
+		const tie = tieList.find((item) => item.parts.includes(query["part-index"] as string))
+		if (!tie) return
+		// 延音线和连线重叠
+		if (tie.tieId && tie.tieId.length) {
+			for(let tieIndex = 0; tieIndex < tie.tieId.length; tieIndex++){
+				const vftie: any = document.querySelector(`#vf-auto${tie.tieId[tieIndex]}-tie`)
+				const vfcurve = vftie?.parentNode?.parentNode?.querySelectorAll('.vf-curve')
+				if (vfcurve && vfcurve.length){
+					for(let i = 0; i < vfcurve.length; i++){
+						const result = collisionDetection(vftie, vfcurve[i])
+						if (result.isCollision){
+							vfcurve[i].style.transform = `translateY(-8px)`;
+							break;
+						}
+					}
+				}
+			}
+		}
+		
+		// 小节数字
+		if (tie.staveSection && tie.staveSection.length) {
+			const sectionList = document.querySelectorAll('.vf-StaveSection')
+			sectionList.forEach((node, index) => {
+				node.classList.add(`section-${index}`)
+			})
+			for(let i = 0; i < tie.staveSection.length; i++){
+				const item: any = document.querySelector( '.' + tie.staveSection[i].id)
+				if (item){
+					item.style.transform = `translateY(${tie.staveSection[i].y}px)`;
+				}
+			}
+		}
+
+		// modifiers 里面的符号
+		if(tie.vfmodifiers && tie.vfmodifiers.length){
+			const modifierList = document.querySelectorAll('.vf-modifiers')
+			modifierList.forEach((node, index) => {
+				node.classList.add(`modifiers-${index}`)
+			}) 
+			for(let i = 0; i < tie.vfmodifiers.length; i++){
+				const modifier = tie.vfmodifiers[i]
+				const item: SVGAElement = document.querySelector( '.' + modifier.id)!
+				if (item){
+					if (modifier.isLast){
+						const lastEle: any = Array.from(item.childNodes).at(-1)
+						if (lastEle){
+							lastEle.style.transform = `translateY(${modifier.y}px)`;
+						}
+					}
+				}
+			}
+		}
+
+		// 房子
+		if (tie.voltas){
+			const modifierList = document.querySelectorAll('.vf-Volta') as unknown as HTMLElement[]
+			modifierList.forEach((node, index) => {
+				node.style.transform = `translateY(${tie.voltas}px)`;
+			}) 
+		}
+
+		// 单个音符
+		if (tie.stavenote && tie.stavenote.length) {
+			for(let i = 0; i < tie.stavenote.length; i++){
+				const item = tie.stavenote[i]
+				const ele = document.querySelector('#' + item.id)! as unknown as HTMLElement
+				ele && (ele.style.transform = `translateY(${item.y}px)`)
+			}
+		}
+	}
+	
+};
+
+// 谱面优化
+const resetFormate = () => {
+	container.value = document.getElementById('scrollContainer')
+	if (state.extStyleConfigJson || !container.value) return;
+	const stafflines: SVGAElement[] = Array.from((container.value as HTMLElement).querySelectorAll(".staffline"));
+	const baseStep = 4; // 两个元素相间,的间距
+	const musicalDistance = 28; // 音阶与第一条线谱的间距,默认设置为28
+	for (let i = 0, len = stafflines.length; i < len; i++) {
+		const staffline = stafflines[i];
+		const stafflineBox = staffline.getBBox();
+		const stafflineCenter = stafflineBox.y + stafflineBox.height / 2;
+		const vfmeasures: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure"));
+		const vfcurve: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-curve"));
+		const vfvoices: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-voices"));
+		const vfbeams: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-beams"));
+		const vfties: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-ties"));
+		const vflines: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-line"));
+		const texts: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-stave text"));
+		const rects: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-stave rect[fill=none]"));
+		const staveSection: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure .vf-staveSection"));
+		const paths: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-stave path"));
+		// 获取第一个线谱的y轴坐标
+		const firstLinePathY = paths[0]?.getBBox().y || 0
+		// 反复标记 和 小节碰撞
+		const repetWord = ["To Coda", "D.S. al Coda", "Coda"];
+		texts
+			.filter((n) => repetWord.includes(n.textContent || ""))
+			.forEach((t) => {
+				vfbeams.forEach((curve) => {
+					const result = collisionDetection(t, curve);
+					const prePath: SVGAElement = t?.previousSibling as unknown as SVGAElement;
+					if (result.isCollision) {
+						const shift_y = Number(t.getAttribute("y")) - (result.b1 - result.t2) - baseStep + "";
+						t.setAttribute("y", shift_y);
+						// console.log('音阶间距',shift_y)
+						if (prePath && prePath.getAttribute("stroke-width") === "0.3" && prePath.getAttribute("stroke") === "none" && (prePath.getAttribute("d")?.length || 0) > 3000) {
+							prePath.style.transform = `translateY(${-(result.b1 - result.t2 + baseStep)}px)`;
+						}
+					}
+				});
+				vfvoices.forEach((curve) => {
+					const result = collisionDetection(t, curve);
+					const prePath: SVGAElement = t?.previousSibling as unknown as SVGAElement;
+					if (result.isCollision) {
+						const shift_y = Number(t.getAttribute("y")) - (result.b1 - result.t2) - baseStep + "";
+						t.setAttribute("y", shift_y);
+						// console.log('音阶间距',shift_y)
+						if (prePath && prePath.getAttribute("stroke-width") === "0.3" && prePath.getAttribute("stroke") === "none" && (prePath.getAttribute("d")?.length || 0) > 3000) {
+							prePath.style.transform = `translateY(${-(result.b1 - result.t2 + baseStep)}px)`;
+						}
+					}
+				});
+			});
+		// 文字方框和飞线碰撞
+		staveSection.forEach((t) => {
+			let shift_y = 0;
+			[...vfcurve, ...vfties, ...vfvoices].forEach((curve) => {
+				const result = collisionDetection(t, curve);
+				if (result.isCollision) {
+					shift_y = Math.min(shift_y, result.t2 - result.b1 - baseStep);
+				}
+			});
+			t.style.transform = `translateY(${shift_y}px)`;
+		});
+
+		// 文字和小节碰撞
+		let vftexts = Array.from(staffline.querySelectorAll(".vf-text > text")).filter((n: any) => n.getBBox().y < stafflineCenter);
+		for (let i = 0; i < vftexts.length; i++) {
+			const _text = vftexts[i];
+			for (let j = 0; j < vftexts.length; j++) {
+				if (_text.parentNode === vftexts[j].parentNode) continue;
+				const result = collisionDetection(_text as SVGAElement, vftexts[j] as SVGAElement);
+				if (result.isCollision) {
+					if (_text.textContent === vftexts[j].textContent) {
+						vftexts[j].parentNode?.removeChild(vftexts[j]);
+						continue;
+					}
+				}
+			}
+		}
+		vftexts = Array.from(staffline.querySelectorAll(".vf-text > text")).filter((n: any) => n.getBBox().y < stafflineCenter);
+		let maxY = 0;
+		let _vftexts: SVGAElement[] = [];
+
+		vftexts.forEach((vftext: any) => {
+			const textBox = vftext.getBBox();
+			if (textBox.y < stafflineCenter) {
+				maxY = Math.max(maxY, textBox.y + textBox.height);
+				//console.log('音阶间距',textBox.y, textBox.height)
+				_vftexts.push(vftext as SVGAElement);
+			}
+		});
+		if (maxY !== 0 && _vftexts.length > 1) {
+			_vftexts.forEach((vftext) => {
+				vftext.setAttribute("y", maxY + "");
+				//console.log('音阶间距',maxY)
+			});
+		}
+		vftexts.forEach((vftext) => {
+			[...vfcurve, ...vfmeasures, ...vflines].forEach((vfmeasure) => {
+				let result = collisionDetection(vftext as SVGAElement, vfmeasure);
+				if (result.isCollision && result.b1 < result.b2 && result.t1 < result.b2 - (result.b2 - result.t2) / 2) {
+					const shift_y = Number(vftext.getAttribute("y")) - (result.b1 - result.t2) - baseStep + "";
+					vftext.setAttribute("y", shift_y);
+					//console.log('音阶间距',shift_y)
+				}
+			});
+		});
+
+		vftexts.forEach((vftext) => {
+			vftexts.forEach((text) => {
+				if (vftext.parentNode !== text.parentNode && !["marcato", "legato"].includes(vftext.textContent as string)) {
+					if (["marcato", "legato"].includes(text.textContent as string)) {
+						const result = collisionDetection(vftext as SVGAElement, text as SVGAElement, 30, 30);
+						if (result.isCollision) {
+							const textBBox = (vftext as SVGAElement).getBBox();
+							text.setAttribute("x", textBBox.x + textBBox.width + 5 + "");
+							text.setAttribute("y", textBBox.y + textBBox.height - 5 + "");
+							//console.log('音阶间距',textBBox.y + textBBox.height - 5 + "")
+						}
+					} else {
+						const result = collisionDetection(vftext as SVGAElement, text as SVGAElement);
+						if (result.isCollision) {
+							const _y = Number(vftext.getAttribute("y"));
+							const shift_y = result.b2 - result.t2 < 24 ? 24 : result.b2 - result.t2;
+							text.setAttribute("y", _y - shift_y - 0.5 + "");
+							//console.log('音阶间距',_y - shift_y - 0.5 + "")
+						}
+					}
+				}
+			});
+		});
+		// 修改音阶和线谱的间距
+		const clefList = ['C', 'G', 'D', 'A', 'E', 'B', 'F#', 'C#', 'G#', 'F', 'Bb', 'Eb', 'Ab', 'Db', 'Gb', 'Cb', 'Fb', 'D#', 'A#', 'E#']
+		const btransList = ['Bb', 'Eb', 'Ab', 'Db', 'Gb', 'Cb', 'Fb']
+		const jtrsnsList = ['F#', 'C#', 'G#', 'D#', 'A#', 'E#', 'B#']
+		vftexts.forEach((label: any) => {
+			const labelText = label.textContent as string
+			if (clefList.includes(labelText)){
+				const _y = Number(label.getAttribute("y"))
+				const endY = firstLinePathY ? firstLinePathY - musicalDistance : _y
+				label.setAttribute("y", endY)
+			}
+			if (btransList.includes(labelText)) {
+				label.textContent = labelText.replace('b','♭')
+			}
+			if (jtrsnsList.includes(labelText)) {
+				label.textContent = labelText.replace('#','♯')
+			}
+		});
+		const vftextBottom = Array.from(staffline.querySelectorAll(".vf-text > text")).filter((n: any) => n.getBBox().y > stafflineCenter);
+		const vflineBottom = Array.from(staffline.querySelectorAll(".vf-line")).filter((n: any) => n.getBBox().y > stafflineCenter);
+		// 去重
+		for (let i = 0; i < vftextBottom.length; i++) {
+			const _text = vftextBottom[i];
+			for (let j = 0; j < vftextBottom.length; j++) {
+				if (_text.parentNode === vftextBottom[j].parentNode) continue;
+				const result = collisionDetection(_text as SVGAElement, vftextBottom[j] as SVGAElement);
+				if (result.isCollision) {
+					if (_text.textContent === vftextBottom[j].textContent) {
+						vftextBottom[j].parentNode?.removeChild(vftextBottom[j]);
+						continue;
+					}
+				}
+			}
+		}
+		// 1,2线谱底部文字重叠问题
+		vftextBottom.forEach((vftext) => {
+			[...vfmeasures].forEach((n) => {
+				let result = collisionDetection(vftext as SVGAElement, n);
+				if (result.isCollision) {
+					vftext.setAttribute("y", result.b2 + Math.abs(result.t1 - Number(vftext.getAttribute("y"))) + "");
+					//console.log('音阶间距', result.b2 + Math.abs(result.t1 - Number(vftext.getAttribute("y"))) + "")
+				}
+			});
+		});
+		// 如果渐弱渐强有平行的文字
+		vflineBottom.forEach((line) => {
+			const texts: any[] = [];
+			if (line.nextElementSibling?.classList.contains("vf-line")) {
+				vftextBottom.forEach((text) => {
+					let result = collisionDetection(line as SVGAElement, text as SVGAElement, 20, 20);
+					if (result.isCollision) {
+						texts.push({
+							text: text as SVGAElement,
+							result,
+						});
+					}
+				});
+			}
+			if (texts.length === 1) {
+				const result = texts[0].result;
+				const text = texts[0].text;
+				if (result.x2 + result.w2 < result.x1) {
+					// 左
+					if (Math.abs(result.y2 - result.y1) > 10) {
+						text.setAttribute("y", result.y1 + result.h2 / 2 + "");
+						//console.log('音阶间距', result.y1 + result.h2 / 2 + "")
+					}
+				} else if (result.x2 > result.x1 + result.w1) {
+					// 右
+					if (Math.abs(result.y2 - result.y1) > 10) {
+						text.setAttribute("y", result.y1 + result.h2 / 2 + "");
+						//console.log('音阶间距', result.y1 + result.h2 / 2 + "")
+					}
+				} else {
+					if (Math.abs(result.x2 - result.x1) < Math.abs(result.x2 + result.w2 - result.x1 - result.w1)) {
+						// console.log(text, '有交集', '靠左')
+						text.setAttribute("x", result.x1 - result.w2 - 5 + "");
+						if (Math.abs(result.y2 - result.y1) > 10) {
+							text.setAttribute("y", result.y1 + result.h2 / 2 + "");
+							//console.log('音阶间距', result.y1 + result.h2 / 2 + "")
+						}
+					} else {
+						// console.log(text, '有交集', '靠右')
+						text.setAttribute("x", result.x1 + result.w1 + 5 + "");
+						if (Math.abs(result.y2 - result.y1) > 10) {
+							text.setAttribute("y", result.y1 + result.h2 / 2 + "");
+							//console.log('音阶间距', result.y1 + result.h2 / 2 + "")
+						}
+					}
+				}
+			} else if (texts.length === 2) {
+				const result1 = texts[0].result;
+				const text1 = texts[0].text;
+				const result2 = texts[1].result;
+				const text2 = texts[1].text;
+				text1.setAttribute("x", result1.x1 - result1.w2 - 5 + "");
+				if (Math.abs(result1.y2 - result1.y1) > 10) {
+					text1.setAttribute("y", result1.y1 + result1.h2 / 2 + "");
+					//console.log('音阶间距', result1.y1 + result1.h2 / 2 + "")
+				}
+				text2.setAttribute("x", result2.x1 + result2.w1 + 5 + "");
+				if (Math.abs(result2.y2 - result2.y1) > 10) {
+					text2.setAttribute("y", result2.y1 + result2.h2 / 2 + "");
+					//console.log('音阶间距', result2.y1 + result2.h2 / 2 + "")
+				}
+			} else if (texts.length === 3) {
+				// console.log(texts)
+			}
+		});
+
+		vftextBottom.forEach((vftext) => {
+			vftextBottom.forEach((text) => {
+				if (vftext.parentNode !== text.parentNode && !["marcato", "legato", "cresc.", "Cantabile"].includes(vftext.textContent as string)) {
+					if (["marcato", "legato", "cresc.", "Cantabile"].includes(text.textContent as string)) {
+						const result = collisionDetection(vftext as SVGAElement, text as SVGAElement, 30, 30);
+						if (result.isCollision) {
+							const textBBox = (vftext as SVGAElement).getBBox();
+							text.setAttribute("x", textBBox.x + textBBox.width + 5 + "");
+							text.setAttribute("y", textBBox.y + textBBox.height - 5 + "");
+							//console.log('音阶间距', textBBox.y + textBBox.height - 5 + "")
+						}
+					} else {
+						const result = collisionDetection(vftext as SVGAElement, text as SVGAElement);
+						if (result.isCollision) {
+							text.setAttribute("y", result.y1 + result.h1 + result.h2 + "");
+							//console.log('音阶间距', result.y1 + result.h1 + result.h2 + "")
+						}
+					}
+				}
+			});
+		});
+	}
+
+	// setTimeout(() => this.resetGlobalText());
+};
+// 技巧文本
+const resetGlobalText = () => {
+	const svg = container.value.querySelector("svg");
+	if (!svg) return;
+	const svgBBox = svg.getBBox();
+	let vfstavetempo: SVGAElement[] = Array.from(container.value.querySelectorAll(".vf-stavetempo")).reduce((eles: SVGAElement[], value: any) => {
+		if (eles.find((n) => n.outerHTML === value.outerHTML)) value?.parentNode?.removeChild(value);
+		else eles.push(value);
+		return eles;
+	}, []);
+	const staffline: SVGAElement[] = Array.from(container.value.querySelectorAll(".staffline"));
+	const vfmeasures: SVGAElement[] = Array.from(container.value.querySelectorAll(".staffline > .vf-measure"));
+	const vftexts: SVGAElement[] = Array.from(container.value.querySelectorAll(".staffline > .vf-text"));
+	const vfcurves: SVGAElement[] = Array.from(container.value.querySelectorAll(".staffline > .vf-curve"));
+
+	vfstavetempo.forEach((child: SVGAElement) => {
+		let _y = 0;
+		[...vfmeasures, ...vftexts, ...vfcurves].forEach((ele) => {
+			const result = collisionDetection(child as SVGAElement, ele);
+			if (result.isCollision && (result.b1 < result.b2 || result.r1 > result.l2 || result.l1 < result.r2)) {
+				_y = Math.min(_y, result.t2 - result.b1);
+			}
+		});
+		if (_y !== 0) {
+			child.style.transform = `translateY(${_y}px)`;
+		}
+
+		const childBBox = child.getBBox();
+		const rightY = (childBBox.x + childBBox.width) * 0.7 - Number(svg.getAttribute("width"));
+		if (rightY > 0) {
+			[...staffline, ...vfstavetempo].forEach((tempo) => {
+				if (child != tempo) {
+					const result = collisionDetection(child as SVGAElement, tempo, Math.abs(rightY), Math.abs(_y));
+					if (result.isCollision) {
+						_y = result.t2 - result.b1;
+					}
+				}
+			});
+			child.style.transform = `translate(-${rightY / 0.7}px,${_y}px)`;
+		}
+	});
+
+	if (svgBBox.y < 0) {
+		svg.setAttribute("height", Number(svg.getAttribute("height")) - svgBBox.y + 10);
+	}
+};
+
+// 碰撞检测
+const collisionDetection = (a: SVGAElement, b: SVGAElement, distance: number = 0, distance_y: number = 0) => {
+	const abbox = a.getBBox();
+	const bbbox = b.getBBox();
+	let t1 = abbox.y - distance_y;
+	let l1 = abbox.x - distance;
+	let r1 = abbox.x + abbox.width + distance;
+	let b1 = abbox.y + abbox.height + distance_y;
+
+	let t2 = bbbox.y;
+	let l2 = bbbox.x;
+	let r2 = bbbox.x + bbbox.width;
+	let b2 = bbbox.y + bbbox.height;
+	if (b1 < t2 || l1 > r2 || t1 > b2 || r1 < l2) {
+		// 表示没碰上
+		return {
+			isCollision: false,
+			t1,
+			l1,
+			r1,
+			b1,
+			t2,
+			l2,
+			r2,
+			b2,
+			x1: abbox.x,
+			y1: abbox.y,
+			x2: bbbox.x,
+			y2: bbbox.y,
+			h1: abbox.height,
+			h2: bbbox.height,
+			w1: abbox.width,
+			w2: bbbox.width,
+		};
+	} else {
+		return {
+			isCollision: true,
+			t1,
+			l1,
+			r1,
+			b1,
+			t2,
+			l2,
+			r2,
+			b2,
+			x1: abbox.x,
+			y1: abbox.y,
+			x2: bbbox.x,
+			y2: bbbox.y,
+			h1: abbox.height,
+			h2: bbbox.height,
+			w1: abbox.width,
+			w2: bbbox.width,
+		};
+	}
+};

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

@@ -104,6 +104,7 @@ export default defineComponent({
           // 没有授权
           if (res?.content?.reson) {
             state.setting.camera = false
+            store.set("musicscoresetting", state.setting);
           }
         }
       }

+ 3 - 0
src/state.ts

@@ -148,6 +148,8 @@ const state = reactive({
   enableNotation: false,
   /** 曲谱ID */
   examSongId: "",
+  /** 内容平台的曲谱ID,可能会和业务端的id不一样 */
+  cbsExamSongId: "",
   /** 曲谱名称 */
   examSongName: "",
   /** 曲谱封面 */
@@ -833,6 +835,7 @@ const setState = (data: any, index: number) => {
   state.categoriesName = data.musicTagNames;
   // state.enableEvaluation = data.isEvaluated ? true : false;
   state.examSongId = data.bizId + "";
+  state.cbsExamSongId = data.id + "";
   state.examSongName = data.name;
   state.coverImg = data.musicCover ?? "";
   state.isCombineRender = data.musicSheetType === "SINGLE" && data.musicSheetSoundList?.length > 1

+ 27 - 21
src/view/follow-practice/index.tsx

@@ -33,7 +33,7 @@ const audioFrequency = ref(0);
 const followTime = ref(0);
 // 切换录音
 const openToggleRecord = async (open: boolean = true) => {
-	api_cloudToggleFollow(open ? "start" : "end");
+	if (!open) api_cloudToggleFollow(open ? "start" : "end");
 	// 记录跟练时长
 	if (open) {
 		followTime.value = Date.now();
@@ -70,27 +70,33 @@ const onClear = () => {
 
 /** 开始跟练 */
 export const handleFollowStart = async () => {
-	// 跟练模式开始前,增加播放系统节拍器
-	followData.start = true;
-	const tickend = await handleStartTick();
-	// console.log("🚀 ~ tickend:", tickend)
-	// 节拍器返回false, 取消播放
-	if (!tickend) {
-		followData.start = false;
-		return false;
+	const res = api_cloudToggleFollow("start");
+	// 用户没有授权,需要重置状态
+	if (res?.content?.reson) {
+		// 
+	} else {
+		// 跟练模式开始前,增加播放系统节拍器
+		followData.start = true;
+		const tickend = await handleStartTick();
+		// console.log("🚀 ~ tickend:", tickend)
+		// 节拍器返回false, 取消播放
+		if (!tickend) {
+			followData.start = false;
+			return false;
+		}
+		onClear();
+		followData.start = true;
+		followData.index = 0;
+		followData.list = [];
+		resetPlaybackToStart();
+		openToggleRecord(true);
+		getNoteIndex();
+		const duration: any = getDuration(state.osmd as unknown as OpenSheetMusicDisplay);
+		metronomeData.totalNumerator = duration.numerator || 2
+		metronomeData.followAudioIndex = 1
+		state.beatStartTime = 0
+		followBeatPaly();		
 	}
-	onClear();
-	followData.start = true;
-	followData.index = 0;
-	followData.list = [];
-	resetPlaybackToStart();
-	openToggleRecord(true);
-	getNoteIndex();
-	const duration: any = getDuration(state.osmd as unknown as OpenSheetMusicDisplay);
-	metronomeData.totalNumerator = duration.numerator || 2
-	metronomeData.followAudioIndex = 1
-	state.beatStartTime = 0
-	followBeatPaly();
 };
 /** 结束跟练 */
 export const handleFollowEnd = () => {