import { computed, defineComponent, nextTick, onMounted, onUnmounted, reactive, ref } from "vue";
import ABCJS, {
	AbcElem,
	AbcVisualParams,
	ClickListenerAnalysis,
	ClickListenerDrag,
	SynthObjectController,
} from "abcjs";
import "ABCJS/ABCJS-audio.css";
import styles from "./index.module.less";
import { showConfirmDialog } from "vant";
import Keys from "../component/keys";
import { Collapse, CollapseItem, Snackbar } from "@varlet/ui";
import { IAbc, IMeasure, INote, INoteActive } from "../types";
import { ABC_DATA, createMeasure, createNote, renderMeasures } from "./runtime";
import TheIcon from "/src/components/The-icon";
import { cloneDeep } from "lodash";
import TheSpeed from "./component/the-speed";
import { getImage } from "./images";
import { Dropdown, Dsubmenu, Doption, Trigger, Input, Select, Option } from "@arco-design/web-vue";
import {
	NButton,
	NDropdown,
	NGi,
	NGrid,
	NIcon,
	NInput,
	NInputNumber,
	NModal,
	NPopover,
	NPopselect,
	NSelect,
	NSpace,
	useMessage,
} from "naive-ui";
import { LongArrowAltDown, LongArrowAltUp } from "@vicons/fa";
import { svg2canvas } from "/src/utils/svg2canvas";
import { downloadFile } from "/src/utils";
import FileBtn, { IFileBtnType } from "./component/file-btn";
import TheSetting from "./component/the-setting";
import { useRoute } from "vue-router";
import { api_musicSheetCreationDetail, api_musicSheetCreationUpdate } from "../api";

const allPitches = [
	"C,,,,",
	"D,,,,",
	"E,,,,",
	"F,,,,",
	"G,,,,",
	"A,,,,",
	"B,,,,",
	"C,,,",
	"D,,,",
	"E,,,",
	"F,,,",
	"G,,,",
	"A,,,",
	"B,,,",
	"C,,",
	"D,,",
	"E,,",
	"F,,",
	"G,,",
	"A,,",
	"B,,",
	"C,",
	"D,",
	"E,",
	"F,",
	"G,",
	"A,",
	"B,",
	"C",
	"D",
	"E",
	"F",
	"G",
	"A",
	"B",
	"c",
	"d",
	"e",
	"f",
	"g",
	"a",
	"b",
	"c'",
	"d'",
	"e'",
	"f'",
	"g'",
	"a'",
	"b'",
	"c''",
	"d''",
	"e''",
	"f''",
	"g''",
	"a''",
	"b''",
	"c'''",
	"d'''",
	"e'''",
	"f'''",
	"g'''",
	"a'''",
	"b'''",
	"c''''",
	"d''''",
	"e''''",
	"f''''",
	"g''''",
	"a''''",
	"b''''",
];

const initMusic = (total: number): IMeasure[] => {
	return new Array(total).fill(0).map((item, index) => {
		return {
			measureNumber: index + 1,
			barline: "|",
			celf: "",
			key: "",
			repeat: "",
			notes: [
				{
					accidental: "",
					clef: "",
					meter: "",
					content: "z",
					noteType: "4",
					play: [],
					key: "",
					speed: "",
					dynamics: "",
					dCode: "",
					tie: "",
					tCode: "",
					dot: "",
					slus: "",
				},
			],
		};
	});
};

function moveNote(note: string, step: number) {
	var x = allPitches.indexOf(note);
	if (x >= 0) {
		const _note = allPitches[x - step];
		return _note ? _note : note;
	}
	return note;
}

