liushengqiang 2 years ago
parent
commit
6709132c16

+ 28 - 0
src/helpers/communication.ts

@@ -105,3 +105,31 @@ export const api_setStatusBarVisibility = () => {
 		},
 		},
 	});
 	});
 };
 };
+
+/** 跟练录音切换 */
+export const api_cloudToggleFollow = (state: "start" | "end") => {
+	if (!storeData.isApp) return Promise.resolve({} as any);
+	return promisefiyPostMessage({
+		api: "cloudToggleFollow",
+		content: {
+			state,
+		},
+	});
+};
+
+/** 跟练录音监听 */
+export const api_cloudFollowTime = (onFollowTime: CallBack, listen = true) => {
+	if (listen) {
+		listenerMessage("cloudFollowTime", onFollowTime);
+	} else {
+		removeListenerMessage("cloudFollowTime", onFollowTime);
+	}
+};
+
+
+/** 结束webview */
+export const api_back = () => {
+	postMessage({
+		api: 'back'
+	})
+}

+ 23 - 10
src/page-colexiu/detail/index.tsx

@@ -20,6 +20,8 @@ import { mappingVoicePart, subjectFingering } from "/src/view/fingering/fingerin
 import Fingering from "/src/view/fingering";
 import Fingering from "/src/view/fingering";
 import store from "store";
 import store from "store";
 import Tick, { handleInitTick } from "/src/view/tick";
 import Tick, { handleInitTick } from "/src/view/tick";
+import FollowPractice from "/src/view/follow-practice";
+import FollowModel from "../follow-model";
 
 
 export default defineComponent({
 export default defineComponent({
 	name: "music-list",
 	name: "music-list",
@@ -140,7 +142,7 @@ export default defineComponent({
 			} catch (error) {}
 			} catch (error) {}
 			// 设置节拍器
 			// 设置节拍器
 			if (state.needTick) {
 			if (state.needTick) {
-				const beatLengthInMilliseconds = osmd?.Sheet?.SheetPlaybackSetting?.beatLengthInMilliseconds || (60 / bpm * 1000);
+				const beatLengthInMilliseconds = osmd?.Sheet?.SheetPlaybackSetting?.beatLengthInMilliseconds || (60 / bpm) * 1000;
 				handleInitTick(beatLengthInMilliseconds, osmd?.Sheet?.SheetPlaybackSetting?.Rhythm?.Numerator || 4);
 				handleInitTick(beatLengthInMilliseconds, osmd?.Sheet?.SheetPlaybackSetting?.Rhythm?.Numerator || 4);
 			}
 			}
 		};
 		};
@@ -193,15 +195,18 @@ export default defineComponent({
 			}
 			}
 		);
 		);
 		// 监听播放状态
 		// 监听播放状态
-		watch(() => state.playState, () => {
-			detailData.headerHide = state.playState === 'play' ? true : false
-		})
+		watch(
+			() => state.playState,
+			() => {
+				detailData.headerHide = state.playState === "play" ? true : false;
+			}
+		);
 		onMounted(() => {
 		onMounted(() => {
-			window.addEventListener('resize', resetMusicScore)
-		})
+			window.addEventListener("resize", resetMusicScore);
+		});
 		onBeforeUnmount(() => {
 		onBeforeUnmount(() => {
-			window.removeEventListener('resize', resetMusicScore)
-		})
+			window.removeEventListener("resize", resetMusicScore);
+		});
 		return () => (
 		return () => (
 			<div
 			<div
 				class={[styles.detail, state.setting.camera && styles.opencamera, state.setting.eyeProtection && "eyeProtection"]}
 				class={[styles.detail, state.setting.camera && styles.opencamera, state.setting.eyeProtection && "eyeProtection"]}
@@ -220,8 +225,8 @@ export default defineComponent({
 					style={{ ...fingerConfig.value.container }}
 					style={{ ...fingerConfig.value.container }}
 					class={[styles.container, !state.setting.displayCursor && "hideCursor"]}
 					class={[styles.container, !state.setting.displayCursor && "hideCursor"]}
 					onClick={(e: Event) => {
 					onClick={(e: Event) => {
-						if (state.playState === 'play') {
-							detailData.headerHide = !detailData.headerHide
+						if (state.playState === "play") {
+							detailData.headerHide = !detailData.headerHide;
 						}
 						}
 					}}
 					}}
 				>
 				>
@@ -254,6 +259,14 @@ export default defineComponent({
 				</div>
 				</div>
 				{/* 节拍器 */}
 				{/* 节拍器 */}
 				{state.needTick && <Tick />}
 				{state.needTick && <Tick />}
+
+				{/* 跟练模式 */}
+				{state.modeType === "follow" && (
+					<>
+						<FollowPractice />
+						<FollowModel />
+					</>
+				)}
 			</div>
 			</div>
 		);
 		);
 	},
 	},

+ 23 - 15
src/page-colexiu/evaluat-model/index.module.less

@@ -4,27 +4,35 @@
     }
     }
 }
 }
 
 
