黄琪勇 1 gadu atpakaļ
vecāks
revīzija
f4bfb7d020

+ 45 - 0
src/hooks/useDrag/dragbom.tsx

@@ -0,0 +1,45 @@
+import { defineComponent, computed, reactive, onMounted } from 'vue';
+import styles from './index.module.less';
+// 底部拖动区域
+export default defineComponent({
+  name: 'dragBom',
+  emits: ["guideDone"],
+	props: {
+		/** 是否显示引导 */
+		showGuide: {
+			type: Boolean,
+			default: false,
+		},
+	},
+  setup(props, { emit }) {
+    const data = reactive({
+      guidePos: "bottom" as "bottom" | "top",
+    });
+
+    const initGuidePos = () => {
+      const pageHeight = document.documentElement.clientHeight || document.body.clientHeight;
+      const guideHeight = document.querySelector('.bom_guide')?.getBoundingClientRect().height || 0;
+      const dragTop = document.querySelector('.bom_drag')?.getBoundingClientRect()?.top || 0;
+      data.guidePos = pageHeight - dragTop < guideHeight ? "top" : "bottom";
+    }
+    onMounted(() => {
+      initGuidePos();
+    });
+    return () => (
+      <>
+        <div class={[styles.dragBom, 'bom_drag']}>
+          <div class={styles.box}></div>
+          <div class={[styles.box, styles.right]}></div>
+        </div>
+        {
+          props.showGuide && 
+          <div class={[styles.guide, data.guidePos === "top" && styles.guideTop, 'bom_guide']}>
+            <div class={styles.guideBg}></div>
+            <div class={styles.guideDone} onClick={() => emit("guideDone")}></div>
+          </div>          
+        }
+
+      </>
+    );
+  }
+});

BIN
src/hooks/useDrag/img/left.png


BIN
src/hooks/useDrag/img/modalDragBg.png


BIN
src/hooks/useDrag/img/modalDragBg2.png


BIN
src/hooks/useDrag/img/modalDragDone.png


BIN
src/hooks/useDrag/img/right.png


+ 61 - 0
src/hooks/useDrag/index.module.less

@@ -0,0 +1,61 @@
+.dragBom {
+  width: 100%;
+  height: 21px;
+  display: flex;
+  justify-content: space-between;
+  border-radius: 0 0 7px 7px;
+  overflow: hidden;
+  .box {
+    width: 21px;
+    height: 100%;
+    background: url('./img/left.png') no-repeat;
+    background-size: 100% 100%;
+    &.right {
+      background: url('./img/right.png') no-repeat;
+      background-size: 100% 100%;
+    }
+  }
+}
+.guide {
+  position: absolute;
+  left: 0;
+  top: calc(100% - 10px);
+  &::before {
+    content: "";
+    display: block;
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 9;
+    width: 100vw;
+    height: 100vh;
+    background: rgba(0,0,0,0.2);
+  }
+  .guideBg {
+    position: relative;
+    z-index: 99;
+    width: 200px;
+    height: 102px;
+    background: url('./img/modalDragBg.png') no-repeat;
+    background-size: 100% 100%;
+  }
+  .guideDone {
+    position: absolute;
+    z-index: 99;
+    left: 34.6%;
+    top: 72.2%;
+    width: 50px;
+    height: 20px;
+    background: url('./img/modalDragDone.png') no-repeat;
+    background-size: 100% 100%;
+    cursor: pointer;
+  }
+  &.guideTop {
+    top: initial;
+    bottom: 2px;
+    .guideBg {
+      background: url('./img/modalDragBg2.png') no-repeat;
+      background-size: 100% 100%;
+    }
+  }
+}

+ 158 - 0
src/hooks/useDrag/index.ts

