Pārlūkot izejas kodu

添加课件播放

lex-xin 6 mēneši atpakaļ
vecāks
revīzija
e9a29ae51a
26 mainītis faili ar 906 papildinājumiem un 347 dzēšanām
  1. 2 2
      components.d.ts
  2. 17 0
      src/components/globalTools/globalTools.ts
  3. BIN
      src/components/globalTools/images/g-arrow-right.png
  4. BIN
      src/components/globalTools/images/icon-note.png
  5. BIN
      src/components/globalTools/images/icon-tool.png
  6. BIN
      src/components/globalTools/images/icon-whiteboard.png
  7. 102 0
      src/components/globalTools/index.module.less
  8. 221 0
      src/components/globalTools/index.tsx
  9. 7 1
      src/components/o-guide/index.module.less
  10. 32 0
      src/views/coursewarePlay/component/courseware-tips/index.module.less
  11. 24 0
      src/views/coursewarePlay/component/courseware-tips/index.tsx
  12. 146 0
      src/views/coursewarePlay/component/courseware-type/index.module.less
  13. 27 0
      src/views/coursewarePlay/component/courseware-type/index.tsx
  14. 9 7
      src/views/coursewarePlay/component/point.module.less
  15. 1 1
      src/views/coursewarePlay/component/points.tsx
  16. 1 1
      src/views/coursewarePlay/component/tools/pen.module.less
  17. 7 0
      src/views/coursewarePlay/component/tools/pen.tsx
  18. 46 21
      src/views/coursewarePlay/component/video-play.tsx
  19. 28 21
      src/views/coursewarePlay/component/video.module.less
  20. BIN
      src/views/coursewarePlay/image/btn_go_practice.png
  21. BIN
      src/views/coursewarePlay/image/icon-current.png
  22. 0 0
      src/views/coursewarePlay/image/icons.json
  23. BIN
      src/views/coursewarePlay/image/tips-bg.png
  24. 81 32
      src/views/coursewarePlay/index.module.less
  25. 154 260
      src/views/coursewarePlay/index.tsx
  26. 1 1
      vite.config.ts

+ 2 - 2
components.d.ts

