import { defineComponent, onMounted, reactive, onUnmounted, ref, Transition, computed, nextTick, watch, toRef } from 'vue'; import styles from './index.module.less'; import 'plyr/dist/plyr.css'; import MusicScore from './component/musicScore'; // import iconChange from './image/icon-change.png'; // import iconMenu from './image/icon-menu.png'; // import iconUp from './image/icon-up.png'; // import iconDown from './image/icon-down.png'; // import iconNote from './image/icon-note.png'; // import iconWhiteboard from './image/icon-whiteboard.png'; // import iconAssignHomework from './image/icon-assignHomework.png'; // import iconClose from './image/icon-close.png'; // import iconOverPreivew from './image/icon-over-preview.png'; import { Vue3Lottie } from 'vue3-lottie'; import playLoadData from './datas/data.json'; // import Moveable from 'moveable'; import VideoPlay from './component/video-play'; import { useMessage, NDrawer, NDrawerContent, NModal, NSpace, NButton, NCollapse, NCollapseItem, 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 { api_teacherChapterLessonCoursewareDetail, courseScheduleUpdate, lessonCoursewareDetail, lessonPreTrainingPage, queryCourseware } from '../prepare-lessons/api'; import { vaildUrl } from '/src/utils/urlUtils'; import TimerMeter from '/src/components/timerMeter'; import { iframeDislableKeyboard, px2vw } from '/src/utils'; import PlaceholderTone from '/src/components/layout/modals/placeholderTone'; import { state as globalState } from '/src/state'; import Chapter from './model/chapter'; import { useRouter } from 'vue-router'; import { useUserStore } from '@/store/modules/users'; import iconNote from './new-image/icon-note.png'; import iconWhite from './new-image/icon-white.png'; import rightIconEnd from './image/right_icon1.png'; import rightIconArrange from './image/right_icon2.png'; import rightIconPostil from './image/right_icon3.png'; import rightIconWhiteboard from './image/right_icon4.png'; import rightIconMetronome from './image/right_icon5.png'; import rightIconTuner from './image/right_icon6.png'; import rightIconTimer from './image/right_icon7.png'; import rightIconCall from './image/right_icon10.png'; import rightIconPackUp from './image/right_icon11.png'; import leftIconPackUp from './image/right_icon8.png'; import rightIconMusic from './image/right_icon9.png'; import bottomIconSwitch from './image/bottom_icon1.png'; import bottomIconResource from './image/bottom_icon2.png'; import bottomIconPre from './image/bottom_icon3.png'; import bottomIconNext from './image/bottom_icon4.png'; import rightIconTool from './image/right_icon12.png'; import rightHideIcon from './image/right_hide_icon.png'; import leftHideIcon from './image/left_hide_icon.png'; import SelectResources from '../prepare-lessons/model/select-resources'; import { getStudentAfterWork, getStudentList } from '../studentList/api'; import TheNoticeBar from '/src/components/TheNoticeBar'; import ClassWork from './model/class-work'; import SelectClass from './model/select-class'; import SourceList from './model/source-list'; import RhythmModal from './component/rhythm-modal'; import InstruemntDetail from '/src/views/prepare-lessons/model/source-instrument/detail'; import TheotyDetail from '/src/views/prepare-lessons/model/source-knowledge/detail'; import MusicDetail from '/src/views/prepare-lessons/model/source-music/detail'; import ListenModal from '/src/components/card-preview/listen-modal'; import Train from '../prepare-lessons/components/lesson-main/train'; import ResourceMain from '../prepare-lessons/components/resource-main'; import { useResizeObserver } from '@vueuse/core'; import { storage } from '/src/utils/storage'; import { ACCESS_TOKEN_ADMIN } from '/src/store/mutation-types'; import useDrag from '@/hooks/useDrag'; import Dragbom from '@/hooks/useDrag/dragbom'; export type ToolType = 'init' | 'pen' | 'whiteboard' | 'call'; export type ToolItem = { type: ToolType; name: string; icon: string; }; export default defineComponent({ name: 'CoursewarePlay', props: { type: { type: String, default: '' }, courseId: { type: String, default: '' }, subjectId: { type: [String, Number], default: '' }, // 教材编号 lessonCourseId: { type: [String, Number], default: '' }, detailId: { type: String, default: '' }, // 班级编号 classGroupId: { type: String, default: '' }, // 上课记录编号 classId: { type: String, defaault: '' }, preStudentNum: { type: [String, Number], default: '' } }, emits: ['close'], setup(props, { emit }) { const message = useMessage(); const route = useRoute(); const router = useRouter(); const users = useUserStore(); /** 设置播放容器 16:9 */ const parentContainer = reactive({ width: '100vw' }); // const NPopoverRef = ref(); // 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: 'class' as '' | 'preview' | 'class', // 预览类型 courseId: '' as any, // 课件编号 subjectId: '' as any, // 声部编号 lessonCourseId: '' as any, // 教材编号 lessonCoursewareDetailId: '' as any, // 章节 lessonCoursewareSubjectList: [] as any, // 教材上的声部 detailId: '' as any, // 编号 - 课程编号 classGroupId: '' as any, // 上课时需要 班级编号 classId: '' as any, // 上课编号 preStudentNum: '' as any, // 班上学生 // detail: null, knowledgePointList: [] as any, itemList: [] as any, // showHead: true, // isCourse: false, // isRecordPlay: false, videoRefs: {} as any[], audioRefs: {} as any[], modelAttendStatus: false, // 布置作业提示弹窗 modalAttendMessage: '本节课未设置课后作业,是否继续?', modelTrainStatus: false, // 训练设置 selectClassStatus: false, // 选择课件 homeworkStatus: true, // 布置作业完成时 removeVisiable: false, removeTitle: '', removeContent: '', removeCourseStatus: false, // 是否布置作业 teacherChapterName: '', lessonPreTrainingId: null, selectResourceStatus: false, videoState: 'init' as 'init' | 'play', videoItemRef: null as any, animationState: 'start' as 'start' | 'end' }); 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 listenerKeyUpState = ref(false); const getDetail = async () => { try { const res = await api_teacherChapterLessonCoursewareDetail( data.courseId ); data.teacherChapterName = res.data.name || ''; // 布置的作业编号 data.lessonPreTrainingId = res.data.lessonPreTrainingId; // activeData.isAutoPlay = res.data.autoPlay || false; // 自动播放 const tempRows = res.data.chapterKnowledgeList || []; const temp: any = []; const allItem: any = []; tempRows.forEach((row: any, index: number) => { if (!Array.isArray(row.chapterKnowledgeMaterialList)) { return; } const childList: any[] = []; row.chapterKnowledgeMaterialList.forEach((child: any) => { if (!child.removeFlag) { childList.push({ id: child.id, materialId: child.bizId, coverImg: child.bizInfo.coverImg, type: child.type, title: child.bizInfo.name, dataJson: child.dataJson, isCollect: !!child.favoriteFlag, isSelected: child.source === 'PLATFORM' ? true : false, content: child.bizInfo.content, parentIndex: index }); } }); temp.push({ title: row.name, list: childList }); allItem.push(...childList); }); data.knowledgePointList = temp; data.itemList = allItem?.map((m: any) => { return { ...m, iframeRef: null, videoEle: null, audioEle: null, autoPlay: res.data.autoPlay || false, //加载完成是否自动播放 isprepare: false, // 视频是否加载完成 isRender: false // 是否渲染了 }; }); setTimeout(() => { data.animationState = 'end'; }, 500); } catch (e) { // console.log(e); } }; const showModalBeat = ref(false); const showModalTone = ref(false); const showModalTime = ref(false); // ifram事件处理 const iframeHandle = (ev: MessageEvent) => { // console.log(ev.data?.api, ev.data, 'ev.data'); if (ev.data?.api === 'headerTogge') { activeData.model = ev.data.show || (ev.data.playState == 'play' ? false : true); } // if (ev.data?.api === 'onAttendToggleMenu') { activeData.model = !activeData.model; } if (ev.data?.api === 'api_fingerPreView') { clearInterval(activeData.timer); activeData.model = !ev.data.state; } // if (ev.data?.api === 'documentBodyKeyup') { if (ev.data?.code === 'ArrowLeft') { setModalOpen(); handlePreAndNext('up'); } if (ev.data?.code === 'ArrowRight') { setModalOpen(); handlePreAndNext('down'); } } // 点名返回 if (ev.data?.api === 'callBack') { closeStudyTool(); } if (ev.data?.api === 'onLogin') { const documentDom: any = document; documentDom.exitFullscreen ? documentDom.exitFullscreen() : documentDom.mozCancelFullScreen ? documentDom.mozCancelFullScreen() : documentDom.webkitExitFullscreen ? documentDom.webkitExitFullscreen() : ''; users.logout(); router.replace('/login'); } }; onMounted(() => { // initMoveable(); const query = route.query; // console.log(query, props.preStudentNum, '学生人数'); // 先取参数, data.type = props.type || (query.type as any); data.courseId = props.courseId || query.courseId; data.subjectId = props.subjectId || query.subjectId; data.detailId = props.detailId || query.detailId; data.lessonCourseId = props.lessonCourseId || query.lessonCourseId; data.classGroupId = props.classGroupId || query.classGroupId; data.classId = props.classId || query.classId; data.preStudentNum = props.preStudentNum || query.preStudentNum; window.addEventListener('message', iframeHandle); getDetail(); getLessonCoursewareDetail(); if (data.type === 'preview') { // 预览隐藏点名和布置作业 const hideListIds = [2, 10]; let index = rightList.length - 1; while (index >= 0) { if (hideListIds.includes(rightList[index].id)) { console.log(index); rightList.splice(index, 1); } index--; } } rollCallStudentList(); }); // const onFullScreen = () => { // if (data.type === 'preview') { // const el: any = document.querySelector('#app'); // if (el.mozRequestFullScreen) { // el.mozRequestFullScreen(); // } else if (el.webkitRequestFullscreen) { // el.webkitRequestFullscreen(); // } else if (el.requestFullScreen) { // el.requestFullscreen(); // } // } // }; const popupData = reactive({ open: false, activeIndex: 0, courseActiveIndex: 0, // 课件选择的第几个 toolOpen: false, // 工具弹窗控制 chapterOpen: false, // 切换章节 chapterDetails: [] as any, courseId: null as any, // 章节编号 chapterLoading: false // 加载数据 }); watch( () => [popupData.open, popupData.chapterOpen], val => { // 为了处理window电脑滑动时的问题 - pointr-events setTimeout(() => { const drawers = document.querySelectorAll('.n-drawer-container'); if (val[0] || val[1]) { drawers?.forEach(drawer => { drawer.classList.remove('n-drawer-container-relative'); }); } else { drawers?.forEach(drawer => { drawer.classList.add('n-drawer-container-relative'); }); } }, 200); } ); const formatParentId = (id: any, list: any, ids = [] as any) => { for (const item of list) { if (item.knowledgeList && item.knowledgeList.length > 0) { const cIds: any = formatParentId(id, item.knowledgeList, [ ...ids, item.id ]); if (cIds.includes(id)) { return cIds; } } if (item.id === id) { return [...ids, id]; } } return ids; }; /** 获取章节 */ const getLessonCoursewareDetail = async () => { try { const res = await lessonCoursewareDetail({ id: data.lessonCourseId, subjectId: data.subjectId }); popupData.chapterDetails = res.data.lessonList || []; const ids = formatParentId(data.detailId, popupData.chapterDetails); data.lessonCoursewareDetailId = ids[0]; data.lessonCoursewareSubjectList = res.data.subjectList || []; } catch { // } }; /** 更新上课记录 */ const classCourseScheduleUpdate = async () => { try { if (!data.classId) return; await courseScheduleUpdate({ lessonCoursewareKnowledgeDetailId: data.detailId, id: data.classId }); } catch { // } }; const activeName = computed(() => { let name = ''; popupData.chapterDetails.forEach((chapter: any) => { if (chapter.id === data.lessonCoursewareDetailId) { // name = chapter.name; chapter.knowledgeList?.forEach((know: any) => { if (know.id === data.detailId) { name = know.name; } }); } }); return name; }); /**停止所有的播放 */ const handleStop = (isStop = true) => { // console.log(isStop, 'stop'); for (let i = 0; i < data.itemList.length; i++) { const activeItem = data.itemList[i]; if (activeItem.type === 'VIDEO' && activeItem.videoEle) { try { if (isStop) { activeItem.videoEle?.currentTime(0); } activeItem.videoEle?.pause(); } catch (e: any) { // console.log(e, 'e'); } } if (activeItem.type === 'SONG' && activeItem.audioEle) { activeItem.audioEle?.stop(); } // console.log('🚀 ~ activeItem:', activeItem) // 停止曲谱的播放 if (activeItem.type === 'MUSIC') { activeItem.iframeRef?.contentWindow?.postMessage( { api: 'setPlayState' }, '*' ); } if ( activeItem.type === 'INSTRUMENT' || activeItem.type === 'MUSICIAN' || activeItem.type === 'MUSIC_WIKI' ) { activeItem.iframeRef?.handleChangeAudio('pause'); } // console.log(activeItem.type, 'activeItem.type'); if (activeItem.type === 'RHYTHM') { activeItem.iframeRef?.contentWindow?.postMessage( { api: 'setPlayState', data: false }, '*' ); } if (activeItem.type === 'LISTEN') { 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(); } } } }; // ppt iframe 点击事件 // const iframeClick = () => { // if(document.all) { // document.getElementById("iframe-ppt")?.attachEvent("click", () => { // activeData.model = !activeData.model // }); // } else { // document.getElementById("iframe-ppt")?.contentWindow?.postMessage({ // api: 'onAttendToggleMenu' // }, '*'); // } // } // 切换播放 // 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; data.animationState = 'start'; data.videoState = 'init'; handleStop(); clearTimeout(acitveTimer.value); activeData.model = true; checkedAnimation(popupData.activeIndex, index); popupData.activeIndex = index; // 处理资源列表滚动 nextTick(() => { scrollResourceSection(); }); 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(); nextTick(() => { if (item.error) { // console.log(item, 'item error'); item.videoEle?.src(item.content); item.error = false; // item.videoEle?.onPlay(); } data.animationState = 'end'; }); } if (item.type === 'PPT') { // } } }, 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 = async (type: string) => { if (type === 'up') { // 判断上面是否还有章节 if (popupData.activeIndex > 0) { handleSwipeChange(popupData.activeIndex - 1); return; } // 获取当前是哪个章节 let detailIndex = popupData.chapterDetails.findIndex( (item: any) => item.id == data.lessonCoursewareDetailId ); const detailItem = popupData.chapterDetails[detailIndex]?.knowledgeList || []; let lessonIndex = detailItem.findIndex( (item: any) => item.id == data.detailId ); let lessonStatus = false; // 当前章节上面是否有内容 let lessonCoursewareDetailId = ''; let coursewareDetailKnowledgeId = ''; while (lessonIndex >= 0) { lessonIndex--; if (lessonIndex >= 0) { if (detailItem[lessonIndex].coursewareNum > 0) { lessonStatus = true; lessonCoursewareDetailId = detailItem[lessonIndex].lessonCoursewareDetailId; coursewareDetailKnowledgeId = detailItem[lessonIndex].id; } } if (lessonStatus) { break; } } // 判断当前章节下面课程是否有内容,否则往上一个章节走 if (lessonStatus) { popupData.courseId = coursewareDetailKnowledgeId; data.selectClassStatus = true; return; } let prevLessonStatus = false; while (detailIndex >= 0) { detailIndex--; const tempDetail = popupData.chapterDetails[detailIndex]?.knowledgeList || []; let tempLessonLength = tempDetail.length; while (tempLessonLength > 0) { if (tempDetail[tempLessonLength - 1].coursewareNum > 0) { prevLessonStatus = true; lessonCoursewareDetailId = tempDetail[tempLessonLength - 1].lessonCoursewareDetailId; coursewareDetailKnowledgeId = tempDetail[tempLessonLength - 1].id; } tempLessonLength--; if (prevLessonStatus) { break; } } if (prevLessonStatus) { break; } } // 判断当前章节下面课程是否有内容,否则往上一个章节走 if (prevLessonStatus) { popupData.courseId = coursewareDetailKnowledgeId; data.selectClassStatus = true; return; } } else { if (popupData.activeIndex < data.itemList.length - 1) { handleSwipeChange(popupData.activeIndex + 1); return; } // 获取当前是哪个章节 let detailIndex = popupData.chapterDetails.findIndex( (item: any) => item.id == data.lessonCoursewareDetailId ); const detailItem = popupData.chapterDetails[detailIndex]?.knowledgeList || []; let lessonIndex = detailItem.findIndex( (item: any) => item.id == data.detailId ); let lessonStatus = false; // 当前章节下面是否有内容 let lessonCoursewareDetailId = ''; let coursewareDetailKnowledgeId = ''; while (lessonIndex < detailItem.length - 1) { lessonIndex++; if (lessonIndex >= 0) { if (detailItem[lessonIndex].coursewareNum > 0) { lessonStatus = true; lessonCoursewareDetailId = detailItem[lessonIndex].lessonCoursewareDetailId; coursewareDetailKnowledgeId = detailItem[lessonIndex].id; } } if (lessonStatus) { break; } } // 判断当前章节下面课程是否有内容,否则往下一个章节走 if (lessonStatus) { popupData.courseId = coursewareDetailKnowledgeId; data.selectClassStatus = true; return; } let nextLessonStatus = false; while (detailIndex <= popupData.chapterDetails.length - 1) { detailIndex++; const tempDetail = popupData.chapterDetails[detailIndex]?.knowledgeList || []; let tempLessonLength = 0; while (tempLessonLength <= tempDetail.length - 1) { if (tempDetail[tempLessonLength].coursewareNum > 0) { nextLessonStatus = true; lessonCoursewareDetailId = tempDetail[tempLessonLength].lessonCoursewareDetailId; coursewareDetailKnowledgeId = tempDetail[tempLessonLength].id; } tempLessonLength++; if (nextLessonStatus) { break; } } if (nextLessonStatus) { break; } } // 判断当前章节下面课程是否有内容,否则往上一个章节走 if (nextLessonStatus) { popupData.courseId = coursewareDetailKnowledgeId; data.selectClassStatus = true; return; } } }; /** 弹窗关闭 */ 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) => { if (e.code === 'ArrowLeft') { // if (popupData.activeIndex === 0) return; setModalOpen(); handlePreAndNext('up'); } else if (e.code === 'ArrowRight') { // if (popupData.activeIndex === data.itemList.length - 1) return; setModalOpen(); handlePreAndNext('down'); } else if (e.code === 'Space') { // const activeItem = data.itemList[popupData.activeIndex]; // console.log(activeItem, activeItem.videoEle); // // 暂停视频和曲谱的播放 // if (activeItem.type === 'VIDEO' && activeItem.videoEle) { // activeItem.videoEle?.play(); // } // if (activeItem.type === 'SONG' && activeItem.audioEle) { // activeItem.audioEle?.play(); // } // if (activeItem.type === 'MUSIC') { // activeItem.iframeRef?.contentWindow?.postMessage( // { api: 'setPlayState' }, // '*' // ); // } } }); // const toggleListenerKeyUp = (type: string) => { // if (type === 'remove') { // document.body.removeEventListener('keyup', () => { // listenerKeyUpState.value = false; // }); // } else { // // 监听页面键盘事件 - 上下切换 // document.body.addEventListener('keyup', (e: KeyboardEvent) => { // // console.log(e, 'e'); // if (e.code === 'ArrowLeft') { // // if (popupData.activeIndex === 0) return; // setModalOpen(); // handlePreAndNext('up'); // } else if (e.code === 'ArrowRight') { // // if (popupData.activeIndex === data.itemList.length - 1) return; // setModalOpen(); // handlePreAndNext('down'); // } // }); // listenerKeyUpState.value = true; // } // }; // 监听切换到ppt课件时,手动移除键盘监听器 // watch(() => popupData.activeIndex, () => { // const activeItem = data.itemList[popupData.activeIndex]; // if (activeItem?.type === 'PPT') { // toggleListenerKeyUp('remove') // } else { // !listenerKeyUpState.value && toggleListenerKeyUp('add') // } // }) watch( () => popupData.activeIndex, () => { const item = data.itemList[popupData.activeIndex]; popupData.courseActiveIndex = item.parentIndex; } ); const setModalOpen = (status = true) => { clearTimeout(activeData.timer); activeData.model = status; Object.values(data.videoRefs).map((n: any) => n?.toggleHideControl(status) ); Object.values(data.audioRefs).map((n: any) => n?.toggleHideControl(status) ); }; /** 教学数据 */ const studyData = reactive({ type: '' as ToolType, penShow: false, whiteboardShow: false, callShow: false, callStudentList: [] as any // 学生列表 }); /** 打开教学工具 */ const openStudyTool = (item: ToolItem) => { handleStop(false); clearModel(); popupData.toolOpen = false; studyData.type = item.type; switch (item.type) { case 'pen': studyData.penShow = true; break; case 'whiteboard': studyData.whiteboardShow = true; break; case 'call': studyData.callShow = true; break; } }; /** 关闭教学工具 */ const closeStudyTool = () => { studyData.type = 'init'; toggleModel(); setModelOpen(); }; const startShowModal = ( val: 'setTimeIcon' | 'beatIcon' | 'toneIcon' | 'iconNote2' ) => { if (val == 'setTimeIcon') { showModalTime.value = true; } if (val == 'beatIcon') { showModalBeat.value = true; } if (val == 'toneIcon') { showModalTone.value = true; } }; // 是否允许上一页 const isUpArrow = computed(() => { /** * 1,判断当前课程中是否处在第一个资源; * 2,判断当前课程是否在当前章节的第一个; * 3,判断当前章节,当前课程上面还没有其它课程,是否有资源; * 4,判断当前章节上面还没有其它章节; * 5,判断上面章节里面课程是否有资源; */ if (popupData.activeIndex > 0) { return true; } // 获取当前是哪个章节 let detailIndex = popupData.chapterDetails.findIndex( (item: any) => item.id == data.lessonCoursewareDetailId ); const detailItem = popupData.chapterDetails[detailIndex]?.knowledgeList || []; let lessonIndex = detailItem.findIndex( (item: any) => item.id == data.detailId ); // 说明已经是第一单元,第一课 if (detailIndex <= 0 && lessonIndex <= 0) { return false; } let lessonStatus = false; // 当前章节上面是否有内容 while (lessonIndex >= 0) { lessonIndex--; if (lessonIndex >= 0) { if (detailItem[lessonIndex].coursewareNum > 0) { lessonStatus = true; } } } // 判断当前章节下面课程是否有内容,否则往上一个章节走 if (lessonStatus) { return true; } // 已经是第一个章节了 if (detailIndex <= 0) { return false; } let prevLessonStatus = false; while (detailIndex >= 0) { detailIndex--; const tempDetail = popupData.chapterDetails[detailIndex]?.knowledgeList || []; let tempLessonLength = tempDetail.length; while (tempLessonLength > 0) { if (tempDetail[tempLessonLength - 1].coursewareNum > 0) { prevLessonStatus = true; } tempLessonLength--; } if (prevLessonStatus) { return true; } } return false; }); // 是否允许下一页 const isDownArrow = computed(() => { if (popupData.activeIndex < data.itemList.length - 1) { return true; } // 获取当前是哪个章节 let detailIndex = popupData.chapterDetails.findIndex( (item: any) => item.id == data.lessonCoursewareDetailId ); const detailItem = popupData.chapterDetails[detailIndex]?.knowledgeList || []; let lessonIndex = detailItem.findIndex( (item: any) => item.id == data.detailId ); // 说明已经是最后-单元,最后一课 if ( detailIndex >= popupData.chapterDetails.length - 1 && lessonIndex >= detailItem.length - 1 ) { return false; } let lessonStatus = false; // 当前章节下面是否有内容 while (lessonIndex < detailItem.length - 1) { lessonIndex++; if (lessonIndex >= 0) { if (detailItem[lessonIndex].coursewareNum > 0) { lessonStatus = true; } } } // 判断当前章节下面课程是否有内容,否则往下一个章节走 if (lessonStatus) { return true; } // 已经是最后一个章节了 if (detailIndex >= popupData.chapterDetails.length - 1) { return false; } let nextLessonStatus = false; while (detailIndex < popupData.chapterDetails.length - 1) { detailIndex++; const tempDetail = popupData.chapterDetails[detailIndex]?.knowledgeList || []; let tempLessonLength = 0; while (tempLessonLength <= tempDetail.length - 1) { if (tempDetail[tempLessonLength].coursewareNum > 0) { nextLessonStatus = true; } tempLessonLength++; } if (nextLessonStatus) { return true; } } return false; }); const activeVideoItem = computed(() => { const item = data.itemList[popupData.activeIndex]; if (item && item.type && item.type.toLocaleUpperCase() === 'VIDEO') { return item; } return {}; }); // 右侧菜单栏 const rightList = reactive([ { name: '上一张', icon: bottomIconPre, id: 11 }, { name: '下一张', icon: bottomIconNext, id: 12 }, { name: '切换章节', icon: bottomIconSwitch, id: 13 }, { name: '资源列表', icon: bottomIconResource, id: 14 }, { name: '曲目资源', icon: rightIconMusic, id: 9 }, { name: '点名', icon: rightIconCall, id: 10 }, { name: '布置作业', icon: rightIconArrange, id: 2 }, { name: '工具箱', icon: rightIconTool, id: 15 }, { name: '结束课程', name2: '结束预览', icon: rightIconEnd, id: 1 }, { name: '收起', icon: leftIconPackUp, id: 8 } ]); const tooltipList = [ { name: '节拍器', icon: rightIconMetronome, id: 5 }, { name: '计时器', icon: rightIconTimer, id: 7 }, { name: '批注', icon: rightIconPostil, id: 3 }, { name: '白板', icon: rightIconWhiteboard, id: 4 } // { // name: '调音器', // icon: rightIconTuner, // id: 6 // } ]; // 默认收起菜单 const columnShow = ref(true); // 菜单位置 const columnPos = ref<'left' | 'right'>('left'); watch(columnPos, () => { for (let i = 0; i < data.itemList.length; i++) { const activeItem = data.itemList[i]; if (activeItem.type === 'RHYTHM') { activeItem.iframeRef?.contentWindow?.postMessage( { api: 'imagePos', data: columnPos.value }, '*' ); } } }); // 右边栏操作 const operateRightBtn = async (id: number) => { if (![8, 11, 12, 13, 14].includes(id)) { handleStop(false); } switch (id) { case 1: if (data.type === 'preview') { data.removeVisiable = true; data.removeTitle = '结束预览'; data.removeContent = '请确认是否结束预览?'; } else { const res = await getStudentAfterWork({ courseScheduleId: data.classId, page: 1, rows: 99 }); if (res.data.rows && res.data.rows.length) { data.removeContent = '请确认是否结束课程?'; data.removeCourseStatus = false; } else { data.removeContent = '本次课堂尚未布置作业,是否结束课程?'; data.removeCourseStatus = true; } data.removeVisiable = true; data.removeTitle = '结束课程'; } break; case 2: // 学生人数必须大于0,才可以布置作业 if (data.preStudentNum <= 0) return; // const res = await lessonPreTrainingPage({ // coursewareKnowledgeDetailId: data.detailId, // subjectId: data.subjectId, // page: 1, // rows: 99 // }); // if (res.data.rows && res.data.rows.length) { // data.modalAttendMessage = '本节课已设置课后作业,是否布置?'; // } // data.modelAttendStatus = true; const res = await getStudentAfterWork({ courseScheduleId: data.classId, page: 1, rows: 99 }); if (res.data.rows && res.data.rows.length) { // data.modalAttendMessage = '请确认是否结束课程?'; data.modalAttendMessage = '本次课程已布置作业,是否继续?'; data.modelAttendStatus = true; } else { data.modelTrainStatus = true; nextTick(() => { getModalHeight(); }); data.modelAttendStatus = false; } break; case 3: openStudyTool({ type: 'pen', icon: iconNote, name: '批注' }); break; case 4: openStudyTool({ type: 'whiteboard', icon: iconWhite, name: '白板' }); break; case 5: startShowModal('beatIcon'); break; case 6: startShowModal('toneIcon'); break; case 7: startShowModal('setTimeIcon'); break; case 8: columnShow.value = false; break; case 9: // 选择曲目时需要暂停所有播放 handleStop(false); data.selectResourceStatus = true; break; case 10: // 点名 // await rollCallStudentList(); if (studyData.callStudentList.length > 0) { openStudyTool({ type: 'call', icon: iconWhite, name: '点名' }); return; } break; case 11: if (!isUpArrow.value) return; handlePreAndNext('up'); break; case 12: if (!isDownArrow.value) return; handlePreAndNext('down'); break; case 13: popupData.chapterOpen = true; break; case 14: popupData.open = true; nextTick(() => { scrollResourceSection(); }); break; default: break; } }; // 点名学生列表 const rollCallStudentList = async () => { // if (!data.classId) return; try { const res = await getStudentList({ classGroupId: data.classGroupId, page: 1, rows: 999 }); const result = res.data || {}; if (Array.isArray(result.rows) && result.rows.length > 0) { const tempStudents: any = []; result.rows.forEach((row: any) => { tempStudents.push({ name: row.nickname, img: row.avatar }); }); studyData.callStudentList = [...tempStudents]; } } catch { // } }; // 滚动到某个元素的位置 const scrollResourceSection = () => { const drawerCardItemRefs = document.querySelectorAll('.drawerCardItemRef'); if ( popupData.activeIndex >= 0 && drawerCardItemRefs[popupData.activeIndex] ) { drawerCardItemRefs[popupData.activeIndex].scrollIntoView(); } }; const getModalHeight = () => { const dom: any = document.querySelector('#model-homework-height'); if (dom) { useResizeObserver(dom as HTMLElement, (entries: any) => { const entry = entries[0]; const { height } = entry.contentRect; dom.style.setProperty('--window-page-lesson-height', height + 'px'); }); } }; /* 弹窗加拖动 */ // 选择课件弹窗 const selCourBoxClass = 'selCourBoxClass_drag'; const selCourDragData = useDrag( [`${selCourBoxClass}>.n-card-header`, `${selCourBoxClass} .bom_drag`], selCourBoxClass, toRef(data, 'selectClassStatus'), users.info.id ); // 选择资源弹窗 const selResourBoxClass = 'selResourBoxClass_drag'; const selResourDragData = useDrag( [ `${selResourBoxClass} .select-resource>.n-tabs>.n-tabs-nav--top.n-tabs-nav`, `${selResourBoxClass} .bom_drag` ], selResourBoxClass, toRef(data, 'selectResourceStatus'), users.info.id ); return () => (
{data.modalAttendMessage}
{data.removeContent}