Bläddra i källkod

feat: 练习作业新版功能开发

TIANYONG 1 månad sedan
förälder
incheckning
0f7b6857f9

+ 63 - 6
src/page-instrument/custom-plugins/work-home/index.module.less

@@ -1,13 +1,70 @@
 .homework{
     position: fixed;
-    left: 14px;
+    left: 46px;
     top: 64px;
-    background-color: rgba(0, 0, 0, .6);
-    border-radius: 20px;
+    background-color: #C5E6F7;
+    border-radius: 12px;
     font-size: 14px;
-    color: #fff;
-    padding: 5px 8px;
+    color: #080808;
+    width: 106px;
+    text-align: center;
+    padding: 4px 0;
     line-height: 1;
-    font-weight: 300;
     z-index: 100;
+    span {
+        margin-left: 8px;
+    }
+    .blinkDot {
+        position: absolute;
+        left: 8px;
+        top: 9px;
+        width: 3px;
+        height: 3px;
+        border-radius: 50%;
+        background: #FF5A56;
+        animation: blink 1s infinite; /* 定义动画,周期 2 秒,永远重复 */
+    }
+    .grayDot {
+        position: absolute;
+        left: 8px;
+        top: 9px;
+        width: 3px;
+        height: 3px;
+        border-radius: 50%;
+        background: #aaaaaa;
+    }
+}
+
+@keyframes blink {
+    0% {
+      opacity: 1; /* 完全可见 */
+    }
+    50% {
+      opacity: 0; /* 完全透明 */
+    }
+    100% {
+      opacity: 1; /* 完全可见 */
+    }
+}
+
+.workDonePop {
+    position: fixed;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    background: rgba(0, 0, 0, 0.7);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    z-index: 999;
+    .doneBg {
+        width: 520px;
+    }
+    .doneBtn {
+        width: 113px;
+        margin-top: -50px;
+        cursor: pointer;
+    }
 }

+ 45 - 7
src/page-instrument/custom-plugins/work-home/index.tsx

@@ -2,7 +2,9 @@ import { defineComponent, onMounted, reactive, watch } from "vue";
 import styles from "./index.module.less";
 // import { verifyMembershipServices } from "../vip-verify";
 import { api_lessonTrainingSubmitTraining, api_lessonTrainingTrainingStudentDetail } from "../../api";
