黄琪勇 hace 1 año
padre
commit
69310ece0c

+ 14 - 0
src/hooks/useDrag/dragbom.jsx

@@ -0,0 +1,14 @@
+import { defineComponent } from 'vue';
+import styles from './index.module.less';
+// 底部拖动区域
+export default defineComponent({
+  name: 'dragBom',
+  setup() {
+    return () => (
+      <div class={[styles.dragBom, 'bom_drag']}>
+        <div class={styles.box}></div>
+        <div class={styles.box}></div>
+      </div>
+    );
+  }
+});

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


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


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

@@ -0,0 +1,18 @@
+.dragBom {
+  width: 100%;
+  height: 42px;
+  display: flex;
+  justify-content: space-between;
+  border-radius: 0 0 16px 16px;
+  overflow: hidden;
+  .box {
+    width: 42px;
+    height: 100%;
+    background: url('./img//left.png') no-repeat;
+    background-size: 100% 100%;
+    &:last-child {
+      background: url('./img//right.png') no-repeat;
+      background-size: 100% 100%;
+    }
+  }
+}

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

@@ -0,0 +1,153 @@
+// 弹窗拖动
+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;
+          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`
+        };
+  });
+  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));
+}

+ 16 - 2
src/views/attend-class/index.module.less

@@ -770,10 +770,24 @@
   height: 100%;
 }
 
+:global{
+  .selResourBoxClass_drag{
+    .select-resource{
+      padding-bottom: 0;
+      height: 50vh;
+      .list_container{
+        --listContainerHeight:50vh;
+        .selresources_item_Wrap{
+          width: calc(100% / 3) !important;
+          padding-bottom: calc(100% / 3 * 0.73333) !important;
+        }
+      }
+    }
+  }
+}
 .selectMusicModal {
   position: relative;
-  width: 1352px;
-
+  width: 1050px;
   :global {
     .n-card-header {
       position: absolute;

+ 31 - 3
src/views/attend-class/index.tsx

@@ -7,7 +7,8 @@ import {
   Transition,
   computed,
   nextTick,
-  watch
+  watch,
+  toRef
 } from 'vue';
 import styles from './index.module.less';
 import 'plyr/dist/plyr.css';
@@ -93,6 +94,8 @@ import ResourceMain from '../prepare-lessons/components/resource-main';
 import { useResizeObserver } from '@vueuse/core';
 import { storage } from '/src/utils/storage';
 import { ACCESS_TOKEN_ADMIN } from '/src/store/mutation-types';
+import useDrag from '@/hooks/useDrag';
+import Dragbom from '@/hooks/useDrag/dragbom';
 
 export type ToolType = 'init' | 'pen' | 'whiteboard' | 'call';
 export type ToolItem = {
@@ -1442,6 +1445,26 @@ export default defineComponent({
       }
     };
 
+    /* 弹窗加拖动 */
+    // 选择课件弹窗
+    const selCourBoxClass = 'selCourBoxClass_drag';
+    const selCourDragData = useDrag(
+      [`${selCourBoxClass}>.n-card-header`, `${selCourBoxClass} .bom_drag`],
+      selCourBoxClass,
+      toRef(data, 'selectClassStatus'),
+      users.info.id
+    );
+    // 选择资源弹窗
+    const selResourBoxClass = 'selResourBoxClass_drag';
+    const selResourDragData = useDrag(
+      [
+        `${selResourBoxClass} .select-resource>.n-tabs>.n-tabs-nav--top.n-tabs-nav`,
+        `${selResourBoxClass} .bom_drag`
+      ],
+      selResourBoxClass,
+      toRef(data, 'selectResourceStatus'),
+      users.info.id
+    );
     return () => (
       <div id="playContent" class={[styles.playContent, 'wrap']}>
         <div
@@ -1921,8 +1944,10 @@ export default defineComponent({
           class={[
             'modalTitle background',
             // styles.attendClassModal,
-            styles.selectClassModal
+            styles.selectClassModal,
+            selCourBoxClass
           ]}
+          style={selCourDragData.styleDrag.value}
           title={'选择课件'}>
           <SelectClass
             classId={data.classId}
@@ -1953,6 +1978,7 @@ export default defineComponent({
               popupData.chapterLoading = false;
             }}
           />
+          <Dragbom></Dragbom>
         </NModal>
 
         {/* 布置作业 */}
@@ -2081,10 +2107,12 @@ export default defineComponent({
 
         <NModal
           v-model:show={data.selectResourceStatus}
-          class={['modalTitle', styles.selectMusicModal]}
+          class={['modalTitle', styles.selectMusicModal, selResourBoxClass]}
+          style={selResourDragData.styleDrag.value}
           preset="card"
           title={'选择资源'}>
           <SelectResources from="class" />
+          <Dragbom></Dragbom>
         </NModal>
         <NModal
           transformOrigin="center"

+ 5 - 5
src/views/attend-class/model/select-class/index.module.less

@@ -1,10 +1,10 @@
 .selectClass {
-  padding: 12px 0 27px;
+  padding: 12px 0 0;
 }
 
 .selectClassScroll {
-  min-height: 60vh;
-  max-height: 60vh;
+  min-height: 46vh;
+  max-height: 46vh;
 
 }
 
@@ -24,7 +24,7 @@
   &.listEmpty {
     display: flex;
     align-items: center;
-    min-height: 60vh;
+    min-height: 46vh;
   }
 
 
@@ -35,4 +35,4 @@
       padding: 0 10px;
     }
   }
-}
+}

+ 0 - 5
src/views/prepare-lessons/model/select-resources/index.module.less

@@ -55,8 +55,3 @@
     }
   }
 }
-
-.listContainer {
-  margin-bottom: 20px;
-  max-height: 50vh;
-}

+ 2 - 1
src/views/prepare-lessons/model/select-resources/select-item/index.module.less

@@ -1,4 +1,5 @@
 .listContainer {
+  --listContainerHeight:85vh;
   margin: 0;
   // max-height: calc(80vh - var(--modal-lesson-search-height) - 50px - 30Px);
 
@@ -58,4 +59,4 @@
       }
     }
   }
-}
+}

+ 4 - 4
src/views/prepare-lessons/model/select-resources/select-item/index.tsx

@@ -187,9 +187,9 @@ export default defineComponent({
           )}
         </div>
         <NScrollbar
-          class={styles.listContainer}
+          class={[styles.listContainer, 'list_container']}
           style={{
-            'max-height': `calc(85vh - var(--modal-lesson-tab-height) - ${state.searchHeight} - 12px) `
+            'max-height': `calc(var(--listContainerHeight) - var(--modal-lesson-tab-height) - ${state.searchHeight}) `
           }}
           onScroll={(e: any) => {
             const clientHeight = e.target?.clientHeight;
@@ -208,7 +208,7 @@ export default defineComponent({
           <NSpin show={state.loading} size={'small'}>
             <div
               style={{
-                'min-height': `calc(85vh - var(--modal-lesson-tab-height) - ${state.searchHeight} - 12px)`
+                'min-height': `calc(var(--listContainerHeight) - var(--modal-lesson-tab-height) - ${state.searchHeight})`
               }}
               class={[
                 styles.listSection,
@@ -219,7 +219,7 @@ export default defineComponent({
               {state.tableList.length > 0 && (
                 <div class={styles.list}>
                   {state.tableList.map((item: any) => (
-                    <div class={styles.itemWrap}>
+                    <div class={[styles.itemWrap, 'selresources_item_Wrap']}>
                       <div class={styles.itemWrapBox}>
                         <CardType
                           isShowAdd={props.from === 'class' ? false : true}