|
|
@@ -67,20 +67,10 @@
|
|
|
<a-card :bordered="false" class="mt-2" style="width: 1200px">
|
|
|
<a-tabs v-model:activeKey="tabsActiveKey">
|
|
|
<a-tab-pane key="1" tab="讲义">
|
|
|
- <div style="height: 900px">
|
|
|
- <div v-if="!showPdf">渲染pdf失败</div>
|
|
|
- <vue-office-pdf :src="itemObj.url" style="width: 100%; height: 100%" @error="errorHandler" />
|
|
|
- </div>
|
|
|
+ <handouts :itemObj="itemObj" :hourId="selectedKeys[0]"></handouts>
|
|
|
</a-tab-pane>
|
|
|
<a-tab-pane key="2" tab="字幕">
|
|
|
- <a-input v-model:value="subtitleVal" allowClear placeholder="请输入" />
|
|
|
- <div style="height: 900px; overflow-y: auto" class="mt-2">
|
|
|
- <div v-if="subtitle">{{ subtitle }}</div>
|
|
|
- <div v-for="(item, idx) in subtitleList" :key="idx">
|
|
|
- <div>{{ item.startTime }}~{{ item.endTime }}</div>
|
|
|
- <div style="cursor: pointer; padding: 10px 0" @click="videoSpeed(item)">{{ item.text }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <subtitleBox :url="danmuObj.url" @videoSpeed="videoSpeed"></subtitleBox>
|
|
|
</a-tab-pane>
|
|
|
<a-tab-pane key="3" tab="笔记">
|
|
|
<note :idsObj="idsObj" ref="noteRef" @edit="noteEdit"></note>
|
|
|
@@ -91,7 +81,7 @@
|
|
|
</a-tabs>
|
|
|
</a-card>
|
|
|
</div>
|
|
|
- <forumBtn :forumData="forumData"></forumBtn>
|
|
|
+ <forumBtn :forumData="forumData" resourceType="0"></forumBtn>
|
|
|
</a-layout-content>
|
|
|
</a-layout>
|
|
|
</a-layout>
|
|
|
@@ -104,8 +94,9 @@
|
|
|
import sysConfig from '@/config/index'
|
|
|
import note from './note.vue'
|
|
|
import askDiv from './ask.vue'
|
|
|
- import VueOfficePdf from '@vue-office/pdf'
|
|
|
- import axios from 'axios'
|
|
|
+ import handouts from './handouts.vue'
|
|
|
+ import subtitleBox from './subtitle.vue'
|
|
|
+
|
|
|
const route = useRoute()
|
|
|
const router = useRouter()
|
|
|
const classDetail = ref({})
|
|
|
@@ -115,13 +106,13 @@
|
|
|
const selectedKeys = ref([])
|
|
|
const collapsed = ref(false)
|
|
|
const videoRef = ref()
|
|
|
- const currentTimenew = ref()
|
|
|
+ const currentTimenew = ref(0)
|
|
|
const idsObj = computed(() => {
|
|
|
let item = findNodeByKey(classTimeList.value, selectedKeys.value[0])
|
|
|
return {
|
|
|
courseId: route.query.id,
|
|
|
- chapterId: item?.chapterId,
|
|
|
- hourId: selectedKeys.value[0]
|
|
|
+ chapterId: selectedKeys.value[0],
|
|
|
+ hourId: classHourData.value?.chapterId
|
|
|
}
|
|
|
})
|
|
|
function findNodeByKey(list, id) {
|
|
|
@@ -160,6 +151,8 @@
|
|
|
}
|
|
|
})
|
|
|
videoRef.value.src = classTimeData.value.filter((r) => r.funcType == 1)[0]?.url
|
|
|
+ footprintClassAdd()
|
|
|
+ getVideoTime()
|
|
|
})
|
|
|
}
|
|
|
|
|
|
@@ -172,9 +165,6 @@
|
|
|
})
|
|
|
const danmuObj = computed(() => {
|
|
|
let item = classTimeData.value.length > 0 ? classTimeData.value.filter((r) => r.funcType == 3)[0] : { url: '' }
|
|
|
- if (item?.url) {
|
|
|
- GetSrtInfo(item.url)
|
|
|
- }
|
|
|
return item
|
|
|
})
|
|
|
const videoUrl = ref('')
|
|
|
@@ -203,30 +193,42 @@
|
|
|
timeStamp1.value = parseInt(e.target.currentTime) //播放进度 (秒)
|
|
|
biNum.value = Math.floor((timeStamp1.value / allTime.value) * 10000) / 100 //暂时没用到
|
|
|
currentTime.value = e.target.currentTime
|
|
|
- if (videoJumpTime.value) {
|
|
|
- videoJumpTime.value = false
|
|
|
- newsschedule.value = currentTime.value
|
|
|
- } else {
|
|
|
- if (newsschedule.value <= currentTime.value) {
|
|
|
- //请求接口获取的参数就是判断当前观看的时长是否小于当前时间 小于当前时间就禁止拖动进度条
|
|
|
|
|
|
- if (e.srcElement.currentTime - currTime.value > 3) {
|
|
|
- //这里拖动进度条时间 - 当前观看的时长 > 3秒 这边判定它为拖动进度条
|
|
|
- e.srcElement.currentTime = currTime.value > maxTime.value ? currTime.value : maxTime.value
|
|
|
- let newsVal = initialtime.value
|
|
|
- if (newsVal) {
|
|
|
- videoContext.value.currentTime = newsVal
|
|
|
- }
|
|
|
- //当前用户记录观看时间 大于 实施播放时间
|
|
|
- if (currTime.value > newsVal) {
|
|
|
- videoContext.value.currentTime = currTime.value
|
|
|
- }
|
|
|
- console.log('快进了')
|
|
|
- }
|
|
|
- currTime.value = e.srcElement.currentTime
|
|
|
- maxTime.value = currTime.value > maxTime.value ? currTime.value : maxTime.value
|
|
|
- }
|
|
|
+ console.log('🚀 ~ timeUpdate ~ e.srcElement.currentTime:', e.srcElement.currentTime)
|
|
|
+ console.log('🚀 ~ timeUpdate ~ currTime.value:', currTime.value)
|
|
|
+ if (e.srcElement.currentTime - currTime.value > 3) {
|
|
|
+ addClassPlan(3)
|
|
|
+ console.log('快进了')
|
|
|
}
|
|
|
+ if (currTime.value - e.srcElement.currentTime > 3) {
|
|
|
+ addClassPlan(3)
|
|
|
+ console.log('快退了')
|
|
|
+ }
|
|
|
+ currTime.value = e.srcElement.currentTime
|
|
|
+ // if (videoJumpTime.value) {
|
|
|
+ // videoJumpTime.value = false
|
|
|
+ // newsschedule.value = currentTime.value
|
|
|
+ // } else {
|
|
|
+ // if (newsschedule.value <= currentTime.value) {
|
|
|
+ // //请求接口获取的参数就是判断当前观看的时长是否小于当前时间 小于当前时间就禁止拖动进度条
|
|
|
+
|
|
|
+ // if (e.srcElement.currentTime - currTime.value > 3) {
|
|
|
+ // //这里拖动进度条时间 - 当前观看的时长 > 3秒 这边判定它为拖动进度条
|
|
|
+ // e.srcElement.currentTime = currTime.value > maxTime.value ? currTime.value : maxTime.value
|
|
|
+ // let newsVal = initialtime.value
|
|
|
+ // if (newsVal) {
|
|
|
+ // videoContext.value.currentTime = newsVal
|
|
|
+ // }
|
|
|
+ // //当前用户记录观看时间 大于 实施播放时间
|
|
|
+ // if (currTime.value > newsVal) {
|
|
|
+ // videoContext.value.currentTime = currTime.value
|
|
|
+ // }
|
|
|
+ // console.log('快进了')
|
|
|
+ // }
|
|
|
+ // currTime.value = e.srcElement.currentTime
|
|
|
+ // maxTime.value = currTime.value > maxTime.value ? currTime.value : maxTime.value
|
|
|
+ // }
|
|
|
+ // }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -242,47 +244,7 @@
|
|
|
videoJumpTime.value = true
|
|
|
currentTimenew.value = e.startTime
|
|
|
}
|
|
|
- //获取字幕内容,发送一个get请求
|
|
|
- function GetSrtInfo(srtUrl) {
|
|
|
- subtitle.value = ''
|
|
|
- axios
|
|
|
- .get(`${srtUrl}`)
|
|
|
- .then(function (response) {
|
|
|
- try {
|
|
|
- let textList = response.data
|
|
|
- .split(/\n\s\n/)
|
|
|
- .filter((item) => item != '')
|
|
|
- .map((item, index) => {
|
|
|
- let textItem = item.split(/\n/)
|
|
|
- return {
|
|
|
- index: index,
|
|
|
- sort: textItem[0],
|
|
|
- text: textItem[2],
|
|
|
- startTime: ToSeconds(textItem[1].split(' --> ')[0]),
|
|
|
- endTime: ToSeconds(textItem[1].split(' --> ')[1]),
|
|
|
- timeLine: textItem[1]
|
|
|
- }
|
|
|
- })
|
|
|
- danmuObj.value.srtInfoList = textList
|
|
|
- } catch (error) {
|
|
|
- subtitle.value = '字幕解析失败'
|
|
|
- }
|
|
|
- })
|
|
|
- .catch(function (error) {
|
|
|
- console.log(error)
|
|
|
- })
|
|
|
- }
|
|
|
- //将时间转化为秒
|
|
|
- function ToSeconds(t) {
|
|
|
- var s = 0.0
|
|
|
- if (t) {
|
|
|
- var p = t.split(':')
|
|
|
- for (let i = 0; i < p.length; i++) {
|
|
|
- s = s * 60 + parseFloat(p[i].replace(',', '.'))
|
|
|
- }
|
|
|
- }
|
|
|
- return s
|
|
|
- }
|
|
|
+
|
|
|
const forumData = computed(() => {
|
|
|
let item = findNodeByKey(classTimeList.value, selectedKeys.value[0]) ?? {}
|
|
|
if (!item.src) {
|
|
|
@@ -291,19 +253,30 @@
|
|
|
return {
|
|
|
id: selectedKeys.value[0],
|
|
|
title: item?.name,
|
|
|
- videoUrl: btoa(encodeURIComponent(videoRef.value?.src ? videoRef.value.src : item.src))
|
|
|
+ videoUrl: btoa(encodeURIComponent(videoRef.value?.src ? videoRef.value.src : item.src)),
|
|
|
+ courseId: route.query.id,
|
|
|
+ chapterId: selectedKeys.value[0],
|
|
|
+ courseName: classDetail.value?.courseName,
|
|
|
+ chapterName: classHourData.value?.name
|
|
|
}
|
|
|
})
|
|
|
const showPdf = ref(true)
|
|
|
function errorHandler() {
|
|
|
showPdf.value = false
|
|
|
}
|
|
|
- const subtitle = ref()
|
|
|
const getVideoTime = () => {
|
|
|
- classCentre.theLastDetail().then((data) => {
|
|
|
- initialtime.value = parseFloat(data.endTime) / 1000
|
|
|
- currentTimenew.value = parseFloat(data.endTime) / 1000
|
|
|
- })
|
|
|
+ classCentre
|
|
|
+ .theLastDetail({
|
|
|
+ funcType: 1,
|
|
|
+ type: 1,
|
|
|
+ hourld: classHourData.value?.chapterId
|
|
|
+ })
|
|
|
+ .then((data) => {
|
|
|
+ if (data.endTime) {
|
|
|
+ initialtime.value = parseFloat(data.endTime) / 1000
|
|
|
+ currentTimenew.value = parseFloat(data.endTime) / 1000
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
// 毫秒转换时分秒
|
|
|
@@ -331,12 +304,12 @@
|
|
|
return ms
|
|
|
}
|
|
|
onBeforeUnmount(() => {
|
|
|
- outNowTimesStr.value = Date.now()
|
|
|
- addClassPlan()
|
|
|
+ addClassPlan(1)
|
|
|
})
|
|
|
const nowTimesStr = Date.now()
|
|
|
const outNowTimesStr = ref()
|
|
|
- const addClassPlan = () => {
|
|
|
+ const addClassPlan = (type) => {
|
|
|
+ outNowTimesStr.value = Date.now()
|
|
|
let progress = parseFloat((videoRef.value?.currentTime / videoRef.value?.duration) * 100)
|
|
|
if (
|
|
|
(progress || progress == 0) &&
|
|
|
@@ -348,9 +321,10 @@
|
|
|
startTime: parseFloat(initialtime.value),
|
|
|
endTime: Math.round(videoRef.value.currentTime * 1000),
|
|
|
progress: Math.round(progress),
|
|
|
- hourId: selectedKeys.value[0],
|
|
|
+ hourId: classHourData.value?.chapterId,
|
|
|
stayTime: outNowTimesStr.value - nowTimesStr,
|
|
|
- type: 1
|
|
|
+ type: type,
|
|
|
+ funcType: type
|
|
|
})
|
|
|
.then((data) => {})
|
|
|
}
|
|
|
@@ -369,17 +343,20 @@
|
|
|
})
|
|
|
})
|
|
|
}
|
|
|
- // 模糊查询函数
|
|
|
- const subtitleVal = ref()
|
|
|
- const subtitleList = computed(() => {
|
|
|
- return danmuObj.value.srtInfoList?.filter((item) => {
|
|
|
- if (subtitleVal.value) {
|
|
|
- return item.text.includes(subtitleVal.value)
|
|
|
- } else {
|
|
|
- return true
|
|
|
- }
|
|
|
+ //足迹
|
|
|
+ const footprintClassAdd = () => {
|
|
|
+ classCentre.footprintClassAdd({
|
|
|
+ hourName: classHourData.value.name,
|
|
|
+ chapterName: classHourData.value.name,
|
|
|
+ courseName: classDetail.value.courseName,
|
|
|
+ hourId: classHourData.value.chapterId,
|
|
|
+ chapterId: selectedKeys.value[0],
|
|
|
+ courseId: classDetail.value.courseId,
|
|
|
+ fileId: classHourData.value.courseRelates.filter((r) => r.funcType == 1)[0].relateId,
|
|
|
+ fileName: classHourData.value.courseRelates.filter((r) => r.funcType == 1)[0].name,
|
|
|
+ filePath: classHourData.value.courseRelates.filter((r) => r.funcType == 1)[0].url
|
|
|
})
|
|
|
- })
|
|
|
+ }
|
|
|
onMounted(() => {
|
|
|
getClassData()
|
|
|
getVideoTime()
|