-.btn {
+.startBtn {
     position: fixed;
     position: fixed;
     left: 50%;
     left: 50%;
     top: 50%;
     top: 50%;
-    transform: translate(-50%, -50%);
-    width: 130px;
-    height: 130px;
-    z-index: 10;
+    margin-left: -70px;
+    margin-top: -70px;
+    width: 140px;
+    height: 140px;
+    z-index: 11;
     & > img {
     & > img {
-        display: block;
-        width: 100%;
-        height: 100%;
+      display: block;
+      width: 100%;
+      height: 100%;
     }
     }
-}
-
-.endBtn {
+  }
+  .endBtn{
+    position: fixed;
+    left: 50%;
     top: 16px;
     top: 16px;
-    transform: translateX(-50%);
-    width: 119px;
-    height: 41px;
-}
+    width: 120px;
+    height: 40px;
+    margin-left: -70px;
+    z-index: 11;
+    & > img {
+      display: block;
+      width: 100%;
+      height: 100%;
+    }
+  }
 
 
 .dialogueBox {
 .dialogueBox {
     position: fixed;
     position: fixed;

+ 19 - 18
src/page-colexiu/evaluat-model/index.tsx

@@ -1,5 +1,5 @@
 import { Popup, Snackbar } from "@varlet/ui";
 import { Popup, Snackbar } from "@varlet/ui";
-import { defineComponent, onMounted, reactive, watch } from "vue";
+import { Transition, defineComponent, onMounted, reactive, watch } from "vue";
 import {
 import {
 	connectWebsocket,
 	connectWebsocket,
 	evaluatingData,
 	evaluatingData,
@@ -26,7 +26,7 @@ import { Vue3Lottie } from "vue3-lottie";
 import startData from "./data/start.json";
 import startData from "./data/start.json";
 import startingData from "./data/starting.json";
 import startingData from "./data/starting.json";
 import iconTastBg from "./icons/task-bg.svg";
 import iconTastBg from "./icons/task-bg.svg";
-import iconEvaluat from './icons/evaluating.json'
+import iconEvaluat from "./icons/evaluating.json";
 
 
 // frequency 频率, amplitude 振幅, decibels 分贝
 // frequency 频率, amplitude 振幅, decibels 分贝
 type TCriteria = "frequency" | "amplitude" | "decibels";
 type TCriteria = "frequency" | "amplitude" | "decibels";
@@ -116,7 +116,7 @@ export default defineComponent({
 					dontEvaluating: ListenMode || dontEvaluatingMode || item.skipMode,
 					dontEvaluating: ListenMode || dontEvaluatingMode || item.skipMode,
 					musicalNotesIndex: item.i,
 					musicalNotesIndex: item.i,
 					denominator: note.noteElement?.Length.denominator,
 					denominator: note.noteElement?.Length.denominator,
-					isOrnament: !!note?.voiceEntry?.ornamentContainer
+					isOrnament: !!note?.voiceEntry?.ornamentContainer,
 				};
 				};
 				datas.push(data);
 				datas.push(data);
 			}
 			}
@@ -144,7 +144,7 @@ export default defineComponent({
 				// evaluationCriteria: getEvaluationCriteria(),
 				// evaluationCriteria: getEvaluationCriteria(),
 			};
 			};
 			await connectWebsocket(content);
 			await connectWebsocket(content);
-			state.playSource = 'music';
+			state.playSource = "music";
 		};
 		};
 
 
 		/** 评测结果按钮处理 */
 		/** 评测结果按钮处理 */
