Bläddra i källkod

Merge branch 'hqyDev' of http://git.dayaedu.com/huangqiyong/pptList into dev-online

黄琪勇 7 månader sedan
förälder
incheckning
f04e018e17

+ 1 - 1
.env.development

@@ -1,5 +1,5 @@
 
-VITE_APP_URL = "http://192.168.3.122:9527/pptApi"
+VITE_APP_URL = "http://localhost:9527/pptApi"
 
 ## 云教练地址
 VITE_YJL_URL = "https://test.kt.colexiu.com/instrument"

+ 12 - 2
src/api/pptOperate.ts

@@ -13,7 +13,7 @@ export const getTeacherChapterKnowledgeMaterial = (id: string, fromType: queryPa
   })
 }
 
-// 保存信息
+// 老师端 保存信息
 export const putTeacherChapterKnowledgeMaterial = (data: { id: string; dataJson: string }) => {
   return httpAxios.axioseRquest({
     method: "post",
@@ -22,9 +22,19 @@ export const putTeacherChapterKnowledgeMaterial = (data: { id: string; dataJson:
   })
 }
 
+// 平台端 保存信息
+export const putChapterKnowledgeMaterialUpdate = (data: { id: string; dataJson: string }) => {
+  return httpAxios.axioseRquest({
+    method: "post",
+    url: "/edu-app/chapterKnowledgeMaterial/update",
+    data
+  })
+}
+
 // 获取曲目信息
-export const getMaterialQueryPage = (data: Record<string, any>) => {
+export const getMaterialQueryPage = (data: Record<string, any>, abortController: AbortController) => {
   return httpAxios.axioseRquest({
+    signal: abortController.signal,
     method: "post",
     url: "/edu-app/material/queryPage",
     data

+ 3 - 2
src/hooks/useCreateElement.ts

@@ -322,7 +322,7 @@ export default () => {
    * 创建云教练元素
    * @param url 云教练地址
    */
-  const createCloudCoachElement = (sid: string) => {
+  const createCloudCoachElement = (sid: string, title: string) => {
     createElement({
       type: "elf",
       subtype: "elf-sing-play",
@@ -332,7 +332,8 @@ export default () => {
       rotate: 0,
       left: 0,
       top: 0,
-      sid
+      sid,
+      title
     })
   }
 

+ 1 - 5
src/libs/jsonTool.ts

@@ -8,11 +8,7 @@ import { slides as slidesData } from "@/mocks/slides"
 export function getHttpJson(url: string): Promise<{ code: number; data: Record<string, any> }> {
   return new Promise((res, rej) => {
     axios
-      .get(url, {
-        headers: {
-          "Cache-Control": "max-age=3600"
-        }
-      })
+      .get(url)
       .then(resData => {
         if (resData.status === 200 && typeof resData.data === "object") {
           res({

+ 27 - 11
src/messageHooks/pptScreen.ts

@@ -1,28 +1,44 @@
-import { onMounted, onUnmounted, watch } from "vue"
+import { onMounted, onUnmounted, watch, type Ref, type ComputedRef } from "vue"
 import { useSlidesStore } from "@/store"
 
-export const changePageSlideMes = (changePageSlide: (type: "prev" | "next") => void) => {
+export const changePageSlideMes = (
+  execPrev: () => void,
+  execNext: () => void,
+  animationIndex: Ref<number>,
+  formatedAnimations: ComputedRef<any[]>
+) => {
   const slidesStore = useSlidesStore()
 
   /** 初始化ppt完成之后给父级传递消息 */
   function pptInitMes() {
-    window.parent.postMessage({ type: "initPPT", content: { slidesLen: slidesStore.slides.length } }, "*")
+    window.parent.postMessage(
+      { type: "initPPT", content: { slidesLen: slidesStore.slides.length, isAnimationed: animationIndex.value === formatedAnimations.value.length } },
+      "*"
+    )
   }
   function handleMessage(event: any) {
     const { type, content } = event.data || {}
     if (type === "changePageSlide") {
-      changePageSlide(content)
+      /*  翻页 */
+      if (content === "prev") {
+        execPrev()
+      } else if (content === "next") {
+        execNext()
+      }
     }
   }
 
   pptInitMes()
-  watch(
-    () => slidesStore.slideIndex,
-    () => {
-      // 翻页完成之后的事件
-      window.parent.postMessage({ type: "changeSlideIndex", content: { slideIndex: slidesStore.slideIndex } }, "*")
-    }
-  )
+  watch([() => slidesStore.slideIndex, animationIndex], () => {
+    // 翻页完成之后的事件  isAnimationed 动画结束
+    window.parent.postMessage(
+      {
+        type: "changeSlideIndex",
+        content: { slideIndex: slidesStore.slideIndex, isAnimationed: animationIndex.value === formatedAnimations.value.length }
+      },
+      "*"
+    )
+  })
   onMounted(() => {
     window.addEventListener("message", handleMessage)
   })

+ 6 - 2
src/store/pptWork.ts

@@ -1,6 +1,6 @@
 import { defineStore } from "pinia"
 import { store } from "./index"
-import { getTeacherChapterKnowledgeMaterial, putTeacherChapterKnowledgeMaterial } from "@/api/pptOperate"
+import { getTeacherChapterKnowledgeMaterial, putTeacherChapterKnowledgeMaterial, putChapterKnowledgeMaterialUpdate } from "@/api/pptOperate"
 import { httpAjaxErrMsg } from "@/plugins/httpAjax"
 import { useRoute } from "vue-router"
 import LoadingBar from "@/plugins/loadingBar"
@@ -10,6 +10,7 @@ import { ElMessage } from "element-plus"
 import { toBlob } from "html-to-image"
 import { useSlidesStore } from "@/store"
 import queryParams, { initQueryParams } from "@/queryParams"
+import router from "@/router"
 
 type pptWork = { id: string; coverImg: string; jsonUrl: string; isSave: boolean }
 
@@ -42,6 +43,9 @@ const useStore = defineStore("pptWork", {
               jsonToPpt(jsonRes.data)
             }
           }
+        } else {
+          // 获取不到ppt数据的时候 跳转到错误页面
+          router.replace("/err")
         }
         LoadingBar.loading(false)
       }
@@ -53,7 +57,7 @@ const useStore = defineStore("pptWork", {
       fileUpload(`${this.id}ppt`, blob, `${this.id}/`, false, { isLoading: false })
         .then(url => {
           const _time = Date.now()
-          httpAjaxErrMsg(putTeacherChapterKnowledgeMaterial, {
+          httpAjaxErrMsg(queryParams.fromType === "PLATFORM" ? putChapterKnowledgeMaterialUpdate : putTeacherChapterKnowledgeMaterial, {
             id: this.id,
             dataJson: JSON.stringify({
               coverImg: this.coverImg + `?v=_${_time}`, // 加上时间戳,防止资源更新之后的缓存

+ 3 - 0
src/types/slides.ts

@@ -625,11 +625,14 @@ export interface PPTAudioElement extends PPTBaseElement {
  * subtype: elf-sing-play
  *
  * sid: 曲子id
+ *
+ * title:曲目名称
  */
 export interface PPTCloudCoachElement extends PPTBaseElement {
   type: "elf"
   subtype: "elf-sing-play"
   sid: string
+  title: string
 }
 
 export type PPTElement =

+ 2 - 2
src/views/Editor/CanvasTool/index.vue

@@ -341,8 +341,8 @@ function handleUpload(fileData: UploadRequestOptions) {
 }
 
 // 处理云教练创建
-function handleCloudCoach(id: string) {
-  createCloudCoachElement(id)
+function handleCloudCoach(id: string, name: string) {
+  createCloudCoachElement(id, name)
   cloudCoachVisible.value = false
 }
 

+ 11 - 1
src/views/Editor/Thumbnails/index.vue

@@ -86,7 +86,7 @@
 </template>
 
 <script lang="ts" setup>
-import { computed, nextTick, ref, watch } from "vue"
+import { computed, nextTick, onMounted, ref, watch } from "vue"
 import { storeToRefs } from "pinia"
 import { useMainStore, useSlidesStore, useKeyboardStore } from "@/store"
 import { fillDigit } from "@/utils/common"
@@ -146,6 +146,16 @@ watch(
   }
 )
 
+// 从预览切换回来的时候 滚动到对应的位置
+onMounted(() => {
+  const activeThumbnailRef: HTMLElement = thumbnailsRef.value?.$el?.querySelector(".thumbnail-item.active")
+  if (thumbnailsRef.value && activeThumbnailRef && !isElementInViewport(activeThumbnailRef, thumbnailsRef.value.$el)) {
+    setTimeout(() => {
+      activeThumbnailRef.scrollIntoView()
+    }, 100)
+  }
+})
+
 // 切换页面
 const changeSlideIndex = (index: number) => {
   mainStore.setActiveElementIdList([])

+ 0 - 5
src/views/Screen/BaseView.vue

@@ -184,11 +184,6 @@ const contextmenus = (): ContextmenuItem[] => {
   }
   return menusData
 }
-
-defineExpose({
-  execPrev,
-  execNext
-})
 </script>
 
 <style lang="scss" scoped>

+ 2 - 17
src/views/Screen/PresenterView.vue

@@ -104,18 +104,8 @@ const timerlVisible = ref(false)
 const laserPen = ref(false)
 const screenStore = useScreenStore()
 
-const {
-  mousewheelListener,
-  touchStartListener,
-  touchEndListener,
-  turnPrevSlide,
-  turnNextSlide,
-  turnSlideToIndex,
-  turnSlideToId,
-  animationIndex,
-  execPrev,
-  execNext
-} = useExecPlay()
+const { mousewheelListener, touchStartListener, touchEndListener, turnPrevSlide, turnNextSlide, turnSlideToIndex, turnSlideToId, animationIndex } =
+  useExecPlay()
 
 const { slideWidth, slideHeight } = useSlideSize(slideListWrapRef)
 const { exitScreening } = useScreening()
@@ -194,11 +184,6 @@ const contextmenus = (): ContextmenuItem[] => {
   }
   return menusData
 }
-
-defineExpose({
-  execPrev,
-  execNext
-})
 </script>
 
 <style lang="scss" scoped>

+ 54 - 52
src/views/Screen/hooks/useExecPlay.ts

@@ -1,10 +1,11 @@
-import { onMounted, onUnmounted, ref } from 'vue'
-import { throttle } from 'lodash'
-import { storeToRefs } from 'pinia'
-import { useSlidesStore } from '@/store'
-import { KEYS } from '@/configs/hotkey'
-import { ANIMATION_CLASS_PREFIX } from '@/configs/animation'
-import message from '@/utils/message'
+import { onMounted, onUnmounted, ref } from "vue"
+import { throttle } from "lodash"
+import { storeToRefs } from "pinia"
+import { useSlidesStore, useScreenStore } from "@/store"
+import { KEYS } from "@/configs/hotkey"
+import { ANIMATION_CLASS_PREFIX } from "@/configs/animation"
+import message from "@/utils/message"
+import { changePageSlideMes } from "@/messageHooks/pptScreen"
 
 export default () => {
   const slidesStore = useSlidesStore()
@@ -41,21 +42,21 @@ export default () => {
       }
 
       const animationName = `${ANIMATION_CLASS_PREFIX}${animation.effect}`
-      
+
       // 执行动画前先清除原有的动画状态(如果有)
-      elRef.style.removeProperty('--animate-duration')
+      elRef.style.removeProperty("--animate-duration")
       for (const classname of elRef.classList) {
         if (classname.indexOf(ANIMATION_CLASS_PREFIX) !== -1) elRef.classList.remove(classname, `${ANIMATION_CLASS_PREFIX}animated`)
       }
-      
+
       // 执行动画
-      elRef.style.setProperty('--animate-duration', `${animation.duration}ms`)
+      elRef.style.setProperty("--animate-duration", `${animation.duration}ms`)
       elRef.classList.add(animationName, `${ANIMATION_CLASS_PREFIX}animated`)
 
       // 执行动画结束,将“退场”以外的动画状态清除
       const handleAnimationEnd = () => {
-        if (animation.type !== 'out') {
-          elRef.style.removeProperty('--animate-duration')
+        if (animation.type !== "out") {
+          elRef.style.removeProperty("--animate-duration")
           elRef.classList.remove(animationName, `${ANIMATION_CLASS_PREFIX}animated`)
         }
 
@@ -66,14 +67,14 @@ export default () => {
           if (autoNext) runAnimation()
         }
       }
-      elRef.addEventListener('animationend', handleAnimationEnd, { once: true })
+      elRef.addEventListener("animationend", handleAnimationEnd, { once: true })
     }
   }
 
   onMounted(() => {
     const firstAnimations = formatedAnimations.value[0]
     if (firstAnimations && firstAnimations.animations.length) {
-      const autoExecFirstAnimations = firstAnimations.animations.every(item => item.trigger === 'auto' || item.trigger === 'meantime')
+      const autoExecFirstAnimations = firstAnimations.animations.every(item => item.trigger === "auto" || item.trigger === "meantime")
       if (autoExecFirstAnimations) runAnimation()
     }
   })
@@ -86,15 +87,15 @@ export default () => {
     for (const animation of animations) {
       const elRef: HTMLElement | null = document.querySelector(`#screen-element-${animation.elId} [class^=base-element-]`)
       if (!elRef) continue
-      
-      elRef.style.removeProperty('--animate-duration')
+
+      elRef.style.removeProperty("--animate-duration")
       for (const classname of elRef.classList) {
         if (classname.indexOf(ANIMATION_CLASS_PREFIX) !== -1) elRef.classList.remove(classname, `${ANIMATION_CLASS_PREFIX}animated`)
       }
     }
 
     // 如果撤销时该位置有且仅有强调动画,则继续执行一次撤销
-    if (animations.every(item => item.type === 'attention')) execPrev()
+    if (animations.every(item => item.type === "attention")) execPrev()
   }
 
   // 关闭自动播放
@@ -113,9 +114,13 @@ export default () => {
     loopPlay.value = loop
   }
 
-  const throttleMassage = throttle(function(msg) {
-    message.success(msg)
-  }, 1000, { leading: true, trailing: false })
+  const throttleMassage = throttle(
+    function (msg) {
+      message.success(msg)
+    },
+    1000,
+    { leading: true, trailing: false }
+  )
 
   // 向上/向下播放
   // 遇到元素动画时,优先执行动画播放,无动画则执行翻页
@@ -124,34 +129,29 @@ export default () => {
   const execPrev = () => {
     if (formatedAnimations.value.length && animationIndex.value > 0) {
       revokeAnimation()
-    }
-    else if (slideIndex.value > 0) {
+    } else if (slideIndex.value > 0) {
       slidesStore.updateSlideIndex(slideIndex.value - 1)
       if (slideIndex.value < playedSlidesMinIndex.value) {
         animationIndex.value = 0
         playedSlidesMinIndex.value = slideIndex.value
-      }
-      else animationIndex.value = formatedAnimations.value.length
-    }
-    else {
+      } else animationIndex.value = formatedAnimations.value.length
+    } else {
       if (loopPlay.value) turnSlideToIndex(slides.value.length - 1)
-      else throttleMassage('已经是第一页了')
+      else throttleMassage("已经是第一页了")
     }
     inAnimation.value = false
   }
   const execNext = () => {
     if (formatedAnimations.value.length && animationIndex.value < formatedAnimations.value.length) {
       runAnimation()
-    }
-    else if (slideIndex.value < slides.value.length - 1) {
+    } else if (slideIndex.value < slides.value.length - 1) {
       slidesStore.updateSlideIndex(slideIndex.value + 1)
       animationIndex.value = 0
       inAnimation.value = false
-    }
-    else {
+    } else {
       if (loopPlay.value) turnSlideToIndex(0)
       else {
-        throttleMassage('已经是最后一页了')
+        throttleMassage("已经是最后一页了")
         closeAutoPlay()
       }
       inAnimation.value = false
@@ -162,7 +162,7 @@ export default () => {
   const autoPlayInterval = ref(2500)
   const autoPlay = () => {
     closeAutoPlay()
-    message.success('开始自动放映')
+    message.success("开始自动放映")
     autoPlayTimer.value = setInterval(execNext, autoPlayInterval.value)
   }
 
@@ -173,18 +173,22 @@ export default () => {
   }
 
   // 鼠标滚动翻页
-  const mousewheelListener = throttle(function(e: WheelEvent) {
-    if (e.deltaY < 0) execPrev()
-    else if (e.deltaY > 0) execNext()
-  }, 500, { leading: true, trailing: false })
+  const mousewheelListener = throttle(
+    function (e: WheelEvent) {
+      if (e.deltaY < 0) execPrev()
+      else if (e.deltaY > 0) execNext()
+    },
+    500,
+    { leading: true, trailing: false }
+  )
 
   // 触摸屏上下滑动翻页
-  const touchInfo = ref<{ x: number; y: number; } | null>(null)
+  const touchInfo = ref<{ x: number; y: number } | null>(null)
 
   const touchStartListener = (e: TouchEvent) => {
     touchInfo.value = {
       x: e.changedTouches[0].pageX,
-      y: e.changedTouches[0].pageY,
+      y: e.changedTouches[0].pageY
     }
   }
   const touchEndListener = (e: TouchEvent) => {
@@ -193,7 +197,7 @@ export default () => {
     const offsetX = Math.abs(touchInfo.value.x - e.changedTouches[0].pageX)
     const offsetY = e.changedTouches[0].pageY - touchInfo.value.y
 
-    if ( Math.abs(offsetY) > offsetX && Math.abs(offsetY) > 50 ) {
+    if (Math.abs(offsetY) > offsetX && Math.abs(offsetY) > 50) {
       touchInfo.value = null
 
       if (offsetY > 0) execPrev()
@@ -206,17 +210,11 @@ export default () => {
     const key = e.key.toUpperCase()
 
     if (key === KEYS.UP || key === KEYS.LEFT || key === KEYS.PAGEUP) execPrev()
-    else if (
-      key === KEYS.DOWN || 
-      key === KEYS.RIGHT ||
-      key === KEYS.SPACE || 
-      key === KEYS.ENTER ||
-      key === KEYS.PAGEDOWN
-    ) execNext()
+    else if (key === KEYS.DOWN || key === KEYS.RIGHT || key === KEYS.SPACE || key === KEYS.ENTER || key === KEYS.PAGEDOWN) execNext()
   }
 
-  onMounted(() => document.addEventListener('keydown', keydownListener))
-  onUnmounted(() => document.removeEventListener('keydown', keydownListener))
+  onMounted(() => document.addEventListener("keydown", keydownListener))
+  onUnmounted(() => document.removeEventListener("keydown", keydownListener))
 
   // 切换到上一张/上一张幻灯片(无视元素的入场动画)
   const turnPrevSlide = () => {
@@ -240,7 +238,11 @@ export default () => {
       animationIndex.value = 0
     }
   }
-
+  const screenStore = useScreenStore()
+  if (["pptScreen", "mobileScreen"].includes(screenStore.mode)) {
+    // mes 翻页
+    changePageSlideMes(execPrev, execNext, animationIndex, formatedAnimations)
+  }
   return {
     autoPlayTimer,
     autoPlayInterval,
@@ -258,6 +260,6 @@ export default () => {
     turnSlideToId,
     execPrev,
     execNext,
-    animationIndex,
+    animationIndex
   }
 }

+ 2 - 14
src/views/Screen/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="pptist-screen">
-    <BaseView ref="screenViewDom" :changeViewMode="changeViewMode" v-if="viewMode === 'base'" />
-    <PresenterView ref="screenViewDom" :changeViewMode="changeViewMode" v-else-if="viewMode === 'presenter'" />
+    <BaseView :changeViewMode="changeViewMode" v-if="viewMode === 'base'" />
+    <PresenterView :changeViewMode="changeViewMode" v-else-if="viewMode === 'presenter'" />
   </div>
 </template>
 
@@ -12,7 +12,6 @@ import useScreening from "@/hooks/useScreening"
 
 import BaseView from "./BaseView.vue"
 import PresenterView from "./PresenterView.vue"
-import { changePageSlideMes } from "@/messageHooks/pptScreen"
 
 const viewMode = ref<"base" | "presenter">("base")
 
@@ -22,17 +21,6 @@ const changeViewMode = (mode: "base" | "presenter") => {
 
 const { exitScreening } = useScreening()
 
-const screenViewDom = ref()
-// mes 翻页
-changePageSlideMes((type: "prev" | "next") => {
-  /*  翻页 */
-  if (type === "prev") {
-    screenViewDom.value.execPrev()
-  } else if (type === "next") {
-    screenViewDom.value.execNext()
-  }
-})
-
 // 快捷键退出放映
 const keydownListener = (e: KeyboardEvent) => {
   const key = e.key.toUpperCase()

+ 15 - 2
src/views/components/element/cloudCoachElement/BaseCloudCoachElement.vue

@@ -9,17 +9,23 @@
     }"
   >
     <div class="rotate-wrapper" :style="{ transform: `rotate(${elementInfo.rotate}deg)` }">
-      <div class="element-content"></div>
+      <div class="element-content">
+        <div class="title" :style="{ fontSize: 14 / scale + 'px' }">{{ elementInfo.title || "乐谱" }}</div>
+      </div>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
 import type { PPTCloudCoachElement } from "@/types/slides"
+import { ref, inject } from "vue"
+import { injectKeySlideScale } from "@/types/injectKey"
 
 defineProps<{
   elementInfo: PPTCloudCoachElement
 }>()
+
+const scale = inject(injectKeySlideScale) || ref(1)
 </script>
 
 <style lang="scss" scoped>
@@ -36,7 +42,14 @@ defineProps<{
   display: flex;
   justify-content: center;
   align-items: center;
-  background: url("./cloudCoachList//imgs/musicBg.png") no-repeat;
+  background: url("./cloudCoachList/imgs/musicBg.png") no-repeat;
   background-size: 100% 100%;
+  .title {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    padding: 0 40px;
+    color: #fff;
+  }
 }
 </style>

+ 89 - 28
src/views/components/element/cloudCoachElement/cloudCoachList/cloudCoachList.vue

@@ -23,7 +23,7 @@
           </div>
         </div>
         <div class="query">
-          <Input :placeholder="'请输入搜索关键词'" v-model:value="queryData.name">
+          <Input :placeholder="'请输入搜索关键词'" v-model:value="queryData.name" @enter="handleQuery">
             <template #prefix>
               <img class="img" src="./imgs/query.png" alt="" />
             </template>
@@ -34,7 +34,7 @@
         </div>
       </div>
       <div class="musicListCon">
-        <div class="queryFrom">
+        <div class="queryFrom" :class="{ isExpandAct: !isExpand }">
           <div v-show="queryData.sourceType === 2" class="queryFromList">
             <div class="tit">教程:</div>
             <div class="queryFromCon">
@@ -97,6 +97,10 @@
             </div>
           </div>
         </div>
+        <div v-show="queryData.sourceType === 2" @click="isExpand = !isExpand" class="isExpand" :class="{ active: isExpand }">
+          <div>{{ isExpand ? "收起" : "展开" }}</div>
+          <img src="./imgs/jiao.png" alt="" />
+        </div>
         <div class="musicListConBox" v-loading="loading">
           <div class="musicList" :class="{ empty: !musicList.length && !loading }">
             <div class="musicListBox" v-if="musicList.length && !loading">
@@ -122,8 +126,14 @@
                   </div>
                 </div>
                 <div class="musicRight">
-                  <img class="sc" @click="handleFavorite(item)" :src="item.favoriteFlag ? scActImg : scImg" alt="" />
-                  <div class="addBtn" @click="handleAddMusic(item.id)">添加</div>
+                  <img
+                    v-if="queryParams.fromType !== 'PLATFORM'"
+                    class="sc"
+                    @click="handleFavorite(item)"
+                    :src="item.favoriteFlag ? scActImg : scImg"
+                    alt=""
+                  />
+                  <div class="addBtn" @click="handleAddMusic(item.id, item.name)">添加</div>
                 </div>
               </div>
             </div>
@@ -151,35 +161,44 @@ import { httpAjax } from "@/plugins/httpAjax"
 import queryParams from "@/queryParams"
 import scActImg from "./imgs/scAct.png"
 import scImg from "./imgs/sc.png"
+import { CODE_ERR_CANCELED } from "@/libs/auth"
 
 const emits = defineEmits<{
-  (event: "update", id: string): void
+  (event: "update", id: string, name: string): void
   (event: "close"): void
 }>()
 
-function handleAddMusic(id: string) {
-  emits("update", id)
+function handleAddMusic(id: string, name: string) {
+  emits("update", id, name)
   emits("close")
 }
 
-const tabData = [
-  {
-    label: "相关资源",
-    value: 5
-  },
-  {
-    label: "共享资源",
-    value: 2
-  },
-  {
-    label: "我的资源",
-    value: 3
-  },
-  {
-    label: "我的收藏",
-    value: 4
-  }
-]
+const tabData =
+  queryParams.fromType === "PLATFORM"
+    ? [
+        {
+          label: "共享资源",
+          value: 2
+        }
+      ]
+    : [
+        {
+          label: "相关资源",
+          value: 5
+        },
+        {
+          label: "共享资源",
+          value: 2
+        },
+        {
+          label: "我的资源",
+          value: 3
+        },
+        {
+          label: "我的收藏",
+          value: 4
+        }
+      ]
 // 场景
 const audioPlayTypesOption = [
   { text: "全部", value: "" },
@@ -196,7 +215,7 @@ const queryData = reactive({
   page: 1,
   rows: 21,
   total: 0,
-  sourceType: 5,
+  sourceType: tabData[0].value,
   name: "",
   bookVersionId: "",
   audioPlayTypes: "",
@@ -209,6 +228,7 @@ const queryData = reactive({
 const musicList = ref<any[]>([])
 const loading = ref(true)
 const vLoading = ElLoading.directive
+const isExpand = ref(true)
 
 getQueryList()
 function getQueryList() {
@@ -270,6 +290,7 @@ function clearQueryData() {
 }
 function handleTabChange(sourceType: number) {
   clearQueryData()
+  isExpand.value = true
   queryData.sourceType = sourceType
   handleQuery()
 }
@@ -301,6 +322,8 @@ function handleQuery() {
   queryData.rows = 21
   handleGetQuery()
 }
+
+let controller: AbortController
 function handleGetQuery() {
   loading.value = true
   let { sourceType, subject, audioPlayTypes, name, page, rows, bookVersionId } = queryData
@@ -367,7 +390,15 @@ function handleGetQuery() {
       audioPlayTypes: audioPlayTypesParams
     }
   }
-  httpAjax(getMaterialQueryPage, params).then(res => {
+  if (controller) {
+    controller.abort()
+  }
+  controller = new AbortController()
+  httpAjax(getMaterialQueryPage, params, controller).then(res => {
+    // 自己关闭的时候不取消加载
+    if (res.code === CODE_ERR_CANCELED) {
+      return
+    }
     if (res.code === 200) {
       musicList.value = res.data.rows.map((item: any) => {
         item.name = highlightedText(item.name, queryData.name)
@@ -537,6 +568,11 @@ const highlightedText = (text: string, query: string) => {
       display: flex;
       flex-direction: column;
       .queryFrom {
+        &.isExpandAct {
+          height: 42px;
+          overflow: hidden;
+        }
+        flex-shrink: 0;
         padding: 0 30px;
         .queryFromList {
           display: flex;
@@ -585,6 +621,30 @@ const highlightedText = (text: string, query: string) => {
           }
         }
       }
+      .isExpand {
+        flex-shrink: 0;
+        margin-bottom: 12px;
+        cursor: pointer;
+        display: flex;
+        justify-content: center;
+        font-weight: 400;
+        font-size: 14px;
+        color: #198cfe;
+        line-height: 20px;
+        align-items: center;
+        &:hover {
+          opacity: 0.8;
+        }
+        &.active > img {
+          transform: rotate(0deg);
+        }
+        & > img {
+          transform: rotate(180deg);
+          margin-left: 4px;
+          width: 10px;
+          height: 10px;
+        }
+      }
       .musicListConBox {
         flex-grow: 1;
         overflow: hidden;
@@ -613,6 +673,7 @@ const highlightedText = (text: string, query: string) => {
               display: flex;
               justify-content: space-between;
               align-items: center;
+              height: 102px;
               &:nth-last-child(-n + 3) {
                 margin-bottom: 0;
               }
@@ -727,7 +788,7 @@ const highlightedText = (text: string, query: string) => {
                 }
                 .addBtn {
                   margin-left: 12px;
-                  width: 58px;
+                  width: 54px;
                   height: 26px;
                   background: #198cfe;
                   border-radius: 4px;

BIN
src/views/components/element/cloudCoachElement/cloudCoachList/imgs/jiao.png


BIN
src/views/components/element/cloudCoachElement/cloudCoachList/imgs/musicBg.png


+ 30 - 17
src/views/components/element/cloudCoachElement/cloudCoachPlayer/cloudCoachPlayer.vue

@@ -8,8 +8,12 @@
     }"
   >
     <div v-if="loading" class="loading-overlay">
-      <div class="spinner"></div>
-      <div class="text">云教练加载中...</div>
+      <div class="loadingBox">
+        <div class="loadingItem"></div>
+        <div class="loadingItem"></div>
+        <div class="loadingItem"></div>
+        <div class="loadingItem"></div>
+      </div>
     </div>
     <iframe class="musicIframe" frameborder="0" :src="url" @load="handleIframeLoad"></iframe>
   </div>
@@ -37,7 +41,7 @@ const url = computed(() => {
 })
 
 // 先关闭这个功能
-const loading = ref(false)
+const loading = ref(true)
 function handleIframeLoad() {
   loading.value = false
 }
@@ -69,23 +73,32 @@ function handleIframeLoad() {
     flex-direction: column;
     z-index: 10;
     color: #fff;
-    background-color: #213793;
-    .spinner {
-      border: 4px solid #f3f3f3;
-      border-top: 4px solid #213793;
-      border-radius: 50%;
-      width: 40px;
-      height: 40px;
-      animation: spin 1s linear infinite;
-    }
-    .text {
-      margin-top: 10px;
+    background: url("../cloudCoachList/imgs/musicBg.png");
+    background-size: cover;
+    .loadingBox {
+      width: 30px;
+      height: 30px;
+      display: flex;
+      justify-content: space-between;
+      flex-wrap: wrap;
+      align-content: space-between;
+      animation: rotate 1.5s linear infinite;
+      .loadingItem {
+        width: 12px;
+        height: 12px;
+        border-radius: 50%;
+        background: #20bdff;
+        opacity: 0.5;
+        &:nth-child(2) {
+          opacity: 1;
+        }
+      }
     }
-    @keyframes spin {
-      0% {
+    @keyframes rotate {
+      from {
         transform: rotate(0deg);
       }
-      100% {
+      to {
         transform: rotate(360deg);
       }
     }

+ 1 - 1
src/viewsframe/errorPage/errorPage.vue

@@ -3,7 +3,7 @@
     <div class="error">
       <img src="./imgs/404.png" class="img" alt="" />
       <div class="tit">页面找不到了~</div>
-      <ElButton class="backBtn" type="primary" plain @click="handleGoHome">返回</ElButton>
+      <!-- <ElButton class="backBtn" type="primary" plain @click="handleGoHome">返回</ElButton> -->
     </div>
   </div>
 </template>