Просмотр исходного кода

Merge branch 'master' of http://git.dayaedu.com/lex/orchestra-app

lex 2 лет назад
Родитель
Сommit
d1d80c68c3

+ 18 - 59
src/helpers/utils.ts

@@ -16,9 +16,7 @@ export const browser = () => {
     // ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
     android: u.indexOf('ORCHESTRAAPPA') > -1 || u.indexOf('Adr') > -1, //android终端
     iPhone: u.indexOf('ORCHESTRAAPPI') > -1, //是否为iPhone或者QQHD浏览器
-    isApp:
-      u.indexOf('ORCHESTRAAPPI') > -1 ||
-      u.indexOf('ORCHESTRAAPPA') > -1,
+    isApp: u.indexOf('ORCHESTRAAPPI') > -1 || u.indexOf('ORCHESTRAAPPA') > -1,
     isTeacher: u.indexOf('ORCHESTRATEACHER') > -1,
     isStudent: u.indexOf('ORCHESTRASTUDENT') > -1,
     isSchool: u.indexOf('ORCHESTRASCHOOL') > -1,
@@ -34,20 +32,18 @@ export const browser = () => {
 // 获取授权的code码
 export const getUrlCode = (name = 'code') => {
   // 截取url中的code方法
-  const url = location.search;
-  const theRequest: any = new Object();
-  if (url.indexOf("?") != -1) {
-    const str = url.substr(1);
-    const strs = str.split("&");
+  const url = location.search
+  const theRequest: any = new Object()
+  if (url.indexOf('?') != -1) {
+    const str = url.substr(1)
+    const strs = str.split('&')
     for (let i = 0; i < strs.length; i++) {
-      theRequest[strs[i].split("=")[0]] = strs[i].split("=")[1];
+      theRequest[strs[i].split('=')[0]] = strs[i].split('=')[1]
     }
   }
-  console.log(theRequest, 'theRequest');
-  return theRequest[name];
-
-};
-
+  console.log(theRequest, 'theRequest')
+  return theRequest[name]
+}
 
 export const getRandomKey = () => {
   const key = '' + new Date().getTime() + Math.floor(Math.random() * 1000000)
@@ -108,15 +104,7 @@ export const closeLoading = () => {
 
 export const getWeekCh = (week: number, type = 0) => {
   const template = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
-  const template2 = [
-    '星期天',
-    '星期一',
-    '星期二',
-    '星期三',
-    '星期四',
-    '星期五',
-    '星期六'
-  ]
+  const template2 = ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
   return type ? template2[week] : template[week]
 }
 
@@ -130,43 +118,14 @@ export const numberFormat = (num: number, type?: string) => {
 export const moneyFormat = (value: number, format = '0,0.00') => {
   return numeral(value).format(format)
 }
-export const dateFormat = (
-  value: string | Date,
-  format = 'YYYY-MM-DD HH:mm:ss'
-) => {
+export const dateFormat = (value: string | Date, format = 'YYYY-MM-DD HH:mm:ss') => {
   return dayjs(value).format(format)
 }
 
-
-export function addFormMinute(timerStr, time = 0) {
-  const timer = dayjs('2021-12-17' + ' ' + timerStr).add(time, 'minute')
-  return timer.format('HH:mm:ss')
-}
-export function addFormMinuteAddS(timerStr, time = 0) {
-  const timer = dayjs('2021-12-17' + ' ' + timerStr)
-    .add(time, 'minute')
-    .add(1, 'second')
-  return timer.format('HH:mm:ss')
-}
-export function addFormMinuteMS(timerStr, time = 0) {
-  const timer = dayjs('2021-12-17' + ' ' + timerStr)
-    .add(time, 'minute')
-    .subtract(1, 'second')
-  return timer.format('HH:mm:ss')
-}
-export function reduceFormMinute(timerStr, time = 0) {
-  const timer = dayjs('2021-12-17' + ' ' + timerStr).subtract(time, 'minute')
-  return timer.format('HH:mm:ss')
-}
-export function reduceFormMinuteAddS(timerStr, time = 0) {
-  const timer = dayjs('2021-12-17' + ' ' + timerStr)
-    .subtract(time, 'minute')
-    .add(1, 'second')
-  return timer.format('HH:mm:ss')
-}
-export function reduceFormMinuteMS(timerStr, time = 0) {
-  const timer = dayjs('2021-12-17' + ' ' + timerStr)
-    .subtract(time, 'minute')
-    .subtract(1, 'second')
-  return timer.format('HH:mm:ss')
+// 秒转分
+export const getSecondRPM = (second: number) => {
+  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')
+  return mm + ':' + dd
 }

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

@@ -35,7 +35,6 @@ export default defineComponent({
             class={styles.collapse}
             modelValue={pointData.active}
             onUpdate:modelValue={(val: any) => {
-              console.log(val)
               pointData.active = val
             }}
             accordion

+ 26 - 30
src/views/coursewarePlay/index.module.less

@@ -3,13 +3,14 @@
   height: 100vh;
   background-color: rgba(89, 98, 126, 0.2);
 }
-.playModel{
+.playModel {
   position: absolute;
-    left: 0;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    box-shadow: inset 0px 0px 164px 0px rgba(0,0,0,1);
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  box-shadow: inset 0px 0px 164px 0px rgba(0, 0, 0, 1);
+  pointer-events: none;
 }
 .headerContainer {
   position: fixed;
@@ -20,6 +21,7 @@
   padding: 10px;
   display: flex;
   align-items: center;
+  background: linear-gradient(180deg, rgba(0, 0, 0, .6), transparent);
 }
 .backBtn {
   position: absolute;
@@ -51,23 +53,14 @@
     }
   }
 }
-.videoItem {
+.itemDiv {
+  position: relative;
   width: 100%;
   height: 100%;
-  --plyr-color-main: var(--van-primary);
   video {
     width: 100%;
     height: 100%;
   }
-  :global {
-    .plyr {
-      height: 100%;
-    }
-  }
-}
-.imgItem {
-  width: 100%;
-  height: 100%;
   img {
     display: block;
     width: 100%;
@@ -75,10 +68,6 @@
     object-fit: contain;
   }
 }
-.songItem {
-  width: 100%;
-  height: 100%;
-}
 .rightFixedBtns {
   position: fixed;
   top: 50%;
@@ -94,12 +83,12 @@
     border-top-right-radius: 0;
   }
 }
-.leftFixedBtns{
+.leftFixedBtns {
   position: fixed;
   top: 50%;
   transform: translateY(-50%);
   left: 20px;
-  .prePoint{
+  .prePoint {
     margin-bottom: 8px;
   }
 }
@@ -117,26 +106,33 @@
     opacity: 0.8;
   }
 }
-.bottomFixedContainer{
-  position: fixed;
+.bottomFixedContainer {
+  position: absolute;
   left: 0;
   right: 0;
   bottom: 0;
-  .time{
+  z-index: 10;
+  background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
+  backdrop-filter: blur(2px);
+  .time {
     display: flex;
     justify-content: space-between;
     color: #fff;
     font-size: 10px;
     padding: 4px 10px;
   }
-  .actions{
+  .slider {
+    padding: 8px 10px;
+  }
+  .actions {
     display: flex;
     justify-content: space-between;
     color: #fff;
     font-size: 12px;
-    padding: 4px 10px 18px 10px;
-    :global{
-      .van-icon{
+    padding: 8px 10px;
+    align-items: center;
+    :global {
+      .van-icon {
         font-size: 20px;
         margin-right: 14px;
       }

+ 262 - 163
src/views/coursewarePlay/index.tsx

@@ -1,4 +1,15 @@
-import { Button, Icon, Popup, Slider, Swipe, SwipeItem, Tab, Tabs } from 'vant'
+import {
+  Button,
+  closeToast,
+  Icon,
+  Popup,
+  showToast,
+  Slider,
+  Swipe,
+  SwipeItem,
+  Tab,
+  Tabs
+} from 'vant'
 import {
   defineComponent,
   onMounted,
@@ -22,32 +33,40 @@ import MusicScore from './component/musicScore'
 import iconMenu from './image/icon-menu.svg'
 import iconDian from './image/icon-dian.svg'
 import iconPoint from './image/icon-point.svg'
+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 Points from './component/points'
+import { getSecondRPM } from '@/helpers/utils'
 
 export default defineComponent({
   name: 'CoursewarePlay',
   setup() {
-    const handleInit = () => {
+    const handleInit = (type = 0) => {
       postMessage({
         api: 'setRequestedOrientation',
         content: {
-          orientation: 0
+          orientation: type
         }
       })
       postMessage({
         api: 'setBarStatus',
         content: {
-          status: 0
+          status: type
         }
       })
       postMessage({
         api: 'setStatusBarVisibility',
         content: {
-          isVisibility: 0
+          isVisibility: type
         }
       })
     }
     handleInit()
+    onUnmounted(() => {
+      handleInit(1)
+    })
 
     const route = useRoute()
     const data = reactive({
@@ -55,33 +74,52 @@ export default defineComponent({
       active: '',
       itemActive: '',
       knowledgePointList: [] as any,
+      itemList: [] as any,
       showHead: true,
       players: [] as any
     })
     const activeData = reactive({
+      nowTime: 0,
       model: true, // 遮罩
-      currentTime: 10
+      videoBtns: true, // 视频
+      currentTime: 0,
+      duration: 0,
+      timer: null as any,
+      item: null as any
     })
-    const itemList = computed(() => {
+    const getItemList = () => {
       const list: any = []
       for (let i = 0; i < data.knowledgePointList.length; i++) {
         const item = data.knowledgePointList[i]
         for (let j = 0; j < item.materialList.length; j++) {
           const material = item.materialList[j]
           if (popupData.itemActive === '') {
-            popupData.tabActive = material.knowledgePointId
             popupData.tabName = item.name
+            popupData.tabActive = material.knowledgePointId
             popupData.itemActive = material.id
             popupData.itemName = material.name
+            popupData.activeIndex = 0
+          }
+          let videoItem = {}
+          if (material.type === 'VIDEO') {
+            videoItem = {
+              currentTime: 0,
+              duration: 0,
+              paused: true,
+              loop: false,
+              videoEle: null,
+              timer: null
+            }
           }
           list.push({
-            ...material
+            ...material,
+            ...videoItem
           })
         }
       }
-      // console.log('🚀 ~ list', list)
+      console.log('🚀 ~ list', list)
       return list
-    })
+    }
     const getDetail = async () => {
       try {
         const res: any = await request.get(
@@ -95,132 +133,77 @@ export default defineComponent({
             n.index = 0
             return n
           })
+          data.itemList = getItemList()
         }
       } catch (error) {}
     }
-    const videoInit = () => {
-      console.log(document.querySelectorAll('.player'))
-      data.players = Plyr.setup('.player', {
-        debug: false,
-        ratio: '16:9',
-        clickToPlay: true,
-        controls: [
-          'play-large',
-          'play',
-          'progress',
-          'current-time',
-          'duration',
-          'mute',
-          'volume',
-          'restart'
-        ]
-      })
-      data.players.forEach((p: Plyr) => {
-        // console.log(p)
-        p.on('play', () => {
-          console.log('开始播放了')
-          data.showHead = false
-        })
-        p.on('pause', () => {
-          console.log('暂停了')
-          data.showHead = true
-        })
-        p.on('controlsshown', () => {
-          console.log('显示控件')
-          data.showHead = true
-        })
-        p.on('controlshidden', () => {
-          console.log('控件隐藏')
-          data.showHead = false
-        })
-      })
-      console.log('🚀 ~ player', data.players)
-    }
-    const testFile = ref('')
     onMounted(() => {
-      // const o = new ActiveXObject("wscript.shell")
       getDetail()
-      postMessage(
-        {
-          api: 'getCourseFilePath',
-          content: {
-            url: 'https://daya.ks3-cn-beijing.ksyuncs.com/01/1672976208474.jpg',
-            materialId: '1610610237357969409',
-            updateTime: '2023-01-04 20:12:58',
-            type: 'VIDEO' // SONG VIDEO IMAGE
-          }
-        },
-        (res) => {
-          if (res?.content) {
-            testFile.value = 'customScheme://' + res.content.localPath
-            fetch(testFile.value)
-          }
-        }
-      )
-    })
-    listenerMessage('getCourseFilePath', (res) => {
-      if (res?.content) {
-        testFile.value = res.content.localPath
-      }
     })
     // 返回
     const goback = () => {
       // history.go(-1)
       postMessage({ api: 'back' })
     }
-    // 所有的切换
-    const handleChange = () => {
-      // console.log('切换了')
-      const iframes = document.querySelectorAll('.musicIframe')
-      Array.from(iframes).map((f: any) => {
-        f.contentWindow.postMessage({ api: 'setPlayState' }, '*')
-      })
-      data.players.forEach((p: any) => {
-        p.stop()
-      })
-    }
-    onUnmounted(() => {
-      postMessage({
-        api: 'setRequestedOrientation',
-        content: {
-          orientation: 1
-        }
-      })
-      postMessage({
-        api: 'setBarStatus',
-        content: {
-          status: 1
-        }
-      })
-      postMessage({
-        api: 'setStatusBarVisibility',
-        content: {
-          isVisibility: 1
-        }
-      })
-    })
 
+    const swipeRef = ref()
     const popupData = reactive({
       open: false,
-      activeIndex: 0,
+      activeIndex: -1,
       tabActive: '',
       tabName: '',
       itemActive: '',
       itemName: ''
     })
+    // 设置当前的激活状态
+    const setActiveData = () => {
+      handleStopVideo()
+    }
+    watch(() => popupData.activeIndex, setActiveData)
+
+    // 停止所有的播放
+    const handleStopVideo = () => {
+      data.itemList.forEach((m: any) => {
+        m.videoEle?.pause()
+      })
+    }
+    // 获取name
+    const setAllName = () => {
+      const item = data.itemList.find((n: any) => n.id == popupData.itemActive)
+      const tab = data.knowledgePointList.find((n: any) => n.id == popupData.tabActive)
+      if (item) {
+        popupData.itemName = item.name
+      }
+      if (tab) {
+        popupData.tabName = tab.name
+      }
+    }
     // 切换素材
     const toggleMaterial = () => {
-      const index = itemList.value.findIndex((n: any) => n.id == popupData.itemActive)
-      popupData.activeIndex = index
-      console.log('🚀 ~ popupData', popupData.activeIndex)
+      const index = data.itemList.findIndex((n: any) => n.id == popupData.itemActive)
+      if (index > -1) {
+        popupData.activeIndex = index
+        swipeRef.value?.swipeTo(index)
+        setAllName()
+      }
+    }
+    // 轮播切换
+    const handleSwipeChange = (val: any) => {
+      popupData.activeIndex = val
+      const item = data.itemList[val]
+      if (item) {
+        popupData.tabActive = item.knowledgePointId
+        popupData.itemActive = item.id
+        setAllName()
+      }
     }
     // 上一个知识点, 下一个知识点
     const handlePreAndNext = (type: string) => {
-      console.log(popupData.tabActive)
-      const tabIndex = data.knowledgePointList.findIndex((n: any) => n.id == popupData.tabActive)
-      const itemIndex = itemList.value.findIndex((n: any) => n.id == popupData.itemActive)
-      
-      console.log("🚀 ~ tab", tabIndex, itemIndex)
+      if (type === 'up') {
+        swipeRef.value?.prev()
+      } else {
+        swipeRef.value?.next()
+      }
     }
 
     // 去点名,签退
@@ -235,48 +218,188 @@ export default defineComponent({
         }
       })
     }
+
+    // 双击
+    const handleDbClick = (item: any) => {
+      // console.log(activeData.item)
+      if (item && item.type === 'VIDEO') {
+        const videoEle: HTMLVideoElement = document.querySelector(`[data-vid='${item.id}']`)!
+        if (videoEle) {
+          if (videoEle.paused) {
+            closeToast()
+            videoEle.play()
+          } else {
+            showToast('已暂停')
+            videoEle.pause()
+          }
+        }
+        item.timer = setTimeout(() => {
+          activeData.model = false
+        }, 3000)
+        console.dir(videoEle)
+      }
+    }
+
+    // 视频播放
+    const handleVideoPlay = (e: Event) => {
+      const videoEle = e.target! as unknown as HTMLVideoElement
+      // console.log(videoEle.paused, videoEle.currentTime, videoEle.duration)
+      if (videoEle.paused) return
+      activeData.currentTime = videoEle.currentTime
+      activeData.duration = videoEle.duration
+    }
+
+    // 调整播放进度
+    const handleChangeSlider = (val: any, m: any) => {
+      if (m?.videoEle) {
+        m.videoEle.currentTime = val
+      }
+    }
+
     return () => (
       <div class={styles.coursewarePlay}>
         <Swipe
           style={{ height: '100vh' }}
+          ref={swipeRef}
           showIndicators={false}
           loop={false}
-          initialSwipe={popupData.activeIndex}
           vertical
           lazyRender={true}
-          onChange={(val: any) => {
-            // item.index = val
-            // popupData.itemActive = `${item.id}-${item?.materialList?.[item.index]?.id}`
-          }}
+          onChange={handleSwipeChange}
         >
-          {itemList.value.map((m: any) => {
+          {data.itemList.map((m: any, mIndex: number) => {
             return (
               <SwipeItem>
-                {m.type === 'VIDEO' ? (
-                  <div class={styles.videoItem}>
-                    <video class="player">
-                      <source src={m.content} type="video/mp4" />
-                    </video>
-                  </div>
-                ) : m.type === 'IMG' ? (
-                  <div class={styles.imgItem}>
-                    <img src={m.content} />
-                  </div>
-                ) : (
-                  <div class={styles.songItem}>
-                    <MusicScore music={m} />
+                <>
+                  <div
+                    class={styles.itemDiv}
+                    onClick={() => {
+                      clearTimeout(activeData.timer)
+                      clearTimeout(m.timer)
+                      if (Date.now() - activeData.nowTime < 300) {
+                        handleDbClick(m)
+                        return
+                      }
+                      activeData.nowTime = Date.now()
+                      activeData.timer = setTimeout(() => {
+                        activeData.model = !activeData.model
+                      }, 300)
+                    }}
+                  >
+                    {m.type === 'VIDEO' ? (
+                      <>
+                        <video
+                          class="player"
+                          data-vid={m.id}
+                          src={m.content}
+                          loop={m.loop}
+                          onLoadedmetadata={(e: Event) => {
+                            const videoEle = e.target as unknown as HTMLVideoElement
+                            // console.log('video加载成功', videoEle)
+                            m.currentTime = videoEle.currentTime
+                            m.duration = videoEle.duration
+                            m.videoEle = videoEle
+                          }}
+                          onTimeupdate={(e: Event) => {
+                            const videoEle = e.target as unknown as HTMLVideoElement
+                            // console.log('video播放中')
+                            m.currentTime = videoEle.currentTime
+                          }}
+                          onPlay={() => {
+                            console.log('播放')
+                            m.paused = false
+                          }}
+                          onPause={() => {
+                            console.log('暂停')
+                            m.paused = true
+                          }}
+                        >
+                          <source src={m.content} type="video/mp4" />
+                        </video>
+                        <Transition name="bottom">
+                          {activeData.model && (
+                            <div class={styles.bottomFixedContainer}>
+                              <div class={styles.time}>
+                                <span>{getSecondRPM(m.currentTime)}</span>
+                                <span>{getSecondRPM(m.duration)}</span>
+                              </div>
+                              <div class={styles.slider}>
+                                <Slider
+                                  buttonSize={16}
+                                  step={0.01}
+                                  v-model:modelValue={m.currentTime}
+                                  onUpdate:modelValue={(val: any) => handleChangeSlider(val, m)}
+                                  min={0}
+                                  max={m.duration}
+                                />
+                              </div>
+
+                              <div class={styles.actions}>
+                                <div>
+                                  {m.paused ? (
+                                    <Icon
+                                      name={iconplay}
+                                      onClick={(e: Event) => {
+                                        e.stopPropagation()
+                                        clearTimeout(m.timer)
+                                        console.log('点击播放', m.videoEle)
+                                        m.videoEle?.play()
+                                        m.paused = false
+                                        m.timer = setTimeout(() => {
+                                          activeData.model = false
+                                        }, 3000)
+                                      }}
+                                    />
+                                  ) : (
+                                    <Icon
+                                      name={iconpause}
+                                      onClick={(e: Event) => {
+                                        e.stopPropagation()
+                                        console.log('点击暂停')
+                                        m.videoEle?.pause()
+                                        m.paused = true
+                                      }}
+                                    />
+                                  )}
+                                  {m.loop ? (
+                                    <Icon
+                                      name={iconLoopActive}
+                                      onClick={(e: Event) => {
+                                        e.stopPropagation()
+                                        m.loop = false
+                                      }}
+                                    />
+                                  ) : (
+                                    <Icon
+                                      name={iconLoop}
+                                      onClick={(e: Event) => {
+                                        e.stopPropagation()
+                                        m.loop = true
+                                      }}
+                                    />
+                                  )}
+                                </div>
+                                <div>{popupData.itemName}</div>
+                              </div>
+                            </div>
+                          )}
+                        </Transition>
+                      </>
+                    ) : m.type === 'IMG' ? (
+                      <img src={m.content} />
+                    ) : (
+                      <MusicScore music={m} />
+                    )}
+                    {/* <Transition name="van-fade">
+                      {activeData.model && <div class={styles.playModel}></div>}
+                    </Transition> */}
                   </div>
-                )}
+                </>
               </SwipeItem>
             )
           })}
         </Swipe>
-        <div
-          class={styles.playModel}
-          onClick={() => {
-            activeData.model = !activeData.model
-          }}
-        ></div>
+
         <Transition name="top">
           {activeData.model && (
             <div class={styles.headerContainer}>
@@ -336,30 +459,6 @@ export default defineComponent({
           )}
         </Transition>
 
-        <Transition name="bottom">
-          {activeData.model && (
-            <div class={styles.bottomFixedContainer}>
-              <div class={styles.time}>
-                <span>03:12</span>
-                <span>10:12</span>
-              </div>
-              <Slider
-                buttonSize={16}
-                style={{ margin: '8px 0' }}
-                v-model:modelValue={activeData.currentTime}
-                min={0}
-                max={100}
-              />
-              <div class={styles.actions}>
-                <div>
-                  <Icon name="play-circle" />
-                  <Icon name="pause-circle" />
-                </div>
-                <div>长笛的呼吸练习</div>
-              </div>
-            </div>
-          )}
-        </Transition>
         <Popup
           class={styles.popup}
           overlayClass={styles.overlayClass}