@@ -9,9 +9,9 @@ export {}
 
 declare module '@vue/runtime-core' {
   export interface GlobalComponents {
-    HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
+    GlobalTools: typeof import('./src/components/globalTools/globalTools.vue')['default']
+    GlobalTools1: typeof import('./src/components/globalTools/globalTools-1.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
-    VanButton: typeof import('vant/es')['Button']
   }
 }

+ 17 - 0
src/components/globalTools/globalTools.ts

@@ -0,0 +1,17 @@
+import { ref } from "vue"
+
+/** 工具栏状态 */
+export const toolOpen = ref(false)
+// 批注
+export const penShow = ref(false)
+// 白板
+export const whitePenShow = ref(false)
+// 是否正在播放
+export const isPlay = ref(false)
+// 是否隐藏
+export const isHidden = ref(true)
+
+/** 是否隐藏工具栏 */
+export const handleHidden = (status = true) => {
+   isHidden.value = status
+}

BIN
src/components/globalTools/images/g-arrow-right.png


BIN
src/components/globalTools/images/icon-note.png


BIN
src/components/globalTools/images/icon-tool.png


BIN
src/components/globalTools/images/icon-whiteboard.png


+ 102 - 0
src/components/globalTools/index.module.less

@@ -0,0 +1,102 @@
+.globalTools {
+  &.isPlay {
+     .iconTools,
+     .expendTools {
+        opacity: 0.4;
+     }
+  }
+  &.isHidden {
+     .iconTools,
+     .expendTools {
+        opacity: 0;
+        display: none;
+     }
+  }
+
+  .mask {
+     position: fixed;
+     left: 0;
+     right: 0;
+     top: 0;
+     bottom: 0;
+     background-color: transparent;
+     z-index: 2998;
+  }
+  .iconTools,
+  .expendTools {
+     position: fixed;
+     right: -2px;
+     top: 0;
+     transform: translateY(var(--toolTranslateY));
+     // margin-top: -29px;
+     z-index: 2999;
+     // padding: 0 5px;
+     background: rgba(0, 0, 0, 0.4);
+     border-radius: 200px 0px 0px 200px;
+     border: 2px solid rgba(255, 255, 255, 0.3);
+     border-right-width: 0;
+     cursor: pointer;
+     font-size: 0;
+     // transition: transform 0.2s ease;
+     img {
+        padding: 5px 8px;
+        width: 24px;
+        height: 24px;
+        box-sizing: content-box;
+        -moz-user-select: none;
+        /* 火狐浏览器 */
+        -webkit-user-drag: none;
+        /* 谷歌、Safari和Opera浏览器 */
+        -webkit-user-select: none;
+        /* 谷歌、Safari和Opera浏览器 */
+        -ms-user-select: none;
+        /* IE10+浏览器 */
+        user-select: none;
+        /* 通用 */
+        -webkit-touch-callout: none;
+        /* iOS Safari */
+
+        &:hover {
+           opacity: 0.8;
+        }
+     }
+  }
+
+  .iconTools {
+     // transition-delay: 0.2s;
+  }
+
+  .expendTools {
+     // transform: translateX(100%);
+     display: none;
+     img {
+        cursor: pointer;
+        padding-left: 12px;
+        padding-right: 12px;
+     }
+     .iconWhiteboard {
+        // margin: 0 30px;
+        padding-left: 8px;
+        padding-right: 8px;
+     }
+     .iconArrow {
+        padding: 7px 12px;
+        width: 18px;
+        height: 18px;
+     }
+  }
+
+  .hideTools {
+     // transition: transform 0.2s ease;
+     transform: translateY(var(--toolTranslateY));
+     display: none;
+  }
+
+  .showTools {
+     // transition: transform 0.2s ease;
+     // transition-delay: 0.2s;
+     transform: translateY(var(--toolTranslateY));
+     display: flex;
+     align-items: center;
+  }
+}

+ 221 - 0
src/components/globalTools/index.tsx

@@ -0,0 +1,221 @@
+import {
+  toolOpen,
+  whitePenShow,
+  penShow,
+  isPlay,
+  isHidden
+} from './globalTools';
+import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
+import { useRoute } from 'vue-router';
+import styles from './index.module.less';
+import iconTool from './images/icon-tool.png';
+import iconNote from './images/icon-note.png';
+import iconWhiteboard from './images/icon-whiteboard.png';
+import gArrowRight from './images/g-arrow-right.png';
+import Pen from '@/views/coursewarePlay/component/tools/pen';
+import { nextTick } from 'process';
+
+export default defineComponent({
+  name: 'globalTools',
+  setup() {
+    const isMask = ref(false); // 是否显示遮罩层,为了处理云教练里面拖动不了的问题
+    const route = useRoute();
+    // watch(
+    //   () => route.path,
+    //   () => {
+    //     handleStatus();
+    //   }
+    // );
+    const iconToolsDom = ref<HTMLDivElement>();
+    const expendToolsDom = ref<HTMLDivElement>();
+
+    function openTool() {
+      if (isLock) return;
+      isPlay.value = false
+      toolOpen.value = !toolOpen.value;
+    }
+
+    function openType(type: 'note' | 'whiteboard') {
+      if (isLock) return;
+      if (type === 'note') {
+        penShow.value = true;
+
+        isHidden.value = true;
+      } else if (type === 'whiteboard') {
+        whitePenShow.value = true;
+        isHidden.value = true;
+      }
+    }
+
+    function handleStatus() {
+      isHidden.value = route.path === '/login' ? true : false;
+    }
+
+    function computePos(type: 'width' | 'height', value: number) {
+      const clientNum =
+        type == 'width'
+          ? document.documentElement.clientWidth
+          : document.documentElement.clientHeight;
+      console.log(value, clientNum)
+      return {
+        pos: ((clientNum - value) / 2).toFixed(5)
+      };
+    }
+
+    /* 拖拽还没有兼容rem */
+    let isLock = false;
+    let toolMoveY = 0; // 移动的距离
+    function drag(el: HTMLElement) {
+      function mousedown(e: MouseEvent | TouchEvent) {
+        const isTouchEv = isTouchEvent(e);
+        const event = isTouchEv ? e.touches[0] : e;
+        isLock = false;
+        isMask.value = true;
+        const parentElement = el;
+        const parentElementRect = parentElement.getBoundingClientRect();
+        const downX = event.clientX;
+        const downY = event.clientY;
+        // const clientWidth = document.documentElement.clientWidth
+        const clientHeight = document.documentElement.clientHeight;
+        // const minLeft = 0
+        const minTop = 0;
+        // const maxLeft = clientWidth - parentElementRect.width
+        const maxTop = clientHeight - parentElementRect.height;
+        function onMousemove(e: MouseEvent | TouchEvent) {
+          const event = isTouchEvent(e) ? e.touches[0] : e;
+          // let moveX = parentElementRect.left + (e.clientX - downX)
+          let moveY = parentElementRect.top + (event.clientY - downY);
+          // let moveY = e.clientY - downY
+          // moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX
+          moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY;
+          toolMoveY = moveY;
+          document.documentElement.style.setProperty(
+            '--toolTranslateY',
+            `${moveY}px`
+          );
+
+          // 计算移动的距离
+          const cX = event.clientX - downX;
+          const cY = event.clientY - downY;
+
+          // 如果移动距离超过一定阈值,则认为是拖动
+          if (Math.abs(cX) > 3 || Math.abs(cY) > 3) {
+            isLock = true; // 设置为拖动状态
+          }
+        }
+        function onMouseup() {
+          document.removeEventListener(
+            isTouchEv ? 'touchmove' : 'mousemove',
+            onMousemove
+          );
+          document.removeEventListener(
+            isTouchEv ? 'touchend' : 'mouseup',
+            onMouseup
+          );
+          isMask.value = false;
+        }
+        document.addEventListener(
+          isTouchEv ? 'touchmove' : 'mousemove',
+          onMousemove
+        );
+        document.addEventListener(
+          isTouchEv ? 'touchend' : 'mouseup',
+          onMouseup
+        );
+      }
+      el.addEventListener('mousedown', mousedown);
+      el.addEventListener('touchstart', mousedown);
+    }
+    function isTouchEvent(e: MouseEvent | TouchEvent): e is TouchEvent {
+      return window.TouchEvent && e instanceof window.TouchEvent;
+    }
+    //重新计算位置 居中
+    function refreshPos() {
+      // computePos("height", iconToolsDom.value?.clientHeight ||
+      console.log(iconToolsDom.value?.clientHeight);
+      const posHeight = computePos(
+        'height',
+        iconToolsDom.value?.clientHeight || 0
+      );
+      if (iconToolsDom.value) {
+        document.documentElement.style.setProperty(
+          '--toolTranslateY',
+          `${posHeight.pos}px`
+        );
+      }
+    }
+    let rect: any;
+    function onResize() {
+      rect = rect ? rect : iconToolsDom.value?.getBoundingClientRect();
+      const clientHeight = document.documentElement.clientHeight;
+      const maxTop = clientHeight - rect.height;
+      if (toolMoveY >= maxTop) {
+        document.documentElement.style.setProperty(
+          '--toolTranslateY',
+          `${maxTop}px`
+        );
+      }
+    }
+    onMounted(() => {
+      handleStatus();
+      drag(iconToolsDom.value!);
+      drag(expendToolsDom.value!);
+      nextTick(() => {
+        refreshPos();
+      })
+      window.addEventListener('resize', onResize);
+    });
+
+    onUnmounted(() => {
+      window.removeEventListener('resize', onResize);
+    });
+    return () => (
+      <div>
+        <div
+          class={[
+            styles.globalTools,
+            isPlay.value ? styles.isPlay : '',
+            isHidden.value ? styles.isHidden : ''
+          ]}>
+          {isMask.value && <div class={styles.mask}></div>}
+
+          <div
+            class={[[styles.iconTools, toolOpen.value ? styles.hideTools : '']]}
+            ref={iconToolsDom}>
+            <img onClick={openTool} src={iconTool} />
+          </div>
+          <div
+            class={[styles.expendTools, toolOpen.value ? styles.showTools : '']}
+            ref={expendToolsDom}>
+            <img onClick={() => openType('note')} src={iconNote} />
+            <img
+              onClick={() => openType('whiteboard')}
+              class={styles.iconWhiteboard}
+              src={iconWhiteboard}
+            />
+            <img
+              onClick={openTool}
+              class={styles.iconArrow}
+              src={gArrowRight}
+            />
+          </div>
+        </div>
+        <Pen
+          show={penShow.value}
+          close={() => {
+            penShow.value = false;
+            isHidden.value = false;
+          }}
+        />
+        <Pen
+          show={whitePenShow.value}
+          isWhite
+          close={() => {
+            whitePenShow.value = false;
+            isHidden.value = false;
+          }}
+        />
+      </div>
+    );
+  }
+});

+ 7 - 1
src/components/o-guide/index.module.less

@@ -4,9 +4,14 @@
   :global {
     .van-tabs__nav {
       background-color: transparent;
+      --van-tabs-bottom-bar-width: 16px;
       .van-tab {
-        color: #fff;
+        color: rgba(255,255,255,.5);
         font-size: 16px;
+        font-weight: 500;
+      }
+      .van-tab--active {
+        color: #fff;
       }
     }
     .van-tab__panel {
@@ -20,6 +25,7 @@
     }
     .van-tabs__line{
       bottom: .5rem;
+      background: linear-gradient( 135deg, #79FECA 0%, #06CEC1 100%);
     }
   }
   .content {

+ 32 - 0
src/views/coursewarePlay/component/courseware-tips/index.module.less

@@ -0,0 +1,32 @@
+.container {
+  width: 453px;
+  height: 302px;
+  background: url('../../image/tips-bg.png') top center no-repeat #fff;
+  background-size: contain;
+  border-radius: 20px;
+  display: flex;
+  flex-direction: column;
+
+  .title {
+    font-weight: 600;
+    font-size: 16px;
+    color: #131415;
+    line-height: 22px;
+    text-align: center;
+    padding: 12px 0;
+    flex-shrink: 0;
+  }
+
+  .content {
+    flex: 1;
+    overflow-x: hidden;
+    overflow-y: auto;
+    padding: 0 20px;
+    margin-bottom: 16px;
+    font-size: 14px;
+
+    &::-webkit-scrollbar {
+      display: none;
+    }
+  }
+}

+ 24 - 0
src/views/coursewarePlay/component/courseware-tips/index.tsx

@@ -0,0 +1,24 @@
+import { defineComponent, PropType } from "vue";
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'coruseware-tips',
+  props: {
+    titleName: {
+      type: String,
+      default: '阶段目标'
+    },
+    content: {
+      type: String,
+      default: ''
+    }
+  },
+  setup(props) {
+    return () => <div class={styles.container}>
+      <div class={styles.title}>
+        {props.titleName}
+      </div>
+      <div class={styles.content} v-html={props.content}></div>
+    </div>
+  }
+})

+ 146 - 0
src/views/coursewarePlay/component/courseware-type/index.module.less

@@ -0,0 +1,146 @@
+.container {
+  display: flex;
+  flex-direction: column;
+  min-width: 300px;
+  max-width: 300px;
+  height: 100vh;
+  color: #fff;
+  font-size: 12px;
+  box-sizing: border-box;
+}
+
+.pointHead {
+  display: flex;
+  align-items: center;
+  padding: 13px 10px 15px 15px;
+  flex-shrink: 0;
+  font-size: 16px;
+  font-weight: 500;
+
+  img {
+    width: 20px;
+    height: 20px;
+    margin-right: 6px;
+  }
+}
+
+.content {
+  flex: 1;
+  overflow-y: auto;
+  padding: 0 8px;
+}
+
+
+.item {
+  display: inline-block;
+  margin: 0 0 18px;
+  padding: 0 8px;
+  width: calc(33.333% - 16px);
+  box-sizing: content-box;
+
+  .cover {
+    position: relative;
+    border-radius: 2px;
+    overflow: hidden;
+    margin-bottom: 8px;
+    box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.2);
+  }
+
+  .currentText {
+    width: 28px;
+    height: 13px;
+    position: absolute;
+    top: 2px;
+    left: 2px;
+    background: url('../../image/icon-current.png') no-repeat center center;
+    background-size: contain;
+  }
+
+  .model {
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    background-color: rgba(0, 0, 0, 0.4);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: #fff;
+    font-size: 12px;
+    line-height: 18px;
+
+    img {
+      width: 12px;
+      height: 12px;
+      margin-right: 4px;
+    }
+  }
+
+  .coverNum {
+    position: absolute;
+    bottom: 12px;
+    left: 50%;
+    transform: translateX(-50%);
+    border-radius: 20px;
+    color: rgba(116, 44, 0, 1);
+    background-color: #fff;
+    padding: 4px 6px;
+    line-height: 1;
+    font-size: 12px;
+    z-index: 1;
+    white-space: nowrap;
+    word-break: break-all;
+    min-width: 50px;
+    text-align: center;
+  }
+
+  .coverImg {
+    width: 100%;
+    background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAMAAAAPdrEwAAABOFBMVEUAAAC0tLTT09PU1NTt7e3////T09P////T09P////T09P////X19f////U1NTU1NTT09PT09PU1NTU1NTV1dXT09PU1NTU1NTV1dXZ2dn+/v7R0dH////////KysrIyMjT09O0tLTU1NS0tLTU1NS0tLTT09PT09PT09PU1NTU1NTU1NTT09O2trbU1NTV1dXV1dXW1tbV1dXW1tbV1dXJycm4uLj///+0tLT///+0tLT////p6em0tLT4+Pj///+2trb///+1tbX///+0tLT////T09P5+fn+/v63t7e8vLz8/Pzl5eXW1tbBwcH39/fw8PDs7Ozb29v7+/vg4ODOzs65ubny8vLJycnp6enGxsbFxcW+vr62trb09PTY2NjLy8vCwsLn5+fi4uLS0tLu7u7Q0NDd3d02Mu/gAAAARHRSTlMAnPwvBfv07ODdw5AbGezmyrirl5B4aT0kDZyclTwsIPj48+Ta1tPS0LGhiIaEcGJgV05FNhMS7++8vKyslZRzc1ZWJRSpe/cAAALfSURBVFjD7djXcuIwGAVg1pTQAiT0Ekiy6b1v7whsA6b3EGAJu+//BstaiWNiCYGlXGTG55KBDzH6j2xjMmJET5ZdDivQFavDtTxLXlsCFFlam7HmiUxl49ftApRxYWkHLe3A0lZa2oqlAXUMGk/fHG9vpCnSk/pZNJ18m6aOWELRN1CmtbMI+jjNJH0Evc2GlhD0Bhu6h6DTjPIq6Pqonb8XXoCWmjKSHTCnpccp5ges6bHCZAW2dBc8JcOWLqjoPFu6oqLLr2bVQxX9h/GElBWmKDCmxSKAyXWYt1GE677rLtLGejsLcuOCQMI7lVFlsMjxJJUeW3bP+OSTskBJqcuSFppAFT4vsqMrYDrVAitazMHV8kBJs8WGzsPmNoRCFSj5fcuA7vJKvcQ8UJKrCNT0WH0mdEpASbFOSdfhyClvzagGsSzR0D14LHTSSho1/mkQaw39dB9u2vThCU8KQj1JtFiVt+z5ONSLmnoSaeszuia/+lfzAaGS09STQDum6SH/cOXX5rY9Xz0Rj6Sqy0YmjUzrbp56ah6kIT2AH8Pe4M5TT83jP6ThsnALmq+eiD8tlIt/G8POWU8FVNMNuXc8rnH4epJpOHg1jIivJ5mWcvLg4ZqMryeZhnOLm1hyPfF0C95R9PAcvp4jcSYNL7UDHEWuJ56GO46FyPXE0+/+/7Lhgs+ffU093yPoDwCAEcki1/Mjgv4BQFUkSeR6/jQh8gn0SQy5np9NqFi+CgSDWE9rwmJCJ/X9yxt9iSdisVji2y+TESNGXjiW6LU7FYkkzQ9JRiIp93XUoodyX12cBg/9qyvOHbvXxmUw4Wxe+45zZdV/GDy9uHJbZqPhk7jTjrTI4ezO+EkY8wUBW4Y6tgCSPvNxtDLnOzOhEw2HAvt7Hj2oZ28/EApHyRtpvjwPBY/8B5Ot9O1u2b2eTds6x8nr4tZtmx6vfWvXN9nCA/9RMHR+aZ5sohEji+YfnN0/51L6d+cAAAAASUVORK5CYII=');
+    background-repeat: no-repeat;
+    background-position: center;
+    background-size: 50%;
+    border-radius: 2px;
+    overflow: hidden;
+
+    &>img {
+      display: block;
+      width: 100%;
+      height: 95px;
+      opacity: 0;
+      transition: opacity .3s;
+    }
+
+    :global {
+      .van-image__loading {
+        position: relative;
+        height: 95px;
+        animation: van-skeleton-blink var(--van-skeleton-duration) ease-in-out infinite;
+      }
+    }
+
+    &::before {
+      content: '';
+      position: absolute;
+      left: 5px;
+      width: 5px;
+      height: 100%;
+      background: linear-gradient(270deg, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0.03) 100%);
+      box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.2);
+      z-index: 1;
+    }
+  }
+
+  .name {
+    width: 109%;
+    font-size: 12px;
+    font-weight: 600;
+    color: rgba(255,255,255,0.5);
+    line-height: 20px;
+
+    &.active {
+      color: #FFFFFF;
+    }
+  }
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 27 - 0
src/views/coursewarePlay/component/courseware-type/index.tsx


