Ver Fonte

乐理资源 模块添加

黄琪勇 há 1 mês atrás
pai
commit
a94df61d61
24 ficheiros alterados com 469 adições e 24 exclusões
  1. 2 1
      src/api/musicResources.ts
  2. 23 1
      src/hooks/useCreateElement.ts
  3. 4 0
      src/messageHooks/mobileScreen.ts
  4. 26 1
      src/types/slides.ts
  5. 3 1
      src/views/Editor/Canvas/EditableElement.vue
  6. 2 2
      src/views/Editor/Canvas/hooks/useDragElement.ts
  7. 6 4
      src/views/Editor/CanvasTool/index.vue
  8. 2 2
      src/views/Editor/Toolbar/ElementPositionPanel.vue
  9. 10 0
      src/views/Editor/Toolbar/ElementStylePanel/MusicResourcesStylePanel.vue
  10. 3 1
      src/views/Editor/Toolbar/ElementStylePanel/index.vue
  11. 1 1
      src/views/Editor/Toolbar/index.vue
  12. 3 1
      src/views/Mobile/MobileEditor/MobileEditableElement.vue
  13. 9 0
      src/views/Screen/BaseView.vue
  14. 3 1
      src/views/Screen/ScreenElement.vue
  15. 3 1
      src/views/components/ThumbnailSlide/ThumbnailElement.vue
  16. 62 0
      src/views/components/element/musicResourcesElement/BaseMusicResourcesElement.vue
  17. 58 0
      src/views/components/element/musicResourcesElement/ScreenMusicResourcesElement.vue
  18. 13 4
      src/views/components/element/musicResourcesElement/index.ts
  19. 122 0
      src/views/components/element/musicResourcesElement/musicResourcesElement.vue
  20. BIN
      src/views/components/element/musicResourcesElement/musicResourcesList/imgs/musicBg.png
  21. 2 1
      src/views/components/element/musicResourcesElement/musicResourcesList/musicPreview.vue
  22. 3 2
      src/views/components/element/musicResourcesElement/musicResourcesList/musicResourcesList.vue
  23. 2 0
      src/views/components/element/musicResourcesElement/musicResourcesPlayer/index.ts
  24. 107 0
      src/views/components/element/musicResourcesElement/musicResourcesPlayer/musicResourcesPlayer.vue

+ 2 - 1
src/api/musicResources.ts

@@ -1,4 +1,5 @@
 import { httpAxios } from "@/api/ApiInstance"
+import { type pptContentType } from "@/views/components/element/musicResourcesElement"
 
 /**
  * 获取乐理知识 旁边的列表
@@ -18,7 +19,7 @@ export const getListKnowledge = () => {
  * 获取查询配置
  */
 
-export const getKnowledgeWikiCategoryType = (type: "MUSIC" | "INSTRUMENT" | "MUSICIAN") => {
+export const getKnowledgeWikiCategoryType = (type: Exclude<pptContentType, "THEORY">) => {
   return httpAxios.axioseRquest({
     method: "post",
     url: "/edu-app/knowledgeWikiCategoryType/page",

+ 23 - 1
src/hooks/useCreateElement.ts

@@ -7,6 +7,7 @@ import { type ShapePoolItem, SHAPE_PATH_FORMULAS } from "@/configs/shapes"
 import type { LinePoolItem } from "@/configs/lines"
 import { CHART_DEFAULT_DATA } from "@/configs/chart"
 import useHistorySnapshot from "@/hooks/useHistorySnapshot"
+import { type pptContentType } from "@/views/components/element/musicResourcesElement"
 
 interface CommonElementPosition {
   top: number
@@ -396,6 +397,26 @@ export default () => {
       top: 0
     })
   }
+
+  /**
+   * 音乐资源
+   */
+  const createMusicResourcesElement = (sid: string, name: string, sType: pptContentType) => {
+    createElement({
+      type: "elf",
+      subtype: "elf-music-resources",
+      sid,
+      name,
+      sType,
+      id: nanoid(10),
+      width: viewportSize.value,
+      height: viewportSize.value * viewportRatio.value,
+      rotate: 0,
+      left: 0,
+      top: 0
+    })
+  }
+
   return {
     createImageElement,
     createChartElement,
@@ -409,6 +430,7 @@ export default () => {
     createCloudCoachElement,
     createEnjoyElement,
     createListeningPracticeElement,
-    createRhythmPracticeElement
+    createRhythmPracticeElement,
+    createMusicResourcesElement
   }
 }

+ 4 - 0
src/messageHooks/mobileScreen.ts

@@ -3,6 +3,10 @@ import { onMounted, onUnmounted } from "vue"
 
 export const changeToggeMes = () => {
   function handleMessage(event: any) {
+    // 当这个页面不是 iframe包裹的时候  会循环触发headerTogge  因为window.parent === window 相等 所以排除掉这个
+    if (window.parent === window) {
+      return
+    }
     const { api, playState } = event.data || {}
     if (api === "headerTogge") {
       window.parent.postMessage(

+ 26 - 1
src/types/slides.ts

@@ -37,7 +37,8 @@ export const enum ElementSubtypeTypes {
   SING_PLAY = "elf-sing-play",
   ENJOY = "elf-enjoy",
   LISTENING_PRACTICE = "elf-listening-practice",
-  RHYTHM_PRACTICE = "elf-rhythm-practice"
+  RHYTHM_PRACTICE = "elf-rhythm-practice",
+  MUSIC_RESOURCES = "elf-music-resources"
 }
 
 /**
@@ -701,6 +702,29 @@ export interface PPTRhythmPracticeElement extends PPTBaseElement {
   dataJson: string
 }
 
+/**
+ * 音乐知识
+ *
+ * type: elf
+ *
+ * subtype: elf-music-resources
+ *
+ * sid: 资源id
+ *
+ * name: 资源名称
+ *
+ * sType: 资源类型
+ *
+ */
+import { type pptContentType } from "@/views/components/element/musicResourcesElement"
+export interface PPTMusicResourcesElement extends PPTBaseElement {
+  type: "elf"
+  subtype: "elf-music-resources"
+  sid: string
+  name: string
+  sType: pptContentType
+}
+
 export type PPTElement =
   | PPTTextElement
   | PPTImageElement
@@ -715,6 +739,7 @@ export type PPTElement =
   | PPTEnjoyElement
   | PPTListeningPracticeElement
   | PPTRhythmPracticeElement
+  | PPTMusicResourcesElement
 
 export type AnimationType = "in" | "out" | "attention"
 export type AnimationTrigger = "click" | "meantime" | "auto"

+ 3 - 1
src/views/Editor/Canvas/EditableElement.vue

@@ -39,6 +39,7 @@ import cloudCoachElement from "@/views/components/element/cloudCoachElement"
 import enjoyElement from "@/views/components/element/enjoyElement"
 import listeningPracticeElement from "@/views/components/element/listeningPracticeElement"
 import rhythmPracticeElement from "@/views/components/element/rhythmPracticeElement"
+import musicResourcesElement from "@/views/components/element/musicResourcesElement"
 
 const props = defineProps<{
   elementInfo: PPTElement
@@ -65,7 +66,8 @@ const currentElementComponent = computed<unknown>(() => {
     [ElementSubtypeTypes.SING_PLAY]: cloudCoachElement,
     [ElementSubtypeTypes.ENJOY]: enjoyElement,
     [ElementSubtypeTypes.LISTENING_PRACTICE]: listeningPracticeElement,
-    [ElementSubtypeTypes.RHYTHM_PRACTICE]: rhythmPracticeElement
+    [ElementSubtypeTypes.RHYTHM_PRACTICE]: rhythmPracticeElement,
+    [ElementSubtypeTypes.MUSIC_RESOURCES]: musicResourcesElement
   }
   return elementTypeMap[props.elementInfo.type] || elementSubtypeMap[props.elementInfo.subtype] || null
 })

+ 2 - 2
src/views/Editor/Canvas/hooks/useDragElement.ts

@@ -25,7 +25,7 @@ export default (elementList: Ref<PPTElement[]>, alignmentLines: Ref<AlignmentLin
       if (
         activeElementIdList.value.includes(item.id) &&
         item.type === "elf" &&
-        ["elf-sing-play", "elf-listening-practice", "elf-rhythm-practice"].includes(item.subtype)
+        ["elf-sing-play", "elf-listening-practice", "elf-rhythm-practice", "elf-music-resources"].includes(item.subtype)
       ) {
         item.isMove = true
       }
@@ -298,7 +298,7 @@ export default (elementList: Ref<PPTElement[]>, alignmentLines: Ref<AlignmentLin
         if (
           activeElementIdList.value.includes(item.id) &&
           item.type === "elf" &&
-          ["elf-sing-play", "elf-listening-practice", "elf-rhythm-practice"].includes(item.subtype)
+          ["elf-sing-play", "elf-listening-practice", "elf-rhythm-practice", "elf-music-resources"].includes(item.subtype)
         ) {
           item.isMove = false
         }

+ 6 - 4
src/views/Editor/CanvasTool/index.vue

@@ -464,6 +464,7 @@ import musicTheoryList from "@/views/components/element/musicResourcesElement/mu
 import musicResourcesList from "@/views/components/element/musicResourcesElement/musicResourcesList"
 import fileUpload from "@/utils/oss-file-upload"
 import usePptWork from "@/store/pptWork"
+import { type pptContentType } from "@/views/components/element/musicResourcesElement"
 
 const useSlidesHook = useSlidesStore()
 
@@ -496,7 +497,8 @@ const {
   createCloudCoachElement,
   createEnjoyElement,
   createListeningPracticeElement,
-  createRhythmPracticeElement
+  createRhythmPracticeElement,
+  createMusicResourcesElement
 } = useCreateElement()
 
 const insertImageElement = (files: FileList) => {
@@ -520,7 +522,7 @@ const listeningPracticeVisible = ref(false)
 const rhythmPracticeVisible = ref(false)
 const musicTheoryVisible = ref(false)
 const musicResourcesVisible = ref(false)
-const musicResourcesType = ref<"MUSIC" | "INSTRUMENT" | "MUSICIAN">("INSTRUMENT")
+const musicResourcesType = ref<Exclude<pptContentType, "THEORY">>("INSTRUMENT")
 
 // 音视频
 function handleUpload(fileData: UploadRequestOptions) {
@@ -612,8 +614,8 @@ function handleResources(item: Record<string, any>) {
 }
 
 // 音乐知识
-function handleAddMusicResources(item: Record<string, any>, type: string) {
-  console.log(item, type, "添加")
+function handleAddMusicResources(item: Record<string, any>, type: pptContentType) {
+  createMusicResourcesElement(item.id, item.name, type)
   musicTheoryVisible.value = false
   musicResourcesVisible.value = false
 }

+ 2 - 2
src/views/Editor/Toolbar/ElementPositionPanel.vue

@@ -42,7 +42,7 @@
       <div class="row">
         <NumberInput
           :min="minSize"
-          :max="1500"
+          :max="1920"
           :step="5"
           :disabled="isVerticalText"
           :value="width"
@@ -58,7 +58,7 @@
         <div style="width: 10%" v-else></div>
         <NumberInput
           :min="minSize"
-          :max="800"
+          :max="1080"
           :step="5"
           :disabled="isHorizontalText || handleElement!.type === 'table'"
           :value="height"

+ 10 - 0
src/views/Editor/Toolbar/ElementStylePanel/MusicResourcesStylePanel.vue

@@ -0,0 +1,10 @@
+<!--
+* 音乐资源设置
+-->
+<template>
+  <div class=""></div>
+</template>
+
+<script setup lang="ts"></script>
+
+<style lang="scss" scoped></style>

+ 3 - 1
src/views/Editor/Toolbar/ElementStylePanel/index.vue

@@ -24,6 +24,7 @@ import CloudCoachStylePanel from "./CloudCoachStylePanel.vue"
 import EnjoyStylePanel from "./EnjoyStylePanel.vue"
 import ListeningPracticeStylePanel from "./ListeningPracticeStylePanel.vue"
 import RhythmPracticeStylePanel from "./RhythmPracticeStylePanel.vue"
+import MusicResourcesStylePanel from "./MusicResourcesStylePanel.vue"
 
 const panelMap = {
   [ElementTypes.TEXT]: TextStylePanel,
@@ -41,7 +42,8 @@ const elementSubtypeMap = {
   [ElementSubtypeTypes.SING_PLAY]: CloudCoachStylePanel,
   [ElementSubtypeTypes.ENJOY]: EnjoyStylePanel,
   [ElementSubtypeTypes.LISTENING_PRACTICE]: ListeningPracticeStylePanel,
-  [ElementSubtypeTypes.RHYTHM_PRACTICE]: RhythmPracticeStylePanel
+  [ElementSubtypeTypes.RHYTHM_PRACTICE]: RhythmPracticeStylePanel,
+  [ElementSubtypeTypes.MUSIC_RESOURCES]: MusicResourcesStylePanel
 }
 const { activeElementIdList, activeElementList, handleElement, activeGroupElementId } = storeToRefs(useMainStore())
 

+ 1 - 1
src/views/Editor/Toolbar/index.vue

@@ -41,7 +41,7 @@ const elementTabs = computed<ElementTabs[]>(() => {
   }
   if (
     handleElement.value?.type === "elf" &&
-    ["elf-sing-play", "elf-enjoy", "elf-listening-practice", "elf-rhythm-practice"].includes(handleElement.value?.subtype)
+    ["elf-sing-play", "elf-enjoy", "elf-listening-practice", "elf-rhythm-practice", "elf-music-resources"].includes(handleElement.value?.subtype)
   ) {
     return [
       { label: "位置", key: ToolbarStates.EL_POSITION },

+ 3 - 1
src/views/Mobile/MobileEditor/MobileEditableElement.vue

@@ -26,6 +26,7 @@ import cloudCoachElement from "@/views/components/element/cloudCoachElement"
 import enjoyElement from "@/views/components/element/enjoyElement"
 import listeningPracticeElement from "@/views/components/element/listeningPracticeElement"
 import rhythmPracticeElement from "@/views/components/element/rhythmPracticeElement"
+import musicResourcesElement from "@/views/components/element/musicResourcesElement"
 
 const props = defineProps<{
   elementInfo: PPTElement
@@ -50,7 +51,8 @@ const currentElementComponent = computed<unknown>(() => {
     [ElementSubtypeTypes.SING_PLAY]: cloudCoachElement,
     [ElementSubtypeTypes.ENJOY]: enjoyElement,
     [ElementSubtypeTypes.LISTENING_PRACTICE]: listeningPracticeElement,
-    [ElementSubtypeTypes.RHYTHM_PRACTICE]: rhythmPracticeElement
+    [ElementSubtypeTypes.RHYTHM_PRACTICE]: rhythmPracticeElement,
+    [ElementSubtypeTypes.MUSIC_RESOURCES]: musicResourcesElement
   }
   return elementTypeMap[props.elementInfo.type] || elementSubtypeMap[props.elementInfo.subtype] || null
 })

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

@@ -43,6 +43,15 @@
         <IconPower v-if="screenStore.mode === 'pptEditor'" class="tool-btn" v-tooltip="'结束放映'" @click="exitScreening()" />
       </div>
     </div> -->
+    <!-- 编辑模式下 预览加上退出全屏按钮 -->
+    <div v-if="screenStore.mode === 'pptEditor'" class="tools-right visible">
+      <div class="content">
+        <div class="tool-btn page-number" @click="slideThumbnailModelVisible = true">幻灯片 {{ slideIndex + 1 }} / {{ slides.length }}</div>
+        <IconOffScreenOne class="tool-btn" v-tooltip="'退出全屏'" v-if="fullscreenState" @click="manualExitFullscreen()" />
+        <IconFullScreenOne class="tool-btn" v-tooltip="'进入全屏'" v-else @click="enterFullscreen()" />
+        <IconPower v-if="screenStore.mode === 'pptEditor'" class="tool-btn" v-tooltip="'结束放映'" @click="exitScreening()" />
+      </div>
+    </div>
   </div>
 </template>
 

+ 3 - 1
src/views/Screen/ScreenElement.vue

@@ -36,6 +36,7 @@ import ScreenCloudCoachElement from "@/views/components/element/cloudCoachElemen
 import ScreenEnjoyElement from "@/views/components/element/enjoyElement/ScreenEnjoyElement.vue"
 import ScreenListeningPracticeElement from "@/views/components/element/listeningPracticeElement/ScreenListeningPracticeElement.vue"
 import ScreenRhythmPracticeElement from "@/views/components/element/rhythmPracticeElement/ScreenRhythmPracticeElement.vue"
+import ScreenMusicResourcesElement from "@/views/components/element/musicResourcesElement/ScreenMusicResourcesElement.vue"
 
 const props = defineProps<{
   elementInfo: PPTElement
@@ -62,7 +63,8 @@ const currentElementComponent = computed<unknown>(() => {
     [ElementSubtypeTypes.SING_PLAY]: ScreenCloudCoachElement,
     [ElementSubtypeTypes.ENJOY]: ScreenEnjoyElement,
     [ElementSubtypeTypes.LISTENING_PRACTICE]: ScreenListeningPracticeElement,
-    [ElementSubtypeTypes.RHYTHM_PRACTICE]: ScreenRhythmPracticeElement
+    [ElementSubtypeTypes.RHYTHM_PRACTICE]: ScreenRhythmPracticeElement,
+    [ElementSubtypeTypes.MUSIC_RESOURCES]: ScreenMusicResourcesElement
   }
   return elementTypeMap[props.elementInfo.type] || elementSubtypeMap[props.elementInfo.subtype] || null
 })

+ 3 - 1
src/views/components/ThumbnailSlide/ThumbnailElement.vue

@@ -27,6 +27,7 @@ import BaseCloudCoachElement from "@/views/components/element/cloudCoachElement/
 import BaseEnjoyElement from "@/views/components/element/enjoyElement/BaseEnjoyElement.vue"
 import BaseListeningPracticeElement from "@/views/components/element/listeningPracticeElement/BaseListeningPracticeElement.vue"
 import BaseRhythmPracticeElement from "@/views/components/element/rhythmPracticeElement/BaseRhythmPracticeElement.vue"
+import BaseMusicResourcesElement from "@/views/components/element/musicResourcesElement/BaseMusicResourcesElement.vue"
 
 const props = defineProps<{
   elementInfo: PPTElement
@@ -50,7 +51,8 @@ const currentElementComponent = computed<unknown>(() => {
     [ElementSubtypeTypes.SING_PLAY]: BaseCloudCoachElement,
     [ElementSubtypeTypes.ENJOY]: BaseEnjoyElement,
     [ElementSubtypeTypes.LISTENING_PRACTICE]: BaseListeningPracticeElement,
-    [ElementSubtypeTypes.RHYTHM_PRACTICE]: BaseRhythmPracticeElement
+    [ElementSubtypeTypes.RHYTHM_PRACTICE]: BaseRhythmPracticeElement,
+    [ElementSubtypeTypes.MUSIC_RESOURCES]: BaseMusicResourcesElement
   }
   return elementTypeMap[props.elementInfo.type] || elementSubtypeMap[props.elementInfo.subtype] || null
 })

+ 62 - 0
src/views/components/element/musicResourcesElement/BaseMusicResourcesElement.vue

@@ -0,0 +1,62 @@
+<template>
+  <div
+    class="base-element-musicResources"
+    :style="{
+      top: elementInfo.top + 'px',
+      left: elementInfo.left + 'px',
+      width: elementInfo.width + 'px',
+      height: elementInfo.height + 'px'
+    }"
+  >
+    <div class="rotate-wrapper" :style="{ transform: `rotate(${elementInfo.rotate}deg)` }">
+      <div class="element-content">
+        <div class="title" :style="{ fontSize: 13 / scale + 'px' }">{{ `${titNameObj[elementInfo.sType]}-${elementInfo.name}` }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import type { PPTMusicResourcesElement } from "@/types/slides"
+import { ref, inject } from "vue"
+import { injectKeySlideScale } from "@/types/injectKey"
+
+defineProps<{
+  elementInfo: PPTMusicResourcesElement
+}>()
+
+const scale = inject(injectKeySlideScale) || ref(1)
+
+const titNameObj = {
+  INSTRUMENT: "乐器百科",
+  MUSICIAN: "音乐家",
+  MUSIC: "名曲鉴赏",
+  THEORY: "乐理知识"
+}
+</script>
+
+<style lang="scss" scoped>
+.base-element-musicResources {
+  position: absolute;
+}
+.rotate-wrapper {
+  width: 100%;
+  height: 100%;
+}
+.element-content {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: url("./musicResourcesList/imgs/musicBg.png") no-repeat;
+  background-size: 100% 100%;
+  .title {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    padding: 0 40px;
+    color: #333333;
+  }
+}
+</style>

+ 58 - 0
src/views/components/element/musicResourcesElement/ScreenMusicResourcesElement.vue

@@ -0,0 +1,58 @@
+<template>
+  <div
+    class="base-element-cloudCoach screen-element-musicResources"
+    :style="{
+      top: elementInfo.top + 'px',
+      left: elementInfo.left + 'px',
+      width: elementInfo.width + 'px',
+      height: elementInfo.height + 'px'
+    }"
+  >
+    <div class="rotate-wrapper" :style="{ transform: `rotate(${elementInfo.rotate}deg)` }">
+      <div class="element-content">
+        <musicResourcesPlayer
+          v-if="inCurrentSlide"
+          :width="elementInfo.width"
+          :height="elementInfo.height"
+          :scale="scale"
+          :sid="elementInfo.sid"
+          :type="elementInfo.sType"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { computed, inject, ref } from "vue"
+import { storeToRefs } from "pinia"
+import { useSlidesStore } from "@/store"
+import type { PPTMusicResourcesElement } from "@/types/slides"
+import { injectKeySlideId, injectKeySlideScale } from "@/types/injectKey"
+import musicResourcesPlayer from "./musicResourcesPlayer"
+
+defineProps<{
+  elementInfo: PPTMusicResourcesElement
+}>()
+
+const { currentSlide } = storeToRefs(useSlidesStore())
+
+const scale = inject(injectKeySlideScale) || ref(1)
+const slideId = inject(injectKeySlideId) || ref("")
+
+const inCurrentSlide = computed(() => currentSlide.value.id === slideId.value)
+</script>
+
+<style lang="scss" scoped>
+.screen-element-musicResources {
+  position: absolute;
+}
+.rotate-wrapper {
+  width: 100%;
+  height: 100%;
+}
+.element-content {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 13 - 4
src/views/components/element/musicResourcesElement/index.ts

@@ -1,8 +1,12 @@
+import musicResourcesElement from "./musicResourcesElement.vue"
+export default musicResourcesElement
+
 import { getToken } from "@/libs/auth"
 import { stringifyQuery } from "@/libs/cipher"
-import { CLASSROOM_URL_API } from "@/config"
+import { CLASSROOM_URL_API, CLASSAPP_URL_API } from "@/config"
+import queryParams from "@/queryParams"
 
-type pptContentType = "INSTRUMENT" | "MUSICIAN" | "MUSIC" | "THEORY"
+export type pptContentType = "INSTRUMENT" | "MUSICIAN" | "MUSIC" | "THEORY"
 type pptType = "modal" | "preview"
 
 const typeObj = {
@@ -15,6 +19,11 @@ const typeObj = {
  * 获取资源url
  */
 export function getMusicResourcesUrl(pptContentType: pptContentType, pptType: pptType, pptId: string) {
-  //return `${CLASSROOM_URL_API}/#/pptResources?${stringifyQuery(`Authorization=${getToken()}&source=admin&pptContentType=${pptContentType}&pptType=${pptType}&pptId=${pptId}`)}`
-  return `http://localhost:5005/#/pptResources?${stringifyQuery(`Authorization=${getToken()}&source=admin&pptContentType=${typeObj[pptContentType]}&pptType=${pptType}&pptId=${pptId}`)}`
+  if (queryParams.fromType == "CLASS") {
+    return `${CLASSAPP_URL_API}/#/pptResources?${`Authorization=${getToken()}&pptContentType=${typeObj[pptContentType]}&pptType=${pptType}&pptId=${pptId}`}`
+    //return `http://192.168.0.147:9002/#/pptResources?${`Authorization=${getToken()}&pptContentType=${typeObj[pptContentType]}&pptType=${pptType}&pptId=${pptId}`}`
+  } else {
+    return `${CLASSROOM_URL_API}/#/pptResources?${stringifyQuery(`Authorization=${getToken()}&source=admin&pptContentType=${pptContentType}&pptType=${pptType}&pptId=${pptId}`)}`
+    //return `http://localhost:5005/#/pptResources?${stringifyQuery(`Authorization=${getToken()}&source=admin&pptContentType=${typeObj[pptContentType]}&pptType=${pptType}&pptId=${pptId}`)}`
+  }
 }

+ 122 - 0
src/views/components/element/musicResourcesElement/musicResourcesElement.vue

@@ -0,0 +1,122 @@
+<template>
+  <div
+    class="musicResourcesElement"
+    :class="{ lock: elementInfo.lock }"
+    :style="{
+      top: elementInfo.top + 'px',
+      left: elementInfo.left + 'px',
+      width: elementInfo.width + 'px',
+      height: elementInfo.height + 'px'
+    }"
+  >
+    <div class="rotate-wrapper" :style="{ transform: `rotate(${elementInfo.rotate}deg)` }">
+      <div
+        class="element-content"
+        v-contextmenu="contextmenus"
+        @mousedown="$event => handleSelectElement($event)"
+        @touchstart="$event => handleSelectElement($event)"
+      >
+        <div
+          v-if="isShowMask"
+          @mousedown.stop="$event => handleSelectElement($event, false)"
+          @touchstart.stop="$event => handleSelectElement($event, false)"
+          class="mask"
+        ></div>
+        <musicResourcesPlayer
+          :width="elementInfo.width"
+          :height="elementInfo.height"
+          :scale="canvasScale"
+          :sid="elementInfo.sid"
+          :type="elementInfo.sType"
+        />
+        <div
+          :class="['handler-border', item]"
+          v-for="item in ['t', 'b', 'l', 'r']"
+          :key="item"
+          @mousedown="$event => handleSelectElement($event)"
+          @touchstart="$event => handleSelectElement($event)"
+        ></div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { storeToRefs } from "pinia"
+import { useMainStore } from "@/store"
+import type { PPTMusicResourcesElement } from "@/types/slides"
+import type { ContextmenuItem } from "@/components/Contextmenu/types"
+import musicResourcesPlayer from "./musicResourcesPlayer"
+import { computed } from "vue"
+
+const props = defineProps<{
+  elementInfo: PPTMusicResourcesElement
+  selectElement: (e: MouseEvent | TouchEvent, element: PPTMusicResourcesElement, canMove?: boolean) => void
+  contextmenus: () => ContextmenuItem[] | null
+}>()
+
+const mainStore = useMainStore()
+const { canvasScale } = storeToRefs(mainStore)
+
+/* 当没有选中 或者 拖动过程中加一个遮罩,以免事件进入 iframe 无法触发*/
+const isShowMask = computed(() => {
+  return mainStore.handleElementId !== props.elementInfo.id || props.elementInfo.isMove
+})
+const handleSelectElement = (e: MouseEvent | TouchEvent, canMove = true) => {
+  if (props.elementInfo.lock) return
+  e.stopPropagation()
+
+  props.selectElement(e, props.elementInfo, canMove)
+}
+</script>
+
+<style lang="scss" scoped>
+.musicResourcesElement {
+  position: absolute;
+  &.lock .handler-border {
+    cursor: default;
+  }
+}
+.rotate-wrapper {
+  width: 100%;
+  height: 100%;
+}
+.element-content {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  .mask {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+  }
+}
+.handler-border {
+  position: absolute;
+  cursor: move;
+  &.t {
+    width: 100%;
+    height: 10px;
+    top: 0;
+    left: 0;
+  }
+  &.b {
+    width: 100%;
+    height: 10px;
+    bottom: 0;
+    left: 0;
+  }
+  &.l {
+    width: 10px;
+    height: 100%;
+    left: 0;
+    top: 0;
+  }
+  &.r {
+    width: 10px;
+    height: 100%;
+    right: 0;
+    top: 0;
+  }
+}
+</style>

BIN
src/views/components/element/musicResourcesElement/musicResourcesList/imgs/musicBg.png


+ 2 - 1
src/views/components/element/musicResourcesElement/musicResourcesList/musicPreview.vue

@@ -18,6 +18,7 @@
 <script setup lang="ts">
 import { computed } from "vue"
 import { getMusicResourcesUrl } from "../index"
+import { type pptContentType } from "@/views/components/element/musicResourcesElement"
 
 const emits = defineEmits<{
   (event: "close"): void
@@ -25,7 +26,7 @@ const emits = defineEmits<{
 
 const props = defineProps<{
   musicObj: Record<string, any>
-  type: "MUSIC" | "INSTRUMENT" | "MUSICIAN"
+  type: Exclude<pptContentType, "THEORY">
 }>()
 
 const url = computed(() => {

+ 3 - 2
src/views/components/element/musicResourcesElement/musicResourcesList/musicResourcesList.vue

@@ -155,13 +155,14 @@ import { CODE_ERR_CANCELED } from "@/libs/auth"
 import musicListVue from "./components/musicList.vue"
 import musicianListVue from "./components/musicianList.vue"
 import instrumentListVue from "./components/instrumentList.vue"
+import { type pptContentType } from "@/views/components/element/musicResourcesElement"
 
 const props = defineProps<{
-  type: "MUSIC" | "INSTRUMENT" | "MUSICIAN"
+  type: Exclude<pptContentType, "THEORY">
 }>()
 
 const emits = defineEmits<{
-  (event: "update", item: Record<string, any>, type: "MUSIC" | "INSTRUMENT" | "MUSICIAN"): void
+  (event: "update", item: Record<string, any>, type: Exclude<pptContentType, "THEORY">): void
   (event: "close"): void
 }>()
 

+ 2 - 0
src/views/components/element/musicResourcesElement/musicResourcesPlayer/index.ts

@@ -0,0 +1,2 @@
+import musicResourcesPlayer from "./musicResourcesPlayer.vue"
+export default musicResourcesPlayer

+ 107 - 0
src/views/components/element/musicResourcesElement/musicResourcesPlayer/musicResourcesPlayer.vue

@@ -0,0 +1,107 @@
+<template>
+  <div
+    class="musicResourcesPlayer"
+    :style="{
+      width: width * scale + 'px',
+      height: height * scale + 'px',
+      transform: `scale(${1 / scale})`
+    }"
+  >
+    <div v-if="loading" class="loading-overlay">
+      <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>
+</template>
+
+<script setup lang="ts">
+import { ref, computed } from "vue"
+import { getMusicResourcesUrl } from "../index"
+import { type pptContentType } from "@/views/components/element/musicResourcesElement"
+
+const props = withDefaults(
+  defineProps<{
+    width: number
+    height: number
+    scale?: number
+    type: pptContentType
+    sid: string
+  }>(),
+  {
+    scale: 1
+  }
+)
+
+const url = computed(() => {
+  return getMusicResourcesUrl(props.type, "preview", props.sid)
+})
+
+// 先关闭这个功能
+const loading = ref(true)
+function handleIframeLoad() {
+  loading.value = false
+}
+</script>
+
+<style lang="scss" scoped>
+.musicResourcesPlayer {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  overflow: hidden;
+  user-select: none;
+  line-height: 1;
+  transform-origin: 0 0;
+  .musicIframe {
+    width: 100%;
+    height: 100%;
+  }
+  .loading-overlay {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+    z-index: 10;
+    color: #fff;
+    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 rotate {
+      from {
+        transform: rotate(0deg);
+      }
+      to {
+        transform: rotate(360deg);
+      }
+    }
+  }
+}
+</style>