This commit is contained in:
Wxp 2025-08-14 17:32:28 +08:00
parent 90ffb5a444
commit a428d2b36b
32 changed files with 355 additions and 247 deletions

BIN
public/banners/banner8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1011 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 812 B

After

Width:  |  Height:  |  Size: 908 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 944 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 359 KiB

View File

@ -81,56 +81,9 @@ body {
width: 100%; width: 100%;
max-width: 1420px; max-width: 1420px;
margin: 0 auto; margin: 0 auto;
padding: 0 20px; /* padding: 0 20px; */
} }
/* 响应式断点 */
@media (max-width: 1200px) {
.container {
max-width: 1140px;
padding: 0 16px;
}
}
@media (max-width: 992px) {
.container {
max-width: 960px;
padding: 0 16px;
}
}
@media (max-width: 768px) {
.container {
max-width: 720px;
padding: 0 12px;
}
}
@media (max-width: 576px) {
.container {
max-width: 540px;
padding: 0 12px;
}
}
@media (max-width: 480px) {
.container {
padding: 0 8px;
}
}
/* 缩放兼容性 - 确保在所有缩放级别下都能正常显示 */
@media screen and (min-resolution: 2dppx) {
body {
zoom: 1;
}
}
@media screen and (max-resolution: 1dppx) {
body {
zoom: 1;
}
}
/* 工具类 */ /* 工具类 */
.text-center { .text-center {
@ -157,24 +110,4 @@ body {
.d-block { .d-block {
display: block !important; display: block !important;
} }
@media (max-width: 768px) {
.d-md-none {
display: none !important;
}
.d-md-block {
display: block !important;
}
}
@media (max-width: 576px) {
.d-sm-none {
display: none !important;
}
.d-sm-block {
display: block !important;
}
}
</style> </style>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,6 +7,12 @@ import router from './router'
import i18n from './i18n' import i18n from './i18n'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import '@/assets/fonts/优设标题黑.ttf'
import '@/assets/fonts/AlimamaShuHeiTi-Bold.ttf'
import '@/assets/fonts/文道潮黑.ttf'
import '@/assets/fonts/庞门正道标题体3.0.ttf'
import '@/assets/fonts/DouyinSansBold.otf'
// Naive UI // Naive UI
import { import {
create, create,

View File

@ -295,21 +295,17 @@ onMounted(() => {
.activity-card { .activity-card {
background: white; background: white;
border-radius: 8px; border-radius: 10px;
overflow: hidden; overflow: hidden;
transition: all 0.3s ease; transition: all 0.3s ease;
cursor: pointer; cursor: pointer;
} box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
.activity-card:hover {
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
transform: translateY(-4px);
} }
/* 卡片头部 */ /* 卡片头部 */
.card-header { .card-header {
position: relative; position: relative;
height: 180px; height: 298px;
overflow: hidden; overflow: hidden;
border-radius: 12px 12px 0 0; border-radius: 12px 12px 0 0;
} }

View File

@ -110,7 +110,7 @@
分类<span class="category-link">{{ course.category?.name || '信息技术' }}</span> 分类<span class="category-link">{{ course.category?.name || '信息技术' }}</span>
</span> </span>
<div class="meta-right"> <div class="meta-right">
<button class="btn-notes"> <button class="btn-notes" @click="handleNotesClick">
<i class="icon-note"></i> <i class="icon-note"></i>
记笔记 记笔记
</button> </button>
@ -134,7 +134,7 @@
<div class="course-description"> <div class="course-description">
<p>{{ course.description || <p>{{ course.description ||
'本课程深度聚焦问题让每一位教师了解并学习使用DeepSeek结合办公自动化职业岗位标准以实际工作任务为引导强调课程内容的易用性和岗位要求的匹配性。课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书技能大赛紧密结合课程设置紧密对应实际全面共享可为职业工作人员、在校学生、创行教师提供服务与学习支持。' '本课程深度聚焦问题让每一位教师了解并学习使用DeepSeek结合办公自动化职业岗位标准以实际工作任务为引导强调课程内容的易用性和岗位要求的匹配性。课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书技能大赛紧密结合课程设置紧密对应实际全面共享可为职业工作人员、在校学生、创行教师提供服务与学习支持。'
}}</p> }}</p>
</div> </div>
<!-- 讲师信息 --> <!-- 讲师信息 -->
@ -281,7 +281,7 @@
</div> </div>
<div class="lesson-info"> <div class="lesson-info">
<span class="lesson-title" :class="{ 'disabled': !isUserEnrolled }">{{ section.name <span class="lesson-title" :class="{ 'disabled': !isUserEnrolled }">{{ section.name
}}</span> }}</span>
</div> </div>
<div class="lesson-meta"> <div class="lesson-meta">
<span v-if="isVideoLesson(section)" class="lesson-duration" <span v-if="isVideoLesson(section)" class="lesson-duration"
@ -487,6 +487,21 @@ const enrollmentLoading = ref(false) // 报名加载状态
// //
const RegistrationStatus = ref(false) const RegistrationStatus = ref(false)
//
const handleNotesClick = () => {
if (isUserEnrolled.value) {
//
console.log('开始记笔记')
//
} else if (userStore.isLoggedIn) {
//
enrollConfirmVisible.value = true
} else {
//
showLoginModal()
}
}
// //
const isUserEnrolled = computed(() => { const isUserEnrolled = computed(() => {
// AND // AND
@ -523,41 +538,64 @@ const generateMockSections = (): CourseSection[] => {
{ id: 5, lessonId: courseId.value, name: '第一课 程序设计入门', outline: 'https://example.com/video4.m3u8', parentId: 0, sort: 5, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '00:52:22' }, { id: 5, lessonId: courseId.value, name: '第一课 程序设计入门', outline: 'https://example.com/video4.m3u8', parentId: 0, sort: 5, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '00:52:22' },
{ id: 6, lessonId: courseId.value, name: '操作PPT', outline: 'https://example.com/ppt2.ppt', parentId: 0, sort: 6, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, { id: 6, lessonId: courseId.value, name: '操作PPT', outline: 'https://example.com/ppt2.ppt', parentId: 0, sort: 6, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 7, lessonId: courseId.value, name: '第二课 循环结构', outline: 'https://example.com/video5.m3u8', parentId: 0, sort: 7, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '01:03:56' }, { id: 7, lessonId: courseId.value, name: '第二课 循环结构', outline: 'https://example.com/video5.m3u8', parentId: 0, sort: 7, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: true, duration: '01:03:56' },
{ id: 8, lessonId: courseId.value, name: '函数&循环', outline: '', parentId: 0, sort: 8, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, { id: 8, lessonId: courseId.value, name: '函数&循环', outline: 'https://example.com/video5.m3u8', parentId: 0, sort: 8, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 9, lessonId: courseId.value, name: '练习题目', outline: '', parentId: 0, sort: 9, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, { id: 9, lessonId: courseId.value, name: '第三课 条件结构', outline: 'https://example.com/video6.m3u8', parentId: 0, sort: 9, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:45:30' },
// - (6) // - (6)
{ id: 10, lessonId: courseId.value, name: '条件语句详解', outline: 'https://example.com/video6.m3u8', parentId: 0, sort: 10, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:45:30' }, { id: 10, lessonId: courseId.value, name: '项目一:计算器开发', outline: 'https://example.com/video7.m3u8', parentId: 0, sort: 10, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:20:15' },
{ id: 11, lessonId: courseId.value, name: '循环语句应用', outline: 'https://example.com/video7.m3u8', parentId: 0, sort: 11, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:38:15' }, { id: 11, lessonId: courseId.value, name: '项目源码下载', outline: 'https://example.com/source1.zip', parentId: 0, sort: 11, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 12, lessonId: courseId.value, name: '控制结构参考资料', outline: 'https://example.com/ppt3.ppt', parentId: 0, sort: 12, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, { id: 12, lessonId: courseId.value, name: '项目二:数据管理系统', outline: 'https://example.com/video8.m3u8', parentId: 0, sort: 12, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:45:20' },
{ id: 13, lessonId: courseId.value, name: '条件判断练习', outline: '', parentId: 0, sort: 13, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, { id: 13, lessonId: courseId.value, name: '作业:完成个人项目', outline: '', parentId: 0, sort: 13, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 14, lessonId: courseId.value, name: '循环结构作业', outline: '', parentId: 0, sort: 14, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, { id: 14, lessonId: courseId.value, name: '项目三Web应用开发', outline: 'https://example.com/video9.m3u8', parentId: 0, sort: 14, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '02:10:45' },
{ id: 15, lessonId: courseId.value, name: '控制结构测试', outline: '', parentId: 0, sort: 15, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, { id: 15, lessonId: courseId.value, name: '期末考试', outline: '', parentId: 0, sort: 15, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
// - (5) // - (4)
{ id: 16, lessonId: courseId.value, name: 'AI发展历程', outline: 'https://example.com/video8.m3u8', parentId: 0, sort: 16, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:12:45' }, { id: 16, lessonId: courseId.value, name: '高级特性介绍', outline: 'https://example.com/video10.m3u8', parentId: 0, sort: 16, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:55:30' },
{ id: 17, lessonId: courseId.value, name: '大语言模型原理', outline: 'https://example.com/video9.m3u8', parentId: 0, sort: 17, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:58:20' }, { id: 17, lessonId: courseId.value, name: '性能优化技巧', outline: 'https://example.com/video11.m3u8', parentId: 0, sort: 17, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:15:20' },
{ id: 18, lessonId: courseId.value, name: 'AI模型对比资料', outline: 'https://example.com/ppt4.ppt', parentId: 0, sort: 18, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, { id: 18, lessonId: courseId.value, name: '部署与发布', outline: 'https://example.com/video12.m3u8', parentId: 0, sort: 18, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:40:15' },
{ id: 19, lessonId: courseId.value, name: 'AI应用场景分析', outline: '', parentId: 0, sort: 19, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }, { id: 19, lessonId: courseId.value, name: '课程总结', outline: 'https://example.com/video13.m3u8', parentId: 0, sort: 19, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:30:10' },
{ id: 20, lessonId: courseId.value, name: '大语言模型考试', outline: '', parentId: 0, sort: 20, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
// - DeepSeek (6) // - (3)
{ id: 21, lessonId: courseId.value, name: 'DeepSeek平台介绍', outline: 'https://example.com/video10.m3u8', parentId: 0, sort: 21, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:42:10' }, { id: 20, lessonId: courseId.value, name: '行业发展趋势', outline: 'https://example.com/video14.m3u8', parentId: 0, sort: 20, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:35:45' },
{ id: 22, lessonId: courseId.value, name: 'API接口使用', outline: 'https://example.com/video11.m3u8', parentId: 0, sort: 22, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:55:35' }, { id: 21, lessonId: courseId.value, name: '学习资源推荐', outline: 'https://example.com/resources.pdf', parentId: 0, sort: 21, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 23, lessonId: courseId.value, name: '实战项目演示', outline: 'https://example.com/video12.m3u8', parentId: 0, sort: 23, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:25:18' }, { id: 22, lessonId: courseId.value, name: '结业证书申请', outline: '', parentId: 0, sort: 22, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 24, lessonId: courseId.value, name: 'DeepSeek开发文档', outline: 'https://example.com/ppt5.ppt', parentId: 0, sort: 24, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 25, lessonId: courseId.value, name: '项目实战作业', outline: '', parentId: 0, sort: 25, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 26, lessonId: courseId.value, name: 'DeepSeek应用考试', outline: '', parentId: 0, sort: 26, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
// - (5) // - (2)
{ id: 27, lessonId: courseId.value, name: '项目需求分析', outline: 'https://example.com/video13.m3u8', parentId: 0, sort: 27, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:35:45' }, { id: 23, lessonId: courseId.value, name: '常见问题解答', outline: 'https://example.com/video15.m3u8', parentId: 0, sort: 23, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:25:30' },
{ id: 28, lessonId: courseId.value, name: '系统架构设计', outline: 'https://example.com/video14.m3u8', parentId: 0, sort: 28, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '00:48:22' }, { id: 24, lessonId: courseId.value, name: '在线答疑直播', outline: 'https://example.com/live1.m3u8', parentId: 0, sort: 24, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: '01:30:00' }
{ id: 29, lessonId: courseId.value, name: '项目开发指南', outline: 'https://example.com/ppt6.ppt', parentId: 0, sort: 29, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 30, lessonId: courseId.value, name: '综合项目作业', outline: '', parentId: 0, sort: 30, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined },
{ id: 31, lessonId: courseId.value, name: '期末综合考试', outline: '', parentId: 0, sort: 31, level: 1, revision: 1, createdAt: Date.now(), updatedAt: Date.now(), deletedAt: null, completed: false, duration: undefined }
] ]
} }
//
const groupSectionsByChapter = (sections: CourseSection[]) => {
const chapterTitles = [
'课前准备',
'程序设计基础知识',
'实战项目',
'高级应用',
'拓展学习',
'答疑与交流'
]
const groups: ChapterGroup[] = []
let sectionsPerChapter = [4, 5, 6, 4, 3, 2] //
let sectionIndex = 0
for (let i = 0; i < chapterTitles.length; i++) {
const chapterSections = sections.slice(sectionIndex, sectionIndex + sectionsPerChapter[i])
if (chapterSections.length > 0) {
groups.push({
title: `${i+1}${chapterTitles[i]}`,
sections: chapterSections,
expanded: i === 0 //
})
}
sectionIndex += sectionsPerChapter[i]
}
return groups
}
// //
const generateChapterGroups = () => { const generateChapterGroups = () => {
// //
@ -569,47 +607,12 @@ const generateChapterGroups = () => {
console.log('开始生成章节分组,原始数据:', courseSections.value) console.log('开始生成章节分组,原始数据:', courseSections.value)
console.log('章节数据数量:', courseSections.value.length) console.log('章节数据数量:', courseSections.value.length)
// // 使
const groups: ChapterGroup[] = [ groupedSections.value = groupSectionsByChapter(courseSections.value)
{ console.log('生成的章节分组:', groupedSections.value)
title: '第一章 课前准备',
sections: courseSections.value.slice(0, 4), // 4
expanded: true
},
{
title: '第二章 程序设计基础知识',
sections: courseSections.value.slice(4, 9), // 5
expanded: true
},
{
title: '第三章 程序的控制结构',
sections: courseSections.value.slice(9, 15), // 6
expanded: false
},
{
title: '第四章 大语言模型介绍',
sections: courseSections.value.slice(15, 20), // 5
expanded: false
},
{
title: '第五章 DeepSeek实际应用',
sections: courseSections.value.slice(20, 26), // 6
expanded: false
},
{
title: '第六章 综合项目实战',
sections: courseSections.value.slice(26, 31), // 5
expanded: false
}
]
console.log('生成的章节分组:', groups)
console.log('第一章节数:', groups[0].sections.length)
console.log('第二章节数:', groups[1].sections.length)
groupedSections.value = groups
} }
// // 使groupSectionsByChapter
// const getChapterTitle = (chapterIndex: number): string => { // const getChapterTitle = (chapterIndex: number): string => {
// const titles = [ // const titles = [
// '', // '',
@ -775,56 +778,50 @@ const loadCourseSections = async () => {
sectionsLoading.value = true sectionsLoading.value = true
sectionsError.value = '' sectionsError.value = ''
console.log('开始加载课程章节课程ID:', courseId.value) console.log('调用API获取课程章节...')
console.log('调用API: CourseApi.getCourseSections')
const response = await CourseApi.getCourseSections(courseId.value) const response = await CourseApi.getCourseSections(courseId.value)
console.log('章节API响应:', response) console.log('章节API响应:', response)
console.log('响应状态码:', response.code)
console.log('响应数据:', response.data)
if (response.code === 0 || response.code === 200) { if (response.code === 0 || response.code === 200) {
courseSections.value = response.data.list || [] if (response.data && Array.isArray(response.data)) {
console.log('章节数据设置成功,数量:', courseSections.value.length) courseSections.value = response.data
console.log('章节详细数据:', courseSections.value) groupedSections.value = groupSectionsByChapter(response.data)
console.log('章节数据设置成功:', courseSections.value)
// API使 console.log('分组数据:', groupedSections.value)
if (courseSections.value.length === 0) { } else {
console.log('API返回数据为空,使用模拟数据') console.log('API返回的章节数据为空,使用模拟数据')
courseSections.value = generateMockSections() loadMockData()
} }
//
generateChapterGroups()
} else { } else {
console.log('API调用失败使用模拟数据') console.log('API返回错误使用模拟数据')
courseSections.value = generateMockSections() loadMockData()
generateChapterGroups()
sectionsError.value = '' //
} }
} catch (err) { } catch (err) {
console.error('加载课程章节失败:', err) console.error('加载课程章节失败:', err)
console.log('网络错误,使用模拟数据') console.log('API调用失败使用模拟数据')
courseSections.value = generateMockSections() loadMockData()
generateChapterGroups()
sectionsError.value = '' //
} finally { } finally {
sectionsLoading.value = false sectionsLoading.value = false
} }
} }
// //
// const loadMockData = () => { const loadMockData = () => {
// console.log('') console.log('加载模拟章节数据')
// courseSections.value = generateMockSections() const mockSections = generateMockSections()
// generateChapterGroups() courseSections.value = mockSections
// sectionsError.value = '' groupedSections.value = groupSectionsByChapter(mockSections)
// console.log(':', courseSections.value.length)
// console.log(':', groupedSections.value.length) //
// } const completed = mockSections.filter(section => section.completed).length
completedLessons.value = completed
progress.value = Math.round((completed / mockSections.length) * 100)
}
// / // /
const toggleChapter = (chapterIndex: number) => { const toggleChapter = (chapterIndex: number) => {
console.log('点击切换章节,章节索引:', chapterIndex)
if (groupedSections.value[chapterIndex]) { if (groupedSections.value[chapterIndex]) {
groupedSections.value[chapterIndex].expanded = !groupedSections.value[chapterIndex].expanded groupedSections.value[chapterIndex].expanded = !groupedSections.value[chapterIndex].expanded
} }

View File

@ -717,6 +717,7 @@ const loadMockData = () => {
// / // /
const toggleChapter = (chapterIndex: number) => { const toggleChapter = (chapterIndex: number) => {
console.log('切换章节展开/收起:', chapterIndex)
groupedSections.value[chapterIndex].expanded = !groupedSections.value[chapterIndex].expanded groupedSections.value[chapterIndex].expanded = !groupedSections.value[chapterIndex].expanded
} }

View File

@ -57,21 +57,30 @@
@click="selectMajor('个人成长')">个人成长</span> @click="selectMajor('个人成长')">个人成长</span>
<span class="filter-tag" :class="{ active: selectedMajor === '教学案例' }" <span class="filter-tag" :class="{ active: selectedMajor === '教学案例' }"
@click="selectMajor('教学案例')">教学案例</span> @click="selectMajor('教学案例')">教学案例</span>
<span class="filter-tag" :class="{ active: selectedMajor === '班级管理' }" <span class="filter-tag" :class="{ active: selectedMajor === '教育技术' }"
@click="selectMajor('班级管理')">班级管理</span> @click="selectMajor('教育技术')">教育技术</span>
<span class="filter-tag" :class="{ active: selectedMajor === '通识技能' }" <span class="filter-tag" :class="{ active: selectedMajor === '心理健康' }"
@click="selectMajor('通识技能')">通识技能</span> @click="selectMajor('心理健康')">心理健康</span>
<span class="filter-tag" :class="{ active: selectedMajor === '信息素养' }" <span class="filter-tag" :class="{ active: selectedMajor === '家校沟通' }"
@click="selectMajor('信息素养')">信息素养</span> @click="selectMajor('家校沟通')">家校沟通</span>
<span class="filter-tag" :class="{ active: selectedMajor === '师风师德' }" <span class="filter-tag" :class="{ active: selectedMajor === '课程设计' }"
@click="selectMajor('师风师德')">师风师德</span> @click="selectMajor('课程设计')">课程设计</span>
<span class="filter-tag" :class="{ active: selectedMajor === '专题教育' }" <span class="filter-tag" :class="{ active: selectedMajor === '教育政策' }"
@click="selectMajor('专题教育')">专题教育</span> @click="selectMajor('教育政策')">教育政策</span>
<span class="filter-tag" :class="{ active: selectedMajor === '综合实践' }" <span class="filter-tag" :class="{ active: selectedMajor === '教学评估' }"
@click="selectMajor('综合实践')">综合实践</span> @click="selectMajor('教学评估')">教学评估</span>
<span class="filter-tag" :class="{ active: selectedMajor === '个人成长' }" <span class="filter-tag" :class="{ active: selectedMajor === '创新教育' }"
@click="selectMajor('个人成长')">个人成长</span> @click="selectMajor('创新教育')">创新教育</span>
<span class="filter-tag" :class="{ active: selectedMajor === 'STEAM教育' }"
@click="selectMajor('STEAM教育')">STEAM教育</span>
<span class="filter-tag" :class="{ active: selectedMajor === '教育心理学' }"
@click="selectMajor('教育心理学')">教育心理学</span>
<span class="filter-tag" :class="{ active: selectedMajor === '差异化教学' }"
@click="selectMajor('差异化教学')">差异化教学</span>
<span class="filter-tag" :class="{ active: selectedMajor === '教育领导力' }"
@click="selectMajor('教育领导力')">教育领导力</span>
<span class="filter-tag" :class="{ active: selectedMajor === '在线教学' }"
@click="selectMajor('在线教学')">在线教学</span>
</div> </div>
</div> </div>
@ -109,9 +118,9 @@
<!-- 排序标签 --> <!-- 排序标签 -->
<div class="sort-tabs"> <div class="sort-tabs">
<span class="sort-tab">最新</span> <span class="sort-tab" :class="{ active: selectedSort === '最新' }" @click="selectSort('最新')">最新</span>
<span class="sort-tab">最热</span> <span class="sort-tab" :class="{ active: selectedSort === '最热' }" @click="selectSort('最热')">最热</span>
<span class="sort-tab active">推荐</span> <span class="sort-tab" :class="{ active: selectedSort === '推荐' }" @click="selectSort('推荐')">推荐</span>
</div> </div>
<!-- 加载状态 --> <!-- 加载状态 -->
@ -215,6 +224,9 @@ const itemsPerPage = 20
const totalItems = computed(() => total.value) const totalItems = computed(() => total.value)
const totalPages = computed(() => Math.ceil(totalItems.value / itemsPerPage)) const totalPages = computed(() => Math.ceil(totalItems.value / itemsPerPage))
//
const selectedSort = ref('推荐')
// 广 // 广
const showAdvertisement = ref(true) const showAdvertisement = ref(true)
@ -264,6 +276,13 @@ const visiblePages = computed(() => {
return pages return pages
}) })
//
const selectSort = (sort: string) => {
selectedSort.value = sort
currentPage.value = 1 //
loadCourses()
}
// 使 // 使
const loadCourses = async () => { const loadCourses = async () => {
try { try {
@ -289,6 +308,21 @@ const loadCourses = async () => {
}) })
} }
//
switch (selectedSort.value) {
case '最新':
filteredCourses.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
break
case '最热':
filteredCourses.sort((a, b) => b.studentCount - a.studentCount)
break
case '推荐':
default:
//
filteredCourses.sort((a, b) => (b.rating * 0.7 + b.studentCount * 0.3) - (a.rating * 0.7 + a.studentCount * 0.3))
break
}
// //
if (selectedMajor.value !== '全部') { if (selectedMajor.value !== '全部') {
filteredCourses = filteredCourses.filter(course => filteredCourses = filteredCourses.filter(course =>

View File

@ -137,7 +137,6 @@ const toggleCourseInfo = (teacherId: number) => {
// //
const filterTabs = ref([ const filterTabs = ref([
{ id: 'field', name: '课长领域' },
{ id: 'all', name: '全部' }, { id: 'all', name: '全部' },
{ id: 'chinese-promotion', name: '汉语国际推广' }, { id: 'chinese-promotion', name: '汉语国际推广' },
{ id: 'chinese-language', name: '汉语言' }, { id: 'chinese-language', name: '汉语言' },
@ -403,17 +402,18 @@ const goToPage = (page: number) => {
/* 筛选标签栏 */ /* 筛选标签栏 */
.filter-tabs { .filter-tabs {
display: flex; display: flex;
align-items: center;
gap: 0; gap: 0;
margin-bottom: 40px; margin-bottom: 40px;
padding-bottom: 30px;
background: transparent; background: transparent;
border-bottom: 1px solid #e5e5e5; border-bottom: 1px solid #e5e5e5;
padding: 0;
box-shadow: none; box-shadow: none;
} }
.filter-tab { .filter-tab {
margin-right: 25px; margin-right: 25px;
margin-bottom: 30px; /* margin-bottom: 30px; */
padding: 7px 10px; padding: 7px 10px;
border: none; border: none;
background: transparent; background: transparent;
@ -428,7 +428,7 @@ const goToPage = (page: number) => {
} }
.filter-tabs div { .filter-tabs div {
padding: 7px 10px; padding: 7px 10px 7px 0;
margin-right: 10px; margin-right: 10px;
} }

View File

@ -14,24 +14,24 @@
<div class="divider_2"></div> <div class="divider_2"></div>
</div> </div>
<div class="box_3 active"> <div class="box_3" :class="{ active: activeTab === 0 }" @click="handleTabChange(0)">
<div class="image-text_2 justify-between"> <div class="image-text_2 justify-between">
<img class="thumbnail_8" referrerpolicy="no-referrer" <img class="thumbnail_8" referrerpolicy="no-referrer"
src="/images/Help-center/SketchPngd9dfa413c705d7d7838aa04a1af69011abc78cfe7a9d0d31b5bfca3ed5a4c990.png" /> :src="activeTab === 0 ? '/images/Help-center/SketchPngd9dfa413c705d7d7838aa04a1af69011abc78cfe7a9d0d31b5bfca3ed5a4c990.png' : '/images/Help-center/disposition.png'" />
<span class="text-group_2">账号问题</span> <span class="text-group_2">账号问题</span>
</div> </div>
</div> </div>
<div class="box_3"> <div class="box_3" :class="{ active: activeTab === 1 }" @click="handleTabChange(1)">
<div class="image-text_2 justify-between"> <div class="image-text_2 justify-between">
<img class="thumbnail_8" referrerpolicy="no-referrer" <img class="thumbnail_8" referrerpolicy="no-referrer"
src="/images/Help-center/SketchPng8c77f6b5914ca8b5148cb9e177fb5d7ad7b15bbad1eb5506086428c4b5243169.png" /> :src="activeTab === 1 ? '/images/Help-center/Gc_24_line-Authentication(1).png@2x.png' : '/images/Help-center/SketchPng8c77f6b5914ca8b5148cb9e177fb5d7ad7b15bbad1eb5506086428c4b5243169.png'" />
<span class="text-group_2">认证证书</span> <span class="text-group_2">认证证书</span>
</div> </div>
</div> </div>
<div class="box_3"> <div class="box_3" :class="{ active: activeTab === 2 }" @click="handleTabChange(2)">
<div class="image-text_2 justify-between"> <div class="image-text_2 justify-between">
<img class="thumbnail_8" referrerpolicy="no-referrer" <img class="thumbnail_8" referrerpolicy="no-referrer"
src="/images/Help-center/SketchPng9eac41c079f953a4c9dd6e8ea78ccfedb8a08687a399dfa96c25967f42408792.png" /> :src="activeTab === 2 ? '/images/Help-center/course-active.png' : '/images/Help-center/SketchPng9eac41c079f953a4c9dd6e8ea78ccfedb8a08687a399dfa96c25967f42408792.png'" />
<span class="text-group_2">课程问题</span> <span class="text-group_2">课程问题</span>
</div> </div>
</div> </div>
@ -39,17 +39,44 @@
<div class="group_2 justify-between"> <div class="group_2 justify-between">
<div class="block_1 flex-col"> <div class="block_1 flex-col">
<span class="text_4">帐号问题</span> <span class="text_4" v-if="activeTab === 0">帐号问题</span>
<span class="text_4" v-else-if="activeTab === 1">认证证书</span>
<span class="text_4" v-else>课程问题</span>
<!-- 分割线 --> <!-- 分割线 -->
<div class="divider_1"></div> <div class="divider_1"></div>
<div class="section_1 justify-between">
<img class="thumbnail_1" referrerpolicy="no-referrer" <div v-if="activeTab === 0">
src="/images/Help-center/SketchPngcebb162be4c752de66c89f16a525f570b179222941fc1ebd59ee37257e634009.png" /> <div class="section_1 justify-between">
<span class="text_5">1.如何在线上注册账号</span> <img class="thumbnail_1" referrerpolicy="no-referrer"
src="/images/Help-center/SketchPngcebb162be4c752de66c89f16a525f570b179222941fc1ebd59ee37257e634009.png" />
<span class="text_5">1.如何在线上注册账号</span>
</div>
<span class="text_6">
浏览器登录www.xuetangx.com打开网页后点击右上角登录按钮进行账号注册您也可以在微信小程序和app的登录界面进行注册
</span>
</div>
<div v-else-if="activeTab === 1">
<div class="section_1 justify-between">
<img class="thumbnail_1" referrerpolicy="no-referrer"
src="/images/Help-center/SketchPngcebb162be4c752de66c89f16a525f570b179222941fc1ebd59ee37257e634009.png" />
<span class="text_5">1.如何获取课程认证证书</span>
</div>
<span class="text_6">
完成课程所有学习内容并通过考核后可在课程详情页面申请认证证书认证证书通常在3-5个工作日内审核发放
</span>
</div>
<div v-else>
<div class="section_1 justify-between">
<img class="thumbnail_1" referrerpolicy="no-referrer"
src="/images/Help-center/SketchPngcebb162be4c752de66c89f16a525f570b179222941fc1ebd59ee37257e634009.png" />
<span class="text_5">1.如何购买课程</span>
</div>
<span class="text_6">
浏览课程详情页面点击"立即购买"按钮按照提示完成支付流程即可支持微信支付宝等多种支付方式
</span>
</div> </div>
<span class="text_6">
浏览器登录www.xuetangx.com打开网页后点击右上角登录按钮进行账号注册您也可以在微信小程序和app的登录界面进行注册
</span>
<div class="section_1 justify-between"> <div class="section_1 justify-between">
<img class="thumbnail_1" referrerpolicy="no-referrer" <img class="thumbnail_1" referrerpolicy="no-referrer"
src="/images/Help-center/SketchPngcebb162be4c752de66c89f16a525f570b179222941fc1ebd59ee37257e634009.png" /> src="/images/Help-center/SketchPngcebb162be4c752de66c89f16a525f570b179222941fc1ebd59ee37257e634009.png" />
@ -117,7 +144,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue';
// tab
const activeTab = ref(0);
// tab
const handleTabChange = (index: number) => {
activeTab.value = index;
}
</script> </script>
<style scoped> <style scoped>
@ -209,7 +244,7 @@
width: 72px; width: 72px;
height: 21px; height: 21px;
overflow-wrap: break-word; overflow-wrap: break-word;
color: rgba(2, 136, 209, 1); color: rgba(153, 153, 153, 1);
font-size: 18px; font-size: 18px;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
font-weight: normal; font-weight: normal;
@ -218,6 +253,9 @@
line-height: 21px; line-height: 21px;
} }
.box_3.active .text-group_2 {
color: #0288D1;
}
.image-text_3 { .image-text_3 {
width: 98px; width: 98px;
height: 23px; height: 23px;

View File

@ -136,8 +136,11 @@
<section class="advertisement-section" v-if="showAdvertisement"> <section class="advertisement-section" v-if="showAdvertisement">
<div class="container"> <div class="container">
<div class="ad-container"> <div class="ad-container">
<button class="close-btn" @click="closeAdvertisement">关闭</button> <!-- <button class="close-btn" @click="closeAdvertisement">关闭</button> -->
<img src="/images/advertising/advertising1.png" alt="广告图片" class="ad-image" /> <img src="/images/advertising/advertising3.png" alt="广告图片" class="ad-image" />
<div class="ad-container-text">
2025AI算法挑战活动大赛
</div>
</div> </div>
</div> </div>
</section> </section>
@ -236,16 +239,6 @@
</div> </div>
</section> </section>
<!-- 广告 -->
<section class="advertisement-section" v-if="showAdvertisement">
<div class="container">
<div class="ad-container">
<button class="close-btn" @click="closeAdvertisement">关闭</button>
<img src="/images/advertising/advertising1.png" alt="广告图片" class="ad-image" />
</div>
</div>
</section>
<!-- ai智能体验 --> <!-- ai智能体验 -->
<section class="ai-smart-experience"> <section class="ai-smart-experience">
<div class="container"> <div class="container">
@ -290,6 +283,27 @@
</div> </div>
</section> --> </section> -->
<!-- 广告 -->
<section class="advertisement-section" v-if="showAdvertisement">
<div class="container">
<div class="ad-container">
<button class="close-btn" @click="closeAdvertisement">关闭</button>
<img src="/images/advertising/advertising4.png" alt="广告图片" class="ad-image" />
<div class="ad-container-title1">
<h3>数据分析高阶集训营</h3>
<div class="ad-box">
<div class="ad-line"></div>
<span>DATA ANALYSIS BOOT CAMP</span>
</div>
</div>
<div class="ad-container-title2">
以数据为剑 破解难题之锁
</div>
</div>
</div>
</section>
<!-- 精选评论 --> <!-- 精选评论 -->
<section class="featured-reviews"> <section class="featured-reviews">
<div class="container"> <div class="container">
@ -736,6 +750,39 @@ onMounted(async () => {
</script> </script>
<style scoped> <style scoped>
/* 引入字体 */
@font-face {
font-family: 'TheTitleIsBlack';
src: url('@/assets/fonts/优设标题黑.ttf') format('truetype');
font-display: swap;
}
@font-face {
font-family: 'AlimamaShuHeiTiBold';
src: url('@/assets/fonts/AlimamaShuHeiTi-Bold.ttf') format('truetype');
font-display: swap;
}
@font-face {
font-family: 'WendaoIsTide';
src: url('@/assets/fonts/文道潮黑.ttf') format('truetype');
font-display: swap;
}
@font-face {
font-family: 'PangMenIsRight';
src: url('@/assets/fonts/庞门正道标题体3.0.ttf') format('truetype');
font-display: swap;
}
@font-face {
font-family: 'DouyinSansBold';
src: url('@/assets/fonts/DouyinSansBold.otf') format('truetype');
font-display: swap;
}
.home { .home {
width: 100%; width: 100%;
background: #f8f9fa; background: #f8f9fa;
@ -1107,6 +1154,64 @@ onMounted(async () => {
text-align: center; text-align: center;
} }
.ad-container-text {
position: absolute;
color: #3BA4EB;
top: 48%;
transform: translateY(-50%);
left: 24%;
font-size: 22px;
}
.ad-container-title1 {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 15%;
}
.ad-container-title1 span {
font-size: 11px;
font-weight: 700;
color: #53789B;
}
.ad-container-title1 h3 {
padding: 0;
margin-bottom: -8px;
font-family: 'DouyinSansBold';
color: #021B50;
font-size: 26px;
font-weight: 600;
}
.ad-box {
display: flex;
align-items: center;
gap: 8px;
}
.ad-line {
width: 32px;
height: 3px;
background: linear-gradient(to right, #5479F7, #60D9E9);
}
.ad-container-title2 {
position: absolute;
top: 65%;
right: 29%;
transform: translateY(-50%);
width: 204px;
height: 26px;
color: #fff;
background: linear-gradient(to right, #1D46F3, #60D9E9);
font-size: 14px;
display: flex;
justify-content: center;
align-items: center;
}
.ad-image { .ad-image {
width: 100%; width: 100%;
height: auto; height: auto;
@ -1158,6 +1263,7 @@ onMounted(async () => {
.stat-item { .stat-item {
flex: 1; flex: 1;
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
gap: 20px; gap: 20px;
padding: 0; padding: 0;
@ -1199,13 +1305,13 @@ onMounted(async () => {
.stat-content { .stat-content {
text-align: right; text-align: left;
flex: 1; /* flex: 1; */
} }
.stat-number { .stat-number {
font-size: 22px; font-size: 22px;
font-weight: 700; /* font-weight: 700; */
color: #292C2E; color: #292C2E;
margin-bottom: 6px; margin-bottom: 6px;
line-height: 1.1; line-height: 1.1;
@ -1220,6 +1326,7 @@ onMounted(async () => {
word-wrap: break-word; word-wrap: break-word;
word-break: break-word; word-break: break-word;
hyphens: auto; hyphens: auto;
text-align: left;
} }
.special-content { .special-content {
@ -1287,6 +1394,8 @@ onMounted(async () => {
} }
.section-title-text { .section-title-text {
/* 字体 */
font-family: 'AlimamaShuHeiTiBold';
height: 32px; height: 32px;
line-height: 32px; line-height: 32px;
font-size: 30px; font-size: 30px;
@ -1819,7 +1928,7 @@ onMounted(async () => {
} }
.path-image { .path-image {
width: 448px; width: 100%;
height: 195px; height: 195px;
border-radius: 8px; border-radius: 8px;
object-fit: cover; object-fit: cover;

View File

@ -139,7 +139,7 @@
src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPng23376f42e0d0f21014efca4f1a7ee3c5efa70f6e1419d0d3e6c4a680191c7ef5" /> src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPng23376f42e0d0f21014efca4f1a7ee3c5efa70f6e1419d0d3e6c4a680191c7ef5" />
<span class="text_21">{{ course.duration || '12小时43分钟' }}</span> <span class="text_21">{{ course.duration || '12小时43分钟' }}</span>
<img class="thumbnail_8" referrerpolicy="no-referrer" <img class="thumbnail_8" referrerpolicy="no-referrer"
:src="course.status === 'learning' ? 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng51c1f99cd7b1c15c6efdc0480d16ff2681be4bef17a9dedfcaac33f2976fbd81' : 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng317a0d8f3287bb788c48059c8181479ad5eba8557ef1c09215d9a1c962d0db67'" /> :src="course.status === 'learning' ? 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng317a0d8f3287bb788c48059c8181479ad5eba8557ef1c09215d9a1c962d0db67' : 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng317a0d8f3287bb788c48059c8181479ad5eba8557ef1c09215d9a1c962d0db67'" />
<span class="text_22">已看{{ course.watchedTime || '10小时20分钟' }}</span> <span class="text_22">已看{{ course.watchedTime || '10小时20分钟' }}</span>
<div class="text-wrapper_2 flex-col" @click="goToCourse(course.id)"> <div class="text-wrapper_2 flex-col" @click="goToCourse(course.id)">
<span class="text_23">{{ course.status === 'learning' ? '去学习' : '去复习' }}</span> <span class="text_23">{{ course.status === 'learning' ? '去学习' : '去复习' }}</span>
@ -927,7 +927,7 @@ const { t, locale } = useI18n()
// //
const bannerImage = computed(() => { const bannerImage = computed(() => {
return locale.value === 'zh' ? '/banners/banner1.png' : '/banners/banner1-en.png' return locale.value === 'zh' ? '/banners/banner8.png' : '/banners/banner1-en.png'
}) })
const bannerAlt = computed(() => { const bannerAlt = computed(() => {
@ -5217,7 +5217,7 @@ border-bottom: 1.5px solid #E6E6E6;
.activity-grid { .activity-grid {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(4, 1fr);
gap: 1.04vw; gap: 1.04vw;
/* 20px转换为vw */ /* 20px转换为vw */
margin-top: 1.04vh; margin-top: 1.04vh;
@ -5535,9 +5535,9 @@ border-bottom: 1.5px solid #E6E6E6;
color: white; color: white;
font-size: 0.63vw; font-size: 0.63vw;
/* 12px转换为vw */ /* 12px转换为vw */
padding: 0.1vh 0.31vw; padding: 2px 2px;
/* 2px 6px转换 */ /* 2px 6px转换 */
border-radius: 0.52vw; border-radius: 50%;
/* 10px转换为vw */ /* 10px转换为vw */
min-width: 1.04vw; min-width: 1.04vw;
/* 20px转换为vw */ /* 20px转换为vw */

View File

@ -300,7 +300,7 @@ const allImages = ref([
.container { .container {
margin: 0 auto; margin: 0 auto;
padding: 0 20px; /* padding: 0 20px; */
} }
.section-title { .section-title {
@ -466,6 +466,8 @@ const allImages = ref([
/* 全部视频区域 */ /* 全部视频区域 */
.all-videos { .all-videos {
margin-left: -130px;
width: 100vw;
padding: 40px 0; padding: 40px 0;
background-color: #fff; background-color: #fff;
margin-bottom: 80px; margin-bottom: 80px;
@ -486,11 +488,7 @@ const allImages = ref([
overflow: hidden; overflow: hidden;
transition: all 0.3s; transition: all 0.3s;
cursor: pointer; cursor: pointer;
} box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
.video-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
} }
.video-card .card-image { .video-card .card-image {

View File

@ -503,11 +503,7 @@ onMounted(() => {
transition: transform 0.2s, box-shadow 0.2s; transition: transform 0.2s, box-shadow 0.2s;
cursor: pointer; cursor: pointer;
min-height: 350px; min-height: 350px;
} box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
.course-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
} }
.course-image { .course-image {