更新:课程详情的初步代码

This commit is contained in:
2025-11-14 15:13:21 +08:00
parent e7e0597026
commit 21b03635a2
25 changed files with 4958 additions and 12 deletions

191
hooks/useComment.ts Normal file
View File

@@ -0,0 +1,191 @@
// hooks/useComment.ts
/**
* 评论相关的可复用逻辑
*/
import { ref } from 'vue'
import { courseApi } from '@/api/modules/course'
import { bookApi } from '@/api/modules/book'
import type { IComment } from '@/types/comment'
export function useComment(type: 'course' | 'book') {
const commentList = ref<IComment[]>([])
const loading = ref(false)
const hasMore = ref(true)
const currentPage = ref(0)
/**
* 加载评论列表
*/
const loadComments = async (relationId: number, userId: number, limit: number = 15) => {
if (loading.value) return
try {
loading.value = true
currentPage.value++
let res: any
if (type === 'course') {
res = await courseApi.getCourseComments(relationId, currentPage.value, limit, userId)
} else {
res = await bookApi.getBookComments(relationId, currentPage.value, limit)
}
if (res.code === 0 && res.page) {
const newComments = res.page.records.map((comment: IComment) => {
// 处理图片
if (comment.images) {
comment.imgList = comment.images.split(',')
} else {
comment.imgList = []
}
// 处理子评论
if (comment.children && comment.children.length > 0) {
comment.Bchildren = comment.children.slice(0, 5)
} else {
comment.Bchildren = []
}
return comment
})
commentList.value = [...commentList.value, ...newComments]
hasMore.value = res.page.pages > currentPage.value
}
} catch (error) {
console.error('加载评论失败:', error)
} finally {
loading.value = false
}
}
/**
* 添加评论
*/
const addComment = async (
relationId: number,
userId: number,
content: string,
images: string[],
parentComment?: IComment
) => {
try {
let res: any
if (type === 'course') {
res = await courseApi.addCourseComment({
type: 0,
courseId: relationId,
chapterId: '',
pid: parentComment?.id || 0,
userId,
forUserId: parentComment?.user.id || userId,
content,
images: images.join(',')
})
} else {
res = await bookApi.insertComment(relationId, content, parentComment?.id || 0)
}
if (res.code === 0) {
const newComment = type === 'course' ? res.courseGuestbook : res.bookComment
if (newComment) {
newComment.imgList = newComment.images ? newComment.images.split(',') : []
newComment.children = []
newComment.Bchildren = []
if (parentComment) {
// 回复评论
const parentIndex = commentList.value.findIndex(c => c.id === parentComment.id)
if (parentIndex !== -1) {
commentList.value[parentIndex].children.unshift(newComment)
commentList.value[parentIndex].Bchildren.unshift(newComment)
}
} else {
// 一级评论
commentList.value.unshift(newComment)
}
}
uni.showToast({ title: '发布成功', icon: 'success' })
return true
}
return false
} catch (error) {
console.error('添加评论失败:', error)
uni.showToast({ title: '发布失败', icon: 'none' })
return false
}
}
/**
* 点赞/取消点赞
*/
const toggleLike = async (commentId: number, userId: number) => {
try {
// 查找评论
let targetComment: IComment | null = null
for (const comment of commentList.value) {
if (comment.id === commentId) {
targetComment = comment
break
}
for (const child of comment.children) {
if (child.id === commentId) {
targetComment = child
break
}
}
if (targetComment) break
}
if (!targetComment) return
// 调用API
if (type === 'course') {
if (targetComment.support) {
await courseApi.unlikeComment(userId, commentId)
targetComment.support = false
targetComment.supportCount--
} else {
await courseApi.likeComment(userId, commentId)
targetComment.support = true
targetComment.supportCount++
}
} else {
if (targetComment.support) {
await bookApi.unlikeComment(commentId)
targetComment.support = false
targetComment.supportCount--
} else {
await bookApi.likeComment(commentId)
targetComment.support = true
targetComment.supportCount++
}
}
} catch (error) {
console.error('点赞失败:', error)
}
}
/**
* 重置评论列表
*/
const resetComments = () => {
commentList.value = []
currentPage.value = 0
hasMore.value = true
}
return {
commentList,
loading,
hasMore,
loadComments,
addComment,
toggleLike,
resetComments
}
}

98
hooks/useCourse.ts Normal file
View File

@@ -0,0 +1,98 @@
// hooks/useCourse.ts
/**
* 课程相关的可复用逻辑
*/
import { ref } from 'vue'
import { courseApi } from '@/api/modules/course'
import type { ICourseDetail, ICatalogue, IChapter, IVipInfo } from '@/types/course'
export function useCourse() {
const loading = ref(false)
const courseDetail = ref<ICourseDetail | null>(null)
const catalogueList = ref<ICatalogue[]>([])
const chapterList = ref<IChapter[]>([])
const userVip = ref<IVipInfo | null>(null)
/**
* 获取课程详情
*/
const fetchCourseDetail = async (courseId: number) => {
try {
loading.value = true
const res = await courseApi.getCourseDetail(courseId)
if (res.code === 0 && res.data) {
courseDetail.value = res.data.course
catalogueList.value = res.data.catalogues || []
return res.data
}
} catch (error) {
console.error('获取课程详情失败:', error)
throw error
} finally {
loading.value = false
}
}
/**
* 获取章节列表
*/
const fetchChapterList = async (catalogueId: number) => {
try {
const res = await courseApi.getCatalogueChapterList(catalogueId)
if (res.code === 0) {
chapterList.value = res.chapterList || []
return res.chapterList
}
} catch (error) {
console.error('获取章节列表失败:', error)
chapterList.value = []
throw error
}
}
/**
* 检查VIP状态
*/
const checkVipStatus = async (courseId: number) => {
try {
const res = await courseApi.checkCourseVip(courseId)
if (res.code === 0) {
userVip.value = res.userVip || null
return res.userVip
}
} catch (error) {
console.error('检查VIP状态失败:', error)
userVip.value = null
throw error
}
}
/**
* 领取免费课程
*/
const getFreeCourse = async (catalogueId: number) => {
try {
const res = await courseApi.startStudyForMF(catalogueId)
if (res.code === 0) {
uni.showToast({ title: '领取成功', icon: 'success' })
return true
}
return false
} catch (error) {
console.error('领取免费课程失败:', error)
throw error
}
}
return {
loading,
courseDetail,
catalogueList,
chapterList,
userVip,
fetchCourseDetail,
fetchChapterList,
checkVipStatus,
getFreeCourse
}
}