323 lines
9.7 KiB
TypeScript
323 lines
9.7 KiB
TypeScript
import { defineStore } from 'pinia'
|
||
import { ref, computed } from 'vue'
|
||
import { CourseApi } from '@/api/modules/course'
|
||
import type { Course as ApiCourse } from '@/api/types'
|
||
|
||
export type Course = ApiCourse
|
||
|
||
export interface Lesson {
|
||
id: number
|
||
courseId: number
|
||
title: string
|
||
description: string
|
||
videoUrl?: string
|
||
duration: string
|
||
order: number
|
||
isCompleted?: boolean
|
||
isFree?: boolean
|
||
}
|
||
|
||
export const useCourseStore = defineStore('course', () => {
|
||
// 状态
|
||
const courses = ref<Course[]>([])
|
||
const currentCourse = ref<Course | null>(null)
|
||
const lessons = ref<Lesson[]>([])
|
||
const enrolledCourses = ref<Course[]>([])
|
||
const isLoading = ref(false)
|
||
const searchQuery = ref('')
|
||
const selectedCategory = ref('')
|
||
const selectedLevel = ref('')
|
||
|
||
// 计算属性
|
||
const filteredCourses = computed(() => {
|
||
let filtered = courses.value
|
||
|
||
if (searchQuery.value) {
|
||
filtered = filtered.filter(course =>
|
||
course.title.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
|
||
course.description.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
|
||
course.instructor.name.toLowerCase().includes(searchQuery.value.toLowerCase())
|
||
)
|
||
}
|
||
|
||
if (selectedCategory.value) {
|
||
filtered = filtered.filter(course => course.category.name === selectedCategory.value)
|
||
}
|
||
|
||
if (selectedLevel.value) {
|
||
filtered = filtered.filter(course => course.level === selectedLevel.value)
|
||
}
|
||
|
||
return filtered
|
||
})
|
||
|
||
const categories = computed(() => {
|
||
const cats = courses.value.map(course => course.category)
|
||
return [...new Set(cats)]
|
||
})
|
||
|
||
// 方法
|
||
const fetchCourses = async () => {
|
||
isLoading.value = true
|
||
try {
|
||
console.log('尝试从API获取课程数据...')
|
||
const response = await CourseApi.getCourses()
|
||
console.log('API响应:', response)
|
||
courses.value = response.data.list
|
||
} catch (error) {
|
||
console.error('API调用失败,使用模拟数据:', error)
|
||
// 如果API调用失败,使用模拟数据作为后备
|
||
const mockCourses: Course[] = [
|
||
{
|
||
id: 1,
|
||
title: 'Vue.js 3 完整教程',
|
||
description: '从零开始学习Vue.js 3,包括Composition API、TypeScript集成等现代开发技术',
|
||
content: '详细的Vue.js 3课程内容',
|
||
instructor: {
|
||
id: 1,
|
||
name: '李老师',
|
||
title: '前端开发专家',
|
||
bio: '资深前端开发工程师',
|
||
avatar: 'https://via.placeholder.com/50',
|
||
rating: 4.8,
|
||
studentsCount: 1234,
|
||
coursesCount: 5,
|
||
experience: '5年前端开发经验',
|
||
education: ['计算机科学学士'],
|
||
certifications: ['Vue.js认证']
|
||
},
|
||
thumbnail: 'https://via.placeholder.com/300x200',
|
||
coverImage: 'https://via.placeholder.com/300x200',
|
||
price: 299,
|
||
originalPrice: 399,
|
||
currency: 'CNY',
|
||
rating: 4.8,
|
||
ratingCount: 100,
|
||
studentsCount: 1234,
|
||
duration: '12小时',
|
||
level: 'intermediate',
|
||
category: {
|
||
id: 1,
|
||
name: '前端开发',
|
||
slug: 'frontend',
|
||
description: '前端开发相关课程'
|
||
},
|
||
tags: ['Vue.js', 'JavaScript', 'TypeScript'],
|
||
totalLessons: 20,
|
||
language: 'zh-CN',
|
||
skills: ['Vue.js', 'TypeScript', 'Composition API'],
|
||
requirements: ['JavaScript基础', 'HTML/CSS基础'],
|
||
objectives: ['掌握Vue.js 3核心概念', '学会使用Composition API', '理解TypeScript集成'],
|
||
status: 'published',
|
||
createdAt: '2024-01-01',
|
||
updatedAt: '2024-01-15',
|
||
publishedAt: '2024-01-01'
|
||
},
|
||
{
|
||
id: 2,
|
||
title: 'React 18 实战开发',
|
||
description: '掌握React 18的新特性,包括并发渲染、Suspense等高级功能',
|
||
content: '详细的React 18课程内容',
|
||
instructor: {
|
||
id: 2,
|
||
name: '王老师',
|
||
title: 'React专家',
|
||
bio: '资深React开发工程师',
|
||
avatar: 'https://via.placeholder.com/50',
|
||
rating: 4.9,
|
||
studentsCount: 2156,
|
||
coursesCount: 8,
|
||
experience: '6年React开发经验',
|
||
education: ['软件工程硕士'],
|
||
certifications: ['React认证']
|
||
},
|
||
thumbnail: 'https://via.placeholder.com/300x200',
|
||
coverImage: 'https://via.placeholder.com/300x200',
|
||
price: 399,
|
||
originalPrice: 499,
|
||
currency: 'CNY',
|
||
rating: 4.9,
|
||
ratingCount: 200,
|
||
studentsCount: 2156,
|
||
duration: '15小时',
|
||
level: 'advanced',
|
||
category: {
|
||
id: 1,
|
||
name: '前端开发',
|
||
slug: 'frontend',
|
||
description: '前端开发相关课程'
|
||
},
|
||
tags: ['React', 'JavaScript', 'Hooks'],
|
||
totalLessons: 25,
|
||
language: 'zh-CN',
|
||
skills: ['React 18', 'Hooks', '并发渲染'],
|
||
requirements: ['JavaScript基础', 'React基础'],
|
||
objectives: ['掌握React 18新特性', '学会并发渲染', '理解Suspense'],
|
||
status: 'published',
|
||
createdAt: '2024-01-05',
|
||
updatedAt: '2024-01-20',
|
||
publishedAt: '2024-01-05'
|
||
},
|
||
{
|
||
id: 3,
|
||
title: 'Node.js 后端开发',
|
||
description: '学习Node.js后端开发,包括Express、数据库操作、API设计等',
|
||
content: '详细的Node.js课程内容',
|
||
instructor: {
|
||
id: 3,
|
||
name: '张老师',
|
||
title: 'Node.js专家',
|
||
bio: '资深后端开发工程师',
|
||
avatar: 'https://via.placeholder.com/50',
|
||
rating: 4.7,
|
||
studentsCount: 987,
|
||
coursesCount: 6,
|
||
experience: '7年后端开发经验',
|
||
education: ['计算机科学硕士'],
|
||
certifications: ['Node.js认证']
|
||
},
|
||
thumbnail: 'https://via.placeholder.com/300x200',
|
||
coverImage: 'https://via.placeholder.com/300x200',
|
||
price: 349,
|
||
originalPrice: 449,
|
||
currency: 'CNY',
|
||
rating: 4.7,
|
||
ratingCount: 150,
|
||
studentsCount: 987,
|
||
duration: '18小时',
|
||
level: 'intermediate',
|
||
category: {
|
||
id: 2,
|
||
name: '后端开发',
|
||
slug: 'backend',
|
||
description: '后端开发相关课程'
|
||
},
|
||
tags: ['Node.js', 'Express', 'MongoDB'],
|
||
totalLessons: 30,
|
||
language: 'zh-CN',
|
||
skills: ['Node.js', 'Express', 'MongoDB', 'API设计'],
|
||
requirements: ['JavaScript基础', '编程基础'],
|
||
objectives: ['掌握Node.js后端开发', '学会Express框架', '理解数据库操作'],
|
||
status: 'published',
|
||
createdAt: '2024-01-10',
|
||
updatedAt: '2024-01-25',
|
||
publishedAt: '2024-01-10'
|
||
}
|
||
]
|
||
courses.value = mockCourses
|
||
} finally {
|
||
isLoading.value = false
|
||
}
|
||
}
|
||
|
||
const fetchCourseById = async (id: number) => {
|
||
isLoading.value = true
|
||
try {
|
||
const response = await CourseApi.getCourseById(id)
|
||
currentCourse.value = response.data
|
||
} catch (error) {
|
||
console.error('Failed to fetch course:', error)
|
||
// 如果API调用失败,从本地数据中查找
|
||
const course = courses.value.find(c => c.id === id)
|
||
if (course) {
|
||
currentCourse.value = course
|
||
}
|
||
} finally {
|
||
isLoading.value = false
|
||
}
|
||
}
|
||
|
||
const fetchLessons = async (courseId: number) => {
|
||
isLoading.value = true
|
||
try {
|
||
// 模拟API调用
|
||
await new Promise(resolve => setTimeout(resolve, 500))
|
||
|
||
// 模拟课程章节数据
|
||
const mockLessons: Lesson[] = [
|
||
{
|
||
id: 1,
|
||
courseId,
|
||
title: '课程介绍',
|
||
description: '了解课程内容和学习目标',
|
||
duration: '10分钟',
|
||
order: 1,
|
||
isFree: true
|
||
},
|
||
{
|
||
id: 2,
|
||
courseId,
|
||
title: '环境搭建',
|
||
description: '配置开发环境和工具',
|
||
duration: '20分钟',
|
||
order: 2,
|
||
isFree: true
|
||
},
|
||
{
|
||
id: 3,
|
||
courseId,
|
||
title: '基础语法',
|
||
description: '学习基础语法和概念',
|
||
duration: '45分钟',
|
||
order: 3
|
||
}
|
||
]
|
||
|
||
lessons.value = mockLessons
|
||
} catch (error) {
|
||
console.error('Failed to fetch lessons:', error)
|
||
} finally {
|
||
isLoading.value = false
|
||
}
|
||
}
|
||
|
||
const enrollCourse = async (courseId: number) => {
|
||
isLoading.value = true
|
||
try {
|
||
// 模拟API调用
|
||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||
|
||
const course = courses.value.find(c => c.id === courseId)
|
||
if (course) {
|
||
course.isEnrolled = true
|
||
course.progress = 0
|
||
enrolledCourses.value.push(course)
|
||
}
|
||
|
||
return { success: true, message: '报名成功' }
|
||
} catch (error) {
|
||
return { success: false, message: '报名失败' }
|
||
} finally {
|
||
isLoading.value = false
|
||
}
|
||
}
|
||
|
||
const updateProgress = async (courseId: number, progress: number) => {
|
||
const course = enrolledCourses.value.find(c => c.id === courseId)
|
||
if (course) {
|
||
course.progress = progress
|
||
}
|
||
}
|
||
|
||
return {
|
||
// 状态
|
||
courses,
|
||
currentCourse,
|
||
lessons,
|
||
enrolledCourses,
|
||
isLoading,
|
||
searchQuery,
|
||
selectedCategory,
|
||
selectedLevel,
|
||
// 计算属性
|
||
filteredCourses,
|
||
categories,
|
||
// 方法
|
||
fetchCourses,
|
||
fetchCourseById,
|
||
fetchLessons,
|
||
enrollCourse,
|
||
updateProgress
|
||
}
|
||
})
|