export default defineComponent({
	name: "Home",
	setup() {
		const route = useRoute();
		const message = useMessage();
		const popup = reactive({
			instrument: false,
			moveKeyShow: false, // 移调弹窗
			speedShow: false, // 节拍弹窗
			accidentalsShow: false, // 临时升降记号弹窗
			clefShow: false, // 谱号弹窗
			keyShow: false, // 调号弹窗
			meterShow: false, // 拍号弹窗
			playShow: false, // 演奏技法弹窗
			dynamicsShow: false, // 力度标记弹窗
			barShow: false, // 小节弹窗
			mearseDeleteShow: false,
			staffShow: false, // 五线谱弹窗
			settingShow: false, // 设置弹窗
		});
		const data = reactive({
			musicId: "",
			musicName: "", // 曲谱名称
			subjectId: "", // 声部
			speed: "",
			music: "",
			playState: false, // 播放状态
			active: null as unknown as INoteActive,
			select: {
				state: false,
				list: [] as any[],
				parmas: null as any,
			},
			isClickNote: false,
			/** 音符类型 */
			noteType: "",
			selectMeasure: {
				start: "",
				end: "",
			},
			slide: ["note", "clef", "key"],

			morePlay: false, // 更多演奏技法

			addMearseType: "pre" as "pre" | "next" | "finish", // 添加小节类型
			addMearseNumber: 1, // 添加小节数量

			deleteMearseType: "ing" as "ing" | "finish", // 删除小节类型
		});
		const noteTypes = ABC_DATA.types.map((item) => item.value).filter(Boolean);
		const accidentals = ABC_DATA.accidentals.map((item) => item.value).filter(Boolean);
		const clefs = ABC_DATA.clef.map((item) => item.value).filter(Boolean);
		const playTypes = ABC_DATA.play.map((item) => item.value).filter(Boolean);
		const dynamics = ABC_DATA.dynamics
			.map((item) => item.value)
			.flat()
			.filter(Boolean);
		const barTypes = ABC_DATA.bar.map((item) => item.value).filter(Boolean);
		console.log("🚀 ~ noteTypes:", noteTypes, accidentals, clefs, playTypes, dynamics);

		/** 点击音符 */
		const clickListener = (
			abcElem: AbcElem,
			tuneNumber: number,
			classes: string,
			analysis: ClickListenerAnalysis,
			drag: ClickListenerDrag
		) => {
			// console.log("🚀 ~ data.select.state:", data.select.state);
			let indexStr: any = abcElem.chord?.find((n) => n.position === "left")?.name || "";
			indexStr = indexStr.split(".").map((n: string) => Number(n));
			const active = {
				...cloneDeep(abcElem),
				measureIndex: indexStr[0],
				noteIndex: indexStr[1],
				isFirstChecked: true,
			};

			// 选择范围模式
			if (data.select.state) {
				data.select.list.push(active);
				if (data.select.list.length === 1) {
					Snackbar("请先选择结束音符");
				}
				if (data.select.list.length === 2) {
					data.select.list = data.select.list.sort((a, b) => a.startChar - b.startChar);
					handleSelectNote();
				}
				return;
			}
			data.active = active;

			console.log(
				"🚀 ~ abcElem:",
				abcElem,
				data.music.substring(data.active.startChar, data.active.endChar)
			);
			if (drag) {
				// console.log("🚀 ~ drag:", drag);
				handleMoveNote("drag", drag.step);
				return;
			}
			if (!abcElem?.midiPitches) return;
			ABCJS.synth.playEvent(abcElem.midiPitches, abcElem.midiGraceNotePitches, 1000);
		};

		const textAreaRef = ref();
		const abcData = reactive({
			visualObj: null as any,
			midiBuffer: null as unknown as ABCJS.MidiBuffer,
			abcOptions: {
				add_classes: true,
				clickListener: clickListener,
				responsive: "resize",
				dragging: true,
				selectTypes: true, // ["note", "clef", "keySignature", "timeSignature", "dynamicDecoration"],
				visualTranspose: 0,
				wrap: {
					minSpacing: 2,
					maxSpacing: 10,
					preferredMeasuresPerLine: 4,
				},
				staffwidth: 800,
			} as AbcVisualParams,
			synthControl: null as unknown as SynthObjectController,
			synthOptions: {
				program: 0,
				// soundFontUrl: "/soundFonts/",
				// soundFontUrl: "https://paulrosen.github.io/midi-js-soundfonts/MusyngKite/",
			},
			abc: {
				celf: "K:treble",
				minUnit: "L:1/4",
				meter: "M:4/4",
				speed: "Q:1/4=60",
				key: "K:C",
				measures: initMusic(30),
			} as IAbc,
		});

		/** 添加音符 */
		const handleCreateNote = (measureIndex: number, noteIndex: number, options: INote) => {
			// console.log("🚀 ~ noteIndex:", noteIndex);
			const measure = abcData.abc.measures[measureIndex];
			if (measure) {
				measure.notes.splice(noteIndex + 1, 0, options);
			}
		};

		/**
		 * 分词
		 * @param str 字符串
		 * @returns
		 * @description
		 */
		const tokenize = (str: string) => {
			const arr = str.split(/(!.+?!|".+?")/);
			let output: string[] = [];
			for (let i = 0; i < arr.length; i++) {
				const token = arr[i];
				if (token.length > 0) {
					if (token[0] !== '"' && token[0] !== "!") {
						const arr2 = arr[i].split(/([A-Ga-gz][,']*)/);
						output = output.concat(arr2);
					} else output.push(token);
				}
			}
			return output;
		};

		const cursorControl = {
			// self.onReady = function () {
			// 	var downloadLink = document.querySelector(".download");
			// 	downloadLink.addEventListener("click", download);
			// 	downloadLink.setAttribute("style", "");
			// 	var clickEl = document.querySelector(".click-explanation");
			// 	clickEl.setAttribute("style", "");
			// };
			onStart: function () {
				console.log("开始");
				data.playState = true;
				var svg = document.querySelector("#paper svg");
				var cursor = document.createElementNS("http://www.w3.org/2000/svg", "line");
				cursor.setAttribute("class", "ABCJS-cursor");
				cursor.setAttributeNS(null, "x1", "0");
				cursor.setAttributeNS(null, "y1", "0");
				cursor.setAttributeNS(null, "x2", "0");
				cursor.setAttributeNS(null, "y2", "0");
				svg?.appendChild(cursor);
			},
			// self.beatSubdivisions = 2;
			onBeat: function (beatNumber: any, totalBeats: any, totalTime: any) {},
			onEvent: (ev: any) => {
				console.log("🚀 ~ ev:", ev);
				if (ev.measureStart && ev.left === null) return; // this was the second part of a tie across a measure line. Just ignore it.

				var lastSelection = document.querySelectorAll("#paper svg .highlight");
				for (var k = 0; k < lastSelection.length; k++) lastSelection[k].classList.remove("highlight");

				for (var i = 0; i < ev.elements.length; i++) {
					var note = ev.elements[i];
					for (var j = 0; j < note.length; j++) {
						note[j].classList.add("highlight");
					}
				}

				var cursor = document.querySelector("#paper svg .ABCJS-cursor");
				if (cursor) {
					cursor.setAttribute("x1", ev.left + ev.width / 2);
					cursor.setAttribute("x2", ev.left + ev.width / 2);
					cursor.setAttribute("y1", ev.top);
					cursor.setAttribute("y2", ev.top + ev.height);
				}
			},
			onFinished: function () {
				console.log("finished");
				var els = document.querySelectorAll("svg .highlight");
				for (var i = 0; i < els.length; i++) {
					els[i].classList.remove("highlight");
				}
				var cursor = document.querySelector("#paper svg .ABCJS-cursor");
				if (cursor) {
					cursor.setAttribute("x1", "0");
					cursor.setAttribute("x2", "0");
					cursor.setAttribute("y1", "0");
					cursor.setAttribute("y2", "0");
				}
			},
		};

		const resetMidi = () => {
			abcData.synthControl = new ABCJS.synth.SynthController();
			abcData.synthControl.load("#audio", cursorControl, {
				displayLoop: true,
				displayRestart: true,
				displayPlay: true,
				displayProgress: true,
			});

			const midiBuffer = new ABCJS.synth.CreateSynth();
			console.log(midiBuffer);
			midiBuffer.init({
				visualObj: abcData.visualObj,
				options: abcData.synthOptions,
			});
			abcData.synthControl
				.setTune(abcData.visualObj, false, {
					midiTranspose: abcData.abcOptions.visualTranspose,
					...abcData.synthOptions,
				})
				.then(function (response) {
					// console.log("Audio successfully loaded.");
					// console.log("🚀 ~ abcData.synthControl:", abcData.synthControl);
				});
		};

		const togglePlay = (type: "play" | "pause" | "reset") => {
			console.log("🚀 ~ abcData.synthControl:", abcData.synthControl);

			if (["play", "pause"].includes(type)) {
				const playBtn: HTMLElement = document.querySelector(".abcjs-midi-start.abcjs-btn")!;
				if (!playBtn) return;
				playBtn.click();
				data.playState = !data.playState;
			} else if (type === "reset") {
				const resetBtn: HTMLElement = document.querySelector(".abcjs-midi-reset.abcjs-btn")!;
				if (!resetBtn) return;
				resetBtn.click();
			}
		};

		const renderSvg = () => {
			abcData.visualObj = ABCJS.renderAbc("paper", data.music, abcData.abcOptions)[0];
			console.log("🚀 ~ visualObj:", abcData.visualObj);
		};

		const renderBoxRect = () => {
			const svg = document.querySelector("#paper svg");
			const padding = 4;
			for (let i = 0; i < abcData.visualObj.lines.length; i++) {
				const line = abcData.visualObj.lines[i];
				for (let j = 0; j < line.staff.length; j++) {
					const staff = line.staff[j];
					const voices = [...staff.voices].flat();
					for (let l = 0; l < voices.length; l++) {
						const item = voices[l];
						// console.log(item.el_type);
						if (["note", "keySignature", "clef", "timeSignature"].includes(item.el_type)) {
							const box = item.abselem.elemset?.[0]?.getBBox?.() || null;
							// console.log("🚀 ~ box:", item.abselem, box);
							if (box) {
								const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
								rect.setAttributeNS(null, "x", box.x - padding + "");
								rect.setAttributeNS(null, "y", box.y - padding + "");
								rect.setAttributeNS(null, "width", box.width + padding * 2 + "");
								rect.setAttributeNS(null, "height", box.height + padding * 2 + "");
								rect.setAttributeNS(null, "fill", "rgba(0,0,0,0)");
								rect.setAttributeNS(null, "stroke", "rgba(0,0,0,0)");
								rect.setAttributeNS(null, "rx", "2");
								rect.classList.add("abcjs-note-hover");
								svg?.appendChild(rect);
							}
						}
					}
				}
			}
			// const annotation = document.querySelectorAll("#paper .abcjs-annotation");
			// annotation.forEach((n) => {
			// 	n.setAttribute("color", "rgba(0,0,0,0)");
			// })
		};

		/**
		 * @param isProduct 是否是生成曲谱
		 */
		const handleResetRender = (isProduct = true) => {
			return new Promise((resolve) => {
				nextTick(() => {
					textAreaRef.value.value = data.music = isProduct ? renderMeasures(abcData.abc) : data.music;
					renderSvg();
					resetMidi();
					renderBoxRect();
					resolve(1);
				});
			});
		};

		// 高亮选中的音符
		const rangeHighlight = (startChar: number) => {
			// console.log(data.active.endChar, abcData.visualObj.getElementFromChar(data.active.startChar));
			const abcElem: AbcElem = abcData.visualObj.getElementFromChar(startChar);
			if (abcElem) {
				abcData.visualObj.engraver.rangeHighlight(abcElem.startChar, abcElem.endChar);
			}
			return abcElem;
		};

		/**
		 *
		 * @param key
		 * @param type  note 音符 accidental 临时升降记号
		 * @returns
		 */
		const handleChange = async (params: { type: string; value: any }) => {
			const type = params.type;
			const value = params.value;
			console.log(params);
			if (type === "type") {
				// 设置音符类型
				data.noteType = value;
				return;
			}

			// 修改音符,或者添加音符
			if (type === "note") {
				if (data.active) {
					if (data.active.el_type !== "note") return;
					const activeNote =
						abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
					// console.log(activeNote, data.active.isFirstChecked);
					const _values = value.split("-");
					console.log("🚀 ~ _value:", _values);
					if (data.active.isFirstChecked) {
						activeNote.content = _values[0];
						activeNote.noteType = data.noteType;
						if (_values[1]) {
							activeNote.accidental = _values[1] || "";
						}
					} else {
						handleCreateNote(
							data.active.measureIndex,
							data.active.noteIndex,
							createNote({
								content: _values[0],
								noteType: data.noteType,
								accidental: _values[1] || "",
							})
						);
					}
					await handleResetRender();
					let _abcElem: AbcElem;
					if (data.active.isFirstChecked) {
						data.active.isFirstChecked = false;
						_abcElem = rangeHighlight(data.active.startChar);
					} else {
						const oldElem: AbcElem = abcData.visualObj.getElementFromChar(data.active.startChar);
						const abcElem: AbcElem = abcData.visualObj.getElementFromChar(oldElem.endChar);
						if (abcElem) {
							let indexStr: any = abcElem.chord?.find((n) => n.position === "left")?.name || "";
							indexStr = indexStr.split(".").map((n: string) => Number(n));
							data.active = {
								...abcElem,
								measureIndex: indexStr[0],
								noteIndex: indexStr[1],
								isFirstChecked: false,
							};
						}
						_abcElem = rangeHighlight(abcElem.startChar);
					}
					if (!_abcElem?.midiPitches) return;
					ABCJS.synth.playEvent(_abcElem.midiPitches, _abcElem.midiGraceNotePitches, 1000);
				} else {
					const measureIndex = abcData.abc.measures.length - 1;
					const noteIndex = abcData.abc.measures[measureIndex].notes.length - 1;
					handleCreateNote(
						measureIndex,
						noteIndex,
						createNote({
							content: value,
							noteType: data.noteType,
						})
					);
					handleResetRender();
				}
			}

			// 临时升降记号
			if (type === "accidentals") {
				if (!data.active) {
					Snackbar({
						content: "请先选择音符",
						position: "top",
					});
					return;
				}
				const activeNote =
					abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
				if (activeNote.content === "z") {
					Snackbar({
						content: "休止符无法添加临时升降记号",
					});
					return;
				}
				activeNote.accidental = value;
				await handleResetRender();
				rangeHighlight(data.active.startChar);
			}

			// 谱号
			if (type === "clef") {
				if (data.active) {
					const activeNote =
						abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
					if (!activeNote) return;
					activeNote.clef = `[${value}]`;
					await handleResetRender();
				} else {
					abcData.abc.celf = value;
					handleResetRender();
				}
			}

			// 调号
			if (type === "key") {
				if (data.active) {
					const activeNote =
						abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
					if (!activeNote) return;
					activeNote.key = `[${value}]`;
					await handleResetRender();
				} else {
					abcData.abc.key = value;
					await handleResetRender();
				}
			}

			// 拍号
			if (type === "meter") {
				if (data.active) {
					const activeNote =
						abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
					if (!activeNote) return;
					activeNote.meter = `[${value}]`;
					await handleResetRender();
				} else {
					abcData.abc.meter = value;
					await handleResetRender();
				}
			}

			//  演奏技法
			if (type === "play") {
				if (!data.active) {
					Snackbar({
						content: "请先选择音符",
					});
					return;
				}
				const activeNote =
					abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
				if (!activeNote) return;
				if (activeNote.play.includes(value)) {
					activeNote.play = activeNote.play.filter((item) => item !== value);
				} else {
					activeNote.play.push(value);
				}
				await handleResetRender();
				rangeHighlight(data.active.startChar);
			}
			// 力度标记,渐强渐弱
			if (type === "dynamics") {
				if (Array.isArray(value)) {
					// 渐强渐弱
					clearSelectNote();
					data.select.list = [];
					data.select.state = true;
					data.select.parmas = params;
					Snackbar({
						content: "请先选择开始音符",
						position: "top",
					});
					return;
				}
				if (!data.active) {
					Snackbar({
						content: "请先选择音符",
					});
					return;
				}

				const activeNote =
					abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
				if (!activeNote) return;
				if (activeNote.dynamics === value) {
					activeNote.dynamics = "";
				} else {
					activeNote.dynamics = value;
				}
				await handleResetRender();
				rangeHighlight(data.active.startChar);
			}

			// 连线
			if (type === "tie") {
				if (Array.isArray(value)) {
					// 渐强渐弱
					clearSelectNote();
					data.select.list = [];
					data.select.state = true;
					data.select.parmas = params;
					Snackbar({
						content: "请先选择开始音符",
					});
					return;
				}
				if (!data.active) {
					Snackbar({
						content: "请先选择音符",
					});
					return;
				}

				const activeNote =
					abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
				if (!activeNote) return;
				if (activeNote.tie === value) {
					activeNote.tie = "";
				} else {
					activeNote.tie = value;
					console.log("🚀 ~ activeNote:", activeNote);
				}
				await handleResetRender();
				rangeHighlight(data.active.startChar);
			}

			// 反复
			if (type === "repeat") {
				if (!data.active) {
					return;
				}
				const activeMeasure = abcData.abc.measures[data.active.measureIndex] || null;
				if (!activeMeasure) return;
				if (activeMeasure.repeat === value) {
					activeMeasure.repeat = "";
				} else {
					activeMeasure.repeat = value;
				}
				await handleResetRender();
				rangeHighlight(data.active.startChar + value.length);
			}

			// 小节线
			if (type === "barline") {
				if (!data.active) {
					return;
				}
				const activeMeasure = abcData.abc.measures[data.active.measureIndex] || null;
				if (!activeMeasure) return;
				// 如果是开始重复,就修改前一个小节的barline
				if (value === "|:") {
					const prevMeasure = abcData.abc.measures[data.active.measureIndex - 1] || null;
					if (!prevMeasure) return;
					prevMeasure.barline = value;
				} else {
					activeMeasure.barline = value;
				}
				await handleResetRender();
			}

			// 速度
			if (type === "speeds") {
				if (data.active) {
					if (data.active.measureIndex === 0 && data.active.noteIndex === 0) {
						abcData.abc.speed = value;
						await handleResetRender();
					} else {
						const activeNote =
							abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
						if (!activeNote) return;
						activeNote.speed = `[${value}]`;
						await handleResetRender();
					}
					rangeHighlight(data.active.startChar);
				} else {
					abcData.abc.speed = value;
					await handleResetRender();
				}
			}

			//  附点
			if (type === "dot") {
				if (!data.active) {
					Snackbar({
						content: "请先选择音符",
					});
					return;
				}
				const activeNote =
					abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
				if (!activeNote) return;
				activeNote.dot = activeNote.dot ? "" : value;
				await handleResetRender();
				rangeHighlight(data.active.startChar);
			}

			// 3连音
			if (type === "slus") {
				const activeNote =
					abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
				if (!activeNote) return;
				activeNote.slus = activeNote.slus === value ? "" : value;
				await handleResetRender();
				rangeHighlight(data.active.startChar);
			}
		};

		const handleDeleteNote = () => {
			if (!data.active) return;
			if (data.active.startChar === 0) return;
			data.music =
				data.music.substring(0, data.active.startChar) + data.music.substring(data.active.endChar);
			handleResetRender();
			data.active = null as unknown as INoteActive;
		};

		const clearSelectNote = () => {
			data.active = null as unknown as INoteActive;
			const notes = document.querySelectorAll(".abcjs-note_selected");
			notes.forEach((item) => {
				item.classList.remove("abcjs-note_selected");
				item.setAttribute("fill", "currentColor");
			});
		};

		const handleSelectNote = async () => {
			const type = data.select.parmas?.type;
			const value = data.select.parmas?.value;
			const startItem = data.select.list[0];
			const endItem = data.select.list[1];
			// 力度标记,渐强渐弱
			if (type === "dynamics") {
				const crescendo = Date.now() + "";
				abcData.abc.measures[startItem.measureIndex].notes[startItem.noteIndex].dynamics = value[0];
				abcData.abc.measures[startItem.measureIndex].notes[startItem.noteIndex].dCode = crescendo;
				abcData.abc.measures[endItem.measureIndex].notes[endItem.noteIndex].dynamics = value[1];
				abcData.abc.measures[endItem.measureIndex].notes[endItem.noteIndex].dCode = crescendo;
				await handleResetRender();
			}

			// 连音
			if (type === "tie") {
				const crescendo = Date.now() + "";
				if (abcData.abc.measures[startItem.measureIndex].notes[startItem.noteIndex].tie) {
					const tie = abcData.abc.measures[startItem.measureIndex].notes[startItem.noteIndex].tie;
					abcData.abc.measures[startItem.measureIndex].notes[startItem.noteIndex].tie = value[0] + tie;
				} else {
					abcData.abc.measures[startItem.measureIndex].notes[startItem.noteIndex].tie = value[0];
					abcData.abc.measures[startItem.measureIndex].notes[startItem.noteIndex].tCode = crescendo;
				}
				if (abcData.abc.measures[endItem.measureIndex].notes[endItem.noteIndex].tie) {
					const tie = abcData.abc.measures[endItem.measureIndex].notes[endItem.noteIndex].tie;
					abcData.abc.measures[endItem.measureIndex].notes[endItem.noteIndex].tie = tie + value[1];
				} else {
					abcData.abc.measures[endItem.measureIndex].notes[endItem.noteIndex].tie = value[1];
					abcData.abc.measures[endItem.measureIndex].notes[endItem.noteIndex].tCode = crescendo;
				}
				await handleResetRender();
			}

			data.select.state = false;
			data.select.list = [];
			data.select.parmas = null;
		};

		/** 移调 */
		const handleMoveKey = (step: number) => {
			console.log("移调", step);
			const oldStep = abcData.abcOptions.visualTranspose || 0;
			abcData.abcOptions.visualTranspose = oldStep + step;
			popup.moveKeyShow = false;
			handleResetRender();
		};

		/**
		 * 移动音符
		 * @param note 音符
		 * @param step 移动步数
		 */
		const handleMoveNote = async (type: "up" | "donw" | "drag", _step?: number) => {
			if (!data.active) return;
			const step = _step ? _step : type === "up" ? -1 : 1;
			const activeNote =
				abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || null;
			if (!activeNote) return;
			activeNote.content = moveNote(activeNote.content, step);
			// arr now contains elements that are either a chord, a decoration, a note name, or anything else. It can be put back to its original string with .join("").

			await handleResetRender();
			const _abcElem = rangeHighlight(data.active.startChar);
			if (!_abcElem?.midiPitches) return;
			console.log(_abcElem, abcData.visualObj.millisecondsPerMeasure());
			ABCJS.synth.playEvent(_abcElem.midiPitches, _abcElem.midiGraceNotePitches, 1000);
		};

		const handleKeyUp = (e: KeyboardEvent) => {
			if (e.key === "Backspace") handleDeleteNote();

			if (!data.active) return false;
			if (/^[A-Ga-g]$/.test(e.key)) {
				handleChange({ type: "note", value: e.key.toLocaleUpperCase() });
			}
			if (["ArrowUp", "ArrowDown"].includes(e.key)) {
				console.log(e.key);
				e.preventDefault();
				e.stopPropagation();
				handleMoveNote(e.key === "ArrowUp" ? "up" : "donw");
				return false;
			}
		};

		/** 重置曲谱 */
		const handleCreateSvg = () => {
			abcData.abc.measures = initMusic(30);
			handleResetRender();
		};

		const instruments = computed(() => {
			return ABCJS.synth.instrumentIndexToName.map((name, index) => ({ label: name, value: index }));
		});
		const getDetailData = async () => {
			const res = await api_musicSheetCreationDetail(route.query.id);
			if (res?.code == 200) {
				data.musicId = res.data.id || "";
				data.musicName = res.data.name || "";
				let abc = "" as any;
				try {
					abc = JSON.parse(res.data.creationData);
				} catch (error) {
					console.log(error);
				}
				if (abc) {
					abcData.abc.measures = abc;
				}
			}
		};
		const handleSaveMusic = async () => {
			await api_musicSheetCreationUpdate({
				name: data.musicName,
				creationConfig: JSON.stringify(abcData.abc.measures),
				id: data.musicId,
				subjectId: 3,
				creationData: data.music,
			});
			message.success("保存成功");
		};
		onMounted(async () => {
			await getDetailData();
			console.log(ABCJS);
			await handleResetRender();
			console.log(ABCJS.extractMeasures(data.music));
			document.addEventListener("keyup", handleKeyUp);
			window.onbeforeunload = (e) => {
				e.preventDefault();
				e.returnValue = '还有没保存的'
			};
		});
		onUnmounted(() => {
			document.removeEventListener("keyup", handleKeyUp);
		});

		const measureComputed = computed(() => {
			if (!data.active) return {} as unknown as IMeasure;
			const activeMeasure = abcData.abc.measures[data.active.measureIndex] || {};
			return activeMeasure;
		});

		const noteComputed = computed(() => {
			if (!data.active) return {} as unknown as INote;
			const activeNote =
				abcData.abc.measures[data.active.measureIndex]?.notes[data.active.noteIndex] || {};
			return activeNote;
		});

		/** 新建曲谱 */
		const handleCreateMusic = () => {
			showConfirmDialog({
				title: "温馨提示",
				message: "是否覆盖当前乐谱?",
			}).then(() => {
				handleCreateSvg();
				data.active = null as unknown as INoteActive;
			});
		};

		/** 添加小节 */
		const handleAddMearse = () => {
			for (let i = 0; i < data.addMearseNumber; i++) {
				if (["pre", "next"].includes(data.addMearseType)) {
					if (!data.active) {
						message.warning("请选择小节");
						return;
					}
					if (data.addMearseType === "pre") {
						abcData.abc.measures.splice(data.active.measureIndex, 0, createMeasure());
					} else if (data.addMearseType === "next") {
						abcData.abc.measures.splice(data.active.measureIndex + 1, 0, createMeasure());
					}
				} else {
					abcData.abc.measures.push(createMeasure());
				}
			}
			popup.barShow = false;
			handleResetRender();
		};

		const handleDeleteMearse = () => {
			if (data.deleteMearseType === "ing") {
				if (!data.active) {
					message.warning("请选择小节");
					return;
				}
				abcData.abc.measures.splice(data.active.measureIndex, 1);
			} else if (data.deleteMearseType === "finish") {
				abcData.abc.measures.splice(abcData.abc.measures.length - 1, 1);
			}
			popup.mearseDeleteShow = false;
			handleResetRender();
		};

		const downPng = async () => {
			await handleResetRender();
			const paper = document.getElementById("paper");
			if (!paper) return;
			const svg: any = paper.children[0]?.cloneNode(true);
			const annotation = svg.querySelectorAll(".abcjs-annotation");
			annotation.forEach((n: HTMLElement) => {
				n.remove();
			});
			const svgBox = paper.getBoundingClientRect();
			console.log("🚀 ~ svgBox:", svgBox);
			svg.setAttribute("width", `${svgBox.width * 3}`);
			svg.setAttribute("height", `${svgBox.height * 3}`);
			const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
			console.log("🚀 ~ svg:", svg);
			rect.setAttribute("x", "0");
			rect.setAttribute("y", "0");
			rect.setAttribute("width", `${svgBox.width * 10}`);
			rect.setAttribute("height", `${svgBox.height * 10}`);
			rect.setAttribute("fill", "#fff");
			svg.prepend(rect);
			if (svg) {
				const _canvas = svg2canvas(svg.outerHTML);
				// document.body.appendChild(_canvas);
				let el: any = document.createElement("a");
				// 设置 href 为图片经过 base64 编码后的字符串，默认为 png 格式
				el.href = _canvas.toDataURL();
				el.download = data.musicName + ".png";

				// 创建一个点击事件并对 a 标签进行触发
				const event = new MouseEvent("click");
				el.dispatchEvent(event);
			}
		};

		const downRef = ref();
		const downMidi = () => {
			const midi = ABCJS.synth.getMidiFile(abcData.visualObj, {
				chordsOff: true,
				midiOutputType: "link",
				fileName: "曲谱",
			});
			// console.log("🚀 ~ midi:", midi)
			downRef.value.innerHTML = midi;
			downRef.value.querySelector("a").click();
		};
		const downWav = () => {
			try {
				if (abcData.synthControl) {
					abcData.synthControl.download("曲谱.wav");
				}
			} catch (error) {
				const midiBuffer = new ABCJS.synth.CreateSynth();
				midiBuffer
					.init({
						visualObj: abcData.visualObj,
						options: abcData.synthOptions,
					})
					.then(() => {
						midiBuffer.prime().then(() => {
							// console.log(midiBuffer.download());
							downloadFile(midiBuffer.download(), "曲谱.wav");
						});
					});
			}
		};

		const handleDownFile = (type: IFileBtnType) => {
			if (type === "png") {
				downPng();
			} else if (type === "midi") {
				downMidi();
			} else if (type === "wav") {
				downWav();
			}
		};

		const handleExport = () => {
			const input = document.createElement("input");
			input.type = "file";
			input.accept = ".xml,.musicxml";
			input.onchange = (e: any) => {
				const file = e.target.files[0];
				const reader = new FileReader();
				reader.onload = (e: any) => {
					let abc = e.target.result;
					console.log("🚀 ~ abc:", abc);
					abc = new DOMParser().parseFromString(abc, "text/xml");
					console.log("🚀 ~ abc:", abc);
					abc = (window as any).vertaal(abc, { p: "f", t: 1, u: 0, v: 3, mnum: 0 });
					console.log(abc);
					data.music = abc[0];
					handleResetRender(false);
				};
				reader.readAsText(file);
			};
			input.click();
		};

		return () => (
			<div class={styles.container}>
				<div class={styles.containerTop}>
					<div class={styles.topWrap}>
						<div class={styles.topBtn}>
							<FileBtn
								onSelect={(val: IFileBtnType) => {
									if (val === "newMusic") {
										handleCreateMusic();
									} else if (val === "save") {
										handleSaveMusic();
									} else if (["xml"].includes(val)) {
										handleExport();
									} else if (val === "upload") {
									} else if (["png", "midi", "wav"].includes(val)) {
										handleDownFile(val);
									} else if (val === "print") {
									}
								}}
							/>
							<div>文件</div>
						</div>

						<div class={styles.topLine}></div>

						<div class={styles.topBtn} onClick={() => handleChange({ type: "dot", value: ">" })}>
							<div class={[styles.btnImg, noteComputed.value.dot === ">" && styles.btnImgActive]}>
								<img class={styles.topBtnIcon} src={getImage("icon_1.png")} />
							</div>
							<div>附点</div>
						</div>

						<div class={styles.topLine}></div>

						{ABC_DATA.accidentals.map((item) => (
							<div
								class={styles.topBtn}
								onClick={() => handleChange({ type: "accidentals", value: item.value })}
							>
								<div
									class={[
										styles.btnImg,
										noteComputed.value.accidental === item.value && styles.btnImgActive,
									]}
								>
									<img class={styles.topBtnIcon} src={item.icon} />
								</div>
								<div>{item.name}</div>
							</div>
						))}

						<div class={styles.topLine}></div>

						{ABC_DATA.tie.map((item) => (
							<div
								class={styles.topBtn}
								onClick={() => handleChange({ type: "tie", value: item.value })}
							>
								<div
									class={[styles.btnImg, noteComputed.value.tie === item.value && styles.btnImgActive]}
								>
									<img class={styles.topBtnIcon} src={item.icon} />
								</div>
								<div>{item.name}</div>
							</div>
						))}

						<div class={styles.topLine}></div>

						{ABC_DATA.play.slice(0, 4).map((item) => (
							<div
								class={[styles.topBtn]}
								onClick={() => handleChange({ type: "play", value: item.value })}
							>
								<div
									class={[
										styles.btnImg,
										noteComputed.value.play?.includes(item.value) && styles.btnImgActive,
									]}
								>
									<img class={styles.topBtnIcon} src={item.icon} />
								</div>
								<div>{item.name}</div>
							</div>
						))}

						<Trigger trigger="click">
							{{
								default: () => (
									<div class={styles.topDownArrow}>
										<img src={getImage("icon_arrow.png")} />
									</div>
								),
								content: () => (
									<div class={[styles.wrapBox, styles.dropDownWrap]}>
										{ABC_DATA.play.slice(4).map((item) => (
											<div
												class={[styles.topBtn]}
												onClick={() => {
													data.morePlay = false;
													handleChange({ type: "play", value: item.value });
												}}
											>
												<div
													class={[
														styles.btnImg,
														noteComputed.value.play?.includes(item.value) && styles.btnImgActive,
													]}
												>
													<TheIcon iconClassName={item.icon} />
												</div>
												<div>{item.name}</div>
											</div>
										))}
									</div>
								),
							}}
						</Trigger>

						<div class={styles.topLine}></div>

						<NDropdown
							trigger="click"
							options={ABC_DATA.slus as any}
							labelField="name"
							keyField="value"
							onSelect={(val) => {
								console.log(val);
								handleChange({ type: "slus", value: val });
							}}
						>
							<div class={[styles.topBtn]}>
								<div class={styles.btnImg}>
									<img class={styles.topBtnIcon} src={getImage("icon_13.png")} />
								</div>
								<div>连音</div>
							</div>
						</NDropdown>

						<div class={[styles.topBtn, styles.btnDisabled]}>
							<div class={styles.btnImg}>
								<img class={styles.topBtnIcon} src={getImage("icon_14.png")} />
							</div>
							<div>翻转</div>
						</div>

						<div class={styles.topLine}></div>

						<NPopover
							v-model:value={popup.moveKeyShow}
							trigger="click"
							contentStyle={{ width: "320px" }}
						>
							{{
								trigger: () => (
									<div class={styles.topBtn}>
										<div class={styles.btnImg} onClick={() => (popup.instrument = true)}>
											<img class={styles.topBtnIcon} src={getImage("icon_25.png")} />
										</div>
										<div>选择声部</div>
									</div>
								),
								default: () => (
									<>
										<div class={styles.btnLineTitle}>选择声部</div>

										<NSelect
											filterable
											options={instruments.value}
											v-model:value={abcData.synthOptions.program}
											onChange={() => handleResetRender()}
										></NSelect>
									</>
								),
							}}
						</NPopover>

						<NPopover
							v-model:value={popup.moveKeyShow}
							trigger="click"
							contentStyle={{ width: "320px" }}
						>
							{{
								trigger: () => (
									<div class={styles.topBtn}>
										<div class={styles.btnImg}>
											<img class={styles.topBtnIcon} src={getImage("icon_15.png")} />
										</div>
										<div>移调</div>
									</div>
								),
								default: () => (
									<>
										<div class={styles.btnLineTitle}>移调方式</div>

										<NSpace>
											<NButton secondary onClick={() => handleMoveKey(-1)}>
												<NIcon component={LongArrowAltDown} />
												向下移调
											</NButton>
											<NButton secondary onClick={() => handleMoveKey(1)}>
												<NIcon component={LongArrowAltUp} />
												向上移调
											</NButton>
										</NSpace>

										<div class={styles.btnLineTitle}>目标音调</div>

										<NGrid cols={5} yGap={8}>
											{ABC_DATA.key.map((item) => (
												<NGi>
													<div
														class={styles.btnItem}
														onClick={() => handleChange({ type: "key", value: item.value })}
													>
														<div class={[styles.btnItemIcon]}>
															<TheIcon iconClassName={item.icon} />
														</div>
														<div class={styles.btnItemName}>{item.name}</div>
													</div>
												</NGi>
											))}
										</NGrid>
									</>
								),
							}}
						</NPopover>

						<NPopover v-model:value={popup.speedShow} trigger="click" placement="bottom">
							{{
								trigger: () => (
									<div class={[styles.topBtn]}>
										<div class={styles.btnImg}>
											<img class={styles.topBtnIcon} src={getImage("icon_16.png")} />
										</div>
										<div>速度调整</div>
									</div>
								),
								default: () => <TheSpeed onChange={(val) => handleChange(val)} />,
							}}
						</NPopover>

						<NPopover
							v-model:show={popup.staffShow}
							trigger="click"
							placement="bottom"
							contentStyle={{ width: "320px" }}
						>
							{{
								trigger: () => (
									<div class={[styles.topBtn]}>
										<div class={styles.btnImg}>
											<img class={styles.topBtnIcon} src={getImage("icon_17.png")} />
										</div>
										<div>谱面显示</div>
									</div>
								),
								default: () => (
									<>
										<div class={styles.btnLineTitle}>乐谱大小</div>

										<NSpace>
											<NButton
												type={abcData.abcOptions.staffwidth === 1200 ? "primary" : "default"}
												secondary
												onClick={() => {
													abcData.abcOptions.staffwidth = 1200;
													handleResetRender();
												}}
											>
												小
											</NButton>
											<NButton
												type={abcData.abcOptions.staffwidth === 800 ? "primary" : "default"}
												secondary
												onClick={() => {
													abcData.abcOptions.staffwidth = 800;
													handleResetRender();
												}}
											>
												中
											</NButton>
											<NButton
												type={abcData.abcOptions.staffwidth === 400 ? "primary" : "default"}
												secondary
												onClick={() => {
													abcData.abcOptions.staffwidth = 400;
													handleResetRender();
												}}
											>
												大
											</NButton>
										</NSpace>

										<div class={styles.btnLineTitle}>小节数</div>

										<NSpace vertical>
											<NInputNumber
												min={1}
												v-model:value={(abcData.abcOptions.wrap as any).preferredMeasuresPerLine}
												placeholder="请输入小节数"
												onChange={() => {
													handleResetRender();
												}}
											/>

											{/* <NSpace style={{ marginTop: "20px" }} align="center" wrap={false} wrapItem={false}>
												<NButton style={{ width: "48%" }} round onClick={() => (popup.staffShow = false)}>
													取消
												</NButton>
												<NButton
													style={{ width: "48%" }}
													round
													type="primary"
												>
													确定
												</NButton>
											</NSpace> */}
										</NSpace>
									</>
								),
							}}
						</NPopover>

						<NPopover
							v-model:show={popup.barShow}
							trigger="click"
							placement="bottom"
							contentStyle={{ width: "320px" }}
						>
							{{
								trigger: () => (
									<div class={[styles.topBtn]}>
										<div class={styles.btnImg}>
											<img class={styles.topBtnIcon} src={getImage("icon_18.png")} />
										</div>
										<div>添加小节</div>
									</div>
								),
								default: () => (
									<>
										<div class={styles.btnLineTitle}>添加方式</div>

										<NSpace>
											<NButton
												type={data.addMearseType === "pre" ? "primary" : "default"}
												secondary
												onClick={() => (data.addMearseType = "pre")}
											>
												当前小节前
											</NButton>
											<NButton
												type={data.addMearseType === "next" ? "primary" : "default"}
												secondary
												onClick={() => (data.addMearseType = "next")}
											>
												当前小节后
											</NButton>
											<NButton
												type={data.addMearseType === "finish" ? "primary" : "default"}
												secondary
												onClick={() => (data.addMearseType = "finish")}
											>
												曲谱末尾
											</NButton>
										</NSpace>

										<div class={styles.btnLineTitle}>小节数</div>

										<NSpace vertical>
											<NInputNumber
												min={1}
												v-model:value={data.addMearseNumber}
												placeholder="请输入小节数"
											/>

											<NSpace style={{ marginTop: "20px" }} align="center" wrap={false} wrapItem={false}>
												<NButton style={{ width: "48%" }} round onClick={() => (popup.barShow = false)}>
													取消
												</NButton>
												<NButton
													style={{ width: "48%" }}
													round
													type="primary"
													onClick={() => handleAddMearse()}
												>
													确定
												</NButton>
											</NSpace>
										</NSpace>
									</>
								),
							}}
						</NPopover>

						<NPopover v-model:show={popup.mearseDeleteShow} trigger="click" placement="bottom">
							{{
								trigger: () => (
									<div class={[styles.topBtn]}>
										<div class={styles.btnImg}>
											<img class={styles.topBtnIcon} src={getImage("icon_19.png")} />
										</div>
										<div>删除小节</div>
									</div>
								),
								default: () => (
									<>
										<div class={styles.btnLineTitle}>删除方式</div>

										<NSpace vertical>
											<NSpace>
												<NButton
													type={data.deleteMearseType === "ing" ? "primary" : "default"}
													secondary
													onClick={() => (data.deleteMearseType = "ing")}
												>
													当前选中小节
												</NButton>
												<NButton
													type={data.deleteMearseType === "finish" ? "primary" : "default"}
													secondary
													onClick={() => (data.deleteMearseType = "finish")}
												>
													末尾空白小节
												</NButton>
											</NSpace>

											<NSpace style={{ marginTop: "20px" }} align="center" wrap={false} wrapItem={false}>
												<NButton style={{ width: "48%" }} round onClick={() => (popup.barShow = false)}>
													取消
												</NButton>
												<NButton
													style={{ width: "48%" }}
													round
													type="primary"
													onClick={() => handleDeleteMearse()}
												>
													确定
												</NButton>
											</NSpace>
										</NSpace>
									</>
								),
							}}
						</NPopover>

						<div class={styles.topLine}></div>

						<div
							style={{ marginLeft: "auto" }}
							class={styles.topBtn}
							onClick={() => togglePlay("reset")}
						>
							<div class={styles.btnImg}>
								<img class={styles.topBtnIcon} src={getImage("icon_20.png")} />
							</div>
							<div>重播</div>
						</div>
						<div class={styles.topBtn} onClick={() => togglePlay(data.playState ? "pause" : "play")}>
							<div class={styles.btnImg}>
								<img
									style={{ display: data.playState ? "" : "none" }}
									class={styles.topBtnIcon}
									src={getImage("icon_21_1.png")}
								/>
								<img
									style={{ display: data.playState ? "none" : "" }}
									class={styles.topBtnIcon}
									src={getImage("icon_21.png")}
								/>
							</div>
							<div>{data.playState ? "暂停" : "播放"}</div>
						</div>
						<div class={[styles.topBtn, styles.btnDisabled]}>
							<div class={styles.btnImg}>
								<img class={styles.topBtnIcon} src={getImage("icon_22.png")} />
							</div>
							<div>选段</div>
						</div>
						<div class={[styles.topBtn, styles.btnDisabled]}>
							<div class={styles.btnImg}>
								<img class={styles.topBtnIcon} src={getImage("icon_23.png")} />
							</div>
							<div>节拍器</div>
						</div>
						<div class={[styles.topBtn]} onClick={() => (popup.settingShow = true)}>
							<div class={styles.btnImg}>
								<img class={styles.topBtnIcon} src={getImage("icon_24.png")} />
							</div>
							<div>设置</div>
						</div>
					</div>
				</div>
				<div class={styles.content}>
					<div class={styles.slide}>
						<Collapse v-model={data.slide} elevation={false} divider={false}>
							<CollapseItem title="音符" name="note">
								<div class={styles.wrapBox}>
									{ABC_DATA.types.map((item) => (
										<div
											class={styles.topBtn}
											onClick={() => handleChange({ type: "type", value: item.value })}
										>
											<div class={[styles.btnImg, data.noteType === item.value && styles.btnImgActive]}>
												<TheIcon iconClassName={item.icon} />
											</div>
											<div>{item.name}</div>
										</div>
									))}
									<div class={styles.topBtn} onClick={() => handleChange({ type: "note", value: "z" })}>
										<div
											class={[styles.btnImg, noteComputed.value.content === "z" && styles.btnImgActive]}
										>
											<img style={{ width: "24px", height: "24px" }} src={getImage("icon_rest.png")} />
										</div>
										<div>休止符</div>
									</div>
								</div>
							</CollapseItem>
							<CollapseItem title="谱号" name="clef">
								<div class={styles.wrapBox}>
									{ABC_DATA.clef.map((item) => (
										<div
											class={styles.topBtn}
											onClick={() => handleChange({ type: "clef", value: item.value })}
										>
											<div class={[styles.btnImg]}>
												<TheIcon iconClassName={item.icon} />
											</div>
											<div>{item.name}</div>
										</div>
									))}
								</div>
							</CollapseItem>
							<CollapseItem title="调号" name="key">
								<div class={styles.wrapBox}>
									{ABC_DATA.key.map((item) => (
										<div
											class={styles.topBtn}
											onClick={() => handleChange({ type: "key", value: item.value })}
										>
											<div class={[styles.btnImg]}>
												<TheIcon iconClassName={item.icon} />
											</div>
											<div>{item.name}</div>
										</div>
									))}
								</div>
							</CollapseItem>

							<CollapseItem title="拍号" name="meter">
								<div class={styles.wrapBox}>
									{ABC_DATA.meter.map((item) => (
										<div
											class={styles.topBtn}
											onClick={() => handleChange({ type: "meter", value: item.value })}
										>
											<div class={[styles.btnImg]}>
												<TheIcon iconClassName={item.icon} />
											</div>
											<div>{item.name}</div>
										</div>
									))}
								</div>
							</CollapseItem>

							<CollapseItem title="力度记号" name="dynamics">
								<div class={styles.wrapBox}>
									{ABC_DATA.dynamics.map((item) => (
										<div
											class={styles.topBtn}
											onClick={() => handleChange({ type: "dynamics", value: item.value })}
										>
											<div
												class={[
													styles.btnImg,
													noteComputed.value.dynamics === item.value && styles.btnImgActive,
												]}
											>
												<TheIcon iconClassName={item.icon} size={["2em", "2em"]} />
											</div>
											<div>{item.name}</div>
										</div>
									))}
								</div>
							</CollapseItem>
							<CollapseItem title="反复与跳跃" name="repeat">
								<div class={styles.wrapBox}>
									{ABC_DATA.repeat.map((item) => (
										<div
											class={[styles.topBtn, styles.longTopBtn]}
											onClick={() => handleChange({ type: "repeat", value: item.value })}
										>
											<div
												class={[
													styles.btnImg,
													measureComputed.value.repeat === item.value && styles.btnImgActive,
												]}
											>
												<TheIcon iconClassName={item.icon} size={["5em", "1em"]} />
											</div>
											<div>{item.name}</div>
										</div>
									))}
								</div>
							</CollapseItem>
							<CollapseItem title="小节线" name="line">
								<div class={styles.wrapBox}>
									{ABC_DATA.bar.map((item) => (
										<div
											class={styles.topBtn}
											onClick={() => {
												data.morePlay = false;
												handleChange({ type: "barline", value: item.value });
											}}
										>
											<div
												class={[
													styles.btnImg,
													measureComputed.value.barline === item.value && styles.btnImgActive,
												]}
											>
												<TheIcon iconClassName={item.icon} size={["2em", "2em"]} />
											</div>
											<div>{item.name}</div>
										</div>
									))}
								</div>
							</CollapseItem>
						</Collapse>
					</div>
					<div class={styles.box}>
						<div class={styles.titleBox}>
							<div style={{ width: "50%", margin: "0 auto" }}>
								<NInput v-model:value={data.musicName} placeholder="乐谱名称" />
								{/* // <Input v-model={data.musicName} variant="outlined" placeholder="乐谱名称" /> */}
							</div>
						</div>
						<div id="paper"></div>
						<Keys show={data.active ? true : false} onClick={(val) => handleChange(val)} />
						{/* <div>
							<button onClick={handleCreateSvg}>重置曲谱</button>
						</div> */}

						<div style={{ display: "none" }}>
							<textarea
								ref={textAreaRef}
								class={styles.value}
								id="abc"
								onChange={() => {
									console.log(textAreaRef.value.value);
									data.music = textAreaRef.value.value;
									handleResetRender();
								}}
							></textarea>
						</div>
						<div id="audio" style={{ opacity: 0 }}></div>
						<div id="warnings"></div>

						<p class="beat"></p>
						<pre class="clicked-info"></pre>
						<pre class="feedback"></pre>
						<div id="container"></div>
					</div>
				</div>
				<div ref={downRef}></div>

				<TheSetting v-model:show={popup.settingShow} />
			</div>
		);
	},
});
