liushengqiang 1 tahun lalu
induk
melakukan
9caba183f9

+ 1 - 1
src/pc/App.tsx

@@ -1,5 +1,5 @@
 import { computed, defineComponent, onBeforeMount } from "vue";
-import { RouterView } from "vue-router";
+import { RouterView, useRoute } from "vue-router";
 import TheError from "../components/The-error";
 import { setUserInfo, storeData } from "../store";
 import { getQuery } from "../utils/queryString";

+ 8 - 0
src/pc/api.ts

@@ -24,3 +24,11 @@ export const api_musicSheetCreationRemove = (data: any) => {
 export const api_musicSheetCreationDetail = (data: any) => {
 	return request.get(`/musicSheetCreation/detail/${data}`);
 };
+/** 曲谱更新 */
+export const api_musicSheetCreationUpdate = (data: any) => {
+	return request.post(`/musicSheetCreation/update`, {data, requestType: 'json'});
+};
+/** 声部 */
+export const api_subjectList = () => {
+	return request.post(`/subject/list`);
+};

+ 6 - 0
src/pc/create/component/the-create/index.module.less

@@ -1,5 +1,11 @@
+:global{
+    .n-modal-mask{
+        background-color: transparent;
+    }
+}
 .setbox {
     position: relative;
+    top: -10vh;
     display: flex;
     flex-direction: column;
     border-radius: 6px;

+ 52 - 19
src/pc/create/component/the-create/index.tsx

@@ -19,14 +19,14 @@ import {
 	NTabs,
 	useMessage,
 } from "naive-ui";
-import { defineComponent, reactive, watch } from "vue";
+import { defineComponent, onMounted, reactive, watch } from "vue";
 import { Close } from "@vicons/ionicons5";
 import styles from "./index.module.less";
 import { getImage } from "/src/pc/home/images";
 import { ABC_DATA } from "/src/pc/home/runtime";
 import TheIcon from "/src/components/The-icon";
 import TheSpeed from "/src/pc/home/component/the-speed";
-import { api_musicSheetCreationSave } from "/src/pc/api";
+import { api_musicSheetCreationSave, api_subjectList } from "/src/pc/api";
 export default defineComponent({
 	name: "TheCreate",
 	props: {
@@ -41,32 +41,41 @@ export default defineComponent({
 		const instruments = [
 			{
 				label: "竖笛",
-				key: "shudi",
+				key: "CLARINET",
+				id: 4,
 				icon: getImage("icon_27_0.png"),
 			},
 			{
 				label: "排箫",
-				key: "paixiao",
+				key: "PANPIPE",
+				id: 1,
 				icon: getImage("icon_27_1.png"),
 			},
 			{
 				label: "口风琴",
-				key: "koufengqin",
+				key: "HARMONICA",
+				id: 5,
 				icon: getImage("icon_27_2.png"),
 			},
 			{
 				label: "陶笛",
-				key: "taodie",
+				key: "OCARINA",
+				id: 2,
 				icon: getImage("icon_27_3.png"),
 			},
 			{
 				label: "葫芦丝",
-				key: "hulusi",
+				key: "FENUGREEK_SILK",
+				id: 3,
 				icon: getImage("icon_27_4.png"),
 			},
 		];
+		const formsOptions = reactive({
+			subjects: [] as any[],
+			loading: false,
+		});
 		const froms = reactive({
-			instrument: "shudi",
+			subjectId: 4,
 			key: ABC_DATA.key[0],
 			meter: ABC_DATA.meter[0],
 			speed: 80,
@@ -74,16 +83,40 @@ export default defineComponent({
 		});
 
 		const handleCreate = async () => {
-			await api_musicSheetCreationSave({
-				creationData: "sd",
-				name: "sd",
-				creationConfig: "sd",
-				subjectId: 1,
-			});
-			emit('create')
+			formsOptions.loading = true;
+			try {
+				await api_musicSheetCreationSave({
+					creationData: "",
+					name: "",
+					creationConfig: JSON.stringify({
+						key: froms.key.value,
+						meter: froms.meter.value,
+						speed: froms.speed,
+						measure: froms.measure,
+					}),
+					subjectId: 1,
+				});
+				emit("create");
+			} catch (error) {
+				console.log("🚀 ~ error:", error);
+			}
+			formsOptions.loading = false;
+		};
+
+		const getSubjects = async () => {
+			const res = await api_subjectList();
+			formsOptions.subjects = res.data || [];
 		};
+		onMounted(async () => {
+			getSubjects();
+		});
 		return () => (
-			<NModal autoFocus={false} show={props.show} onUpdate:show={(val) => emit("update:show", val)}>
+			<NModal
+				transformOrigin="center"
+				autoFocus={false}
+				show={props.show}
+				onUpdate:show={(val) => emit("update:show", val)}
+			>
 				<div class={styles.setbox}>
 					<div class={styles.head}>
 						<div>新建乐谱</div>
@@ -102,8 +135,8 @@ export default defineComponent({
 						<NSpace style={{ paddingBottom: "45px" }}>
 							{instruments.map((item) => (
 								<div
-									class={[styles.item, froms.instrument === item.key && styles.itemActive]}
-									onClick={() => (froms.instrument = item.key)}
+									class={[styles.item, froms.subjectId === item.id && styles.itemActive]}
+									onClick={() => (froms.subjectId = item.id)}
 								>
 									<div class={styles.itemImg}>
 										<img class={styles.icon} src={item.icon} />
@@ -204,7 +237,7 @@ export default defineComponent({
 							<NButton round onClick={() => emit("update:show", false)}>
 								取消
 							</NButton>
-							<NButton round type="primary" onClick={() => handleCreate()}>
+							<NButton loading={formsOptions.loading} round type="primary" onClick={() => handleCreate()}>
 								确定
 							</NButton>
 						</div>

+ 37 - 10
src/pc/create/index.tsx

@@ -1,6 +1,6 @@
-import { defineComponent, onMounted, reactive } from "vue";
+import { defineComponent, nextTick, onMounted, reactive, ref } from "vue";
 import styles from "./index.module.less";
-import { NButton, NSpace, useDialog } from "naive-ui";
+import { NButton, NSpace, NSpin, useDialog } from "naive-ui";
 import { getImage } from "../home/images";
 import TheCreate from "./component/the-create";
 import { storeData } from "/src/store";
@@ -10,7 +10,7 @@ import { useRouter } from "vue-router";
 export default defineComponent({
 	name: "Create",
 	setup() {
-        const router = useRouter()
+		const router = useRouter();
 		const dialog = useDialog();
 		const forms = reactive({
 			teacherId: storeData.user.id,
@@ -21,14 +21,21 @@ export default defineComponent({
 		const data = reactive({
 			list: [] as any[],
 			addShow: false,
+			loading: false,
 			finish: false,
+			isCreated: false,
 		});
 		const getList = async () => {
+			data.loading = true;
 			const res = await api_musicSheetCreationPage({ ...forms });
 			if (res?.code == 200) {
-				data.list = res.data.rows;
+				if (data.isCreated) {
+					handleOpenNotaion(res.data.rows[0]);
+				}
+				data.list = data.list.concat(res.data.rows);
 				data.finish = res.data.rows.length < forms.rows;
 			}
+			data.loading = false;
 		};
 		const handleReset = () => {
 			forms.page = 1;
@@ -49,12 +56,28 @@ export default defineComponent({
 				onNegativeClick: () => {},
 			});
 		};
+		const loadingRef = ref();
 		onMounted(() => {
 			getList();
+			const obv = new IntersectionObserver((entries) => {
+				if (entries[0].isIntersecting) {
+					if (data.finish || data.loading) return;
+					forms.page++;
+					getList();
+				}
+			});
+			obv.observe(loadingRef.value?.$el);
 		});
-        const handleOpenNotaion = (item: any) => {
-            window.parent.open(`${location.origin}/notation/#/?id=${item.id}`)
-        }
+		const handleOpenNotaion = (item: any) => {
+			window.parent.postMessage(
+				{
+					api: "notation_open",
+					url: `${location.origin}/notation/#/?id=${item.id}`,
+				},
+				"*"
+			);
+		};
+
 		return () => (
 			<div class={styles.wrap}>
 				<NSpace size={18}>
@@ -65,9 +88,7 @@ export default defineComponent({
 
 					{data.list.map((item) => (
 						<div class={styles.item} onClick={() => handleOpenNotaion(item)}>
-							<div class={styles.imgBox}>
-								<img src={getImage("icon_29.png")} />
-							</div>
+							<div class={styles.imgBox}>{/* <img src={getImage("icon_29.png")} /> */}</div>
 							<div class={styles.itemBottom}>
 								<div class={styles.bottombox}>
 									<div class={styles.bottomLeft}>
@@ -89,11 +110,17 @@ export default defineComponent({
 						</div>
 					))}
 				</NSpace>
+				{!data.finish && (
+					<NSpace ref={loadingRef} justify="center" style={{ padding: "30px" }}>
+						<NSpin size="large" />
+					</NSpace>
+				)}
 
 				<TheCreate
 					v-model:show={data.addShow}
 					onCreate={() => {
 						data.addShow = false;
+						data.isCreated = true;
 						handleReset();
 					}}
 				/>

+ 0 - 1
src/pc/home/component/file-btn/index.tsx

@@ -24,7 +24,6 @@ export default defineComponent({
 					</div>
 				),
 				key: "save",
-				disabled: true
 			},
 			{
 				label: () => (

+ 1 - 1
src/pc/home/index.module.less

@@ -196,7 +196,7 @@
 
 .titleBox {
     :global {
-        .arco-input-wrapper {
+        .n-input__border {
             border: 1px dashed #ccc;
         }
     }

+ 35 - 8
src/pc/home/index.tsx

@@ -24,6 +24,7 @@ import {
 	NGi,
 	NGrid,
 	NIcon,
+	NInput,
 	NInputNumber,
 	NModal,
 	NPopover,
@@ -38,7 +39,7 @@ 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 } from "../api";
+import { api_musicSheetCreationDetail, api_musicSheetCreationUpdate } from "../api";
 
 const allPitches = [
 	"C,,,,",
@@ -173,8 +174,10 @@ export default defineComponent({
 			settingShow: false, // 设置弹窗
 		});
 		const data = reactive({
+			musicId: "",
 			musicName: "", // 曲谱名称
-			musicCompose: "", // 曲谱作者
+			subjectId: "", // 声部
+			speed: "",
 			music: "",
 			playState: false, // 播放状态
 			active: null as unknown as INoteActive,
@@ -910,7 +913,30 @@ export default defineComponent({
 			return ABCJS.synth.instrumentIndexToName.map((name, index) => ({ label: name, value: index }));
 		});
 		const getDetailData = async () => {
-			await api_musicSheetCreationDetail(route.query.id);
+			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();
@@ -918,6 +944,10 @@ export default defineComponent({
 			await handleResetRender();
 			console.log(ABCJS.extractMeasures(data.music));
 			document.addEventListener("keyup", handleKeyUp);
+			window.onbeforeunload = (e) => {
+				e.preventDefault();
+				e.returnValue = '还有没保存的'
+			};
 		});
 		onUnmounted(() => {
 			document.removeEventListener("keyup", handleKeyUp);
@@ -1091,6 +1121,7 @@ export default defineComponent({
 									if (val === "newMusic") {
 										handleCreateMusic();
 									} else if (val === "save") {
+										handleSaveMusic();
 									} else if (["xml"].includes(val)) {
 										handleExport();
 									} else if (val === "upload") {
@@ -1714,13 +1745,9 @@ export default defineComponent({
 					<div class={styles.box}>
 						<div class={styles.titleBox}>
 							<div style={{ width: "50%", margin: "0 auto" }}>
-								<Input v-model={data.musicName} placeholder="乐谱名称" />
+								<NInput v-model:value={data.musicName} placeholder="乐谱名称" />
 								{/* // <Input v-model={data.musicName} variant="outlined" placeholder="乐谱名称" /> */}
 							</div>
-							<div style={{ width: "140px", margin: "20px 0 0 auto" }}>
-								<Input v-model={data.musicCompose} placeholder="作曲" />
-								{/* <Input v-model={data.musicCompose} size="small" variant="outlined" placeholder="作曲" /> */}
-							</div>
 						</div>
 						<div id="paper"></div>
 						<Keys show={data.active ? true : false} onClick={(val) => handleChange(val)} />

+ 2 - 2
src/utils/request.ts

@@ -30,8 +30,8 @@ request.interceptors.request.use(
 			url: _prefix + url,
 			options: {
 				...options,
-				params: cleanDeep(options.params),
-				data: cleanDeep(options.data),
+				params: options.params,
+				data: options.data,
 				headers: {
 					...options.headers,
 					...authHeaders,