skyblued 2 éve
szülő
commit
f393ff2218

+ 187 - 182
src/views/exercise-after-class/index.module.less

@@ -1,203 +1,208 @@
+.playContent {
+  width: 100vw;
+  height: 100vh;
+  background-color: #000;
+  overflow: hidden;
+}
 .coursewarePlay {
-    position: relative;
-    height: 100vh;
-    background-color: rgba(89, 98, 126, 0.2);
-  }
-  .playModel {
-    position: absolute;
-    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;
-    top: 0;
-    left: 0;
-    right: 0;
-    z-index: 1;
-    padding: 10px 24px;
-    display: flex;
-    align-items: center;
-    color: #fff;
-    font-size: 12px;
-    background: linear-gradient(180deg, rgba(0, 0, 0, .6), transparent);
-  }
-  .backBtn {
-    color: #fff;
-    width: 40px;
-    height: 26px;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    z-index: 10;
-  }
-  .menu {
-    flex: 1;
-    display: flex;
-    justify-content: center;
-    color: #fff;
-  }
-  .tabsContent {
-    width: 100vw;
-    height: 100vh;
-    :global {
-      .van-tabs__wrap {
-        display: none !important;
-      }
-      .van-tabs__content {
-        width: 100%;
-        height: 100%;
-      }
-    }
-  }
-  .itemDiv {
-    position: relative;
-    width: 100%;
-    height: 100%;
-    video {
-      width: 100%;
-      height: 100%;
+  position: relative;
+  height: 100vh;
+  margin: 0 auto;
+}
+.playModel {
+  position: absolute;
+  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;
+  top: 0;
+  left: 0;
+  right: 0;
+  z-index: 1;
+  padding: 10px 24px;
+  display: flex;
+  align-items: center;
+  color: #fff;
+  font-size: 12px;
+  background: linear-gradient(180deg, rgba(0, 0, 0, 0.6), transparent);
+}
+.backBtn {
+  color: #fff;
+  width: 40px;
+  height: 26px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  z-index: 10;
+}
+.menu {
+  flex: 1;
+  display: flex;
+  justify-content: center;
+  color: #fff;
+}
+.tabsContent {
+  width: 100vw;
+  height: 100vh;
+  :global {
+    .van-tabs__wrap {
+      display: none !important;
     }
-    img {
-      display: block;
+    .van-tabs__content {
       width: 100%;
       height: 100%;
-      object-fit: contain;
     }
   }
-  .videoModel{
-    position: absolute;
-    top: 0;
-    left: 0;
+}
+.itemDiv {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  video {
     width: 100%;
     height: 100%;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    & > img{
-      width: 50px;
-      height: 50px;
-    }
   }
-  .rightFixedBtns {
-    position: fixed;
-    top: 50%;
-    transform: translateY(-50%);
-    right: 20px;
-    .point {
-      margin-top: 10px;
-      border-bottom-left-radius: 0;
-      border-bottom-right-radius: 0;
-    }
-    .point + .fullBtn {
-      border-top-left-radius: 0;
-      border-top-right-radius: 0;
-    }
+  img {
+    display: block;
+    width: 100%;
+    height: 100%;
+    object-fit: contain;
   }
-  .leftFixedBtns {
-    position: fixed;
-    top: 50%;
-    transform: translateY(-50%);
-    left: 20px;
-    .prePoint {
-      margin-bottom: 8px;
-    }
+}
+.videoModel {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  & > img {
+    width: 50px;
+    height: 50px;
+  }
+}
+.rightFixedBtns {
+  position: fixed;
+  top: 50%;
+  transform: translateY(-50%);
+  right: 20px;
+  .point {
+    margin-top: 10px;
+    border-bottom-left-radius: 0;
+    border-bottom-right-radius: 0;
   }
-  .fullBtn {
-    width: 38px;
-    height: 55px;
-    background: rgba(51, 51, 51, 0.15);
-    border-radius: 8px;
+  .point + .fullBtn {
+    border-top-left-radius: 0;
+    border-top-right-radius: 0;
+  }
+}
+.leftFixedBtns {
+  position: fixed;
+  top: 50%;
+  transform: translateY(-50%);
+  left: 20px;
+  .prePoint {
+    margin-bottom: 8px;
+  }
+}
+.fullBtn {
+  width: 38px;
+  height: 55px;
+  background: rgba(51, 51, 51, 0.15);
+  border-radius: 8px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  color: #fff;
+  justify-content: space-evenly;
+  &:active {
+    opacity: 0.8;
+  }
+}
+.bottomFixedContainer {
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 10;
+  background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
+  padding: 0 30px;
+  .time {
     display: flex;
-    flex-direction: column;
-    align-items: center;
+    justify-content: space-between;
     color: #fff;
-    justify-content: space-evenly;
-    &:active {
-      opacity: 0.8;
-    }
+    font-size: 10px;
+    padding: 4px 0;
   }
-  .bottomFixedContainer {
-    position: absolute;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    z-index: 10;
-    background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
-    padding: 0 30px;
-    .time {
+  .slider {
+    padding: 10px 0;
+  }
+  .actions {
+    display: flex;
+    justify-content: space-between;
+    color: #fff;
+    font-size: 12px;
+    align-items: center;
+    .actionBtn {
       display: flex;
-      justify-content: space-between;
-      color: #fff;
-      font-size: 10px;
-      padding: 4px 0;
     }
-    .slider {
-      padding: 10px 0;
-    }
-    .actions {
-      display: flex;
-      justify-content: space-between;
-      color: #fff;
-      font-size: 12px;
-      align-items: center;
-      .actionBtn{
-        display: flex;
-      }
-      .actionBtn > img {
-        width: 26px;
-        height: 26px;
-        display: block;
-        padding: 8px 8px 14px 8px;
-      }
+    .actionBtn > img {
+      width: 26px;
+      height: 26px;
+      display: block;
+      padding: 8px 8px 14px 8px;
     }
   }
-  .popup {
-    background: rgba(0, 0, 0, 0.5);
+}
+.popup {
+  background: rgba(0, 0, 0, 0.5);
+}
+.overlayClass {
+  --van-overlay-background: transparent;
+}
+:global {
+  .top-enter-active,
+  .top-leave-active {
+    transition: transform 0.5s;
   }
-  .overlayClass {
-    --van-overlay-background: transparent;
+  .top-enter-from,
+  .top-leave-to {
+    transform: translateY(-100%);
   }
-  :global {
-    .top-enter-active,
-    .top-leave-active {
-      transition: transform 0.5s;
-    }
-    .top-enter-from,
-    .top-leave-to {
-      transform: translateY(-100%);
-    }
-  
-    .left-enter-active,
-    .left-leave-active {
-      transition: all 0.5s;
-    }
-    .left-enter-from,
-    .left-leave-to {
-      left: -60px;
-    }
-  
-    .right-enter-active,
-    .right-leave-active {
-      transition: all 0.5s;
-    }
-  
-    .right-enter-from,
-    .right-leave-to {
-      right: -60px;
-    }
-  
-    .bottom-enter-active,
-    .bottom-leave-active {
-      transition: transform 0.5s;
-    }
-  
-    .bottom-enter-from,
-    .bottom-leave-to {
-      transform: translateY(100%);
-    }
+
+  .left-enter-active,
+  .left-leave-active {
+    transition: all 0.5s;
+  }
+  .left-enter-from,
+  .left-leave-to {
+    left: -60px;
+  }
+
+  .right-enter-active,
+  .right-leave-active {
+    transition: all 0.5s;
+  }
+
+  .right-enter-from,
+  .right-leave-to {
+    right: -60px;
+  }
+
+  .bottom-enter-active,
+  .bottom-leave-active {
+    transition: transform 0.5s;
+  }
+
+  .bottom-enter-from,
+  .bottom-leave-to {
+    transform: translateY(100%);
   }
-  
+}

+ 149 - 138
src/views/exercise-after-class/index.tsx

@@ -1,19 +1,5 @@
-import {
-  Icon,
-  showConfirmDialog,
-  Slider,
-  Swipe,
-  SwipeItem
-} from 'vant'
-import {
-  defineComponent,
-  onMounted,
-  reactive,
-  onUnmounted,
-  ref,
-  watch,
-  Transition,
-} from 'vue'
+import { Icon, showConfirmDialog, Slider, Swipe, SwipeItem } from 'vant'
+import { defineComponent, onMounted, reactive, onUnmounted, ref, watch, Transition } from 'vue'
 import styles from './index.module.less'
 import 'plyr/dist/plyr.css'
 import request from '@/helpers/request'
@@ -38,7 +24,23 @@ const materialType = {
 export default defineComponent({
   name: 'exercise-after-class',
   setup() {
+    /** 设置播放容器 16:9 */
+    const parentContainer = reactive({
+      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)
+      if (width > max) {
+        parentContainer.width = '100vw'
+        return
+      } else {
+        parentContainer.width = width + 'px'
+      }
+    }
     const handleInit = (type = 0) => {
+      setContainer()
       // 横屏
       postMessage({
         api: 'setRequestedOrientation',
@@ -98,7 +100,10 @@ export default defineComponent({
       let details = []
       try {
         const res: any = await request.get(
-          state.platformApi + `/lessonTraining/courseSchedule/${route.query.courseScheduleId}`
+          state.platformApi + `/lessonTraining/courseSchedule/${route.query.courseScheduleId}`,
+          {
+            hideLoading: true
+          }
         )
         if (Array.isArray(res?.data)) {
           const studentLevel = state.user?.data?.studentLevel || 1
@@ -124,7 +129,7 @@ export default defineComponent({
           videoEle: null,
           timer: null,
           muted: true, // 静音
-          autoplay: true, //自动播放
+          autoplay: true //自动播放
         })
         popupData.itemActive = videoData.id
         popupData.tabName = videoData.materialName
@@ -147,7 +152,10 @@ export default defineComponent({
       try {
         const res: any = await request.post(
           state.platformApi +
-            `/studentLessonTraining/trainingRecord/${query.courseScheduleId}?userId=${state.user?.data?.id}`
+            `/studentLessonTraining/trainingRecord/${query.courseScheduleId}?userId=${state.user?.data?.id}`,
+          {
+            hideLoading: true
+          }
         )
         if (res?.data) {
           getTrainingTimes(res.data)
@@ -197,7 +205,8 @@ export default defineComponent({
         const res: any = await request.post(
           state.platformApi + '/studentLessonTraining/lessonTrainingRecord',
           {
-            data: body
+            data: body,
+            hideLoading: true
           }
         )
         trainingRecord()
@@ -235,7 +244,7 @@ export default defineComponent({
               if (nextItem?.type === materialType.视频) {
                 const searchUrl = qs.stringify({
                   ...query,
-                    materialId: nextItem.materialId
+                  materialId: nextItem.materialId
                 })
                 // console.log('下一题视频', data.details[itemIndex].materialId, nextItem.materialId)
                 location.href = `${location.origin}${location.pathname}#/exerciseAfterClass?${searchUrl}`
@@ -271,131 +280,133 @@ export default defineComponent({
     }
 
     return () => (
-      <div class={styles.coursewarePlay}>
-        <Swipe
-          style={{ height: '100vh' }}
-          ref={swipeRef}
-          showIndicators={false}
-          loop={false}
-          vertical
-          lazyRender={true}
-          touchable={false}
-        >
-          {data.itemList.map((m: any, mIndex: number) => {
-            return (
-              <SwipeItem>
-                <>
-                  <div
-                    class={styles.itemDiv}
-                    onClick={() => {
-                      clearTimeout(m.timer)
-                      activeData.model = !activeData.model
-                    }}
-                  >
-                    <video
-                      playsinline="false"
-                      preload="auto"
-                      class="player"
-                      poster={iconVideobg}
-                      data-vid={m.id}
-                      src={m.content}
-                      loop={m.loop}
-                      autoplay={m.autoplay}
-                      muted={m.muted}
-                      onLoadedmetadata={async (e: Event) => {
-                        const videoEle = e.target as unknown as HTMLVideoElement
-                        m.duration = videoEle.duration
-                        m.videoEle = videoEle
-                      }}
-                      onTimeupdate={(e: Event) => {
-                        const videoEle = e.target as unknown as HTMLVideoElement
-                        m.currentTime = videoEle.currentTime
-                      }}
-                      onPlay={() => {
-                        // 播放
-                        m.paused = false
-                        if (m.muted){
-                          m.muted = false
-                          m.videoEle.pause()
-                        }
+      <div class={styles.playContent}>
+        <div class={styles.coursewarePlay} style={{ width: parentContainer.width }}>
+          <Swipe
+            style={{ height: '100%' }}
+            ref={swipeRef}
+            showIndicators={false}
+            loop={false}
+            vertical
+            lazyRender={true}
+            touchable={false}
+          >
+            {data.itemList.map((m: any, mIndex: number) => {
+              return (
+                <SwipeItem>
+                  <>
+                    <div
+                      class={styles.itemDiv}
+                      onClick={() => {
+                        clearTimeout(m.timer)
+                        activeData.model = !activeData.model
                       }}
-                      onPause={() => {
-                        //暂停
-                        m.paused = true
-                      }}
-                      onEnded={() => addTrainingRecord(m)}
                     >
-                      <source src={m.content} type="video/mp4" />
-                    </video>
-                  </div>
-                  <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}>
-                          {m.duration && (
-                            <Slider
-                              buttonSize={16}
-                              modelValue={m.currentTime}
-                              min={0}
-                              max={m.duration}
-                            />
-                          )}
-                        </div>
-
-                        <div class={styles.actions}>
-                          <div class={styles.actionBtn}>
-                            {m.paused ? (
-                              <img
-                                src={iconplay}
-                                onClick={(e: Event) => {
-                                  clearTimeout(m.timer)
-                                  m.videoEle?.play()
-                                  m.paused = false
-                                  m.timer = setTimeout(() => {
-                                    activeData.model = false
-                                  }, 4000)
-                                }}
-                              />
-                            ) : (
-                              <img
-                                src={iconpause}
-                                onClick={(e: Event) => {
-                                  clearTimeout(m.timer)
-                                  m.videoEle?.pause()
-                                  m.paused = true
-                                }}
+                      <video
+                        playsinline="false"
+                        preload="auto"
+                        class="player"
+                        poster={iconVideobg}
+                        data-vid={m.id}
+                        src={m.content}
+                        loop={m.loop}
+                        autoplay={m.autoplay}
+                        muted={m.muted}
+                        onLoadedmetadata={async (e: Event) => {
+                          const videoEle = e.target as unknown as HTMLVideoElement
+                          m.duration = videoEle.duration
+                          m.videoEle = videoEle
+                        }}
+                        onTimeupdate={(e: Event) => {
+                          const videoEle = e.target as unknown as HTMLVideoElement
+                          m.currentTime = videoEle.currentTime
+                        }}
+                        onPlay={() => {
+                          // 播放
+                          m.paused = false
+                          if (m.muted) {
+                            m.muted = false
+                            m.videoEle.pause()
+                          }
+                        }}
+                        onPause={() => {
+                          //暂停
+                          m.paused = true
+                        }}
+                        onEnded={() => addTrainingRecord(m)}
+                      >
+                        <source src={m.content} type="video/mp4" />
+                      </video>
+                    </div>
+                    <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}>
+                            {m.duration && (
+                              <Slider
+                                buttonSize={16}
+                                modelValue={m.currentTime}
+                                min={0}
+                                max={m.duration}
                               />
                             )}
                           </div>
+
+                          <div class={styles.actions}>
+                            <div class={styles.actionBtn}>
+                              {m.paused ? (
+                                <img
+                                  src={iconplay}
+                                  onClick={(e: Event) => {
+                                    clearTimeout(m.timer)
+                                    m.videoEle?.play()
+                                    m.paused = false
+                                    m.timer = setTimeout(() => {
+                                      activeData.model = false
+                                    }, 4000)
+                                  }}
+                                />
+                              ) : (
+                                <img
+                                  src={iconpause}
+                                  onClick={(e: Event) => {
+                                    clearTimeout(m.timer)
+                                    m.videoEle?.pause()
+                                    m.paused = true
+                                  }}
+                                />
+                              )}
+                            </div>
+                          </div>
                         </div>
-                      </div>
-                    )}
-                  </Transition>
-                </>
-              </SwipeItem>
-            )
-          })}
-        </Swipe>
+                      )}
+                    </Transition>
+                  </>
+                </SwipeItem>
+              )
+            })}
+          </Swipe>
 
-        <Transition name="top">
-          {activeData.model && (
-            <div class={styles.headerContainer} ref={headeRef}>
-              <div class={styles.backBtn} onClick={() => goback()}>
-                <Icon name={iconBack} />
-                返回
-              </div>
-              <div class={styles.menu}>{popupData.tabName}</div>
-              <div class={styles.nums}>
-                练习次数:{data.trainingTimes}/
-                {(data.videoData as any)?.training?.practiceTimes || 0}
+          <Transition name="top">
+            {activeData.model && (
+              <div class={styles.headerContainer} ref={headeRef}>
+                <div class={styles.backBtn} onClick={() => goback()}>
+                  <Icon name={iconBack} />
+                  返回
+                </div>
+                <div class={styles.menu}>{popupData.tabName}</div>
+                <div class={styles.nums}>
+                  练习次数:{data.trainingTimes}/
+                  {(data.videoData as any)?.training?.practiceTimes || 0}
+                </div>
               </div>
-            </div>
-          )}
-        </Transition>
+            )}
+          </Transition>
+        </div>
       </div>
     )
   }