import { Button, closeToast, Icon, Popup, showToast, Slider, Swipe, SwipeItem, Tab, Tabs } from 'vant' import { defineComponent, onMounted, reactive, nextTick, onUnmounted, ref, watch, Transition, computed } from 'vue' import iconBack from './image/back.svg' import styles from './index.module.less' import 'plyr/dist/plyr.css' import request from '@/helpers/request' import { state } from '@/state' import { useRoute } from 'vue-router' 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' import iconPoint from './image/icon-point.svg' 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 { 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: 'setTitleBarVisibility', content: { status: type } }) // 安卓的状态栏 postMessage({ api: 'setStatusBarVisibility', content: { isVisibility: type } }) } handleInit() onUnmounted(() => { handleInit(1) window.removeEventListener('message', iframeHandle) }) const route = useRoute() const headeRef = ref() const data = reactive({ detail: null, knowledgePointList: [] as any, itemList: [] as any, showHead: true, isCourse: false }) const activeData = reactive({ nowTime: 0, model: true, // 遮罩 videoBtns: true, // 视频 currentTime: 0, duration: 0, timer: null as any, item: null as any }) 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 getCourseSchedule = async () => { if (!route.query.courseId) return try { const res = await request.get( `${state.platformApi}/courseSchedule/detail/${route.query.courseId}` ) if (res?.data) { data.isCourse = res.data.status === 'COMPLETE' ? false : true } } catch (e) { console.log(e) } } 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 (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, progress: 0, paused: true, loop: false, videoEle: null, timer: null, playModel: false, isprepare: false, isDrage: false, muted: (i === 0 && j === 0) ? true : false, } } list.push({ ...material, ...videoItem, iframeRef: null, tabName: item.name, isLast: j === itemLength, // 当前知识点 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) data.itemList = list } const getDetail = async () => { try { const res: any = await request.get( state.platformApi + `/lessonCoursewareDetail/detail/${route.query.id}` ) if (Array.isArray(res?.data)) { data.detail = res.data } if (Array.isArray(res?.data?.knowledgePointList)) { data.knowledgePointList = res.data.knowledgePointList.map((n: any) => { n.index = 0 return n }) getItemList() } } catch (error) {} } // ifram事件处理 const iframeHandle = (ev: MessageEvent) => { // console.log(ev.data) if (ev.data?.api === 'headerTogge') { // activeData.model = ev.data.show activeData.model = !activeData.model } } onMounted(() => { getDetail() getCourseSchedule() window.addEventListener('message', iframeHandle) }) // 返回 const goback = () => { postMessage({ api: 'goBack' }) } const swipeRef = ref() const popupData = reactive({ firstIndex: 0, open: false, activeIndex: -1, tabActive: '', tabName: '', itemActive: '', itemName: '' }) // 设置当前的激活状态 const setActiveData = (val: any, oldVal: any) => { handleStopVideo() handleStopMusicScore() } watch(() => popupData.activeIndex, setActiveData) // 停止所有的播放 const handleStopVideo = () => { data.itemList.forEach((m: any) => { m.videoEle?.pause() }) } // 停止曲谱的播放 const handleStopMusicScore = () => { data.itemList.forEach((m: any) => { m.iframeRef?.contentWindow?.postMessage({ api: 'setPlayState' }, '*') }) } // 切换素材 const toggleMaterial = () => { const index = data.itemList.findIndex((n: any) => n.id == popupData.itemActive) if (index > -1) { popupData.activeIndex = index swipeRef.value?.swipeTo(index) } } // 轮播切换 const handleSwipeChange = (val: any) => { console.log('轮播切换') popupData.activeIndex = val const item = data.itemList[val] if (item) { popupData.tabActive = item.knowledgePointId popupData.itemActive = item.id popupData.itemName = item.name popupData.tabName = item.tabName if (item.type == 'SONG'){ activeData.model = true } } } // 上一个知识点, 下一个知识点 const handlePreAndNext = (type: string) => { if (type === 'up') { swipeRef.value?.prev() } else { swipeRef.value?.next() } } // 去点名,签退 const gotoRollCall = (pageTag: string) => { postMessage({ api: 'open_app_page', content: { action: 'app', pageTag: pageTag, url: '', params: JSON.stringify({ courseId: route.query.courseId }) } }) } // 双击 const handleDbClick = (item: any) => { // console.log(item) if (item && item.type === 'VIDEO') { const videoEle: HTMLVideoElement = item.videoEle if (videoEle) { if (videoEle.paused) { closeToast() videoEle.play() } else { showToast('已暂停') videoEle.pause() } } } } // 暂停播放 const handlePaused = (e: Event, m: any) => { e.stopPropagation() m.videoEle?.pause() m.paused = true } // 开始播放 const handlePlay = (e: Event, m: any) => { e.stopPropagation() clearTimeout(m.timer) closeToast() m.videoEle?.play() } // 调整播放进度 const handleChangeSlider = (m: any) => { if (m?.videoEle) { // console.log('进度条', m.progress) m.currentTime = m.duration * (m.progress / 100) m.videoEle.currentTime = m.currentTime } } //当前视频播放完 const handleEnded = (m: any) => { // console.log(m) if (popupData.activeIndex != data.itemList.length - 1) { popupData.activeIndex++ swipeRef.value?.next() const nextItem = data.itemList[popupData.activeIndex] if (nextItem.type === 'VIDEO') { nextTick(() => { // 自动播放下一个视频 clearTimeout(m.timer) closeToast() 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 () => (