Browse Source

导入导出

liushengqiang 1 year ago
parent
commit
49a3e28318

+ 1 - 0
package.json

@@ -21,6 +21,7 @@
     "consola": "^2.15.3",
     "dayjs": "^1.11.7",
     "eventemitter3": "^5.0.0",
+    "file-saver": "^2.0.5",
     "howler": "^2.2.3",
     "html2canvas": "^1.4.1",
     "lodash": "^4.17.21",

+ 7 - 0
pnpm-lock.yaml

@@ -40,6 +40,9 @@ dependencies:
   eventemitter3:
     specifier: ^5.0.0
     version: 5.0.0
+  file-saver:
+    specifier: ^2.0.5
+    version: 2.0.5
   howler:
     specifier: ^2.2.3
     version: 2.2.3
@@ -2772,6 +2775,10 @@ packages:
       reusify: 1.0.4
     dev: true
 
+  /file-saver@2.0.5:
+    resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
+    dev: false
+
   /fill-range@7.0.1:
     resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
     engines: {node: '>=8'}

+ 1 - 0
src/env.d.ts

@@ -5,3 +5,4 @@ declare module "*.vue" {
 
 	export default vueComponent;
 }
+declare module "file-saver"

+ 8 - 0
src/pc/api.ts

@@ -32,3 +32,11 @@ export const api_musicSheetCreationUpdate = (data: any) => {
 export const api_subjectList = () => {
 	return request.post(`/subject/list`);
 };
+
+/** 导入xml */
+export const api_xmlToAbc = (data: any) => {
+	return request.post(`/musicSheetCreation/xmlToAbc`, {
+		requestType: 'form',
+		data: data
+	});
+}

+ 6 - 1
src/pc/home/component/file-btn/index.module.less

@@ -39,10 +39,15 @@
         .n-dropdown-menu {
             min-width: 120px;
         }
+        .n-dropdown-option .n-dropdown-option{
+            min-width: 125px;
+        }
+        
 
         .n-dropdown-option-body {
+            margin: 4px 0;
             padding: 0 12px;
-            --n-option-height: 45px;
+            --n-option-height: 38px;
 
             .n-dropdown-option-body__prefix {
                 display: none;

+ 22 - 27
src/pc/home/component/file-btn/index.tsx

@@ -14,6 +14,7 @@ export type IFileBtnType =
 	| "wav"
 	| "midi"
 	| "print"
+	| "down-xml"
 	| "exit";
 
 export default defineComponent({
@@ -39,23 +40,23 @@ export default defineComponent({
 				),
 				key: "save",
 			},
-			// {
-			// 	label: () => (
-			// 		<div class={styles.dropItem}>
-			// 			<img class={styles.dropIcon} src={getImage("icon_26_0.png")} />
-			// 			<span>导入</span>
-			// 		</div>
-			// 	),
-			// 	key: "import",
-			// 	// disabled: true,
-			// 	children: [
-			// 		{
-			// 			label: "XML",
-			// 			key: "xml",
-			// 			// disabled: true,
-			// 		},
-			// 	],
-			// },
+			{
+				label: () => (
+					<div class={styles.dropItem}>
+						<img class={styles.dropIcon} src={getImage("icon_26_0.png")} />
+						<span>导入</span>
+					</div>
+				),
+				key: "import",
+				// disabled: true,
+				children: [
+					{
+						label: "XML",
+						key: "xml",
+						// disabled: true,
+					},
+				],
+			},
 			{
 				label: () => (
 					<div class={styles.dropItem}>
@@ -76,6 +77,10 @@ export default defineComponent({
 				key: "export",
 				children: [
 					{
+						label: "XML",
+						key: "down-xml",
+					},
+					{
 						label: "PNG",
 						key: "png",
 					},
@@ -99,16 +104,6 @@ export default defineComponent({
 				key: "print",
 				disabled: true,
 			},
-			// {
-			// 	label: () => (
-			// 		<div class={styles.dropItem}>
-			// 			<img class={styles.dropIcon} src={getImage("icon_26_5.png")} />
-			// 			<span>退出</span>
-			// 		</div>
-			// 	),
-			// 	key: "exit",
-			// 	disabled: false,
-			// },
 		];
 		return () => (
 			<NDropdown

+ 22 - 3
src/pc/home/index.tsx

@@ -57,6 +57,7 @@ import { UseDraggable } from "@vueuse/components";
 import { getQuery } from "/src/utils/queryString";
 import Metronome, { metronomeData } from "/src/helpers/metronome";
 import cleanDeep from "clean-deep";
+import { saveAs } from "file-saver";
 
 export const initMusic = (total: number): IMeasure[] => {
 	return new Array(total).fill(0).map((item, index) => {
@@ -629,7 +630,7 @@ export default defineComponent({
 						autoFocus: false,
 						class: "deleteDialog saveDialog",
 						title: "温馨提示",
-						content: '是否保存当前曲谱?',
+						content: "是否保存当前曲谱?",
 						positiveText: "保存",
 						positiveButtonProps: {
 							type: "primary",
@@ -1225,6 +1226,7 @@ export default defineComponent({
 				}
 			}
 			data.loading = false;
+			return res;
 		};
 		const handleSaveMusic = async (tips = true) => {
 			await api_musicSheetCreationUpdate({
@@ -1412,6 +1414,20 @@ export default defineComponent({
 			}
 		};
 
+		const downXML = async () => {
+			const msg = message.loading("导出中...");
+			await handleSaveMusic(false);
+			const res = await getDetailData();
+			if (!res?.data?.xml) {
+				msg.type = "error";
+				msg.content = "导出失败";
+				return;
+			}
+			saveAs(res.data.xml, (data.musicName || '曲谱') + ".xml");
+			msg.type = "success";
+			msg.content = "导出成功";
+		};
+
 		const handleDownFile = (type: IFileBtnType) => {
 			if (type === "png") {
 				downPng();
@@ -1419,6 +1435,8 @@ export default defineComponent({
 				downMidi();
 			} else if (type === "wav") {
 				downWav();
+			} else if (type === "down-xml") {
+				downXML();
 			}
 		};
 
@@ -1428,6 +1446,7 @@ export default defineComponent({
 			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;
@@ -1502,7 +1521,7 @@ export default defineComponent({
 										} else if (["xml"].includes(val)) {
 											handleExport();
 										} else if (val === "upload") {
-										} else if (["png", "midi", "wav"].includes(val)) {
+										} else if (["png", "midi", "wav", "down-xml"].includes(val)) {
 											handleDownFile(val);
 										} else if (val === "print") {
 										}
@@ -2316,7 +2335,7 @@ export default defineComponent({
 							)}
 
 							{/* <textarea ref={textAreaRef} class={styles.value} id="abc"></textarea> */}
-							<div id="importRef"></div>
+							<div id="importRef" style={{ display: "none" }}></div>
 							<div id="audio" style={{ display: "none" }}></div>
 							{data.loadingAudioSrouce && (
 								<div class={styles.loading}>

+ 35 - 11
src/pc/home/runtime.ts

@@ -323,6 +323,27 @@ export const formateAbc = (visualObj: TuneObject, option: any) => {
 	const list = [];
 	let notes = [];
 	let measureIndex = 0;
+
+	const get_accidental = (noteItem: INote) => {
+		let accidental = "";
+
+		if (noteItem.content.includes("_")) {
+			accidental = "_";
+		}
+		if (noteItem.content.includes("__")) {
+			accidental = "__";
+		}
+		if (noteItem.content.includes("=")) {
+			accidental = "=";
+		}
+		if (noteItem.content.includes("^")) {
+			accidental = "^";
+		}
+		if (noteItem.content.includes("^^")) {
+			accidental = "^^";
+		}
+		return accidental;
+	};
 	for (let i = 0; i < visualObj.lines.length; i++) {
 		const line = visualObj.lines[i];
 		if (line.staff) {
@@ -369,21 +390,14 @@ export const formateAbc = (visualObj: TuneObject, option: any) => {
 							}
 							if (element.el_type === "note") {
 								// const abcEle = visualObj.getElementFromChar(element.startChar);
-								console.log("🚀 ~ abcEle:", element);
-								let content = ''
-								if (element.rest) {
-									content = 'z';
-								} else {
-									content = element.pitches?.[0]?.name ?? "";
-								}
-								console.log(content)
-								const note = createNote({
+								// console.log("🚀 ~ abcEle:", element);
+								let noteItem = {
 									clef: "", //// 谱号
 									key: "", // 调号
 									speed: "", // 速度
 									slus: "", // 3连音
 									tie: "", // 连音线 前,连音线 后
-									content: content, // 音符
+									content: "", // 音符
 									noteType: formateGetData.getNoteType(element.duration), // 音符时值
 									play: [],
 									dynamics: "", // 力度符号
@@ -391,7 +405,17 @@ export const formateAbc = (visualObj: TuneObject, option: any) => {
 									dot: "", //附点
 									tieline: "", // 延音线
 									segno: "", // 分割
-								});
+								};
+								if (element.rest) {
+									noteItem.content = "z";
+								} else {
+									noteItem.content = element.pitches?.[0]?.name ?? "";
+								}
+								noteItem.accidental = get_accidental(noteItem as any);
+								if (noteItem.accidental) {
+									noteItem.content = noteItem.content.replace(noteItem.accidental, "");
+								}
+								const note = createNote(noteItem);
 								measure.notes.push(note);
 							}
 						}