@@ -209,20 +209,21 @@ export default defineComponent({
 		);
 		);
 		return () => (
 		return () => (
 			<div>
 			<div>
-				{evaluatingData.websocketState && (
-					<>
-						{!evaluatingData.startBegin && (
-							<div class={styles.btn} onClick={handleStartBegin}>
-								<img src={iconEvaluat.evaluatingStart} />
-							</div>
-						)}
-						{evaluatingData.startBegin && (
-							<div class={[styles.btn, styles.endBtn]} onClick={() => handleEndBegin(false)}>
-								<img src={iconEvaluat.evaluatingEnd} />
-							</div>
-						)}
-					</>
-				)}
+				<Transition name="pop-center">
+					{evaluatingData.websocketState && !evaluatingData.startBegin && (
+						<div class={styles.startBtn} onClick={handleStartBegin}>
+							<img src={iconEvaluat.evaluatingStart} />
+						</div>
+					)}
+				</Transition>
+				<Transition name="pop-center">
+					{evaluatingData.websocketState && evaluatingData.startBegin && (
+						<div class={styles.endBtn} onClick={() => handleEndBegin(false)}>
+							<img src={iconEvaluat.evaluatingEnd} />
+						</div>
+					)}
+				</Transition>
+
 				<div style={{ display: !evaluatingData.startBegin ? "" : "none" }} class={styles.dialogueBox} key="start">
 				<div style={{ display: !evaluatingData.startBegin ? "" : "none" }} class={styles.dialogueBox} key="start">
 					<div class={styles.dialogue}>
 					<div class={styles.dialogue}>
 						<img class={styles.dialoguebg} src={iconTastBg} />
 						<img class={styles.dialoguebg} src={iconTastBg} />

File diff suppressed because it is too large
+ 1 - 0
src/page-colexiu/follow-model/icons.json


+ 36 - 0
src/page-colexiu/follow-model/index.module.less

@@ -0,0 +1,36 @@
+:global{
+    .green{
+        .vf-notehead > path {
+            fill: green;
+        }
+    }
+}
+.startBtn {
+  position: fixed;
+  left: 50%;
+  top: 50%;
+  margin-left: -70px;
+  margin-top: -70px;
+  width: 140px;
+  height: 140px;
+  z-index: 11;
+  & > img {
+    display: block;
+    width: 100%;
+    height: 100%;
+  }
+}
+.endBtn{
+  position: fixed;
+  left: 50%;
+  top: 16px;
+  width: 120px;
+  height: 40px;
+  margin-left: -70px;
+  z-index: 11;
+  & > img {
+    display: block;
+    width: 100%;
+    height: 100%;
+  }
+}

+ 50 - 0
src/page-colexiu/follow-model/index.tsx

@@ -0,0 +1,50 @@
+import { Transition, defineComponent, onBeforeUnmount, onMounted, ref } from "vue";
+import styles from "./index.module.less";
+import icons from "./icons.json";
+import { handleFollowEnd, handleFollowStart } from "/src/view/follow-practice";
+
+export default defineComponent({
+	name: "follow-model",
+	setup() {
+		const startBtn = ref(false);
+		const endBtn = ref(false);
+		onMounted(() => {
+			startBtn.value = true;
+		});
+		onBeforeUnmount(() => {
+			startBtn.value = false;
+		});
+		return () => (
+			<>
+				<Transition name="pop-center">
+					{startBtn.value && (
+						<div class={styles.startBtn} key="start">
+							<img
+								src={icons.start}
+								onClick={() => {
+									startBtn.value = false;
+									endBtn.value = true;
+									handleFollowStart();
+								}}
+							/>
+						</div>
+					)}
+				</Transition>
+				<Transition name="pop-center">
+					{endBtn.value && (
+						<div class={styles.endBtn} key="end">
+							<img
+								src={icons.end}
+								onClick={() => {
+									startBtn.value = true;
+                                    endBtn.value = false;
+									handleFollowEnd();
+								}}
+							/>
+						</div>
+					)}
+				</Transition>
+			</>
+		);
+	},
+});

+ 5 - 0
src/page-colexiu/header-top/index.module.less

@@ -119,5 +119,10 @@
 :global {
 :global {
     .var-popup {
     .var-popup {
         overflow: hidden;
         overflow: hidden;
+        pointer-events: none;
+        .var-popup__overlay,
+        .var-popup__content{
+            pointer-events: auto;
+        }
     }
     }
 }
 }

+ 10 - 1
src/page-colexiu/header-top/index.tsx

@@ -14,6 +14,8 @@ import Settting from "./settting";
 import ModeTypeMode from "./mode-type-mode";
 import ModeTypeMode from "./mode-type-mode";
 import state, { handleChangeSection, handleResetPlay, handleRessetState, togglePlay } from "/src/state";
 import state, { handleChangeSection, handleResetPlay, handleRessetState, togglePlay } from "/src/state";
 import { getAudioCurrentTime } from "/src/view/audio-list";
 import { getAudioCurrentTime } from "/src/view/audio-list";
+import { toggleFollow } from "/src/view/follow-practice";
+import { api_back } from "/src/helpers/communication";
 
 
 export const headData = reactive({
 export const headData = reactive({
 	speedShow: false,
 	speedShow: false,
@@ -36,6 +38,8 @@ export default defineComponent({
 		const handleChangeModeType = (value: "practise" | "follow" | "evaluating") => {
 		const handleChangeModeType = (value: "practise" | "follow" | "evaluating") => {
 			if (value === "evaluating") {
 			if (value === "evaluating") {
 				toggleEvaluat();
 				toggleEvaluat();
+			} else if (value === "follow") {
+				toggleFollow();
 			}
 			}
 			headerData.modeMode = false;
 			headerData.modeMode = false;
 		};
 		};
@@ -59,9 +63,14 @@ export default defineComponent({
 		const fingeringDisplay = computed(() => {
 		const fingeringDisplay = computed(() => {
 			return state.fingeringInfo.name;
 			return state.fingeringInfo.name;
 		});
 		});
+
+		/** 返回 */
+		const handleBack = () => {
+			api_back()
+		};
 		return () => (
 		return () => (
 			<div ref={headRef} class={styles.headerTop}>
 			<div ref={headRef} class={styles.headerTop}>
-				<div class={styles.back}>
+				<div class={styles.back} onClick={handleBack}>
 					<img src={iconBack} />
 					<img src={iconBack} />
 				</div>
 				</div>
 				<Title text={state.examSongName} rightView={false} />
 				<Title text={state.examSongName} rightView={false} />

+ 3 - 0
src/state.ts

@@ -7,6 +7,7 @@ import { handleEndBegin, handleStartEvaluat, sendEvaluatingOffsetTime } from "./
 import { IFingering } from "src/view/fingering/fingering-config";
 import { IFingering } from "src/view/fingering/fingering-config";
 import { handleStartTick } from "./view/tick";
 import { handleStartTick } from "./view/tick";
 import { audioListStart, getAudioCurrentTime, getAudioDuration, setAudioCurrentTime, setAudioPlaybackRate } from "./view/audio-list";
 import { audioListStart, getAudioCurrentTime, getAudioDuration, setAudioCurrentTime, setAudioPlaybackRate } from "./view/audio-list";
+import { toggleFollow } from "./view/follow-practice";
 
 
 /** 入门 | 进阶 | 大师 */
 /** 入门 | 进阶 | 大师 */
 export type IDifficulty = "BEGINNER" | "ADVANCED" | "PERFORMER";
 export type IDifficulty = "BEGINNER" | "ADVANCED" | "PERFORMER";
@@ -410,6 +411,8 @@ export const handleRessetState = () => {
 		handleStartEvaluat();
 		handleStartEvaluat();
 	} else if (state.modeType === "practise") {
 	} else if (state.modeType === "practise") {
 		togglePlay("paused");
 		togglePlay("paused");
+	} else if (state.modeType === 'follow') {
+		toggleFollow(false)
 	}
 	}
 };
 };
 export default state;
 export default state;

+ 26 - 12
src/style.css

@@ -1,22 +1,36 @@
-*{
-  margin: 0;
-  padding: 0;
+* {
+  margin    : 0;
+  padding   : 0;
   box-sizing: border-box;
   box-sizing: border-box;
 }
 }
-:root{
-  --cursor-color: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABRJREFUCB1jZDy49T8DEDCBCBAAACTkAnq23WmtAAAAAElFTkSuQmCC);
+
+:root {
+  --cursor-color        : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABRJREFUCB1jZDy49T8DEDCBCBAAACTkAnq23WmtAAAAAElFTkSuQmCC);
   --container-background: #fff;
   --container-background: #fff;
-  --active-stave-box: rgba(1, 193, 181, 0.2);
-  --corsor-opacity: 1;
+  --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;
+
+.eyeProtection {
+  --cursor-color            : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABZJREFUCB1j/N8sv5UBCJhABMN/hv8AKQgEWNQffFMAAAAASUVORK5CYII=);
+  --container-background    : #fff4e1;
   --active-measur-backgorund: rgba(255, 98, 37, 0.18);
   --active-measur-backgorund: rgba(255, 98, 37, 0.18);
 }
 }
-.hideCursor{
+
+.hideCursor {
   --corsor-opacity: 0;
   --corsor-opacity: 0;
 }
 }
-.selectionToast{
+
+.selectionToast {
   top: 10vh;
   top: 10vh;
+}
+
+.pop-center-enter-from,
+.pop-center-leave-to {
+  transform: scale(0);
+}
+
+.pop-center-enter-active,
+.pop-center-leave-active {
+  transition: all 0.25s;
 }
 }

+ 171 - 0
src/view/follow-practice/index.tsx

@@ -0,0 +1,171 @@
+import { defineComponent, onMounted, onUnmounted, reactive, ref, } from "vue";
+import state, { gotoNext } from "/src/state";
+import { IPostMessage } from "/src/utils/native-message";
+import { api_cloudFollowTime, api_cloudToggleFollow } from "/src/helpers/communication";
+import { storeData } from "/src/store";
+import { Snackbar } from "@varlet/ui";
+
+export const followData = reactive({
+	list: [] as any, // 频率列表
+	index: 0,
+	start: false,
+	rendered: false,
+});
+
+/** 点击跟练模式 */
+export const toggleFollow = (notCancel = true) => {
+	state.modeType = state.modeType === "follow" ? "practise" : "follow";
+	// 取消跟练
+	if (!notCancel) {
+		followData.start = false;
+		openToggleRecord(false);
+	}
+};
+
+const noteFrequency = ref(0);
+const audioFrequency = ref(0);
+const followTime = ref(0);
+// 切换录音
+const openToggleRecord = async (open: boolean = true) => {
+	await api_cloudToggleFollow(open ? "start" : "end");
+	// 记录跟练时长
+	if (open) {
+		followTime.value = Date.now();
+	} else {
+		const playTime = Date.now() - followTime.value;
+		if (followTime.value !== 0 && playTime > 0) {
+			followTime.value = 0;
+		}
+	}
+};
+
+// 清除音符状态
+const onClear = () => {
+	state.times.forEach((item: any) => {
+		const note: HTMLElement = document.querySelector(`div[data-vf=vf${item.id}]`)!;
+		if (note) {
+			note.classList.remove("error");
+			note.classList.remove("success");
+		}
+	});
+};
+
+/** 开始跟练 */
+export const handleFollowStart = async () => {
+  if (!storeData.isApp){
+    Snackbar({
+      content: '请在APP端使用',
+      type: 'warning',
+    })
+    return
+  }
+	onClear();
+	followData.start = true;
+	followData.index = 0;
+	followData.list = [];
+	gotoNext(state.times[0]);
+	await openToggleRecord(true);
+  setStep()
+};
+/** 结束跟练 */
+export const handleFollowEnd = () => {
+	followData.start = false;
+	openToggleRecord(false);
+	followData.index = 0;
+	gotoNext(state.times[0]);
+};
+
+// 下一个
+const next = () => {
+	gotoNext(state.times[followData.index]);
+};
+
+// 获取当前音符
+const getNoteIndex = (): any => {
+	const item = state.times[followData.index];
+	if (item.frequency <= 0) {
+		followData.index = followData.index + 1;
+		next();
+		return getNoteIndex();
+	}
+	noteFrequency.value = item.frequency;
+	// state.fixedKey = item.realKey;
+	return {
+		id: item.id,
+		min: item.frequency - item.prevFrequency * 0.1,
+		max: item.frequency + item.nextFrequency * 0.1,
+	};
+};
+let checking = false;
+/** 录音回调 */
+const onFollowTime = (evt?: IPostMessage) => {
+	const frequency: number = evt?.content?.frequency;
+	audioFrequency.value = frequency;
+	// console.log("🚀 ~ frequency:", frequency);
+	followData.list.push(frequency);
+};
+
+/** 在渲染前后计算光标应该走到的音符 */
+const setStep = () => {
+	let startTime = Date.now();
+	requestAnimationFrame(() => {
+		const endTime = Date.now();
+		// 渲染时间大于16.6,就会让页面卡顿, 如果渲染时间大与16.6就下一个渲染帧去计算
+		if (endTime - startTime < 16.6) {
+			if (!followData.start) {
+				return;
+			}
+			checked();
+		}
+		setStep();
+	});
+};
+
+const checked = () => {
+	if (checking) return;
+	checking = true;
+	const item = getNoteIndex();
+	// console.log("🚀 ~ item:", item)
+	for (let i = 0; i < followData.list.length; i++) {
+		const frequency = followData.list[i];
+		if (frequency > item.min && frequency < item.max) {
+			// console.log(item.min, frequency, item.max);
+			next();
+			followData.index += 1;
+			followData.list = followData.list.slice(i + 1);
+			setColor(item, true);
+			checking = false;
+			return;
+		}
+	}
+	setColor(item);
+	checking = false;
+};
+const setColor = (item: any, isRight = false) => {
+	const note: HTMLElement = document.querySelector(`div[data-vf=vf${item.id}]`)!;
+	if (note) {
+		if (isRight) {
+			note.classList.remove("error");
+			note.classList.add("success");
+		} else {
+			note.classList.remove("success");
+			note.classList.add("error");
+		}
+	}
+};
+
+export default defineComponent({
+	name: "follow",
+	setup() {
+		onMounted(() => {
+			api_cloudFollowTime(onFollowTime);
+			console.log("进入跟练模式");
+		});
+		onUnmounted(() => {
+			api_cloudFollowTime(onFollowTime, false);
+			onClear();
+			console.log("退出跟练模式");
+		});
+		return () => <div></div>;
+	},
+});

+ 30 - 0
src/view/selection/index.module.less

@@ -161,4 +161,34 @@
     color: #fff;
     color: #fff;
     font-weight: bold;
     font-weight: bold;
     font-size: 14px;
     font-size: 14px;
+}
+
+.noteFollow{
+    pointer-events: none;
+    text-align: center;
+    display: none;
+    :global{
+        .van-icon-success,
+        .van-icon-cross{
+            display: none;
+        }
+    }
+    &:global(.success){
+        color: #07c160;
+        display: block;
+        :global{
+            .van-icon-success{
+                display: initial;
+            }
+        }
+    }
+    &:global(.error){
+        color: #ee0a24;
+        display: block;
+        :global{
+            .van-icon-cross{
+                display: initial;
+            }
+        }
+    }
 }
 }

+ 7 - 1
src/view/selection/index.tsx

@@ -4,6 +4,7 @@ import styles from "./index.module.less";
 import { metronomeData } from "/src/helpers/metronome";
 import { metronomeData } from "/src/helpers/metronome";
 import { evaluatingData } from "../evaluating";
 import { evaluatingData } from "../evaluating";
 import { getLeveByScoreMeasure, leveByScoreMeasureIcons } from "../evaluating/evaluatResult";
 import { getLeveByScoreMeasure, leveByScoreMeasureIcons } from "../evaluating/evaluatResult";
+import { Icon } from "vant";
 
 
 export default defineComponent({
 export default defineComponent({
 	name: "selection",
 	name: "selection",
@@ -162,7 +163,12 @@ export default defineComponent({
 				})}
 				})}
 				{selectData.notes.map((item: any) => {
 				{selectData.notes.map((item: any) => {
 					return (
 					return (
-						<div class={[styles.position, disableClickNote.value && styles.disable, styles.note]} style={item.bbox} onClick={() => skipNotePlay(item.index)}></div>
+						<div class={[styles.position, disableClickNote.value && styles.disable, styles.note]} style={item.bbox} onClick={() => skipNotePlay(item.index)}>
+							<div class={styles.noteFollow} data-vf={"vf" + item.id}>
+								<Icon name="success" />
+								<Icon name="cross" />
+							</div>
+						</div>
 					);
 					);
 				})}
 				})}
 			</div>
 			</div>

+ 0 - 1
src/view/tick/index.tsx

@@ -68,7 +68,6 @@ export default defineComponent({
 		/** 手动关闭 */
 		/** 手动关闭 */
 		const handleClose = () => {
 		const handleClose = () => {
 			tickData.tickEnd = true
 			tickData.tickEnd = true
-			// handleRessetState();
 		};
 		};
 		return () => (
 		return () => (
 			<Popup class={styles.popup} v-model:show={tickData.show} closeable onClickCloseIcon={handleClose}>
 			<Popup class={styles.popup} v-model:show={tickData.show} closeable onClickCloseIcon={handleClose}>

Some files were not shown because too many files changed in this diff