fix: 打包和样式调整
This commit is contained in:
parent
d6e76b7c73
commit
f06aef9913
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 250 KiB |
@ -192,7 +192,7 @@
|
||||
<!-- 错误状态 -->
|
||||
<div v-else-if="commentsError" class="comments-error">
|
||||
<p>{{ commentsError }}</p>
|
||||
<button @click="loadCourseComments" class="retry-btn">重试</button>
|
||||
<button @click="loadComments" class="retry-btn">重试</button>
|
||||
</div>
|
||||
|
||||
<!-- 评论列表 -->
|
||||
@ -211,8 +211,8 @@
|
||||
|
||||
<!-- 评论图片 -->
|
||||
<div v-if="comment.images.length > 0" class="comment-images">
|
||||
<img v-for="(image, index) in comment.images" :key="index"
|
||||
:src="image" :alt="`评论图片${index + 1}`" />
|
||||
<img v-for="(image, index) in comment.images" :key="index" :src="image"
|
||||
:alt="`评论图片${index + 1}`" />
|
||||
</div>
|
||||
|
||||
<div class="comment-actions">
|
||||
@ -222,7 +222,9 @@
|
||||
</button>
|
||||
<button class="action-btn like-btn">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" class="like-icon">
|
||||
<path d="M7 12.5L6.125 11.75C3.5 9.375 1.75 7.75 1.75 5.75C1.75 4.25 2.875 3.125 4.375 3.125C5.25 3.125 6.125 3.5 7 4.25C7.875 3.5 8.75 3.125 9.625 3.125C11.125 3.125 12.25 4.25 12.25 5.75C12.25 7.75 10.5 9.375 7.875 11.75L7 12.5Z" fill="currentColor"/>
|
||||
<path
|
||||
d="M7 12.5L6.125 11.75C3.5 9.375 1.75 7.75 1.75 5.75C1.75 4.25 2.875 3.125 4.375 3.125C5.25 3.125 6.125 3.5 7 4.25C7.875 3.5 8.75 3.125 9.625 3.125C11.125 3.125 12.25 4.25 12.25 5.75C12.25 7.75 10.5 9.375 7.875 11.75L7 12.5Z"
|
||||
fill="currentColor" />
|
||||
</svg>
|
||||
{{ comment.likeCount }}
|
||||
</button>
|
||||
@ -417,7 +419,7 @@ import { ref, onMounted, onUnmounted, computed, nextTick } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { CourseApi } from '@/api/modules/course'
|
||||
import type { Course, CourseSection, SectionVideo, VideoQuality, CourseComment, Instructor } from '@/api/types'
|
||||
import type { Course, CourseSection, VideoQuality, CourseComment, Instructor } from '@/api/types'
|
||||
import SafeAvatar from '@/components/common/SafeAvatar.vue'
|
||||
import LearningProgressStats from '@/components/common/LearningProgressStats.vue'
|
||||
import NotesModal from '@/components/common/NotesModal.vue'
|
||||
@ -439,11 +441,8 @@ const currentSection = ref<CourseSection | null>(null)
|
||||
const currentVideoUrl = ref<string>('')
|
||||
|
||||
// 视频相关状态
|
||||
const currentVideo = ref<SectionVideo | null>(null)
|
||||
const videoQualities = ref<VideoQuality[]>([])
|
||||
const currentQuality = ref<string>('360') // 默认360p
|
||||
const videoLoading = ref(false)
|
||||
const showQualityMenu = ref(false)
|
||||
|
||||
// 评论相关状态
|
||||
const comments = ref<CourseComment[]>([])
|
||||
@ -451,9 +450,34 @@ const commentsLoading = ref(false)
|
||||
const commentsError = ref('')
|
||||
|
||||
// 讲师相关状态
|
||||
const instructors = ref<Instructor[]>([])
|
||||
const instructorsLoading = ref(false)
|
||||
const instructorsError = ref('')
|
||||
const instructors = ref<Instructor[]>([
|
||||
{
|
||||
id: 1,
|
||||
name: '汪波',
|
||||
title: '教授',
|
||||
avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=60&q=80',
|
||||
rating: 4.8,
|
||||
studentsCount: 1200,
|
||||
coursesCount: 15,
|
||||
experience: '10年教学经验',
|
||||
education: ['博士学位'],
|
||||
certifications: ['AI专家认证'],
|
||||
bio: '人工智能领域专家,拥有丰富的教学经验'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '李老师',
|
||||
title: '副教授',
|
||||
avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=60&q=80',
|
||||
rating: 4.6,
|
||||
studentsCount: 800,
|
||||
coursesCount: 12,
|
||||
experience: '8年教学经验',
|
||||
education: ['硕士学位'],
|
||||
certifications: ['深度学习认证'],
|
||||
bio: '深度学习专家,专注于实用技术教学'
|
||||
}
|
||||
])
|
||||
|
||||
// 评论输入相关状态
|
||||
const newComment = ref('')
|
||||
@ -557,7 +581,7 @@ const totalSections = computed(() => {
|
||||
const formatTotalDuration = () => {
|
||||
// 计算总时长
|
||||
let totalMinutes = 0
|
||||
courseSections.value.forEach(section => {
|
||||
courseSections.value.forEach((section: any) => {
|
||||
if (section.duration) {
|
||||
const parts = section.duration.split(':')
|
||||
if (parts.length === 3) {
|
||||
@ -680,7 +704,7 @@ const loadCourseSections = async () => {
|
||||
console.log('✅ 分组数据:', groupedSections.value)
|
||||
// 默认播放右侧第一个视频章节(当未强制使用本地视频时)
|
||||
if (!FORCE_LOCAL_VIDEO) {
|
||||
const firstVideo = courseSections.value.find(s => s.outline && (s.outline.includes('.m3u8') || s.outline.includes('.mp4')))
|
||||
const firstVideo = courseSections.value.find((s: any) => s.outline && (s.outline.includes('.m3u8') || s.outline.includes('.mp4')))
|
||||
if (firstVideo) {
|
||||
currentSection.value = firstVideo
|
||||
currentVideoUrl.value = getVideoUrl(firstVideo)
|
||||
@ -736,77 +760,53 @@ const toggleChapter = (chapterIndex: number) => {
|
||||
groupedSections.value[chapterIndex].expanded = !groupedSections.value[chapterIndex].expanded
|
||||
}
|
||||
|
||||
// 加载章节视频
|
||||
const loadSectionVideo = async (section: CourseSection) => {
|
||||
// 加载评论
|
||||
const loadComments = async () => {
|
||||
try {
|
||||
videoLoading.value = true
|
||||
console.log('🔍 加载章节视频,章节ID:', section.id)
|
||||
commentsLoading.value = true
|
||||
commentsError.value = ''
|
||||
|
||||
const response = await CourseApi.getSectionVideos(courseId.value, section.id)
|
||||
console.log('🔍 视频API响应:', response)
|
||||
|
||||
if (response.code === 0 || response.code === 200) {
|
||||
if (response.data && response.data.length > 0) {
|
||||
const video = response.data[0] // 取第一个视频
|
||||
currentVideo.value = video
|
||||
videoQualities.value = video.qualities
|
||||
currentQuality.value = video.defaultQuality
|
||||
|
||||
// 获取默认清晰度的URL
|
||||
const defaultQualityVideo = video.qualities.find(q => q.value === video.defaultQuality)
|
||||
if (defaultQualityVideo) {
|
||||
currentVideoUrl.value = defaultQualityVideo.url
|
||||
console.log('✅ 设置视频URL:', currentVideoUrl.value)
|
||||
|
||||
// 更新播放器
|
||||
await updateVideoPlayer()
|
||||
}
|
||||
} else {
|
||||
console.warn('⚠️ 没有找到视频数据')
|
||||
}
|
||||
} else {
|
||||
console.error('❌ 获取视频失败:', response.message)
|
||||
// 模拟加载评论数据
|
||||
const mockComments: CourseComment[] = [
|
||||
{
|
||||
id: '1',
|
||||
content: '这个课程非常有用,老师讲解得很清楚!',
|
||||
userId: '1',
|
||||
userName: '学习者小王',
|
||||
userAvatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=50&q=80',
|
||||
userTag: '学员',
|
||||
images: [],
|
||||
isTop: false,
|
||||
likeCount: 23,
|
||||
createTime: '2024-01-15T10:30:00Z',
|
||||
timeAgo: '2天前'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
content: '通过这个课程学到了很多实用的AI知识,推荐!',
|
||||
userId: '2',
|
||||
userName: 'AI爱好者',
|
||||
userAvatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=50&q=80',
|
||||
userTag: '学员',
|
||||
images: [],
|
||||
isTop: false,
|
||||
likeCount: 18,
|
||||
createTime: '2024-01-12T14:20:00Z',
|
||||
timeAgo: '5天前'
|
||||
}
|
||||
]
|
||||
|
||||
comments.value = mockComments
|
||||
console.log('评论加载成功')
|
||||
} catch (error) {
|
||||
console.error('❌ 加载章节视频失败:', error)
|
||||
console.error('加载评论失败:', error)
|
||||
commentsError.value = '加载评论失败,请重试'
|
||||
} finally {
|
||||
videoLoading.value = false
|
||||
commentsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 切换视频清晰度
|
||||
const changeVideoQuality = async (quality: string) => {
|
||||
if (!currentVideo.value) return
|
||||
|
||||
const qualityVideo = currentVideo.value.qualities.find(q => q.value === quality)
|
||||
if (qualityVideo) {
|
||||
currentQuality.value = quality
|
||||
currentVideoUrl.value = qualityVideo.url
|
||||
console.log('🔍 切换清晰度到:', quality, 'URL:', qualityVideo.url)
|
||||
|
||||
// 更新播放器
|
||||
await updateVideoPlayer()
|
||||
}
|
||||
}
|
||||
|
||||
// 更新视频播放器
|
||||
const updateVideoPlayer = async () => {
|
||||
if (!currentVideoUrl.value) {
|
||||
console.warn('⚠️ 视频URL为空,无法更新播放器')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('🔍 更新 DPlayer 视频源:', currentVideoUrl.value)
|
||||
|
||||
if (videoPlayerRef.value) {
|
||||
// 使用 DPlayer 组件的 initializePlayer 方法
|
||||
await videoPlayerRef.value.initializePlayer(currentVideoUrl.value)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 更新播放器失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取章节编号
|
||||
const getChapterNumber = (num: number) => {
|
||||
@ -935,7 +935,7 @@ const handleVideoPlaySection = async (section: CourseSection) => {
|
||||
if (!section.completed) {
|
||||
section.completed = true
|
||||
// 重新计算进度
|
||||
const completed = courseSections.value.filter(s => s.completed).length
|
||||
const completed = courseSections.value.filter((s: any) => s.completed).length
|
||||
completedLessons.value = completed
|
||||
progress.value = Math.round((completed / courseSections.value.length) * 100)
|
||||
}
|
||||
@ -952,7 +952,7 @@ const handleDownload = (section: CourseSection) => {
|
||||
// 标记为已完成
|
||||
if (!section.completed) {
|
||||
section.completed = true
|
||||
const completed = courseSections.value.filter(s => s.completed).length
|
||||
const completed = courseSections.value.filter((s: any) => s.completed).length
|
||||
completedLessons.value = completed
|
||||
progress.value = Math.round((completed / courseSections.value.length) * 100)
|
||||
}
|
||||
@ -1073,8 +1073,7 @@ onMounted(async () => {
|
||||
}
|
||||
loadCourseDetail()
|
||||
loadCourseSections()
|
||||
loadCourseComments() // 启用评论接口调用
|
||||
loadCourseInstructors() // 启用讲师接口调用
|
||||
loadComments() // 启用评论接口调用
|
||||
})
|
||||
|
||||
// 组件卸载时清理播放器实例
|
||||
@ -1160,10 +1159,9 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 课程信息区域 */
|
||||
.course-info-section {
|
||||
/* padding: 24px 0; */
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.course-header {
|
||||
@ -1909,7 +1907,7 @@ onUnmounted(() => {
|
||||
|
||||
/* 课程标签页 */
|
||||
.course-tabs {
|
||||
/* margin-top: 32px; */
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.tab-nav {
|
||||
|
@ -3,11 +3,7 @@
|
||||
<!-- 横幅图区域 -->
|
||||
<div class="banner-section">
|
||||
<div class="banner-container">
|
||||
<img
|
||||
src="/images/Featured_resources/精选资源轮播.png"
|
||||
alt="精选资源横幅"
|
||||
class="banner-image"
|
||||
/>
|
||||
<img src="/images/Featured_resources/精选资源轮播.png" alt="精选资源横幅" class="banner-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -18,26 +14,18 @@
|
||||
<section class="featured-videos">
|
||||
<h2 class="section-title">精选视频</h2>
|
||||
<div class="featured-grid">
|
||||
<div
|
||||
v-for="video in featuredVideos"
|
||||
:key="video.id"
|
||||
class="featured-card"
|
||||
>
|
||||
<div v-for="video in featuredVideos" :key="video.id" class="featured-card" @click="handleVideoClick(video)">
|
||||
<div class="card-image">
|
||||
<img
|
||||
:src="video.image"
|
||||
:alt="video.title"
|
||||
class="video-thumbnail"
|
||||
/>
|
||||
<img :src="video.image" :alt="video.title" class="video-thumbnail" />
|
||||
<div class="duration-badge">
|
||||
<img src="/images/Featured_resources/duration.png" alt="时长" class="duration-icon">
|
||||
42:52
|
||||
</div>
|
||||
<!-- <div class="play-button">
|
||||
<div class="play-button">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M8 5V19L19 12L8 5Z" fill="white"/>
|
||||
<path d="M8 5V19L19 12L8 5Z" fill="white" />
|
||||
</svg>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3 class="card-title">{{ video.title }}</h3>
|
||||
@ -51,37 +39,25 @@
|
||||
<h2 class="section-title">全部视频</h2>
|
||||
<!-- 筛选标签 -->
|
||||
<div class="filter-tabs">
|
||||
<button
|
||||
v-for="tab in videoTabs"
|
||||
:key="tab.id"
|
||||
:class="['filter-tab', { active: activeVideoTab === tab.id }]"
|
||||
@click="activeVideoTab = tab.id"
|
||||
>
|
||||
<button v-for="tab in videoTabs" :key="tab.id"
|
||||
:class="['filter-tab', { active: activeVideoTab === tab.id }]" @click="activeVideoTab = tab.id">
|
||||
{{ tab.name }}
|
||||
</button>
|
||||
</div>
|
||||
<!-- 视频网格 -->
|
||||
<div class="video-grid">
|
||||
<div
|
||||
v-for="video in allVideos"
|
||||
:key="video.id"
|
||||
class="video-card"
|
||||
>
|
||||
<div v-for="video in allVideos" :key="video.id" class="video-card" @click="handleVideoClick(video)">
|
||||
<div class="card-image">
|
||||
<img
|
||||
:src="video.image"
|
||||
:alt="video.title"
|
||||
class="video-thumbnail"
|
||||
/>
|
||||
<img :src="video.image" :alt="video.title" class="video-thumbnail" />
|
||||
<div class="duration-badge">
|
||||
<img src="/images/Featured_resources/duration.png" alt="时长" class="duration-icon">
|
||||
42:52
|
||||
</div>
|
||||
<!-- <div class="play-button">
|
||||
<div class="play-button">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M8 5V19L19 12L8 5Z" fill="white"/>
|
||||
<path d="M8 5V19L19 12L8 5Z" fill="white" />
|
||||
</svg>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3 class="card-title">{{ video.title }}</h3>
|
||||
@ -98,28 +74,16 @@
|
||||
<h2 class="section-title">全部图片</h2>
|
||||
<!-- 筛选标签 -->
|
||||
<div class="filter-tabs">
|
||||
<button
|
||||
v-for="tab in imageTabs"
|
||||
:key="tab.id"
|
||||
:class="['filter-tab', { active: activeImageTab === tab.id }]"
|
||||
@click="activeImageTab = tab.id"
|
||||
>
|
||||
<button v-for="tab in imageTabs" :key="tab.id"
|
||||
:class="['filter-tab', { active: activeImageTab === tab.id }]" @click="activeImageTab = tab.id">
|
||||
{{ tab.name }}
|
||||
</button>
|
||||
</div>
|
||||
<!-- 图片网格 -->
|
||||
<div class="image-grid">
|
||||
<div
|
||||
v-for="image in allImages"
|
||||
:key="image.id"
|
||||
class="image-card"
|
||||
>
|
||||
<div v-for="image in allImages" :key="image.id" class="image-card">
|
||||
<div class="card-image">
|
||||
<img
|
||||
:src="image.image"
|
||||
:alt="image.title"
|
||||
class="image-thumbnail"
|
||||
/>
|
||||
<img :src="image.image" :alt="image.title" class="image-thumbnail" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3 class="card-title">{{ image.title }}</h3>
|
||||
@ -132,28 +96,65 @@
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 视频播放弹窗 -->
|
||||
<div v-if="showVideoModal" class="video-modal-overlay" @click="closeVideoModal">
|
||||
<div class="video-modal" @click.stop>
|
||||
<div class="video-modal-header">
|
||||
<h3 class="video-modal-title">{{ currentVideo?.title || '视频播放' }}</h3>
|
||||
<button class="close-btn" @click="closeVideoModal">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M18 6L6 18M6 6l12 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="video-modal-body">
|
||||
<DPlayerVideo ref="videoPlayerRef" :video-url="currentVideoUrl" :placeholder-image="currentVideo?.image"
|
||||
:placeholder-text="'点击播放视频'" :title="currentVideo?.title || '视频播放'" @play="handleVideoPlay"
|
||||
@pause="handleVideoPause" @ended="handleVideoEnded" @error="handleVideoError" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, nextTick } from 'vue'
|
||||
import DPlayerVideo from '@/components/course/DPlayerVideo.vue'
|
||||
|
||||
// 视频播放弹窗相关状态
|
||||
const showVideoModal = ref(false)
|
||||
const currentVideo = ref<any>(null)
|
||||
const currentVideoUrl = ref('')
|
||||
const videoPlayerRef = ref<InstanceType<typeof DPlayerVideo>>()
|
||||
|
||||
// 视频源配置
|
||||
const VIDEO_CONFIG = {
|
||||
// 本地视频(当前使用)
|
||||
LOCAL: '/video/first.mp4',
|
||||
// HLS流(服务器准备好后使用)
|
||||
HLS: 'http://110.42.96.65:55513/learn/index.m3u8'
|
||||
}
|
||||
|
||||
// 精选视频数据
|
||||
const featuredVideos = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: '西安工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/精选视频1.png'
|
||||
image: '/images/Featured_resources/精选视频1.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL // 添加视频URL
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '华南工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/精选视频2.png'
|
||||
image: '/images/Featured_resources/精选视频2.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '西安工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/精品视频3.png'
|
||||
image: '/images/Featured_resources/精品视频3.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
}
|
||||
])
|
||||
|
||||
@ -173,42 +174,50 @@ const allVideos = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: '北京工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/全部视频1.png'
|
||||
image: '/images/Featured_resources/全部视频1.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '北京工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/全部视频2.png'
|
||||
image: '/images/Featured_resources/全部视频2.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '西安工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/全部视频3.png'
|
||||
image: '/images/Featured_resources/全部视频3.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '北京工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/全部视频4.png'
|
||||
image: '/images/Featured_resources/全部视频4.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '中国工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/全部视频5.png'
|
||||
image: '/images/Featured_resources/全部视频5.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: '西安工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/全部视频6.png'
|
||||
image: '/images/Featured_resources/全部视频6.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: '西安工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/全部视频7.png'
|
||||
image: '/images/Featured_resources/全部视频7.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: '内蒙古工业大学内部资源之一',
|
||||
image: '/images/Featured_resources/全部视频8.png'
|
||||
image: '/images/Featured_resources/全部视频8.png',
|
||||
videoUrl: VIDEO_CONFIG.LOCAL
|
||||
}
|
||||
])
|
||||
|
||||
@ -266,6 +275,52 @@ const allImages = ref([
|
||||
image: '/images/Featured_resources/全部图片8.png'
|
||||
}
|
||||
])
|
||||
|
||||
// 视频播放相关方法
|
||||
const handleVideoClick = async (video: any) => {
|
||||
console.log('点击视频:', video.title)
|
||||
currentVideo.value = video
|
||||
currentVideoUrl.value = video.videoUrl || VIDEO_CONFIG.LOCAL
|
||||
showVideoModal.value = true
|
||||
|
||||
// 等待弹窗显示后初始化播放器
|
||||
await nextTick()
|
||||
if (videoPlayerRef.value) {
|
||||
await videoPlayerRef.value.initializePlayer(currentVideoUrl.value)
|
||||
}
|
||||
}
|
||||
|
||||
const closeVideoModal = () => {
|
||||
showVideoModal.value = false
|
||||
currentVideo.value = null
|
||||
currentVideoUrl.value = ''
|
||||
|
||||
// 销毁播放器实例
|
||||
if (videoPlayerRef.value) {
|
||||
videoPlayerRef.value.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
// DPlayer 事件处理方法
|
||||
const handleVideoPlay = () => {
|
||||
console.log('视频开始播放')
|
||||
}
|
||||
|
||||
const handleVideoPause = () => {
|
||||
console.log('视频暂停')
|
||||
}
|
||||
|
||||
const handleVideoEnded = () => {
|
||||
console.log('视频播放结束')
|
||||
}
|
||||
|
||||
const handleVideoError = (error: any) => {
|
||||
console.error('视频播放错误:', error)
|
||||
// 可以在这里处理错误,比如自动切换到本地视频
|
||||
if (currentVideoUrl.value !== VIDEO_CONFIG.LOCAL) {
|
||||
currentVideoUrl.value = VIDEO_CONFIG.LOCAL
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -663,4 +718,150 @@ const allImages = ref([
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 视频播放弹窗样式 */
|
||||
.video-modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.video-modal {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
width: 1000px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
animation: modalFadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes modalFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.video-modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20px 24px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.video-modal-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
background: #e5e7eb;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.video-modal-body {
|
||||
padding: 0;
|
||||
background: #000;
|
||||
position: relative;
|
||||
height: 60vh;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
/* 播放按钮显示样式 */
|
||||
.play-button {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.featured-card:hover .play-button,
|
||||
.video-card:hover .play-button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.featured-card .play-button {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.video-card .play-button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
/* 响应式设计 - 弹窗 */
|
||||
@media (max-width: 768px) {
|
||||
.video-modal {
|
||||
width: 95vw;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.video-modal-header {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.video-modal-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.video-modal-body {
|
||||
height: 50vh;
|
||||
min-height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.video-modal-overlay {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.video-modal {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.video-modal-header {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.video-modal-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.video-modal-body {
|
||||
height: 40vh;
|
||||
min-height: 250px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -298,7 +298,13 @@ const loadCourses = async () => {
|
||||
name: '汪波',
|
||||
avatar: '/images/Teachers/师资力量1.png',
|
||||
title: '云南师范大学教授',
|
||||
bio: '课程设计专家'
|
||||
bio: '课程设计专家',
|
||||
rating: 4.7,
|
||||
studentsCount: 567,
|
||||
coursesCount: 6,
|
||||
experience: '15年',
|
||||
education: ['云南师范大学', '课程设计博士'],
|
||||
certifications: ['高级课程设计师', '教育专家']
|
||||
},
|
||||
status: 'published',
|
||||
createdAt: '2024-03-10T09:15:00Z',
|
||||
@ -328,7 +334,13 @@ const loadCourses = async () => {
|
||||
name: '汪波',
|
||||
avatar: '/images/Teachers/师资力量1.png',
|
||||
title: '云南师范大学教授',
|
||||
bio: '教育研究专家'
|
||||
bio: '教育研究专家',
|
||||
rating: 4.5,
|
||||
studentsCount: 432,
|
||||
coursesCount: 6,
|
||||
experience: '15年',
|
||||
education: ['云南师范大学', '教育研究博士'],
|
||||
certifications: ['高级教育研究专家', '学术顾问']
|
||||
},
|
||||
status: 'published',
|
||||
createdAt: '2024-01-25T16:45:00Z',
|
||||
@ -358,7 +370,13 @@ const loadCourses = async () => {
|
||||
name: '汪波',
|
||||
avatar: '/images/Teachers/师资力量1.png',
|
||||
title: '云南师范大学教授',
|
||||
bio: '心理咨询专家'
|
||||
bio: '心理咨询专家',
|
||||
rating: 4.9,
|
||||
studentsCount: 678,
|
||||
coursesCount: 6,
|
||||
experience: '15年',
|
||||
education: ['云南师范大学', '心理学博士'],
|
||||
certifications: ['高级心理咨询师', '心理治疗师']
|
||||
},
|
||||
status: 'published',
|
||||
createdAt: '2024-02-05T11:20:00Z',
|
||||
@ -388,7 +406,13 @@ const loadCourses = async () => {
|
||||
name: '汪波',
|
||||
avatar: '/images/Teachers/师资力量1.png',
|
||||
title: '云南师范大学教授',
|
||||
bio: '教育评估专家'
|
||||
bio: '教育评估专家',
|
||||
rating: 4.4,
|
||||
studentsCount: 345,
|
||||
coursesCount: 6,
|
||||
experience: '15年',
|
||||
education: ['云南师范大学', '教育评估博士'],
|
||||
certifications: ['高级教育评估师', '测量技术专家']
|
||||
},
|
||||
status: 'published',
|
||||
createdAt: '2024-03-15T13:10:00Z',
|
||||
|
Loading…
x
Reference in New Issue
Block a user