Quellcode durchsuchen

fix(回放): 修复无法暂停问题,修复无法接着下一个视频播放问题,修复进度条异常问题

xieyonghong vor 4 Jahren
Ursprung
Commit
02d0e6a4e0

+ 14 - 7
src/components/Player/index.tsx

@@ -1,4 +1,4 @@
-import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
+import { useEffect, useRef, forwardRef, useImperativeHandle, useState } from 'react';
 import { isFunction } from 'lodash';
 
 export type PlayerProps = {
@@ -12,17 +12,18 @@ export type PlayerProps = {
   updateTime?: number;
   key?: string | number;
   loading?: boolean;
-  onDestroy?: () => void;
+  onDestroy?: (e?: any) => void;
   onMessage?: (msg: any) => void;
   onError?: (err: any) => void;
   onTimeUpdate?: (time: any) => void;
-  onPause?: () => void;
-  onPlay?: () => void;
+  onPause?: (e?: any) => void;
+  onPlay?: (e?: any) => void;
   protocol?: 'mp4' | 'flv' | 'hls';
   onFullscreen?: () => void;
   onSnapOutside?: (base64: any) => void;
   onSnapInside?: (base64: any) => void;
   onCustomButtons?: (name: any) => void;
+  onEnded?: (e?: any) => void;
   onClick?: () => void;
 };
 
@@ -36,9 +37,11 @@ const EventsEnum = {
   snapOutside: 'onSnapOutside',
   snapInside: 'onSnapInside',
   customButtons: 'onCustomButtons',
+  ended: 'onEnded',
 };
 const LivePlayer = forwardRef((props: PlayerProps, ref) => {
   const player = useRef<HTMLVideoElement>(null);
+  const [url, setUrl] = useState(props.url);
 
   useEffect(() => {
     return () => {
@@ -49,14 +52,18 @@ const LivePlayer = forwardRef((props: PlayerProps, ref) => {
     };
   }, []);
 
+  useEffect(() => {
+    setUrl(props.url);
+  }, [props.url]);
+
   /**
    * 事件初始化
    */
   const EventInit = () => {
     for (const key in EventsEnum) {
-      player.current?.addEventListener(key, () => {
+      player.current?.addEventListener(key, (e) => {
         if (EventsEnum[key] in props) {
-          props[EventsEnum[key]]();
+          props[EventsEnum[key]](e);
         }
       });
     }
@@ -84,7 +91,7 @@ const LivePlayer = forwardRef((props: PlayerProps, ref) => {
       hide-big-play-button={true}
       poster={props.poster || ''}
       timeout={props.timeout || 20}
-      video-url={props.url || ''}
+      video-url={url || ''}
     />
   );
 });

+ 47 - 25
src/pages/media/Device/Playback/index.tsx

@@ -26,19 +26,22 @@ export default () => {
   const [type, setType] = useState('local');
   const [historyList, setHistoryList] = useState<recordsItemType[]>([]);
   const [time, setTime] = useState<Moment | undefined>(undefined);
-  const [playTime, setPlayTime] = useState(0);
   // const [loading, setLoading] = useState(false)
   const [cloudTime, setCloudTime] = useState<any>();
-  const [playing, setPlaying] = useState(false);
   const location = useLocation();
   const player = useRef<any>();
+  const [playStatus, setPlayStatus] = useState(0); // 播放状态, 0 停止, 1 播放, 2 暂停, 3 播放完成
+  const [playTime, setPlayTime] = useState(0);
 
+  const playNowTime = useRef<number>(0); // 当前播放视频标识
+  const playTimeNode = useRef<any>(null);
+  const isEnded = useRef(false); // 是否结束播放
   const param = new URLSearchParams(location.search);
   const deviceId = param.get('id');
   const channelId = param.get('channelId');
 
   const queryLocalRecords = async (date: Moment) => {
-    setPlaying(false);
+    setPlayStatus(0);
     setUrl('');
     if (deviceId && channelId && date) {
       const params = {
@@ -73,7 +76,7 @@ export default () => {
   };
 
   const queryServiceRecords = async (date: Moment) => {
-    setPlaying(false);
+    setPlayStatus(0);
     setUrl('');
     if (deviceId && channelId && date) {
       const params = {
@@ -189,25 +192,41 @@ export default () => {
             live={type === 'local'}
             ref={player}
             onPlay={() => {
-              setPlaying(true);
+              isEnded.current = false;
+              setPlayStatus(1);
             }}
             onPause={() => {
-              setPlaying(false);
+              setPlayStatus(2);
+            }}
+            onEnded={() => {
+              setPlayStatus(0);
+              if (playTimeNode.current && !isEnded.current) {
+                isEnded.current = true;
+                playTimeNode.current.onNextPlay();
+              }
             }}
             onDestroy={() => {
-              setPlaying(false);
+              setPlayStatus(0);
+              if (player.current.getVueInstance) {
+                player.current.getVueInstance().pause();
+              }
             }}
             onError={() => {
-              setPlaying(false);
+              setPlayStatus(0);
+            }}
+            onTimeUpdate={(e) => {
+              setPlayTime(parseInt(e.detail[0]));
             }}
           />
           <TimeLine
+            ref={playTimeNode}
             type={type}
             data={historyList}
             dateTime={time}
             onChange={(times) => {
               if (times) {
-                setPlayTime(Number(times.endTime.valueOf()));
+                playNowTime.current = Number(times.startTime.valueOf());
+                setPlayTime(0);
                 setUrl(
                   type === 'local'
                     ? service.playbackLocal(
@@ -223,7 +242,8 @@ export default () => {
                 setUrl('');
               }
             }}
-            playing={playing}
+            playStatus={playStatus}
+            playTime={playNowTime.current + playTime * 1000}
             localToServer={cloudTime}
           />
         </div>
@@ -266,28 +286,26 @@ export default () => {
                 itemLayout="horizontal"
                 dataSource={historyList}
                 renderItem={(item) => {
+                  const _startTime = item.startTime || item.mediaStartTime;
                   const startTime = moment(item.startTime || item.mediaStartTime).format(
                     'HH:mm:ss',
                   );
                   const endTime = moment(item.endTime || item.mediaEndTime).format('HH:mm:ss');
                   const downloadObj = DownloadIcon(item);
-                  const timeId = item.endTime || item.mediaEndTime;
-
-                  console.log(timeId, playTime);
                   return (
                     <List.Item
                       actions={[
                         <Tooltip
                           key="play-btn"
-                          title={item.startTime === playTime ? '暂停' : '播放'}
+                          title={
+                            _startTime === playNowTime.current && playStatus === 1 ? '暂停' : '播放'
+                          }
                         >
                           <a
                             onClick={() => {
-                              if (!playTime) {
-                                setPlayTime(item.startTime);
-                                if (item.filePath) {
-                                  service.playbackStart(item.id);
-                                } else if (deviceId && channelId) {
+                              if (playStatus === 0 || _startTime !== playNowTime.current) {
+                                playNowTime.current = _startTime;
+                                if (type === 'local' && deviceId && channelId) {
                                   setUrl(
                                     service.playbackLocal(
                                       deviceId,
@@ -297,17 +315,21 @@ export default () => {
                                       moment(item.endTime).format('YYYY-MM-DD HH:mm:ss'),
                                     ),
                                   );
+                                } else {
+                                  setUrl(service.playbackStart(item.id));
                                 }
-                              } else {
-                                console.log(player.current);
-                                if (player.current.pause) {
-                                  player.current.pause();
+                              } else if (playStatus == 1 && _startTime === playNowTime.current) {
+                                if (player.current.getVueInstance) {
+                                  player.current.getVueInstance().pause();
                                 }
-                                setPlayTime(0);
                               }
                             }}
                           >
-                            {timeId === playTime ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
+                            {_startTime === playNowTime.current && playStatus === 1 ? (
+                              <PauseCircleOutlined />
+                            ) : (
+                              <PlayCircleOutlined />
+                            )}
                           </a>
                         </Tooltip>,
                         <Tooltip key={'download'} title={downloadObj.title}>

+ 39 - 37
src/pages/media/Device/Playback/timeLine.tsx

@@ -1,7 +1,7 @@
 import { message } from 'antd';
 import moment from 'moment';
 import type { Moment } from 'moment';
-import { useEffect, useState, useRef } from 'react';
+import { useEffect, useState, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';
 import './index.less';
 import { recordsItemType } from '@/pages/media/Device/Playback/typings';
 import { useSize } from 'ahooks';
@@ -19,7 +19,8 @@ interface Props {
   data: recordsItemType[];
   dateTime?: Moment;
   type: string;
-  playing: boolean;
+  playStatus: number;
+  playTime: number;
   server?: any;
   localToServer?: {
     endTime: number;
@@ -28,7 +29,7 @@ interface Props {
   getPlayList?: (data: any) => void;
 }
 
-const Progress = (props: Props) => {
+const Progress = forwardRef((props: Props, ref) => {
   const [startT, setStartT] = useState<number>(
     new Date(moment(props.dateTime).startOf('day').format('YYYY-MM-DD HH:mm:ss')).getTime(),
   ); // 获取选中当天开始时间戳
@@ -37,7 +38,7 @@ const Progress = (props: Props) => {
   ).getTime(); // 获取选中当天结束时间戳
 
   const [list, setList] = useState<any[]>([]);
-  const [time, setTime] = useState<number>(startT);
+  const [playTime, setPlayTime] = useState<number>(0);
 
   const LineContent = useRef<HTMLDivElement>(null);
   const LineContentSize = useSize(LineContent);
@@ -61,6 +62,8 @@ const Progress = (props: Props) => {
   }, [props.dateTime]);
 
   const onChange = (startTime: number, endTime: number, deviceId: string, channelId: string) => {
+    console.log(startTime, endTime, deviceId, channelId);
+    setPlayTime(startTime);
     props.onChange({
       startTime: moment(startTime),
       endTime: moment(endTime),
@@ -69,6 +72,24 @@ const Progress = (props: Props) => {
     });
   };
 
+  const onNextPlay = useCallback(() => {
+    if (playTime) {
+      // 查找下一个视频
+      const nowIndex = props.data.findIndex((item) => {
+        const startTime = item.startTime || item.mediaStartTime;
+        return startTime === playTime;
+      });
+      // 是否为最后一个
+      if (nowIndex !== props.data.length - 1) {
+        const nextPlay = props.data[nowIndex + 1];
+        const startTime = nextPlay.startTime || nextPlay.mediaStartTime;
+        const endTime = nextPlay.endTime || nextPlay.mediaEndTime;
+        const deviceId = props.type === 'local' ? nextPlay.deviceId : nextPlay.id;
+        onChange(startTime, endTime, deviceId, nextPlay.channelId);
+      }
+    }
+  }, [props.type, playTime]);
+
   useEffect(() => {
     const { data, localToServer, type } = props;
     if (data && Array.isArray(data) && data.length > 0) {
@@ -76,7 +97,6 @@ const Progress = (props: Props) => {
       if (type === 'local') {
         // 播放第一个
         onChange(data[0].startTime, data[0].endTime, data[0].deviceId, data[0].channelId);
-        setTime(startT);
       } else if (type === 'cloud') {
         // 是否从本地跳转到云端播放
         if (localToServer && Object.keys(localToServer).length > 0) {
@@ -95,14 +115,11 @@ const Progress = (props: Props) => {
               playItem.id,
               playItem.channelId,
             );
-            setTime(playItem.mediaStartTime);
           } else {
             props.onChange(undefined);
-            setTime(localToServer.startTime);
             message.error('没有可播放的视频资源');
           }
         } else {
-          setTime(data[0].mediaStartTime);
           onChange(data[0].mediaStartTime, data[0].mediaEndTime, data[0].id, data[0].channelId);
         }
       }
@@ -110,28 +127,14 @@ const Progress = (props: Props) => {
       // 本地跳转云端但是无资源
       props.onChange(undefined);
       message.error('没有可播放的视频资源');
-      setTime(startT);
       setList([]);
     } else {
       // 啥都没有
-      setTime(startT);
       setList([]);
       props.onChange(undefined);
     }
   }, [props.data]);
 
-  useEffect(() => {
-    // if(props.server && Object.keys(props.server).length > 0){
-    //   if(props.type === 'local'){
-    //     setTime(props.server.startTime)
-    //     props.play({ start: props.server.startTime, end: props.server.endTime })
-    //   } else {
-    //     setTime(props.server.mediaStartTime)
-    //     props.play(props.server)
-    //   }
-    // }
-  }, [props.server]);
-
   const getLineItemStyle = (
     startTime: number,
     endTime: number,
@@ -146,21 +149,20 @@ const Progress = (props: Props) => {
   };
 
   useEffect(() => {
-    let timerId: any = null;
-    if (props.playing) {
-      timerId = setInterval(() => {
-        // eslint-disable-next-line @typescript-eslint/no-shadow
-        setTime((time) => time + 1000);
-      }, 1000);
+    if (
+      props.playTime &&
+      props.playTime >= startT &&
+      props.playTime <= endT &&
+      props.data &&
+      props.data.length
+    ) {
+      setTimeAndPosition((props.playTime - startT) / 3600000 / 24);
     }
-    return () => timerId && clearInterval(timerId);
-  }, [props.playing]);
+  }, [props.playTime, startT]);
 
-  useEffect(() => {
-    if (time >= startT && time <= endT && props.data && props.data.length) {
-      setTimeAndPosition((time - startT) / 3600000 / 24);
-    }
-  }, [time]);
+  useImperativeHandle(ref, () => ({
+    onNextPlay,
+  }));
 
   return (
     <div className={'time-line-warp'}>
@@ -196,10 +198,10 @@ const Progress = (props: Props) => {
         </div>
         <div id="btn" className={classNames('time-line-btn')}></div>
         <div id="time" className={classNames('time-line')}>
-          {moment(time).format('HH:mm:ss')}
+          {moment(props.playTime || 0).format('HH:mm:ss')}
         </div>
       </div>
     </div>
   );
-};
+});
 export default Progress;