|
@@ -65,6 +65,8 @@ import { saveAs } from "file-saver";
|
|
|
import qs from "query-string";
|
|
|
import { useDocumentVisibility } from "@vueuse/core";
|
|
|
import request from "/src/utils/request";
|
|
|
+import { api_uploadFile } from "/src/utils/uploadFile";
|
|
|
+import { bufferToWave } from "/src/helpers/parseABC";
|
|
|
|
|
|
export const initMusic = (total: number): IMeasure[] => {
|
|
|
return new Array(total).fill(0).map((item, index) => {
|
|
@@ -132,10 +134,11 @@ export default defineComponent({
|
|
|
selectMearesShow: false, // 选择小节弹窗
|
|
|
});
|
|
|
const data = reactive({
|
|
|
+ saveLoading: false,
|
|
|
loading: true,
|
|
|
drawCount: 0,
|
|
|
isSave: true,
|
|
|
- musicId: "",
|
|
|
+ musicId: Date.now().toString(),
|
|
|
musicName: "", // 曲谱名称
|
|
|
creator: "", // 创建者
|
|
|
subjectId: "", // 声部
|
|
@@ -1321,6 +1324,7 @@ export default defineComponent({
|
|
|
data.musicId = res.data.id || "";
|
|
|
data.musicName = res.data.name || "";
|
|
|
data.creator = res.data.creator || "";
|
|
|
+ data.subjectId = res.data.subjectId || "";
|
|
|
let abc = "" as any;
|
|
|
try {
|
|
|
abc = JSON.parse(res.data.creationData);
|
|
@@ -1346,56 +1350,78 @@ export default defineComponent({
|
|
|
data.loading = false;
|
|
|
return res;
|
|
|
};
|
|
|
+ const setSaveLoading = (tips: boolean) => {
|
|
|
+ data.saveLoading = true;
|
|
|
+ if (tips) {
|
|
|
+ message.loading("保存中...", { duration: 0 });
|
|
|
+ }
|
|
|
+ };
|
|
|
const handleSaveMusic = async (tips = true) => {
|
|
|
const query = getQuery();
|
|
|
abcData.abc.title = data.musicName;
|
|
|
abcData.abc.creator = data.creator;
|
|
|
- if (query.id) {
|
|
|
- await api_musicSheetCreationUpdate({
|
|
|
- name: data.musicName,
|
|
|
- creator: data.creator,
|
|
|
- creationConfig: renderMeasures(abcData.abc, {
|
|
|
- hiddenIndex: true,
|
|
|
- showTitle: true,
|
|
|
- showCreator: true,
|
|
|
- }),
|
|
|
- creationData: JSON.stringify(cleanDeep(abcData.abc)),
|
|
|
- id: query.id,
|
|
|
- subjectId: "",
|
|
|
- });
|
|
|
- } else {
|
|
|
- const res = await api_musicSheetCreationSave({
|
|
|
- name: data.musicName,
|
|
|
- creator: data.creator,
|
|
|
- creationConfig: renderMeasures(abcData.abc, {
|
|
|
- hiddenIndex: true,
|
|
|
- showTitle: true,
|
|
|
- showCreator: true,
|
|
|
- }),
|
|
|
- creationData: JSON.stringify(cleanDeep(abcData.abc)),
|
|
|
- subjectId: "",
|
|
|
- });
|
|
|
- if (res?.data) {
|
|
|
- const hash = location.hash.split("?");
|
|
|
- const qs_data = qs.parse(hash[1]);
|
|
|
- qs_data.id = res.data;
|
|
|
- try {
|
|
|
- delete qs_data.config;
|
|
|
- } catch (error) {
|
|
|
- console.log("🚀 ~ error:", error);
|
|
|
+ setSaveLoading(tips);
|
|
|
+ const wavUrl = await productWav(false);
|
|
|
+ const pngUrl = await productPng(false);
|
|
|
+ console.log("🚀 ~ pngUrl:", pngUrl);
|
|
|
+ try {
|
|
|
+ if (query.id) {
|
|
|
+ await api_musicSheetCreationUpdate({
|
|
|
+ name: data.musicName,
|
|
|
+ creator: data.creator,
|
|
|
+ creationConfig: renderMeasures(abcData.abc, {
|
|
|
+ hiddenIndex: true,
|
|
|
+ showTitle: true,
|
|
|
+ showCreator: true,
|
|
|
+ }),
|
|
|
+ creationData: JSON.stringify(cleanDeep(abcData.abc)),
|
|
|
+ id: query.id,
|
|
|
+ subjectId: data.subjectId,
|
|
|
+ filePath: wavUrl,
|
|
|
+ coverImg: pngUrl
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ const res = await api_musicSheetCreationSave({
|
|
|
+ name: data.musicName,
|
|
|
+ creator: data.creator,
|
|
|
+ creationConfig: renderMeasures(abcData.abc, {
|
|
|
+ hiddenIndex: true,
|
|
|
+ showTitle: true,
|
|
|
+ showCreator: true,
|
|
|
+ }),
|
|
|
+ creationData: JSON.stringify(cleanDeep(abcData.abc)),
|
|
|
+ subjectId: data.subjectId,
|
|
|
+ filePath: wavUrl,
|
|
|
+ coverImg: pngUrl
|
|
|
+ });
|
|
|
+ if (res?.data) {
|
|
|
+ const hash = location.hash.split("?");
|
|
|
+ const qs_data = qs.parse(hash[1]);
|
|
|
+ qs_data.id = res.data;
|
|
|
+ try {
|
|
|
+ delete qs_data.config;
|
|
|
+ } catch (error) {
|
|
|
+ console.log("🚀 ~ error:", error);
|
|
|
+ }
|
|
|
+ location.hash = hash[0] + "?" + qs.stringify(qs_data);
|
|
|
}
|
|
|
- location.hash = hash[0] + "?" + qs.stringify(qs_data);
|
|
|
}
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
}
|
|
|
+
|
|
|
if (tips) {
|
|
|
+ message.destroyAll();
|
|
|
message.success("保存成功");
|
|
|
}
|
|
|
data.isSave = true;
|
|
|
+ data.saveLoading = false;
|
|
|
};
|
|
|
const hanldeInitCreate = () => {
|
|
|
const query = getQuery();
|
|
|
const abc = decodeUrl(query.config);
|
|
|
console.log("🚀 ~ abc:", abc);
|
|
|
+ data.subjectId = abc.subjectId || "";
|
|
|
abcData.abc.celf = abc.celf ?? "K:treble";
|
|
|
abcData.abc.key = abc.key ?? "K:C";
|
|
|
abcData.abc.meter = abc.meter ?? "M:4/4";
|
|
@@ -1533,36 +1559,53 @@ export default defineComponent({
|
|
|
handleResetRender();
|
|
|
};
|
|
|
|
|
|
+ const productPng = (isUrl = true) => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ const paper = document.getElementById("exportPng");
|
|
|
+ if (!paper) return;
|
|
|
+ const abc = renderMeasures(abcData.abc, {
|
|
|
+ hiddenIndex: true,
|
|
|
+ showTitle: true,
|
|
|
+ showCreator: true,
|
|
|
+ });
|
|
|
+ ABCJS.renderAbc(paper, abc, abcData.abcOptions);
|
|
|
+ const svg: any = paper.children[0]?.cloneNode(true);
|
|
|
+ const svgBox = paper.getBoundingClientRect();
|
|
|
+ svg.setAttribute("width", `${svgBox.width * 3}`);
|
|
|
+ svg.setAttribute("height", `${svgBox.height * 3}`);
|
|
|
+ const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
|
+ 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);
|
|
|
+ if (isUrl) {
|
|
|
+ // 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);
|
|
|
+ } else {
|
|
|
+ _canvas.toBlob(async (blob) => {
|
|
|
+ const pngUrl = await api_uploadFile(blob, data.musicId + ".png");
|
|
|
+ resolve(pngUrl);
|
|
|
+ }, "image/png");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
const downPng = async () => {
|
|
|
abcData.abc.title = `T:${data.musicName}`;
|
|
|
abcData.abc.creator = `R:${data.creator}`;
|
|
|
- const paper = document.getElementById("exportPng");
|
|
|
- if (!paper) return;
|
|
|
- const abc = renderMeasures(abcData.abc, { hiddenIndex: true, showTitle: true, showCreator: true });
|
|
|
- ABCJS.renderAbc(paper, abc, abcData.abcOptions);
|
|
|
- const svg: any = paper.children[0]?.cloneNode(true);
|
|
|
- const svgBox = paper.getBoundingClientRect();
|
|
|
- svg.setAttribute("width", `${svgBox.width * 3}`);
|
|
|
- svg.setAttribute("height", `${svgBox.height * 3}`);
|
|
|
- const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
|
- 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);
|
|
|
- }
|
|
|
+ productPng();
|
|
|
};
|
|
|
|
|
|
const downRef = ref();
|
|
@@ -1576,12 +1619,8 @@ export default defineComponent({
|
|
|
downRef.value.innerHTML = midi;
|
|
|
downRef.value.querySelector("a").click();
|
|
|
};
|
|
|
- const downWav = () => {
|
|
|
- try {
|
|
|
- if (abcData.synthControl) {
|
|
|
- abcData.synthControl.download("曲谱.wav");
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
+ const productWav = async (isUrl = true) => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
const midiBuffer = new ABCJS.synth.CreateSynth();
|
|
|
midiBuffer
|
|
|
.init({
|
|
@@ -1589,11 +1628,25 @@ export default defineComponent({
|
|
|
options: abcData.synthOptions,
|
|
|
})
|
|
|
.then(() => {
|
|
|
- midiBuffer.prime().then(() => {
|
|
|
- // console.log(midiBuffer.download());
|
|
|
- downloadFile(midiBuffer.download(), "曲谱.wav");
|
|
|
+ midiBuffer.prime().then(async () => {
|
|
|
+ if (isUrl) {
|
|
|
+ downloadFile(midiBuffer.download(), (data.musicName || "曲谱") + ".wav");
|
|
|
+ } else {
|
|
|
+ const blob = bufferToWave((midiBuffer as any).getAudioBuffer());
|
|
|
+ const wavurl = await api_uploadFile(blob, data.musicId + ".wav");
|
|
|
+ resolve(wavurl);
|
|
|
+ }
|
|
|
});
|
|
|
});
|
|
|
+ });
|
|
|
+ };
|
|
|
+ const downWav = () => {
|
|
|
+ try {
|
|
|
+ if (abcData.synthControl) {
|
|
|
+ abcData.synthControl.download((data.musicName || "曲谱") + ".wav");
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ productWav();
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -1707,6 +1760,7 @@ export default defineComponent({
|
|
|
</div>
|
|
|
<div class={styles.topBtn}>
|
|
|
<FileBtn
|
|
|
+ saveLoading={data.saveLoading}
|
|
|
onSelect={(val: IFileBtnType) => {
|
|
|
if (val === "newMusic") {
|
|
|
handleCreateMusic();
|