Forráskód Böngészése

Merge branch 'main' of http://git.dayaedu.com/huangqiyong/classroom into dev

黄琪勇 7 hónapja
szülő
commit
debc5856b8

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 0
dist/css/514.6201e6fa.css


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/css/879.eee3bcd1.css


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/css/960.c558f835.css


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/css/app.2ae84a6b.css


+ 4 - 0
dist/index.html

@@ -1,6 +1,10 @@
 <!doctype html><html lang=""><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="renderer" content="webkit"/><meta name="force-rendering" content="webkit"/><link rel="icon" href="/favicon.ico"/><title>乐教通</title><script>if (!!window.ActiveXObject || "ActiveXObject" in window) {
             window.location.href = "./ieIncompatible/index.html"
+<<<<<<< HEAD
          }</script><script defer="defer" src="/js/chunk-vendors.027bd478.js"></script><script defer="defer" src="/js/app.8232cbf4.js"></script><link href="/css/app.3fa2d767.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but classroom doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"><style>.firstLoading {
+=======
+         }</script><script defer="defer" src="/js/chunk-vendors.e1ccbebf.js"></script><script defer="defer" src="/js/app.a965d2c6.js"></script><link href="/css/app.2ae84a6b.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but classroom doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"><style>.firstLoading {
+>>>>>>> 691c2d3258fb2ddb5a8679f84098766bb4dcdb7c
                position: fixed;
                left: 50%;
                top: 50%;

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/js/179.d250bf8a.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/js/428.5c32a0cf.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/js/514.5f74bbe0.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/js/544.346165db.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/js/549.e5d3c5b0.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/js/611.b537918c.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 0
dist/js/879.f28154f8.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/js/app.a965d2c6.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
dist/js/chunk-vendors.e1ccbebf.js


+ 3 - 5
src/api/cloudTextbooks.api.ts

@@ -9,11 +9,9 @@ export const queryLessonCourseware_gym = (type: string, abortController: AbortCo
       method: "post",
       url: "/api-teacher/lessonCourseware/queryLessonCourseware",
       data: {
-         query: {
-            subjectId: type,
-            page: 1,
-            rows: 9999
-         }
+         subjectId: type,
+         page: 1,
+         rows: 9999
       }
    })
 }

+ 2 - 4
src/api/curriculum.api.ts

@@ -26,10 +26,8 @@ export const queryLessonCourseware_gym = () => {
       method: "post",
       url: "/api-teacher/lessonCourseware/queryLessonCourseware",
       data: {
-         query: {
-            page: 1,
-            rows: 9999
-         }
+         page: 1,
+         rows: 9999
       }
    })
 }

+ 17 - 0
src/assets/index.scss

@@ -29,3 +29,20 @@ body {
       appearance: textfield;
    }
 }
+
+.defaultMessage {
+   --el-message-bg-color: rgba(0, 0, 0, 0.7) !important;
+   border: none !important;
+   --el-message-text-color: #fff !important;
+   border-radius: 6px !important;
+   top: 50% !important;
+   transform: translate(-50%, -50%) !important;
+   .el-icon {
+      display: none;
+   }
+   .el-message__content {
+      font-weight: 500;
+      font-size: 19px;
+      color: #ffffff;
+   }
+}

+ 7 - 0
src/businessComponents/globalTools/globalTools.ts

@@ -8,3 +8,10 @@ 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
+}

+ 95 - 26
src/businessComponents/globalTools/globalTools.vue

@@ -4,11 +4,11 @@
 * @Date:2024年10月14日10:03:11
 -->
 <template>
-   <div class="globalTools" :class="isPlay ? 'isPlay' : ''">
+   <div class="globalTools" :class="[isPlay ? 'isPlay' : '', isHidden ? 'isHidden' : '']">
+      <div class="mask" v-if="isMask"></div>
       <div :class="['iconTools', toolOpen ? 'hideTools' : '']" ref="iconToolsDom">
          <img @click="openTool" src="@/img/layout/icon-tool.png" />
       </div>
-
       <div :class="['expendTools', toolOpen ? 'showTools' : '']" ref="expendToolsDom">
          <img @click="openType('note')" src="@/img/layout/icon-note.png" />
          <img @click="openType('whiteboard')" class="iconWhiteboard" src="@/img/layout/icon-whiteboard.png" />
