|
@@ -0,0 +1,376 @@
|
|
|
|
+import { useEffect, useState, useCallback } from 'react'
|
|
|
|
+import Taro, { useReady } from '@tarojs/taro'
|
|
|
|
+import {
|
|
|
|
+ Swiper, SwiperItem, Video,
|
|
|
|
+ View, Image, Button
|
|
|
|
+} from '@tarojs/components'
|
|
|
|
+import { DETAIL_PAGESOURCE, CATEGORY_PAGESOURCE, LIKE_ICON, DEFAULT_ICON, VIEW_AUTO_TYPE } from '@/const'
|
|
|
|
+import { favoriteUrl, unfavoriteUrl } from '@/http/api'
|
|
|
|
+import Route from '@/class/Route'
|
|
|
|
+import { videoViewReport, videoPlayReport, videoActionReport } from '@/logger'
|
|
|
|
+import { once } from '@/utils'
|
|
|
|
+import './index.less'
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+let activeIndex = 0
|
|
|
|
+let favoritePending = false
|
|
|
|
+const videoViewedMap = new Map()
|
|
|
|
+
|
|
|
|
+export default function VideoSwiper({ list, onFinish, circular, onFavorited }) {
|
|
|
|
+ const [currentIndex, setCurrentIndex] = useState(0)
|
|
|
|
+
|
|
|
|
+ useReady(() => {
|
|
|
|
+ activeIndex = 0
|
|
|
|
+ videoViewedMap.clear()
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ function onSwiperChange(res) {
|
|
|
|
+ const { detail } = res || {}
|
|
|
|
+ const { current } = detail || {}
|
|
|
|
+ activeIndex = current
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function onAnimationFinish() {
|
|
|
|
+ onFinish(activeIndex)
|
|
|
|
+ setCurrentIndex(activeIndex)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <Swiper
|
|
|
|
+ className='video-swiper'
|
|
|
|
+ vertical
|
|
|
|
+ circular={circular}
|
|
|
|
+ current={currentIndex}
|
|
|
|
+ onChange={onSwiperChange}
|
|
|
|
+ onAnimationFinish={onAnimationFinish}
|
|
|
|
+ >
|
|
|
|
+ {list.map((video, index) => {
|
|
|
|
+ return (
|
|
|
|
+ <SwiperItem className='video-swiper-item' key={video.id}>
|
|
|
|
+ <CustomVideo video={video} current={currentIndex} index={index}/>
|
|
|
|
+ <VideoIntroduce detail={video} />
|
|
|
|
+ <VideoBar video={video} onFavorited={onFavorited}/>
|
|
|
|
+ </SwiperItem>
|
|
|
|
+ )
|
|
|
|
+ })}
|
|
|
|
+ </Swiper>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function CustomVideo({ video, current, index }) {
|
|
|
|
+ const [showEndCover, setShowEndCover] = useState(false)
|
|
|
|
+ let videoContext = Taro.createVideoContext(`${video.id}`)
|
|
|
|
+ const logReportVideoPlaySuccessOnce = once(logReportVideoPlaySuccess)
|
|
|
|
+ const logReportVideoRealPlayOnce = once(logReportVideoRealPlay)
|
|
|
|
+ const logReportVideoPlayEndOnce = once(logReportVideoPlayEnd)
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ logReportVideoView(video, current, index)
|
|
|
|
+
|
|
|
|
+ if (current === index) {
|
|
|
|
+ videoContext.play()
|
|
|
|
+
|
|
|
|
+ logReportVideoPlay(video)
|
|
|
|
+ } else {
|
|
|
|
+ videoContext.pause()
|
|
|
|
+ }
|
|
|
|
+ }, [current, video])
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ setShowEndCover(false)
|
|
|
|
+ }, [current])
|
|
|
|
+
|
|
|
|
+ function onTimeUpdate(evt) {
|
|
|
|
+ if (current !== index)
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ const { detail } = evt || {}
|
|
|
|
+ const { currentTime, duration } = detail || {}
|
|
|
|
+
|
|
|
|
+ logReportVideoPlaySuccessOnce(video)
|
|
|
|
+
|
|
|
|
+ if (currentTime / duration >= 0.3 || currentTime >= 20)
|
|
|
|
+ logReportVideoRealPlayOnce(video)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function onEnded() {
|
|
|
|
+ logReportVideoPlayEndOnce(video)
|
|
|
|
+ current === index && setShowEndCover(true)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function onRePlay() {
|
|
|
|
+ setShowEndCover(false)
|
|
|
|
+ videoContext.seek(0)
|
|
|
|
+ videoContext.play()
|
|
|
|
+
|
|
|
|
+ logReportVideoPlay(video)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <View className='custom-video'>
|
|
|
|
+ <Video
|
|
|
|
+ className='video'
|
|
|
|
+ id={`${video.id}`}
|
|
|
|
+ src={video.videoPath || ''}
|
|
|
|
+ controls
|
|
|
|
+ autoplay={false}
|
|
|
|
+ showCenterPlayBtn={false}
|
|
|
|
+ poster={video.videoCoverSnapshotPath}
|
|
|
|
+ onTimeUpdate={onTimeUpdate}
|
|
|
|
+ onEnded={onEnded}
|
|
|
|
+ />
|
|
|
|
+
|
|
|
|
+ {showEndCover && <VideoPlayEndCover onRePlay={onRePlay} />}
|
|
|
|
+ </View>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function VideoIntroduce({detail}) {
|
|
|
|
+ return (
|
|
|
|
+ <View className='video-introduce'>
|
|
|
|
+ <View className='video-user-info'>
|
|
|
|
+ <Image className='avatar' src={detail.avatarUrl} />
|
|
|
|
+ {detail.nickName}
|
|
|
|
+ </View>
|
|
|
|
+ <View className='video-title'>
|
|
|
|
+ {detail.title}
|
|
|
|
+ </View>
|
|
|
|
+ <View className='video-play-count'>
|
|
|
|
+ 播放{detail.playCount}次
|
|
|
|
+ </View>
|
|
|
|
+ </View>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function VideoBar({ video, onFavorited }) {
|
|
|
|
+ const [likeIcon, setLikeIcon] = useState(video.favorited ? LIKE_ICON : DEFAULT_ICON)
|
|
|
|
+ const [showTips, setShowTips] = useState(false)
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ setLikeIcon(video.favorited ? LIKE_ICON : DEFAULT_ICON)
|
|
|
|
+ }, [video.favorited])
|
|
|
|
+
|
|
|
|
+ function clickLikeIcon(favorite) {
|
|
|
|
+ if (favoritePending)
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ favoritePending = true
|
|
|
|
+
|
|
|
|
+ const url = favorite ? favoriteUrl : unfavoriteUrl
|
|
|
|
+ onFavorited(video.id, favorite)
|
|
|
|
+
|
|
|
|
+ Taro.$http.post(url, {
|
|
|
|
+ videoId: video.id
|
|
|
|
+ }).then((res: RequestType) => {
|
|
|
|
+ const { code } = res
|
|
|
|
+
|
|
|
|
+ favoritePending = false
|
|
|
|
+
|
|
|
|
+ if (code !== 0) {
|
|
|
|
+ onFavorited(video.id, !favorite)
|
|
|
|
+ Taro.showToast({
|
|
|
|
+ title: '收藏失败',
|
|
|
|
+ icon: 'error'
|
|
|
|
+ })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ }).catch(() => {
|
|
|
|
+ favoritePending = false
|
|
|
|
+ onFavorited(video.id, !favorite)
|
|
|
|
+ Taro.showToast({
|
|
|
|
+ title: '收藏失败',
|
|
|
|
+ icon: 'error'
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function clickOperationBar(e) {
|
|
|
|
+ e.stopPropagation()
|
|
|
|
+ setShowTips(!showTips)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function clickTips() {
|
|
|
|
+ const route = new Route()
|
|
|
|
+ route.push({
|
|
|
|
+ url: '/pages/complaining/index',
|
|
|
|
+ query: {
|
|
|
|
+ videoId: video.id
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function clickVideoBar(e) {
|
|
|
|
+ e.stopPropagation()
|
|
|
|
+ setShowTips(false)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <View className='video-bar' onClick={clickVideoBar}>
|
|
|
|
+ <View className='operation' onClick={clickOperationBar}>
|
|
|
|
+ <View className='bot'></View>
|
|
|
|
+ <View className='bot margin10'></View>
|
|
|
|
+ <View className='bot'></View>
|
|
|
|
+ {showTips && <View className='tips' onClick={clickTips}>
|
|
|
|
+ <Image src='http://weapppiccdn.yishihui.com/wxicon/common/icon_jubao.png' />
|
|
|
|
+ 举报
|
|
|
|
+ </View>}
|
|
|
|
+ </View>
|
|
|
|
+ <View className='right'>
|
|
|
|
+ <View className='like'>
|
|
|
|
+ <Image className='like-icon' src={likeIcon} onClick={() => clickLikeIcon(!video.favorited)}/>
|
|
|
|
+ </View>
|
|
|
|
+ <Button className='share-btn-f' openType='share' data-button-type={6}>
|
|
|
|
+ <View className='wechat-icon' />
|
|
|
|
+ 发给好友
|
|
|
|
+ </Button>
|
|
|
|
+ </View>
|
|
|
|
+ </View>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function VideoPlayEndCover({ onRePlay }) {
|
|
|
|
+ return (
|
|
|
|
+ <View className='video-play-end-cover'>
|
|
|
|
+ <View className='container'>
|
|
|
|
+ <View className='item left'>
|
|
|
|
+ <Image src='http://weapppiccdn.yishihui.com/wxicon/common/icon_replay_01.png' onClick={onRePlay} />
|
|
|
|
+ 重播
|
|
|
|
+ </View>
|
|
|
|
+ <Button className='item right' openType='share' data-button-type={10}>
|
|
|
|
+ <Image src='http://weapppiccdn.yishihui.com/wxicon/common/icon_share_wechat_01.png' />
|
|
|
|
+ 发给好友
|
|
|
|
+ </Button>
|
|
|
|
+ </View>
|
|
|
|
+ <View className='more-video'>
|
|
|
|
+ <Image src='http://weapppiccdn.yishihui.com/wxicon/common/icon_slide_tips.png' />
|
|
|
|
+ 上滑看更多精彩视频
|
|
|
|
+ </View>
|
|
|
|
+ </View>
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 视频曝光
|
|
|
|
+function logReportVideoView(video, current, index) {
|
|
|
|
+ if (videoViewedMap.has(video.id))
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ if (current !== index)
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ if (video.type === 'temp')
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ videoViewReport({
|
|
|
|
+ actionPosition: index,
|
|
|
|
+ autoType: VIEW_AUTO_TYPE.clickView,
|
|
|
|
+ extParams: JSON.stringify({
|
|
|
|
+ recomTraceId: video.recomTraceId,
|
|
|
|
+ }),
|
|
|
|
+ viewId: video.viewId,
|
|
|
|
+ flowPool: video.flowPool || '',
|
|
|
|
+ measureId: video.measure,
|
|
|
|
+ measureType: video.measureType,
|
|
|
|
+ pageSource: DETAIL_PAGESOURCE,
|
|
|
|
+ recommendLogVO: video.recommendLogVO || '',
|
|
|
|
+ recommendSource: video.recommendSource,
|
|
|
|
+ rootPageSource: '', // TODO: 分享之后加上
|
|
|
|
+ rootPageTimestamp: '', // TODO: 分享之后加上
|
|
|
|
+ shareDepth: '', // TODO: 分享之后加上
|
|
|
|
+ videoIds: [video.id]
|
|
|
|
+ }).then(() => videoViewedMap.set(video.id, video.id))
|
|
|
|
+}
|
|
|
|
+// 视频播放
|
|
|
|
+function logReportVideoPlay(video) {
|
|
|
|
+ if (video.type === 'temp')
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ videoPlayReport({
|
|
|
|
+ videoId: video.id,
|
|
|
|
+ pageSource: DETAIL_PAGESOURCE,
|
|
|
|
+ rootPageSource: CATEGORY_PAGESOURCE,
|
|
|
|
+ shareDepth: '', // TODO: 分享之后
|
|
|
|
+ rootPageTimestamp: '', // TODO: 分享之后
|
|
|
|
+ rootMid: '', // TODO: 分享之后
|
|
|
|
+ recommendSource: video.recommendSource || 0,
|
|
|
|
+ autoType: VIEW_AUTO_TYPE.clickView,
|
|
|
|
+ playId: video.playId,
|
|
|
|
+ viewId: video.viewId,
|
|
|
|
+ measureType: video.measureType || 0,
|
|
|
|
+ measureId: video.measure,
|
|
|
|
+ flowPool: video.flowPool || '',
|
|
|
|
+ recommendId: video.recommendId || '',
|
|
|
|
+ recommendLogVO: video.recommendLogVO || ''
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+// 播放成功
|
|
|
|
+function logReportVideoPlaySuccess(video) {
|
|
|
|
+ if (video.type === 'temp')
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ videoActionReport({
|
|
|
|
+ businessType: 'videoPlaySuccess',
|
|
|
|
+ videoId: video.id,
|
|
|
|
+ pageSource: DETAIL_PAGESOURCE,
|
|
|
|
+ rootPageSource: CATEGORY_PAGESOURCE,
|
|
|
|
+ shareDepth: '', // TODO: 分享之后
|
|
|
|
+ rootPageTimestamp: '', // TODO: 分享之后
|
|
|
|
+ rootMid: '', // TODO: 分享之后
|
|
|
|
+ recommendSource: video.recommendSource || 0,
|
|
|
|
+ autoType: VIEW_AUTO_TYPE.clickView,
|
|
|
|
+ playId: video.playId,
|
|
|
|
+ viewId: video.viewId,
|
|
|
|
+ measureType: video.measureType || 0,
|
|
|
|
+ measureId: video.measure,
|
|
|
|
+ flowPool: video.flowPool || '',
|
|
|
|
+ recommendId: video.recommendId || '',
|
|
|
|
+ recommendLogVO: video.recommendLogVO || ''
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+// 真实播放
|
|
|
|
+function logReportVideoRealPlay(video) {
|
|
|
|
+ if (video.type === 'temp')
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ videoActionReport({
|
|
|
|
+ businessType: 'videoRealPlay',
|
|
|
|
+ videoId: video.id,
|
|
|
|
+ pageSource: DETAIL_PAGESOURCE,
|
|
|
|
+ rootPageSource: CATEGORY_PAGESOURCE,
|
|
|
|
+ shareDepth: '', // TODO: 分享之后
|
|
|
|
+ rootPageTimestamp: '', // TODO: 分享之后
|
|
|
|
+ rootMid: '', // TODO: 分享之后
|
|
|
|
+ recommendSource: video.recommendSource || 0,
|
|
|
|
+ autoType: VIEW_AUTO_TYPE.clickView,
|
|
|
|
+ playId: video.playId,
|
|
|
|
+ viewId: video.viewId,
|
|
|
|
+ measureType: video.measureType || 0,
|
|
|
|
+ measureId: video.measure,
|
|
|
|
+ flowPool: video.flowPool || '',
|
|
|
|
+ recommendId: video.recommendId || '',
|
|
|
|
+ recommendLogVO: video.recommendLogVO || ''
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+// 播放结束
|
|
|
|
+function logReportVideoPlayEnd(video) {
|
|
|
|
+ if (video.type === 'temp')
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ videoActionReport({
|
|
|
|
+ businessType: 'videoPlayEnd',
|
|
|
|
+ videoId: video.id,
|
|
|
|
+ pageSource: DETAIL_PAGESOURCE,
|
|
|
|
+ rootPageSource: CATEGORY_PAGESOURCE,
|
|
|
|
+ shareDepth: '', // TODO: 分享之后
|
|
|
|
+ rootPageTimestamp: '', // TODO: 分享之后
|
|
|
|
+ rootMid: '', // TODO: 分享之后
|
|
|
|
+ recommendSource: video.recommendSource || 0,
|
|
|
|
+ autoType: VIEW_AUTO_TYPE.clickView,
|
|
|
|
+ playId: video.playId,
|
|
|
|
+ viewId: video.viewId,
|
|
|
|
+ measureType: video.measureType || 0,
|
|
|
|
+ measureId: video.measure,
|
|
|
|
+ flowPool: video.flowPool || '',
|
|
|
|
+ recommendId: video.recommendId || '',
|
|
|
|
+ recommendLogVO: video.recommendLogVO || ''
|
|
|
|
+ })
|
|
|
|
+}
|