@@ -0,0 +1,158 @@
+// 弹窗拖动
+import { ref, Ref, watch, nextTick, computed } from 'vue';
+
+type posType = {
+  top: number;
+  left: number;
+};
+
+/**
+ * @params classList  可拖动地方的class值,也为唯一值
+ * @params boxClass  容器class值必须为唯一值,这个class和useid拼接 作为缓存主键
+ * @params dragShow  弹窗是否显示
+ * @params userId    当前用户id
+ */
+export default function useDrag(
+  classList: string[],
+  boxClass: string,
+  dragShow: Ref<boolean>,
+  userId: string
+) {
+  const pos = ref<posType>({
+    top: -1, // -1 为初始值 代表没有缓存 默认居中
+    left: -1
+  });
+  const useIdDargClass = userId + boxClass;
+  watch(dragShow, () => {
+    if (dragShow.value) {
+      // 初始化pos值
+      initPos();
+      window.addEventListener('resize', refreshPos);
+      nextTick(() => {
+        const boxClassDom = document.querySelector(
+          `.${boxClass}`
+        ) as HTMLElement;
+        if (!boxClassDom) {
+          return;
+        }
+        classList.map((className: string) => {
+          const classDom = document.querySelector(
+            `.${className}`
+          ) as HTMLElement;
+          console.log(classDom)
+          if (classDom) {
+            classDom.style.cursor = 'move';
+            drag(classDom, boxClassDom, pos);
+          }
+        });
+      });
+    } else {
+      window.removeEventListener('resize', refreshPos);
+      setCachePos(useIdDargClass, pos.value);
+    }
+  });
+  const styleDrag = computed(() => {
+    // 没有设置拖动的时候保持原本的
+    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'
+        };
+  });
+  function initPos() {
+    const posCache = getCachePos(useIdDargClass);
+    // 有缓存 用缓存的值,没有缓存用默认
+    if (posCache) {
+      pos.value = posCache;
+    }
+  }
+  function refreshPos() {
+    const boxClassDom = document.querySelector(`.${boxClass}`) as HTMLElement;
+    if (!boxClassDom) return;
+    const parentElementRect = boxClassDom.getBoundingClientRect();
+    const clientWidth = document.documentElement.clientWidth;
+    const clientHeight = document.documentElement.clientHeight;
+    const { top, left } = pos.value;
+    const maxLeft = clientWidth - parentElementRect.width;
+    const maxTop = clientHeight - parentElementRect.height;
+    let moveX = left;
+    let moveY = top;
+    const minLeft = 0;
+    const minTop = 0;
+    moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX;
+    moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY;
+    pos.value = {
+      top: moveY,
+      left: moveX
+    };
+  }
+  return {
+    pos,
+    styleDrag
+  };
+}
+
+// 拖动
+function drag(el: HTMLElement, parentElement: HTMLElement, pos: Ref<posType>) {
+  function mousedown(e: MouseEvent) {
+    const parentElementRect = parentElement.getBoundingClientRect();
+    const downX = e.clientX;
+    const downY = e.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);
+      moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX;
+      moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY;
+      pos.value = {
+        top: moveY,
+        left: moveX
+      };
+    }
+    function onMouseup() {
+      document.removeEventListener('mousemove', onMousemove);
+      document.removeEventListener('mouseup', onMouseup);
+    }
+    document.addEventListener('mousemove', onMousemove);
+    document.addEventListener('mouseup', onMouseup);
+  }
+  el.addEventListener('mousedown', mousedown);
+}
+
+// 缓存
+const localStorageName = 'dragCachePos';
+function getCachePos(useIdDargClass: string): null | undefined | posType {
+  const localCachePos = localStorage.getItem(localStorageName);
+  if (localCachePos) {
+    try {
+      return JSON.parse(localCachePos)[useIdDargClass];
+    } catch {
+      return null;
+    }
+  }
+  return null;
+}
+function setCachePos(useIdDargClass: string, pos: posType) {
+  const localCachePos = localStorage.getItem(localStorageName);
+  let cachePosObj: Record<string, any> = {};
+  if (localCachePos) {
+    try {
+      cachePosObj = JSON.parse(localCachePos);
+    } catch {
+      //
+    }
+  }
+  cachePosObj[useIdDargClass] = pos;
+  localStorage.setItem(localStorageName, JSON.stringify(cachePosObj));
+}

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

@@ -131,7 +131,7 @@ export default defineComponent({
           )}
         </div>
 
