iGuwan-homework/src/views/dashboard/CoursesView.vue

525 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="courses-container">
<!-- 背景动画 -->
<div class="background-animation">
<div class="floating-shapes">
<div class="shape shape-1"></div>
<div class="shape shape-2"></div>
<div class="shape shape-3"></div>
</div>
</div>
<div class="main-content">
<!-- 页面标题 -->
<div class="page-header">
<h1 class="page-title">我的课程</h1>
<p class="page-subtitle">探索知识的海洋开启学习之旅</p>
</div>
<!-- 课程筛选 -->
<div class="course-filters">
<div class="filter-tabs">
<button
v-for="category in categories"
:key="category.id"
:class="['filter-tab', { active: activeCategory === category.id }]"
@click="activeCategory = category.id"
>
{{ category.name }}
</button>
</div>
<div class="search-box">
<input
type="text"
placeholder="搜索课程..."
v-model="searchQuery"
class="search-input"
>
<i class="search-icon">🔍</i>
</div>
</div>
<!-- 课程网格 -->
<div class="courses-grid">
<div
v-for="course in filteredCourses"
:key="course.id"
class="course-card"
@click="goToCourse(course.id)"
>
<div class="course-image">
<img :src="course.image" :alt="course.title">
<div class="course-badge">{{ course.level }}</div>
</div>
<div class="course-content">
<h3 class="course-title">{{ course.title }}</h3>
<p class="course-description">{{ course.description }}</p>
<div class="course-meta">
<span class="course-duration">⏱️ {{ course.duration }}</span>
<span class="course-lessons">📚 {{ course.lessons }}课时</span>
</div>
<div class="course-progress">
<div class="progress-bar">
<div
class="progress-fill"
:style="{ width: course.progress + '%' }"
></div>
</div>
<span class="progress-text">{{ course.progress }}%</span>
</div>
<div class="course-actions">
<button class="continue-btn">继续学习</button>
<button class="details-btn">查看详情</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const activeCategory = ref('all')
const searchQuery = ref('')
const categories = ref([
{ id: 'all', name: '全部课程' },
{ id: 'math', name: '数学' },
{ id: 'chinese', name: '语文' },
{ id: 'english', name: '英语' },
{ id: 'science', name: '科学' },
{ id: 'programming', name: '编程' }
])
const courses = ref([
{
id: 1,
title: '高等数学基础',
description: '从基础概念到高级应用全面掌握高等数学知识',
image: 'https://images.unsplash.com/photo-1635070041078-e363dbe005cb?w=400',
category: 'math',
level: '初级',
duration: '12周',
lessons: 48,
progress: 65
},
{
id: 2,
title: '现代文学赏析',
description: '深入理解现代文学作品提升文学素养和鉴赏能力',
image: 'https://images.unsplash.com/photo-1481627834876-b7833e8f5570?w=400',
category: 'chinese',
level: '中级',
duration: '10周',
lessons: 30,
progress: 40
},
{
id: 3,
title: '英语口语进阶',
description: '提升英语口语表达能力掌握地道的英语交流技巧',
image: 'https://images.unsplash.com/photo-1434030216411-0b793f4b4173?w=400',
category: 'english',
level: '高级',
duration: '8周',
lessons: 24,
progress: 80
},
{
id: 4,
title: 'Python编程入门',
description: '零基础学习Python编程掌握编程思维和实践技能',
image: 'https://images.unsplash.com/photo-1526379095098-d400fd0bf935?w=400',
category: 'programming',
level: '初级',
duration: '16周',
lessons: 60,
progress: 25
},
{
id: 5,
title: '物理实验探索',
description: '通过实验探索物理世界的奥秘培养科学思维',
image: 'https://images.unsplash.com/photo-1532094349884-543bc11b234d?w=400',
category: 'science',
level: '中级',
duration: '14周',
lessons: 42,
progress: 55
},
{
id: 6,
title: '化学基础理论',
description: '掌握化学基本原理理解物质变化的本质',
image: 'https://images.unsplash.com/photo-1554475901-4538ddfbccc2?w=400',
category: 'science',
level: '初级',
duration: '12周',
lessons: 36,
progress: 90
}
])
const filteredCourses = computed(() => {
let filtered = courses.value
if (activeCategory.value !== 'all') {
filtered = filtered.filter(course => course.category === activeCategory.value)
}
if (searchQuery.value) {
filtered = filtered.filter(course =>
course.title.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
course.description.toLowerCase().includes(searchQuery.value.toLowerCase())
)
}
return filtered
})
const goToCourse = (courseId: number) => {
router.push(`/course/${courseId}`)
}
onMounted(() => {
// 页面加载动画
const mainContent = document.querySelector('.main-content')
if (mainContent) {
mainContent.classList.add('loaded')
}
})
</script>
<style scoped>
.courses-container {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: relative;
overflow: hidden;
padding-top: 80px;
}
.background-animation {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1;
}
.floating-shapes {
position: absolute;
width: 100%;
height: 100%;
}
.shape {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
animation: float 6s ease-in-out infinite;
}
.shape-1 {
width: 80px;
height: 80px;
top: 20%;
left: 10%;
animation-delay: 0s;
}
.shape-2 {
width: 120px;
height: 120px;
top: 60%;
right: 15%;
animation-delay: 2s;
}
.shape-3 {
width: 60px;
height: 60px;
bottom: 20%;
left: 20%;
animation-delay: 4s;
}
@keyframes float {
0%, 100% { transform: translateY(0px) rotate(0deg); }
50% { transform: translateY(-20px) rotate(180deg); }
}
.main-content {
position: relative;
z-index: 2;
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
opacity: 0;
transform: translateY(30px);
transition: all 0.8s ease;
}
.main-content.loaded {
opacity: 1;
transform: translateY(0);
}
.page-header {
text-align: center;
margin-bottom: 3rem;
}
.page-title {
font-size: 3rem;
font-weight: 700;
color: white;
margin-bottom: 1rem;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.page-subtitle {
font-size: 1.2rem;
color: rgba(255, 255, 255, 0.8);
margin: 0;
}
.course-filters {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
gap: 2rem;
}
.filter-tabs {
display: flex;
gap: 1rem;
}
.filter-tab {
padding: 0.8rem 1.5rem;
border: none;
border-radius: 25px;
background: rgba(255, 255, 255, 0.1);
color: white;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.filter-tab:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-2px);
}
.filter-tab.active {
background: rgba(255, 255, 255, 0.3);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.search-box {
position: relative;
}
.search-input {
padding: 0.8rem 1rem 0.8rem 3rem;
border: none;
border-radius: 25px;
background: rgba(255, 255, 255, 0.1);
color: white;
backdrop-filter: blur(10px);
width: 300px;
transition: all 0.3s ease;
}
.search-input::placeholder {
color: rgba(255, 255, 255, 0.6);
}
.search-input:focus {
outline: none;
background: rgba(255, 255, 255, 0.2);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.search-icon {
position: absolute;
left: 1rem;
top: 50%;
transform: translateY(-50%);
color: rgba(255, 255, 255, 0.6);
}
.courses-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 2rem;
}
.course-card {
background: rgba(255, 255, 255, 0.1);
border-radius: 20px;
overflow: hidden;
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
cursor: pointer;
}
.course-card:hover {
transform: translateY(-10px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
background: rgba(255, 255, 255, 0.15);
}
.course-image {
position: relative;
height: 200px;
overflow: hidden;
}
.course-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.course-card:hover .course-image img {
transform: scale(1.1);
}
.course-badge {
position: absolute;
top: 1rem;
right: 1rem;
background: rgba(255, 255, 255, 0.9);
color: #333;
padding: 0.3rem 0.8rem;
border-radius: 15px;
font-size: 0.8rem;
font-weight: 600;
}
.course-content {
padding: 1.5rem;
}
.course-title {
font-size: 1.3rem;
font-weight: 600;
color: white;
margin-bottom: 0.5rem;
}
.course-description {
color: rgba(255, 255, 255, 0.8);
font-size: 0.9rem;
line-height: 1.5;
margin-bottom: 1rem;
}
.course-meta {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
font-size: 0.8rem;
color: rgba(255, 255, 255, 0.7);
}
.course-progress {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1.5rem;
}
.progress-bar {
flex: 1;
height: 6px;
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);
border-radius: 3px;
transition: width 0.3s ease;
}
.progress-text {
font-size: 0.8rem;
color: rgba(255, 255, 255, 0.8);
font-weight: 600;
}
.course-actions {
display: flex;
gap: 1rem;
}
.continue-btn, .details-btn {
flex: 1;
padding: 0.8rem;
border: none;
border-radius: 10px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.continue-btn {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
}
.continue-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(79, 172, 254, 0.4);
}
.details-btn {
background: rgba(255, 255, 255, 0.1);
color: white;
border: 1px solid rgba(255, 255, 255, 0.3);
}
.details-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-2px);
}
@media (max-width: 768px) {
.course-filters {
flex-direction: column;
gap: 1rem;
}
.filter-tabs {
flex-wrap: wrap;
justify-content: center;
}
.search-input {
width: 100%;
}
.courses-grid {
grid-template-columns: 1fr;
}
.page-title {
font-size: 2rem;
}
}
</style>