-import state, { handleSetSpeed, hanldeDirectSelection, setSection } from "/src/state";
+import state, { handleSetSpeed, hanldeDirectSelection, setSection, togglePlay } from "/src/state";
+import { getSecondRPM } from "/src/utils";
+import { headImg } from "/src/page-instrument/header-top/image";
 
 export default defineComponent({
 	name: "HomeWork",
@@ -15,14 +17,17 @@ export default defineComponent({
 	emits: ["change"],
 	setup(props, {expose}) {
 		const training = reactive({
-			trainingTimes: "",
-			trainingSpeed: 0,
-			times: 0,
+			trainingTimes: "", // 已经练习的时长,单位分钟
+			trainingSpeed: 0, // 作业规定的速度
+			times: 0, // 作业规定的练习时长,单位分钟
+			trainingTimeSecond: 0, // 实时更新的练习时长,单位秒
 			workRecord: "",
 			isAddOk: 0,
 			starTime: 0,
 			start: "" as any,
 			end: "" as any,
+			timer: null as any, // 定时器
+			showWorkDonePop: false, // 显示需要提交作业弹窗
 		});
 
 		/** 隐藏评测功能 */
@@ -48,6 +53,7 @@ export default defineComponent({
 				}
 				training.times = trainingContent.trainingTimes || 0;
 				training.trainingTimes = (workeData.trainingTimes / 60).toFixed(1) || "0";
+				training.trainingTimeSecond = workeData.trainingTimes || 0;
 				training.trainingSpeed = trainingContent.practiceSpeed;
 				training.start = Number(trainingContent.practiceChapterBegin);
 				training.end = Number(trainingContent.practiceChapterEnd);
@@ -64,6 +70,7 @@ export default defineComponent({
 			const res = await api_lessonTrainingTrainingStudentDetail(props.workeData.id);
 			if (res?.code === 200) {
 				training.trainingTimes = (res.data.trainingTimes / 60).toFixed(1) || "0";
+				training.trainingTimeSecond = res.data.trainingTimes || 0;
 				state.isWorkDone = Number(training.trainingTimes) >= Number(training.times);
 			}
 		};
@@ -82,13 +89,31 @@ export default defineComponent({
 			} catch (error) {}
 		};
 
+		const handleStart = () => {
+			training.timer = setInterval(() => {
+				training.trainingTimeSecond += 1;
+				// 如果播放中,作业从未达标到达标状态,需要暂停播放,并且弹窗提示作业已达标
+				if (!state.isWorkDone && training.trainingTimeSecond >= training.times * 60) {
+					togglePlay("paused")
+					state.isWorkDone = true
+					training.showWorkDonePop = true
+				}
+				console.log('练习时长',training.trainingTimeSecond)
+			}, 1000);
+		};
+        const handleStop = () => {
+            clearInterval(training.timer)
+        }
+
 		watch(
 			() => state.playState,
 			() => {
 				if (state.playState === "play") {
 					training.starTime = Date.now();
+					handleStart();
 				} else {
 					addHomeworkRecored();
+					handleStop();
 				}
 			}
 		);
@@ -108,9 +133,22 @@ export default defineComponent({
 			getWorkData
 		})
 		return () => (
-			<div class={styles.homework}>
-				{training.trainingTimes} / {training.times} 分钟
-			</div>
+			<>
+				<div class={styles.homework}>
+					<i class={state.playState === "play" ? styles.blinkDot : styles.grayDot}></i>
+					<span>{getSecondRPM(training.trainingTimeSecond)} / {getSecondRPM(training.times*60)}</span>
+				</div>
+				{
+					training.showWorkDonePop && 
+					<div class={styles.workDonePop}>
+						<img class={styles.doneBg} src={headImg("workDonePop.png")} />
+						<img class={styles.doneBtn} src={headImg("workDoneBtn.png")} onClick={() => {
+							training.showWorkDonePop = false
+                			addHomeworkRecored();
+              			}} />
+					</div>
+				}
+			</>
 		);
 	},
 });

BIN
src/page-instrument/header-top/image/workDoneBtn.png


BIN
src/page-instrument/header-top/image/workDonePop.png


BIN
src/page-instrument/header-top/image/workNoBack.png


BIN
src/page-instrument/header-top/image/workNoContinue.png


BIN
src/page-instrument/header-top/image/workNoDoneBg.png


+ 29 - 0
src/page-instrument/header-top/workHomePop/index.module.less

@@ -51,3 +51,32 @@
         }
     }
 }
+
+.microBox {
+    position: relative;
+    width: 100vw;
+    height: 100vh;
+    .microBg {
+        position: absolute;
+        left: 50%;
+        top: 20%;
+        height: 60%;
+        transform: translateX(-50%);
+    }
+    .microBtn {
+        position: absolute;
+        bottom: 23.5%;
+        left: 50%;
+        transform: translate(-45%);
+    }
+    .microCancel {
+        width: 11.2vw;
+        height: 100%;
+        margin-right: 2px;
+    }
+    .microConfirm {
+        width: 11.2vw;
+        height: 100%;
+        margin-left: 2px;
+    }
+}

+ 16 - 9
src/page-instrument/header-top/workHomePop/index.tsx

@@ -14,15 +14,22 @@ export default defineComponent({
 	emits: ["close"],
 	setup(props, { emit }) {
 		return () => (
-			<div class={styles.popBox}>
-				<img class={styles.boxBg} src={headImg("workHome_bg.png")} />
-				<img class={styles.boxTitle} src={headImg("workHome_icon1.png")} />
-				<div class={styles.boxContent}>
-					<p>本条练习还没达到老师的练习要求,是否继续练习?</p>
-					<div class={styles.boxBtn}>
-						<img class={styles.boxClose} src={headImg("workHome_icon3.png")} onClick={() => emit("close")} />
-						<img class={styles.boxConfirm} src={headImg("workHome_icon2.png")} onClick={() => emit("close", true)} />
-					</div>
+			// <div class={styles.popBox}>
+			// 	<img class={styles.boxBg} src={headImg("workHome_bg.png")} />
+			// 	<img class={styles.boxTitle} src={headImg("workHome_icon1.png")} />
+			// 	<div class={styles.boxContent}>
+			// 		<p>本条练习还没达到老师的练习要求,是否继续练习?</p>
+			// 		<div class={styles.boxBtn}>
+			// 			<img class={styles.boxClose} src={headImg("workHome_icon3.png")} onClick={() => emit("close")} />
+			// 			<img class={styles.boxConfirm} src={headImg("workHome_icon2.png")} onClick={() => emit("close", true)} />
+			// 		</div>
+			// 	</div>
+			// </div>
+			<div class={styles.microBox}>
+				<img class={styles.microBg} src={headImg("workNoDoneBg.png")} />
+				<div class={styles.microBtn}>
+					<img class={styles.microCancel} src={headImg("workNoBack.png")} onClick={() => emit("close")} />
+					<img class={styles.microConfirm} src={headImg("workNoContinue.png")} onClick={() => emit("close", true)} />
 				</div>
 			</div>
 		);

+ 9 - 8
src/page-instrument/view-detail/index.tsx

@@ -127,14 +127,15 @@ export default defineComponent({
         Object.assign(state.setting, settting);
         //state.setting.beatVolume = state.setting.beatVolume || 50
         state.setting.beatVolume = 50;
-        if (state.setting.camera) {
-          const res = await api_openCamera();
-          // 没有授权
-          if (res?.content?.reson) {
-            state.setting.camera = false;
-            store.set("musicscoresetting", state.setting);
-          }
-        }
+        // 默认进来不需要开启摄像头,进入评测页面才需要判断是否开启摄像头
+        // if (state.setting.camera) {
+        //   const res = await api_openCamera();
+        //   // 没有授权
+        //   if (res?.content?.reson) {
+        //     state.setting.camera = false;
+        //     store.set("musicscoresetting", state.setting);
+        //   }
+        // }
       }
     });
 

+ 14 - 0
src/view/evaluating/index.tsx

@@ -34,6 +34,7 @@ import {
   api_cloudChangeSpeed,
   api_startDelayCheck,
   api_closeDelayCheck,
+  api_openCamera,
 } from "/src/helpers/communication";
 import state, { IPlayState, clearSelection, handleStopPlay, onPlay, resetPlaybackToStart, togglePlay, initSetPlayRate, resetBaseRate, scrollViewNote } from "/src/state";
 import { IPostMessage } from "/src/utils/native-message";
@@ -760,6 +761,18 @@ export default defineComponent({
       }
     };
 
+    // 打开摄像头
+    const openSetCamera = async () => {
+      if (state.setting.camera) {
+        const res = await api_openCamera();
+        // 没有授权
+        if (res?.content?.reson) {
+          state.setting.camera = false;
+          store.set("musicscoresetting", state.setting);
+        }
+      }
+    }
+
     watch(pageVisibility, (value) => {
       if (value == "hidden" && evaluatingData.startBegin) {
         // handleEndBegin();
@@ -786,6 +799,7 @@ export default defineComponent({
       }
     );
     onMounted(() => {
+      openSetCamera();
       resetPlaybackToStart();
       hanlde_record();
       evaluatingData.resultData = {};