Browse Source

feat: 添加延迟检测

TIANYONG 1 year ago
parent
commit
f1186c1617
63 changed files with 1375 additions and 162 deletions
  1. 1 1
      src/helpers/native-message.ts
  2. 0 0
      src/pages/detail/CheckDelayPopup/image/bg.json
  3. BIN
      src/pages/detail/CheckDelayPopup/image/delay_btn_icon1.png
  4. BIN
      src/pages/detail/CheckDelayPopup/image/delay_btn_icon2.png
  5. BIN
      src/pages/detail/CheckDelayPopup/image/icon1.png
  6. BIN
      src/pages/detail/CheckDelayPopup/image/icon10.png
  7. BIN
      src/pages/detail/CheckDelayPopup/image/icon11.png
  8. BIN
      src/pages/detail/CheckDelayPopup/image/icon12.png
  9. BIN
      src/pages/detail/CheckDelayPopup/image/icon2.png
  10. BIN
      src/pages/detail/CheckDelayPopup/image/icon3.png
  11. BIN
      src/pages/detail/CheckDelayPopup/image/icon4.png
  12. BIN
      src/pages/detail/CheckDelayPopup/image/icon5.png
  13. BIN
      src/pages/detail/CheckDelayPopup/image/icon6.png
  14. BIN
      src/pages/detail/CheckDelayPopup/image/icon7.png
  15. BIN
      src/pages/detail/CheckDelayPopup/image/icon8.png
  16. BIN
      src/pages/detail/CheckDelayPopup/image/icon9.png
  17. BIN
      src/pages/detail/CheckDelayPopup/image/icon_backBtn.png
  18. BIN
      src/pages/detail/CheckDelayPopup/image/icon_bg.png
  19. BIN
      src/pages/detail/CheckDelayPopup/image/icon_content.png
  20. BIN
      src/pages/detail/CheckDelayPopup/image/icon_content1.png
  21. BIN
      src/pages/detail/CheckDelayPopup/image/icon_dianchi.png
  22. BIN
      src/pages/detail/CheckDelayPopup/image/icon_dianzhiActive.png
  23. BIN
      src/pages/detail/CheckDelayPopup/image/icon_duihua.png
  24. BIN
      src/pages/detail/CheckDelayPopup/image/icon_duihua1.png
  25. BIN
      src/pages/detail/CheckDelayPopup/image/icon_duihua2.png
  26. BIN
      src/pages/detail/CheckDelayPopup/image/icon_duihua3.png
  27. BIN
      src/pages/detail/CheckDelayPopup/image/icon_startBtn.png
  28. 6 0
      src/pages/detail/CheckDelayPopup/image/index.ts
  29. 0 0
      src/pages/detail/CheckDelayPopup/image/left_ adorn.json
  30. 0 0
      src/pages/detail/CheckDelayPopup/image/right_ adorn.json
  31. 0 0
      src/pages/detail/CheckDelayPopup/image/step1_icon.json
  32. 0 0
      src/pages/detail/CheckDelayPopup/image/step2_icon.json
  33. 0 0
      src/pages/detail/CheckDelayPopup/image/step3_icon.json
  34. 0 0
      src/pages/detail/CheckDelayPopup/image/step4_icon.json
  35. 0 0
      src/pages/detail/CheckDelayPopup/image/step5_icon.json
  36. BIN
      src/pages/detail/CheckDelayPopup/image/step_state_icon1.png
  37. BIN
      src/pages/detail/CheckDelayPopup/image/step_state_icon2.png
  38. BIN
      src/pages/detail/CheckDelayPopup/image/step_state_icon3.png
  39. BIN
      src/pages/detail/CheckDelayPopup/image/step_tips_icon1.png
  40. BIN
      src/pages/detail/CheckDelayPopup/image/step_tips_icon2.png
  41. BIN
      src/pages/detail/CheckDelayPopup/image/step_tips_icon3.png
  42. BIN
      src/pages/detail/CheckDelayPopup/image/step_tips_icon4.png
  43. BIN
      src/pages/detail/CheckDelayPopup/image/step_tips_icon5.png
  44. BIN
      src/pages/detail/CheckDelayPopup/image/step_top_icon.png
  45. 394 0
      src/pages/detail/CheckDelayPopup/index.module.less
  46. 150 0
      src/pages/detail/CheckDelayPopup/index.tsx
  47. BIN
      src/pages/detail/Headphone/image/icon_btn.png
  48. BIN
      src/pages/detail/Headphone/image/icon_top.png
  49. 50 0
      src/pages/detail/Headphone/index.module.less
  50. 32 0
      src/pages/detail/Headphone/index.tsx
  51. 0 0
      src/pages/detail/PhoneTip/data.json
  52. BIN
      src/pages/detail/PhoneTip/icon_tip.png
  53. 23 0
      src/pages/detail/PhoneTip/index.module.less
  54. 23 0
      src/pages/detail/PhoneTip/index.tsx
  55. 455 152
      src/pages/detail/evaluating/index.tsx
  56. 3 1
      src/pages/detail/runtime.ts
  57. 1 1
      src/pages/detail/setting-popup/set.tsx
  58. 1 1
      src/pages/detail/setting-state.ts
  59. 0 0
      src/subpages/colexiu/buttons/data/start_new.json
  60. 0 0
      src/subpages/colexiu/buttons/data/starting_new.json
  61. 228 4
      src/subpages/colexiu/buttons/evaluating.tsx
  62. 7 1
      src/subpages/colexiu/index.tsx
  63. 1 1
      src/subpages/colexiu/popups/setting/evaluat.tsx

+ 1 - 1
src/helpers/native-message.ts

