Browse Source

休止符显示

liushengqiang 1 year ago
parent
commit
a05cba98eb

+ 28 - 11
index-colexiu.html

@@ -1,13 +1,30 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Vite + Vue + TS</title>
-  </head>
-  <body>
-    <div id="app"></div>
-    <script type="module" src="/src/main.ts"></script>
-  </body>
-</html>
+
+<head>
+  <meta charset="UTF-8" />
+  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <title>酷乐秀</title>
+  <style>
+    #loading {
+      position: fixed;
+      left: 50%;
+      top: 50%;
+      transform: translate(-50%, -50%);
+      display: none;
+    }
+
+    #loading.show {
+      display: block;
+    }
+  </style>
+</head>
+
+<body>
+  <div id="app"></div>
+  <img id="loading" class="show" src="/loading.svg" alt="loading" />
+  <script type="module" src="/src/page-colexiu/main.ts"></script>
+</body>
+
+</html>

+ 12 - 0
src/helpers/communication.ts

@@ -87,3 +87,15 @@ export const api_openWebView = (content: any): Promise<IPostMessage | undefined>
 	if (!isApp()) return Promise.resolve({} as any);
 	return promisefiyPostMessage({ api: "openWebView", content });
 };
+
+/** 开启摄像头 */
+export const api_openCamera = (): Promise<IPostMessage | undefined> => {
+	if (!isApp()) return Promise.resolve({} as any);
+	return promisefiyPostMessage({ api: "openCamera" });
+};
+
+/** 关闭摄像头 */
+export const api_closeCamera = (): Promise<IPostMessage | undefined> => {
+	if (!isApp()) return Promise.resolve({} as any);
+	return promisefiyPostMessage({ api: "closeCamera" });
+};

+ 15 - 0
src/helpers/formateMusic.ts

@@ -645,6 +645,8 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 	let gradualSpeed;
 	let gradualChange: GradualChange | undefined;
 	let gradualChangeIndex = 0;
+	let totalMultipleRestMeasures = 0
+	let multipleRestMeasures = 0
 	const _notes = [] as any[];
 
 	if (state.gradualTimes) {
@@ -910,6 +912,18 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 				// 全休止符, 公用stave
 				// stave = allNotes[allNotes.length - 1].stave
 			}
+			
+			if(note.sourceMeasure.multipleRestMeasures) {
+				totalMultipleRestMeasures = note.sourceMeasure.multipleRestMeasures
+				multipleRestMeasures = 0
+			}
+			if (multipleRestMeasures < totalMultipleRestMeasures) {
+				multipleRestMeasures++
+			} else {
+				multipleRestMeasures = 0
+				totalMultipleRestMeasures = 0
+			}
+			
 			// console.log(note.tie)
 			const nodeDetail = {
 				isStaccato: note.voiceEntry.isStaccato(),
@@ -952,6 +966,7 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 				noteLength: 1,
 				osdmContext: osmd,
 				speedbeatUnit: beatUnit,
+				multipleRestMeasures: multipleRestMeasures,
 			};
 			nodeDetail.realKey = formatRealKey(note.halfTone - fixedKey * 12, nodeDetail);
 			nodeDetail.duration = nodeDetail.endtime - nodeDetail.time;

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

