添加了一个学习路径页面

This commit is contained in:
username 2025-07-22 20:59:46 +08:00
parent f518ea0966
commit 4c69fdf4fc
5 changed files with 759 additions and 14 deletions

View File

@ -17,15 +17,19 @@
<img src="/nav-icons/火.png" alt="" class="nav-icon" />
{{ t('header.courses') }}
</div>
<div class="nav-item" :class="{ active: activeKey === 'training' }" @click="handleMenuSelect('training')">
{{ t('header.training') }}
</div>
<div class="nav-item" :class="{ active: activeKey === 'practice' }" @click="handleMenuSelect('practice')">
{{ t('header.resources') }}
</div>
<div class="nav-item" :class="{ active: activeKey === 'resources' }" @click="handleMenuSelect('resources')">
<div class="nav-item" :class="{ active: activeKey === 'faculty' }" @click="handleMenuSelect('faculty')">
{{ t('header.learningPaths') }}
</div>
<div class="nav-item" :class="{ active: activeKey === 'resources' }" @click="handleMenuSelect('resources')">
{{ t('header.resources') }}
</div>
<div class="nav-item" :class="{ active: activeKey === 'activities' }" @click="handleMenuSelect('activities')">
{{ t('header.about') }}
<img src="/nav-icons/new.png" alt="new" class="new-badge" />
@ -190,7 +194,7 @@ const handleMenuSelect = (key: string) => {
//
router.push('/')
break
case 'practice':
case 'faculty':
//
router.push('/')
break

View File

@ -1,11 +1,11 @@
{
"header": {
"home": "Home",
"courses": "Courses",
"training": "Training",
"learningPaths": "Learning Paths",
"resources": "Resources",
"about": "About Us",
"courses": "Popular Courses",
"training": "Special Training",
"learningPaths": "Faculty",
"resources": "Featured Resources",
"about": "Activities",
"languageSwitch": "Language",
"learningCenter": "Learning Center",
"management": "Management",

View File

@ -1,11 +1,11 @@
{
"header": {
"home": "首页",
"courses": "",
"courses": "热门好课",
"training": "专题训练",
"learningPaths": "学习路径",
"resources": "资源中心",
"about": "关于我们",
"learningPaths": "师资力量",
"resources": "精选资源",
"about": "活动",
"languageSwitch": "切换语言",
"learningCenter": "学习中心",
"management": "管理端",

View File

@ -9,6 +9,7 @@ import Learning from '@/views/Learning.vue'
import Profile from '@/views/Profile.vue'
import Login from '@/views/Login.vue'
import Register from '@/views/Register.vue'
import LearningPaths from '@/views/LearningPaths.vue'
const routes: RouteRecordRaw[] = [
{
@ -69,6 +70,14 @@ const routes: RouteRecordRaw[] = [
title: '注册'
}
},
{
path: '/learning-paths',
name: 'LearningPaths',
component: LearningPaths,
meta: {
title: '学习路径'
}
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',

732
src/views/LearningPaths.vue Normal file
View File

@ -0,0 +1,732 @@
<template>
<div class="learning-paths-page">
<!-- 页面标题区域 -->
<div class="page-header">
<div class="container">
<div class="header-content">
<h1 class="page-title">学习路径</h1>
<p class="page-subtitle">成就卓越的学习之路开启智慧之门</p>
</div>
<div class="header-decoration">
<!-- 装饰图片暂时隐藏 -->
</div>
</div>
</div>
<!-- 主要内容区域 -->
<div class="main-content">
<div class="container">
<div class="content-layout">
<!-- 左侧筛选栏 -->
<div class="filter-sidebar">
<!-- 所有路径标题 - 无背景样式 -->
<h3 class="filter-title">所有路径</h3>
<div class="filter-section">
<div class="filter-options">
<div class="filter-option active" :class="{ active: selectedCategory === 'psychology' }" @click="selectCategory('psychology')">
<span class="option-icon blue-icon"></span>
<span class="option-text">数据心理学</span>
</div>
<div class="filter-option" :class="{ active: selectedCategory === 'ai' }" @click="selectCategory('ai')">
<span class="option-icon gray-icon"></span>
<span class="option-text">AI 时代生存指南从工程师到架构师...</span>
</div>
<div class="filter-option" :class="{ active: selectedCategory === 'english1' }" @click="selectCategory('english1')">
<span class="option-icon gray-icon"></span>
<span class="option-text">新视野英语训练营</span>
</div>
<div class="filter-option" :class="{ active: selectedCategory === 'english2' }" @click="selectCategory('english2')">
<span class="option-icon gray-icon"></span>
<span class="option-text">新视野英语训练营</span>
</div>
<div class="filter-option" :class="{ active: selectedCategory === 'learning' }" @click="selectCategory('learning')">
<span class="option-icon gray-icon"></span>
<span class="option-text">科学学习方法 | 强化记忆</span>
</div>
<div class="filter-option" :class="{ active: selectedCategory === 'health' }" @click="selectCategory('health')">
<span class="option-icon gray-icon"></span>
<span class="option-text">运动与健康</span>
</div>
<div class="filter-option" :class="{ active: selectedCategory === 'education' }" @click="selectCategory('education')">
<span class="option-icon gray-icon"></span>
<span class="option-text">数师教育学科技能体系</span>
</div>
</div>
</div>
</div>
<!-- 右侧内容区域 -->
<div class="content-main">
<!-- 课程标题 - 无背景样式 -->
<h3 class="content-title">课程</h3>
<!-- 统计信息和筛选行 -->
<div class="content-header">
<div class="result-info">
<span class="result-stats"> 34 | 567 课程 | 1243 小时</span>
</div>
<div class="sort-options">
<span class="sort-label">难度等级</span>
<select v-model="sortBy" class="sort-select">
<option value="default">全部</option>
<option value="beginner">初级</option>
<option value="intermediate">中级</option>
<option value="advanced">高级</option>
</select>
</div>
</div>
<!-- 学习路径列表 -->
<div class="paths-list">
<div class="path-card" v-for="path in paginatedPaths" :key="path.id" @click="goToPath(path.id)">
<div class="card-image">
<div class="image-placeholder"></div>
<div class="card-badge">热门</div>
</div>
<div class="card-content">
<h3 class="card-title">{{ path.title }}</h3>
<div class="card-meta">
<span class="meta-item">{{ path.level }}</span>
<span class="meta-item">{{ path.duration }}</span>
<span class="meta-item">免费</span>
</div>
<p class="card-description">{{ path.description }}</p>
<div class="card-footer">
<div class="card-stats">
<span class="stat-item">{{ path.studentsCount }}人学习</span>
<span class="stat-item">{{ path.lessonsCount }}个课程</span>
</div>
<div class="card-rating">
<span class="rating-icon">👍</span>
<span class="rating-text">5.0</span>
</div>
</div>
</div>
</div>
</div>
<!-- 分页 -->
<div class="pagination">
<button class="page-btn" :disabled="currentPage === 1" @click="goToPage(currentPage - 1)">
上一页
</button>
<button
class="page-btn"
:class="{ active: page === currentPage }"
v-for="page in visiblePages"
:key="page"
@click="goToPage(page)"
>
{{ page }}
</button>
<button class="page-btn" :disabled="currentPage === totalPages" @click="goToPage(currentPage + 1)">
下一页
</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 selectedCategory = ref('psychology')
const sortBy = ref('default')
//
const currentPage = ref(1)
const pageSize = 8
//
const learningPaths = ref([
{
id: 1,
title: '数据心理学的起源',
description: '本课程深度解析,让您一次性掌握数据分析的心理学基础。适合希望从心理学角度理解数据的学习者。这是一门综合性的课程,涵盖了数据分析的各个方面。通过本课程的学习,您将能够掌握数据分析的核心技能,并能够在实际工作中应用这些技能。',
image: 'https://images.unsplash.com/photo-1635070041078-e363dbe005cb?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
category: 'psychology',
level: '数学基础',
duration: '免费',
studentsCount: 1234,
lessonsCount: 24,
badge: '热门'
},
{
id: 2,
title: '数据心理学的发展历程',
description: '本课程深度解析,让您一次性掌握数据分析的心理学基础。适合希望从心理学角度理解数据的学习者。这是一门综合性的课程,涵盖了数据分析的各个方面。通过本课程的学习,您将能够掌握数据分析的核心技能。',
image: 'https://images.unsplash.com/photo-1509228468518-180dd4864904?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
category: 'psychology',
level: '数学基础',
duration: '免费',
studentsCount: 856,
lessonsCount: 30,
badge: '热门'
},
{
id: 3,
title: '研究情境性环境的影响',
description: '本课程深度解析,让您一次性掌握数据分析的心理学基础。适合希望从心理学角度理解数据的学习者。这是一门综合性的课程,涵盖了数据分析的各个方面。通过本课程的学习,您将能够掌握数据分析的核心技能。',
image: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
category: 'psychology',
level: '数学基础',
duration: '免费',
studentsCount: 678,
lessonsCount: 36,
badge: '热门'
},
{
id: 4,
title: '研究学习环境设计和有效教学模式',
description: '本课程深度解析,让您一次性掌握数据分析的心理学基础。适合希望从心理学角度理解数据的学习者。这是一门综合性的课程,涵盖了数据分析的各个方面。通过本课程的学习,您将能够掌握数据分析的核心技能。',
image: 'https://images.unsplash.com/photo-1551650975-87deedd944c3?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
category: 'psychology',
level: '数学基础',
duration: '免费',
studentsCount: 945,
lessonsCount: 30,
badge: '热门'
},
{
id: 5,
title: '数据心理学的起源',
description: '本课程深度解析,让您一次性掌握数据分析的心理学基础。适合希望从心理学角度理解数据的学习者。这是一门综合性的课程,涵盖了数据分析的各个方面。通过本课程的学习,您将能够掌握数据分析的核心技能。',
image: 'https://images.unsplash.com/photo-1596495578065-6e0763fa1178?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',
category: 'psychology',
level: '数学基础',
duration: '免费',
studentsCount: 1567,
lessonsCount: 18,
badge: '热门'
},
])
//
const filteredPaths = computed(() => {
let filtered = learningPaths.value
if (selectedCategory.value) {
filtered = filtered.filter(path => path.category === selectedCategory.value)
}
return filtered
})
const totalPages = computed(() => Math.ceil(filteredPaths.value.length / pageSize))
const paginatedPaths = computed(() => {
const start = (currentPage.value - 1) * pageSize
const end = start + pageSize
return filteredPaths.value.slice(start, end)
})
const visiblePages = computed(() => {
const pages = []
const total = totalPages.value
const current = currentPage.value
for (let i = Math.max(1, current - 2); i <= Math.min(total, current + 2); i++) {
pages.push(i)
}
return pages
})
//
const selectCategory = (category: string) => {
selectedCategory.value = category
currentPage.value = 1
}
const goToPage = (page: number) => {
currentPage.value = page
}
const goToPath = (pathId: number) => {
router.push(`/learning-path/${pathId}`)
}
onMounted(() => {
//
console.log('学习路径页面加载完成')
})
</script>
<style scoped>
.learning-paths-page {
min-height: 100vh;
background-color: #f8f9fa;
}
/* 页面标题区域 */
.page-header {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
padding: 60px 0;
position: relative;
overflow: hidden;
}
.page-header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg, rgba(255,255,255,0.1) 25%, transparent 25%),
linear-gradient(-45deg, rgba(255,255,255,0.1) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, rgba(255,255,255,0.1) 75%),
linear-gradient(-45deg, transparent 75%, rgba(255,255,255,0.1) 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
opacity: 0.1;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
position: relative;
}
.header-content {
text-align: center;
color: white;
}
.page-title {
font-size: 48px;
font-weight: 700;
margin: 0 0 16px 0;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.page-subtitle {
font-size: 18px;
font-weight: 400;
margin: 0;
opacity: 0.9;
}
.header-decoration {
position: absolute;
right: 50px;
top: 50%;
transform: translateY(-50%);
}
.decoration-image {
width: 200px;
height: auto;
opacity: 0.8;
}
/* 主要内容区域 */
.main-content {
padding: 40px 0 80px;
background-color: rgb(246, 246, 246);
}
.content-layout {
display: flex;
gap: 30px;
align-items: flex-start;
}
/* 左侧筛选栏 */
.filter-sidebar {
width: 280px;
flex-shrink: 0;
}
.filter-section {
background: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 0;
box-shadow: none;
border: 1px solid #e9ecef;
}
.filter-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin: 0 0 20px 0;
padding: 0;
/* 所有路径标题直接显示在灰色背景上,无背景样式 */
}
.filter-options {
display: flex;
flex-direction: column;
gap: 0;
}
.filter-option {
display: flex;
align-items: center;
padding: 10px 0;
border-radius: 0;
cursor: pointer;
transition: all 0.2s;
border: none;
border-bottom: 1px solid #e9ecef;
background: transparent;
}
.filter-option:last-child {
border-bottom: none;
}
.filter-option:hover {
background-color: transparent;
}
.filter-option.active .option-text {
color: #1976d2;
font-weight: 500;
}
.filter-option.active .blue-icon {
color: #1976d2;
}
.option-icon {
display: inline-block;
margin-right: 8px;
font-size: 12px;
width: 12px;
height: 12px;
line-height: 1;
flex-shrink: 0;
}
.blue-icon {
color: #1976d2;
}
.gray-icon {
color: #999;
}
.option-text {
font-size: 14px;
font-weight: 400;
color: #666;
line-height: 1.4;
word-wrap: break-word;
word-break: break-word;
flex: 1;
}
/* 右侧内容区域 */
.content-main {
flex: 1;
}
.content-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin: 0 0 20px 0;
padding: 0;
/* 课程标题直接显示在灰色背景上,无背景样式 */
}
.content-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 0;
width: 100%;
}
.result-info {
color: #666;
font-size: 14px;
}
.result-stats {
font-weight: 400;
color: #666;
}
.sort-options {
display: flex;
align-items: center;
gap: 8px;
}
.sort-label {
font-size: 14px;
color: #666;
}
.sort-select {
padding: 4px 8px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
background: white;
cursor: pointer;
color: #666;
}
/* 学习路径列表 */
.paths-list {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 40px;
}
.path-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
transition: all 0.2s;
cursor: pointer;
display: flex;
min-height: 120px;
}
.path-card:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.card-image {
position: relative;
width: 160px;
flex-shrink: 0;
background: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
}
.image-placeholder {
width: 100%;
height: 100%;
background: #e0e0e0;
display: flex;
align-items: center;
justify-content: center;
}
.card-badge {
position: absolute;
top: 8px;
left: 8px;
background: #ff6b35;
color: white;
padding: 2px 6px;
border-radius: 3px;
font-size: 11px;
font-weight: 500;
}
.card-content {
padding: 16px 20px;
flex: 1;
display: flex;
flex-direction: column;
}
.card-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin: 0 0 8px 0;
line-height: 1.3;
}
.card-meta {
display: flex;
gap: 8px;
margin-bottom: 8px;
}
.meta-item {
font-size: 12px;
color: #666;
background: #f8f9fa;
padding: 2px 6px;
border-radius: 3px;
}
.card-description {
font-size: 13px;
color: #666;
line-height: 1.5;
margin: 0 0 12px 0;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
flex: 1;
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: auto;
}
.card-stats {
display: flex;
gap: 12px;
}
.stat-item {
font-size: 12px;
color: #999;
}
.card-rating {
display: flex;
align-items: center;
gap: 4px;
}
.rating-icon {
font-size: 14px;
}
.rating-text {
font-size: 12px;
color: #666;
font-weight: 500;
}
/* 分页样式 */
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
margin-top: 40px;
}
.page-btn {
padding: 8px 16px;
border: 1px solid #ddd;
background: white;
color: #666;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
min-width: 40px;
}
.page-btn:hover:not(:disabled) {
border-color: #2196f3;
color: #2196f3;
}
.page-btn.active {
background: #2196f3;
border-color: #2196f3;
color: white;
}
.page-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* 响应式设计 */
@media (max-width: 1024px) {
.content-layout {
flex-direction: column;
}
.filter-sidebar {
width: 100%;
}
.filter-options {
flex-direction: row;
flex-wrap: wrap;
gap: 12px;
}
.filter-option {
flex: 0 0 auto;
}
}
@media (max-width: 768px) {
.page-header {
padding: 40px 0;
}
.page-title {
font-size: 32px;
}
.page-subtitle {
font-size: 16px;
}
.header-decoration {
display: none;
}
.paths-list {
grid-template-columns: 1fr;
gap: 16px;
}
.content-header {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.sort-options {
align-self: flex-end;
}
}
@media (max-width: 480px) {
.container {
padding: 0 16px;
}
.main-content {
padding: 20px 0 40px;
}
.filter-section {
padding: 16px;
}
.card-content {
padding: 16px;
}
.pagination {
gap: 4px;
}
.page-btn {
padding: 6px 12px;
font-size: 12px;
min-width: 32px;
}
}
</style>