StudyDetailPage.vue
7.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
<!--
* @Date: 2025-04-07
* @Description: 学习详情页面
-->
<template>
<div class="study-detail-page bg-gradient-to-b from-green-50/70 to-white/90 min-h-screen pb-20">
<div v-if="course" class="flex flex-col h-screen">
<!-- 固定区域:视频播放和标签页 -->
<div class="fixed top-0 left-0 right-0 z-10 top-wrapper">
<!-- 视频播放区域 -->
<div class="w-full bg-black relative">
<!-- 视频封面和播放按钮 -->
<div v-if="!isPlaying" class="relative w-full" style="aspect-ratio: 16/9;">
<img :src="course.cover" :alt="course.title" class="w-full h-full object-cover" />
<div class="absolute inset-0 flex items-center justify-center cursor-pointer"
@click="startPlay">
<div
class="w-24 h-24 rounded-full bg-black/50 flex items-center justify-center hover:bg-black/70 transition-colors">
<font-awesome-icon icon="circle-play" class="text-5xl text-white"
style="font-size: 3rem;" />
</div>
</div>
</div>
<!-- 视频播放器 -->
<VideoPlayer v-show="isPlaying" ref="videoPlayerRef" :video-url="course.videoUrl" :autoplay="false"
@onPlay="handleVideoPlay" @onPause="handleVideoPause" />
</div>
<!-- 标签页区域 -->
<div class="px-4 py-3 bg-white">
<van-tabs v-model:active="activeTab" sticky animated swipeable shrink @change="handleTabChange">
<van-tab title="介绍" name="intro">
</van-tab>
<van-tab :title-style="{ 'min-width': '50%' }" name="comments">
<template #title>评论(999)</template>
</van-tab>
</van-tabs>
</div>
</div>
<!-- 滚动区域:介绍和评论内容 -->
<div class="overflow-y-auto flex-1" :style="{paddingTop: topWrapperHeight, height: 'calc(100vh - ' + topWrapperHeight + ')'}">
<div id="intro" class="py-4 px-4">
<h1 class="text-lg font-bold mb-2">{{ course.title }}</h1>
<div class="text-gray-500 text-sm flex items-center gap-2">
<span>{{ course.date }}</span>
<span class="text-gray-300">|</span>
<span>{{ course.studyCount || 0 }}次学习</span>
</div>
</div>
<div class="h-2 bg-gray-100"></div>
<div id="comment" class="py-4 px-4 space-y-4">
<div v-for="comment in comments" :key="comment.id" class="bg-white rounded-lg p-4 shadow-sm">
<div class="flex items-center mb-2">
<img :src="comment.avatar" class="w-8 h-8 rounded-full mr-2" />
<div>
<div class="font-medium">{{ comment.username }}</div>
<div class="text-gray-500 text-xs">{{ comment.time }}</div>
</div>
</div>
<div class="text-gray-700">{{ comment.content }}</div>
</div>
</div>
</div>
<!-- 底部操作栏 -->
<div class="fixed bottom-0 left-0 right-0 bg-white border-t px-4 py-2 flex items-center space-x-4">
<van-button icon="bars" class="flex-none" @click="showCatalog = true">课程目录</van-button>
<div class="flex-grow">
<van-field v-model="newComment" placeholder="说点什么吧~" class="bg-gray-100 rounded-full" />
</div>
<van-button type="primary" size="small" @click="submitComment">发送</van-button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { useTitle } from '@vueuse/core';
import VideoPlayer from '@/components/ui/VideoPlayer.vue';
const route = useRoute();
const course = ref(null);
const activeTab = ref('intro');
const newComment = ref('');
const showCatalog = ref(false);
const isPlaying = ref(false);
const videoPlayerRef = ref(null);
// 开始播放视频
const startPlay = async () => {
isPlaying.value = true;
await nextTick();
if (videoPlayerRef.value) {
videoPlayerRef.value.play();
}
};
// 处理视频播放状态
const handleVideoPlay = () => {
isPlaying.value = true;
};
const handleVideoPause = () => {
// 保持视频播放器可见,只在初始状态显示封面
};
// 评论列表
const comments = ref([
{
id: 1,
username: '欢乐马',
avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg',
content: '教育的顶级传承,是你用什么样的心,传承智慧',
time: '2024-12-04 18:51'
},
{
id: 2,
username: '欢乐马',
avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg',
content: '不要用战术上的勤奋,掩盖战略上的懒惰',
time: '2024-12-04 08:01'
},
{
id: 3,
username: '欢乐马',
avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg',
content: '和老师积极互动,整个课堂像为你而讲',
time: '2024-12-04 07:54'
}
]);
// 设置页面标题
useTitle('学习详情');
const topWrapperHeight = ref(0);
onMounted(() => {
nextTick(() => {
const topWrapper = document.querySelector('.top-wrapper');
if (topWrapper) {
topWrapperHeight.value = topWrapper.clientHeight + 'px';
}
})
const courseId = route.params.id;
if (courseId) {
// TODO: 这里需要替换为实际的API调用
// 临时使用模拟数据
course.value = {
id: courseId,
title: '开学礼·止的智慧·心法老师·20241001(上)',
videoUrl: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4',
progress: 35,
studyTime: 3600,
type: '视频课程',
studyCount: 1896,
cover: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg',
date: '2024-12-04'
};
}
})
// 提交评论
const submitComment = () => {
if (!newComment.value.trim()) return;
comments.value.unshift({
id: Date.now(),
username: '当前用户',
avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg',
content: newComment.value,
time: new Date().toLocaleString()
});
newComment.value = '';
};
// 处理标签页切换
const handleTabChange = (name) => {
nextTick(() => {
const element = document.getElementById(name === 'intro' ? 'intro' : 'comment');
if (element && container) {
const topOffset = element.offsetTop - parseInt(topWrapperHeight.value);
window.scrollTo({
top: topOffset,
behavior: 'smooth'
});
}
})
};
</script>