+ 9 - 7
src/views/coursewarePlay/component/point.module.less

@@ -1,8 +1,8 @@
 .container {
   display: flex;
   flex-direction: column;
-  min-width: 288px;
-  max-width: 288px;
+  min-width: 300px;
+  max-width: 300px;
   height: 100vh;
   color: #fff;
   font-size: 12px;
@@ -14,12 +14,13 @@
   align-items: center;
   padding: 13px 10px 15px 15px;
   flex-shrink: 0;
-  font-size: 14px;
+  font-size: 16px;
+  font-weight: 500;
 
   img {
-    width: 16px;
-    height: 16px;
-    margin-right: 7px;
+    width: 20px;
+    height: 20px;
+    margin-right: 6px;
   }
 }
 
@@ -127,6 +128,7 @@
   padding: 5px 5px 5px 0;
   border-radius: 6px;
   font-size: 12px;
+  font-weight: 500;
   position: relative;
 
   :global {
@@ -146,7 +148,7 @@
 
 .itemActive {
   background: rgba(0, 255, 224, 0.15);
-  color: var(--van-primary);
+  color: #00FFE8;
 
   :global {
     .van-icon {

+ 1 - 1
src/views/coursewarePlay/component/points.tsx

@@ -65,7 +65,7 @@ export default defineComponent({
       <div class={styles.container}>
         <div class={styles.pointHead}>
           <img src={iconMulv} />
-          课程目录
+          知识点目录
         </div>
         <div class={styles.content}>
           <Collapse

+ 1 - 1
src/views/coursewarePlay/component/tools/pen.module.less

@@ -4,7 +4,7 @@
     right: 0;
     bottom: 0;
     top: 0;
-    z-index: 11;
+    z-index: 2999;
 }
 .open{
     display: block;

+ 7 - 0
src/views/coursewarePlay/component/tools/pen.tsx

@@ -20,6 +20,10 @@ import styles from './pen.module.less';
 export default defineComponent({
   name: 'tools-pen',
   props: {
+    isWhite: {
+      type: Boolean,
+      default: false
+    },
     show: {
       type: Boolean,
       default: false
@@ -122,6 +126,9 @@ export default defineComponent({
         ]}>
         <iframe
           class={styles.iframe}
+          style={{
+            background: props.isWhite ? '#fff' : 'transparent'
+          }}
           frameborder="0"
           width="100vw"
           height="100vh"

+ 46 - 21
src/views/coursewarePlay/component/video-play.tsx

@@ -25,7 +25,7 @@ import {
 
 import TCPlayer from 'tcplayer.js';
 import 'tcplayer.js/dist/tcplayer.min.css';
-import { Slider } from 'vant';
+import { showToast, Slider } from 'vant';
 import { state } from '@/state';
 
 // 秒转分
@@ -98,6 +98,22 @@ export default defineComponent({
     });
     const speedBtnId = 'speed' + Date.now() + Math.floor(Math.random() * 100);
 
+    /** 设置播放容器 16:9 */
+    const parentContainer = reactive({
+      width: '100%'
+    });
+    const setContainer = () => {
+      const min = Math.min(screen.width, screen.height);
+      const max = Math.max(screen.width, screen.height);
+      const width = min * (16 / 9);
+      if (width > max) {
+        parentContainer.width = '100%';
+        return;
+      } else {
+        parentContainer.width = width + 'px';
+      }
+    };
+
     // const forms = reactive({
     //   subjectIds: [],
     //   orgainIds: []
@@ -136,8 +152,10 @@ export default defineComponent({
       if (!videoItem.value) return;
       if (data.loop) {
         videoItem.value.loop(false);
+        showToast("已关闭循环播放")
       } else {
         videoItem.value.loop(true);
+        showToast("已打开循环播放")
       }
       data.loop = !data.loop;
     };
@@ -289,6 +307,7 @@ export default defineComponent({
     };
 
     onMounted(() => {
+      setContainer()
       videoItem.value = TCPlayer(videoID, {
         appID: '',
         controls: false,
@@ -319,6 +338,8 @@ export default defineComponent({
       }
     );
 
+    
+
     // 去云练习完整版
     const gotoAccomany = (e: any) => {
       // 去云练习完整版
@@ -381,15 +402,17 @@ export default defineComponent({
         onClick={() => {
           data.speedControl = false;
         }}>
-        <video
-          style={{ width: '100%', height: '100%' }}
-          src={item.value.content}
-          ref={videoRef}
-          id={videoID}
-          preload="auto"
-          playsinline
-          webkit-playsinline></video>
-        <div class={styles.videoSection}></div>
+        <div style={{ width: parentContainer.width, height: '100%', margin: '0 auto' }}>
+          <video
+            style={{ width: '100%', height: '100%' }}
+            src={item.value.content}
+            ref={videoRef}
+            id={videoID}
+            preload="auto"
+            playsinline
+            webkit-playsinline></video>
+          <div class={styles.videoSection}></div>
+        </div>
 
         <div
           class={[styles.controls, data.showBar ? '' : styles.hide]}
@@ -400,11 +423,11 @@ export default defineComponent({
           //   emit('close')
           // }}
         >
-          <div class={styles.time}>
-            <div>{getSecondRPM(data.currentTime)}</div>/
-            <div>{getSecondRPM(data.duration)}</div>
-          </div>
           <div class={styles.slider}>
+            <div class={styles.time}>
+              <div>{getSecondRPM(data.currentTime)}</div>/
+              <div>{getSecondRPM(data.duration)}</div>
+            </div>
             <Slider
               step={0.01}
               class={styles.timeProgress}
@@ -425,22 +448,24 @@ export default defineComponent({
                 }}>
                 <img src={data.playState === 'pause' ? iconPlay : iconPause} />
               </div>
-              <div class={styles.actionBtn} onClick={toggleLoop}>
+              <div class={[styles.actionBtn, styles.btnLoop]} onClick={toggleLoop}>
                 <img src={data.loop ? iconLoopActive : iconLoop} />
               </div>
               <div class={styles.actionBtn} id={speedBtnId}>
                 <img src={iconSpeed} />
               </div>
             </div>
-            <div class={styles.name}>{item.value.name}</div>
+            {/* <div class={styles.name}>{item.value.name}</div> */}
+
+            {item.value.materialMusicId && (
+              <div
+                class={[styles.goPractice]}
+                onClick={gotoAccomany}></div>
+            )}
           </div>
         </div>
 
-        {item.value.materialMusicId && (
-          <div
-            class={[styles.goPractice, data.showBar ? '' : styles.hide]}
-            onClick={gotoAccomany}></div>
-        )}
+        
 
         <div
           style={{

+ 28 - 21
src/views/coursewarePlay/component/video.module.less

@@ -166,7 +166,6 @@
   left: 0;
   bottom: 0;
   right: 0;
-  height: 80px;
   background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
   display: flex;
   flex-direction: column;
@@ -185,12 +184,16 @@
     // width: 100%;
     color: #fff;
     font-size: 14px;
-    padding: 4px 20px;
+    font-weight: 600;
+    padding: 4px 20px 4px 0;
   }
 
   .slider {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
     // width: 100%;
-    padding: 0 16px 0 20px;
+    padding: 0 40px 0;
     --van-slider-button-width: 13px !important;
     --van-slider-button-height: 13px !important;
 
@@ -205,6 +208,9 @@
         width: 100%;
         height: 100%;
       }
+      .van-slider__button {
+        box-shadow: none;
+      }
     }
   }
 
@@ -212,7 +218,7 @@
     display: flex;
     align-items: center;
     justify-content: space-between;
-    padding: 0 16px 8px 15px;
+    padding: 8px 40px 12px 36px;
 
     .name {
       font-size: 14px;
@@ -235,19 +241,20 @@
 
     .actionBtn {
       display: flex;
-      width: 30px;
-      height: 30px;
-      padding: 4px 0;
+      width: 28px;
+      height: 28px;
+      margin-right: 20px;
       background: transparent;
+      box-sizing: content-box;
 
-      &+.actionBtn {
-        // margin-left: 12px;
+      &.btnLoop {
+        width: 33px;
+        height: 28px;
+      }
+      >img {
+        width: 100%;
+        height: 100%;
       }
-    }
-
-    .actionBtn>img {
-      width: 100%;
-      height: 100%;
     }
 
     :global {
@@ -308,7 +315,7 @@
 .sliderPopup {
   position: absolute;
   z-index: 9999;
-  left: 68px;
+  left: 128px;
   bottom: 46px;
   display: flex;
   align-items: center;
@@ -356,19 +363,19 @@
 
   :global {
     .van-slider {
-      margin: 7px 0;
+      margin: 13px 0;
     }
   }
 }
 
 .goPractice {
-  width: 89px;
-  height: 32px;
+  width: 86px;
+  height: 30px;
   background: url('./../image/btn_go_practice.png') no-repeat center;
   background-size: contain;
-  position: absolute;
-  right: 16px;
-  bottom: 60px;
+  // position: absolute;
+  // right: 16px;
+  // bottom: 60px;
   z-index: 11;
   transition: all .5s ease;
 

BIN
src/views/coursewarePlay/image/btn_go_practice.png


BIN
src/views/coursewarePlay/image/icon-current.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/views/coursewarePlay/image/icons.json


BIN
src/views/coursewarePlay/image/tips-bg.png


+ 81 - 32
src/views/coursewarePlay/index.module.less

@@ -31,34 +31,62 @@
   right: 0;
   z-index: 10;
   display: flex;
-  align-items: center;
+  align-items: flex-start;
   justify-content: space-between;
-  height: 40px;
+  // height: 40px;
   background: linear-gradient(180deg, rgba(0, 0, 0, 0.6), transparent);
   transition: transform 0.5s;
   box-sizing: border-box;
-  pointer-events: none;
 
   div {
     box-sizing: border-box;
   }
 }
-
 .backBtn {
   color: #fff;
   height: 100%;
   display: flex;
   justify-content: space-between;
-  align-items: center;
+  align-items: flex-start;
   z-index: 10;
-  padding: 0 15px;
-  pointer-events: auto;
+  font-size: 18px;
+  padding: 12px 15px 20px 40px;
 
   :global {
     .van-icon {
       margin-right: 8px;
     }
   }
+
+  .titleSection {
+    .title {
+      font-weight: 600;
+      font-size: 16px;
+      color: #ffffff;
+      line-height: 22px;
+    }
+  }
+  .titleContent {
+    display: flex;
+    align-items: center;
+    padding-top: 6px;
+    p {
+      font-size: 14px;
+      color: #ffffff;
+      line-height: 20px;
+    }
+    span {
+      margin-left: 6px;
+      font-size: 11px;
+      color: #ffffff;
+      line-height: 1.3;
+      background: rgba(0, 0, 0, 0.1);
+      border-radius: 10px;
+      border: 1px solid rgba(255, 255, 255, 0.7);
+      padding: 2px 8px;
+      box-sizing: content-box;
+    }
+  }
 }
 
 .headRight {
@@ -68,19 +96,26 @@
   align-items: center;
   margin-left: auto;
   height: 100%;
-  padding-right: 15px;
-  pointer-events: auto;
+  padding-right: 40px;
+  padding-top: 12px;
+
+  .pointBtn {
+    font-weight: 600;
+    font-size: 14px;
+    color: #FFFFFF;
+    line-height: 20px;
+    padding-right: 20px;
+  }
 
   .rightBtn {
     display: flex;
     justify-content: center;
     align-items: center;
     height: 100%;
-    padding: 0 10px;
 
     img {
-      width: 22px;
-      height: 22px;
+      width: 24px;
+      height: 24px;
       display: block;
     }
   }
@@ -167,8 +202,9 @@
 }
 
 .fullBtn {
-  width: 38px;
-  height: 46px;
+  width: 24px;
+  height: 24px;
+  padding: 10px 9px;
   display: flex;
   flex-direction: column;
   align-items: center;
@@ -176,21 +212,20 @@
   justify-content: space-evenly;
   overflow: hidden;
   white-space: nowrap;
+  box-sizing: content-box;
+  border-radius: 7px;
 
   &:active {
     background: rgba(255, 255, 255, 0.2);
   }
-}
 
-.rightFixedBtns {
-  position: absolute;
-  top: 50%;
-  transform: translateY(-50%);
-  right: 12px;
-  z-index: 10;
+  &.disabled {
+    opacity: 0.4;
+  }
 
-  .btnsBottom {
-    margin-top: 10px;
+  img {
+    width: inherit;
+    height: inherit;
   }
 }
 
@@ -198,16 +233,14 @@
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
-  left: 12px;
+  left: 40px;
   z-index: 10;
-
-  .prePoint {
-    margin-bottom: 8px;
-  }
+  background: rgba(0, 0, 0, 0.4);
+  border-radius: 7px;
 }
 
 .btnsWrap {
-  background: rgba(51, 51, 51, 0.4);
+  // background: rgba(51, 51, 51, 0.4);
   border-radius: 6px;
   overflow: hidden;
 }
@@ -263,6 +296,22 @@
 .popup {
   background: rgba(0, 0, 0, 0.5);
 }
+.popupCoursewarePlay {
+  background: rgba(0, 0, 0, 0.8) !important;
+  box-shadow: -6px 0px 20px 0px rgba(0,0,0,0.3) !important;
+  border-radius: 16px 0px 0px 16px !important;
+}
+.popupPoint {
+  :global {
+    .van-popup__close-icon {
+      font-size: 18px;
+      top: 14px;
+      right: 20px;
+      color: #333333;
+    }
+  }
+}
+
 
 .overlayClass {
   --van-overlay-background: transparent;
@@ -380,13 +429,13 @@
   background: url('./image/btn_go_practice.png') no-repeat center;
   background-size: contain;
   position: absolute;
-  right: 12px;
-  bottom: 60px;
+  right: 40px;
+  bottom: 12px;
   z-index: 11;
   transition: all .5s ease;
 
 
   &.hide {
-    transform: translateX(66px);
+    transform: translateY(55px);
   }
 }

+ 154 - 260
src/views/coursewarePlay/index.tsx

@@ -25,13 +25,7 @@ import MusicScore from './component/musicScore';
 // import iconDian from './image/icon-dian.svg';
 // import iconPoint from './image/icon-point.svg';
 // import qs from 'query-string';
-import {
-  iconUp,
-  iconDown,
-  // iconPen,
-  iconTouping,
-  iconMenu
-} from './image/icons.json';
+import { iconUp, iconDown, iconPen, iconTouping, iconMenu, iconCourseType } from './image/icons.json';
 import Points from './component/points';
 import { browser } from '@/helpers/utils';
 import { Vue3Lottie } from 'vue3-lottie';
@@ -40,12 +34,14 @@ import { usePageVisibility } from '@vant/use';
 // import PlayRecordTime from './playRecordTime';
 import { handleCheckVip } from '../hook/useFee';
 import OGuide from '@/components/o-guide';
-import Tool, { ToolItem, ToolType } from './component/tool';
-import Pen from './component/tools/pen';
 // import VideoItem from './component/video-item';
 import VideoPlay from './component/video-play';
 import deepClone from '@/helpers/deep-clone';
 import { useInterval, useIntervalFn } from '@vueuse/core';
+import CoursewareType from './component/courseware-type';
+import CoursewareTips from './component/courseware-tips';
+import GlobalTools from '@/components/globalTools';
+import { isPlay, penShow, toolOpen, whitePenShow } from '@/components/globalTools/globalTools';
 
 export default defineComponent({
   name: 'CoursewarePlay',
@@ -77,7 +73,7 @@ export default defineComponent({
     };
     const handleInit = (type = 0) => {
       //设置容器16:9
-      setContainer();
+      // setContainer();
       // 横屏
       postMessage(
         {
@@ -121,7 +117,9 @@ export default defineComponent({
     const route = useRoute();
     const headeRef = ref();
     const data = reactive({
+      currentId: route.query.id as any,
       detail: null as any,
+      refLevelList: [] as any, // 课堂类型
       knowledgePointList: [] as any,
       itemList: [] as any,
       showHead: true,
@@ -282,11 +280,11 @@ export default defineComponent({
         }, 500);
       });
     };
-    const getDetail = async () => {
+    const getDetail = async (id?: any) => {
       try {
         const res: any = await request.get(
           state.platformApi +
-            `/lessonCourseware/getLessonCourseDetail/${route.query.id}`,
+            `/lessonCourseware/getLessonCourseDetail/${id || route.query.id}`,
           {
             hideLoading: true
           }
@@ -365,6 +363,17 @@ export default defineComponent({
       }
     };
 
+    const onTitleTip = (type: "phaseGoals" | "checkItem", text: string) => {
+      handleStop()
+      popupData.pointOpen = true
+      popupData.pointContent = text
+      if(type === "checkItem") {
+        popupData.pointTitle = '阶段目标'
+      } else if(type === "phaseGoals") {
+        popupData.pointTitle = '检查事项'
+      }
+    }
+
     // ifram事件处理
     const iframeHandle = (ev: MessageEvent) => {
       if (ev.data?.api === 'headerTogge') {
@@ -453,8 +462,24 @@ export default defineComponent({
         //
       }
     };
+
+    const getRefLevel = async (id?: any) => {
+      try {
+        const res = await request.post(state.platformApi + '/lessonCourseware/refLevel', {
+          data: {
+            lessonCoursewareDetailId: id || route.query.id
+          }
+        })
+        console.log(res.data, '1212')
+        data.refLevelList = res.data || []
+      } catch {
+        // 
+      }
+    }
+
     onMounted(async () => {
       await sysParamConfig();
+      await getRefLevel()
       await getDetail();
       const hasFree = String(data.detail?.accessScope) === '0';
       if (!hasFree) {
@@ -506,6 +531,10 @@ export default defineComponent({
     };
 
     const popupData = reactive({
+      pointOpen: false,
+      pointContent: "", 
+      pointTitle: "",
+      coursewareOpen: false,
       open: false,
       activeIndex: 0,
       playIndex: 0,
@@ -570,18 +599,6 @@ export default defineComponent({
       activeData.model = type;
     };
 
-    // 去点名,签退
-    // const gotoRollCall = (pageTag: string) => {
-    //   postMessage({
-    //     api: 'open_app_page',
-    //     content: {
-    //       action: 'app',
-    //       pageTag: pageTag,
-    //       url: '',
-    //       params: JSON.stringify({ courseId: route.query.courseId })
-    //     }
-    //   });
-    // };
 
     // 双击
     const handleDbClick = () => {
@@ -743,42 +760,6 @@ export default defineComponent({
       }
     };
 
-    /** 教学数据 */
-    const studyData = reactive({
-      type: '' as ToolType,
-      penShow: false
-    });
-
-    /** 打开教学工具 */
-    const openStudyTool = (item: ToolItem) => {
-      const activeItem = data.itemList[popupData.activeIndex];
-      // 暂停视频和曲谱的播放
-      if (activeItem.typeCode === 'VIDEO' && activeItem.videoEle) {
-        activeItem.videoEle.pause();
-      }
-      if (activeItem.typeCode === 'SONG') {
-        activeItem.iframeRef?.contentWindow?.postMessage(
-          { api: 'setPlayState' },
-          '*'
-        );
-      }
-      clearModel();
-      popupData.toolOpen = false;
-      studyData.type = item.type;
-
-      switch (item.type) {
-        case 'pen':
-          studyData.penShow = true;
-          break;
-      }
-    };
-
-    /** 关闭教学工具 */
-    const closeStudyTool = () => {
-      studyData.type = 'init';
-      toggleModel();
-    };
-
     const activeVideoItem = computed(() => {
       const item = data.itemList[popupData.activeIndex];
       if (
@@ -851,6 +832,28 @@ export default defineComponent({
       }
     );
 
+    // 是否收起
+    watch(
+      () => activeData.model,
+      () => {
+        if (activeData.model) {
+            isPlay.value = false
+        } else {
+            isPlay.value = true
+            toolOpen.value = false
+        }
+      }
+    )
+    // 白板的批注打开时暂停播放
+    watch(
+      () => [whitePenShow.value, penShow.value],
+      () => {
+        if (whitePenShow.value || penShow.value) {
+          handleStop()
+        }
+      }
+    )
+
     /**
      * 初始化视频时长
      * @param newVal 播放状态
@@ -894,24 +897,6 @@ export default defineComponent({
     // 更新时间
     const updateStat = async () => {
       try {
-        // const itemList = data.itemList;
-        // const params: any = [];
-        // itemList.forEach((item: any) => {
-        //   if (item.moreTime.length > 0) {
-        //     const videoBrowseData = formatEffectiveTime(item.moreTime);
-        //     const time =
-        //       videoBrowseData.length > 0 ? formatTimer(videoBrowseData) : 0;
-        //     const temp = {
-        //       lessonCoursewareDetailId: route.query.id,
-        //       browseTime: time, // 播放时长
-        //       videoBrowseData: JSON.stringify(videoBrowseData), // 播放的数据
-        //       videoTime: item.videoTime, // 视频时长
-        //       materialId: item.materialId
-        //     };
-        //     params.push(temp);
-        //   }
-        // });
-
         // 只有学生才统计数据
         if (state.platformType === 'STUDENT') {
           const videoTime = videoIntervalRef.counter.value;
@@ -1048,52 +1033,6 @@ export default defineComponent({
                       ? effects[effectIndex.value].next
                       : {}
                   }>
-                  {/* {m.type === 'VIDEO' && (
-                      <>
-                        <VideoPlay
-                          ref={(v: any) => (data.videoRefs[mIndex] = v)}
-                          item={m}
-                          isActive={activeEle}
-                          isEmtry={isEmtry}
-                          onPrepare={(val) => {
-                            m.isprepare = val
-                          }}
-                          onLoadedmetadata={(videoItem: any) => {
-                            m.videoEle = videoItem
-                          }}
-                          onTogglePlay={(paused: boolean) => {
-                            // console.log('播放切换', paused)
-                            if (!m.isprepare) {
-                              m.isprepare = true
-                            }
-                            m.autoPlay = false
-                            if (paused || popupData.open || popupData.guideOpen) {
-                              clearTimeout(activeData.timer)
-                            } else {
-                              setModelOpen()
-                            }
-                          }}
-                          onEnded={() => {
-                            const _index = popupData.activeIndex + 1
-                            if (_index < data.itemList.length) {
-                              handleSwipeChange(_index)
-                            }
-                          }}
-                          onReset={() => {
-                            if (!m.videoEle?.paused) {
-                              setModelOpen()
-                            }
-                          }}
-                        />
-                        <Transition name="van-fade">
-                          {!m.isprepare && (
-                            <div class={styles.loadWrap}>
-                              <Vue3Lottie animationData={playLoadData}></Vue3Lottie>
-                            </div>
-                          )}
-                        </Transition>
-                      </>
-                    )} */}
                   <Transition name="van-fade">
                     {m.typeCode === 'VIDEO' &&
                       data.animationState !== 'end' &&
@@ -1152,160 +1091,84 @@ export default defineComponent({
               );
             })}
           </div>
-          <Transition name="right">
-            {activeData.model && (
-              <div
-                class={styles.rightFixedBtns}
-                onClick={(e: Event) => {
-                  e.stopPropagation();
-                  clearTimeout(activeData.timer);
-                }}>
-                <div class={styles.btnsWrap}>
-                  <div
-                    class={[styles.fullBtn, styles.point]}
-                    onClick={() => (popupData.open = true)}>
-                    <img src={iconMenu} />
-                    <span>知识点</span>
-                  </div>
-                </div>
-
-                <div class={[styles.btnsWrap, styles.btnsBottom]}>
-                  {/* <div class={styles.fullBtn} onClick={() => (popupData.guideOpen = true)}>
-                      <img src={iconTouping} />
-                      <span>投屏</span>
-                    </div> */}
-                  {/* {data.isCourse && (
-                    <>
-                      <div
-                        class={styles.fullBtn}
-                        onClick={() => gotoRollCall('student_roll_call')}>
-                        <img src={iconDian} />
-                        <span>点名</span>
-                      </div>
-                      <div
-                        class={styles.fullBtn}
-                        onClick={() => gotoRollCall('sign_out')}>
-                        <img src={iconPoint} />
-                        <span>签退</span>
-                      </div>
-                    </>
-                  )} */}
-                </div>
-              </div>
-            )}
-          </Transition>
 
           <Transition name="left">
             {activeData.model && (
-              <div
-                class={styles.leftFixedBtns}
-                onClick={(e: Event) => e.stopPropagation()}>
-                {popupData.activeIndex != 0 && (
-                  <div class={[styles.btnsWrap, styles.prePoint]}>
+              <div class={styles.leftFixedBtns} onClick={(e: Event) => e.stopPropagation()}>
+                <div class={[styles.btnsWrap, styles.prePoint]}>
+                  <div class={styles.fullBtn} onClick={() => {
+                    handleStop()
+                    popupData.coursewareOpen = true
+                  }}>
+                    <img src={iconCourseType} />
+                  </div>
+                  <div class={styles.fullBtn} onClick={() => {
+                    handleStop()
+                    popupData.open = true
+                  }}>
+                    <img src={iconMenu} />
+                    {/* <span>知识点</span> */}
+                  </div>
+                  
                     <div
-                      class={styles.fullBtn}
+                      class={[styles.fullBtn, !(popupData.activeIndex != 0) && styles.disabled]}
                       onClick={() => {
-                        // useThrottleFn(() => {
-                        //   handlePreAndNext('up')
-                        // }, 300)
-                        // onChangeSwiper('up')
-                        handlePreAndNext('up');
-                      }}>
+                        if(popupData.activeIndex != 0) handlePreAndNext('up')
+                      }}
+                    >
                       <img src={iconUp} />
-                      <span style={{ textAlign: 'center' }}>上一个</span>
+                      {/* <span style={{ textAlign: 'center' }}>上一个</span> */}
                     </div>
-                  </div>
-                )}
-                {popupData.activeIndex != data.itemList.length - 1 && (
-                  <div class={styles.btnsWrap}>
                     <div
-                      class={styles.fullBtn}
+                      class={[styles.fullBtn, !(popupData.activeIndex != data.itemList.length - 1) && styles.disabled]}
                       onClick={() => {
-                        // console.log('click down')
-                        // useThrottleFn(() => {
-                        //   console.log('click down pass')
-                        //   handlePreAndNext('down')
-                        // }, 300)
-                        // onChangeSwiper('down')
-                        handlePreAndNext('down');
-                      }}>
-                      <span style={{ textAlign: 'center' }}>下一个</span>
+                        if(popupData.activeIndex != data.itemList.length - 1) handlePreAndNext('down')
+                      }}
+                    >
+                      {/* <span style={{ textAlign: 'center' }}>下一个</span> */}
                       <img src={iconDown} />
                     </div>
-                  </div>
-                )}
+                 </div>
               </div>
             )}
           </Transition>
         </div>
 
-        <div
-          style={{ transform: activeData.model ? '' : 'translateY(-100%)' }}
-          id="coursePlayHeader"
-          class={styles.headerContainer}
-          ref={headeRef}>
-          <div class={styles.backBtn} onClick={() => goback()}>
-            <Icon name={iconBack} />
-            返回
-          </div>
-          {/* {data.isCourse && (
-            <PlayRecordTime ref={playRef} list={data.knowledgePointList} />
-          )} */}
           <div
-            class={styles.menu}
-            onClick={() => {
-              const _effectIndex = effectIndex.value + 1;
-              effectIndex.value =
-                _effectIndex >= effects.length - 1 ? 0 : _effectIndex;
-              setModelOpen();
-            }}>
-            {popupData.tabName}
-          </div>
-
-          {state.platformType == 'TEACHER' && (
-            <div
-              class={styles.headRight}
-              onClick={(e: Event) => {
-                e.stopPropagation();
-                clearTimeout(activeData.timer);
-              }}>
-              <div
-                class={styles.rightBtn}
-                onClick={() => (popupData.guideOpen = true)}>
-                <img src={iconTouping} />
+            style={{ transform: activeData.model ? '' : 'translateY(-100%)' }}
+            id="coursePlayHeader"
+            class={styles.headerContainer}
+            ref={headeRef}
+          >
+            <div class={styles.backBtn} onClick={() => goback()}>
+              <Icon name={iconBack} />
+              <div class={styles.titleSection}>
+                <div class={styles.title}>{popupData.tabName}</div>
+                <div class={styles.titleContent}>
+                  <p>{data.itemList[popupData.activeIndex]?.name}</p>
+                  {data.detail?.lessonTargetDesc ? <span onClick={() => onTitleTip('phaseGoals', data.detail?.lessonTargetDesc)}>阶段目标</span>: ""}
+                  {data.itemList[popupData.activeIndex]?.checkItem ? <span onClick={() => onTitleTip('checkItem', data.itemList[popupData.activeIndex]?.checkItem)}>检查事项</span> : ""}
+                </div>
               </div>
-              {/* <div
-                class={styles.rightBtn}
-                onClick={() => {
-                  openStudyTool({
-                    type: 'pen',
-                    icon: iconPen,
-                    name: '批注'
-                  });
-                }}>
-                <img src={iconPen} />
-              </div> */}
-              {/* <div class={styles.rightBtn} onClick={() => (popupData.toolOpen = true)}>
-                <img src={iconMore} />
-              </div> */}
             </div>
-          )}
-        </div>
 
-        {/* 更多弹窗 */}
-        <Popup
-          class={styles.popupMore}
-          overlayClass={styles.overlayClass}
-          position="right"
-          round
-          v-model:show={popupData.toolOpen}
-          onClose={handleClosePopup}>
-          <Tool onHandleTool={openStudyTool} />
-        </Popup>
+            {state.platformType === 'TEACHER' && (
+              <div
+                class={styles.headRight}
+                onClick={(e: Event) => {
+                  e.stopPropagation()
+                  clearTimeout(activeData.timer)
+                }}
+              >
+                <div class={styles.rightBtn} onClick={() => (popupData.guideOpen = true)}>
+                  <img src={iconTouping} />
+                </div>
+              </div>
+            )}
+          </div>
 
         <Popup
-          class={styles.popup}
-          style={{ background: 'rgba(0,0,0, 0.75)' }}
+          class={[styles.popup, styles.popupCoursewarePlay]}
           overlayClass={styles.overlayClass}
           position="right"
           round
@@ -1324,7 +1187,31 @@ export default defineComponent({
         </Popup>
 
         <Popup
-          class={styles.popup}
+          class={[styles.popup, styles.popupCoursewarePlay]}
+          overlayClass={styles.overlayClass}
+          position="right"
+          round
+          v-model:show={popupData.coursewareOpen}
+          onClose={handleClosePopup}>
+            {/* 课件类型 */}
+            <CoursewareType list={data.refLevelList} onConfirm={async (item: any) => {
+              // 判断是否为当前课程类型
+              if(data.currentId === item.id) {
+                return
+              }
+              data.currentId = item.id;
+              await getDetail(item.id);
+              await getRefLevel(item.id);
+              popupData.coursewareOpen = false;
+              popupData.activeIndex = 0;
+              nextTick(() => {
+                popupData.open = true
+              })
+            }} />
+        </Popup>
+
+        <Popup
+          class={[styles.popup, styles.popupCoursewarePlay]}
           overlayClass={styles.overlayClass}
           position="right"
           round
@@ -1333,9 +1220,16 @@ export default defineComponent({
           <OGuide />
         </Popup>
 
-        {studyData.penShow && (
-          <Pen show={studyData.type === 'pen'} close={() => closeStudyTool()} />
-        )}
+        <Popup
+          class={[styles.popup, styles.popupCoursewarePlay, styles.popupPoint]}
+          round
+          closeable
+          v-model:show={popupData.pointOpen}
+          onClose={handleClosePopup}>
+          <CoursewareTips content={popupData.pointContent} titleName={popupData.pointTitle} />
+        </Popup>
+
+        <GlobalTools />
       </div>
     );
   }

+ 1 - 1
vite.config.ts

@@ -14,7 +14,7 @@ function resolve(dir: string) {
 }
 // https://vitejs.dev/config/
 // https://github.com/vitejs/vite/issues/1930 .env
-const proxyUrl = 'https://test.gym.lexiaoya.cn';
+const proxyUrl = 'https://dev.gym.lexiaoya.cn';
 export default defineConfig({
   base: './',
   plugins: [

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels