浏览代码

功能完成

liushengqiang 2 年之前
父节点
当前提交
7ca5cbd162

+ 4 - 1
src/page-gym/App.tsx

@@ -1,5 +1,5 @@
 import request from "umi-request";
-import { computed, defineComponent, onBeforeMount } from "vue";
+import { computed, defineComponent, onBeforeMount, onMounted } from "vue";
 import { RouterView } from "vue-router";
 import TheError from "../components/The-error";
 import { setUserInfo, storeData } from "../store";
@@ -36,6 +36,9 @@ export default defineComponent({
 			setUser();
 			localStorage.setItem("behaviorId", getRandomKey());
 		});
+		onMounted(() => {
+			document.getElementById("loading")!.className = "";
+		})
 
 		const inited = computed(() => {
 			return storeData.status === "login";

+ 12 - 2
src/page-gym/detail/index.module.less

@@ -26,10 +26,20 @@
         height: var(--header-height);
     }
 
-    .fingeringHeight {
-        position: relative;
+    .fingeringBottm {
+        position: absolute;
+        left: 0;
+        bottom: 0;
+        width: 100%;
         height: var(--fingerin-bottom);
     }
+    .fingeringRight {
+        position: absolute;
+        right: 0;
+        top: 0;
+        width: var(--fingerin-right);
+        height: 100%;
+    }
 
     .container {
         position: relative;

+ 24 - 7
src/page-gym/detail/index.tsx

@@ -1,6 +1,6 @@
 import queryString from "query-string";
 import { Skeleton } from "vant";
-import { computed, defineComponent, onBeforeMount, onMounted, reactive, Transition } from "vue";
+import { computed, defineComponent, nextTick, onBeforeMount, onMounted, reactive, Transition, watch } from "vue";
 import { useRoute } from "vue-router";
 import { formateTimes } from "../../helpers/formateMusic";
 import Metronome, { metronomeData } from "../../helpers/metronome";
@@ -8,7 +8,7 @@ import state, { isRhythmicExercises } from "../../state";
 import { storeData } from "../../store";
 import { setGlobalData } from "../../utils";
 import AudioList from "../../view/audio-list";
-import MusicScore from "../../view/music-score";
+import MusicScore, { resetMusicScore } from "../../view/music-score";
 import { sysMusicScoreAccompanimentQueryPage, sysMusicScoreCategoriesQueryTree } from "../api";
 import EvaluatModel from "../evaluat-model";
 import HeaderTop from "../header-top";
@@ -139,7 +139,6 @@ export default defineComponent({
 				getCategory(values[0]);
 				getMusicInfo(values[1]);
 			});
-			document.getElementById("loading")!.className = "";
 		});
 
 		/** 渲染完成 */
@@ -156,12 +155,30 @@ export default defineComponent({
 		/** 指法配置 */
 		const fingerConfig = computed(() => {
 			if (state.setting.displayFingering && state.fingeringInfo?.name) {
-				return {
-					"--fingerin-bottom": state.fingeringInfo.direction === "vertical" ? "" : "1.6rem",
-				};
+				if (state.fingeringInfo.direction === "transverse") {
+					return {
+						"--fingerin-bottom": "1.6rem",
+					};
+				} else {
+					return {
+						"--fingerin-right": "3rem",
+					};
+				}
 			}
 			return {};
 		});
+
+		watch(() => state.setting.displayFingering, () => {
+			if (state.fingeringInfo.direction === 'vertical'){
+				if (state.setting.displayFingering){
+					document.getElementById("musicAndSelection")?.style.removeProperty('--music-zoom')
+				} else {
+					nextTick(() => {
+						resetMusicScore()
+					})
+				}
+			}
+		})
 		return () => (
 			<div class={[styles.detail, state.setting.camera && styles.opencamera]} style={{ paddingLeft: detailData.paddingLeft, ...fingerConfig.value }}>
 				{!state.musicRendered && (
@@ -186,7 +203,7 @@ export default defineComponent({
 					)}
 					{/* 指法 */}
 					{state.setting.displayFingering && state.fingeringInfo?.name && (
-						<div class={styles.fingeringHeight} style={{ height: state.fingeringInfo.direction === "vertical" ? 0 : "" }}>
+						<div class={[state.fingeringInfo.direction === "transverse" ? styles.fingeringBottm : styles.fingeringRight]}>
 							<Fingering />
 						</div>
 					)}

+ 1 - 1
src/page-gym/header-top/index.tsx

@@ -114,7 +114,7 @@ export default defineComponent({
 					</div>
 				</div>
 
-				<Popup teleport="body" closeOnClickOverlay={false} defaultStyle={false} v-model:show={headerData.settingMode}>
+				<Popup teleport="body" defaultStyle={false} v-model:show={headerData.settingMode}>
 					<Settting onClose={() => headerData.settingMode = false} />
 				</Popup>
 			</div>

+ 4 - 0
src/page-gym/header-top/settting/index.module.less

@@ -39,6 +39,10 @@
             height: calc(86vh - 50px);
             overflow-y: auto;
             padding: 0 10px 10px 10px;
+            &::-webkit-scrollbar {
+                width: 0;
+                display: none;
+            }
         }
     }
 }

+ 2 - 1
src/utils/request.ts

@@ -59,8 +59,9 @@ request.interceptors.response.use(
 			}
 			if (data.code === 403) {
 				if (browserInfo.isApp) {
-					// postMessage({ api: "login" });
+					postMessage({ api: "login" });
 				} else {
+					storeData.status = 'error'
 					showToast('登录过期')
 				}
 			}

+ 11 - 16
src/view/fingering/fingering-config.ts

@@ -13,8 +13,6 @@ export type IFingering = {
 	name: IVocals;
 	direction: "vertical" | "transverse";
 	width?: string;
-	paddingLeft?: string;
-	paddingRight?: string;
 };
 
 type ITypeContent = {
@@ -24,17 +22,17 @@ type ITypeContent = {
 export type IVocals = "flute" | "clarinet" | "saxophone" | "trumpet" | "horn" | "trombone" | "up-bass-horn" | "small-drum" | "tuba" | "piccolo";
 
 /** 映射声部ID */
-export const mappingVoicePart = (id: number, soruce: 'GYM' | 'COLEXIU' | 'ORCHESTRA') : number => {
-  if (soruce === 'GYM') {
-    return id
-  } else if (soruce === 'COLEXIU'){
-    const subject: {[_key: string | number]: number} = {
-      2: 32
-    }
-    return subject[id]
-  }
-  return 0
-}
+export const mappingVoicePart = (id: number, soruce: "GYM" | "COLEXIU" | "ORCHESTRA"): number => {
+	if (soruce === "GYM") {
+		return id;
+	} else if (soruce === "COLEXIU") {
+		const subject: { [_key: string | number]: number } = {
+			2: 32,
+		};
+		return subject[id];
+	}
+	return 0;
+};
 
 /** 声部的指法配置信息 */
 export const subjectFingering: ITypeContent = {
@@ -46,8 +44,6 @@ export const subjectFingering: ITypeContent = {
 		name: "clarinet",
 		direction: "vertical",
 		width: "1rem",
-		paddingLeft: "0rem",
-		paddingRight: "1rem",
 	}, // 单簧管
 	5: {
 		name: "saxophone",
@@ -90,7 +86,6 @@ export const subjectFingering: ITypeContent = {
 		name: "piccolo",
 		direction: "vertical",
 		width: "1rem",
-		paddingRight: "0.8rem",
 	}, // 短笛
 };
 

+ 14 - 3
src/view/fingering/index.module.less

@@ -1,7 +1,4 @@
 .fingeringContainer{
-  position: absolute;
-  left: 0;
-  bottom: 0;
   width: 100%;
   height: 100%;
   display: flex;
@@ -9,6 +6,13 @@
   align-items: center;
   padding: 0 10px;
 }
+.vertical{
+  padding: 10px 6px 10px 0;
+  box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 10px;
+  .imgs{
+    width: 70%;
+  }
+}
 .imgs{
   position: relative;
   width: 84%;
@@ -23,6 +27,13 @@
     max-height: 100%;
   }
 }
+.rightContent{
+  display: flex;
+  flex-direction: column;
+  justify-content: space-evenly;
+  align-items: center;
+  height: 100%;
+}
 .yidiao{
   width: 30px;
   color: var(--van-primary-color);

+ 41 - 59
src/view/fingering/index.tsx

@@ -1,49 +1,8 @@
-import { computed, defineComponent, onBeforeMount, onMounted, reactive, Ref, ref, toRefs } from "vue";
+import { computed, defineComponent, onBeforeMount, reactive } from "vue";
 import styles from "./index.module.less";
 import state from "/src/state";
 import { getFingeringConfig, ITypeFingering } from "./fingering-config";
 
-export const getImageSize = (src: string): Promise<HTMLImageElement> => {
-	return new Promise((resolve, reject) => {
-		const img = new Image();
-		img.src = src;
-		img.onload = () => {
-			resolve(img);
-		};
-		img.onerror = (err) => reject(err);
-	});
-};
-
-export const formatFixedKey = (type: string, fixedKey: number): Ref<number> => {
-	if (type === "piccolo" && state.times[0]) {
-		return ref(fixedKey + (1 - state.times[0].octaveOffset) * 12);
-	} else {
-		return ref(fixedKey);
-	}
-};
-
-export const formatRelationship = (relationships: any, usedFixedKey: number) => {
-	let rs = relationships[usedFixedKey] || relationships[0] || [];
-	if (typeof rs[0] === "number" || typeof rs[0] === "string") {
-		return [rs];
-	} else if (typeof rs[0] === "object") {
-		return rs;
-	}
-	return [[]];
-};
-
-export const useFingeringSrc = (activeType: any, fingeringName: string, formatFixedKey: number): Ref<string> => {
-	const src = ref("");
-	if (activeType && fingeringName === "trombone") {
-		if (!activeType.relationship[formatFixedKey]) {
-			src.value = activeType.json.full2;
-			return src;
-		}
-	}
-	src.value = activeType.json.full;
-	return src;
-};
-
 export default defineComponent({
 	name: "fingering",
 	setup(props, { expose }) {
@@ -53,7 +12,6 @@ export default defineComponent({
 		});
 		const getFingeringData = async () => {
 			fingerData.subject = await getFingeringConfig(state.fingeringInfo.name);
-			console.log("🚀 ~ fingerData.relationship:", fingerData.subject);
 		};
 		onBeforeMount(() => {
 			getFingeringData();
@@ -69,24 +27,48 @@ export default defineComponent({
 			const rs: number[] = Array.isArray(relationship[1]) ? relationship[fingerData.relationshipIndex] : relationship;
 			const canTizhi = Array.isArray(relationship[1]);
 			return (
-				<div class={[styles.fingeringContainer]}>
-					<span class={[styles.yidiao, !rs.includes(0) && styles.canDisplay]}>转调</span>
+				<>
+					{state.fingeringInfo.direction === "transverse" ? (
+						<div class={[styles.fingeringContainer]}>
+							<span class={[styles.yidiao, rs.includes(0) && styles.canDisplay]}>转调</span>
+
+							<div class={styles.imgs}>
+								<img src={fingerData.subject?.json?.full} />
+								{rs.map((key: number | string, index: number) => {
+									const nk: string = typeof key === "string" ? key.replace("active-", "") : String(key);
+									return <img data-index={nk} src={fingerData.subject?.json?.[nk]} />;
+								})}
+							</div>
 
-					<div class={styles.imgs}>
-						<img src={fingerData.subject?.json?.full} />
-						{rs.map((key: number | string, index: number) => {
-							const nk: string = typeof key === "string" ? key.replace("active-", "") : String(key);
-							return <img data-index={nk} src={fingerData.subject?.json?.[nk]} />;
-						})}
-					</div>
+							<div
+								class={[styles.tizhi, canTizhi && styles.canDisplay]}
+								onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}
+							>
+								替指
+							</div>
+						</div>
+					) : (
+						<div class={[styles.fingeringContainer, styles.vertical]}>
+							<div class={styles.imgs}>
+								<img src={fingerData.subject?.json?.full} />
+								{rs.map((key: number | string, index: number) => {
+									const nk: string = typeof key === "string" ? key.replace("active-", "") : String(key);
+									return <img data-index={nk} src={fingerData.subject?.json?.[nk]} />;
+								})}
+							</div>
 
-					<div
-						class={[styles.tizhi, canTizhi && styles.canDisplay]}
-						onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}
-					>
-						替指
-					</div>
-				</div>
+							<div class={styles.rightContent}>
+								<span class={[styles.yidiao, rs.includes(0) && styles.canDisplay]}>转调</span>
+								<div
+									class={[styles.tizhi, canTizhi && styles.canDisplay]}
+									onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}
+								>
+									替指
+								</div>
+							</div>
+						</div>
+					)}
+				</>
 			);
 		};
 	},

+ 4 - 0
src/view/music-score/index.module.less

@@ -9,5 +9,9 @@
             width: 0;
             display: none;
         }
+        & > div {
+            transform: scale(var(--music-zoom));
+            transform-origin: left top;
+        }
     }
 }

+ 23 - 8
src/view/music-score/index.tsx

@@ -1,27 +1,42 @@
-import { defineComponent, onBeforeMount, reactive, ref } from "vue";
+import { defineComponent, nextTick, onBeforeMount, reactive, ref } from "vue";
 import { formatXML, onlyVisible } from "../../helpers/formateMusic";
 // // @ts-ignore
 import { OpenSheetMusicDisplay } from "/osmd-extended/src";
 import state from "/src/state";
 import Selection from "../selection";
-import "./index.module.less"
+import "./index.module.less";
+
+const musicData = reactive({
+	showSelection: false, // 可以加载点击浮层
+	isRenderLoading: true,
+	score: "",
+});
+
+/** 重新计算曲谱渲染比例 */
+export const resetMusicScore = () => {
+	const svgEL = document.querySelector("#osmdSvgPage1");
+	const svgContainer = document.getElementById("osmdCanvasPage1");
+	if (svgEL && svgContainer) {
+		let width: any = svgEL?.getAttribute("width");
+		width = isNaN(Number(width)) ? 0 : Number(width);
+		if (width) {
+			const zoom = svgContainer.offsetWidth / width
+			document.getElementById("musicAndSelection")?.style.setProperty('--music-zoom', zoom + '')
+		}
+	}
+};
 
 export default defineComponent({
 	name: "music-score",
 	emits: ["rendered"],
 	setup(prop, { emit }) {
-		const musicData = reactive({
-			showSelection: false, // 可以加载点击浮层
-			isRenderLoading: true,
-			score: "",
-		});
 		const getXML = async () => {
 			const res = await fetch(state.xmlUrl).then((response) => response.text());
 			const xml = formatXML(res);
 			musicData.score = onlyVisible(xml, state.partIndex);
 		};
 		const init = async () => {
-			const container = document.getElementById('musicAndSelection')
+			const container = document.getElementById("musicAndSelection");
 			// console.log("🚀 ~ container:", container);
 			if (!container || !musicData.score) return;
 			const osmd = new OpenSheetMusicDisplay(container, {