import { closeToast, Icon, Popup, showConfirmDialog, showToast, Slider, Swipe, SwipeItem } from 'vant' import { defineComponent, onMounted, reactive, nextTick, onUnmounted, ref, watch, Transition, computed } from 'vue' import styles from './index.module.less' import 'plyr/dist/plyr.css' import request from '@/helpers/request' import { state } from '@/state' import { useRoute, useRouter } from 'vue-router' import iconBack from '../coursewarePlay/image/back.svg' import { postMessage, promisefiyPostMessage } from '@/helpers/native-message' import iconLoop from '../coursewarePlay/image/icon-loop.svg' import iconLoopActive from '../coursewarePlay/image/icon-loop-active.svg' import iconplay from '../coursewarePlay/image/icon-play.svg' import iconpause from '../coursewarePlay/image/icon-pause.svg' import iconVideobg from '../coursewarePlay/image/icon-videobg.png' import { browser, getSecondRPM } from '@/helpers/utils' const materialType = { 视频: 'VIDEO', 图片: 'IMG', 曲目: 'SONG' } export default defineComponent({ name: 'exercise-after-class', 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) }) const route = useRoute() const router = useRouter() const query = route.query const browserInfo = browser() const headeRef = ref() const data = reactive({ videoData: null as any, details: [] as any, trainingTimes: 0, itemList: [] as any, showHead: true, loading: true, recordLoading: false }) const activeData = reactive({ nowTime: 0, model: true, // 遮罩 timer: null as any, item: null as any }) // 获取缓存路径 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 } }) return res } const getDetail = async () => { let details = [] try { const res: any = await request.get( state.platformApi + `/lessonTraining/courseSchedule/${route.query.courseScheduleId}` ) if (Array.isArray(res?.data)) { const studentLevel = state.user?.data?.studentLevel || 1 details = res.data.find((n: any) => n.studentLevel === studentLevel)?.details || [] } } catch (error) { console.log('error') } if (details.length) { data.details = details const videoData: any = details.find((n: any) => n.materialId == route.query.materialId) || {} try { videoData.training = JSON.parse(videoData?.lessonTrainingTemp?.trainingConfigJson) } catch (error) {} //请求本地缓存 if (browserInfo.isApp && ['VIDEO'].includes(videoData.type)) { const localData = await getCacheFilePath(videoData) if (localData?.content?.localPath) { videoData.url = videoData.content videoData.content = localData.content.localPath } } data.itemList.push({ ...videoData, id: videoData.materialId, currentTime: 0, duration: 100, paused: true, loop: false, videoEle: null, timer: null, playModel: true }) popupData.itemActive = videoData.id popupData.tabName = videoData.materialName data.videoData = videoData handleExerciseCompleted() } } const getTrainingTimes = (res: any) => { let trainingTimes = 0 if (Array.isArray(res?.trainings)) { const train = res.trainings.find((n: any) => n.materialId === query.materialId) if (train) { trainingTimes = train.trainingTimes } } data.trainingTimes = trainingTimes } // 获取课后练习记录 const trainingRecord = async () => { try { const res: any = await request.post( state.platformApi + `/studentLessonTraining/trainingRecord/${query.courseScheduleId}?userId=${state.user?.data?.id}` ) if (res?.data) { getTrainingTimes(res.data) handleExerciseCompleted() } } catch (error) {} } onMounted(() => { getDetail() trainingRecord() }) // 返回 const goback = () => { postMessage({ api: 'back' }) } const swipeRef = ref() const popupData = reactive({ firstIndex: 0, open: false, activeIndex: -1, tabActive: '', tabName: '', itemActive: '', itemName: '' }) // 双击 const handleDbClick = (item: any) => { if (item && item.type === 'VIDEO') { const videoEle: HTMLVideoElement = document.querySelector(`[data-vid='${item.id}']`)! if (videoEle) { if (videoEle.paused) { closeToast() videoEle.play() } else { showToast('已暂停') videoEle.pause() } } item.timer = setTimeout(() => { activeData.model = false }, 3000) } } // 达到指标,记录 const addTrainingRecord = async (m: any) => { data.recordLoading = true const body = { materialType: 'VIDEO', record: { sourceTime: m.duration, clientType: state.platformType, feature: 'LESSON_TRAINING', deviceType: browserInfo.android ? 'ANDROID' : browserInfo.isApp ? 'IOS' : 'WEB' }, courseScheduleId: query.courseScheduleId, lessonTrainingId: query.lessonTrainingId, materialId: query.materialId } try { const res: any = await request.post( state.platformApi + '/studentLessonTraining/lessonTrainingRecord', { data: body } ) trainingRecord() } catch (error) {} setTimeout(() => { data.recordLoading = false }, 2000) } // 停止所有的播放 const handleStopVideo = () => { data.itemList.forEach((m: any) => { m.videoEle?.pause() }) } // 判断练习是否完成 const handleExerciseCompleted = () => { if ( data.trainingTimes != 0 && data.trainingTimes == (data.videoData as any)?.training?.practiceTimes ) { handleStopVideo() const itemIndex = data.details.findIndex( (n: any) => n.materialId == data.videoData?.materialId ) const isLastIndex = itemIndex === data.details.length - 1 showConfirmDialog({ title: '课后训练', message: '你已完成该练习~', confirmButtonColor: 'var(--van-primary)', confirmButtonText: isLastIndex ? '完成' : '下一题', cancelButtonText: '继续' }).then(() => { if (!isLastIndex) { const nextItem = data.details[itemIndex + 1] if (nextItem?.type === materialType.视频) { // console.log('下一题视频', nextItem) router.replace({ path: '/exerciseAfterClass', query: { ...query, materialId: nextItem.materialId } }) } if (nextItem?.type === materialType.曲目) { goback() let src = `${location.origin}/orchestra-music-score/?id=${nextItem.content}` postMessage({ api: 'openAccompanyWebView', content: { url: src, orientation: 0, isHideTitle: true, statusBarTextColor: false, isOpenLight: true } }) } } }) } } return () => (