@@ -11,7 +11,7 @@ import { employeeQueryUserInfo, studentQueryUserInfo, teacherQueryUserInfo } fro
 export default defineComponent({
 	name: "App",
 	setup() {
-		const query = getQuery();
+		const query: any = getQuery()
 		/** 获取用户信息 */
 		const getUserInfo = async () => {
 			// const a = await request.get(`/student/queryUserInfo`)

+ 4 - 8
src/page-gym/detail/index.module.less

@@ -17,6 +17,9 @@
     height: 100vh;
     overflow: hidden;
     background-color: var(--van-primary-color);
+    &.opencamera{
+        opacity: .7;
+    }
 
     .headHeight {
         height: 62px;
@@ -28,8 +31,7 @@
         flex: 1;
         overflow-y: auto;
         border-radius: 10px;
-        background: #fff;
-
+        background: var(--container-background);
         &::-webkit-scrollbar {
             width: 0;
             display: none;
@@ -49,10 +51,4 @@
     #musicAndSelection {
         position: relative;
     }
-    #musicContainer #cursorImg-0 {
-        background-repeat: repeat-y;
-        background-color: transparent;
-        background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABRJREFUCB1jZDy49T8DEDCBCBAAACTkAnq23WmtAAAAAElFTkSuQmCC);
-        background-position-x: center;
-    }
 }

+ 16 - 11
src/page-gym/detail/index.tsx

@@ -1,3 +1,4 @@
+import queryString from "query-string";
 import { Skeleton } from "vant";
 import { defineComponent, onBeforeMount, onMounted, reactive, Transition } from "vue";
 import { useRoute } from "vue-router";
@@ -6,7 +7,6 @@ import Metronome, { metronomeData } from "../../helpers/metronome";
 import state, { isRhythmicExercises } from "../../state";
 import { storeData } from "../../store";
 import { setGlobalData } from "../../utils";
-import { getQuery } from "../../utils/queryString";
 import AudioList from "../../view/audio-list";
 import MusicScore from "../../view/music-score";
 import { sysMusicScoreAccompanimentQueryPage, sysMusicScoreCategoriesQueryTree } from "../api";
@@ -14,6 +14,7 @@ import EvaluatModel from "../evaluat-model";
 import HeaderTop from "../header-top";
 import styles from "./index.module.less";
 import { isSpecialShapedScreen } from "/src/helpers/communication";
+import { getQuery } from "/src/utils/queryString";
 import Evaluating, { evaluatingData } from "/src/view/evaluating";
 import MeasureSpeed from "/src/view/plugins/measure-speed";
 import Selection from "/src/view/selection";
@@ -23,8 +24,12 @@ const classids = [1, 30, 97]; // [大雅金唐, 竖笛教程, 声部训练]
 export default defineComponent({
 	name: "music-list",
 	setup() {
-		const route = useRoute();
-		const query = getQuery();
+		const route = useRoute()
+		const query: any = {
+			...getQuery(),
+			...route.query
+		};
+
 		const paramsId = route.params.id as string;
 		const detailData = reactive({
 			isLoading: true,
@@ -145,7 +150,7 @@ export default defineComponent({
 			detailData.showSelection = true;
 		};
 		return () => (
-			<div class={styles.detail} style={{ paddingLeft: detailData.paddingLeft }}>
+			<div class={[styles.detail, state.setting.camera && styles.opencamera]} style={{ paddingLeft: detailData.paddingLeft }}>
 				{!detailData.svgRendered && (
 					<div class={styles.skeleton}>
 						<Skeleton class={styles.skeleton} row={8} />
@@ -154,13 +159,7 @@ export default defineComponent({
 				<div class={styles.headHeight}>
 					<Transition name="van-slide-down">{detailData.svgRendered && <HeaderTop />}</Transition>
 				</div>
-				<div class={styles.container} id="mainContainer">
-					{state.modeType === "evaluating" && (
-						<>
-							<Evaluating />
-							{evaluatingData.rendered && <EvaluatModel />}
-						</>
-					)}
+				<div class={[styles.container, state.setting.eyeProtection && 'eyeProtection', !state.setting.displayCursor && 'hideCursor']} id="mainContainer">
 					{!detailData.isLoading && (
 						<div id="musicAndSelection">
 							<MusicScore onRendered={handleRendered} />
@@ -168,6 +167,12 @@ export default defineComponent({
 						</div>
 					)}
 					{!detailData.isLoading && <AudioList />}
+					{state.modeType === "evaluating" && (
+						<>
+							<Evaluating />
+							{evaluatingData.rendered && <EvaluatModel />}
+						</>
+					)}
 				</div>
 				<div class={styles.plugins}>{detailData.svgRendered && <MeasureSpeed />}</div>
 			</div>

+ 12 - 0
src/page-gym/header-top/image/close2.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g transform="translate(-493.000000, -57.000000)" fill="#01C1B5" fill-rule="nonzero">
+            <g transform="translate(143.000000, 40.000000)">
+                <g transform="translate(350.000000, 17.000000)">
+                    <path d="M1.05548433,1.07092551 L0.973890205,1.16134969 C0.666012474,1.54828454 0.694001358,2.11481906 1.05785686,2.46909941 L6.537,7.949 L1.05548433,13.4315873 C0.672191496,13.8148801 0.672191496,14.4441272 1.05548433,14.8274201 L1.08636669,14.8583024 L1.17896103,14.9399506 C1.56501142,15.2393273 2.12839072,15.2121112 2.48219949,14.8583024 L7.964,9.376 L13.4470285,14.8583024 C13.8303213,15.2415953 14.4595684,15.2415953 14.8428613,14.8583024 L14.8737436,14.8274201 L14.9553918,14.7348257 C15.2547684,14.3487753 15.2275524,13.785396 14.8737436,13.4315873 L9.391,7.949 L14.8737436,2.46675831 C15.2570364,2.08346548 15.2570364,1.45421835 14.8737436,1.07092551 L14.8428613,1.04004316 L14.7502669,0.958394979 C14.3642165,0.659018325 13.8008372,0.686234384 13.4470285,1.04004316 L7.964,6.53 L2.48231995,1.0401637 C2.09890665,0.65675032 1.46965952,0.65675032 1.08636669,1.04004316 L1.05548433,1.07092551 Z" id="路径"></path>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 19 - 10
src/page-gym/header-top/index.tsx

@@ -5,11 +5,13 @@ import iconBack from "./image/icon-back.svg";
 import Title from "./title";
 import state, { handleChangeSection, handleResetPlay, togglePlay } from "../../state";
 import { headImg } from "./image";
-import icons from './image/headerTop.json'
+import icons from "./image/headerTop.json";
 import { Badge, Circle, Popover } from "vant";
 import { metronomeData } from "../../helpers/metronome";
 import Speed from "./speed";
 import { evaluatingData, handleStartEvaluat } from "/src/view/evaluating";
+import { Popup } from "@varlet/ui";
+import Settting from "./settting";
 
 export const headData = reactive({
 	speedShow: false,
@@ -18,12 +20,15 @@ export const headData = reactive({
 export default defineComponent({
 	name: "header-top",
 	setup() {
+		const headerData = reactive({
+			settingMode: false,
+		});
 		const headRef = ref();
 
 		const toggleEvaluat = () => {
-			handleStartEvaluat()
-		}
-		const disabledList = [ "evaluating"]
+			handleStartEvaluat();
+		};
+		const disabledList = ["evaluating"];
 		return () => (
 			<div ref={headRef} class={styles.headerTop}>
 				<div class={styles.back}>
@@ -33,7 +38,7 @@ export default defineComponent({
 
 				<div class={styles.headRight}>
 					<div class={styles.btn} id="tips-step-2" onClick={toggleEvaluat}>
-						<img class={styles.iconBtn} src={state.modeType === 'evaluating' ? icons.evaluating2 : icons.evaluating} />
+						<img class={styles.iconBtn} src={state.modeType === "evaluating" ? icons.evaluating2 : icons.evaluating} />
 						<span>评测</span>
 					</div>
 					<div class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]} id="tips-step-4" onClick={() => handleChangeSection()}>
@@ -43,7 +48,7 @@ export default defineComponent({
 					</div>
 					<div class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]} id="tips-step-5" onClick={() => togglePlay()}>
 						<div class={styles.btnWrap}>
-							<img style={{ marginTop: "-1px" }} class={styles.iconBtn} src={ state.playState === "paused" ? icons.play : icons.pause} />
+							<img style={{ marginTop: "-1px" }} class={styles.iconBtn} src={state.playState === "paused" ? icons.play : icons.pause} />
 							<Circle class={styles.progress} stroke-width={80} currentRate={state.playProgress} rate={100} layerColor="#01C1B5" color="#FFC830" />
 						</div>
 						<span>{state.playState === "play" ? "暂停" : "播放"}</span>
@@ -55,7 +60,7 @@ export default defineComponent({
 							state.playSource = state.playSource === "music" ? "background" : "music";
 						}}
 					>
-						<img class={styles.iconBtn} src={state.playSource === "music" ? icons.music : icons.background } />
+						<img class={styles.iconBtn} src={state.playSource === "music" ? icons.music : icons.background} />
 						<span>{state.playSource === "music" ? "原声" : "伴奏"}</span>
 					</div>
 					<div
@@ -71,7 +76,7 @@ export default defineComponent({
 						class={styles.btn}
 						onClick={async () => {
 							metronomeData.disable = !metronomeData.disable;
-							metronomeData.metro?.initPlayer()
+							metronomeData.metro?.initPlayer();
 						}}
 					>
 						<img style={{ display: metronomeData.disable ? "block" : "none" }} class={styles.iconBtn} src={headImg("tickoff.png")} />
@@ -90,7 +95,7 @@ export default defineComponent({
 									id="tips-step-8"
 									class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]}
 									onClick={(e: Event) => {
-										e.stopPropagation()
+										e.stopPropagation();
 										headData.speedShow = !headData.speedShow;
 									}}
 								>
@@ -103,11 +108,15 @@ export default defineComponent({
 							default: () => <Speed />,
 						}}
 					</Popover>
-					<div class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]}>
+					<div class={[styles.btn, disabledList.includes(state.modeType) && styles.disable]} onClick={() => (headerData.settingMode = true)}>
 						<img class={styles.iconBtn} src={headImg("menu.svg")} />
 						<span>设置</span>
 					</div>
 				</div>
+
+				<Popup teleport="body" closeOnClickOverlay={false} defaultStyle={false} v-model:show={headerData.settingMode}>
+					<Settting onClose={() => headerData.settingMode = false} />
+				</Popup>
 			</div>
 		);
 	},

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

@@ -0,0 +1,73 @@
+.header-settting {
+    position: relative;
+}
+
+.closeBtn {
+    position: absolute;
+    right: -34px;
+    top: -6px;
+    width: 24px;
+    height: 24px;
+    border-radius: 50%;
+    background-color: #fff;
+    overflow: hidden;
+    padding: 6px;
+
+    img {
+        width: 100%;
+        height: 100%;
+        display: block;
+    }
+
+    &:active {
+        opacity: .8;
+    }
+}
+
+.content {
+    position: relative;
+    overflow: hidden;
+    border-radius: 18px;
+    width: 300px;
+    height: 86vh;
+    background-color: #fff;
+    max-height: 310px;
+    --van-tabs-line-height: 50px;
+    --van-tab-active-text-color: var(--van-primary-color);
+    :global{
+        .van-tab__panel{
+            height: calc(86vh - 50px);
+            overflow-y: auto;
+            padding: 0 10px 10px 10px;
+        }
+    }
+}
+
+.tags {
+    display: flex;
+    justify-content: space-between;
+    text-align: center;
+    padding: 0 var(--cell-padding);
+    &.tagsbig {
+        >span {
+            width: 47.5%;
+            text-align: center;
+        }
+    }
+
+    >span {
+        border-radius: 3PX;
+        display: block;
+        width: 31%;
+        font-size: 12PX;
+        padding: 6PX 0;
+        background-color: #F8F8F8;
+        color: #999999;
+        border: 1PX solid #F8F8F8;
+        &.active {
+            color: var(--van-primary-color);
+            border-color: var(--van-primary-color);
+            background-color: #E2FFF9;
+        }
+    }
+}

+ 110 - 0
src/page-gym/header-top/settting/index.tsx

@@ -0,0 +1,110 @@
+import { defineComponent } from "vue";
+import styles from "./index.module.less";
+import iconClose from "../image/close2.svg";
+import { Tab, Tabs } from "vant";
+import { Cell, Switch } from "@varlet/ui";
+import state from "/src/state";
+import { api_closeCamera, api_openCamera } from "/src/helpers/communication";
+
+export default defineComponent({
+	name: "header-settting",
+	emits: ["close"],
+	setup(props, { emit }) {
+		return () => (
+			<div class={styles["header-settting"]}>
+				<div class={styles.closeBtn} onClick={() => emit("close")}>
+					<img src={iconClose} />
+				</div>
+				<div class={styles.content}>
+					<Tabs border animated>
+						<Tab title="设置">
+							<Cell title="护眼模式">
+								{{
+									extra: () => <Switch v-model={state.setting.eyeProtection}></Switch>,
+								}}
+							</Cell>
+							<Cell title="校音提醒">
+								{{
+									extra: () => <Switch v-model={state.setting.soundEffect}></Switch>,
+								}}
+							</Cell>
+							<Cell title="摄像头">
+								{{
+									extra: () => (
+										<Switch
+											v-model={state.setting.camera}
+											onChange={(value) => {
+												if (value) {
+													api_openCamera();
+												} else {
+													api_closeCamera();
+												}
+											}}
+										></Switch>
+									),
+								}}
+							</Cell>
+							<Cell title="循环播放">
+								{{
+									extra: () => <Switch v-model={state.setting.repeatAutoPlay}></Switch>,
+								}}
+							</Cell>
+							<Cell title="显示指法">
+								{{
+									extra: () => <Switch v-model={state.setting.displayFingering}></Switch>,
+								}}
+							</Cell>
+							<Cell title="显示光标">
+								{{
+									extra: () => <Switch v-model={state.setting.displayCursor}></Switch>,
+								}}
+							</Cell>
+							<Cell title="选择调率"></Cell>
+							<div class={[styles.tags, styles.tagsbig]}>
+								<span class={[styles.tag, state.setting.frequency === 440 && styles.active]} onClick={() => (state.setting.frequency = 440)}>
+									440Hz
+								</span>
+								<span class={[styles.tag, state.setting.frequency === 442 && styles.active]} onClick={() => (state.setting.frequency = 442)}>
+									442Hz
+								</span>
+							</div>
+						</Tab>
+						<Tab title="评测">
+							<Cell title="选择评测难度"></Cell>
+							<div class={styles.tags}>
+								<span
+									class={[styles.tag, state.setting.evaluationDifficulty === "BEGINNER" && styles.active]}
+									onClick={() => (state.setting.evaluationDifficulty = "BEGINNER")}
+								>
+									入门级
+								</span>
+								<span
+									class={[styles.tag, state.setting.evaluationDifficulty === "ADVANCED" && styles.active]}
+									onClick={() => (state.setting.evaluationDifficulty = "ADVANCED")}
+								>
+									进阶级
+								</span>
+								<span
+									class={[styles.tag, state.setting.evaluationDifficulty === "PERFORMER" && styles.active]}
+									onClick={() => (state.setting.evaluationDifficulty = "PERFORMER")}
+								>
+									大师级
+								</span>
+							</div>
+							<Cell title="保存到相册">
+								{{
+									extra: () => <Switch v-model={state.setting.saveToAlbum}></Switch>,
+								}}
+							</Cell>
+							<Cell title="开启伴奏">
+								{{
+									extra: () => <Switch v-model={state.setting.enableAccompaniment}></Switch>,
+								}}
+							</Cell>
+						</Tab>
+					</Tabs>
+				</div>
+			</div>
+		);
+	},
+});

+ 2 - 0
src/page-gym/main.ts

@@ -1,6 +1,8 @@
 import 'vant/lib/index.css'
 import "@varlet/ui/es/popup/style/index";
 import "@varlet/ui/es/snackbar/style/index";
+import "@varlet/ui/es/cell/style/index";
+import "@varlet/ui/es/switch/style/index";
 import { createApp } from 'vue'
 import { getRequestHostname } from '../constant/whiteUrl'
 import { initStore } from '../store'

+ 4 - 2
src/page-gym/theme.css

@@ -1,6 +1,8 @@
-:root{
+:root {
     --van-primary-color: #01c1b5;
+    --color-primary    : #01c1b5;
 }
-.vf-StaveSection{
+
+.vf-StaveSection {
     display: none;
 }

+ 1 - 1
src/state.ts

@@ -101,7 +101,7 @@ const state = reactive({
 		/** 显示光标 */
 		displayCursor: true,
 		/** 频率 */
-		frequency: "442",
+		frequency: 442,
 		/** 评测难度 */
 		evaluationDifficulty: "ADVANCED" as IDifficulty,
 		/** 保存到相册 */

+ 14 - 0
src/style.css

@@ -3,6 +3,20 @@
   padding: 0;
   box-sizing: border-box;
 }
+:root{
+  --cursor-color: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABRJREFUCB1jZDy49T8DEDCBCBAAACTkAnq23WmtAAAAAElFTkSuQmCC);
+  --container-background: #fff;
+  --active-stave-box: rgba(1, 193, 181, 0.2);
+  --corsor-opacity: 1;
+}
+.eyeProtection{
+  --cursor-color: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABZJREFUCB1j/N8sv5UBCJhABMN/hv8AKQgEWNQffFMAAAAASUVORK5CYII=);
+  --container-background: #fff4e1;
+  --active-measur-backgorund: rgba(255, 98, 37, 0.18);
+}
+.hideCursor{
+  --corsor-opacity: 0;
+}
 .selectionToast{
   top: 10vh;
 }

+ 7 - 4
src/utils/queryString.ts

@@ -1,9 +1,12 @@
 import qs from 'query-string'
-import { useRoute } from 'vue-router'
 export const getQuery = () => {
-    const route = useRoute()
+    let search = {}
+    try {
+        search = qs.parse(location.search || location.hash.split('?')[1])
+    } catch (error) {
+        
+    }
     return {
-        ...qs.parse(location.search),
-        ...route.query
+        ...search,
     }
 }

+ 3 - 1
src/utils/request.ts

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

+ 5 - 7
src/view/evaluating/index.tsx

@@ -81,11 +81,6 @@ const checkUseEarphone = async () => {
 	const res = await getEarphone();
 	return res?.content?.checkIsWired || false;
 };
-/** 效音提醒 */
-const checkSoundEffect = () => {
-	// console.log("🚀 效音状态状态:")
-	return state.setting.soundEffect;
-};
 
 const handleSoundEffect = (res?: IPostMessage) => {
 	if (res?.content) {
@@ -142,11 +137,14 @@ export const handlePerformDetection = async () => {
 	if (evaluatingData.checkStep === 1) {
 		// 效音
 		// 是否需要开启效音
-		if (checkSoundEffect()) {
+		evaluatingData.checkStep = 10;
+		if (state.setting.soundEffect) {
 			evaluatingData.soundEffectMode = true;
 			handleStartSoundCheck();
+		} else {
+			handlePerformDetection();
 		}
-		evaluatingData.checkStep = 10;
+		
 		return;
 	}
 	if (evaluatingData.checkStep === 10) {

+ 5 - 2
src/view/music-score/index.module.less

@@ -2,10 +2,13 @@
     :global {
         #cursorImg-0 {
             min-height: 58PX;
-            content: url('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
+            content: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
             margin-top: -14PX;
-            background: var(--van-primary-color);
             border-radius: 2px;
+            background-image: var(--cursor-color);
+            background-repeat: repeat-y;
+            background-position-x: 50%;
+            opacity: var(--corsor-opacity);
         }
 
     }

+ 26 - 5
src/view/selection/index.module.less

@@ -3,7 +3,6 @@
     left: 0;
     top: 0;
     right: 0;
-    --active-stave-box: rgba(1, 193, 181, 0.2);
 }
 
 .position {
@@ -113,31 +112,53 @@
     align-items: center;
     pointer-events: none;
     transition: all .8s;
+
     img {
         height: 30px;
     }
 }
 
 :global {
-    .scoreItemLeve0{
+    .scoreItemLeve0 {
         background-color: rgba(255, 142, 142, 0.32);
     }
-    .scoreItemLeve1{
+
+    .scoreItemLeve1 {
         background-color: rgba(1, 193, 181, 0.2);
     }
-    .scoreItemLeve2{
+
+    .scoreItemLeve2 {
         background-color: rgba(255, 178, 82, 0.37);
     }
-    .scoreItemLeve3{
+
+    .scoreItemLeve3 {
         background-color: rgba(255, 220, 64, 0.4);
     }
+
     .centerTop-enter-active {
         opacity: 1;
     }
+
     .centerTop-enter-from {
         opacity: 0;
         left: 50%;
         top: 50%;
         transform: translateX(-50%) translateY(-50%) scale(.3);
     }
+}
+
+.dotWrap {
+    position: absolute;
+    top: -10px;
+    right: 6%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 20px;
+    height: 20px;
+    border-radius: 50%;
+    background-color: rgb(255, 145, 0);
+    color: #fff;
+    font-weight: bold;
+    font-size: 14px;
 }

+ 23 - 21
src/view/selection/index.tsx

@@ -61,10 +61,23 @@ export default defineComponent({
 							selectData.staves.push(noteItem);
 						}
 						MeasureNumberXMLList.push(item.MeasureNumberXML);
+					} else {
+						if (item.multipleRestMeasures) {
+							const preItem = selectData.staves.find((n: any) => n.MeasureNumberXML === item.MeasureNumberXML - 1);
+							if (preItem?.staveBox) {
+								noteItem.staveBox = {
+									left: preItem.staveBox.left,
+									top: preItem.staveBox.top,
+									width: preItem.staveBox.width,
+								};
+								selectData.staves.push(noteItem);
+								MeasureNumberXMLList.push(item.MeasureNumberXML);
+							}
+						}
 					}
 				}
 			}
-			// console.log("🚀 ~ selectData.notes:", selectData.notes);
+			// console.log("🚀 ~ selectData.notes:", selectData.staves);
 		};
 		const showClass = computed(() => {
 			return (item: any) => {
@@ -101,24 +114,6 @@ export default defineComponent({
 		});
 		onMounted(() => {
 			calcNoteData();
-			// let i = 0;
-			// setInterval(() => {
-			// 	// if (i > 6) {
-			// 	// 	i = 0
-			// 	// };
-
-			// 	const s = 
-			// 	evaluatingData.evaluatings[i] = {
-			// 		leve: getLeveByScoreMeasure(Math.floor(Math.random() * 100)),
-			// 		measureIndex: i,
-			// 		measureRenderIndex: i,
-			// 		score: Math.floor(Math.random() * 100),
-			// 		color: "",
-			// 		icon: leveByScoreMeasureIcons[0].icon,
-			// 		show: true,
-			// 	};
-			// 	i++;
-			// }, 2000);
 		});
 		return () => (
 			<div class={styles.selectionContainer}>
@@ -127,14 +122,21 @@ export default defineComponent({
 					return (
 						<>
 							{item.staveBox && (
-								<div class={[styles.position, showClass.value(item), scoreItem ? `scoreItemLeve${scoreItem.leve}` : '']} style={item.staveBox} onClick={() => handleSelection(item)}>
+								<div
+									class={[styles.position, showClass.value(item), scoreItem ? `scoreItemLeve${scoreItem.leve}` : ""]}
+									style={item.staveBox}
+									onClick={() => handleSelection(item)}
+								>
 									{!item.isRestFlag && metronomeData.lineShow && item.MeasureNumberXML === metronomeData.activeMetro?.measureNumberXML && (
 										<div class={styles.line} style={{ left: metronomeData.activeMetro.left }}></div>
 									)}
+									{!!item.multipleRestMeasures && state.activeMeasureIndex == item.MeasureNumberXML && (
+										<div class={styles.dotWrap}>{item.multipleRestMeasures}</div>
+									)}
 									<Transition
 										name="centerTop"
 										onAfterEnter={() => {
-											scoreItem.show = false
+											scoreItem.show = false;
 										}}
 									>
 										{scoreItem?.show && (