143 lines
3.7 KiB
TypeScript
143 lines
3.7 KiB
TypeScript
// stores/course.ts
|
|
import { defineStore } from 'pinia'
|
|
import { courseApi } from '@/api/modules/course'
|
|
import type { ICourseDetail, ICatalogue, IChapter, IVipInfo } from '@/types/course'
|
|
|
|
interface CourseState {
|
|
currentCourse: ICourseDetail | null
|
|
catalogueList: ICatalogue[]
|
|
currentCatalogueIndex: number
|
|
chapterList: IChapter[]
|
|
userVip: IVipInfo | null
|
|
learningProgress: number
|
|
}
|
|
|
|
export const useCourseStore = defineStore('course', {
|
|
state: (): CourseState => ({
|
|
currentCourse: null,
|
|
catalogueList: [],
|
|
currentCatalogueIndex: 0,
|
|
chapterList: [],
|
|
userVip: null,
|
|
learningProgress: 0,
|
|
}),
|
|
|
|
getters: {
|
|
/**
|
|
* 获取当前选中的目录
|
|
*/
|
|
currentCatalogue: (state): ICatalogue | null => {
|
|
if (state.catalogueList.length === 0) return null
|
|
return state.catalogueList[state.currentCatalogueIndex] || null
|
|
},
|
|
|
|
/**
|
|
* 判断当前目录是否已购买
|
|
*/
|
|
isCurrentCataloguePurchased: (state): boolean => {
|
|
const catalogue = state.catalogueList[state.currentCatalogueIndex]
|
|
return catalogue ? catalogue.isBuy === 1 : false
|
|
},
|
|
|
|
/**
|
|
* 判断用户是否为VIP
|
|
*/
|
|
isVip: (state): boolean => {
|
|
return state.userVip !== null
|
|
},
|
|
},
|
|
|
|
actions: {
|
|
/**
|
|
* 获取课程详情
|
|
* @param courseId 课程ID
|
|
*/
|
|
async fetchCourseDetail(courseId: number) {
|
|
try {
|
|
const res = await courseApi.getCourseDetail(courseId)
|
|
if (res.code === 0 && res.data) {
|
|
this.currentCourse = res.data.course
|
|
this.catalogueList = res.data.catalogues || []
|
|
|
|
// 计算学习进度
|
|
if (this.catalogueList.length > 0) {
|
|
const totalProgress = this.catalogueList.reduce((sum, cat) => sum + cat.completion, 0)
|
|
this.learningProgress = Number((totalProgress / this.catalogueList.length).toFixed(2))
|
|
} else {
|
|
this.learningProgress = 0
|
|
}
|
|
}
|
|
return res
|
|
} catch (error) {
|
|
console.error('获取课程详情失败:', error)
|
|
throw error
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 切换目录
|
|
* @param index 目录索引
|
|
*/
|
|
async switchCatalogue(index: number) {
|
|
if (index < 0 || index >= this.catalogueList.length) {
|
|
console.warn('目录索引超出范围')
|
|
return
|
|
}
|
|
|
|
this.currentCatalogueIndex = index
|
|
const catalogue = this.catalogueList[index]
|
|
|
|
// 获取该目录的章节列表
|
|
await this.fetchChapterList(catalogue.id)
|
|
},
|
|
|
|
/**
|
|
* 获取章节列表
|
|
* @param catalogueId 目录ID
|
|
*/
|
|
async fetchChapterList(catalogueId: number) {
|
|
try {
|
|
const res = await courseApi.getCatalogueChapterList(catalogueId)
|
|
if (res.code === 0) {
|
|
this.chapterList = res.chapterList || []
|
|
}
|
|
return res
|
|
} catch (error) {
|
|
console.error('获取章节列表失败:', error)
|
|
this.chapterList = []
|
|
throw error
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 检查用户VIP权益
|
|
* @param courseId 课程ID
|
|
*/
|
|
async checkVipStatus(courseId: number) {
|
|
try {
|
|
const res = await courseApi.checkCourseVip(courseId)
|
|
if (res.code === 0) {
|
|
this.userVip = res.userVip || null
|
|
}
|
|
return res
|
|
} catch (error) {
|
|
console.error('检查VIP权益失败:', error)
|
|
this.userVip = null
|
|
throw error
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 重置课程状态
|
|
*/
|
|
resetCourseState() {
|
|
this.currentCourse = null
|
|
this.catalogueList = []
|
|
this.currentCatalogueIndex = 0
|
|
this.chapterList = []
|
|
this.userVip = null
|
|
this.learningProgress = 0
|
|
},
|
|
},
|
|
})
|