Ver Fonte

添加视频播放

lex há 1 ano atrás
pai
commit
18d47563f6

+ 90 - 3
src/components/card-preview/video-modal/index.module.less

@@ -58,6 +58,7 @@
 
     .actionWrap {
       display: flex;
+      align-items: center;
     }
 
     .actionBtn {
@@ -75,9 +76,36 @@
     }
 
 
+    .actionBtnSpeed {
+      width: 40px;
+      height: 40px;
+      background-color: transparent;
+      cursor: pointer;
+
+      &>img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+
     .iconReplay {
-      width: 31px;
-      height: 29px;
+      width: 40px;
+      height: 40px;
+      background-color: transparent;
+      cursor: pointer;
+      margin: 0 22px;
+
+      &>img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    .iconDownload {
+      width: 40px;
+      height: 40px;
+      margin-left: 5px;
       background-color: transparent;
       cursor: pointer;
 
@@ -90,7 +118,7 @@
 
   .slider {
     width: 100%;
-    padding: 0 20px 0 12px;
+    padding: 0 0 0 12px;
 
     :global {
 
@@ -110,6 +138,65 @@
 
 }
 
+.sliderPopup {
+  position: absolute;
+  z-index: 9999;
+  left: 144px;
+  bottom: 82px;
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+  height: 252px;
+  width: 59Px;
+  padding: 12Px 0 15Px;
+  background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAI4AAAJcCAMAAAAYSmw3AAAAaVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnbPKNAAAAI3RSTlOzAAUJiqaplqF6V0c4nSevpJN+GAZtX1EQGpqDPTQVc2QhqyTybJ0AAAKuSURBVHja7NRJVsJQAAXRRxMg9BwgGWX/2xT0KCKII5M/uHcFNaqMntm25+mm2uVf7KrN9NxuR8885ozX9Sw9mNXr8Z85p2WV3lTL0+uc1SK9Wqxe5HTz9G7e/ZbTZBDN05xJnYHUk8ec4yGDORx/5hz3GdD+eJ8zOWRQh8ldTp2B1d9zmgyuueV0KUD3lTNPAeafOasUYfWRc1qkCIvTe84yhVhec8ZVClGNLznrFGM9yvAHvKkvObMUYzbKNgXZpk1B2pxTkHOmKcg0mxRkk2ImeFVll4IUFQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAG3twIAAAAAAA5P/aCKqqqqqqqqqqqqqqqtJ+nSQ3CgVRFH2XjwCjHnWoCTXe/yJrUlEljCz7R9riD/Ks4E7yRaRzzjnnnHPOOeecc845zZWQuUZKyEhTJWSqXAnJtVFCNtopITvNlJCZKJSMAvGmZLwhJkrGBJElM4SjDEGtRNQgCJWSUAUQMFYSxoAASiWgBBCQxnFN/uWw1eC2/M+h0cAa7nNCqUGVoZPDaqEBLVZ0c9iXGky552MOodFAmkA/B64axBUe5jA56OUOE+6IjvFCL7UY0yG6Ql3oZYo68DwH1qfmXS/w3pzWfCQeyGb1Ja8K/ZKiyi/1LOMB8UTWFzcH4+wBnhCRsmNEDbFErPW3e3ZEE9FCrm+p6THkWHu29BlyjD1XIthyCEt9YUMEaw7tFz0XIthzaMvnz3YUew7tQZ86ZsSx53Ce6hP5mqcsOfE9eSCePYdVpQeWhhqEwX6hnrLFQFjcej2HFgthchupY3rGRNjcCt2pVtgIo1lxV7PHSFjtl/orP2Ml7E7HuTRvTtiJH9G2/AiRlD84lRqqt/0KYQAAAABJRU5ErkJggg==') no-repeat top center;
+  background-size: contain;
+
+  .iconAdd,
+  .iconCut {
+    display: inline-block;
+    width: 24Px;
+    height: 24Px;
+    background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAABMlBMVEUAAAAkqP8ckv8zu/8op/81v/8ajv8elP82v/8rrv8elP4npv8yuf8elP8elf81v/8sr/8elf8vuv8dlv8srv8jn/8zu/8wtf82wP8oqP8npf8Zjf8mpP8Zjf8hmv8bj/40vP8wtP81wP8Zjf41vv8sr/8jnf8aj/0zuf8dlf81vv8rq/4kof4vsf8imP8aj/////8usv8qrP4jn/4inP4dlP4yuf8el/4srv8pqv4gmf4bkf40vf8ssP4wtP8lov4koP4xt/8npv4mpP4zu/8hmv4ajv4ckv4wtv4op/58x/5+y/6Cxv5/zf57xP6Dx/6BxP7u+P/t9/6a1f6Bz/56w/5iuP5zwP5Bpv4yoP6x3/6w3f6d2/6Wzv5tyf5pwv5nvv5svP5Rsv5Pr/5Mq/43p/49/opPAAAAMHRSTlMACoRW+Pf38dTUurGDWEhHR0cjI/b28fHr6+vr19fQ0Lq6sbGoqKiolZWGhoZSUlKk1yinAAAB+UlEQVQ4y43S6VbaQACG4S9E9h3c933fatISI4sWYxUjAVQQ99r2/m+hGQfGMJNEHw4M+XhPTn4AjpQNLM1MhUJTM0uBrAQ/qbXQmUNoLQUve3Nngrk9uMnHjlzF8hAkw0cewklwAr98BDBg47uvjYH72oNx1/WuHfdOFgqFu3qj8bfgiT13Pmy3DbNhtr3jcB5UTNe7DdM0f6s69dRqPemcGG13dV3t2G2737b3bW2+3gUxaxh/LHJfo+eWxLcGZxa2lKqqHcsyuyph2G8aq71rdpL/yar9tW5ZbypTJ3Fd5a0C0oiiKG9W51hhaKzwRiRkFeJfVRFiQRbbx4IaiWvivo14RUBjcY9julKlKtXXGvVA4ofexWuV/T6NyWrf9b6raxZMYuhnX8s9brFgyBE33eOmI5646PN6DBZMIHpIXJCPl0vqnjT3vYuXj9+jiB8KLkl8Je5xbB0Irt5jcd9C5utxBtKwph1oBDtprPH7sASsaFpJs5XYSeMSv68AyJR4NyS+EeYMbNFvHBrzaxTEDj8/k/iZX3fwboGby4/N5mOZGxdA5cbKnxrLoUcunxMn596nDCZx8okEHNZ/+FrHgIRfmwBHHj31MCpDkJsvntqvov0eOOdzcCNHioKIDC/p5aCzDC6n4UdKby5GxoPB8cjiZlrCoP+meld2tFTGwgAAAABJRU5ErkJggg==') no-repeat center;
+    background-size: contain;
+    flex-shrink: 0;
+    cursor: pointer;
+
+    &.disabled {
+      opacity: 0.7;
+    }
+  }
+
+  .iconCut {
+    background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAABGlBMVEUAAAAkqP8zu/8op/8ajv8aj/8yuP8elP4npv4dlP8elP8yuP8elP81v/8sr/8jnf8Zjf81v/81v/8jn/8zu/8wtf8gl/82wP8oqP8npf83wP8qqv8mpP8Zjf81vf8tsv8hmv8bj/41wP8qqv8lof8Zjf41vv8sr/8jnf8aj/0zuf8dlf8bjf00vP8xt/8zvf8stv8dmf8dkv8srv8trf8qq/7///8tsP4jn/4us/8srv8gmf4lov4yuf8dlf4wt/8inf4hm/4ck/4bkf4wtP8koP4mpf4fl/4op/40vP8ajv4pqf4zuv98x/5+y/6Bxf40vv80u/6Dx/6a1f5owP5PsP4/p/5zwP4oo/4yoP7u+P7u9/5svP5it/4TfkURAAAANXRSTlMACoT49+66uoaDWFJSR0dHR/j29vHx8evr69fX19fQ0NDQsbGxsaioqKiVlYZYWCMjIyP29l0yDtwAAAGnSURBVDjLjc6HVsIwGAXg27I37r33nkilWloXCGK17OH7v4YpSKSQtPnS5v7n5J6cYIyUPt1bC/j9gbW907QEN+kjf2mE/ygNnvhWacJWHCzXoWem0DUmRAPPHIEoxkSeXETgcPJEaGSx88Rxr6ZpaqOtcUVARTWt0DBNs06yoBGTSd99NV8gXeKnwDV/hYGQqrZNoqerfCH0xVXVaNr3GqqbOGybhlG3LKunG642QaQMXW9altkmaRhk42UKwKGu6xXLquteDgFpRlGUutV8VbzMSEj1h0ZL8ZZC+FVYGLsPwnaxSudWrcJQa9HCKpbehqp3TFVaWIKPzl12uUsLPviKQx12uUMLPiwWi+XBzHsGOR9YxEqZqn0y1MrUCnYy5Uyfd+4gnBEWRlK8nIR0kxN0KwEHuVzWnrNeeQAgmRWUBLEh1t2ALXYvJIa+oEg3iIHLuRdPc5f4c/6Sz+fd/3NQct6DjBHHj66O4SC7dWWMOZv94Jg9w4SL4Ps3WeRzZvACLLH1d8Iu/Od6DDyJ/emvEdP7CbiREvL28sLU1MLytpyQ4PQLtc9vYI2HRk0AAAAASUVORK5CYII=') no-repeat center;
+    background-size: contain;
+  }
+
+  .sliderPoint {
+    background: #FFFFFF;
+    box-shadow: 0px 2px 4px 0px rgba(102, 102, 102, 0.77);
+    border-radius: 14px;
+    font-size: 14Px;
+    font-weight: 500;
+    height: 22Px;
+    color: #198CFE;
+    min-width: 40Px;
+    text-align: center;
+    vertical-align: text-bottom;
+
+    span {
+      font-size: 12Px;
+    }
+  }
+
+  :global {
+    .n-slider {
+      margin: 7px 0;
+      padding: 0;
+    }
+  }
+}
+
 // .videoWrap {
 //   width: 100%;
 //   height: 100%;

+ 103 - 24
src/components/card-preview/video-modal/index.tsx

@@ -9,6 +9,7 @@ import iconplay from '@views/attend-class/image/icon-pause.png';
 import iconpause from '@views/attend-class/image/icon-play.png';
 import iconReplay from '@views/attend-class/image/icon-replay.png';
 import iconPreviewDownload from '@views/attend-class/image/icon-preivew-download.png';
+import iconSpeed from '@views/attend-class/image/icon-speed.png';
 import { NSlider, useMessage } from 'naive-ui';
 import { saveAs } from 'file-saver';
 
@@ -46,7 +47,12 @@ export default defineComponent({
       currentTime: '00:00',
       durationNum: 0,
       duration: '00:00',
-      showBar: true
+      showBar: true,
+      speedControl: false,
+      speedStyle: {
+        left: '1px'
+      },
+      defaultSpeed: 1 // 默认速度
     });
     const videoRef = ref();
     const videoItem = ref();
@@ -66,15 +72,18 @@ export default defineComponent({
     //
     const toggleHideControl = (isShow: false) => {
       videoFroms.showBar = isShow;
+      videoFroms.speedControl = false;
     };
 
     const onReplay = () => {
+      videoFroms.speedControl = false;
       if (!videoItem.value) return;
       videoItem.value.currentTime(0);
     };
 
     // 切换音频播放
     const onToggleVideo = (e?: MouseEvent) => {
+      videoFroms.speedControl = false;
       e?.stopPropagation();
       if (videoFroms.paused) {
         videoItem.value.play();
@@ -104,11 +113,7 @@ export default defineComponent({
         });
     };
 
-    onMounted(() => {
-      videoItem.value = TCPlayer(videoID, {
-        appID: '',
-        controls: false
-      }); // player-container-id 为播放器容器 ID,必须与 html 中一致
+    const __init = () => {
       if (videoItem.value) {
         videoItem.value.poster(poster.value); // 封面
         videoItem.value.src(isEmtry.value ? '' : src.value); // url 播放地址
@@ -140,6 +145,14 @@ export default defineComponent({
           emit('ended');
         });
       }
+    };
+
+    onMounted(() => {
+      videoItem.value = TCPlayer(videoID, {
+        appID: '',
+        controls: false
+      }); // player-container-id 为播放器容器 ID,必须与 html 中一致
+      __init();
     });
     expose({
       // changePlayBtn,
@@ -175,18 +188,17 @@ export default defineComponent({
                   <img class={styles.playIcon} src={iconpause} />
                 )}
               </button>
-            </div>
-            <div class={styles.time}>
-              <div
-                class="plyr__time plyr__time--current"
-                aria-label="Current time">
-                {videoFroms.currentTime}
-              </div>
-              <span class={styles.line}>/</span>
+
+              <button class={styles.iconReplay} onClick={onReplay}>
+                <img src={iconReplay} />
+              </button>
+
               <div
-                class="plyr__time plyr__time--duration"
-                aria-label="Duration">
-                {videoFroms.duration}
+                class={styles.actionBtnSpeed}
+                onClick={() => {
+                  videoFroms.speedControl = !videoFroms.speedControl;
+                }}>
+                <img src={iconSpeed} />
               </div>
             </div>
           </div>
@@ -198,6 +210,7 @@ export default defineComponent({
               max={videoFroms.durationNum}
               tooltip={false}
               onUpdate:value={(val: number) => {
+                videoFroms.speedControl = false;
                 videoItem.value.currentTime(val);
                 videoFroms.currentTimeNum = val;
                 videoFroms.currentTime = timeFormat(Math.round(val || 0));
@@ -206,21 +219,87 @@ export default defineComponent({
           </div>
 
           <div class={styles.actions}>
+            <div class={styles.time}>
+              <div
+                class="plyr__time plyr__time--current"
+                aria-label="Current time">
+                {videoFroms.currentTime}
+              </div>
+              <span class={styles.line}>/</span>
+              <div
+                class="plyr__time plyr__time--duration"
+                aria-label="Duration">
+                {videoFroms.duration}
+              </div>
+            </div>
             <div class={styles.actionWrap}>
-              <button class={styles.iconReplay} onClick={onReplay}>
-                <img src={iconReplay} />
-              </button>
               {props.isDownload && (
-                <button
-                  class={styles.iconReplay}
-                  onClick={onDownload}
-                  style={{ marginLeft: '15px' }}>
+                <button class={styles.iconDownload} onClick={onDownload}>
                   <img src={iconPreviewDownload} />
                 </button>
               )}
             </div>
           </div>
         </div>
+
+        <div
+          style={{
+            display: videoFroms.speedControl ? 'block' : 'none'
+          }}>
+          <div
+            class={styles.sliderPopup}
+            onClick={(e: Event) => {
+              e.stopPropagation();
+            }}>
+            <i
+              class={styles.iconAdd}
+              onClick={() => {
+                if (videoFroms.defaultSpeed >= 1.5) {
+                  return;
+                }
+
+                if (videoItem.value) {
+                  videoFroms.defaultSpeed =
+                    (videoFroms.defaultSpeed * 10 + 1) / 10;
+                  videoItem.value.playbackRate(videoFroms.defaultSpeed);
+                }
+              }}></i>
+            <NSlider
+              value={videoFroms.defaultSpeed}
+              step={0.1}
+              max={1.5}
+              min={0.6}
+              vertical
+              tooltip={false}
+              onUpdate:value={(val: number) => {
+                videoFroms.defaultSpeed = val;
+                if (videoItem.value) {
+                  videoItem.value.playbackRate(videoFroms.defaultSpeed);
+                }
+              }}>
+              {{
+                thumb: () => (
+                  <div class={styles.sliderPoint}>
+                    {videoFroms.defaultSpeed}
+                    <span>x</span>
+                  </div>
+                )
+              }}
+            </NSlider>
+            <i
+              class={[styles.iconCut]}
+              onClick={() => {
+                if (videoFroms.defaultSpeed <= 0.6) {
+                  return;
+                }
+                if (videoItem.value) {
+                  videoFroms.defaultSpeed =
+                    (videoFroms.defaultSpeed * 10 - 1) / 10;
+                  videoItem.value.playbackRate(videoFroms.defaultSpeed);
+                }
+              }}></i>
+          </div>
+        </div>
       </div>
     );
   }

+ 1 - 0
src/views/attend-class/component/video-play.tsx

@@ -93,6 +93,7 @@ export default defineComponent({
     //
     const toggleHideControl = (isShow: false) => {
       videoFroms.showBar = isShow;
+      videoFroms.speedControl = false;
     };
 
     const onReplay = () => {

+ 5 - 0
src/views/attend-class/component/video.module.less

@@ -98,6 +98,11 @@
       height: 40px;
       background-color: transparent;
       cursor: pointer;
+
+      &>img {
+        width: 100%;
+        height: 100%;
+      }
     }