|
@@ -23,12 +23,11 @@ import {
|
|
|
} from 'vue'
|
|
|
import iconBack from './image/back.svg'
|
|
|
import styles from './index.module.less'
|
|
|
-import Plyr from 'plyr'
|
|
|
import 'plyr/dist/plyr.css'
|
|
|
import request from '@/helpers/request'
|
|
|
import { state } from '@/state'
|
|
|
import { useRoute } from 'vue-router'
|
|
|
-import { listenerMessage, postMessage } from '@/helpers/native-message'
|
|
|
+import { listenerMessage, postMessage, promisefiyPostMessage } from '@/helpers/native-message'
|
|
|
import MusicScore from './component/musicScore'
|
|
|
import iconMenu from './image/icon-menu.svg'
|
|
|
import iconDian from './image/icon-dian.svg'
|
|
@@ -37,25 +36,32 @@ import iconLoop from './image/icon-loop.svg'
|
|
|
import iconLoopActive from './image/icon-loop-active.svg'
|
|
|
import iconplay from './image/icon-play.svg'
|
|
|
import iconpause from './image/icon-pause.svg'
|
|
|
+import iconUp from './image/icon-up.svg'
|
|
|
+import iconDown from './image/icon-down.svg'
|
|
|
+import iconVideobg from './image/icon-videobg.png'
|
|
|
import Points from './component/points'
|
|
|
-import { getSecondRPM } from '@/helpers/utils'
|
|
|
+import { browser, getSecondRPM } from '@/helpers/utils'
|
|
|
+import { useRect } from '@vant/use'
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'CoursewarePlay',
|
|
|
setup() {
|
|
|
const handleInit = (type = 0) => {
|
|
|
+ // 横屏
|
|
|
postMessage({
|
|
|
api: 'setRequestedOrientation',
|
|
|
content: {
|
|
|
orientation: type
|
|
|
}
|
|
|
})
|
|
|
+ // 头,包括返回箭头
|
|
|
postMessage({
|
|
|
- api: 'setBarStatus',
|
|
|
+ api: 'setTitleBarVisibility',
|
|
|
content: {
|
|
|
status: type
|
|
|
}
|
|
|
})
|
|
|
+ // 安卓的状态栏
|
|
|
postMessage({
|
|
|
api: 'setStatusBarVisibility',
|
|
|
content: {
|
|
@@ -66,17 +72,16 @@ export default defineComponent({
|
|
|
handleInit()
|
|
|
onUnmounted(() => {
|
|
|
handleInit(1)
|
|
|
+ window.removeEventListener('message', iframeHandle)
|
|
|
})
|
|
|
|
|
|
const route = useRoute()
|
|
|
+ const headeRef = ref()
|
|
|
const data = reactive({
|
|
|
detail: null,
|
|
|
- active: '',
|
|
|
- itemActive: '',
|
|
|
knowledgePointList: [] as any,
|
|
|
itemList: [] as any,
|
|
|
- showHead: true,
|
|
|
- players: [] as any
|
|
|
+ showHead: true
|
|
|
})
|
|
|
const activeData = reactive({
|
|
|
nowTime: 0,
|
|
@@ -87,38 +92,89 @@ export default defineComponent({
|
|
|
timer: null as any,
|
|
|
item: null as any
|
|
|
})
|
|
|
- const getItemList = () => {
|
|
|
+ watch(
|
|
|
+ () => activeData.model,
|
|
|
+ () => {
|
|
|
+ const videoItem = data.itemList.find((n) => n.id === popupData.itemActive)
|
|
|
+ // 阴影切换的时候,具体去切换某个视频的控件
|
|
|
+ if (videoItem && videoItem.type === 'VIDEO') {
|
|
|
+ videoItem.playModel = activeData.model
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+ // 获取缓存路径
|
|
|
+ const getCacheFilePath = async (material: any) => {
|
|
|
+ const res = await promisefiyPostMessage({
|
|
|
+ api: 'getCourseFilePath',
|
|
|
+ content: {
|
|
|
+ url: material.content,
|
|
|
+ localPath: '',
|
|
|
+ materialId: material.id,
|
|
|
+ updateTime: material.updateTime,
|
|
|
+ type: material.type // SONG VIDEO IMAGE
|
|
|
+ }
|
|
|
+ })
|
|
|
+ console.log('缓存路径返回', res)
|
|
|
+ return res
|
|
|
+ }
|
|
|
+ const getItemList = async () => {
|
|
|
const list: any = []
|
|
|
+ const browserInfo = browser()
|
|
|
+ let _item = null
|
|
|
for (let i = 0; i < data.knowledgePointList.length; i++) {
|
|
|
const item = data.knowledgePointList[i]
|
|
|
+ const itemLength = item.materialList.length - 1
|
|
|
for (let j = 0; j < item.materialList.length; j++) {
|
|
|
const material = item.materialList[j]
|
|
|
- if (popupData.itemActive === '') {
|
|
|
- popupData.tabName = item.name
|
|
|
- popupData.tabActive = material.knowledgePointId
|
|
|
- popupData.itemActive = material.id
|
|
|
- popupData.itemName = material.name
|
|
|
- popupData.activeIndex = 0
|
|
|
+ //请求本地缓存
|
|
|
+ if (browserInfo.isApp && ['VIDEO', 'IMG'].includes(material.type)) {
|
|
|
+ const localData = await getCacheFilePath(material)
|
|
|
+ if (localData?.content?.localPath) {
|
|
|
+ material.url = material.content
|
|
|
+ material.content = localData.content.localPath
|
|
|
+ // console.log("🚀 ~ material", material)
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
let videoItem = {}
|
|
|
if (material.type === 'VIDEO') {
|
|
|
videoItem = {
|
|
|
currentTime: 0,
|
|
|
- duration: 0,
|
|
|
+ duration: 100,
|
|
|
paused: true,
|
|
|
loop: false,
|
|
|
videoEle: null,
|
|
|
- timer: null
|
|
|
+ timer: null,
|
|
|
+ playModel: true
|
|
|
}
|
|
|
}
|
|
|
list.push({
|
|
|
...material,
|
|
|
- ...videoItem
|
|
|
+ ...videoItem,
|
|
|
+ iframeRef: null,
|
|
|
+ tabName: item.name,
|
|
|
+ autoPlay: j === itemLength
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ let item: any = null
|
|
|
+ if (route.query.kId) {
|
|
|
+ item = list.find((n: any) => n.id == route.query.kId)
|
|
|
+ const _firstIndex = list.findIndex((n: any) => n.id == route.query.kId)
|
|
|
+ popupData.firstIndex = _firstIndex > -1 ? _firstIndex : 0
|
|
|
+ } else {
|
|
|
+ item = list[0] || {}
|
|
|
+ }
|
|
|
+ if (item) {
|
|
|
+ popupData.tabName = item.tabName
|
|
|
+ popupData.tabActive = item.knowledgePointId
|
|
|
+ popupData.itemActive = item.id
|
|
|
+ popupData.itemName = item.name
|
|
|
+ popupData.activeIndex = popupData.firstIndex
|
|
|
+ }
|
|
|
console.log('🚀 ~ list', list)
|
|
|
- return list
|
|
|
+ data.itemList = list
|
|
|
}
|
|
|
const getDetail = async () => {
|
|
|
try {
|
|
@@ -133,21 +189,29 @@ export default defineComponent({
|
|
|
n.index = 0
|
|
|
return n
|
|
|
})
|
|
|
- data.itemList = getItemList()
|
|
|
+ getItemList()
|
|
|
}
|
|
|
} catch (error) {}
|
|
|
}
|
|
|
+ // ifram事件处理
|
|
|
+ const iframeHandle = (ev: MessageEvent) => {
|
|
|
+ // console.log(ev.data)
|
|
|
+ if (ev.data?.api === 'headerTogge') {
|
|
|
+ activeData.model = ev.data.show
|
|
|
+ }
|
|
|
+ }
|
|
|
onMounted(() => {
|
|
|
getDetail()
|
|
|
+ window.addEventListener('message', iframeHandle)
|
|
|
})
|
|
|
// 返回
|
|
|
const goback = () => {
|
|
|
- // history.go(-1)
|
|
|
- postMessage({ api: 'back' })
|
|
|
+ postMessage({ api: 'goBack' })
|
|
|
}
|
|
|
|
|
|
const swipeRef = ref()
|
|
|
const popupData = reactive({
|
|
|
+ firstIndex: 0,
|
|
|
open: false,
|
|
|
activeIndex: -1,
|
|
|
tabActive: '',
|
|
@@ -156,8 +220,9 @@ export default defineComponent({
|
|
|
itemName: ''
|
|
|
})
|
|
|
// 设置当前的激活状态
|
|
|
- const setActiveData = () => {
|
|
|
+ const setActiveData = (val: any, oldVal: any) => {
|
|
|
handleStopVideo()
|
|
|
+ handleStopMusicScore()
|
|
|
}
|
|
|
watch(() => popupData.activeIndex, setActiveData)
|
|
|
|
|
@@ -167,16 +232,11 @@ export default defineComponent({
|
|
|
m.videoEle?.pause()
|
|
|
})
|
|
|
}
|
|
|
- // 获取name
|
|
|
- const setAllName = () => {
|
|
|
- const item = data.itemList.find((n: any) => n.id == popupData.itemActive)
|
|
|
- const tab = data.knowledgePointList.find((n: any) => n.id == popupData.tabActive)
|
|
|
- if (item) {
|
|
|
- popupData.itemName = item.name
|
|
|
- }
|
|
|
- if (tab) {
|
|
|
- popupData.tabName = tab.name
|
|
|
- }
|
|
|
+ // 停止曲谱的播放
|
|
|
+ const handleStopMusicScore = () => {
|
|
|
+ data.itemList.forEach((m: any) => {
|
|
|
+ m.iframeRef?.contentWindow?.postMessage({ api: 'setPlayState' }, '*')
|
|
|
+ })
|
|
|
}
|
|
|
// 切换素材
|
|
|
const toggleMaterial = () => {
|
|
@@ -184,7 +244,6 @@ export default defineComponent({
|
|
|
if (index > -1) {
|
|
|
popupData.activeIndex = index
|
|
|
swipeRef.value?.swipeTo(index)
|
|
|
- setAllName()
|
|
|
}
|
|
|
}
|
|
|
// 轮播切换
|
|
@@ -194,7 +253,8 @@ export default defineComponent({
|
|
|
if (item) {
|
|
|
popupData.tabActive = item.knowledgePointId
|
|
|
popupData.itemActive = item.id
|
|
|
- setAllName()
|
|
|
+ popupData.itemName = item.name
|
|
|
+ popupData.tabName = item.tabName
|
|
|
}
|
|
|
}
|
|
|
// 上一个知识点, 下一个知识点
|
|
@@ -236,19 +296,10 @@ export default defineComponent({
|
|
|
item.timer = setTimeout(() => {
|
|
|
activeData.model = false
|
|
|
}, 3000)
|
|
|
- console.dir(videoEle)
|
|
|
+ // console.dir(videoEle)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 视频播放
|
|
|
- const handleVideoPlay = (e: Event) => {
|
|
|
- const videoEle = e.target! as unknown as HTMLVideoElement
|
|
|
- // console.log(videoEle.paused, videoEle.currentTime, videoEle.duration)
|
|
|
- if (videoEle.paused) return
|
|
|
- activeData.currentTime = videoEle.currentTime
|
|
|
- activeData.duration = videoEle.duration
|
|
|
- }
|
|
|
-
|
|
|
// 调整播放进度
|
|
|
const handleChangeSlider = (val: any, m: any) => {
|
|
|
if (m?.videoEle) {
|
|
@@ -256,6 +307,41 @@ export default defineComponent({
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ //当前视频播放完
|
|
|
+ const handleEnded = (m: any) => {
|
|
|
+ // console.log(m)
|
|
|
+ // 自动播放下一个知识点
|
|
|
+ if (m.autoPlay) {
|
|
|
+ if (popupData.activeIndex != data.itemList.length - 1) {
|
|
|
+ popupData.activeIndex++
|
|
|
+ swipeRef.value?.next()
|
|
|
+ const nextItem = data.itemList[popupData.activeIndex]
|
|
|
+ nextTick(() => {
|
|
|
+ nextItem.videoEle?.play()
|
|
|
+ })
|
|
|
+ console.log('🚀 ~ nextItem', nextItem)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //加载第一帧
|
|
|
+ const handleFirstFrame = (video: HTMLVideoElement) => {
|
|
|
+ // console.log("🚀 ~ 加载第一帧", video.videoWidth, video.videoHeight)
|
|
|
+ const captureImage = function () {
|
|
|
+ var canvas = document.createElement('canvas')
|
|
|
+ canvas.width = video.videoWidth
|
|
|
+ canvas.height = video.videoHeight
|
|
|
+ canvas?.getContext('2d')?.drawImage(video, 0, 0, canvas.width, canvas.height)
|
|
|
+ canvas.toBlob((blob) => {
|
|
|
+ // console.log("🚀 ~ blob", blob)
|
|
|
+ const imgUrl = URL.createObjectURL(blob as any)
|
|
|
+ // console.log("🚀 ~ imgUrl", imgUrl)
|
|
|
+ video.setAttribute('poster', imgUrl)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ captureImage()
|
|
|
+ }
|
|
|
+
|
|
|
return () => (
|
|
|
<div class={styles.coursewarePlay}>
|
|
|
<Swipe
|
|
@@ -265,6 +351,7 @@ export default defineComponent({
|
|
|
loop={false}
|
|
|
vertical
|
|
|
lazyRender={true}
|
|
|
+ initialSwipe={popupData.firstIndex}
|
|
|
onChange={handleSwipeChange}
|
|
|
>
|
|
|
{data.itemList.map((m: any, mIndex: number) => {
|
|
@@ -289,38 +376,41 @@ export default defineComponent({
|
|
|
{m.type === 'VIDEO' ? (
|
|
|
<>
|
|
|
<video
|
|
|
- preload='auto'
|
|
|
+ playsinline="false"
|
|
|
+ preload="auto"
|
|
|
class="player"
|
|
|
+ poster={iconVideobg}
|
|
|
data-vid={m.id}
|
|
|
src={m.content}
|
|
|
loop={m.loop}
|
|
|
+ // onLoadeddata={(e: Event) =>
|
|
|
+ // handleFirstFrame(e.target as unknown as HTMLVideoElement)
|
|
|
+ // }
|
|
|
onLoadedmetadata={(e: Event) => {
|
|
|
const videoEle = e.target as unknown as HTMLVideoElement
|
|
|
- // console.log('video加载成功', videoEle)
|
|
|
- videoEle.currentTime = .5
|
|
|
m.currentTime = videoEle.currentTime
|
|
|
m.duration = videoEle.duration
|
|
|
m.videoEle = videoEle
|
|
|
}}
|
|
|
onTimeupdate={(e: Event) => {
|
|
|
const videoEle = e.target as unknown as HTMLVideoElement
|
|
|
- // console.log('video播放中')
|
|
|
m.currentTime = videoEle.currentTime
|
|
|
}}
|
|
|
onPlay={() => {
|
|
|
- console.log('播放')
|
|
|
+ // 播放
|
|
|
m.paused = false
|
|
|
}}
|
|
|
onPause={() => {
|
|
|
+ //暂停
|
|
|
clearTimeout(m.timer)
|
|
|
- console.log('暂停')
|
|
|
m.paused = true
|
|
|
}}
|
|
|
+ onEnded={() => handleEnded(m)}
|
|
|
>
|
|
|
<source src={m.content} type="video/mp4" />
|
|
|
</video>
|
|
|
<Transition name="bottom">
|
|
|
- {activeData.model && (
|
|
|
+ {m.playModel && (
|
|
|
<div class={styles.bottomFixedContainer}>
|
|
|
<div class={styles.time}>
|
|
|
<span>{getSecondRPM(m.currentTime)}</span>
|
|
@@ -345,7 +435,7 @@ export default defineComponent({
|
|
|
onClick={(e: Event) => {
|
|
|
e.stopPropagation()
|
|
|
clearTimeout(m.timer)
|
|
|
- console.log('点击播放', m.videoEle)
|
|
|
+ closeToast()
|
|
|
m.videoEle?.play()
|
|
|
m.paused = false
|
|
|
m.timer = setTimeout(() => {
|
|
@@ -382,7 +472,7 @@ export default defineComponent({
|
|
|
/>
|
|
|
)}
|
|
|
</div>
|
|
|
- <div>{popupData.itemName}</div>
|
|
|
+ <div>{m.name}</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
)}
|
|
@@ -391,7 +481,13 @@ export default defineComponent({
|
|
|
) : m.type === 'IMG' ? (
|
|
|
<img src={m.content} />
|
|
|
) : (
|
|
|
- <MusicScore music={m} />
|
|
|
+ <MusicScore
|
|
|
+ data-vid={m.id}
|
|
|
+ music={m}
|
|
|
+ onSetIframe={(el: any) => {
|
|
|
+ m.iframeRef = el
|
|
|
+ }}
|
|
|
+ />
|
|
|
)}
|
|
|
{/* <Transition name="van-fade">
|
|
|
{activeData.model && <div class={styles.playModel}></div>}
|
|
@@ -405,7 +501,7 @@ export default defineComponent({
|
|
|
|
|
|
<Transition name="top">
|
|
|
{activeData.model && (
|
|
|
- <div class={styles.headerContainer}>
|
|
|
+ <div class={styles.headerContainer} ref={headeRef}>
|
|
|
<div class={styles.backBtn} onClick={() => goback()}>
|
|
|
<Icon name={iconBack} />
|
|
|
返回
|
|
@@ -444,20 +540,21 @@ export default defineComponent({
|
|
|
<Transition name="left">
|
|
|
{activeData.model && (
|
|
|
<div class={styles.leftFixedBtns}>
|
|
|
- <div class={[styles.fullBtn, styles.prePoint]} onClick={() => handlePreAndNext('up')}>
|
|
|
- <span style={{ textAlign: 'center' }}>
|
|
|
- 上一
|
|
|
- <br />
|
|
|
- 知识点
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- <div class={styles.fullBtn} onClick={() => handlePreAndNext('down')}>
|
|
|
- <span style={{ textAlign: 'center' }}>
|
|
|
- 下一
|
|
|
- <br />
|
|
|
- 知识点
|
|
|
- </span>
|
|
|
- </div>
|
|
|
+ {popupData.activeIndex != 0 && (
|
|
|
+ <div
|
|
|
+ class={[styles.fullBtn, styles.prePoint]}
|
|
|
+ onClick={() => handlePreAndNext('up')}
|
|
|
+ >
|
|
|
+ <img src={iconUp} />
|
|
|
+ <span style={{ textAlign: 'center' }}>上一个</span>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {popupData.activeIndex != data.itemList.length - 1 && (
|
|
|
+ <div class={styles.fullBtn} onClick={() => handlePreAndNext('down')}>
|
|
|
+ <span style={{ textAlign: 'center' }}>下一个</span>
|
|
|
+ <img src={iconDown} />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
</div>
|
|
|
)}
|
|
|
</Transition>
|
|
@@ -477,6 +574,7 @@ export default defineComponent({
|
|
|
// console.log(res)
|
|
|
popupData.tabActive = res.tabActive
|
|
|
popupData.itemActive = res.itemActive
|
|
|
+ popupData.tabName = res.tabName
|
|
|
popupData.open = false
|
|
|
toggleMaterial()
|
|
|
}}
|