import { defineComponent, onMounted, reactive, onUnmounted, ref, Transition } from 'vue'; import styles from './index.module.less'; import 'plyr/dist/plyr.css'; import MusicScore from './component/musicScore'; import iconMenu from './image/icon-menu.svg'; import iconUp from './image/icon-up.svg'; import iconDown from './image/icon-down.svg'; import iconNote from './image/icon-note.png'; import iconWhiteboard from './image/icon-whiteboard.png'; import iconAssignHomework from './image/icon-assignHomework.svg'; import iconOverPreivew from './image/icon-over-preview.svg'; import { Vue3Lottie } from 'vue3-lottie'; import playLoadData from './datas/data.json'; import VideoPlay from './component/video-play'; import { useMessage, NDrawer, NDrawerContent, NModal, NSpace, NButton, NTooltip } from 'naive-ui'; import CardType from '@/components/card-type'; import Pen from './component/tools/pen'; import AudioPay from './component/audio-pay'; import TrainSettings from './model/train-settings'; import { useRoute } from 'vue-router'; import { queryCourseware } from '../prepare-lessons/api'; export type ToolType = 'init' | 'pen' | 'whiteboard'; export type ToolItem = { type: ToolType; name: string; icon: string; }; export default defineComponent({ name: 'CoursewarePlay', setup() { const message = useMessage(); const route = useRoute(); /** 设置播放容器 16:9 */ const parentContainer = reactive({ width: '100vw' }); const setContainer = () => { const min = Math.min(screen.width, screen.height); const max = Math.max(screen.width, screen.height); const width = min * (16 / 9); if (width > max) { parentContainer.width = '100vw'; return; } else { parentContainer.width = width + 'px'; } }; const handleInit = (type = 0) => { //设置容器16:9 setContainer(); }; handleInit(); onUnmounted(() => { handleInit(1); }); const data = reactive({ type: '' as '' | 'preview' | 'class', // 预览类型 subjectId: '' as any, // 声部编号 detailId: '' as any, // 编号 - 章节编号 classGroupId: '' as any, // 上课时需要 班级编号 // detail: null, knowledgePointList: [] as any, itemList: [] as any, // showHead: true, // isCourse: false, // isRecordPlay: false, videoRefs: {} as any[], audioRefs: {} as any[], modelAttendStatus: false, // 布置作业提示弹窗 modelTrainStatus: false, // 训练设置 homeworkStatus: true // 布置作业完成时 }); const activeData = reactive({ // isAutoPlay: false, // 是否自动播放 nowTime: 0, model: true, // 遮罩 isAnimation: true, // 是否动画 // videoBtns: true, // 视频 // currentTime: 0, // duration: 0, timer: null as any, item: null as any }); const getDetail = async () => { try { const res = await queryCourseware({ coursewareDetailKnowledgeId: data.detailId, subjectId: data.subjectId, pag: 1, rows: 99 }); const tempRows = res.data.rows || []; const temp: any = []; tempRows.forEach((row: any) => { if (!row.removeFlag) { temp.push({ id: row.id, materialId: row.materialId, coverImg: row.coverImg, type: row.materialType, title: row.materialName, isCollect: !!row.favoriteFlag, isSelected: row.source === 'PLATFORM' ? true : false, content: row.content }); } }); data.knowledgePointList = temp; data.itemList = data.knowledgePointList.map((m: any) => { return { ...m, iframeRef: null, videoEle: null, audioEle: null, autoPlay: false, //加载完成是否自动播放 isprepare: false, // 视频是否加载完成 isRender: false // 是否渲染了 }; }); } catch { // } }; // ifram事件处理 const iframeHandle = (ev: MessageEvent) => { if (ev.data?.api === 'headerTogge') { activeData.model = ev.data.show || (ev.data.playState == 'play' ? false : true); } }; onMounted(() => { const query = route.query; data.type = query.type as any; data.subjectId = query.subjectId; data.detailId = query.detailId; data.classGroupId = query.classGroupId; window.addEventListener('message', iframeHandle); getDetail(); }); const popupData = reactive({ open: false, activeIndex: 0, toolOpen: false // 工具弹窗控制 }); /**停止所有的播放 */ const handleStop = () => { for (let i = 0; i < data.itemList.length; i++) { const activeItem = data.itemList[i]; if (activeItem.type === 'VIDEO' && activeItem.videoEle) { activeItem.videoEle.stop(); } if (activeItem.type === 'SONG' && activeItem.audioEle) { activeItem.audioEle.stop(); } // console.log('🚀 ~ activeItem:', activeItem) // 停止曲谱的播放 if (activeItem.type === 'MUSIC') { activeItem.iframeRef?.contentWindow?.postMessage( { api: 'setPlayState' }, '*' ); } } }; // 切换素材 const toggleMaterial = (itemActive: any) => { const index = data.itemList.findIndex((n: any) => n.id == itemActive); if (index > -1) { handleSwipeChange(index); } }; /** 延迟收起模态框 */ const setModelOpen = () => { clearTimeout(activeData.timer); message.destroyAll(); activeData.timer = setTimeout(() => { activeData.model = false; Object.values(data.videoRefs).map((n: any) => n.toggleHideControl(false) ); Object.values(data.audioRefs).map((n: any) => n.toggleHideControl(false) ); }, 4000); }; /** 立即收起所有的模态框 */ const clearModel = () => { clearTimeout(activeData.timer); message.destroyAll(); activeData.model = false; Object.values(data.videoRefs).map((n: any) => n?.toggleHideControl(false) ); Object.values(data.audioRefs).map((n: any) => n?.toggleHideControl(false) ); }; const toggleModel = (type = true) => { activeData.model = type; Object.values(data.videoRefs).map((n: any) => n?.toggleHideControl(type)); Object.values(data.audioRefs).map((n: any) => n?.toggleHideControl(type)); }; // 双击 const handleDbClick = (item: any) => { if (item && item.type === 'VIDEO') { const videoEle: HTMLVideoElement = item.videoEle; if (videoEle) { if (videoEle.paused) { message.destroyAll(); videoEle.play(); } else { message.warning('已暂停'); videoEle.pause(); } } } }; // 切换播放 // const togglePlay = (m: any, isPlay: boolean) => { // if (isPlay) { // m.videoEle?.play(); // } else { // m.videoEle?.pause(); // } // }; // const showIndex = ref(-4); const effectIndex = ref(3); const effects = [ { prev: { transform: 'translate3d(0, 0, -800px) rotateX(180deg)' }, next: { transform: 'translate3d(0, 0, -800px) rotateX(-180deg)' } }, { prev: { transform: 'translate3d(-100%, 0, -800px)' }, next: { transform: 'translate3d(100%, 0, -800px)' } }, { prev: { transform: 'translate3d(-50%, 0, -800px) rotateY(80deg)' }, next: { transform: 'translate3d(50%, 0, -800px) rotateY(-80deg)' } }, { prev: { transform: 'translate3d(-100%, 0, -800px) rotateY(-120deg)' }, next: { transform: 'translate3d(100%, 0, -800px) rotateY(120deg)' } }, // 风车4 { prev: { transform: 'translate3d(-50%, 50%, -800px) rotateZ(-14deg)', opacity: 0 }, next: { transform: 'translate3d(50%, 50%, -800px) rotateZ(14deg)', opacity: 0 } }, // 翻页5 { prev: { transform: 'translateZ(-800px) rotate3d(0, -1, 0, 90deg)', opacity: 0 }, next: { transform: 'translateZ(-800px) rotate3d(0, 1, 0, 90deg)', opacity: 0 }, current: { transitionDelay: '700ms' } } ]; const acitveTimer = ref(); // 轮播切换 const handleSwipeChange = (index: number) => { // 如果是当前正在播放 或者是视频最后一个 if (popupData.activeIndex == index) return; handleStop(); clearTimeout(acitveTimer.value); checkedAnimation(popupData.activeIndex, index); popupData.activeIndex = index; acitveTimer.value = setTimeout( () => { const item = data.itemList[index]; if (item) { if (item.type == 'MUSIC') { activeData.model = true; } if (item.type === 'SONG') { // 自动播放下一个音频 clearTimeout(activeData.timer); message.destroyAll(); // item.autoPlay = false; // nextTick(() => { // item.audioEle?.onPlay(); // }); } if (item.type === 'VIDEO') { // 自动播放下一个视频 clearTimeout(activeData.timer); message.destroyAll(); // item.autoPlay = false; // nextTick(() => { // item.videoEle?.play(); // }); } } // requestAnimationFrame(() => { // const _effectIndex = effectIndex.value + 1; // effectIndex.value = // _effectIndex >= effects.length - 1 ? 0 : _effectIndex; // }); }, activeData.isAnimation ? 800 : 0 ); }; /** 是否有转场动画 */ const checkedAnimation = (index: number, nextIndex?: number) => { const item = data.itemList[index]; const nextItem = data.itemList[nextIndex!]; if (nextItem) { if (nextItem.knowledgePointId != item.knowledgePointId) { activeData.isAnimation = true; return; } const videoEle = item.videoEle; const nextVideo = nextItem.videoEle; if (videoEle && videoEle.duration < 8 && index < nextIndex!) { activeData.isAnimation = false; } else if (nextVideo && nextVideo.duration < 8 && index > nextIndex!) { activeData.isAnimation = false; } else { activeData.isAnimation = true; } } else { activeData.isAnimation = item?.adviseStudyTimeSecond < 8 ? false : true; } }; // 上一个知识点, 下一个知识点 const handlePreAndNext = (type: string) => { if (type === 'up') { handleSwipeChange(popupData.activeIndex - 1); } else { handleSwipeChange(popupData.activeIndex + 1); } }; /** 弹窗关闭 */ const handleClosePopup = () => { const item = data.itemList[popupData.activeIndex]; if (item?.type == 'VIDEO' && !item.videoEle?.paused) { setModelOpen(); } if (item?.type == 'SONG' && !item.audioEle?.paused) { setModelOpen(); } }; // 监听页面键盘事件 - 上下切换 document.body.addEventListener('keyup', (e: KeyboardEvent) => { // console.log(e, 'e'); if (e.code === 'ArrowUp') { if (popupData.activeIndex === 0) return; handlePreAndNext('up'); } else if (e.code === 'ArrowDown') { if (popupData.activeIndex === data.itemList.length - 1) return; handlePreAndNext('down'); } // else if (e.code === 'Space') { // handleStop(); // } }); /** 教学数据 */ const studyData = reactive({ type: '' as ToolType, penShow: false }); /** 打开教学工具 */ const openStudyTool = (item: ToolItem) => { const activeItem = data.itemList[popupData.activeIndex]; // 暂停视频和曲谱的播放 if (activeItem.type === 'VIDEO' && activeItem.videoEle) { activeItem.videoEle.pause(); } if (activeItem.type === 'SONG' && activeItem.audioEle) { activeItem.audioEle.stop(); } if (activeItem.type === 'MUSIC') { activeItem.iframeRef?.contentWindow?.postMessage( { api: 'setPlayState' }, '*' ); } clearModel(); popupData.toolOpen = false; studyData.type = item.type; switch (item.type) { case 'pen': studyData.penShow = true; break; case 'whiteboard': studyData.penShow = true; } }; /** 关闭教学工具 */ const closeStudyTool = () => { studyData.type = 'init'; toggleModel(); }; return () => (
{ clearTimeout(activeData.timer); activeData.model = !activeData.model; Object.values(data.videoRefs).map((n: any) => n.toggleHideControl(activeData.model) ); Object.values(data.audioRefs).map((n: any) => n.toggleHideControl(activeData.model) ); }}>
{ e.stopPropagation(); setModelOpen(); }}>
{data.itemList.map((m: any, mIndex: number) => { const isRender = m.isRender || Math.abs(popupData.activeIndex - mIndex) < 2; const isEmtry = Math.abs(popupData.activeIndex - mIndex) > 4; if (isRender) { m.isRender = true; } return isRender ? (
popupData.activeIndex ? effects[effectIndex.value].next : {} } onClick={(e: Event) => { e.stopPropagation(); clearTimeout(activeData.timer); if (Date.now() - activeData.nowTime < 300) { handleDbClick(m); return; } activeData.nowTime = Date.now(); activeData.timer = setTimeout(() => { activeData.model = !activeData.model; Object.values(data.videoRefs).map((n: any) => n.toggleHideControl(activeData.model) ); Object.values(data.audioRefs).map((n: any) => n.toggleHideControl(activeData.model) ); if (activeData.model) { setModelOpen(); } }, 300); }}> {m.type === 'VIDEO' ? ( <> (data.videoRefs[mIndex] = v)} item={m} isEmtry={isEmtry} onLoadedmetadata={(videoItem: any) => { m.videoEle = videoItem; m.isprepare = true; }} onTogglePlay={(paused: boolean) => { m.autoPlay = false; if (paused || popupData.open) { clearTimeout(activeData.timer); } else { setModelOpen(); } }} onEnded={() => { const _index = popupData.activeIndex + 1; if (_index < data.itemList.length) { handleSwipeChange(_index); } }} onReset={() => { if (!m.videoEle?.paused) { setModelOpen(); } }} /> {!m.isprepare && (
)}
) : m.type === 'IMG' ? ( ) : m.type === 'SONG' ? ( (data.audioRefs[mIndex] = v)} onLoadedmetadata={(audioItem: any) => { m.audioEle = audioItem; m.isprepare = true; }} onTogglePlay={(paused: boolean) => { m.autoPlay = false; if (paused || popupData.open) { clearTimeout(activeData.timer); } else { setModelOpen(); } }} onEnded={() => { const _index = popupData.activeIndex + 1; if (_index < data.itemList.length) { handleSwipeChange(_index); } }} onReset={() => { if (!m.audioEle?.paused) { setModelOpen(); } }} /> ) : ( { m.iframeRef = el; }} /> )}
) : null; })}
{activeData.model && (
{ e.stopPropagation(); clearTimeout(activeData.timer); }}>
{ if (popupData.activeIndex === 0) return; handlePreAndNext('up'); }}>
(popupData.open = true)}>
{ if (popupData.activeIndex === data.itemList.length - 1) return; handlePreAndNext('down'); }}>
)}
{/*
goback()}> 返回
{popupData.itemName}
*/} {/* 布置作业按钮 */}
{ if (data.type === 'preview') { window.close(); } else { data.modelAttendStatus = true; } }}>
{/* 白板 批注 */}
{{ trigger: () => (
openStudyTool({ type: 'pen', icon: iconNote, name: '批注' }) }>
), default: () => '批注' }}
{{ trigger: () => (
openStudyTool({ type: 'whiteboard', icon: iconWhiteboard, name: '白板' }) }>
), default: () => '白板' }}
{/* 显示列表 */} {data.knowledgePointList.map((item: any, index: number) => ( { popupData.open = false; toggleMaterial(item.id); }} /> ))} {/* 批注 */} {studyData.penShow && ( closeStudyTool()} /> )} {/* 布置作业 */}
本节课已设置课后训练,是否布置?
{ data.modelAttendStatus = false; window.close(); }}> 暂不布置 { data.modelTrainStatus = true; data.modelAttendStatus = false; }}> 布置
{/* 训练设置 */} (data.modelTrainStatus = false)} onConfirm={() => { // 布置完作业之后直接关闭 setTimeout(() => { window.close(); }, 1000); }} /> {/*

作业布置成功

*/}
); } });