@@ -19,6 +19,7 @@
       :close="
          () => {
             penShow = false
+            isHidden = false
          }
       "
       v-model="penShow"
@@ -28,6 +29,7 @@
       :close="
          () => {
             whitePenShow = false
+            isHidden = false
          }
       "
       v-model="whitePenShow"
@@ -37,9 +39,18 @@
 <script setup lang="ts">
 import { baseSize, baseWidth, size } from "@/libs/rem"
 import pen from "@/views/coursewarePlay/components/pen"
-import { toolOpen, whitePenShow, penShow, isPlay } from "./globalTools"
-import { onMounted, ref } from "vue"
+import { toolOpen, whitePenShow, penShow, isPlay, isHidden } from "./globalTools"
+import { onMounted, onUnmounted, ref, watch } from "vue"
+import { useRoute } from "vue-router"
+const isMask = ref(false) // 是否显示遮罩层,为了处理云教练里面拖动不了的问题
 
+const route = useRoute()
+watch(
+   () => route.path,
+   () => {
+      handleStatus()
+   }
+)
 const iconToolsDom = ref<HTMLDivElement>()
 const expendToolsDom = ref<HTMLDivElement>()
 
@@ -49,15 +60,21 @@ function openTool() {
 }
 
 function openType(type: "note" | "whiteboard") {
-   console.log(type, "type")
    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 | string) {
    const clientNum = type == "width" ? baseWidth : document.documentElement.clientHeight
    return typeof value === "string"
@@ -76,38 +93,55 @@ function computePos(type: "width" | "height", value: number | string) {
 
 /* 拖拽还没有兼容rem */
 let isLock = false
+let toolMoveY = 0 // 移动的距离
 function drag(el: HTMLElement) {
-   function mousedown(e: MouseEvent) {
-      e.stopPropagation()
-      e.preventDefault()
+   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 = 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 minLeft = 0
       const minTop = 0
       // const maxLeft = clientWidth - parentElementRect.width
       const maxTop = clientHeight - parentElementRect.height
-      function onMousemove(e: MouseEvent) {
+      function onMousemove(e: MouseEvent | TouchEvent) {
+         const event = isTouchEvent(e) ? e.touches[0] : e
          // let moveX = parentElementRect.left + (e.clientX - downX)
-         let moveY = parentElementRect.top + (e.clientY - downY)
+         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`)
-         isLock = true
+
+         // 计算移动的距离
+         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("mousemove", onMousemove)
-         document.removeEventListener("mouseup", onMouseup)
+         document.removeEventListener(isTouchEv ? "touchmove" : "mousemove", onMousemove)
+         document.removeEventListener(isTouchEv ? "touchend" : "mouseup", onMouseup)
+         isMask.value = false
       }
-      document.addEventListener("mousemove", onMousemove)
-      document.addEventListener("mouseup", onMouseup)
+      document.addEventListener(isTouchEv ? "touchmove" : "mousemove", onMousemove)
+      document.addEventListener(isTouchEv ? "touchend" : "mouseup", onMouseup)
    }
-   el.addEventListener("mousedown", mousedown, true)
+   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() {
@@ -116,15 +150,24 @@ function refreshPos() {
       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(() => {
    drag(iconToolsDom.value!)
    drag(expendToolsDom.value!)
    refreshPos()
+   window.addEventListener("resize", onResize)
+})
 
-   iconToolsDom.value!.onclick = (e: any) => {
-      e.stopPropagation()
-   }
+onUnmounted(() => {
+   window.removeEventListener("resize", onResize)
 })
 </script>
 
@@ -136,24 +179,44 @@ onMounted(() => {
          opacity: $opacity-disabled;
       }
    }
+   &.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: 0;
+      right: -6px;
       top: 0;
       transform: translateY(var(--toolTranslateY));
       // margin-top: -29px;
       z-index: 2999;
-      padding: 8px 14px 8px 16px;
+      // 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: 8px 15px;
          width: 34px;
          height: 34px;
+         box-sizing: content-box;
          -moz-user-select: none;
          /* 火狐浏览器 */
          -webkit-user-drag: none;
@@ -166,6 +229,10 @@ onMounted(() => {
          /* 通用 */
          -webkit-touch-callout: none;
          /* iOS Safari */
+
+         &:hover {
+            opacity: $opacity-hover;
+         }
       }
    }
 
@@ -180,9 +247,10 @@ onMounted(() => {
          cursor: pointer;
       }
       .iconWhiteboard {
-         margin: 0 30px;
+         // margin: 0 30px;
       }
       .iconArrow {
+         padding: 7px 15px;
          width: 28px;
          height: 28px;
       }
@@ -198,7 +266,8 @@ onMounted(() => {
       // transition: transform 0.2s ease;
       // transition-delay: 0.2s;
       transform: translateY(var(--toolTranslateY));
-      display: block;
+      display: flex;
+      align-items: center;
    }
 }
 </style>

+ 13 - 2
src/businessComponents/practiceForm/practiceForm.vue

@@ -5,19 +5,30 @@
 -->
 <template>
    <el-dialog modal-class="practiceFormClass" class="practiceForm" v-bind="$attrs" :fullscreen="true" :show-close="false">
-      <iframe v-if="practiceUrl" class="penIframe" frameborder="0" :src="practiceUrl"></iframe>
+      <iframe v-if="practiceUrl" class="penIframe" ref="practiceDom" frameborder="0" :src="practiceUrl"></iframe>
    </el-dialog>
 </template>
 
 <script setup lang="ts">
-import { onUnmounted } from "vue"
+import { onUnmounted, ref, watch } from "vue"
+import { penShow, whitePenShow } from "../globalTools/globalTools"
 defineProps<{
    practiceUrl: string
 }>()
 const emits = defineEmits<{
    (e: "close"): void
 }>()
+const practiceDom = ref<any>()
 
+// 白板的批注打开时暂停播放
+watch(
+   () => [whitePenShow.value, penShow.value],
+   () => {
+      if (whitePenShow.value || penShow.value) {
+         practiceDom.value?.contentWindow?.postMessage({ api: "setPlayState" }, "*")
+      }
+   }
+)
 // 监听iframe传来的关闭弹窗事件
 window.addEventListener("message", messageClose)
 function messageClose(event: MessageEvent<any>) {

+ 12 - 1
src/views/cloudPractice/cloudPractice.tsx

@@ -1,4 +1,4 @@
-import { computed, defineComponent, nextTick, onMounted, reactive, ref, shallowRef } from "vue"
+import { computed, defineComponent, nextTick, onMounted, reactive, ref, shallowRef, watch } from "vue"
 import styles from "./index.module.scss"
 import NavContainer from "@/businessComponents/navContainer"
 import { ElEmpty, ElMessage, ElScrollbar } from "element-plus"
@@ -35,6 +35,7 @@ import PracticeForm from "@/businessComponents/practiceForm"
 import { saveAs } from "file-saver"
 import JSZip from "jszip"
 import { svgtoblob } from "./formatSvgToImg"
+import { penShow, whitePenShow } from "@/businessComponents/globalTools/globalTools"
 
 export default defineComponent({
    name: "cloudPractice",
@@ -939,6 +940,16 @@ export default defineComponent({
          }
       }
 
+      // 白板的批注打开时暂停播放
+      watch(
+         () => [whitePenShow.value, penShow.value],
+         () => {
+            if (whitePenShow.value || penShow.value) {
+               handleChangeAudio("pause")
+            }
+         }
+      )
+
       onMounted(() => {
          const obv = new IntersectionObserver(entries => {
             if (entries[0].intersectionRatio > 0) {

+ 1 - 0
src/views/cloudPractice/index.module.scss

@@ -354,6 +354,7 @@
          .itemInfo {
             display: flex;
             align-items: center;
+            flex: 1;
          }
 
          .titleName {

+ 1 - 0
src/views/coursewarePlay/components/courseCollapse/courseCollapse.vue

@@ -248,6 +248,7 @@ function handleClick(value: any) {
             }
          }
          .iconArrow {
+            display: flex;
             flex-shrink: 0;
             width: 13px;
             height: 13px;

+ 32 - 2
src/views/coursewarePlay/components/courseMenuCollapse/courseMenuCollapse.vue

@@ -1,12 +1,24 @@
 <template>
    <div class="courseMenuCollapse">
-      <div class="courseMenuItem" v-for="item in props.courseMenuList" :key="item.id" :name="item.id" @click="handleClick(item)">
+      <div
+         class="courseMenuItem"
+         :class="item.useFlag ? 'current' : ''"
+         v-for="item in props.courseMenuList"
+         :key="item.id"
+         :name="item.id"
+         @click="handleClick(item)"
+      >
          <div class="cover">
             <img :src="item.coverImg" />
             <div class="current" v-if="item.useFlag">当前</div>
          </div>
          <div class="text">
-            <ellipsisScroll :autoScroll="item.useFlag" :title="item.lessonCoursewareName" />
+            <el-tooltip popper-class="singleton-tooltip" :offset="5" :showArrow="false" :placement="'top'">
+               <template #content>
+                  <div :style="{ maxWidth: `180px` }">{{ item.lessonCoursewareName }}</div>
+               </template>
+               <div ref="tooltipDom" class="tooltipAutoShow">{{ item.lessonCoursewareName }}</div>
+            </el-tooltip>
          </div>
       </div>
    </div>
@@ -47,6 +59,11 @@ function handleClick(value: any) {
       margin-left: 24px;
       box-sizing: content-box;
       cursor: pointer;
+      &.current {
+         .text {
+            color: #131415;
+         }
+      }
       .cover {
          position: relative;
          width: 100%;
@@ -88,6 +105,19 @@ function handleClick(value: any) {
          line-height: 20px;
          overflow: hidden;
       }
+
+      .tooltipAutoShow {
+         overflow: hidden;
+         white-space: nowrap;
+         text-overflow: ellipsis;
+      }
    }
 }
 </style>
+<style lang="scss">
+.singleton-tooltip {
+   background: rgba(0, 0, 0, 0.7) !important;
+   font-size: 14px !important;
+   font-weight: 500 !important;
+}
+</style>

+ 1 - 2
src/views/coursewarePlay/components/playRecordTime/playRecordTime.vue

@@ -51,7 +51,6 @@ function getCoursewarePlayTime() {
    })
 }
 // 判断如果为同一个则计时
-console.log(props.isCurrentCoursewareMenu, "props.isCurrentCoursewareMenu")
 if (props.isCurrentCoursewareMenu) {
    timerCount()
 }
@@ -94,7 +93,7 @@ function handleCoursewarePlayTime(id: string, time: number) {
       width: 8px;
       height: 8px;
       background: #f73434;
-      animation: loadFade 1s ease-in-out infinite;
+      // animation: loadFade 1s ease-in-out infinite;
       border-radius: 50%;
       @keyframes loadFade {
          0% {

+ 3 - 1
src/views/coursewarePlay/components/useCoursewarePlayTip/coursewarePlayTip.vue

@@ -8,7 +8,9 @@
       <div class="close" @click="close"></div>
       <img class="headImg" v-if="props.modalData.headImg" :src="props.modalData.headImg" />
       <div class="textCon">
-         <div class="text" v-html="props.modalData.text"></div>
+         <ElScrollbar class="elScrollbar">
+            <div class="text" v-html="props.modalData.text"></div>
+         </ElScrollbar>
       </div>
       <div v-if="filterBtnShow" class="dialogBtn">
          <img v-if="props.modalData.btnShow[1]" @click="cancel" src="@/img/useDialogConfirm/cancel.png" />

+ 2 - 2
src/views/coursewarePlay/components/useCoursewarePlayTip/index.ts

@@ -23,8 +23,8 @@ export default ({ text, onCancel, onOk, onClose, btnShow, headImg }: objType) =>
    modalFrame({
       maskClose: true,
       template: coursewarePlayTip,
-      width: 740,
-      height: 470,
+      width: 840,
+      height: 570,
       btnShow: [],
       modalData: {
          text,

+ 89 - 62
src/views/coursewarePlay/coursewarePlay.vue

@@ -10,8 +10,13 @@
             v-show="fileType === 'VIDEO'"
             ref="videoPlayDom"
             @ended="handleChangeCourseware(1)"
+            @loadedmetadata="
+               () => {
+                  isTempAutoPlay = false
+               }
+            "
+            :autoPlay="true"
             @playbackRate="showController"
-            :autoPlay="videoIsAutoPlay"
             :disableEvents="true"
             :isShowController="isShowController"
          />
@@ -19,7 +24,7 @@
             <ElImage :hide-on-click-modal="true" fit="contain" :src="activeCourseware?.content" class="imgPlay" />
          </div>
          <div class="songPlayBox" v-if="fileType === 'SONG'">
-            <iframe class="songIframe" @mousemove="handleMousemove" :src="songPlaySrc" frameborder="0"></iframe>
+            <iframe ref="songPlayDom" class="songIframe" @mousemove="handleMousemove" :src="songPlaySrc" frameborder="0"></iframe>
          </div>
       </div>
       <div class="leftTools posTools">
@@ -57,22 +62,7 @@
             <img src="@/img/coursewarePlay/xia.png" />
             <!-- <div>下一个</div> -->
          </div>
-
-         <!-- <div class="posBtn" @click="handleCoursewareEnd">
-            <img src="@/img/coursewarePlay/jieshu.png" />
-            <div>结束</div>
-         </div> -->
       </div>
-      <!-- <div class="rightTools posTools">
-         <div class="posBtn" @click="drawerShow = true">
-            <img src="@/img/coursewarePlay/zhishidian.png" />
-            <div>知识点</div>
-         </div>
-         <div class="posBtn" @click="handleCoursewareEnd">
-            <img src="@/img/coursewarePlay/jieshu.png" />
-            <div>结束</div>
-         </div>
-      </div> -->
       <div
          v-if="activeCoursewareResourceId"
          @click="
@@ -90,8 +80,9 @@
             <div class="title-section">
                <div class="title">{{ activeCourseware?.parentData.name || "" }}</div>
                <div class="content">
-                  {{ activeCourseware?.name || "" }}
-                  <span v-if="activeCourseware?.phaseGoals" @click="onTitleTip('phaseGoals', activeCourseware?.phaseGoals)">阶段目标</span>
+                  <p>{{ activeCourseware?.name || "" }}</p>
+                  <!-- <span v-if="activeCourseware?.phaseGoals" @click="onTitleTip('phaseGoals', activeCourseware?.phaseGoals)">阶段目标</span> -->
+                  <span v-if="lessonTargetDetail" @click="onTitleTip('phaseGoals', lessonTargetDetail)">阶段目标</span>
                   <span v-if="activeCourseware?.checkItem" @click="onTitleTip('checkItem', activeCourseware?.checkItem)">检查事项</span>
                </div>
             </div>
@@ -110,17 +101,17 @@
             </div>
          </div>
       </div>
-      <el-drawer class="elDrawer" v-model="drawerShow" :show-close="false">
+      <el-drawer class="elDrawer" direction="ltr" v-model="drawerShow" :show-close="false">
          <template #header="{ close }">
             <img class="directory" src="@/img/coursewarePlay/kcml.png" />
-            <div class="tit">课程目录</div>
+            <div class="tit">知识点目录</div>
             <img class="close" @click="close" src="@/img/coursewarePlay/close.png" />
          </template>
          <ElScrollbar class="elScrollbar">
             <courseCollapse :activeCollapse="activeCourseware" :courseList="coursewareList" @handleClick="handleCourseClick" />
          </ElScrollbar>
       </el-drawer>
-      <el-drawer class="elDrawer elCourseMenu" v-model="drawerMenuShow" :show-close="false">
+      <el-drawer class="elDrawer elCourseMenu" direction="ltr" v-model="drawerMenuShow" :show-close="false">
          <template #header="{ close }">
             <img class="directory" src="@/img/coursewarePlay/menuActive.png" />
             <div class="tit">课程类型</div>
@@ -155,16 +146,21 @@ import useCoursewarePlayTip from "./components/useCoursewarePlayTip"
 import useDialogConfirm from "@/hooks/useDialogConfirm"
 import LoadingBar from "@/plugin/loadingBar"
 import { isPlay, penShow, toolOpen, whitePenShow } from "@/businessComponents/globalTools/globalTools"
+import { closeAllModalFrame } from "@/plugin/modalFrame"
 
 const route = useRoute()
 const router = useRouter()
 const userStoreHook = userStore()
 /* 获取资源 */
 const videoPlayDom = ref<InstanceType<typeof videoPlay>>()
+const songPlayDom = ref<any>() // 曲谱对象
+const lessonTargetDetail = ref<string>("") // 阶段目标
 const coursewareMenuList = shallowRef<any[]>([]) // 课程类型
 const coursewareList = shallowRef<any[]>([]) // 知识点
 const flattenCoursewareList = ref<any[]>([]) // 扁平化coursewareList
 const isCurrentCoursewareMenu = shallowRef(true) // 是否为当前选的课程类型
+const currentId = ref<any>(route.params.id)
+const isTempAutoPlay = ref(false)
 // 选中的知识点
 const activeCourseware = computed<undefined | Record<string, any>>(() => {
    return flattenCoursewareList.value[activeCoursewareIndex.value]
@@ -190,10 +186,11 @@ const songPlaySrc = computed<string>(() => {
    return urlObj[userStoreHook.roles!]
 })
 // 视频是否自动播放
-const videoIsAutoPlay = computed<boolean>(() => {
-   // 如果为视频且有阶段目前则不自动播放
-   return fileType.value === "VIDEO" && activeCourseware.value?.phaseGoals ? false : true
-})
+// const videoIsAutoPlay = computed<boolean>(() => {
+//    // 如果为视频且有阶段目前则不自动播放
+//    console.log(fileType.value, isTempAutoPlay.value, "isTempAutoPlay")
+//    return (fileType.value === "VIDEO" && activeCourseware.value?.phaseGoals) || isTempAutoPlay.value ? false : true
+// })
 const activeCoursewareIndex = ref(0)
 const drawerShow = ref(false)
 const drawerMenuShow = ref(false)
@@ -201,10 +198,6 @@ const drawerMenuShow = ref(false)
 const coursewareTotalTime = ref(0)
 // 监控播放
 watch(activeCourseware, () => {
-   handleVideoPause()
-   if (activeCourseware.value?.phaseGoals) {
-      onTitleTip("phaseGoals", activeCourseware.value?.phaseGoals)
-   }
    fileType.value === "VIDEO" &&
       nextTick(() => {
          handlePlayVideo({
@@ -224,7 +217,7 @@ async function getCoursewareList(id?: string) {
    }
    await httpAjaxErrMsg(LessonCoursewareDetailApi[userStoreHook.roles!], id || (route.params.id as string)).then(res => {
       if (res.code === 200) {
-         const { lockFlag, knowledgePointList } = res.data || {}
+         const { lockFlag, knowledgePointList, lessonTargetDesc } = res.data || {}
          if (lockFlag) {
             ElMessageBox.alert("课件已锁定", "温馨提示", {
                confirmButtonText: "退出",
@@ -251,6 +244,7 @@ async function getCoursewareList(id?: string) {
                })
             return
          }
+         lessonTargetDetail.value = lessonTargetDesc ? lessonTargetDesc.replace(/\n/g, "<br />") : ""
          // 处理返回的数据
          handlePointList(knowledgePointList)
       }
@@ -266,8 +260,8 @@ function getCoursewareMenuList(id?: string) {
    }
 
    httpAjaxErrMsg(LessonCoursewareMenuDetailApi[userStoreHook.roles!], {
-      lessonCoursewareDetailId: id || route.params.id
-      // courseScheduleId: "1844948199117283329"
+      lessonCoursewareDetailId: id || route.params.id,
+      courseScheduleId: route.query.modeId as any
    } as any).then(res => {
       if (res.code === 200) {
          coursewareMenuList.value = res.data || []
@@ -276,6 +270,8 @@ function getCoursewareMenuList(id?: string) {
 }
 let flattenCoursewareListData: any = [] // 临时扁平化数据
 function handlePointList(pointList: any[]) {
+   // 重置数据
+   coursewareTotalTime.value = 0
    coursewareList.value = filterPointList(pointList)
    // 如果url里面有materialId 代表指定资料播放
    if (route.query.materialId) {
@@ -322,22 +318,35 @@ function handleCourseClick(value: any) {
    drawerShow.value = false
 }
 async function handleCourseMenuClick(value: any) {
-   LoadingBar.loading(true)
-   flattenCoursewareListData = []
-   activeCoursewareIndex.value = -1
-   if (value.id === route.params.id) {
-      isCurrentCoursewareMenu.value = true
-   } else {
-      isCurrentCoursewareMenu.value = false
+   // 判断是否为当前课程类型
+   if (currentId.value === value.id) {
+      return
    }
+   LoadingBar.loading(true)
+   currentId.value = value.id
+   isCurrentCoursewareMenu.value = value.id === route.params.id ? true : false
+   flattenCoursewareListData = [] // 重置数据
+   isTempAutoPlay.value = true
    await getCoursewareList(value.id)
    getCoursewareMenuList(value.id)
    drawerMenuShow.value = false
    activeCoursewareIndex.value = 0
-
+   nextTick(() => {
+      //    if (!activeCourseware.value?.phaseGoals) {
+      // 切换之后默认打开课程目录
+      drawerShow.value = true
+      //    }
+   })
    LoadingBar.loading(false)
 }
 
+/** 曲目相关 */
+// 暂停曲目播放
+function handleSongPause() {
+   songPlayDom.value?.contentWindow?.postMessage({ api: "setPlayState" }, "*")
+   showController()
+}
+
 /* 播放器相关 */
 // 视频播放或者暂停
 function handleVideoPlay() {
@@ -380,18 +389,29 @@ function preventDefaultContextmenu(event: MouseEvent) {
 }
 function handleKeydown(e: KeyboardEvent) {
    const key = e.key
+
    if (key === " ") {
+      closeAllModalFrame()
+      drawerShow.value = false
       // 视频类型的时候才触发
       fileType.value === "VIDEO" && handleVideoPlay()
    } else if (key === "ArrowLeft") {
+      closeAllModalFrame()
+      drawerShow.value = false
       // 视频类型的时候才触发
       fileType.value === "VIDEO" && handleVideoSpeedCurrentTime("slow")
    } else if (key === "ArrowRight") {
+      closeAllModalFrame()
+      drawerShow.value = false
       // 视频类型的时候才触发
       fileType.value === "VIDEO" && handleVideoSpeedCurrentTime("fast")
    } else if (key === "ArrowDown") {
+      closeAllModalFrame()
+      drawerShow.value = false
       handleChangeCourseware(1)
    } else if (key === "ArrowUp") {
+      closeAllModalFrame()
+      drawerShow.value = false
       handleChangeCourseware(-1)
    }
 }
@@ -489,6 +509,7 @@ watch(
    () => {
       if (whitePenShow.value || penShow.value) {
          handleVideoPause()
+         handleSongPause()
       }
    }
 )
@@ -536,10 +557,6 @@ function onTitleTip(type: "phaseGoals" | "checkItem", text: string) {
          opacity: 0;
          transform: translate(-100%, -50%);
       }
-      .rightTools {
-         opacity: 0;
-         transform: translate(100%, -50%);
-      }
       .topTools {
          opacity: 0;
          transform: translateY(-100%);
@@ -553,10 +570,6 @@ function onTitleTip(type: "phaseGoals" | "checkItem", text: string) {
          opacity: initial;
          transform: translateY(-50%);
       }
-      .rightTools {
-         opacity: initial;
-         transform: translateY(-50%);
-      }
       .goPracticeBtn {
          transform: initial;
       }
@@ -591,7 +604,7 @@ function onTitleTip(type: "phaseGoals" | "checkItem", text: string) {
       top: 0;
       left: 0;
       width: 100%;
-      background: linear-gradient(180deg, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0) 100%);
+      background: linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);
       transition: all 0.5s;
       display: flex;
       align-items: flex-start;
@@ -620,16 +633,23 @@ function onTitleTip(type: "phaseGoals" | "checkItem", text: string) {
                font-size: 18px;
                color: #ffffff;
                line-height: 26px;
+               display: flex;
+               align-items: center;
+
+               p {
+                  line-height: 1;
+                  padding-top: 1px;
+               }
 
                span {
                   background: rgba(0, 0, 0, 0.1);
-                  border-radius: 11px;
+                  border-radius: 16px;
                   border: 1px solid rgba(255, 255, 255, 0.7);
                   font-size: 14px;
                   color: #ffffff;
                   line-height: 22px;
-                  padding: 1px 8px;
-                  margin-left: 6px;
+                  padding: 2px 10px;
+                  margin-left: 10px;
                   cursor: pointer;
                }
             }
@@ -648,6 +668,12 @@ function onTitleTip(type: "phaseGoals" | "checkItem", text: string) {
             img {
                width: 34px;
                height: 34px;
+               padding: 6px;
+               box-sizing: content-box;
+               &:hover {
+                  background-color: rgba(255, 255, 255, 0.2);
+                  border-radius: 6px;
+               }
             }
          }
       }
@@ -662,13 +688,8 @@ function onTitleTip(type: "phaseGoals" | "checkItem", text: string) {
          border-radius: 8px;
          left: 32px;
       }
-      &.rightTools {
-         right: 12px;
-      }
       .posBtn {
-         // background: rgba(0, 0, 0, 0.3);
-         // border-radius: 8px;
-         padding: 20px 12px;
+         padding: 14px 6px;
          font-weight: 500;
          font-size: 16px;
          color: #ffffff;
@@ -676,15 +697,21 @@ function onTitleTip(type: "phaseGoals" | "checkItem", text: string) {
          flex-direction: column;
          align-items: center;
          cursor: pointer;
-         &:hover {
-            opacity: $opacity-hover;
-         }
+         // &:hover {
+         //    opacity: $opacity-hover;
+         // }
          &.disabled {
             opacity: $opacity-disabled;
          }
          > img {
             width: 34px;
             height: 34px;
+            padding: 6px;
+            box-sizing: content-box;
+            &:hover {
+               background-color: rgba(255, 255, 255, 0.2);
+               border-radius: 6px;
+            }
          }
       }
    }

+ 40 - 9
src/views/coursewarePlay/videoPlay/videoPlay.vue

@@ -83,6 +83,7 @@ import { onMounted, onUnmounted, ref, reactive, watch, toRef, watchEffect } from
 import { UUID } from "@/libs/tools"
 import { formatTime } from "./tools"
 import { NSlider } from "naive-ui"
+import { ElMessage } from "element-plus"
 
 const props = defineProps<{
    disableEvents?: boolean
@@ -93,6 +94,7 @@ const emits = defineEmits<{
    (e: "ready"): void //播放器初始化完成
    (e: "ended"): void //播放结束
    (e: "playbackRate"): void //播放速度改动时候
+   (e: "loadedmetadata"): void // 播放器加载初始化数据时
 }>()
 const videoId = "video" + UUID()
 let playerVm: Record<string, any>
@@ -173,9 +175,11 @@ function initVideo() {
    })
    playerVm.on("loadedmetadata", () => {
       console.log("loadedmetadata")
-      if (props.autoPlay) {
+      if (props?.autoPlay) {
          playerVm.play()
       }
+
+      emits("loadedmetadata")
    })
    //总时长变化时候
    playerVm.on("durationchange", () => {
@@ -248,9 +252,30 @@ function pauseVideo() {
    showController()
 }
 // 循环播放
+let message: any = null
 function handleLoop() {
    playController.loop ? playerVm.loop(false) : playerVm.loop(true)
    playController.loop = playerVm.loop()
+
+   if (playController.loop) {
+      if (message) {
+         message.close()
+      }
+      message = ElMessage({
+         message: "已打开循环播放",
+         icon: "",
+         customClass: "defaultMessage"
+      })
+   } else {
+      if (message) {
+         message.close()
+      }
+      message = ElMessage({
+         message: "已关闭循环播放",
+         icon: "",
+         customClass: "defaultMessage"
+      })
+   }
 }
 // 播放速度
 function handlePalySpeedChange(value: number) {
@@ -332,8 +357,8 @@ defineExpose({
       width: 100%;
       left: 0;
       bottom: 0;
-      padding: 0 32px 22px;
-      background: linear-gradient(0deg, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0) 100%);
+      padding: 45px 32px 22px;
+      background: linear-gradient(0deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);
       color: #fff;
       transition: all 0.5s;
       // &:hover {   //取消鼠标移入不隐藏
@@ -363,18 +388,24 @@ defineExpose({
       .playController {
          display: flex;
          justify-content: space-between;
-         padding-top: 10px;
+         padding-top: 4px;
          .leftPlayController {
-            margin-left: -10px;
+            margin-left: -12px;
             display: flex;
             & > img {
                cursor: pointer;
-               width: 48px;
-               height: 48px;
-               margin-right: 30px;
+               width: 36px;
+               height: 36px;
+               margin-right: 18px;
+               padding: 6px;
+               box-sizing: content-box;
+               &:hover {
+                  background-color: rgba(255, 255, 255, 0.2);
+                  border-radius: 6px;
+               }
             }
             .loopImg {
-               width: 56px;
+               width: 42px;
             }
             & > :deep(.palySpeedPopover.el-popover.el-popper) {
                min-width: initial;

+ 3 - 0
vue.config.js

@@ -19,6 +19,9 @@ module.exports = defineConfig({
                         if (file.includes("coursewarePlay")) {
                            return true
                         }
+                        if (file.includes("globalTools")) {
+                           return true
+                        }
                         if (file.includes("normalize")) {
                            return true
                         }

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott