Browse Source

Merge branch 'iteration_0307' into jenkins-main

lex 1 year ago
parent
commit
b1b289a878

+ 17 - 2
public/project/initiation.html

@@ -188,7 +188,7 @@
       <div class="top-tips">科学的教育与关爱,足以改变世界。我们希望,学员的未来会因您和我们的共同努力而更加光辉灿烂!</div>
       <van-cell-group inset class="cell-group">
         <van-field label="学员姓名" :rules="[{ validator, message }]" name="username" v-model="stu.username"
-          placeholder="请填写学员真实姓名"></van-field>
+          placeholder="请填写学员真实姓名" autocomplete="off"></van-field>
         <!-- <van-field label="性别" name="sex" :rules="[{ required: true, message: '请选择性别' }]">
           <template #input>
             <van-radio-group v-model="stu.sex" checked-color="#FF8057" direction="horizontal">
@@ -346,6 +346,21 @@
           document.querySelector('#m_loading').remove()
         }
 
+        // 重置数据
+        this.stu = {
+          username: null, // 姓名
+          // sex: 1, // 性别
+          phone: null, // 电话
+          currentGrade: '', // 年级
+          currentGradeNum: null, // 年级编号
+          currentClass: '', // 班级
+          currentClassNum: null, // 年级编号
+          learningSubjectName: null,
+          joinOrchestra: null, //
+          personalSuggestion: null, // 个人建议
+          joinParentMeeting: null
+        }
+
         // 判断是否是微信,只能微信中打开
         if (!browser().weixin) {
           this.showPopup = true
@@ -552,4 +567,4 @@
   </script>
 </body>
 
-</html>
+</html>

+ 21 - 4
src/helpers/utils.ts

@@ -2,6 +2,7 @@ import dayjs from 'dayjs'
 import numeral from 'numeral'
 import { Toast } from 'vant'
 import { state as helpState } from './helpState'
+import qs from 'query-string'
 
 export const browser = () => {
   const u = navigator.userAgent
@@ -45,6 +46,18 @@ export const getUrlCode = (name = 'code') => {
   return theRequest[name]
 }
 
+export const getQuery = (name = 'code') => {
+  let search: any = {}
+  try {
+    search = {
+      ...qs.parse(location.search),
+      ...qs.parse(location.hash.split('?')[1])
+    }
+  } catch (error) {
+    //
+  }
+  return search[name]
+}
 export const getRandomKey = () => {
   const key = '' + new Date().getTime() + Math.floor(Math.random() * 1000000)
   return key
@@ -125,8 +138,12 @@ export const dateFormat = (value: string | Date, format = 'YYYY-MM-DD HH:mm:ss')
 // 秒转分
 export const getSecondRPM = (second: number, type?: string) => {
   if (isNaN(second)) return '00:00'
-  const mm = Math.floor(second / 60).toString().padStart(2, '0')
-  const dd = Math.floor(second % 60).toString().padStart(2, '0')
+  const mm = Math.floor(second / 60)
+    .toString()
+    .padStart(2, '0')
+  const dd = Math.floor(second % 60)
+    .toString()
+    .padStart(2, '0')
   if (type === 'cn') {
     return mm + '分' + dd + '秒'
   } else {
@@ -136,8 +153,8 @@ export const getSecondRPM = (second: number, type?: string) => {
 
 /**
  * @description 格式化日期控件显示内容
- * @param type 
- * @param option 
+ * @param type
+ * @param option
  * @returns OBJECT
  */
 export const formatterDatePicker = (type: any, option: any) => {

+ 150 - 0
src/views/coursewarePlay/component/video-item/index.module.less

@@ -0,0 +1,150 @@
+.videoWrap {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+.content {
+  position: relative;
+  height: 100%;
+}
+
+.contentWrap {
+  height: 100%;
+
+  video {
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.videoSection {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
+
+.controls {
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  height: 80px;
+  background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  transition: all 0.5s;
+
+  &.hide {
+    transform: translateY(100%);
+  }
+
+  .time {
+    display: flex;
+    justify-content: space-between;
+    width: 100%;
+    color: #fff;
+    font-size: 10px;
+    padding: 4px 20px;
+  }
+
+  .slider {
+    width: 100%;
+    padding: 0 20px;
+
+    :global {
+      .n-slider {
+        --n-handle-size: 13px !important;
+        --n-fill-color: var(--van-primary-color) !important;
+        --n-fill-color-hover: var(--van-primary-color) !important;
+      }
+
+      .van-loading {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+
+  .actions {
+    display: flex;
+    width: 100%;
+    color: #fff;
+    font-size: 12px;
+    padding: 0 20px;
+    align-items: center;
+
+    .actionWrap {
+      display: flex;
+    }
+
+    .actionBtn {
+      display: flex;
+      width: 28px;
+      height: 28px;
+      padding: 4px 0;
+      background: transparent;
+    }
+
+    .actionBtn>img {
+      width: 100%;
+      height: 100%;
+    }
+
+    :global {
+      .van-loading__circular {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    .playIcon {
+      display: none;
+    }
+
+    .btnPlay img:nth-child(2) {
+      display: block;
+    }
+
+    .btnPause img:nth-child(3) {
+      display: block;
+    }
+
+    .btnPlay,
+    .btnPause {
+      :global {
+        .van-loading {
+          display: none;
+        }
+      }
+    }
+
+    .loopBtn {
+      :global {
+        .loop {
+          display: block;
+        }
+
+        .loopActive {
+          display: none;
+        }
+      }
+    }
+
+    .loopBtn.active {
+      :global {
+        .loop {
+          display: none;
+        }
+
+        .loopActive {
+          display: block;
+        }
+      }
+    }
+
+  }
+}

+ 167 - 0
src/views/coursewarePlay/component/video-item/index.tsx

@@ -0,0 +1,167 @@
+import { defineComponent, onMounted, reactive, toRefs, watch } from 'vue'
+import { ref } from 'vue'
+import styles from './index.module.less'
+
+import iconLoop from '../../image/icon-loop.svg'
+import iconLoopActive from '../../image/icon-loop-active.svg'
+import iconplay from '../../image/icon-play.svg'
+import iconpause from '../../image/icon-pause.svg'
+import { NSlider } from 'naive-ui'
+import { getSecondRPM } from '@/helpers/utils'
+
+export default defineComponent({
+  name: 'video-play',
+  props: {
+    item: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    pageVisibility: {
+      type: String,
+      default: ''
+    },
+    show: {
+      type: Boolean,
+      default: false
+    },
+    showModel: {
+      type: Boolean,
+      default: false
+    },
+    isEmtry: {
+      type: Boolean,
+      default: false
+    }
+  },
+  emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset', 'close', 'error'],
+  setup(props, { emit, expose }) {
+    const videoItem = ref()
+    const { item, isEmtry } = toRefs(props)
+    const data = reactive({
+      timer: null as any,
+      currentTime: 0,
+      duration: 0,
+      loop: false,
+      playState: 'pause' as 'play' | 'pause',
+      vudio: null as any,
+      reload: false
+    })
+    const contetRef = ref()
+
+    // watch(
+    //   () => props.show,
+    //   () => {
+    //     onToggleAudio('pause')
+    //   }
+    // )
+
+    let playTimer = null as any
+    // 切换音频播放
+    const onToggleAudio = (state: 'play' | 'pause') => {
+      clearTimeout(playTimer)
+      if (state === 'play') {
+        playTimer = setTimeout(() => {
+          videoItem.value?.play()
+          data.playState = 'play'
+        }, 100)
+      } else {
+        videoItem.value?.pause()
+        data.playState = 'pause'
+      }
+      emit('togglePlay', data.playState)
+    }
+
+    /** 改变播放时间 */
+    const handleChangeTime = (val: number) => {
+      data.currentTime = val
+      clearTimeout(data.timer)
+      data.timer = setTimeout(() => {
+        videoItem.value.currentTime = val;
+        data.timer = null;
+      }, 300)
+    }
+
+    const handleLoadedmetadata = () => {
+      data.reload = false
+      // 获取时长
+      data.duration = videoItem.value.duration()
+
+      emit('loadedmetadata', videoItem.value)
+    }
+    const onTimeupdate = () => {
+      if (data.timer) return
+      data.currentTime = videoItem.value.currentTime()
+    }
+    const onEnded = () => {
+      data.playState = 'pause'
+      emit('ended')
+    }
+    const onPaused = () => {
+      data.playState = 'pause'
+    }
+    const onPlaying = () => {
+      data.playState = 'play'
+    }
+    return () => (
+      <div class={styles.videoWrap}>
+        <div class={styles.content}>
+          <div ref={contetRef} class={styles.contentWrap}>
+            <video
+              ref={videoItem}
+              style={{ width: '100%', height: '100%' }}
+              poster={props.item.coverImg}
+              src={isEmtry.value ? '' : item.value.content}
+              preload="auto"
+              playsinline
+              webkit-playsinline
+              onLoadedmetadata={handleLoadedmetadata}
+              onTimeupdate={onTimeupdate}
+              onEnded={onEnded}
+              onPause={onPaused}
+              onPlaying={onPlaying}
+            ></video>
+          </div>
+          <div class={styles.videoSection}></div>
+        </div>
+
+        <div
+          class={[styles.controls, props.showModel ? '' : styles.hide]}
+          onClick={(e: Event) => {
+            e.stopPropagation()
+          }}
+          onTouchmove={(e: TouchEvent) => {
+            emit('close')
+          }}
+        >
+          <div class={styles.time}>
+            <div>{getSecondRPM(data.currentTime)}</div>
+            <div>{getSecondRPM(data.duration)}</div>
+          </div>
+          <div class={styles.slider}>
+            <NSlider
+              tooltip={false}
+              step={0.01}
+              class={styles.timeProgress}
+              value={data.currentTime}
+              max={data.duration}
+              onUpdate:value={(val) => handleChangeTime(val)}
+            />
+          </div>
+          <div class={styles.actions} onClick={() => emit('close')}>
+            <div
+              class={styles.actionBtn}
+              onClick={() => onToggleAudio(data.playState === 'pause' ? 'play' : 'pause')}
+            >
+              <img src={data.playState === 'pause' ? iconplay : iconpause} />
+            </div>
+            <div class={styles.actionBtn} onClick={() => (data.loop = !data.loop)}>
+              <img src={data.loop ? iconLoopActive : iconLoop} />
+            </div>
+          </div>
+        </div>
+      </div>
+    )
+  }
+})

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

@@ -1,4 +1,4 @@
-import { defineComponent, nextTick, onMounted, toRefs, watch } from 'vue'
+import { defineComponent, nextTick, onMounted, onUnmounted, toRefs, watch } from 'vue'
 import 'plyr/dist/plyr.css'
 import Plyr from 'plyr'
 import { ref } from 'vue'
@@ -22,7 +22,7 @@ export default defineComponent({
       type: Boolean,
       default: false
     },
-    isActive:{
+    isActive: {
       type: Boolean,
       default: false
     }
@@ -31,7 +31,7 @@ export default defineComponent({
   setup(props, { emit, expose }) {
     const { item, isEmtry } = toRefs(props)
     const videoRef = ref()
-    const videoItem = ref<Plyr>()
+    const videoItem: any = ref()
     const controlID = 'v' + Date.now() + Math.floor(Math.random() * 100)
     const playBtnId = 'play' + Date.now() + Math.floor(Math.random() * 100)
     const loopBtnId = 'loop' + Date.now() + Math.floor(Math.random() * 100)
@@ -89,7 +89,7 @@ export default defineComponent({
                 <div class="${styles.actions}">
                     <div class="${styles.actionWrap}">
                         <button id="${playBtnId}" class="${styles.actionBtn}">
-                            <div class="van-loading van-loading--circular" aria-live="polite" aria-busy="true"><span class="van-loading__spinner van-loading__spinner--circular" style="color: rgb(255, 255, 255);"><svg class="van-loading__circular" viewBox="25 25 50 50"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span></div>  
+                            <div class="van-loading van-loading--circular" aria-live="polite" aria-busy="true"><span class="van-loading__spinner van-loading__spinner--circular" style="color: rgb(255, 255, 255);"><svg class="van-loading__circular" viewBox="25 25 50 50"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span></div>
                             <img class="${styles.playIcon}" src="${iconplay}" />
                             <img class="${styles.playIcon}" src="${iconpause}" />
                         </button>
@@ -104,9 +104,9 @@ export default defineComponent({
 
     onMounted(() => {
       videoItem.value = new Plyr(videoRef.value, {
-        autoplay: true,
+        autoplay: false,
         controls: controls,
-        autopause: true, // 一次只允许
+        autopause: false, // 一次只允许
         ratio: '16:9', // 强制所有视频的纵横比
         hideControls: false, // 在 2 秒没有鼠标或焦点移动、控制元素模糊(制表符退出)、播放开始或进入全屏时自动隐藏视频控件。只要移动鼠标、聚焦控制元素或暂停播放,控件就会立即重新出现。
         clickToPlay: false, // 单击(或点击)视频容器将切换播放/暂停
@@ -114,17 +114,16 @@ export default defineComponent({
       })
       if (videoItem.value) {
         videoItem.value.on('play', () => {
-          if (videoItem.value) {
+          if (videoItem.value && videoItem.value.muted) {
             videoItem.value.muted = false
             videoItem.value.volume = 1
           }
-            
+
           // console.log('开始播放', item.value)
           if (!item.value.autoPlay && !item.value.isprepare && videoItem.value) {
             // 加载完成后,取消静音播放
-            
-            console.log(videoItem.value)
             videoItem.value.pause()
+            console.log(videoItem.value?.paused, 'video status')
           }
           changePlayBtn('')
           emit('togglePlay', videoItem.value?.paused)
@@ -139,11 +138,15 @@ export default defineComponent({
         })
         videoItem.value.once('loadedmetadata', (e: Event) => {
           changePlayBtn('play')
-          if (item.value.autoPlay && videoItem.value) {
+          videoItem.value.currentTime = 0
+          if (item.value.autoPlay && videoItem.value && props.isActive) {
             videoItem.value.play()
           }
           emit('loadedmetadata', videoItem.value)
         })
+        videoItem.value.on('timeupdate', (e: Event) => {
+          // console.log(videoItem.value?.currentTime, '111')
+        })
 
         nextTick(() => {
           onDefault()
@@ -154,11 +157,13 @@ export default defineComponent({
       changePlayBtn,
       toggleHideControl
     })
-    watch(() => props.isActive, (val) => {
-      if (!val) {
-        videoItem.value?.pause()
-      }
-    })
+
+    // onUnmounted(() => {
+    //   if (videoItem.value) {
+    //     videoItem.value?.pause()
+    //     videoItem.value?.destroy()
+    //   }
+    // })
     return () => (
       <div class={styles.videoWrap}>
         <video

+ 20 - 9
src/views/coursewarePlay/index.module.less

@@ -37,7 +37,8 @@
   background: linear-gradient(180deg, rgba(0, 0, 0, 0.6), transparent);
   transition: transform 0.5s;
   box-sizing: border-box;
-  div{
+
+  div {
     box-sizing: border-box;
   }
 }
@@ -57,7 +58,8 @@
     }
   }
 }
-.headRight{
+
+.headRight {
   position: relative;
   z-index: 10;
   display: flex;
@@ -65,13 +67,15 @@
   margin-left: auto;
   height: 100%;
   padding-right: 15px;
-  .rightBtn{
+
+  .rightBtn {
     display: flex;
     justify-content: center;
     align-items: center;
     height: 100%;
     padding: 0 10px;
-    img{
+
+    img {
       width: 22px;
       height: 22px;
       display: block;
@@ -118,6 +122,8 @@
   position: absolute;
   left: 0;
   top: 0;
+  right: 0;
+  bottom: 0;
   width: 100%;
   height: 100%;
   background-color: #000;
@@ -127,18 +133,23 @@
   backface-visibility: hidden;
   overflow: hidden;
   z-index: 1;
-  &.itemActive{
+
+  &.itemActive {
     z-index: 10;
   }
-  &.acitveAnimation{
+
+  &.acitveAnimation {
     transition-duration: .8s;
   }
-  &.show{
+
+  &.show {
     display: block;
   }
-  &.hide{
+
+  &.hide {
     display: none;
   }
+
   video {
     width: 100%;
     height: 100%;
@@ -356,6 +367,6 @@
   }
 }
 
-.popupMore{
+.popupMore {
   background: rgba(0, 0, 0, 0.8);
 }

+ 117 - 83
src/views/coursewarePlay/index.tsx

@@ -64,22 +64,16 @@ import Tool, { ToolItem, ToolType } from './component/tool'
 import Tools from './component/tools/pen'
 import Pen from './component/tools/pen'
 import iconPen from './image/icon-pen.png'
+import { useThrottle, useThrottleFn, useDebounceFn } from '@vueuse/core'
 
 export default defineComponent({
   name: 'CoursewarePlay',
   setup() {
     const pageVisibility = usePageVisibility()
-    const isPlay = ref(false)
     /** 页面显示和隐藏 */
-    watch(pageVisibility, (value) => {
-      const activeItem = data.itemList[popupData.activeIndex]
-      if (activeItem.type != 'VIDEO') return
+    watch(() => pageVisibility.value, (value) => {
       if (value == 'hidden') {
-        isPlay.value = !activeItem.videoEle?.paused
-        togglePlay(activeItem, false)
-      } else {
-        // 页面显示,并且
-        if (isPlay.value) togglePlay(activeItem, true)
+        handleStop()
       }
     })
     /** 设置播放容器 16:9 */
@@ -87,9 +81,9 @@ export default defineComponent({
       width: '100vw'
     })
     const setContainer = () => {
-      let min = Math.min(screen.width, screen.height)
-      let max = Math.max(screen.width, screen.height)
-      let width = min * (16 / 9)
+      const min = Math.min(screen.width, screen.height)
+      const max = Math.max(screen.width, screen.height)
+      const width = min * (16 / 9)
       if (width > max) {
         parentContainer.width = '100vw'
         return
@@ -244,18 +238,22 @@ export default defineComponent({
         }
       }
 
-      console.log(list, 'list')
+      // console.log(list, 'list')
 
-      let _firstIndex = list.findIndex((n: any) => n.knowledgePointMaterialRelationId == route.query.kId || n.materialId == route.query.kId)
+      let _firstIndex = list.findIndex(
+        (n: any) =>
+          n.knowledgePointMaterialRelationId == route.query.kId || n.materialId == route.query.kId
+      )
       _firstIndex = _firstIndex > -1 ? _firstIndex : 0
       const item = list[_firstIndex]
 
-      console.log(_firstIndex, '_firstIndex', route.query.kId, 'route.query.kId', item)
+      // console.log(_firstIndex, '_firstIndex', route.query.kId, 'route.query.kId', item)
       // 是否自动播放
       if (activeData.isAutoPlay) {
         item.autoPlay = true
       }
       popupData.activeIndex = _firstIndex
+      popupData.playIndex = _firstIndex
       popupData.tabName = item.tabName
       popupData.tabActive = item.knowledgePointId
       popupData.itemActive = item.id
@@ -429,6 +427,7 @@ export default defineComponent({
     const popupData = reactive({
       open: false,
       activeIndex: 0,
+      playIndex: 0,
       tabActive: '',
       tabName: '',
       itemActive: '',
@@ -439,18 +438,16 @@ export default defineComponent({
 
     /**停止所有的播放 */
     const handleStop = () => {
-      for (let i = 0; i < data.itemList.length; i++) {
-        const activeItem = data.itemList[i]
-        if (activeItem.type === 'VIDEO') {
-          activeItem.videoEle?.pause()
-          activeItem.videoEle?.stop()
-        }
-        // console.log('🚀 ~ activeItem:', activeItem)
-        // 停止曲谱的播放
-        if (activeItem.type === 'SONG') {
-          activeItem.iframeRef?.contentWindow?.postMessage({ api: 'setPlayState' }, '*')
-        }
+      const videos = document.querySelectorAll('video')
+      for (let i = 0; i < videos.length; i++) {
+        const videoEle = videos[i] as HTMLVideoElement
+        videoEle.pause();
       }
+      data.itemList.forEach((item: any) => {
+        if (item.type === 'SONG') {
+          item.iframeRef?.contentWindow?.postMessage({ api: 'setPlayState' }, '*')
+        }
+      })
     }
     // 切换素材
     const toggleMaterial = (itemActive: any) => {
@@ -465,7 +462,7 @@ export default defineComponent({
       closeToast()
       activeData.timer = setTimeout(() => {
         activeData.model = false
-        Object.values(data.videoRefs).map((n: any) => n.toggleHideControl(false))
+        Object.values(data.videoRefs).map((n: any) => n?.toggleHideControl(false))
       }, 4000)
     }
     /** 立即收起所有的模态框 */
@@ -473,11 +470,11 @@ export default defineComponent({
       clearTimeout(activeData.timer)
       closeToast()
       activeData.model = false
-      Object.values(data.videoRefs).map((n: any) => n.toggleHideControl(false))
+      Object.values(data.videoRefs).map((n: any) => n?.toggleHideControl(false))
     }
-    const toggleModel = (type: boolean = true) => {
+    const toggleModel = (type = true) => {
       activeData.model = type
-      Object.values(data.videoRefs).map((n: any) => n.toggleHideControl(type))
+      Object.values(data.videoRefs).map((n: any) => n?.toggleHideControl(type))
     }
 
     // 去点名,签退
@@ -498,7 +495,7 @@ export default defineComponent({
       if (item && item.type === 'VIDEO') {
         const videoEle: HTMLVideoElement = item.videoEle
         if (videoEle) {
-          if (videoEle.paused) {
+          if (videoEle?.paused) {
             closeToast()
             videoEle.play()
           } else {
@@ -585,40 +582,55 @@ export default defineComponent({
       if (popupData.activeIndex == index) return
       handleStop()
       clearTimeout(acitveTimer.value)
-      const oldIndex = popupData.activeIndex
       checkedAnimation(popupData.activeIndex, index)
-      popupData.activeIndex = index
-
-      acitveTimer.value = setTimeout(
-        () => {
-          const item = data.itemList[index]
-          if (item) {
-            popupData.tabActive = item.knowledgePointId
-            popupData.itemActive = item.id
-            popupData.itemName = item.name
-            popupData.tabName = item.tabName
-            if (item.type == 'SONG') {
-              activeData.model = true
-            }
-            if (item.type === 'VIDEO') {
-              // 自动播放下一个视频
-              clearTimeout(activeData.timer)
-              closeToast()
-              item.autoPlay = true
-              nextTick(() => {
-                item.videoEle?.play()
-              })
+      nextTick(() => {
+        popupData.activeIndex = index
+
+        acitveTimer.value = setTimeout(
+          () => {
+            popupData.playIndex = index
+            const item = data.itemList[index]
+            if (item) {
+              popupData.tabActive = item.knowledgePointId
+              popupData.itemActive = item.id
+              popupData.itemName = item.name
+              popupData.tabName = item.tabName
+              if (item.type == 'SONG') {
+                activeData.model = true
+              }
             }
-          }
-          requestAnimationFrame(() => {
-            const _effectIndex = effectIndex.value + 1
-            effectIndex.value = _effectIndex >= effects.length - 1 ? 0 : _effectIndex
-          })
-        },
-        activeData.isAnimation ? 800 : 0
-      )
+            requestAnimationFrame(() => {
+              const _effectIndex = effectIndex.value + 1
+              effectIndex.value = _effectIndex >= effects.length - 1 ? 0 : _effectIndex
+
+              if (item && item.type === 'VIDEO') {
+                // 自动播放下一个视频
+                clearTimeout(activeData.timer)
+                closeToast()
+                item.autoPlay = true
+                nextTick(() => {
+                  item.videoEle?.play()
+                })
+              }
+            })
+          },
+          activeData.isAnimation ? 800 : 0
+        )
+      })
     }
 
+    const onChangeSwiper = useDebounceFn((type: string, itemActive?: any) => {
+      if (type === 'up') {
+        handlePreAndNext('up')
+      }
+      if (type === 'down') {
+        handlePreAndNext('down')
+      }
+      if (type === 'change') {
+        popupData.open = false
+        toggleMaterial(itemActive)
+      }
+    }, 200)
     /** 是否有转场动画 */
     const checkedAnimation = (index: number, nextIndex?: number) => {
       const item = data.itemList[index]
@@ -698,7 +710,7 @@ export default defineComponent({
           onClick={() => {
             clearTimeout(activeData.timer)
             activeData.model = !activeData.model
-            Object.values(data.videoRefs).map((n: any) => n.toggleHideControl(activeData.model))
+            Object.values(data.videoRefs).map((n: any) => n?.toggleHideControl(activeData.model))
           }}
         >
           <div
@@ -711,19 +723,21 @@ export default defineComponent({
           >
             <div class={styles.wraps}>
               {data.itemList.map((m: any, mIndex: number) => {
-                const isRender = Math.abs(popupData.activeIndex - mIndex) < 5
-                const isEmtry = Math.abs(popupData.activeIndex - mIndex) > 3
-                // if (isRender) {
-                //   m.isRender = true
-                // }
-                return isRender ? (
+                const isRenderItem = Math.abs(popupData.activeIndex - mIndex) < 2
+                const isRender = Math.abs(popupData.playIndex - mIndex) < 2
+                const isEmtry = popupData.activeIndex != mIndex
+                // 判断是否是当前选中的元素
+                const activeEle = popupData.playIndex === mIndex ? true : false
+
+                return isRenderItem ? (
                   <div
                     key={'index' + mIndex}
+                    data-id={'data' + mIndex}
                     class={[
                       styles.itemDiv,
-                      popupData.activeIndex === mIndex && styles.itemActive,
+                      activeEle && styles.itemActive,
                       activeData.isAnimation && styles.acitveAnimation,
-                      Math.abs(popupData.activeIndex - mIndex) < 2 ? styles.show : styles.hide
+                      isRenderItem ? styles.show : styles.hide
                     ]}
                     style={
                       mIndex < popupData.activeIndex
@@ -743,7 +757,7 @@ export default defineComponent({
                       activeData.timer = setTimeout(() => {
                         activeData.model = !activeData.model
                         Object.values(data.videoRefs).map((n: any) =>
-                          n.toggleHideControl(activeData.model)
+                          n?.toggleHideControl(activeData.model)
                         )
                         if (activeData.model) {
                           setModelOpen()
@@ -751,22 +765,19 @@ export default defineComponent({
                       }, 300)
                     }}
                   >
-                    {m.type === 'VIDEO' ? (
+                    {m.type === 'VIDEO' && (
                       <>
                         <VideoPlay
                           ref={(v: any) => (data.videoRefs[mIndex] = v)}
                           item={m}
-                          isActive={popupData.activeIndex === mIndex}
+                          isActive={activeEle}
                           isEmtry={isEmtry}
                           onLoadedmetadata={(videoItem: any) => {
                             m.videoEle = videoItem
+                            m.isprepare = true
                           }}
                           onTogglePlay={(paused: boolean) => {
                             // console.log('播放切换', paused)
-                            // 首次播放完成
-                            if (!m.isprepare) {
-                              m.isprepare = true
-                            }
                             m.autoPlay = false
                             if (paused || popupData.open || popupData.guideOpen) {
                               clearTimeout(activeData.timer)
@@ -794,9 +805,9 @@ export default defineComponent({
                           )}
                         </Transition>
                       </>
-                    ) : m.type === 'IMG' ? (
-                      <img src={m.content} />
-                    ) : (
+                    )}
+                    {isRender && m.type === 'IMG' && <img src={m.content} />}
+                    {isRender && m.type === 'SONG' && (
                       <MusicScore
                         activeModel={activeData.model}
                         data-vid={m.id}
@@ -807,7 +818,9 @@ export default defineComponent({
                       />
                     )}
                   </div>
-                ) : null
+                ) : (
+                  ''
+                )
               })}
             </div>
             <Transition name="right">
@@ -859,7 +872,16 @@ export default defineComponent({
                 <div class={styles.leftFixedBtns} onClick={(e: Event) => e.stopPropagation()}>
                   {popupData.activeIndex != 0 && (
                     <div class={[styles.btnsWrap, styles.prePoint]}>
-                      <div class={styles.fullBtn} onClick={() => handlePreAndNext('up')}>
+                      <div
+                        class={styles.fullBtn}
+                        onClick={() => {
+                          // useThrottleFn(() => {
+                          //   handlePreAndNext('up')
+                          // }, 300)
+                          // onChangeSwiper('up')
+                          handlePreAndNext('up')
+                        }}
+                      >
                         <img src={iconUp} />
                         <span style={{ textAlign: 'center' }}>上一个</span>
                       </div>
@@ -867,7 +889,18 @@ export default defineComponent({
                   )}
                   {popupData.activeIndex != data.itemList.length - 1 && (
                     <div class={styles.btnsWrap}>
-                      <div class={styles.fullBtn} onClick={() => handlePreAndNext('down')}>
+                      <div
+                        class={styles.fullBtn}
+                        onClick={() => {
+                          // console.log('click down')
+                          // useThrottleFn(() => {
+                          //   console.log('click down pass')
+                          //   handlePreAndNext('down')
+                          // }, 300)
+                          // onChangeSwiper('down')
+                          handlePreAndNext('down')
+                        }}
+                      >
                         <span style={{ textAlign: 'center' }}>下一个</span>
                         <img src={iconDown} />
                       </div>
@@ -957,6 +990,7 @@ export default defineComponent({
             tabActive={popupData.tabActive}
             itemActive={popupData.itemActive}
             onHandleSelect={(res: any) => {
+              // onChangeSwiper('change', res.itemActive)
               popupData.open = false
               toggleMaterial(res.itemActive)
             }}

+ 4 - 0
src/views/unit-test/unit-create/index.tsx

@@ -135,6 +135,10 @@ export default defineComponent({
                   readonly
                   input-align="right"
                   onClick={() => {
+                    if (state.actions.length <= 0) {
+                      showToast('暂无乐团')
+                      return
+                    }
                     state.showPopoverOrchestra = true
                   }}
                 >