lex 7 months ago
parent
commit
0338ed8603

+ 35 - 30
src/hooks/useDrag/dragbom.tsx

@@ -1,16 +1,16 @@
-import { defineComponent, computed, reactive, onMounted } from 'vue';
-import styles from './index.module.less';
+import { defineComponent, computed, reactive, onMounted } from "vue";
+import styles from "./index.module.less";
 // 底部拖动区域
 export default defineComponent({
-  name: 'dragBom',
+  name: "dragBom",
   emits: ["guideDone"],
-	props: {
-		/** 是否显示引导 */
-		showGuide: {
-			type: Boolean,
-			default: false,
-		},
-	},
+  props: {
+    /** 是否显示引导 */
+    showGuide: {
+      type: Boolean,
+      default: false,
+    },
+  },
   setup(props, { emit }) {
     const data = reactive({
       guidePos: "bottom" as "bottom" | "left" | "right",
@@ -19,19 +19,20 @@ export default defineComponent({
     const initGuidePos = () => {
       const pageHeight = document.documentElement.clientHeight || document.body.clientHeight;
       const pageWidth = document.documentElement.clientWidth || document.body.clientWidth;
-      const guideHeight = document.querySelector('.bom_guide')?.clientHeight || 0;
-      const guideWidth = document.querySelector('.bom_guide')?.clientWidth || 0;
-      const dragBBox = document.querySelector('.bom_drag')?.getBoundingClientRect();
+      const guideHeight = document.querySelector(".bom_guide")?.clientHeight || 0;
+      const guideWidth = document.querySelector(".bom_guide")?.clientWidth || 0;
+      const dragBBox = document.querySelector(".bom_drag")?.getBoundingClientRect();
       const dragTop = dragBBox?.top || 0;
+      const dragHeight = dragBBox?.height || 0;
       const dragLeft = dragBBox?.left || 0;
       // 引导页出现在下边
-      if (pageHeight - dragTop > guideHeight) {
-        data.guidePos = "bottom"
+      if (pageHeight - dragTop - dragHeight > guideHeight) {
+        data.guidePos = "bottom";
       } else {
         // 引导页出现在左边or右边
-        data.guidePos = dragLeft > guideWidth ? "left" : "right"
+        data.guidePos = dragLeft > guideHeight ? "left" : "right";
       }
-    }
+    };
     onMounted(() => {
       setTimeout(() => {
         initGuidePos();
@@ -39,21 +40,25 @@ export default defineComponent({
     });
     return () => (
       <>
-      <div class={[styles.dragbomBox,"dragbomBox"]}>
-        <div class={[styles.dragBom, 'bom_drag']}>
-          <div class={styles.box}></div>
-          <div class={[styles.box, styles.right]}></div>
+        <div class={[styles.dragbomBox, "dragbomBox"]}>
+          <div class={[styles.dragBom, "bom_drag"]}>
+            <div class={styles.box}></div>
+            <div class={[styles.box, styles.right]}></div>
+          </div>
         </div>
-      </div>
-        {
-          props.showGuide && 
-          <div class={[styles.guide, data.guidePos === "left" && styles.guideLeft, data.guidePos === "right" && styles.guideRight, 'bom_guide']} onClick={() => emit("guideDone")}>
+        {props.showGuide && (
+          <div class={[styles.guide, data.guidePos === "left" && styles.guideLeft, data.guidePos === "right" && styles.guideRight, "bom_guide"]} onClick={() => emit("guideDone")}>
             <div class={styles.guideBg}></div>
-            <div class={styles.guideDone} onClick={(e) => {e.stopPropagation();emit("guideDone")}}></div>
-          </div>          
-        }
-
+            <div
+              class={styles.guideDone}
+              onClick={(e) => {
+                e.stopPropagation();
+                emit("guideDone");
+              }}
+            ></div>
+          </div>
+        )}
       </>
     );
-  }
+  },
 });

+ 32 - 21
src/hooks/useDrag/index.ts

@@ -55,14 +55,14 @@ export default function useDrag(
     return pos.value.left === -1 && pos.value.top === -1
       ? {}
       : {
-          position: 'fixed',
-          left: `${pos.value.left}px`,
-          top: `${pos.value.top}px`,
-          transform: 'initial',
-          transformOrigin: 'initial',
-          margin: 'initial',
-          transition: 'initial'
-        };
+        position: 'fixed',
+        left: `${pos.value.left}px`,
+        top: `${pos.value.top}px`,
+        transform: 'initial',
+        transformOrigin: 'initial',
+        margin: 'initial',
+        transition: 'initial'
+      };
   });
   function initPos() {
     const posCache = getCachePos(useIdDargClass);
@@ -75,7 +75,7 @@ export default function useDrag(
     }
   }
   function refreshPos() {
-    if(pos.value.left === -1 && pos.value.top === -1){
+    if (pos.value.left === -1 && pos.value.top === -1) {
       return
     }
     const boxClassDom = document.querySelector(`.${boxClass}`) as HTMLElement;
@@ -105,19 +105,22 @@ export default function useDrag(
 
 // 拖动
 function drag(el: HTMLElement, parentElement: HTMLElement, pos: Ref<posType>) {
-  function mousedown(e: MouseEvent) {
+  function onDown(e: MouseEvent | TouchEvent) {
+    const isTouchEv = isTouchEvent(e);
+    const event = isTouchEv ? e.touches[0] : e;
     const parentElementRect = parentElement.getBoundingClientRect();
-    const downX = e.clientX;
-    const downY = e.clientY;
+    const downX = event.clientX;
+    const downY = event.clientY;
     const clientWidth = document.documentElement.clientWidth;
     const clientHeight = document.documentElement.clientHeight;
     const maxLeft = clientWidth - parentElementRect.width;
     const maxTop = clientHeight - parentElementRect.height;
     const minLeft = 0;
     const minTop = 0;
-    function onMousemove(e: MouseEvent) {
-      let moveX = parentElementRect.left + (e.clientX - downX);
-      let moveY = parentElementRect.top + (e.clientY - downY);
+    function onMove(e: MouseEvent | TouchEvent) {
+      const event = isTouchEvent(e) ? e.touches[0] : e;
+      let moveX = parentElementRect.left + (event.clientX - downX);
+      let moveY = parentElementRect.top + (event.clientY - downY);
       moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX;
       moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY;
       pos.value = {
@@ -125,14 +128,22 @@ function drag(el: HTMLElement, parentElement: HTMLElement, pos: Ref<posType>) {
         left: moveX
       };
     }
-    function onMouseup() {
-      document.removeEventListener('mousemove', onMousemove);
-      document.removeEventListener('mouseup', onMouseup);
+    function onUp() {
+      document.removeEventListener(
+        isTouchEv ? 'touchmove' : 'mousemove',
+        onMove
+      );
+      document.removeEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
     }
-    document.addEventListener('mousemove', onMousemove);
-    document.addEventListener('mouseup', onMouseup);
+    document.addEventListener(isTouchEv ? 'touchmove' : 'mousemove', onMove);
+    document.addEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
   }
-  el.addEventListener('mousedown', mousedown);
+  el.addEventListener('mousedown', onDown);
+  el.addEventListener('touchstart', onDown);
+}
+
+function isTouchEvent(e: MouseEvent | TouchEvent): e is TouchEvent {
+  return window.TouchEvent && e instanceof window.TouchEvent;
 }
 
 // 缓存

+ 0 - 1
src/hooks/useDrag/useDragGuidance.ts

@@ -34,7 +34,6 @@ export default function useDragGuidance() {
    }
    return {
       guidanceShow,
-      guideInfoData,
       setGuidanceShow
    }
 }

+ 8 - 0
src/page-instrument/view-figner/change-subject/index.module.less

@@ -1,6 +1,12 @@
 .changeSubject {
   padding: 49px 17px 19px 24px;
 
+
+  &.changeSubjectPc {
+    // .changeSubjectContainer {
+    //   height: 140px;
+    // }
+  }
 }
 
 .changeSubjectContainer {
@@ -51,6 +57,7 @@
     color: #333333;
     border: 1px solid #D8D8D8;
     margin-bottom: 12px;
+    cursor: pointer;
 
     &:nth-child(3n + 2) {
       margin-left: 2.333%;
@@ -106,6 +113,7 @@
   .btn {
     width: 143px;
     height: 44px;
+    cursor: pointer;
 
     &+.btn {
       margin-left: 9px;

+ 12 - 7
src/page-instrument/view-figner/change-subject/index.tsx

@@ -1,6 +1,7 @@
 import { defineComponent, onMounted, reactive, watch } from "vue";
 import styles from "./index.module.less";
 import { Button, showToast } from "vant";
+import { getQuery } from "/src/utils/queryString";
 
 export default defineComponent({
   name: "change-subject",
@@ -16,6 +17,7 @@ export default defineComponent({
   },
   emits: ["close", "confirm"],
   setup(props, { emit }) {
+    const query = getQuery();
     const state = reactive({
       subjectValue: null as any,
       instrumentCode: null as any,
@@ -23,9 +25,12 @@ export default defineComponent({
     });
 
     // subject 变化时候 重新刷新
-    watch(()=>props.subject,()=>{
-      selectItem()
-    })
+    watch(
+      () => props.subject,
+      () => {
+        selectItem();
+      }
+    );
     //
     const selectItem = () => {
       // const i: any = props.subjectList.find((item: any) => item.value === props.subject);
@@ -67,11 +72,11 @@ export default defineComponent({
     };
 
     onMounted(() => {
-      console.log(props.subjectList, "subjectList", props.subject);
+      console.log(props.subjectList, "subjectList", props.subject, query);
       selectItem();
     });
     return () => (
-      <div class={styles.changeSubject}>
+      <div class={[styles.changeSubject, query.platform === "pc" && styles.changeSubjectPc]}>
         {/* <div class={styles.changeSubjectContainer}>
           <div class={styles.title}>乐器</div>
 
@@ -93,7 +98,7 @@ export default defineComponent({
             ))}
           </div>
         </div> */}
-        <div class={[styles.changeSubjectContainer,"changeSubjectContainer_pc"]}>
+        <div class={[styles.changeSubjectContainer, "changeSubjectContainer_pc"]}>
           <div class={styles.title}>声部</div>
 
           <div class={styles.subjectContainer}>
@@ -135,7 +140,7 @@ export default defineComponent({
           )}
         </div>
 
-        <div class={[styles.btnGroups,"btnGroups_pc"]}>
+        <div class={[styles.btnGroups, "btnGroups_pc"]}>
           <div
             class={[styles.btn, styles.resetBtn]}
             onClick={() => {

+ 488 - 0
src/page-instrument/view-figner/fingeringPoint.ts

@@ -0,0 +1,488 @@
+export const FINER_INSTRUMENT_POINT = {
+  "pan-flute": [
+    {
+      key: 5,
+      name: "G",
+      octave: 4,
+      step: -1,
+      realKey: 55,
+      realName: "G4",
+      style: { width: '5.6%' }
+    },
+    {
+      key: 6,
+      name: "A",
+      octave: 4,
+      step: -1,
+      realKey: 57,
+      realName: "A4",
+      style: { width: '5.3%', height: '93.3%' }
+    },
+    {
+      key: 7,
+      name: "B",
+      octave: 4,
+      step: -1,
+      realKey: 59,
+      realName: "B4",
+      style: { width: '5.4%', height: '88%' }
+    },
+    {
+      key: 1,
+      name: "C",
+      octave: 5,
+      step: 0,
+      realKey: 60,
+      realName: "C5",
+      style: { width: '5.3%', height: '82%' }
+    },
+    {
+      key: 2,
+      name: "D",
+      octave: 5,
+      step: 0,
+      realKey: 62,
+      realName: "D5",
+      style: { width: '5.2%', height: '76.6%' }
+    },
+    {
+      key: 3,
+      name: "E",
+      octave: 5,
+      step: 0,
+      realKey: 64,
+      realName: "E5",
+      style: { width: '5%', height: '70.6%' }
+    },
+    {
+      key: 4,
+      name: "F",
+      octave: 5,
+      step: 0,
+      realKey: 65,
+      realName: "F5",
+      style: { width: '5.2%', height: '64%' }
+    },
+    {
+      key: 5,
+      name: "G",
+      octave: 5,
+      step: 0,
+      realKey: 67,
+      realName: "G5",
+      style: { width: '5%', height: '59%' }
+    },
+    {
+      key: 6,
+      name: "A",
+      octave: 5,
+      step: 0,
+      realKey: 69,
+      realName: "A5",
+      style: { width: '4.7%', height: '55%' }
+
+    },
+    {
+      key: 7,
+      name: "B",
+      octave: 5,
+      step: 0,
+      realKey: 71,
+      realName: "B5",
+      style: { width: '4.8%', height: '51%' }
+    },
+    {
+      key: 1,
+      name: "C",
+      octave: 6,
+      step: 1,
+      realKey: 72,
+      realName: "C6",
+      style: { width: '5%', height: '47.6%' }
+    },
+    {
+      key: 2,
+      name: "D",
+      octave: 6,
+      step: 1,
+      realKey: 74,
+      realName: "D6",
+      style: { width: '4.8%', height: '45%' }
+    },
+    {
+      key: 3,
+      name: "E",
+      octave: 6,
+      step: 1,
+      realKey: 76,
+      realName: "E6",
+      style: { width: '4.7%', height: '42.6%' }
+    },
+    {
+      key: 4,
+      name: "F",
+      octave: 6,
+      step: 1,
+      realKey: 77,
+      realName: "F6",
+      style: { width: '4.6%', height: '40.6%' }
+    },
+    {
+      key: 5,
+      name: "G",
+      octave: 6,
+      step: 1,
+      realKey: 79,
+      realName: "G6",
+      style: { width: '4.6%', height: '38%' }
+    },
+    {
+      key: 6,
+      name: "A",
+      octave: 6,
+      step: 1,
+      realKey: 81,
+      realName: "A6",
+      style: { width: '4%', height: '36.6%' }
+    },
+    {
+      key: 7,
+      name: "B",
+      octave: 6,
+      step: 1,
+      realKey: 83,
+      realName: "B6",
+      style: { width: '4.4%', height: '35%' }
+    },
+    {
+      key: 1,
+      name: "C",
+      octave: 7,
+      step: 2,
+      realKey: 84,
+      realName: "C7",
+      style: { width: '4%', height: '33%' }
+    },
+    {
+      key: 2,
+      name: "D",
+      octave: 7,
+      step: 2,
+      realKey: 86,
+      realName: "D7",
+      style: { width: '4%', height: '31%' }
+    },
+    {
+      key: 3,
+      name: "E",
+      octave: 7,
+      step: 2,
+      realKey: 88,
+      realName: "E7",
+      style: { width: '4%', height: '30%' }
+    },
+    {
+      key: 4,
+      name: "F",
+      octave: 7,
+      step: 2,
+      realKey: 89,
+      realName: "F7",
+      style: { width: '4%', height: '29%' }
+    },
+  ],
+  melodica: [
+    {
+      key: 4,
+      name: "F",
+      octave: 4,
+      step: -1,
+      realKey: 53,
+      realName: "F4",
+    },
+    {
+      key: 5,
+      name: "G",
+      octave: 4,
+      step: -1,
+      realKey: 55,
+      realName: "G4",
+      children: {
+        key: 5,
+        name: "G",
+        octave: 4,
+        step: -1,
+        realKey: 54,
+        mark: "fall",
+        realName: "Gb4",
+        style: { marginLeft: '-48%' }
+      },
+    },
+
+    {
+      key: 6,
+      name: "A",
+      octave: 4,
+      step: -1,
+      realKey: 57,
+      realName: "A4",
+      children: {
+        key: 6,
+        name: "A",
+        octave: 4,
+        step: -1,
+        realKey: 56,
+        mark: "fall",
+        realName: "Ab4",
+        style: { marginLeft: '-29%' }
+      },
+    },
+    {
+      key: 7,
+      name: "B",
+      octave: 4,
+      step: -1,
+      realKey: 59,
+      realName: "B4",
+      children: {
+        key: 7,
+        name: "B",
+        octave: 4,
+        step: -1,
+        realKey: 58,
+        mark: "fall",
+        realName: "Bb4",
+        style: { marginLeft: '-11%' }
+      },
+    },
+    {
+      key: 1,
+      name: "C",
+      octave: 5,
+      step: 0,
+      realKey: 60,
+      realName: "C5",
+    },
+
+    {
+      key: 2,
+      name: "D",
+      octave: 5,
+      step: 0,
+      realKey: 62,
+      realName: "D5",
+      children: {
+        key: 2,
+        name: "D",
+        octave: 5,
+        step: 0,
+        realKey: 61,
+        mark: "fall",
+        realName: "Db5",
+        style: { marginLeft: '-36%' }
+      },
+    },
+
+    {
+      key: 3,
+      name: "E",
+      octave: 5,
+      step: 0,
+      realKey: 64,
+      realName: "E5",
+      children: {
+        key: 3,
+        name: "E",
+        octave: 5,
+        step: 0,
+        realKey: 63,
+        mark: "fall",
+        realName: "Eb5",
+        style: { marginLeft: '-22%' }
+      },
+    },
+    {
+      key: 4,
+      name: "F",
+      octave: 5,
+      step: 0,
+      realKey: 65,
+      realName: "F5",
+    },
+
+    {
+      key: 5,
+      name: "G",
+      octave: 5,
+      step: 0,
+      realKey: 67,
+      realName: "G5",
+      children: {
+        key: 5,
+        name: "G",
+        octave: 5,
+        step: 0,
+        realKey: 66,
+        mark: "fall",
+        realName: "Gb5",
+        style: { marginLeft: '-47%' }
+      },
+    },
+    {
+      key: 6,
+      name: "A",
+      octave: 5,
+      step: 0,
+      realKey: 69,
+      realName: "A5",
+      children: {
+        key: 6,
+        name: "A",
+        octave: 5,
+        step: 0,
+        realKey: 68,
+        mark: "fall",
+        realName: "Ab5",
+        style: { marginLeft: '-29%' }
+      },
+    },
+
+    {
+      key: 7,
+      name: "B",
+      octave: 5,
+      step: 0,
+      realKey: 71,
+      realName: "B5",
+      children: {
+        key: 7,
+        name: "B",
+        octave: 5,
+        step: 0,
+        realKey: 70,
+        mark: "fall",
+        realName: "Bb5",
+        style: { marginLeft: '-11%' }
+      },
+    },
+    {
+      key: 1,
+      name: "C",
+      octave: 6,
+      step: 1,
+      realKey: 72,
+      realName: "C6",
+    },
+
+    {
+      key: 2,
+      name: "D",
+      octave: 6,
+      step: 1,
+      realKey: 74,
+      realName: "D6",
+      children: {
+        key: 2,
+        name: "D",
+        octave: 6,
+        step: 1,
+        realKey: 73,
+        mark: "fall",
+        realName: "Db6",
+        style: { marginLeft: '-34%' }
+      },
+    },
+
+    {
+      key: 3,
+      name: "E",
+      octave: 6,
+      step: 1,
+      realKey: 76,
+      realName: "E6",
+      children: {
+        key: 3,
+        name: "E",
+        octave: 6,
+        step: 1,
+        realKey: 75,
+        mark: "fall",
+        realName: "Eb6",
+        style: { marginLeft: '-23%' }
+      },
+    },
+    {
+      key: 4,
+      name: "F",
+      octave: 6,
+      step: 1,
+      realKey: 77,
+      realName: "F6",
+    },
+
+    {
+      key: 5,
+      name: "G",
+      octave: 6,
+      step: 1,
+      realKey: 79,
+      realName: "G6",
+      children: {
+        key: 5,
+        name: "G",
+        octave: 6,
+        step: 1,
+        realKey: 78,
+        mark: "fall",
+        realName: "Gb6",
+        style: { marginLeft: '-47%' }
+      },
+    },
+
+    {
+      key: 6,
+      name: "A",
+      octave: 6,
+      step: 1,
+      realKey: 81,
+      realName: "A6",
+      children: {
+        key: 6,
+        name: "A",
+        octave: 6,
+        step: 1,
+        realKey: 80,
+        mark: "fall",
+        realName: "Ab6",
+        style: { marginLeft: '-29%' }
+      },
+    },
+
+    {
+      key: 7,
+      name: "B",
+      octave: 6,
+      step: 1,
+      realKey: 83,
+      realName: "B6",
+      children: {
+        key: 7,
+        name: "B",
+        octave: 6,
+        step: 1,
+        realKey: 82,
+        mark: "fall",
+        realName: "Bb6",
+        style: { marginLeft: '-11%' }
+      },
+    },
+    {
+      key: 1,
+      name: "C",
+      octave: 7,
+      step: 2,
+      realKey: 84,
+      realName: "C7",
+    },
+  ]
+} as any

+ 255 - 60
src/page-instrument/view-figner/index.module.less

@@ -108,7 +108,8 @@
             }
         }
     }
-    .tipsOverlay{
+
+    .tipsOverlay {
         width: 57%;
         height: 100%;
         position: fixed;
@@ -117,17 +118,20 @@
         z-index: 2009;
         animation: bgIn 0.2s 0.2s forwards;
     }
-    &.fingerRight .tipsPcBg.tips{
+
+    &.fingerRight .tipsPcBg.tips {
         animation: bgIn 0.15s 0.25s forwards;
-        border-radius:0;
+        border-radius: 0;
         background-image: url('./image/icon_shuo_v.png') !important;
     }
+
     @keyframes bgIn {
-        0%{
+        0% {
             background-color: initial;
         }
-        100%{
-            background-color: rgba(0,0,0,0.5);
+
+        100% {
+            background-color: rgba(0, 0, 0, 0.5);
         }
     }
 }
@@ -192,7 +196,7 @@
     pointer-events: none;
     padding-right: 18px;
     padding-top: env(safe-area-inset-top);
-    z-index: 5;
+    z-index: 11;
 
     .backBtn {
         margin-right: 14px;
@@ -260,29 +264,37 @@
         display: flex;
         flex-direction: column;
     }
-    .userTab{
+
+    .userTab {
         display: flex;
         justify-content: center;
         width: 100%;
-        .userTabBox{
+        position: relative;
+
+        .userTabBox {
             width: 100%;
-            .notes{
+
+            .notes {
                 padding-bottom: 10px;
                 height: initial;
-                .lastNoteContent{
-                    border-radius: 0 !important; 
-                    .noteBox{
+
+                .lastNoteContent {
+                    border-radius: 0 !important;
+
+                    .noteBox {
                         border-radius: 0 !important;
                     }
                 }
-                .noteContent{
+
+                .noteContent {
                     padding: 0 10px;
                 }
-                .changeMusBtn{
+
+                .changeMusBtn {
                     margin-right: 8px;
                     text-align: center;
                     width: 42px;
-                    background: linear-gradient( 180deg, #F4EFED 0%, #D9CEC7 100%);
+                    background: linear-gradient(180deg, #F4EFED 0%, #D9CEC7 100%);
                     box-shadow: 0px 1px 2px 0px #9F9690, inset 0px -2px 0px 0px #CDC0B5, inset 0px 2px 1px 0px #FFFFFF;
                     border-radius: 21px;
                     font-weight: 600;
@@ -292,35 +304,42 @@
                     padding: 7px 6px;
                     height: 46px;
                 }
-                .backBtn{
+
+                .backBtn {
                     line-height: 32px;
                 }
             }
-            .optionBtns{
+
+            .optionBtns {
                 padding-bottom: 0;
             }
-            :global{
-                .van-tabs__wrap{
+
+            :global {
+                .van-tabs__wrap {
                     width: 100%;
                     display: flex;
                     justify-content: center;
                     height: 30px;
-                    .van-tabs__nav{
+
+                    .van-tabs__nav {
                         width: 120px;
                         background-color: initial;
-                        border-bottom: 2px solid rgba(82,138,214,0.15);
+                        border-bottom: 2px solid rgba(82, 138, 214, 0.15);
                         height: initial;
                         padding-bottom: initial;
-                        .van-tab{
+
+                        .van-tab {
                             font-weight: 400;
                             font-size: 15px;
                             color: #616161;
-                            &.van-tab--active{
+
+                            &.van-tab--active {
                                 font-weight: 600;
                                 color: #616161;
                             }
                         }
-                        .van-tabs__line{
+
+                        .van-tabs__line {
                             width: 32px;
                             bottom: -2px;
                             height: 2px;
@@ -329,26 +348,31 @@
                         }
                     }
                 }
-                .van-tabs__content{
+
+                .van-tabs__content {
                     padding-top: 16px;
                     height: 130px;
-                    .van-tab__panel{
+
+                    .van-tab__panel {
                         height: 100%;
                     }
                 }
             }
-            .btnBox{
+
+            .btnBox {
                 height: 100%;
                 display: flex;
                 justify-content: center;
                 align-items: center;
                 margin-top: -16px;
-                .btnCon{
+
+                .btnCon {
                     border-radius: 17px;
                     display: flex;
                     background: rgba(255, 255, 255, 0.5);
                     padding: 6px 5px 3px 6px;
-                    .btnGr{
+
+                    .btnGr {
                         background: url("./image/btnBg.png") no-repeat;
                         background-size: 100% 100%;
                         width: 93px;
@@ -359,14 +383,17 @@
                         justify-content: center;
                         cursor: pointer;
                         margin-left: 5px;
-                        &:first-child{
+
+                        &:first-child {
                             margin-left: 0;
                         }
-                        >img{
+
+                        >img {
                             width: 19px;
                             height: 19px;
                         }
-                        >span{
+
+                        >span {
                             font-weight: 500;
                             font-size: 14px;
                             color: #616161;
@@ -376,14 +403,38 @@
                 }
             }
         }
+
+
+        &.usrTabOverlaping {
+            visibility: hidden;
+            opacity: 0;
+            // &::after {
+            //     position: absolute;
+            //     content: '';
+            //     left: 0;
+            //     top: 0;
+            //     width: 100%;
+            //     height: 100%;
+            //     background: linear-gradient(180deg, rgba(222, 213, 208, 0) 0%, rgba(210, 199, 194, 0.93) 27%, #C5B8B3 100%);
+            //     z-index: 9;
+            // }
+        }
+
     }
+
     .boxFinger {
         flex: 1;
         padding-top: 50px;
         overflow: hidden;
-        &.pcBoxFinger{
+
+        &.pcBoxFinger {
             padding-top: 10px !important;
         }
+
+        &.boxFingerOverlapping {
+            overflow: visible;
+            z-index: 10;
+        }
     }
 
 
@@ -396,7 +447,7 @@
     position: relative;
     z-index: 11;
     flex-shrink: 0;
-    transition: all .3s;
+    transition: all .2s;
     // background-color: rgba(190, 166, 140, 1);
     background-size: 100% 100%;
     background-repeat: no-repeat;
@@ -560,45 +611,72 @@
 
     }
 }
-.btnGrToggleBtn{
+
+.btnGrToggleBtn {
     font-weight: 600;
     font-size: 12px;
     color: #fff;
-    >div{
+
+    >div {
         display: flex;
         flex-direction: column;
         align-items: center;
         z-index: 10;
-        &.nameBox{
+
+        &.nameBox {
             padding-top: 2px;
-            .name{
+
+            .name {
                 font-size: 10px;
             }
-            .noteKey{
+
+            .noteKey {
                 font-size: 12px;
                 position: relative;
                 color: #ffffff;
             }
+
             .dot {
                 display: inline-block;
                 position: absolute;
                 top: 0px;
-                &.botDot{
+
+                &.botDot {
                     top: initial;
                     bottom: -2px;
                 }
             }
         }
     }
-    .name{
+
+    .name {
         display: flex;
     }
-    .arrowImg{
+
+    .arrowImg {
         margin-top: 2px;
         width: 9px;
         height: 5px;
     }
 }
+
+.usrTabOverlapingNotes {
+    position: relative;
+    visibility: hidden;
+    opacity: 0;
+    // &::after {
+    //     position: absolute;
+    //     content: '';
+    //     left: 0;
+    //     top: 0;
+    //     width: 100%;
+    //     height: 100%;
+    //     background: linear-gradient(180deg, rgba(222, 213, 208, 0) 0%, rgba(210, 199, 194, 0.93) 17%, #C5B8B3 100%);
+    //     z-index: 9;
+    // }
+}
+
+
 .notes {
     position: relative;
     display: flex;
@@ -608,6 +686,8 @@
     flex-shrink: 0;
     cursor: pointer;
 
+
+
     &.paddingLeft {
         padding-left: 20Px;
     }
@@ -669,7 +749,7 @@
     .noteBox {
         display: flex;
         overflow-y: hidden;
-        overflow-x: auto;
+        overflow-x: hidden;
         border-radius: 0 25px 25px 0;
         z-index: 9;
 
@@ -952,6 +1032,98 @@
         max-width: 100%;
         max-height: 100%;
     }
+
+    // .fullContent {
+    //     position: absolute;
+    //     left: 50%;
+    //     top: 50%;
+    //     transform: translate(-50%, -50%);
+    //     display: block;
+    //     width: 100%;
+
+    //     .showImgNk {
+    //         position: absolute;
+    //         top: 0;
+    //         left: 0;
+    //         width: 100%;
+    //     }
+
+    //     img {
+    //         width: 100%;
+    //     }
+    // }
+}
+
+.fingeringPointSection {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    z-index: 10;
+
+    .p1 {
+        position: relative;
+        // background: red;
+        cursor: pointer;
+        pointer-events: auto;
+    }
+
+    .p2 {
+        position: absolute;
+        top: 0;
+        z-index: 1;
+        left: 0;
+        cursor: pointer;
+        pointer-events: auto;
+    }
+
+    &>div {
+        width: 100%;
+        height: 100%;
+        display: flex;
+        align-items: flex-start;
+        justify-content: space-between;
+    }
+
+    .pan-flute {
+        padding: 28.5% 3.3% 3.1% 3.8%;
+        justify-content: flex-start;
+
+        &.pan-flute-back {
+            flex-direction: row-reverse;
+            justify-content: space-evenly;
+        }
+
+        .p1 {
+            // background-color: rgba(255, 0, 0, .3);
+            width: 3.4%;
+            height: 100%;
+        }
+    }
+
+    .melodica {
+        padding: 0.9% 3.6% 3% 10.7%;
+
+        .p1 {
+            position: relative;
+            width: 5.2%;
+            // background-color: rgba(255, 0, 0, .3);
+            height: 100%;
+        }
+
+        .p2 {
+            position: absolute;
+            top: 0;
+            width: 54%;
+            height: 58%;
+            // background-color: rgba(0, 0, 255, .3);
+            z-index: 1;
+            left: 0;
+            margin-left: -8%;
+        }
+    }
+
+
 }
 
 .tizhi {
@@ -996,6 +1168,7 @@
     top: 50%;
     right: auto;
     transform: translateY(-50%);
+    z-index: 11;
 
 
     .baseBtn {
@@ -1138,9 +1311,11 @@
             position: absolute;
             left: 50%;
             transform: translateX(-50%);
+
             &.topDot {
                 top: 0;
             }
+
             &.bottomDot {
                 top: initial;
             }
@@ -1452,6 +1627,12 @@
     border-radius: 12px;
     background-size: contain;
     overflow: initial;
+
+    :global {
+        .bom_guide::before {
+            background-color: rgba(0, 0, 0, 0);
+        }
+    }
 }
 
 .linkSourceClass {
@@ -1490,57 +1671,71 @@
     //     display: none;
     // }
 }
-.dragTopBox{
+
+.dragTopBox {
     position: absolute;
     top: 0;
     left: 0;
     height: 40px;
-    width: 100%; 
+    width: 100%;
 }
-:global{
-    .changeSubjectShowBoxClass_drag{
+
+:global {
+    .changeSubjectShowBoxClass_drag {
         height: 307px !important;
         background: url('./image/subject-bg2.png') no-repeat center !important;
         background-size: contain !important;
-        .dragbomBox{
+
+        .dragbomBox {
             height: 37px;
         }
-        .changeSubjectContainer_pc{
+
+        .changeSubjectContainer_pc {
             height: 168px !important;
         }
-        .btnGroups_pc{
+
+        .btnGroups_pc {
             padding-top: 12px !important;
         }
     }
-    .tnoteShowBoxClass_drag{
+
+    .tnoteShowBoxClass_drag {
         padding: 49px 17px 30px 24px;
         width: 375px;
         overflow: initial;
         height: 247px !important;
         background: url('./image/subject-bg3.png') no-repeat center !important;
         background-size: contain !important;
-        .dragbomBox{
+
+        .dragbomBox {
             height: 37px;
         }
-        .toneTitle_pc{
+
+        .toneTitle_pc {
             display: none;
         }
-        .tipContentbox_pc{
+
+        .tipContentbox_pc {
             background-color: initial;
-            &::after{
+
+            &::after {
                 display: none;
             }
-            .tipContent_pc{
-                border:none;
-                .tipWrap_pc{
+
+            .tipContent_pc {
+                border: none;
+
+                .tipWrap_pc {
                     height: 116px !important;
                     flex: initial;
                     overflow-y: auto;
+
                     &::-webkit-scrollbar {
                         display: none;
                     }
                 }
-                .toneAction_pc{
+
+                .toneAction_pc {
                     padding-bottom: 0 !important;
                     padding-top: 12px !important;
                 }

+ 436 - 68
src/page-instrument/view-figner/index.tsx

@@ -22,6 +22,7 @@ import { Tabs, Tab } from "vant";
 import useDrag from "/src/hooks/useDrag";
 import Dragbom from "/src/hooks/useDrag/dragbom";
 import useDragGuidance from "/src/hooks/useDrag/useDragGuidance";
+import { FINER_INSTRUMENT_POINT } from "./fingeringPoint";
 
 export default defineComponent({
   name: "viewFigner",
@@ -51,6 +52,7 @@ export default defineComponent({
       subject: subject as any,
       realKey: 0,
       notes: [] as IFIGNER_INSTRUMENT_Note[],
+      notePoints: [] as any, // 显示的点
       tones: [] as IFIGNER_INSTRUMENT_Note[],
       activeTone: {} as IFIGNER_INSTRUMENT_Note,
       popupActiveTone: {} as IFIGNER_INSTRUMENT_Note,
@@ -102,6 +104,11 @@ export default defineComponent({
       noteType: "all" as "#c" | "all", // 音调
       loadingDom: false, // 切换乐器时需要重置
       loadingImg: false, // 切换模式,加载图片
+      domOverlapping: false, // 元素是否被遮住
+      domOverImgPropery: {
+        width: "100%",
+        height: "100%",
+      } as any,
     });
     const fingerData = reactive({
       relationshipIndex: 0,
@@ -166,6 +173,7 @@ export default defineComponent({
         // 判断是音符状态
         data.notes = data.noteType === "#c" ? appendNote : tempNotes;
         // data.notes = fignerData[`list${data.activeTone.realName || ""}`];
+        data.notePoints = FINER_INSTRUMENT_POINT[data.subject];
       }
     };
     const getFingeringData = async () => {
@@ -251,6 +259,7 @@ export default defineComponent({
         data.noteType = "all";
       }
       data.tipShow = false;
+      resetElement();
       resetMode(true, 0);
       setTimeout(() => {
         __init(false);
@@ -291,6 +300,9 @@ export default defineComponent({
 
       data.loadingDom = false;
       data.loadingImg = false;
+
+      // 初始化获取元素宽高
+      onResize();
     };
 
     // 获取声部
@@ -383,13 +395,17 @@ export default defineComponent({
       __init();
     });
 
+    // 播放时间
+    let noteTimer: any = null;
     /**
      * 播放音频
      * @param item 音频节点
      * @param showNote 是否显示对应的指法
+     * @param isScrollShowNote 是否滚动到对应播放的位置
+     * @param autoStop 是否自动停止
      * @returns
      */
-    const noteClick = (item: IFIGNER_INSTRUMENT_Note, showNote = true) => {
+    const noteClick = (item: IFIGNER_INSTRUMENT_Note, showNote = true, isScrollShowNote = false, autoStop = false, callBack?: any) => {
       // console.log('音高', item.realKey)
       if (data.noteAudio) {
         data.noteAudio.stop();
@@ -398,14 +414,27 @@ export default defineComponent({
           data.noteAudio = null as unknown as Howl;
           return;
         }
+
+        clearTimeout(noteTimer);
       }
       if (showNote) {
         data.realKey = item.realKey;
       }
-      console.log("key:", item.realKey, data.soundFonts);
+      // console.log("key:", item.realKey, data.soundFonts);
       data.noteAudio = data.soundFonts[item.realKey];
       if (data.noteAudio) {
+        clearTimeout(noteTimer);
         data.noteAudio.play();
+        if (isScrollShowNote) scrollAnswer(item.realKey);
+
+        // 判断是否自动停止播放停止
+        if (autoStop) return;
+        noteTimer = setTimeout(() => {
+          handleStop();
+          if (callBack && typeof callBack === "function") {
+            callBack(item);
+          }
+        }, 300);
       }
     };
     const handleStop = () => {
@@ -416,6 +445,106 @@ export default defineComponent({
       }
     };
 
+    const isLongPress = ref(false); // 是否长按
+    const isTouchStart = ref(false); // 是否长按
+    let isTouch = false;
+    let timerNoteId: any;
+    const longPressDuration = 200;
+
+    const onLongPress = () => {
+      console.log("长按检测成功!");
+      isLongPress.value = true;
+      clearTimeout(noteTimer);
+    };
+    // 开始长按检测
+    const startNotePress = async (note: any, isScrollShowNote = true) => {
+      if (playStatus.gamut) return;
+      if (playAction.listenLock) return;
+      if (playAction.showAnswerLoading) return;
+      timerNoteId = setTimeout(onLongPress, longPressDuration);
+      // 为了处理希沃白板垃圾事件
+      if (isTouchStart.value) return;
+      isTouchStart.value = true;
+      if (playStatus.action) {
+        playAction.userAnswer = note;
+        // 判断用户答题
+        const userResult = note.realKey === playAction.standardAnswer.realKey ? 1 : 2;
+        playAction.userAnswerStatus = userResult;
+        playAction.listenLock = true;
+        data.realKey = note.realKey;
+        noteClick(note, true, isScrollShowNote, false, playCallBack);
+      } else {
+        handleStop();
+        noteClick(note, true, isScrollShowNote);
+      }
+    };
+
+    // 取消长按检测
+    const cancelNotePress = async (note: any, isScrollShowNote = true) => {
+      if (timerNoteId !== null) {
+        clearTimeout(timerNoteId);
+        timerNoteId = null;
+      }
+
+      if (isLongPress.value) {
+        handleStop();
+        playCallBack(note);
+      }
+
+      if (isLongPress.value) {
+        isLongPress.value = false;
+      }
+      isTouchStart.value = false;
+
+      console.log(isLongPress.value, timerNoteId, note.realName);
+    };
+
+    const playCallBack = (note: any) => {
+      if (playAction.listenLock) {
+        const userResult = note.realKey === playAction.standardAnswer.realKey ? 1 : 2;
+        resetMode(userResult === 1 ? true : false, 0);
+        data.realKey = 0;
+        // 如果是指法模式显示完之后要还原
+        if (data.fingeringMode === "fingeringMode" && userResult === 2) {
+          // 延迟显示,因为重置的时候有一个异步操作
+          setTimeout(() => {
+            data.realKey = playAction.standardAnswer.realKey;
+          }, 10);
+        }
+        playAction.listenLock = false;
+      }
+    };
+
+    /** 点击音符播放 */
+    const noteInstrumentPlay = async (note: any, isScroll = false) => {
+      // 判断是否在播放音阶
+      if (playStatus.gamut) return;
+      if (playAction.listenLock) return;
+      if (playAction.showAnswerLoading) return;
+      if (playStatus.action) {
+        playAction.userAnswer = note;
+        // 判断用户答题
+        const userResult = note.realKey === playAction.standardAnswer.realKey ? 1 : 2;
+        playAction.userAnswerStatus = userResult;
+        playAction.listenLock = true;
+        data.realKey = note.realKey;
+        await fingeringPlay(note, 1000);
+        resetMode(userResult === 1 ? true : false, 0);
+        data.realKey = 0;
+
+        // 如果是指法模式显示完之后要还原
+        if (data.fingeringMode === "fingeringMode" && userResult === 2) {
+          // 延迟显示,因为重置的时候有一个异步操作
+          setTimeout(() => {
+            data.realKey = playAction.standardAnswer.realKey;
+          }, 10);
+        }
+        playAction.listenLock = false;
+      } else {
+        noteClick(note, true, isScroll);
+      }
+    };
+
     /** 返回 */
     const handleBack = () => {
       // platform: query.platform,
@@ -465,6 +594,16 @@ export default defineComponent({
       loadElement();
       api_setStatusBarVisibility();
     });
+
+    // 判断两个元素是否重叠
+    const isElementOverlapping = (el1: any, el2: any) => {
+      const rect1 = el1?.getBoundingClientRect();
+      const rect2 = el2?.getBoundingClientRect();
+      return !(rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom);
+    };
+
+    // 是否在拖拽
+    const isDragging = ref(false);
     const loadElement = () => {
       const fingeringContainer = document.getElementById("fingeringContainer");
       setDefaultScale();
@@ -472,9 +611,12 @@ export default defineComponent({
       const mc = new Hammer.Manager(fingeringContainer as HTMLElement);
       mc.add(new Hammer.Pan({ threshold: 0, pointers: 0 }));
       mc.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith([mc.get("pan")]);
-      // mc.get("pan").set({ direction: Hammer.DIRECTION_ALL });
-      // mc.get("pinch").set({ enable: true });
+
+      let dragTimeout: any;
+
       mc.on("panstart pinchstart", function (ev) {
+        isDragging.value = true;
+        clearTimeout(dragTimeout);
         data.transform.transition = "";
       });
       mc.on("panmove pinchmove", function (ev) {
@@ -483,19 +625,40 @@ export default defineComponent({
           data.transform.scale = ev.scale * data.transform.startScale;
           data.transform.x = data.transform.startX + ev.deltaX;
           data.transform.y = data.transform.startY + ev.deltaY;
+
+          // 使用示例
+          const element1 = document.getElementById("fullInstrumentImg");
+          const element2 = document.getElementById("fullInstrumentUserTab");
+          data.domOverlapping = isElementOverlapping(element1, element2);
         }
         if (ev.type === "panmove") {
           // console.log("🚀 ~ ev:", ev.type, ev.deltaX, ev.deltaY);
           data.transform.x = data.transform.startX + ev.deltaX;
           data.transform.y = data.transform.startY + ev.deltaY;
+
+          // 使用示例
+          const element1 = document.getElementById("fullInstrumentImg");
+          const element2 = document.getElementById("fullInstrumentUserTab");
+          data.domOverlapping = isElementOverlapping(element1, element2);
         }
       });
+      mc.on("panend pinchend", function (ev) {
+        dragTimeout = setTimeout(() => {
+          isDragging.value = false;
+        }, 100); // 设置一个短暂的延迟以确保拖拽操作结束
+      });
       //
       mc.on("hammer.input", function (ev) {
         if (ev.isFinal) {
+          // isDragging.value = false;
           data.transform.startScale = data.transform.scale;
           data.transform.startX = data.transform.x;
           data.transform.startY = data.transform.y;
+
+          // 使用示例
+          const element1 = document.getElementById("fullInstrumentImg");
+          const element2 = document.getElementById("fullInstrumentUserTab");
+          data.domOverlapping = isElementOverlapping(element1, element2);
         }
       });
     };
@@ -508,6 +671,7 @@ export default defineComponent({
         data.transform.startScale = data.subject === "pan-flute" ? 0.9 : 1;
         data.transform.startX = 0;
         data.transform.startY = 0;
+        data.domOverlapping = false;
       });
     };
 
@@ -541,6 +705,14 @@ export default defineComponent({
         }
       }
     );
+    watch(
+      () => data.tipShow,
+      (val: any) => {
+        if (!val) {
+          onResize();
+        }
+      }
+    );
     /** 课件播放 */
     const changePlay = (res: any) => {
       if (res?.data?.api === "setPlayState") {
@@ -571,7 +743,38 @@ export default defineComponent({
 
     const noteBoxRef = ref();
     const scrollNoteBox = (type: "left" | "right") => {
-      const width = noteBoxRef.value.offsetWidth / 2;
+      const domOffsetWidth = noteBoxRef.value.offsetWidth;
+      const width = domOffsetWidth / 2;
+      const scrollLeft: any = noteBoxRef.value.scrollLeft;
+      // 判断是否移动到最左边
+      if (width >= scrollLeft && type === "left") {
+        // 不管当前显示在哪个音老师滚动到开始位置
+        (noteBoxRef.value as unknown as HTMLElement).scroll({
+          left: 0,
+          top: 0,
+          behavior: "smooth",
+        });
+        return;
+      }
+      // 处理在部分手机点击左右会超出范围
+      if (type === "right") {
+        // 遍历子元素并累加它们的宽度
+        let childElementsWidth = 0;
+        for (let i = 0; i < noteBoxRef.value.children.length; i++) {
+          childElementsWidth += noteBoxRef.value.children[i].offsetWidth;
+        }
+        // 判断是否移动到最右边
+        if (width > childElementsWidth - scrollLeft - domOffsetWidth) {
+          // 不管当前显示在哪个音老师滚动到开始位置
+          (noteBoxRef.value as unknown as HTMLElement).scroll({
+            left: noteBoxRef.value.scrollWidth,
+            top: 0,
+            behavior: "smooth",
+          });
+          return;
+        }
+      }
+
       (noteBoxRef.value as unknown as HTMLElement).scrollBy({
         left: type === "left" ? -width : width,
         behavior: "smooth",
@@ -606,6 +809,13 @@ export default defineComponent({
       getNotes();
 
       setTimeout(() => {
+        (noteBoxRef.value as unknown as HTMLElement).scroll({
+          left: 0,
+          top: 0,
+          behavior: "smooth",
+        });
+      }, 0);
+      setTimeout(() => {
         playAction.resetAction = false;
       }, 2000);
     };
@@ -801,6 +1011,7 @@ export default defineComponent({
     };
 
     /** 滚轮缩放 */
+
     const handleWheel = (e: WheelEvent) => {
       e.preventDefault();
       if (e.deltaY > 0) {
@@ -814,16 +1025,39 @@ export default defineComponent({
           data.transform.scale = 2;
         }
       }
+
+      // 使用示例
+      setTimeout(() => {
+        const element1 = document.getElementById("fullInstrumentImg");
+        const element2 = document.getElementById("fullInstrumentUserTab");
+        data.domOverlapping = isElementOverlapping(element1, element2);
+      }, 0);
     };
 
+    const onResize = () => {
+      nextTick(() => {
+        setTimeout(() => {
+          const element1: any = document.querySelector("#fullInstrumentImg");
+          // console.log(element1, "element1");
+          const rect = element1?.getBoundingClientRect();
+          data.domOverImgPropery = {
+            ...rect,
+            width: rect.width * (1 / data.transform.scale) + "px",
+            height: rect.height * (1 / data.transform.scale) + "px",
+          };
+        }, 330);
+      });
+    };
     onMounted(() => {
       window.addEventListener("message", changePlay);
+      window.addEventListener("resize", onResize);
       const fingeringContainer = document.getElementById("fingeringContainer");
       fingeringContainer?.addEventListener("wheel", handleWheel);
     });
 
     onUnmounted(() => {
       window.removeEventListener("message", changePlay);
+      window.removeEventListener("resize", onResize);
       const fingeringContainer = document.getElementById("fingeringContainer");
       fingeringContainer?.removeEventListener("wheel", handleWheel);
       document.title = "Ai学练";
@@ -1085,7 +1319,7 @@ export default defineComponent({
             <div class={styles.wrapFinger}>
               <div
                 id="fingeringContainer"
-                class={[styles.boxFinger, query.platform === "pc" ? styles.pcBoxFinger : ""]}
+                class={[styles.boxFinger, query.platform === "pc" ? styles.pcBoxFinger : "", data.domOverlapping && data.notePoints?.length > 0 && styles.boxFingerOverlapping]}
                 style={{
                   paddingTop: containerBox.value.paddingTop,
                   paddingBottom: containerBox.value.paddingBottom,
@@ -1099,21 +1333,132 @@ export default defineComponent({
                   class={[styles.fingeringContainer]}
                 >
                   <div class={styles.imgs}>
-                    {!data.loadingImg && <img src={data.fingeringMode === "scaleMode" ? fingerData.subject?.json?.full : fingerData.subject?.json?.full1} />}
+                    {!data.loadingImg && <img id="fullInstrumentImg" src={data.fingeringMode === "scaleMode" ? fingerData.subject?.json?.full : fingerData.subject?.json?.full1} />}
+
                     {rs.map((key: number | string, index: number) => {
                       const nk: string = typeof key === "string" ? key.replace("active-", "") : String(key);
-                      return <img data-index={nk} src={fingerData.subject?.json?.[nk]} />;
+                      return <img class={styles.showImgNk} data-index={nk} src={fingerData.subject?.json?.[nk]} />;
                     })}
                     <div style={{ left: data.viewIndex == 2 ? "0" : "64%" }} class={[styles.tizhi, canTizhi && styles.canDisplay]} onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}>
                       替指
                     </div>
                     <div id="finger-note-2" style={{ left: "50%", transform: "translateX(-50%)" }} class={styles.tizhi} onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}></div>
+
+                    {data.notePoints?.length > 0 && (
+                      <div
+                        class={[styles.fingeringPointSection]}
+                        style={{
+                          width: data.domOverImgPropery.width,
+                          height: data.domOverImgPropery.height,
+                        }}
+                      >
+                        <div class={[styles[data.subject], data.viewIndex === 2 && data.subject === "pan-flute" && styles["pan-flute-back"]]}>
+                          {data.notePoints.map((point: any) => (
+                            <div
+                              class={styles.p1}
+                              style={point.style}
+                              // onClick={(e: any) => {
+                              //   e.stopPropagation();
+                              //   if (isDragging.value) return;
+                              //   noteInstrumentPlay(point, true);
+                              // }}
+                              onMousedown={(e: any) => {
+                                e.stopPropagation();
+                                e.preventDefault();
+                                console.log("onMousedown", e);
+                                if (isTouch) return;
+                                startNotePress(point);
+                              }}
+                              onMouseup={(e: any) => {
+                                e.stopPropagation();
+                                e.preventDefault();
+                                // console.log("onMouseup", e);
+                                if (isTouch) return;
+                                cancelNotePress(point);
+                              }}
+                              onMouseleave={(e: any) => {
+                                e.stopPropagation();
+                                e.preventDefault();
+                                // console.log("onMouseleave", e);
+                                if (isTouch) return;
+                                cancelNotePress(point);
+                              }}
+                              onTouchstart={(e: any) => {
+                                e.stopPropagation();
+                                e.preventDefault();
+                                // console.log("onTouchstart", e);
+                                isTouch = true;
+                                startNotePress(point);
+                              }}
+                              onTouchend={(e: any) => {
+                                e.stopPropagation();
+                                e.preventDefault();
+                                // console.log("onTouchend", e);
+                                cancelNotePress(point);
+                              }}
+                              onTouchcancel={(e: any) => {
+                                e.stopPropagation();
+                                e.preventDefault();
+                                // console.log("onTouchcancel", e);
+                                cancelNotePress(point);
+                              }}
+                            >
+                              {point.children && (
+                                <div
+                                  class={styles.p2}
+                                  // onClick={(e: any) => {
+                                  //   e.stopPropagation();
+                                  //   if (isDragging.value) return;
+                                  //   noteInstrumentPlay(point.children, true);
+                                  // }}
+                                  onMousedown={(e: any) => {
+                                    e.stopPropagation();
+                                    e.preventDefault();
+                                    if (isTouch) return;
+                                    startNotePress(point.children);
+                                  }}
+                                  onMouseup={(e: any) => {
+                                    e.stopPropagation();
+                                    e.preventDefault();
+                                    if (isTouch) return;
+                                    cancelNotePress(point.children);
+                                  }}
+                                  onMouseleave={(e: any) => {
+                                    e.stopPropagation();
+                                    e.preventDefault();
+                                    if (isTouch) return;
+                                    cancelNotePress(point.children);
+                                  }}
+                                  onTouchstart={(e: any) => {
+                                    e.stopPropagation();
+                                    e.preventDefault();
+                                    isTouch = true;
+                                    startNotePress(point.children);
+                                  }}
+                                  onTouchend={(e: any) => {
+                                    e.stopPropagation();
+                                    e.preventDefault();
+                                    cancelNotePress(point.children);
+                                  }}
+                                  onTouchcancel={(e: any) => {
+                                    e.stopPropagation();
+                                    e.preventDefault();
+                                    cancelNotePress(point.children);
+                                  }}
+                                  style={point.children.style}
+                                ></div>
+                              )}
+                            </div>
+                          ))}
+                        </div>
+                      </div>
+                    )}
                   </div>
                 </div>
               </div>
               {/* 老师端过来隐藏 */}
               {query.platform === "pc" ? (
-                <div class={styles.userTab}>
+                <div class={[styles.userTab, data.domOverlapping && data.notePoints?.length > 0 && styles.usrTabOverlaping]} id="fullInstrumentUserTab">
                   <Tabs v-model:active={userTabActive.value} class={styles.userTabBox}>
                     {userTabs.map((item) => {
                       return (
@@ -1203,33 +1548,42 @@ export default defineComponent({
                                             draggable={false}
                                             class={[styles.note, "note-class"]}
                                             key={note.realKey}
-                                            onClick={async () => {
-                                              // 判断是否在播放音阶
-                                              if (playStatus.gamut) return;
-                                              if (playAction.listenLock) return;
-                                              if (playAction.showAnswerLoading) return;
-                                              if (playStatus.action) {
-                                                playAction.userAnswer = note;
-                                                // 判断用户答题
-                                                const userResult = note.realKey === playAction.standardAnswer.realKey ? 1 : 2;
-                                                playAction.userAnswerStatus = userResult;
-                                                playAction.listenLock = true;
-                                                data.realKey = note.realKey;
-                                                await fingeringPlay(note, 1000);
-                                                resetMode(userResult === 1 ? true : false, 0);
-                                                data.realKey = 0;
-
-                                                // 如果是指法模式显示完之后要还原
-                                                if (data.fingeringMode === "fingeringMode" && userResult === 2) {
-                                                  // 延迟显示,因为重置的时候有一个异步操作
-                                                  setTimeout(() => {
-                                                    data.realKey = playAction.standardAnswer.realKey;
-                                                  }, 10);
-                                                }
-                                                playAction.listenLock = false;
-                                              } else {
-                                                noteClick(note);
-                                              }
+                                            // onClick={async () => {
+                                            //   noteInstrumentPlay(note);
+                                            // }}
+                                            onMousedown={(e: any) => {
+                                              e.stopPropagation();
+                                              e.preventDefault();
+                                              if (isTouch) return;
+                                              startNotePress(note, false);
+                                            }}
+                                            onMouseup={(e: any) => {
+                                              e.stopPropagation();
+                                              e.preventDefault();
+                                              if (isTouch) return;
+                                              cancelNotePress(note, false);
+                                            }}
+                                            onMouseleave={(e: any) => {
+                                              e.stopPropagation();
+                                              e.preventDefault();
+                                              if (isTouch) return;
+                                              cancelNotePress(note, false);
+                                            }}
+                                            onTouchstart={(e: any) => {
+                                              e.stopPropagation();
+                                              e.preventDefault();
+                                              isTouch = true;
+                                              startNotePress(note, false);
+                                            }}
+                                            onTouchend={(e: any) => {
+                                              e.stopPropagation();
+                                              e.preventDefault();
+                                              cancelNotePress(note, false);
+                                            }}
+                                            onTouchcancel={(e: any) => {
+                                              e.stopPropagation();
+                                              e.preventDefault();
+                                              cancelNotePress(note, false);
                                             }}
                                           >
                                             <img draggable={false} src={resultImg(note).icon} />
@@ -1329,6 +1683,7 @@ export default defineComponent({
                                             data.viewIndex = 0;
                                           }
                                         }
+
                                         getFingeringData();
                                       }}
                                     >
@@ -1341,6 +1696,7 @@ export default defineComponent({
                                     onClick={() => {
                                       resetElement();
                                       data.tipShow = !data.tipShow;
+                                      onResize();
                                     }}
                                   >
                                     <img src={icons.icon_2_1} />
@@ -1362,9 +1718,9 @@ export default defineComponent({
                   </Tabs>
                 </div>
               ) : (
-                <>
+                <div class={[data.domOverlapping && data.notePoints?.length > 0 && styles.usrTabOverlapingNotes]} id="fullInstrumentUserTab">
                   <div
-                    class={styles.notes}
+                    class={[styles.notes]}
                     style={{
                       paddingLeft: data.paddingLeft ? data.paddingLeft : "",
                     }}
@@ -1399,7 +1755,7 @@ export default defineComponent({
 
                       {/* [styles.noteContent, browsInfo.ios ? "" : styles.noteContentWrap, data.huaweiPad && styles.huaweiPad] */}
                       <div class={styles.lastNoteContent}>
-                        <div ref={noteBoxRef} class={styles.noteBox}>
+                        <div ref={noteBoxRef} class={styles.noteBox} id="noteBox">
                           {data.notes.map((note: IFIGNER_INSTRUMENT_Note, index: number) => {
                             const steps = new Array(Math.abs(note.step)).fill(1);
                             return (
@@ -1408,33 +1764,42 @@ export default defineComponent({
                                 draggable={false}
                                 class={[styles.note, "note-class"]}
                                 key={note.realKey}
-                                onClick={async () => {
-                                  // 判断是否在播放音阶
-                                  if (playStatus.gamut) return;
-                                  if (playAction.listenLock) return;
-                                  if (playAction.showAnswerLoading) return;
-                                  if (playStatus.action) {
-                                    playAction.userAnswer = note;
-                                    // 判断用户答题
-                                    const userResult = note.realKey === playAction.standardAnswer.realKey ? 1 : 2;
-                                    playAction.userAnswerStatus = userResult;
-                                    playAction.listenLock = true;
-                                    data.realKey = note.realKey;
-                                    await fingeringPlay(note, 1000);
-                                    resetMode(userResult === 1 ? true : false, 0);
-                                    data.realKey = 0;
-
-                                    // 如果是指法模式显示完之后要还原
-                                    if (data.fingeringMode === "fingeringMode" && userResult === 2) {
-                                      // 延迟显示,因为重置的时候有一个异步操作
-                                      setTimeout(() => {
-                                        data.realKey = playAction.standardAnswer.realKey;
-                                      }, 10);
-                                    }
-                                    playAction.listenLock = false;
-                                  } else {
-                                    noteClick(note);
-                                  }
+                                // onClick={async () => {
+                                //   noteInstrumentPlay(note);
+                                // }}
+                                onMousedown={(e: any) => {
+                                  e.stopPropagation();
+                                  e.preventDefault();
+                                  if (isTouch) return;
+                                  startNotePress(note, false);
+                                }}
+                                onMouseup={(e: any) => {
+                                  e.stopPropagation();
+                                  e.preventDefault();
+                                  if (isTouch) return;
+                                  cancelNotePress(note, false);
+                                }}
+                                onMouseleave={(e: any) => {
+                                  e.stopPropagation();
+                                  e.preventDefault();
+                                  if (isTouch) return;
+                                  cancelNotePress(note, false);
+                                }}
+                                onTouchstart={(e: any) => {
+                                  e.stopPropagation();
+                                  e.preventDefault();
+                                  isTouch = true;
+                                  startNotePress(note, false);
+                                }}
+                                onTouchend={(e: any) => {
+                                  e.stopPropagation();
+                                  e.preventDefault();
+                                  cancelNotePress(note, false);
+                                }}
+                                onTouchcancel={(e: any) => {
+                                  e.stopPropagation();
+                                  e.preventDefault();
+                                  cancelNotePress(note, false);
                                 }}
                               >
                                 <img draggable={false} src={resultImg(note).icon} />
@@ -1497,7 +1862,7 @@ export default defineComponent({
                       </Button>
                     </div>
                   )}
-                </>
+                </div>
               )}
             </div>
             {/* 老师端过来隐藏 */}
@@ -1537,6 +1902,7 @@ export default defineComponent({
                     onClick={() => {
                       resetElement();
                       data.tipShow = !data.tipShow;
+                      onResize();
                     }}
                   >
                     <img src={icons.icon_2_1} />
@@ -1726,7 +2092,8 @@ export default defineComponent({
           <Popup
             style={query.platform === "pc" ? changeSubjectShowBoxDragData.styleDrag.value : {}}
             v-model:show={data.changeSubjectShow}
-            class={[styles.changeSubjectPopup, changeSubjectShowBoxClass]}
+            class={[styles.changeSubjectPopup, query.platform === "pc" && styles.changeSubjectPopupPc, changeSubjectShowBoxClass]}
+            closeOnClickOverlay={query.platform === "pc" ? false : true}
             onClick={(e: any) => {
               e.stopPropagation();
             }}
@@ -1747,6 +2114,7 @@ export default defineComponent({
                 data.loadingDom = true;
                 fingerData.fingeringInfo = subjectFingering(data.subject);
                 data.activeTone = {} as any;
+                data.noteType = "all";
                 resetElement();
                 resetMode(true, 0);
                 // api_setRequestedOrientation(orientationDirection.value);