@@ -65,7 +65,7 @@ const browserInfo = browser()
 
 if (browserInfo.isApp) {
   window.addEventListener('message', (evt) => {
-    console.log('app回调', evt?.data)
+    // console.log('app回调', evt?.data)
     try {
       const data = evt.data ? (typeof evt.data === 'object' ? evt.data : JSON.parse(evt.data)) : {}
       const uuid = data.content?.uuid || data.uuid

File diff suppressed because it is too large
+ 0 - 0
src/pages/detail/CheckDelayPopup/image/bg.json


BIN
src/pages/detail/CheckDelayPopup/image/delay_btn_icon1.png


BIN
src/pages/detail/CheckDelayPopup/image/delay_btn_icon2.png


BIN
src/pages/detail/CheckDelayPopup/image/icon1.png


BIN
src/pages/detail/CheckDelayPopup/image/icon10.png


BIN
src/pages/detail/CheckDelayPopup/image/icon11.png


BIN
src/pages/detail/CheckDelayPopup/image/icon12.png


BIN
src/pages/detail/CheckDelayPopup/image/icon2.png


BIN
src/pages/detail/CheckDelayPopup/image/icon3.png


BIN
src/pages/detail/CheckDelayPopup/image/icon4.png


BIN
src/pages/detail/CheckDelayPopup/image/icon5.png


BIN
src/pages/detail/CheckDelayPopup/image/icon6.png


BIN
src/pages/detail/CheckDelayPopup/image/icon7.png


BIN
src/pages/detail/CheckDelayPopup/image/icon8.png


BIN
src/pages/detail/CheckDelayPopup/image/icon9.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_backBtn.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_bg.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_content.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_content1.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_dianchi.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_dianzhiActive.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_duihua.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_duihua1.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_duihua2.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_duihua3.png


BIN
src/pages/detail/CheckDelayPopup/image/icon_startBtn.png


+ 6 - 0
src/pages/detail/CheckDelayPopup/image/index.ts

@@ -0,0 +1,6 @@
+//@ts-ignore
+const modules = import.meta.globEager("./*.png");
+export const getDelayImage = (name: string | number) => {
+    const src = modules[`./icon${name}.png`]
+	return src ? src.default : ''
+};

File diff suppressed because it is too large
+ 0 - 0
src/pages/detail/CheckDelayPopup/image/left_ adorn.json


File diff suppressed because it is too large
+ 0 - 0
src/pages/detail/CheckDelayPopup/image/right_ adorn.json


File diff suppressed because it is too large
+ 0 - 0
src/pages/detail/CheckDelayPopup/image/step1_icon.json


File diff suppressed because it is too large
+ 0 - 0
src/pages/detail/CheckDelayPopup/image/step2_icon.json


File diff suppressed because it is too large
+ 0 - 0
src/pages/detail/CheckDelayPopup/image/step3_icon.json


File diff suppressed because it is too large
+ 0 - 0
src/pages/detail/CheckDelayPopup/image/step4_icon.json


File diff suppressed because it is too large
+ 0 - 0
src/pages/detail/CheckDelayPopup/image/step5_icon.json


BIN
src/pages/detail/CheckDelayPopup/image/step_state_icon1.png


BIN
src/pages/detail/CheckDelayPopup/image/step_state_icon2.png


BIN
src/pages/detail/CheckDelayPopup/image/step_state_icon3.png


BIN
src/pages/detail/CheckDelayPopup/image/step_tips_icon1.png


BIN
src/pages/detail/CheckDelayPopup/image/step_tips_icon2.png


BIN
src/pages/detail/CheckDelayPopup/image/step_tips_icon3.png


BIN
src/pages/detail/CheckDelayPopup/image/step_tips_icon4.png


BIN
src/pages/detail/CheckDelayPopup/image/step_tips_icon5.png


BIN
src/pages/detail/CheckDelayPopup/image/step_top_icon.png


+ 394 - 0
src/pages/detail/CheckDelayPopup/index.module.less

@@ -0,0 +1,394 @@
+.delayContainer {
+    position: relative;
+    width: 100vw;
+    height: 100vh;
+    overflow: hidden;
+    // background-image: url('./image/icon_bg.png');
+    background-size: 110% 110%;
+    background-position: center center;
+    background-repeat: no-repeat;
+    // perspective: 500px;
+    .delayBg {
+        width: 100%;
+        height: 100%;
+    }
+    .delayAdorn {
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        transform: translate(-50%,-50%);
+        pointer-events: none;
+        width: 100%;
+    }
+}
+
+.animationContainer {
+    perspective: 500px;
+    pointer-events: none;
+}
+
+.delayBackBtn {
+    position: absolute;
+    left: 20px;
+    top: 20px;
+    display: block;
+    width: 21px;
+    height: 21px;
+}
+
+.delayContent {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    animation: delayContentFrame infinite 10s ease-in-out both;
+    pointer-events: none;
+
+    .iconContent {
+        display: block;
+        width: 237px;
+        height: 167px;
+    }
+
+    .iconDuihua {
+        position: absolute;
+        top: -4px;
+        left: 143px;
+        display: block;
+        transform-origin: left bottom;
+        animation: iconDuihuaScale .5s linear both;
+    }
+    .iconDuihua_delay{
+        animation-delay: .7s;
+    }
+
+    .iconDuihua1 {
+        width: 160px;
+        height: 45px;
+    }
+
+    .iconDuihua2 {
+        width: 141px;
+        height: 39px;
+    }
+
+    .iconDuihua3 {
+        width: 164px;
+        height: 37px;
+    }
+
+    .iconDianchi {
+        display: block;
+        position: absolute;
+        left: 43px;
+        bottom: -21px;
+        width: 150px;
+        height: 44px;
+    }
+
+    .iconDianchiActive {
+        display: block;
+        position: absolute;
+        left: 52px;
+        bottom: -8px;
+        width: 132px;
+        height: 22px;
+        pointer-events: auto;
+    }
+}
+
+
+.delayBody {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%,100%);
+    .delayBox {
+        width: 4.68rem;
+        position: relative;
+        .dbTop {
+            position: absolute;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            .topIcon {
+                width: 2.99rem;
+                height: 0.39rem;
+            }
+            .topDots {
+                position: absolute;
+                left: 0;
+                top: 0;
+                width: 100%;
+                height: 90%;
+                display: flex;
+                align-items: center;
+                justify-content: space-between;
+                padding: 0 0.22rem;
+                img {
+                    width: 0.2rem;
+                    height: 0.2rem;
+                }
+                .aniDot3 {
+                    position: relative;
+                    width: 0.2rem;
+                    height: 0.2rem;
+                    background-image: url('./image/step_state_icon3.png');
+                    background-size: 100% 100%;
+                    background-position: center center;
+                    background-repeat: no-repeat;
+                    animation: aniBg 1.8s step-end infinite;
+                }
+            }
+        }
+        .dbContext {
+            width: 4.68rem;
+            height: 0.95rem;
+        }
+        .dbBtn {
+            position: absolute;
+            right: 0.21rem;
+            bottom: 0.23rem;
+            width: 1.21rem;
+            height: 0.35rem;
+            cursor: pointer;
+            z-index: 999;
+        }
+    }
+}
+@keyframes aniBg {
+    0% {
+        background-image: url('./image/step_state_icon3.png');
+    }
+
+    25% {
+        background-image: url('./image/step_state_icon1.png');
+    }
+
+    50% {
+        background-image: url('./image/step_state_icon3.png');
+    }
+
+    75% {
+        background-image: url('./image/step_state_icon1.png');
+    }
+
+    100% {
+        background-image: url('./image/step_state_icon3.png');
+    }
+}
+
+@keyframes delayContentFrame {
+    0% {
+        top: 47%;
+    }
+
+    50% {
+        top: 53%;
+    }
+
+    100% {
+        top: 47%
+    }
+}
+
+.delayImage {
+    display: block;
+    position: absolute;
+}
+
+.icon1 {
+    left: 119px;
+    top: 12px;
+    width: 59px;
+    height: 49px;
+    animation: icon1 infinite 5s linear;
+}
+
+@keyframes icon1 {
+    0% {
+        transform: translateY(-6px);
+    }
+
+    50% {
+        transform: translateY(6px);
+    }
+
+    100% {
+        transform: translateY(-6px);
+    }
+}
+
+.icon2 {
+    left: 186px;
+    top: 18px;
+    width: 34px;
+    height: 42px;
+    animation: icon3 infinite 1.5s linear;
+}
+
+.icon3 {
+    left: 167px;
+    top: 66px;
+    width: 12px;
+    height: 12px;
+    animation: icon3 infinite 2s linear;
+}
+
+@keyframes icon3 {
+    0% {
+        transform: scale(1.3);
+    }
+
+    50% {
+        transform: scale(1);
+    }
+
+    100% {
+        transform: scale(1.3);
+    }
+}
+
+.icon4 {
+    left: 108px;
+    top: 97px;
+    width: 49px;
+    height: 50px;
+    animation: icon3 infinite 2s 1s linear;
+}
+
+.icon5 {
+    left: -20px;
+    top: 148px;
+    width: 106px;
+    height: 55px;
+}
+
+.icon6 {
+    left: 53px;
+    top: 0px;
+    width: 84px;
+    height: 118px;
+    animation: icon6 2s linear infinite;
+}
+
+@keyframes icon6 {
+    100% {
+        transform: translate(-30vw, 50vh);
+        opacity: .5;
+    }
+}
+
+.icon7 {
+    right: 72px;
+    top: -40px;
+    width: 50px;
+    height: 40px;
+    animation: icon7 12s linear 2s infinite;
+}
+
+@keyframes icon7 {
+    100% {
+        transform: translate(-70vw, 120vh);
+    }
+}
+
+.icon8 {
+    right: -37px;
+    top: 0;
+    width: 37px;
+    height: 31px;
+    animation: icon8 8s linear infinite;
+}
+
+@keyframes icon8 {
+    100% {
+        transform: translate(-70vw, 100vh);
+    }
+}
+
+.icon9 {
+    right: -11px;
+    top: 19px;
+    width: 84px;
+    height: 118px;
+    animation: icon9 2s linear infinite;
+}
+
+@keyframes icon9 {
+    100% {
+        transform: translate(-30vw, 50vh);
+        opacity: .5;
+    }
+}
+
+.icon10 {
+    right: 7px;
+    top: 55px;
+    width: 27px;
+    height: 22px;
+}
+
+.icon11 {
+    right: -30px;
+    top: 136px;
+    width: 102px;
+    height: 106px;
+    transform-style: preserve-3d;
+    animation: icon11 60s linear infinite;
+}
+
+@keyframes icon11 {
+    100% {
+        transform: rotate(360deg);
+    }
+}
+
+.icon12 {
+    left: 0;
+    top: 0;
+    width: 100%;
+}
+
+.heartbeat {
+    animation: heartbeat 1.5s ease-in-out infinite both;
+}
+
+@keyframes heartbeat {
+    from {
+        transform: scale(1);
+        transform-origin: center center;
+        animation-timing-function: ease-out;
+    }
+
+    10% {
+        -webkit-transform: scale(0.91);
+        transform: scale(0.91);
+        animation-timing-function: ease-in;
+    }
+
+    17% {
+        transform: scale(0.98);
+        animation-timing-function: ease-out;
+    }
+
+    33% {
+        transform: scale(0.87);
+        animation-timing-function: ease-in;
+    }
+
+    45% {
+        transform: scale(1);
+        animation-timing-function: ease-out;
+    }
+}
+@keyframes iconDuihuaScale {
+    0% {
+        transform: scale(.5);
+        opacity: 0;
+    }
+
+    100% {
+        transform: scale(1);
+        opacity: 1;
+    }
+}

+ 150 - 0
src/pages/detail/CheckDelayPopup/index.tsx

@@ -0,0 +1,150 @@
+import { PropType, defineComponent, onMounted, watch } from "vue";
+import { Vue3Lottie } from 'vue3-lottie'
+import styles from "./index.module.less";
+import icon_backBtn from "./image/icon_backBtn.png";
+import icon_content from "./image/icon_content.png";
+import icon_content1 from "./image/icon_content1.png";
+import icon_duihua1 from "./image/icon_duihua1.png";
+import icon_duihua2 from "./image/icon_duihua2.png";
+import icon_duihua3 from "./image/icon_duihua3.png";
+import icon_dianchi from "./image/icon_dianchi.png";
+import icon_dianchiActive from "./image/icon_dianzhiActive.png";
+import icon_startBtn from "./image/icon_startBtn.png";
+import { getDelayImage } from "./image";
+import delay_bg from "./image/bg.json"
+import left_adorn from "./image/left_ adorn.json"
+import right_adorn from "./image/right_ adorn.json"
+import step1 from "./image/step1_icon.json"
+import step2 from "./image/step2_icon.json"
+import step3 from "./image/step3_icon.json"
+import step4 from "./image/step4_icon.json"
+import step5 from "./image/step5_icon.json"
+import step_tips_1 from "./image/step_tips_icon1.png"
+import step_tips_2 from "./image/step_tips_icon2.png"
+import step_tips_3 from "./image/step_tips_icon3.png"
+import step_tips_4 from "./image/step_tips_icon4.png"
+import step_tips_5 from "./image/step_tips_icon5.png"
+import step_top_icon from "./image/step_top_icon.png"
+import step_btn_1 from "./image/delay_btn_icon1.png"
+import step_btn_2 from "./image/delay_btn_icon2.png"
+import setp_dot_1 from './image/step_state_icon1.png'
+import setp_dot_2 from './image/step_state_icon2.png'
+import setp_dot_3 from './image/step_state_icon3.png'
+
+interface IDelayData {
+	/** 延迟时间 */
+	time: number;
+	/** 检测次数 */
+	count: number;
+	/** 耳机状态 */
+	erji: boolean;
+	checkStatus: "init" | "ing" | "error";
+	step: number;
+}
+
+/** 延迟检测组件 */
+export default defineComponent({
+	name: "CheckDelayPopup",
+	emits: ["close", "startCheckDelay", "load"],
+	props: {
+		delayData: {
+			type: Object as PropType<IDelayData>,
+			default: () => ({ time: 0, count: 0 }),
+		},
+	},
+	setup(props, { emit }) {
+		const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+		return () => (
+			<div class={styles.delayContainer}>
+				<Vue3Lottie class={styles.delayBg} animationData={delay_bg}></Vue3Lottie>
+				<Vue3Lottie class={styles.delayAdorn} animationData={left_adorn}></Vue3Lottie>
+				<Vue3Lottie class={styles.delayAdorn} animationData={right_adorn}></Vue3Lottie>
+				{/* <div class={styles.animationContainer}>
+					{list.map((item) => {
+						return <img class={[styles.delayImage, styles[`icon${item}`]]} src={getDelayImage(item)} />;
+					})}
+				</div> */}
+				{/*返回按钮*/}
+				{/* <img class={styles.delayBackBtn} src={icon_backBtn} onClick={() => emit("close")} /> */}
+
+				{/* <div class={styles.delayContent}>
+					{props.delayData.checkStatus !== "error" ? (
+						<img class={styles.iconContent} src={icon_content} />
+					) : (
+						<img class={styles.iconContent} src={icon_content1} />
+					)}
+
+					<img style={{ display: props.delayData.checkStatus === "init" ? '' : 'none' }} class={[styles.iconDuihua, styles.iconDuihua1, styles.iconDuihua_delay]} src={icon_duihua1} />
+					<img style={{ display: props.delayData.checkStatus === "ing" ? '' : 'none' }} class={[styles.iconDuihua, styles.iconDuihua2]} src={icon_duihua2} />
+					<img style={{ display: props.delayData.checkStatus === "error" ? '' : 'none' }} class={[styles.iconDuihua, styles.iconDuihua3]} src={icon_duihua3} />
+					<img class={styles.iconDianchi} src={icon_dianchi} />
+					<img
+						style={{ clipPath: `inset(0 ${((2 - props.delayData.count) / 2) * 100}% 0 0 round 4px)` }}
+						class={styles.iconDianchiActive}
+						src={icon_dianchiActive}
+					/>
+					<img style={{ display: props.delayData.checkStatus === "ing" ? 'none' : '' }} class={[styles.iconDianchiActive, styles['heartbeat']]} src={icon_startBtn} onClick={() => emit("startCheckDelay")} />
+				</div>
+				<div class={styles.delayBtns}></div> */}
+
+				<Vue3Lottie class={styles.delayAdorn} animationData={step1} style={{ display: props.delayData.step <= 2 ? '' : 'none' }}></Vue3Lottie>
+				<Vue3Lottie class={styles.delayAdorn} animationData={step2} style={{ display: props.delayData.step === 3 ? '' : 'none' }}></Vue3Lottie>
+				<Vue3Lottie class={styles.delayAdorn} animationData={step3} style={{ display: props.delayData.step === 4 ? '' : 'none' }}></Vue3Lottie>
+				<Vue3Lottie class={styles.delayAdorn} animationData={step4} style={{ display: props.delayData.step === 5 ? '' : 'none' }}></Vue3Lottie>
+				<Vue3Lottie class={styles.delayAdorn} animationData={step5} style={{ display: props.delayData.step >= 6 ? '' : 'none' }}></Vue3Lottie>
+				<div class={styles.delayBody}>
+					<div class={styles.delayBox}>
+						<div class={styles.dbTop}>
+							<img class={styles.topIcon} src={step_top_icon} />
+							{
+								props.delayData.step <= 2 ? 
+								<div class={styles.topDots}>
+									<img src={setp_dot_1} />
+									<img src={setp_dot_1} />
+									<img src={setp_dot_1} />
+									<img src={setp_dot_1} />
+								</div>
+								: props.delayData.step === 3 ? 
+								<div class={styles.topDots}>
+									<span class={styles.aniDot3} ></span>
+									<img src={setp_dot_1} />
+									<img src={setp_dot_1} />
+									<img src={setp_dot_1} />
+								</div>		
+								: props.delayData.step === 4 ? 
+								<div class={styles.topDots}>
+									<img src={setp_dot_2} />
+									<span class={styles.aniDot3} ></span>
+									<img src={setp_dot_1} />
+									<img src={setp_dot_1} />
+								</div>	
+								: props.delayData.step === 5 ? 
+								<div class={styles.topDots}>
+									<img src={setp_dot_2} />
+									<img src={setp_dot_2} />
+									<span class={styles.aniDot3} ></span>
+									<img src={setp_dot_1} />
+								</div>	
+								: 
+								<div class={styles.topDots}>
+									<img src={setp_dot_2} />
+									<img src={setp_dot_2} />
+									<img src={setp_dot_2} />
+									<span class={styles.aniDot3} ></span>
+								</div>																															
+							}
+
+						</div>
+						<img class={styles.dbContext} src={step_tips_1} style={{ display: props.delayData.step <= 2 ? '' : 'none' }} />
+						<img class={styles.dbContext} src={step_tips_2} style={{ display: props.delayData.step === 3 ? '' : 'none' }} />
+						<img class={styles.dbContext} src={step_tips_3} style={{ display: props.delayData.step === 4 ? '' : 'none' }} />
+						<img class={styles.dbContext} src={step_tips_4} style={{ display: props.delayData.step === 5 ? '' : 'none' }} />
+						<img class={styles.dbContext} src={step_tips_5} style={{ display: props.delayData.step >= 6 ? '' : 'none' }} />
+						<img class={styles.dbBtn} src={step_btn_1} style={{ display: props.delayData.step <= 2 ? '' : 'none' }} onClick={() => emit("startCheckDelay")} />
+						<img class={styles.dbBtn} src={step_btn_2} style={{ display: props.delayData.step >= 6 ? '' : 'none' }} onClick={() => {emit("close")}} />
+					</div>
+				</div>
+			</div>
+		);
+	},
+});

BIN
src/pages/detail/Headphone/image/icon_btn.png


BIN
src/pages/detail/Headphone/image/icon_top.png


+ 50 - 0
src/pages/detail/Headphone/index.module.less

@@ -0,0 +1,50 @@
+.popup {
+    background: transparent;
+}
+
+.container {
+    width: 172px;
+}
+
+.avatar {
+    display: block;
+    width: 100%;
+    height: 78px;
+    position: relative;
+    z-index: 1;
+}
+
+.content {
+    position: relative;
+    top: -7px;
+    width: 100%;
+    height: 96px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-evenly;
+    align-items: center;
+    background: #fff;
+    border-radius: 0 0 13px 13px;
+
+    .title {
+        font-size: 12px;
+        font-weight: 500;
+        color: #044962;
+        line-height: 17px;
+    }
+
+    .des {
+        font-size: 9px;
+        font-weight: 400;
+        color: #777777;
+        line-height: 13px;
+    }
+
+    .btn {
+        width: 91px;
+        height: 25px;
+        &:active {
+            opacity: .8;
+        }
+    }
+}

+ 32 - 0
src/pages/detail/Headphone/index.tsx

@@ -0,0 +1,32 @@
+import { Popup } from "vant";
+import { defineComponent, reactive } from "vue";
+import icon_btn from "./image/icon_btn.png";
+import icon_top from "./image/icon_top.png";
+import styles from "./index.module.less";
+
+/** 耳机提示框 */
+export const HeadphoneData = reactive({
+	open: false,
+	toggle(value = true) {
+		this.open = value;
+	}
+});
+
+export default defineComponent({
+	name: "Headphone",
+	emits: ["close"],
+	setup(props, { expose, emit }) {
+		return () => (
+			<Popup teleport="body" class={["popup-scale", styles.popup]} transition="van-scale" show={HeadphoneData.open} onClose={() => emit("close")}>
+				<div class={styles.container}>
+					<img class={styles.avatar} src={icon_top} />
+					<div class={styles.content}>
+						<div class={styles.title}>请佩戴有线耳机</div>
+						<div class={styles.des}>佩戴有线耳机可以保证评测更准确~</div>
+						<img class={styles.btn} src={icon_btn} onClick={() => HeadphoneData.toggle(false)} />
+					</div>
+				</div>
+			</Popup>
+		);
+	},
+});

File diff suppressed because it is too large
+ 0 - 0
src/pages/detail/PhoneTip/data.json


BIN
src/pages/detail/PhoneTip/icon_tip.png


+ 23 - 0
src/pages/detail/PhoneTip/index.module.less

@@ -0,0 +1,23 @@
+.box{
+    position: fixed;
+    bottom: -5px;
+    right: 15px;
+    width: 95px;
+    height: 80px;
+    pointer-events: none;
+    transition: all 1s;
+    transform-origin: bottom right;
+    transform: scale(0);
+    opacity: 0;
+}
+.iconTip{
+    position: absolute;
+    left: -90%;
+    top: -22%;
+    width: 131px;
+    height: 51px;
+}
+.animate__scale{
+    opacity: 1;
+    transform: scale(1);
+}

+ 23 - 0
src/pages/detail/PhoneTip/index.tsx

@@ -0,0 +1,23 @@
+import { defineComponent, onMounted } from "vue";
+import styles from "./index.module.less";
+import { Vue3Lottie } from "vue3-lottie";
+import data from "./data.json";
+import icon_tip from './icon_tip.png'
+
+export default defineComponent({
+	name: "PhoneTip",
+    props: {
+        show: {
+            type: Boolean,
+            default: false
+        }
+    },
+	setup(props) {
+		return () => (
+			<div id="PhoneTipContent" class={[styles.box, props.show ? styles.animate__scale : '']}>
+                <img class={styles.iconTip} src={icon_tip} />
+				<Vue3Lottie animationData={data} speed={2}></Vue3Lottie>
+			</div>
+		);
+	},
+});

+ 455 - 152
src/pages/detail/evaluating/index.tsx

@@ -22,14 +22,43 @@ import {
   listenerMessage,
   removeListenerMessage,
   IPostMessage,
+  CallBack
 } from '/src/helpers/native-message'
 import SettingState from '/src/pages/detail/setting-state'
 import { getLeveByScore, getLeveByScoreMeasure } from './helper'
 import styles from './index.module.less'
 import { browser, getRequestHostname } from '/src/helpers/utils'
+import CheckDelayPopup from "../CheckDelayPopup";
+import Headphone, { HeadphoneData } from "../Headphone";
+import PhoneTip from "../PhoneTip";
 
 const browserInfo = browser()
 
+/** 初始化评测音频 */
+export const evaluatCreateMusicPlayer = () => {
+	return new Promise((resolve) => {
+		// 初始化曲谱音频 和效音音频
+		postMessage(
+      {
+        api: "createMusicPlayer",
+        content: {
+          musicSrc: runtime.songs.background || runtime.songs.music, // 曲谱音频url
+          tuneSrc: "https://oss.dayaedu.com/cloud-coach/1686725501654check_music1_(1).mp3", //效音音频url
+        },
+      },
+      () => {
+        if (browserInfo.ios) {
+          resolve(true);
+        }
+      }
+    );
+		// 安卓不需要
+		if(!browserInfo.ios){
+			resolve(true)
+		}
+	})
+}
+
 let player: any = null
 
 let backtime = 0
@@ -72,6 +101,24 @@ export const resetPlayer = () => {
   }
 }
 
+/** 监听评测弹窗是否隐藏保存演奏按钮 */
+const hideComplexButton = (callback: CallBack, listen?: boolean) => {
+	if (listen) {
+		listenerMessage("hideComplexButton", callback);
+	} else {
+		removeListenerMessage("hideComplexButton", callback);
+	}
+};
+
+// 隐藏存演奏按钮
+const handleComplexButton = (res?: IPostMessage) => {
+	console.log('监听是否隐藏上传云端按钮', res)
+	if (res?.content) {
+		const { header, body } = res.content;
+		detailState.isHideEvaluatReportSaveBtn = true
+	}
+};
+
 export default defineComponent({
   name: 'evaluating',
   data() {
@@ -97,6 +144,22 @@ export default defineComponent({
       shareLoadedPngData: null as null | string,
       isSaveVideo: SettingState.sett.camera && SettingState.eva.save,
       tuningStatus: false,
+			/** 延迟数据 */
+			delayData: {
+				/** 是否强制检测 */
+				isForce: true,
+				/** 弹窗 */
+				open: false,
+				/** 延迟次数 */
+				count: 0,
+				/** 延迟时间 */
+				time: 0,
+				/** 耳机状态 */
+				erji: false,
+				/** 检测状态 */
+				checkStatus: 'init' as 'init' | 'ing' | 'error',
+        step: 1,
+			},      
     }
   },
   computed: {
@@ -435,7 +498,7 @@ export default defineComponent({
         ) {
           skip = true
         }
-        console.log(note.measureOpenIndex, item.measureOpenIndex, note)
+        // console.log(note.measureOpenIndex, item.measureOpenIndex, note)
         // console.log("skip", skip)
         const data = {
           timeStamp: (start * 1000) / rate,
@@ -461,159 +524,233 @@ export default defineComponent({
         this.cancel(data?.content.reson)
       }
     },
-    sendResult(evt?: IPostMessage) {
-      console.log('sendResult', evt)
-      if (evt?.content) {
-        const data = evt?.content?.body
-        if (evt?.content.header.commond === 'overall') {
-          Toast.clear()
-          this.res = data
-          this.endloading = false
-          RuntimeUtils.event.emit('onEvaluationResult', data)
-        } else if (evt?.content.header.commond === 'checkDone') {
-          this.checkStatus = true
-          // postMessage({
-          //   api: 'endSoundCheck'
-          // })
-        } else if (evt?.content.header.commond === 'checking') {
-          // this.trend = evt?.content?.body?.trend
-          this.frequency = evt?.content?.body?.frequency
-        } else {
-          const getBeforeNote = (index: number) => {
-            while (index >= 0) {
-              const item = state.times[index]
-              if (item.stave) {
-                return item
-              }
-              index--
-            }
-          }
-          const setEvaluatings = (
-            note: any,
-            data: any,
-            dontTransition = false
-          ) => {
-            const startNote = getBoundingBoxByverticalNote(note)
-            state.evaluatings = {
-              ...state.evaluatings,
-              [startNote.measureIndex]: {
-                ...startNote,
-                ...getLeveByScoreMeasure(data.score),
-                score: data.score,
-                dontTransition,
-              },
-            }
-          }
+    // sendResult(evt?: IPostMessage) {
+    //   console.log('sendResult', evt)
+    //   if (evt?.content) {
+    //     const data = evt?.content?.body
+    //     if (evt?.content.header.commond === 'overall') {
+    //       Toast.clear()
+    //       this.res = data
+    //       this.endloading = false
+    //       RuntimeUtils.event.emit('onEvaluationResult', data)
+    //     } else if (evt?.content.header.commond === 'checkDone') {
+    //       this.checkStatus = true
+    //       // postMessage({
+    //       //   api: 'endSoundCheck'
+    //       // })
+    //     } else if (evt?.content.header.commond === 'checking') {
+    //       // this.trend = evt?.content?.body?.trend
+    //       this.frequency = evt?.content?.body?.frequency
+    //     } else {
+    //       const getBeforeNote = (index: number) => {
+    //         while (index >= 0) {
+    //           const item = state.times[index]
+    //           if (item.stave) {
+    //             return item
+    //           }
+    //           index--
+    //         }
+    //       }
+    //       const setEvaluatings = (
+    //         note: any,
+    //         data: any,
+    //         dontTransition = false
+    //       ) => {
+    //         const startNote = getBoundingBoxByverticalNote(note)
+    //         state.evaluatings = {
+    //           ...state.evaluatings,
+    //           [startNote.measureIndex]: {
+    //             ...startNote,
+    //             ...getLeveByScoreMeasure(data.score),
+    //             score: data.score,
+    //             dontTransition,
+    //           },
+    //         }
+    //       }
 
-          for (let index = 0; index < state.times.length; index++) {
-            let time = state.times[index]
-            if (
-              data.measureRenderIndex ==
-              time.noteElement.sourceMeasure.measureListIndex
-            ) {
-              if (!time.stave) {
-                const ntime = getBeforeNote(index)
-                // console.log('ntime', ntime)
-                if (ntime) {
-                  time = ntime
-                }
-              }
-              // if (state.evaluatings[data.measureRenderIndex]) {
-              //   // 重复问题,老数据移除
-              //   state.evaluatings = {
-              //     ...state.evaluatings,
-              //     [data.measureRenderIndex]: undefined
-              //   }
-              // }
-              // console.log('sendResult', data, time, time.noteElement.tie)
+    //       for (let index = 0; index < state.times.length; index++) {
+    //         let time = state.times[index]
+    //         if (
+    //           data.measureRenderIndex ==
+    //           time.noteElement.sourceMeasure.measureListIndex
+    //         ) {
+    //           if (!time.stave) {
+    //             const ntime = getBeforeNote(index)
+    //             // console.log('ntime', ntime)
+    //             if (ntime) {
+    //               time = ntime
+    //             }
+    //           }
+    //           // if (state.evaluatings[data.measureRenderIndex]) {
+    //           //   // 重复问题,老数据移除
+    //           //   state.evaluatings = {
+    //           //     ...state.evaluatings,
+    //           //     [data.measureRenderIndex]: undefined
+    //           //   }
+    //           // }
+    //           // console.log('sendResult', data, time, time.noteElement.tie)
 
-              // const startNote = getBoundingBoxByverticalNote(time)
-              // const endNote = getBoundingBoxByverticalNote(getNoteByMeasuresSlursStart(time))//getParentNote
+    //           // const startNote = getBoundingBoxByverticalNote(time)
+    //           // const endNote = getBoundingBoxByverticalNote(getNoteByMeasuresSlursStart(time))//getParentNote
 
-              // if (!time.noteElement.tie) continue
-              // for (const item of time.noteElement.tie.notes) {
-              //   const note = getParentNote(item)
-              //   if (!note) continue
-              //   const startNote = getBoundingBoxByverticalNote(note)
-              //   state.evaluatings = {
-              //     ...state.evaluatings,
-              //     [startNote.measureIndex]: {
-              //       ...startNote,
-              //       ...getLeveByScoreMeasure(data.score),
-              //       score: data.score,
-              //       dontTransition: item !== time.noteElement.tie.StartNote,
-              //     },
-              //   }
-              // }
+    //           // if (!time.noteElement.tie) continue
+    //           // for (const item of time.noteElement.tie.notes) {
+    //           //   const note = getParentNote(item)
+    //           //   if (!note) continue
+    //           //   const startNote = getBoundingBoxByverticalNote(note)
+    //           //   state.evaluatings = {
+    //           //     ...state.evaluatings,
+    //           //     [startNote.measureIndex]: {
+    //           //       ...startNote,
+    //           //       ...getLeveByScoreMeasure(data.score),
+    //           //       score: data.score,
+    //           //       dontTransition: item !== time.noteElement.tie.StartNote,
+    //           //     },
+    //           //   }
+    //           // }
 
-              if (!time.noteElement.tie) {
-                setEvaluatings(time, data)
-              } else {
-                for (const item of time.noteElement.tie.notes) {
-                  const note = getParentNote(item)
-                  if (!note) continue
-                  setEvaluatings(
-                    note,
-                    data,
-                    item !== time.noteElement.tie.StartNote
-                  )
-                  // const startNote = getBoundingBoxByverticalNote(note)
-                  // state.evaluatings = {
-                  //   ...state.evaluatings,
-                  //   [startNote.measureIndex]: {
-                  //     ...startNote,
-                  //     ...getLeveByScoreMeasure(data.score),
-                  //     score: data.score,
-                  //     dontTransition: item !== time.noteElement.tie.StartNote,
-                  //   },
-                  // }
-                }
-              }
+    //           if (!time.noteElement.tie) {
+    //             setEvaluatings(time, data)
+    //           } else {
+    //             for (const item of time.noteElement.tie.notes) {
+    //               const note = getParentNote(item)
+    //               if (!note) continue
+    //               setEvaluatings(
+    //                 note,
+    //                 data,
+    //                 item !== time.noteElement.tie.StartNote
+    //               )
+    //               // const startNote = getBoundingBoxByverticalNote(note)
+    //               // state.evaluatings = {
+    //               //   ...state.evaluatings,
+    //               //   [startNote.measureIndex]: {
+    //               //     ...startNote,
+    //               //     ...getLeveByScoreMeasure(data.score),
+    //               //     score: data.score,
+    //               //     dontTransition: item !== time.noteElement.tie.StartNote,
+    //               //   },
+    //               // }
+    //             }
+    //           }
 
-              // if (startNote.measureIndex !== endNote.measureIndex) {
-              //   state.evaluatings = {
-              //     ...state.evaluatings,
-              //     [endNote.measureIndex]: {
-              //       ...endNote,
-              //       ...getLeveByScoreMeasure(data.score),
-              //       score: data.score,
-              //       dontTransition: true
-              //     },
-              //   }
-              // }
-              break
-            }
-          }
-          // for (const time of state.times) {
-          //   if (data.measureRenderIndex == time.noteElement.sourceMeasure.measureListIndex) {
-          //     if (state.evaluatings[data.measureRenderIndex]) return
-          //     const startNote = getBoundingBoxByverticalNote(time)
-          //     const endNote = getBoundingBoxByverticalNote(getNoteBySlursStart(time, true, 'end'))
-          //     state.evaluatings = {
-          //       ...state.evaluatings,
-          //       [startNote.measureIndex]: {
-          //         ...startNote,
-          //         ...getLeveByScoreMeasure(data.score),
-          //         score: data.score,
-          //       },
-          //     }
-          //     if (startNote.measureIndex !== endNote.measureIndex) {
-          //       state.evaluatings = {
-          //         ...state.evaluatings,
-          //         [endNote.measureIndex]: {
-          //           ...endNote,
-          //           ...getLeveByScoreMeasure(data.score),
-          //           score: data.score,
-          //           dontTransition: true
-          //         },
-          //       }
-          //     }
-          //     break
-          //   }
-          // }
-        }
-      }
-    },
+    //           // if (startNote.measureIndex !== endNote.measureIndex) {
+    //           //   state.evaluatings = {
+    //           //     ...state.evaluatings,
+    //           //     [endNote.measureIndex]: {
+    //           //       ...endNote,
+    //           //       ...getLeveByScoreMeasure(data.score),
+    //           //       score: data.score,
+    //           //       dontTransition: true
+    //           //     },
+    //           //   }
+    //           // }
+    //           break
+    //         }
+    //       }
+    //       // for (const time of state.times) {
+    //       //   if (data.measureRenderIndex == time.noteElement.sourceMeasure.measureListIndex) {
+    //       //     if (state.evaluatings[data.measureRenderIndex]) return
+    //       //     const startNote = getBoundingBoxByverticalNote(time)
+    //       //     const endNote = getBoundingBoxByverticalNote(getNoteBySlursStart(time, true, 'end'))
+    //       //     state.evaluatings = {
+    //       //       ...state.evaluatings,
+    //       //       [startNote.measureIndex]: {
+    //       //         ...startNote,
+    //       //         ...getLeveByScoreMeasure(data.score),
+    //       //         score: data.score,
+    //       //       },
+    //       //     }
+    //       //     if (startNote.measureIndex !== endNote.measureIndex) {
+    //       //       state.evaluatings = {
+    //       //         ...state.evaluatings,
+    //       //         [endNote.measureIndex]: {
+    //       //           ...endNote,
+    //       //           ...getLeveByScoreMeasure(data.score),
+    //       //           score: data.score,
+    //       //           dontTransition: true
+    //       //         },
+    //       //       }
+    //       //     }
+    //       //     break
+    //       //   }
+    //       // }
+    //     }
+    //   }
+    // },
+
+		sendResult(evt?: IPostMessage) {
+			console.log("sendResult", evt);
+			if (evt?.content) {
+				const data = evt?.content?.body;
+				if (evt?.content.header.commond === "overall") {
+					detailState.isHideEvaluatReportSaveBtn = false;
+					Toast.clear();
+					this.res = data;
+					this.endloading = false;
+					RuntimeUtils.event.emit("onEvaluationResult", data);
+				} else if (evt?.content.header.commond === "checkDone") {
+					this.checkStatus = true;
+				} else if (evt?.content.header.commond === "checking") {
+					this.frequency = evt?.content?.body?.frequency;
+				} else if (evt?.content.header.commond === "recordEnd") {
+					if (this.delayData.checkStatus !== 'ing') return
+					this.delayData.count++;
+					if (this.delayData.count >= 2) {
+						this.handleToggleTune('finishTune');
+						return;
+					}
+					setTimeout(() => {
+						this.startTune()
+					}, 100)
+				} else {
+					const getBeforeNote = (index: number) => {
+						while (index >= 0) {
+							const item = state.times[index];
+							if (item.stave) {
+								return item;
+							}
+							index--;
+						}
+					};
+					const setEvaluatings = (note: any, data: any, dontTransition = false) => {
+						const startNote = getBoundingBoxByverticalNote(note);
+						state.evaluatings = {
+							...state.evaluatings,
+							[startNote.measureIndex]: {
+								...startNote,
+								...getLeveByScoreMeasure(data.score),
+								score: data.score,
+								dontTransition,
+							},
+						};
+					};
+
+					for (let index = 0; index < state.times.length; index++) {
+						let time = state.times[index];
+						if (data.measureRenderIndex == time.noteElement.sourceMeasure.measureListIndex) {
+							if (!time.stave) {
+								const ntime = getBeforeNote(index);
+								// console.log('ntime', ntime)
+								if (ntime) {
+									time = ntime;
+								}
+							}
+
+							if (!time.noteElement.tie) {
+								setEvaluatings(time, data);
+							} else {
+								for (const item of time.noteElement.tie.notes) {
+									const note = getParentNote(item);
+									if (!note) continue;
+									setEvaluatings(note, data, item !== time.noteElement.tie.StartNote);
+								}
+							}
+							break;
+						}
+					}
+				}
+			}
+		},
     setWiredStatus(res?: IPostMessage) {
       this.erjiShow = !res?.content.checkIsWired
       this.tuningStatus = true
@@ -741,10 +878,153 @@ export default defineComponent({
         data.cadence = this.res?.cadence
         data.integrity = this.res?.integrity
       }
-      return `${
-        location.origin
-      }/accompany/share-evaluating/index.html?${qs.stringify(data)}`
+      // return `${location.origin}/accompany/share-evaluating/index.html?${qs.stringify(data)}`
+      return ''
     },
+
+
+		/** 评测效验 */
+		async checkEvaluating() {
+			this.delayData.erji = await this.getWiredStatus();
+			this.delayData.time = await this.getDeviceDelay();
+			// 没有设备延迟数据,显示检测组件,并持续检测耳机状态
+			if (!this.delayData.time || this.delayData.isForce) {
+				this.delayData.open = runtime.delayCheckFirst && this.$route.query.evaluatingRecord ? false : true
+				this.delayData.count = 0;
+				if (runtime.delayCheckFirst && this.$route.query.evaluatingRecord) {
+					this.closeErji()
+				}
+				return;
+			}
+			this.handleCheckDelayEnd()
+		},    
+    /** 获取设备延迟 */
+		getDeviceDelay(): Promise<number> {
+			return new Promise((resolve) => {
+				const timer = setTimeout(() => {
+					resolve(0);
+				}, 1000)
+				postMessage({
+					api: "getDeviceDelay",
+				}, (res) => {
+					const delay = res?.content?.value > 0 ? res?.content?.value : 0;
+					clearTimeout(timer)
+					resolve(delay);
+				});
+			});
+		},
+		/** 获取耳机状态 */
+		getWiredStatus(): Promise<boolean> {
+			return new Promise((resolve) => {
+				const timer = setTimeout(() => {
+					resolve(false);
+				}, 1000)
+				postMessage({
+					api: "isWiredHeadsetOn",
+				}, (res) => {
+					const checkIsWired = res?.content?.checkIsWired ? true : false;
+          if (checkIsWired) {
+            if (this.delayData.step <= 5) {
+              this.delayData.step = 3
+            }
+          } else {
+            if (this.delayData.step === 2 || this.delayData.step === 3) {
+              this.delayData.step = 4
+            }
+          }
+					clearTimeout(timer)
+					resolve(checkIsWired);
+				});
+			});
+		},  
+		/** 持续检测耳机状态 */
+    checkWiredStatus() {
+      console.log('耳机状态',this.delayData.checkStatus)
+			// 设备检测结束,停止获取耳机状态
+			if (this.delayData.checkStatus !== 'ing' || this.delayData.open === false) {
+				return
+			}
+			setTimeout(async () => {
+				this.delayData.erji = await this.getWiredStatus();
+				if (this.delayData.erji) {
+					this.delayData.count = 0;
+					this.delayData.time = 0;
+					this.delayData.checkStatus = 'error'
+				}
+				this.checkWiredStatus();
+			}, 1000)
+		},    
+		/** 开始效音 */
+		startTune() {
+			// 带了耳机,停止播放效音
+			if (this.delayData.erji) return;
+			this.handleToggleTune('start')
+			setTimeout(() => {
+				this.handleToggleTune('stop')
+			}, 1500)
+		},      
+		/** 设备延迟检测结束 */
+		handleCheckDelayEnd() {
+			if (this.delayData.erji) {
+				this.closeErji();
+			} else {
+				this.erjiShow = true;
+				HeadphoneData.toggle();
+			}
+		},
+		/** 切换效音 */
+		handleToggleTune(state: 'start' | 'stop' | 'finishTune'){
+			if (state === 'start') {
+        this.delayData.step = 5
+				// 开始效音
+				postMessage({
+					api: "startTune",
+					content: {
+						count: this.delayData.count + '',
+					}
+				})
+			} else if (state === 'stop') {
+				// 结束效音,触发时机: 1.监听后台效音返回 2.点击跳过效音或关闭效音
+				postMessage({
+					api: "endTune"
+				})
+			} else if (state === 'finishTune') {
+        this.delayData.step = 6
+				// 效音完成
+				postMessage({
+					api: "finishTune",
+				}, (res) => {
+					const result = res?.content?.result //1成功 0失败
+					// Toast('检测延迟完成')
+					// setTimeout(() => {
+					// 	this.delayData.open = false
+					// }, 500)
+				})
+			}
+			
+		},    
+		/** 停止设备延迟检测 */
+		handleStopCheckDelay() {
+			runtime.delayCheckFirst = true
+			this.delayData.open = false
+			this.delayData.checkStatus = 'init'
+			this.handleToggleTune('stop')
+			this.close();
+		},    
+		/** 开始检测设备延迟 */
+		async handleStartCheckDelay(){
+			if (this.delayData.checkStatus === 'ing') return;
+      this.delayData.step = 2
+			this.delayData.erji = await this.getWiredStatus();
+			if (this.delayData.erji) {
+				this.delayData.checkStatus = 'error'
+				return;
+			}
+			this.delayData.checkStatus = 'ing';
+			this.startTune();
+			this.checkWiredStatus();
+		},
+
   },
   mounted() {
     if (!SettingState.eva.mute) {
@@ -783,6 +1063,9 @@ export default defineComponent({
       },
       this.setWiredStatus
     )
+    hideComplexButton(handleComplexButton, true);
+    // 开始效验
+		this.checkEvaluating()
   },
   unmounted() {
     state.mode = this.oldMode
@@ -1053,6 +1336,26 @@ export default defineComponent({
             </div>
           ) : null}
         </Popup>
+
+				{/* 延迟检测窗口 */}
+				<Popup 
+					teleport="body"
+					class="popup-scale" 
+					transition="van-scale" 
+					overlay={false}
+					show={this.delayData.open}
+					onClose={() => this.handleCheckDelayEnd()}
+				>
+					<CheckDelayPopup 
+						delayData={this.delayData}
+						onStartCheckDelay={() => this.handleStartCheckDelay()}
+						onClose={() => this.handleStopCheckDelay()} 
+					/>
+				</Popup>
+
+				{/* <Headphone onClose={this.closeErji} />
+				<PhoneTip show={!this.delayData.erji && runtime.evaluatingTips} /> */}
+
       </div>
     )
   },

+ 3 - 1
src/pages/detail/runtime.ts

@@ -132,7 +132,9 @@ const state = reactive({
   /** 第几分轨 */
   partIndex: 0,
   /** 当前音符index */
-  activeIndex: 0
+  activeIndex: 0,
+  /** 阶段评测,延迟检测是否检测过 */
+  delayCheckFirst: false,  
 })
 
 const syncStepIndex = (i: number) => {

+ 1 - 1
src/pages/detail/setting-popup/set.tsx

@@ -36,7 +36,7 @@ export default defineComponent({
           }}
         />
         <Cell
-          title="校音提醒"
+          title="延迟检测"
           vSlots={{
             extra: () => (
               <Switch

+ 1 - 1
src/pages/detail/setting-state.ts

@@ -11,7 +11,7 @@ export interface SettingState {
 export type iSett = {
   /** 护眼模式 */
   eyeProtection: boolean
-  /** 校音提醒 */
+  /** 延迟检测 */
   tuning: boolean
   /** 摄像头 */
   camera: boolean

File diff suppressed because it is too large
+ 0 - 0
src/subpages/colexiu/buttons/data/start_new.json


File diff suppressed because it is too large
+ 0 - 0
src/subpages/colexiu/buttons/data/starting_new.json


+ 228 - 4
src/subpages/colexiu/buttons/evaluating.tsx

@@ -1,5 +1,5 @@
-import { Button, Toast } from 'vant'
-import { defineComponent, onBeforeUnmount, onMounted, Ref, ref, Teleport, Transition } from 'vue'
+import { Button, Toast, Popup } from 'vant'
+import { defineComponent, onBeforeUnmount, onMounted, Ref, ref, Teleport, Transition, reactive } from 'vue'
 import '@dotlottie/player-component'
 import detailState, { isRhythmicExercises } from '/src/pages/detail/state'
 import SettingState from '/src/pages/detail/setting-state'
@@ -21,10 +21,41 @@ import Evaluating, { evaluatingShow } from '../popups/evaluating'
 // @ts-ignore
 import styles from './index.module.less'
 import { Vue3Lottie } from 'vue3-lottie'
-import startData from './data/start.json'
-import startingData from './data/starting.json'
+import startData from './data/start_new.json'
+import startingData from './data/starting_new.json'
 import { unitTestData } from '../unitTest'
 import iconEvaluatingStart from './icons/icon-evaluatingStart.png'
+import qs from 'query-string'
+import CheckDelayPopup from "/src/pages/detail/CheckDelayPopup";
+import Headphone, { HeadphoneData } from "/src/pages/detail/Headphone";
+
+
+/** 初始化评测音频 */
+export const evaluatCreateMusicPlayer = () => {
+	return new Promise((resolve) => {
+		// 初始化曲谱音频 和效音音频
+		postMessage(
+      {
+        api: "createMusicPlayer",
+        content: {
+          musicSrc: runtime.songs.background || runtime.songs.music, // 曲谱音频url
+          tuneSrc: "https://oss.dayaedu.com/cloud-coach/1686725501654check_music1_(1).mp3", //效音音频url
+        },
+      },
+      () => {
+        if (browserInfo.ios) {
+          resolve(true);
+        }
+      }
+    );
+		// 安卓不需要
+		if(!browserInfo.ios){
+			resolve(true)
+		}
+	})
+}
+
+const searchParams: any = qs.parse(location.search)
 
 /**
  * 节拍器时长
@@ -45,6 +76,171 @@ const endResult = ref(null)
 const browserInfo = browser()
 const scoreList: any[] = []
 
+/** 延迟数据 */
+const delayData =  reactive({
+  /** 是否强制检测 */
+  isForce: true,
+  /** 弹窗 */
+  open: false,
+  /** 延迟次数 */
+  count: 0,
+  /** 延迟时间 */
+  time: 0,
+  /** 耳机状态 */
+  erji: false,
+  /** 检测状态 */
+  checkStatus: 'init' as 'init' | 'ing' | 'error',
+  step: 1,
+})
+  /** 获取耳机状态 */
+  const getWiredStatus = (): Promise<boolean> => {
+    return new Promise((resolve) => {
+      const timer = setTimeout(() => {
+        resolve(false);
+      }, 1000)
+      postMessage({
+        api: "isWiredHeadsetOn",
+      }, (res) => {
+        const checkIsWired = res?.content?.checkIsWired ? true : false;
+        if (checkIsWired) {
+          if (delayData.step <= 5) {
+            delayData.step = 3
+          }
+        } else {
+          if (delayData.step === 2 || delayData.step === 3) {
+            delayData.step = 4
+          }
+        }
+        clearTimeout(timer)
+        resolve(checkIsWired);
+      });
+    });
+  }
+
+  const closeErji = () => {
+    //
+  }
+
+  /** 获取设备延迟 */
+  const getDeviceDelay = (): Promise<number> => {
+    return new Promise((resolve) => {
+      const timer = setTimeout(() => {
+        resolve(0);
+      }, 1000)
+      postMessage({
+        api: "getDeviceDelay",
+      }, (res) => {
+        const delay = res?.content?.value > 0 ? res?.content?.value : 0;
+        clearTimeout(timer)
+        resolve(delay);
+      });
+    });
+  }
+  /** 设备延迟检测结束 */
+  const handleCheckDelayEnd = () => {
+    if (delayData.erji) {
+      closeErji();
+    } else {
+      // this.erjiShow = true;
+      HeadphoneData.toggle();
+    }
+  }
+  /** 评测效验 */
+  const checkEvaluating = async () => {
+    delayData.erji = await getWiredStatus();
+    delayData.time = await getDeviceDelay();
+    // 没有设备延迟数据,显示检测组件,并持续检测耳机状态
+    if (!delayData.time || delayData.isForce) {
+      delayData.open = runtime.delayCheckFirst && searchParams.evaluatingRecord ? false : true
+      delayData.count = 0;
+      if (runtime.delayCheckFirst && searchParams.evaluatingRecord) {
+        // closeErji()
+      }
+      return;
+    }
+    handleCheckDelayEnd()
+  }  
+
+
+		/** 持续检测耳机状态 */
+    const checkWiredStatus = () => {
+      console.log('耳机状态',delayData.checkStatus)
+			// 设备检测结束,停止获取耳机状态
+			if (delayData.checkStatus !== 'ing' || delayData.open === false) {
+				return
+			}
+			setTimeout(async () => {
+				delayData.erji = await getWiredStatus();
+				if (delayData.erji) {
+					delayData.count = 0;
+					delayData.time = 0;
+					delayData.checkStatus = 'error'
+				}
+				checkWiredStatus();
+			}, 1000)
+		}  
+		/** 切换效音 */
+		const handleToggleTune = (state: 'start' | 'stop' | 'finishTune') => {
+			if (state === 'start') {
+        delayData.step = 5
+				// 开始效音
+				postMessage({
+					api: "startTune",
+					content: {
+						count: delayData.count + '',
+					}
+				})
+			} else if (state === 'stop') {
+				// 结束效音,触发时机: 1.监听后台效音返回 2.点击跳过效音或关闭效音
+				postMessage({
+					api: "endTune"
+				})
+			} else if (state === 'finishTune') {
+        delayData.step = 6
+				// 效音完成
+				postMessage({
+					api: "finishTune",
+				}, (res) => {
+					const result = res?.content?.result //1成功 0失败
+					// Toast('检测延迟完成')
+					// setTimeout(() => {
+					// 	delayData.open = false
+					// }, 500)
+				})
+			}
+			
+		}    
+		/** 开始效音 */
+		const startTune = () => {
+			// 带了耳机,停止播放效音
+			if (delayData.erji) return;
+			handleToggleTune('start')
+			setTimeout(() => {
+				handleToggleTune('stop')
+			}, 1500)
+		}     
+		/** 停止设备延迟检测 */
+		const handleStopCheckDelay = () => {
+			runtime.delayCheckFirst = true
+			delayData.open = false
+			delayData.checkStatus = 'init'
+			handleToggleTune('stop')
+			// this.close();
+		} 
+		/** 开始检测设备延迟 */
+		const handleStartCheckDelay = async () => {
+			if (delayData.checkStatus === 'ing') return;
+      delayData.step = 2
+			delayData.erji = await getWiredStatus();
+			if (delayData.erji) {
+				delayData.checkStatus = 'error'
+				return;
+			}
+			delayData.checkStatus = 'ing';
+			startTune();
+			checkWiredStatus();
+		}
+
 // frequency 频率, amplitude 振幅, decibels 分贝
 type TCriteria = "frequency" | "amplitude" | "decibels";
 /** 获取评测标准 */
@@ -496,6 +692,16 @@ const sendResult = (evt?: IPostMessage) => {
       // 此处已经在校音中单独监听不做处理
     } else if (evt?.content.header.commond === 'checking') {
       // 此处已经在校音中单独监听不做处理
+    } else if (evt?.content.header.commond === "recordEnd") {
+      if (delayData.checkStatus !== 'ing') return
+        delayData.count++;
+      if (delayData.count >= 2) {
+        handleToggleTune('finishTune');
+        return;
+      }
+      setTimeout(() => {
+        startTune()
+      }, 100)
     } else {
       const getBeforeNote = (index: number) => {
         while (index >= 0) {
@@ -622,6 +828,8 @@ export default defineComponent({
       RuntimeUtils.event.on('tickDestroy', cloudMetronome)
       RuntimeUtils.event.on('tickEnd', evaluatStart)
       hideComplexButton(handleComplexButton, true);
+      // 开始效验
+		  checkEvaluating()
     })
 
     onBeforeUnmount(() => {
@@ -686,6 +894,22 @@ export default defineComponent({
               <Vue3Lottie class={styles.inRadioIcon} animationData={startingData}></Vue3Lottie>
             </div>
           )}
+
+        {/* 延迟检测窗口 */}
+				<Popup 
+					teleport="body"
+					class="popup-scale" 
+					transition="van-scale" 
+					overlay={false}
+					show={delayData.open}
+					onClose={() => handleCheckDelayEnd()}
+				>
+					<CheckDelayPopup 
+						delayData={delayData}
+						onStartCheckDelay={() => handleStartCheckDelay()}
+						onClose={() => handleStopCheckDelay()} 
+					/>
+				</Popup>
         </Teleport>
       )
     }

+ 7 - 1
src/subpages/colexiu/index.tsx

@@ -49,6 +49,7 @@ import { musicInfo } from './state'
 import ToggleMusicSheet from './plugins/toggleMusicSheet'
 import request from '/src/helpers/request'
 import Metronome, { metronomeData } from '/src/helpers/metronome'
+import Evaluating, { evaluatCreateMusicPlayer } from '/src/pages/detail/evaluating'
 
 // json化曲谱的note信息和svg
 export const musicJSON = reactive({
@@ -300,6 +301,7 @@ export default defineComponent({
           RuntimeUtils.refreshView();``
         }
       })
+      evaluatCreateMusicPlayer()
     }
 
     const onStartRender = async () => {
@@ -439,7 +441,11 @@ export default defineComponent({
             {tipShow.value && !error && <Tips />}
           </div>
           {/* 效音 */}
-          <Transition name="van-slide-up">{soundEffectShow.value && <SoundEffect />}</Transition>
+          {/* <Transition name="van-slide-up">{soundEffectShow.value && <SoundEffect />}</Transition> */}
+
+          {/* {runtime.evaluatingStatus && !detailState.renderLoading ? (
+            <Evaluating />
+          ) : null} */}
 
           {/* 单元测验选段 */}
           {!renderLoading.value && <UnitTest />}

+ 1 - 1
src/subpages/colexiu/popups/setting/evaluat.tsx

@@ -26,7 +26,7 @@ export default defineComponent({
               </RadioGroup>
             </Cell>
             <Divider />
-            <Cell center border={false} title="校音提醒">
+            <Cell center border={false} title="延迟检测">
               <Switch v-model={SettingState.sett.tuning} {...switchProps}>
                 off
               </Switch>

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