| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 |
- import { defineComponent, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
- import styles from './video.module.less'
- import { Button, Loading } from 'vant'
- import { browser } from '@/helpers/utils'
- // import Plyr from 'plyr'
- // import 'plyr/dist/plyr.css'
- import TCPlayer from 'tcplayer.js'
- import 'tcplayer.js/dist/tcplayer.css'
- import { useInterval, useIntervalFn } from '@vueuse/core'
- import { useRoute, useRouter } from 'vue-router'
- import request from '@/helpers/request'
- import qs from 'query-string'
- import { usePageVisibility } from '@vant/use'
- import deepClone from '@/helpers/deep-clone'
- export default defineComponent({
- name: 'pre-register',
- setup() {
- const route = useRoute()
- const router = useRouter()
- const pageVisibility = usePageVisibility()
- const openId = sessionStorage.getItem('active-open-id')
- // 页面定时
- const pageTimer = useInterval(1000, { controls: true })
- pageTimer.pause()
- const forms = reactive({
- videoID: 'video' + Date.now() + Math.floor(Math.random() * 100),
- coverImg: '',
- introductionVideo: '',
- introductionVideoTime: 0, // 视频总时长
- videoBrowsePoint: 0, // 视频最后观看点
- saveId: route.query.saveId,
- orchestraId: route.query.id,
- openId: route.query.openId || openId,
- loading: false,
- player: null as any,
- playerSpeed: 1,
- intervalFnRef: null as any,
- videoDetails: [] as any, // 节点列表
- pointVideo: {} as any, // 需要处理有效的时间段
- pointVideoTime: 0, // 有效时长
- videoSelectId: null, // 选中的编号
- isPageHide: false, // 处理页面返回没有刷新的问题
- parentConferencesNotes: '',
- orchestraRegisterType: '',
- status: '',
- registerDisplay: true
- })
- // 播放视频总时长
- const videoIntervalRef = useInterval(1000, { controls: true })
- videoIntervalRef.pause()
- /**
- * 格式化视屏播放有效时间 - 合并区间
- * @param intervals [[], []]
- * @example [[4, 8],[0, 4],[10, 30]]
- * @returns [[0, 8], [10, 30]]
- */
- const formatEffectiveTime = (intervals: any[]) => {
- const res: any = []
- intervals.sort((a, b) => a[0] - b[0])
- let prev = intervals[0]
- for (let i = 1; i < intervals.length; i++) {
- const cur = intervals[i]
- if (prev[1] >= cur[0]) {
- // 有重合
- prev[1] = Math.max(cur[1], prev[1])
- } else {
- // 不重合,prev推入res数组
- res.push(prev)
- prev = cur // 更新 prev
- }
- }
- res.push(prev)
- // console.log(res, 'formatEffectiveTime')
- return formatEffectiveTimeToAfter(res)
- }
- const formatEffectiveTimeToAfter = (res: any[]) => {
- // 格式化有效时间
- const effective: any = []
- const startNode = forms.pointVideo.startNode
- const endNode = forms.pointVideo.endNode
- // console.log(startNode, endNode, 'startNode')
- res.forEach((item: any) => {
- // 开始时间大于 设置时间
- if (item[1] >= item[0]) {
- /**
- * 1、开始时间
- */
- if (item[0] >= startNode && item[0] <= endNode && item[1] <= endNode) {
- // console.log(1)
- effective.push(item)
- }
- if (item[0] >= startNode && item[0] <= endNode && item[1] > endNode) {
- // console.log(3)
- effective.push([item[0], endNode])
- }
- if (item[0] < startNode && item[1] > startNode && item[1] <= endNode) {
- // console.log(4)
- effective.push([startNode, item[1]])
- }
- if (item[0] < startNode && item[1] > startNode && item[1] > endNode) {
- // console.log(4)
- effective.push([startNode, endNode])
- }
- }
- })
- // console.log(effective, 'effective')
- return effective
- }
- /**
- * 获取数据有效期
- * @param intervals [[], []]
- * @returns 0s
- */
- const formatTimer = (intervals: any[]) => {
- const afterIntervals = formatEffectiveTime(intervals)
- // console.log(afterIntervals, 'afterIntervals')
- let time = 0
- afterIntervals.forEach((t: any) => {
- time += t[1] - t[0]
- })
- return time
- }
- const checkVideoDetails = (time: number) => {
- let status = false
- forms.videoDetails.forEach((item: any) => {
- if (item.startNode <= time && time <= item.endNode) {
- forms.videoSelectId = item.id
- status = true
- }
- })
- if(!status) {
- forms.videoSelectId = null
- }
- }
- /**
- * 视屏累计时长
- * 1、视屏开始播放时-开始计时
- * 2、视频暂停时暂停-停止计时
- * 3、视频加载时-停止计时
- * 4、视频倍数播放时,时间正常计时
- * 5、点击视频进度或拖动进度时,时间暂停
- */
- const _init = () => {
- // const controls = [
- // 'play-large',
- // 'play',
- // 'progress',
- // 'captions',
- // 'current-time',
- // 'duration',
- // 'settings',
- // 'fullscreen'
- // ]
- // const params: any = {
- // controls: controls,
- // settings: ['speed'],
- // speed: { selected: 1, options: [0.5, 1, 1.5, 2] },
- // i18n: {
- // speed: '速度',
- // normal: '默认'
- // },
- // autoplay: false,
- // invertTime: false
- // }
- // if (browser().iPhone) {
- // params.fullscreen = {
- // enabled: true,
- // fallback: 'force',
- // iosNative: true
- // }
- // }
- // const times: any = []
- // forms.videoDetails.forEach((item: any) => {
- // times.push({
- // time: item.startNode,
- // label: item.desc
- // })
- // })
- // params.markers = { enabled: true, points: times }
- // forms.player = new Plyr('#register-video', params)
- // forms.player.on('ready', (item: any) => {
- // console.log('ready', item)
- // // forms.player.pause()
- // })
- // forms.player.on('loadedmetadata', () => {
- // console.log('loadedmetadata')
- // forms.loading = false
- // forms.player.currentTime() = forms.videoBrowsePoint
- // checkVideoDetails(forms.player.currentTime())
- // })
- // // 速度变化时
- // forms.player.on('ratechange', () => {
- // forms.playerSpeed =
- // forms.playerSpeed < forms.player.speed ? forms.player.speed : forms.playerSpeed
- // })
- // forms.player.on('seeking', () => {
- // console.log('seeking')
- // videoIntervalRef.isActive.value && videoIntervalRef.pause()
- // })
- // // // 拖动结束时
- // forms.player.on('seeked', () => {
- // console.log('seeked')
- // videoIntervalRef.isActive.value && videoIntervalRef.pause()
- // })
- // // 正在搜索中
- // forms.player.on('waiting', () => {
- // // console.log('waiting pause')
- // videoIntervalRef.isActive.value && videoIntervalRef.pause()
- // })
- // // 如何视频在缓存不会触发
- // forms.player.on('timeupdate', () => {
- // console.log('timeupdate', forms.player.currentTime())
- // // 时间变化时更新每一段的状态
- // checkVideoDetails(forms.player.currentTime())
- // // 判断视频计时器是否暂停,如果暂停则恢复
- // // 添加 「forms.player.playing」 是由会跳转到上次播放时间,会触发些方法
- // if (
- // !videoIntervalRef.isActive.value &&
- // forms.player.currentTime() > 0 &&
- // forms.player.playing
- // ) {
- // // console.log('timeupdate play')
- // videoIntervalRef.resume()
- // }
- // })
- // // 视屏播放时暂停
- // forms.player.on('ended', () => {
- // forms.player.pause()
- // })
- // // 开始播放
- // forms.player.on('play', () => {
- // console.log('play')
- // // 判断视频计时器是否暂停,如果暂停则恢复
- // videoIntervalRef.resume()
- // })
- // // 暂停播放
- // forms.player.on('pause', () => {
- // console.log('pause', videoIntervalRef.isActive.value)
- // videoIntervalRef.pause()
- // })
- // forms.player.on('enterfullscreen', () => {
- // console.log('fullscreen')
- // const i = document.createElement('i')
- // i.id = 'fullscreen-back'
- // i.className = 'van-icon van-icon-arrow-left video-back'
- // i.addEventListener('click', () => {
- // forms.player.fullscreen.exit()
- // })
- // console.log(document.getElementsByClassName('plyr'))
- // document.getElementsByClassName('plyr')[0].appendChild(i)
- // })
- // forms.player.on('exitfullscreen', () => {
- // console.log('exitfullscreen')
- // const i = document.getElementById('fullscreen-back')
- // i && i.remove()
- // })
- const Button = TCPlayer.getComponent('Button')
- const BigPlayButton = TCPlayer.getComponent('BigPlayButton')
- BigPlayButton.prototype.createEl = function () {
- const el = Button.prototype.createEl.call(this)
- const _html =
- '<button><svg width="41px"height="41px"viewBox="0 0 41 41"version="1.1"xmlns="http://www.w3.org/2000/svg"xmlns:xlink="http://www.w3.org/1999/xlink"><g stroke="none"stroke-width="1"fill="none"fill-rule="evenodd"><g transform="translate(-167.000000, -155.000000)"><g transform="translate(0.000000, 85.000000)"><g transform="translate(158.000000, 70.000000)"><g transform="translate(9.000000, 0.000000)"><circle id="椭圆形"stroke="#FFFFFF"fill-opacity="0.1"fill="#D8D8D8"cx="20.5"cy="20.5"r="20"></circle><path d="M14.5483871,27.6859997 L14.5483871,13.4342349 C14.5480523,12.8729571 14.8729597,12.356555 15.3949624,12.0887034 C15.9169651,11.8208518 16.5522696,11.8445472 17.0503046,12.1504437 L28.6530473,19.2778563 C29.1119763,19.5602271 29.3887725,20.0426422 29.3887725,20.5601173 C29.3887725,21.0775924 29.1119763,21.5600075 28.6530473,21.8423783 L17.0503046,28.9697909 C16.5522696,29.2756874 15.9169651,29.2993828 15.3949624,29.0315312 C14.8729597,28.7636796 14.5480523,28.2472775 14.5483871,27.6859997 Z"id="路径"fill="#FFFFFF"fill-rule="nonzero"></path></g></g></g></g></g></svg></button>'
- el.appendChild(
- TCPlayer.dom.createEl('div', {
- className: 'vjs-button-icon',
- innerHTML: _html
- })
- )
- return el
- }
- forms.player = TCPlayer('register-video', {
- appID: '',
- controls: true,
- plugins: {
- // ProgressMarker: {
- // markers: [
- // {
- // content: '1111',
- // timeOffset: 1000
- // }
- // ]
- // }
- }
- }) // player-container-id 为播放器容器 ID,必须与 html 中一致
- if (forms.player) {
- forms.player.src(forms.introductionVideo) // url 播放地址
- forms.player.poster(forms.coverImg || '')
- // forms.player.on('loadstart', () => {})
- forms.player.on('ready', (item: any) => {
- // console.log('ready', item)
- // forms.player.pause()
- })
- forms.player.on('loadedmetadata', () => {
- // console.log('loadedmetadata')
- forms.loading = false
- forms.player.currentTime(forms.videoBrowsePoint)
- checkVideoDetails(forms.player.currentTime())
- })
- // 速度变化时
- forms.player.on('ratechange', () => {
- forms.playerSpeed =
- forms.playerSpeed < forms.player.playbackRate()
- ? forms.player.playbackRate()
- : forms.playerSpeed
- })
- forms.player.on('seeking', () => {
- // console.log('seeking')
- videoIntervalRef.isActive.value && videoIntervalRef.pause()
- })
- // // 拖动结束时
- forms.player.on('seeked', () => {
- // console.log('seeked')
- videoIntervalRef.isActive.value && videoIntervalRef.pause()
- })
- // 正在搜索中
- forms.player.on('waiting', () => {
- // console.log('waiting pause')
- videoIntervalRef.isActive.value && videoIntervalRef.pause()
- })
- // 如何视频在缓存不会触发
- forms.player.on('timeupdate', () => {
- // console.log('timeupdate', forms.player.currentTime())
- // 时间变化时更新每一段的状态
- checkVideoDetails(forms.player.currentTime())
- // 判断视频计时器是否暂停,如果暂停则恢复
- // 添加 「forms.player.playing」 是由会跳转到上次播放时间,会触发些方法
- if (
- !videoIntervalRef.isActive.value &&
- forms.player.currentTime() > 0 &&
- !forms.player.paused()
- ) {
- // console.log('timeupdate play')
- videoIntervalRef.resume()
- }
- })
- // 视屏播放时暂停
- forms.player.on('ended', () => {
- forms.player.pause()
- })
- // 开始播放
- forms.player.on('play', () => {
- console.log('play')
- // 判断视频计时器是否暂停,如果暂停则恢复
- videoIntervalRef.resume()
- })
- // 暂停播放
- forms.player.on('pause', () => {
- console.log('pause', videoIntervalRef.isActive.value)
- videoIntervalRef.pause()
- })
- forms.player.on('fullscreenchange', () => {
- if (forms.player.isFullscreen()) {
- console.log('fullscreen')
- const i = document.createElement('i')
- i.id = 'fullscreen-back'
- i.className = 'van-icon van-icon-arrow-left video-back'
- i.addEventListener('click', () => {
- forms.player.exitFullscreen()
- })
- document.getElementsByClassName('video-js')[0].appendChild(i)
- } else {
- console.log('exitfullscreen')
- const i = document.getElementById('fullscreen-back')
- i && i.remove()
- }
- })
- }
- checkVideoDetails(0)
- }
- // 保存零时时间
- const moreTime: any = ref([]) // 多个观看时间段
- let tempTime: any = [] // 临时存储时间
- const currentTimer = useInterval(1000, { controls: true })
- // 监听播放状态,
- watch(
- () => videoIntervalRef.isActive.value,
- (newVal: boolean) => {
- // console.log(videoIntervalRef.isActive.value, 'videoIntervalRef')
- initVideoCount(newVal)
- }
- )
- /**
- * 初始化视频时长
- * @param newVal 播放状态
- * @param repeat 是否为定时发送的
- */
- const initVideoCount = (newVal: any, repeat = false) => {
- // console.log('watch', forms.player.currentTime)
- const initTime = deepClone(tempTime)
- if (repeat) {
- if (tempTime.length > 0) {
- // console.log('join video', tempTime, 'initTime', initTime)
- tempTime[1] = Math.floor(forms.player.currentTime())
- }
- } else {
- if (newVal) {
- tempTime[0] = Math.floor(forms.player.currentTime())
- } else {
- tempTime[1] = Math.floor(forms.player.currentTime())
- }
- }
- // console.log(newVal, repeat, tempTime, tempTime.length, 'videoIntervalRef.isActive.value in')
- // console.log(forms.player.speed, 'speed')
- if (tempTime.length >= 2) {
- // console.log(tempTime, 'tempTime', moreTime.value)
- // 处理在短时间内的时间差 【视屏拖动,点击可能会导致时间差太大】
- const diffTime =
- tempTime[1] - tempTime[0] - currentTimer.counter.value * forms.playerSpeed > 2
- // console.log(diffTime, 'diffTime', currentTimer.counter.value, forms.playerSpeed, 'value')
- // 结束时间,如果 大于开始时间则清除
- if (tempTime[1] >= tempTime[0] && !diffTime) moreTime.value.push(tempTime)
- if (repeat) {
- tempTime = deepClone(initTime)
- } else {
- tempTime = []
- currentTimer.counter.value = 0
- }
- }
- // console.log('观看的时间', moreTime)
- }
- watch(pageVisibility, (value: any) => {
- console.log('watch', value)
- if (value == 'hidden') {
- forms.player.pause()
- }
- })
- // 更新时间
- const updateStat = async (pageBrowseTime = 10) => {
- try {
- const videoBrowseData = moreTime.value.length > 0 ? formatEffectiveTime(moreTime.value) : []
- // console.log(moreTime.value, videoBrowseData, 'video')
- const time = videoBrowseData.length > 0 ? formatTimer(videoBrowseData) : 0
- // const videoCountTime = videoIntervalRef?.counter.value
- // 判断如何视屏播放时间大于视屏播放有效时间则说明数据有问题,进行重置数据
- const rate = Math.floor((time / Math.floor(forms.pointVideoTime)) * 100)
- // console.log('videoIntervalRef?.counter.value', videoIntervalRef?.counter.value)
- await request.post('/api-student/open/studentBrowseRecord/updateStat', {
- data: {
- id: forms.saveId,
- pageBrowseTime, // 固定10秒
- videoBrowseData: JSON.stringify(videoBrowseData), // 视屏播放数据
- videoBrowseDataTime: time || 0, // 有效的视频观看时长
- videoBrowsePercentage: rate || 0, // 有效的视频观看时长百分比
- videoBrowseTime: videoIntervalRef?.counter.value, // 视频观看时长
- videoBrowsePoint: Math.floor(forms.player.currentTime() || 0) // 视频最后观看点 - 向下取整
- }
- })
- } catch {
- //
- }
- }
- // 提交
- const onSubmit = async () => {
- try {
- forms.player.pause() // 视屏
- forms.intervalFnRef?.pause() // 页面订时器
- currentTimer.pause()
- videoIntervalRef.pause()
- // 页面计时暂停
- pageTimer.pause()
- initVideoCount(videoIntervalRef.isActive.value)
- await updateStat()
- console.log(forms.orchestraRegisterType)
- if (forms.orchestraRegisterType === 'PARENT_CONFERENCES') {
- window.location.href =
- window.location.origin +
- window.location.pathname +
- `/#/preApply?id=${forms.orchestraId}`
- } else if (forms.orchestraRegisterType === 'GROUP_BUY') {
- window.location.href =
- window.location.origin +
- window.location.pathname +
- `/#/preGoodsApply?id=${forms.orchestraId}`
- } else {
- window.location.href =
- window.location.origin +
- window.location.pathname +
- '/project/preRegister.html?' +
- qs.stringify({
- orchestraId: forms.orchestraId,
- openId: forms.openId
- })
- }
- } catch (e) {
- console.log(e, 'e')
- // 还原
- forms.intervalFnRef?.resume()
- pageTimer.resume()
- currentTimer.resume()
- }
- }
- onMounted(async () => {
- try {
- const { data } = await request.get('/api-student/open/studentBrowseRecord/query', {
- params: {
- openId: forms.openId,
- orchestraId: forms.orchestraId
- }
- })
- forms.videoBrowsePoint = data.videoBrowsePoint || 0
- if (forms.player) {
- forms.player.currentTime(data.videoBrowsePoint || 0)
- }
- forms.introductionVideo = data.introductionVideo
- forms.introductionVideoTime = data.introductionVideoTime
- forms.coverImg = data.coverImg
- moreTime.value = data.videoBrowseData ? JSON.parse(data.videoBrowseData) : []
- forms.parentConferencesNotes = data.parentConferencesNotes
- forms.orchestraRegisterType = data.orchestraRegisterType
- forms.registerDisplay = data.registerDisplay
- const videoDetails = data.videoDetails || []
- videoDetails.forEach((video: any) => {
- forms.videoDetails.push({
- startNode: video.startNode,
- endNode: video.endNode,
- desc: video.desc,
- id: video.id
- })
- if (video.pointFlag) {
- forms.pointVideo = video
- forms.pointVideoTime = video.endNode - video.startNode
- }
- })
- _init()
- // 间隔多少时间同步数据
- forms.intervalFnRef = useIntervalFn(async () => {
- // 页面时间恢复
- pageTimer.counter.value = 0
- pageTimer.resume()
- // 同步数据时先进行有效时间进行保存
- initVideoCount(false, true)
- await updateStat()
- videoIntervalRef.counter.value = 0
- }, 10000)
- // const arr = [
- // [10, 10],
- // [53, 53],
- // [64, 64],
- // [74, 74],
- // [155, 155],
- // [173, 173],
- // [183, 183],
- // [191, 201]
- // ]
- // console.log(formatEffectiveTime(arr))
- } catch {
- //
- }
- })
- onUnmounted(() => {
- forms.player?.fullscreen?.exit()
- forms.intervalFnRef?.pause()
- currentTimer.pause()
- // 页面计时暂停
- pageTimer.pause()
- forms.player?.pause();
- forms.player?.src('');
- forms.player?.dispose();
- })
- // 判断是否有openId
- if (!forms.openId) {
- router.replace({
- path: '/pre-register-video',
- query: {
- id: forms.orchestraId
- }
- })
- }
- const onPageShow = () => {
- // console.log(forms.isPageHide, 'showInfo')
- if (forms.isPageHide) {
- window.location.reload()
- }
- }
- // 处理监听页面返回不刷新的问题
- window.addEventListener('pageshow', onPageShow)
- const onPageHide = () => {
- // console.log(forms.isPageHide, 'showInfo')
- forms.isPageHide = true
- }
- window.addEventListener('pagehide', onPageHide)
- onUnmounted(() => {
- window.removeEventListener('pageshow', onPageShow)
- window.removeEventListener('pagehide', onPageHide)
- })
- return () => (
- <div class={styles['pre-register-video']}>
- <div class={styles.videoContainer}>
- <div class={styles['video-content']}>
- <video
- id="register-video"
- class={styles['video']}
- src={forms.introductionVideo}
- playsinline={true}
- poster={forms.coverImg}
- preload="auto"
- ></video>
- {/* 加载视频使用 */}
- {forms.loading && (
- <div class={styles.loadingVideo}>
- <Loading
- size={36}
- color="#FF8057"
- vertical
- style={{ height: '100%', justifyContent: 'center' }}
- >
- 加载中...
- </Loading>
- </div>
- )}
- </div>
- </div>
- <div class={styles.videoCount}>
- <div class={styles.videoTitle}></div>
- <div class={styles.videoCountContent}>
- {forms.videoDetails.map((item: any) => (
- <span
- class={[item.id === forms.videoSelectId ? styles.active : '']}
- onClick={() => {
- forms.player.currentTime(item.startNode)
- forms.player.play()
- forms.videoBrowsePoint = item.startNode
- checkVideoDetails(forms.player.currentTime())
- }}
- >
- {item.desc}
- </span>
- ))}
- </div>
- </div>
- <div class={styles.messageContainer}>
- <div class={styles.messageContent}>
- {/* <p>家长您好!</p>
- <p class={styles.c1}>
- 请家长们合理安排时间,<span>认真观看</span>家长会内容。在<span>详细了解</span>
- 所有要求后,有意向让孩子加入乐团的家长,请在<span>明晚20:00前</span>,为孩子完成
- <span>乐团报名</span>。
- </p>
- <p class={styles.c1}>
- 下周,专业老师将针对意向入团学员进行身体条件确认。谢谢各位的支持!
- </p>
- <p class={styles.bottom}>
- 注:乐团于下学期正式开始训练,训练时间下学期开学前另行通知,训练时间会与学校其他社团错开,家长无需担心时间冲突问题。
- </p> */}
- <div v-html={forms.parentConferencesNotes}></div>
- {forms.registerDisplay && <Button class={styles.submitBtn} onClick={onSubmit}></Button>}
- </div>
- </div>
- </div>
- )
- }
- })
|