|
|
@@ -1,29 +1,137 @@
|
|
|
<template>
|
|
|
- <ie-page>
|
|
|
+ <ie-page bg-color="#F6F8FA">
|
|
|
<ie-navbar :title="pageTitle" />
|
|
|
+ <view class="">
|
|
|
+ <view class="h-[200px] bg-black">
|
|
|
+ <video v-if="playUrl" id="player" class="w-full h-full" :src="playUrl" :poster="coverUrl" object-fit="fill"
|
|
|
+ controls enable-play-gesture play-btn-position="center" :picture-in-picture-mode="[]"
|
|
|
+ :show-background-playback-button="false" @timeupdate="handleTimeUpdate" @ended="handlePlayEnd">
|
|
|
+ </video>
|
|
|
+ </view>
|
|
|
+ <view class="flex items-center gap-20 px-20 py-16 bg-white">
|
|
|
+ <text class="text-28 text-fore-light">倍速播放</text>
|
|
|
+ <uv-tags v-for="item in rateList" :key="item" :text="`x${item}`" size="mini" type="primary"
|
|
|
+ :plain="currentRate !== item" @click="handleRate(item)" custom-class="w-[28px] text-center">
|
|
|
+ </uv-tags>
|
|
|
+ </view>
|
|
|
+ <view class="bg-white">
|
|
|
+ <uv-cell-group>
|
|
|
+ <uv-cell v-for="item in videoList" :key="item.aliId" :title="item.name">
|
|
|
+ <template #title>
|
|
|
+ <view class="flex items-center gap-20" @click="handlePlay(item)">
|
|
|
+ <ie-image :src="item.img" custom-class="w-100 h-64" />
|
|
|
+ <view class="flex-1 min-w-1 ellipsis-1 text-28"
|
|
|
+ :class="[currentVideo?.aliId === item.aliId ? 'text-primary' : 'text-fore-title']">
|
|
|
+ {{ item.name }}
|
|
|
+ </view>
|
|
|
+ <view class="text-24 text-primary flex items-center">
|
|
|
+ <uv-icon :name="currentVideo?.aliId === item.aliId ? 'play-circle-fill' : 'play-circle'" size="20"
|
|
|
+ color="var(--primary-color)" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ </uv-cell>
|
|
|
+ </uv-cell-group>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</ie-page>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
import { useTransferPage } from '@/hooks/useTransferPage';
|
|
|
import type { Study } from '@/types';
|
|
|
+import { getVideoCoursePlayInfo, saveVideoCourseRecord } from '@/api/modules/study';
|
|
|
|
|
|
+let videoContext: UniApp.VideoContext;
|
|
|
+const rateList = ref<number[]>([0.5, 1, 1.25, 1.5, 2]);
|
|
|
const { prevData, transferBack } = useTransferPage();
|
|
|
-const currentVideo = ref < Study.VideoCourse > ();
|
|
|
+const currentRate = ref<number>(1);
|
|
|
+const currentVideo = ref<Study.VideoCourse>();
|
|
|
+const duration = ref(0);
|
|
|
+const currentTime = ref(0);
|
|
|
|
|
|
const videoList = computed(() => {
|
|
|
const { knowledge } = prevData.value as { knowledge: Study.VideoCourseKnowledge };
|
|
|
- return knowledge.children;
|
|
|
+ return knowledge?.children || [];
|
|
|
});
|
|
|
const videoIndex = computed(() => {
|
|
|
return videoList.value.findIndex(item => item.aliId === currentVideo.value?.aliId);
|
|
|
});
|
|
|
const pageTitle = computed(() => {
|
|
|
- return videoList.value[videoIndex.value].name;
|
|
|
+ return videoList.value[videoIndex.value]?.name || '';
|
|
|
});
|
|
|
+const playUrl = ref('');
|
|
|
+const coverUrl = ref('');
|
|
|
+const handleRate = (item: number) => {
|
|
|
+ if (videoContext) {
|
|
|
+ currentRate.value = item;
|
|
|
+ videoContext.playbackRate(item);
|
|
|
+ }
|
|
|
+}
|
|
|
+const handleTimeUpdate = (e: any) => {
|
|
|
+ const newTime = Number(e.detail.currentTime);
|
|
|
+ if (newTime > currentTime.value && (newTime - currentTime.value > 5)) {
|
|
|
+ saveRecord(newTime, duration.value);
|
|
|
+ currentTime.value = newTime;
|
|
|
+ }
|
|
|
+ if (!isNaN(e.detail.duration)) {
|
|
|
+ duration.value = Number(e.detail.duration);
|
|
|
+ }
|
|
|
+}
|
|
|
+const handlePlayEnd = () => {
|
|
|
+ saveRecord(duration.value, duration.value);
|
|
|
+}
|
|
|
+const saveRecord = (current: number, duration: number) => {
|
|
|
+ if (current > 0 && duration > 0) {
|
|
|
+ const percentage = ((current / duration) * 100).toFixed(2);
|
|
|
+ saveVideoCourseRecord({
|
|
|
+ sectionId: currentVideo.value!.aliId,
|
|
|
+ duration: Math.floor(duration),
|
|
|
+ percent: percentage,
|
|
|
+ type: currentVideo.value!.aliIdType
|
|
|
+ }).then(res => {
|
|
|
+ console.log(res);
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+const handlePlay = async (item: Study.VideoCourse) => {
|
|
|
+ currentVideo.value = item;
|
|
|
+ // 等待播放暂停
|
|
|
+ videoContext.pause();
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 150));
|
|
|
+ currentTime.value = 0;
|
|
|
+ duration.value = 0;
|
|
|
+ await loadData();
|
|
|
+ setTimeout(() => {
|
|
|
+ videoContext.play();
|
|
|
+ }, 0);
|
|
|
+}
|
|
|
+const loadData = async () => {
|
|
|
+ if (currentVideo.value) {
|
|
|
+ const aliId = currentVideo.value?.aliId || '';
|
|
|
+ if (aliId.includes('https') || aliId.includes('http')) {
|
|
|
+ playUrl.value = aliId;
|
|
|
+ } else {
|
|
|
+ uni.$ie.showLoading();
|
|
|
+ await getVideoCoursePlayInfo(aliId).then(res => {
|
|
|
+ playUrl.value = res.data.palyUrl;
|
|
|
+ coverUrl.value = res.data.coverUrl;
|
|
|
+ }).finally(() => {
|
|
|
+ uni.$ie.hideLoading();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
onLoad(() => {
|
|
|
currentVideo.value = prevData.value.video;
|
|
|
+ loadData();
|
|
|
+});
|
|
|
+onUnload(() => {
|
|
|
+ saveRecord(currentTime.value, duration.value);
|
|
|
+});
|
|
|
+onReady(() => {
|
|
|
+ videoContext = uni.createVideoContext('player');
|
|
|
});
|
|
|
</script>
|
|
|
|