-        <div class={styles.btnGroups}>
+        <div class={[styles.btnGroups,"btnGroups_pc"]}>
           <div
             class={[styles.btn, styles.resetBtn]}
             onClick={() => {

BIN
src/page-instrument/view-figner/image/subJect-bg2.png


BIN
src/page-instrument/view-figner/image/subJect-bg3.png


+ 42 - 1
src/page-instrument/view-figner/index.module.less

@@ -1478,8 +1478,49 @@
 }
 :global{
     .changeSubjectShowBoxClass_drag{
+        height: 247px !important;
+        background: url('./image/subject-bg2.png') no-repeat center !important;
+        background-size: contain !important;
         .changeSubjectContainer_pc{
-            height: 170px !important;
+            height: 112px !important;
+        }
+        .btnGroups_pc{
+            padding-top: 12px !important;
+        }
+    }
+    .tnoteShowBoxClass_drag{
+        padding: 49px 17px 30px 24px;
+        width: 375px;
+        overflow: hidden;
+        height: 247px !important;
+        background: url('./image/subject-bg3.png') no-repeat center !important;
+        background-size: contain !important;
+        .dragbomBox{
+            height: 38px;
+        }
+        .toneTitle_pc{
+            display: none;
+        }
+        .tipContentbox_pc{
+            background-color: initial;
+            &::after{
+                display: none;
+            }
+            .tipContent_pc{
+                border:none;
+                .tipWrap_pc{
+                    height: 116px !important;
+                    flex: initial;
+                    overflow-y: auto;
+                    &::-webkit-scrollbar {
+                        display: none;
+                    }
+                }
+                .toneAction_pc{
+                    padding-bottom: 0 !important;
+                    padding-top: 12px !important;
+                }
+            }
         }
     }
 }

+ 28 - 6
src/page-instrument/view-figner/index.tsx

@@ -1008,6 +1008,18 @@ export default defineComponent({
         storeData.user.id as string
       );
     }
+    // 移调弹窗
+    let tnoteShowBoxDragData: any;
+    let tnoteShowBoxClass: string;
+    if (query.platform==="pc") {
+      tnoteShowBoxClass = 'tnoteShowBoxClass_drag';
+      tnoteShowBoxDragData = useDrag(
+        [`${tnoteShowBoxClass} .dragTopBox`, `${tnoteShowBoxClass} .dragbomBox`],
+        tnoteShowBoxClass,
+        toRef(data, 'tnoteShow'),
+        storeData.user.id as string
+      );
+    }
     return () => {
       const relationship = fingerData.subject?.relationship?.[data.realKey] || [];
       const rs: number[] = Array.isArray(relationship[1]) ? relationship[fingerData.relationshipIndex] : relationship;
@@ -1631,9 +1643,13 @@ export default defineComponent({
             )}
           </div>
 
-          <Popup class="tonePopup" v-model:show={data.tnoteShow} position={state.platform !== IPlatform.PC && !query.modelType && fingerData.fingeringInfo.orientation === 1 ? "bottom" : "right"}>
+          <Popup class={["tonePopup",tnoteShowBoxClass]} style={
+              query.platform==="pc" ? tnoteShowBoxDragData.styleDrag.value : {}
+            } 
+            v-model:show={data.tnoteShow} 
+            position={state.platform === IPlatform.PC?"center":!query.modelType && fingerData.fingeringInfo.orientation === 1 ? "bottom" : "right"}>
             <div class={styles.tones}>
-              <div class={styles.toneTitle}>
+              <div class={[styles.toneTitle,"toneTitle_pc"]}>
                 <div class={styles.tipTitleName}>移调</div>
                 <Button
                   class={styles.tipClose}
@@ -1645,9 +1661,9 @@ export default defineComponent({
                   <Icon name="cross" size={19} color="#fff" />
                 </Button>
               </div>
-              <div class={styles.tipContentbox}>
-                <div class={styles.tipContent}>
-                  <div class={styles.tipWrap}>
+              <div class={[styles.tipContentbox,"tipContentbox_pc"]}>
+                <div class={[styles.tipContent,"tipContent_pc"]}>
+                  <div class={[styles.tipWrap,"tipWrap_pc"]}>
                     <Space size={0} class={styles.toneContent}>
                       {data.tones.map((tone: IFIGNER_INSTRUMENT_Note) => {
                         const steps = new Array(Math.abs(tone.step)).fill(1);
@@ -1686,7 +1702,7 @@ export default defineComponent({
                       })}
                     </Space>
                   </div>
-                  <div class={styles.toneAction}>
+                  <div class={[styles.toneAction,"toneAction_pc"]}>
                     <img
                       onClick={(e: any) => {
                         e.stopPropagation();
@@ -1707,6 +1723,12 @@ export default defineComponent({
                 </div>
               </div>
             </div>
+            {query.platform==="pc" && <>
+              <div class={[styles.dragTopBox,"dragTopBox"]}></div>
+              <div class={[styles.dragbomBox,"dragbomBox"]}>
+                <Dragbom></Dragbom>
+              </div>
+            </>}
           </Popup>
 
           <Popup