From 06dfacc0749375d3083b696de9560192e49780e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=BC=A0?= <2091066548@qq.com> Date: Sat, 30 Aug 2025 03:57:24 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=96=B0=E8=AF=84=E8=AE=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/AICompanion.vue | 179 +++++++++++++++++++------- src/views/CourseExchanged.vue | 233 +++++++++++++++++++++++++++------- 2 files changed, 320 insertions(+), 92 deletions(-) diff --git a/src/views/AICompanion.vue b/src/views/AICompanion.vue index b76bdde..92eb38a 100644 --- a/src/views/AICompanion.vue +++ b/src/views/AICompanion.vue @@ -141,12 +141,12 @@ - +
@@ -175,7 +175,7 @@ + @click="activeTab = 'comments'">评论({{ commentsCount }})
@@ -222,9 +222,26 @@
-
+ +
+

正在加载评论...

+
+ + +
+

{{ commentsError }}

+ +
+ + +
+

暂无评论,快来发表第一条评论吧!

+
+ + +
- +
@@ -712,7 +729,8 @@ import { useRoute, useRouter } from 'vue-router' import { useAuth } from '@/composables/useAuth' import { useUserStore } from '@/stores/user' import { CourseApi } from '@/api/modules/course' -import type { Course, CourseSection } from '@/api/types' +import type { Course, CourseSection, CourseComment } from '@/api/types' +import SafeAvatar from '@/components/common/SafeAvatar.vue' import LoginModal from '@/components/auth/LoginModal.vue' import RegisterModal from '@/components/auth/RegisterModal.vue' @@ -976,35 +994,28 @@ const formatTotalDuration = () => { return `${hours}小时${minutes}分钟` } -const displayComments = ref([ - { - id: 1, - username: '学习者小王', - avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=50&q=80', - time: '2天前', - content: '老师讲得很详细,从零基础到实际应用都有涉及,非常适合初学者!', - likes: 23, - type: 'comment' - }, - { - id: 2, - username: 'AI爱好者', - avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=50&q=80', - time: '5天前', - content: '课程内容很实用,跟着做了几个项目,收获很大。推荐给想学AI的朋友们!', - likes: 18, - type: 'comment' - }, - { - id: 3, - username: '程序员小李', - avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=50&q=80', - time: '1周前', - content: 'DeepSeek确实是个很强大的工具,通过这个课程学会了很多实用技巧。', - likes: 31, - type: 'comment' - } -]) +// 真实评论数据 +const comments = ref([]) +const commentsLoading = ref(false) +const commentsError = ref('') + +// 为了保持兼容性,将真实评论数据转换为显示格式 +const displayComments = computed(() => { + return comments.value.map(comment => ({ + id: comment.id, + username: comment.userName, + avatar: comment.userAvatar, + time: comment.timeAgo, + content: comment.content, + likes: comment.likeCount || 0, + type: comment.isTop ? 'note' : 'comment' + })) +}) + +// 评论数量计算属性 +const commentsCount = computed(() => { + return comments.value.length +}) // 新评论内容 const newComment = ref('') @@ -1025,22 +1036,63 @@ const handleTextareaClick = (event: MouseEvent) => { } } +// 加载课程评论列表 +const loadCourseComments = async () => { + if (!courseId.value || courseId.value.trim() === '') { + commentsError.value = '课程ID无效' + console.error('课程ID无效:', courseId.value) + return + } + + try { + commentsLoading.value = true + commentsError.value = '' + + console.log('调用API获取课程评论...') + const response = await CourseApi.getCourseComments(courseId.value) + console.log('评论API响应:', response) + + if (response.code === 0 || response.code === 200) { + if (response.data && Array.isArray(response.data)) { + // 按置顶状态和时间排序:置顶评论在前,然后按时间倒序 + const sortedComments = response.data.sort((a, b) => { + // 先按置顶状态排序 + if (a.isTop !== b.isTop) { + return a.isTop ? -1 : 1 // 置顶的在前 + } + // 再按创建时间倒序排序 + return new Date(b.createTime).getTime() - new Date(a.createTime).getTime() + }) + + comments.value = sortedComments + console.log('✅ 评论数据设置成功:', comments.value) + } else { + console.log('⚠️ API返回的评论数据为空') + comments.value = [] + } + } else { + console.log('⚠️ API返回错误') + commentsError.value = response.message || '获取评论失败' + comments.value = [] + } + } catch (err) { + console.error('加载课程评论失败:', err) + commentsError.value = '获取评论失败' + comments.value = [] + } finally { + commentsLoading.value = false + } +} + // 提交评论函数 const submitComment = () => { if (newComment.value.trim()) { - const newCommentObj = { - id: Date.now(), - username: '当前用户', - avatar: 'https://via.placeholder.com/40x40/1890ff/ffffff?text=我', - time: '刚刚', - content: newComment.value, - likes: 0, - type: 'comment' - } - displayComments.value.unshift(newCommentObj) - newComment.value = '' // 这里可以调用API提交评论 - console.log('评论已提交:', newCommentObj) + console.log('提交评论:', newComment.value) + // 提交成功后重新加载评论列表 + // await CourseApi.submitComment(courseId.value, newComment.value) + // loadCourseComments() + newComment.value = '' } } @@ -1599,6 +1651,7 @@ onMounted(() => { initializeMockState() // 初始化模拟状态 loadCourseDetail() loadCourseSections() + loadCourseComments() // 加载评论 }) @@ -4569,4 +4622,36 @@ onMounted(() => { .reply-action-btn:hover { color: #1890ff; } + +/* 评论状态样式 */ +.comments-loading, .comments-error, .no-comments { + padding: 40px 20px; + text-align: center; + color: #666; + font-size: 14px; +} + +.comments-error { + color: #ff4d4f; +} + +.comments-error .retry-btn { + margin-top: 10px; + padding: 8px 16px; + background: #1890ff; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + transition: background 0.2s; +} + +.comments-error .retry-btn:hover { + background: #40a9ff; +} + +.no-comments { + color: #999; +} \ No newline at end of file diff --git a/src/views/CourseExchanged.vue b/src/views/CourseExchanged.vue index 9715f8f..31e0820 100644 --- a/src/views/CourseExchanged.vue +++ b/src/views/CourseExchanged.vue @@ -142,7 +142,7 @@ + @click="courseActiveTab = 'comments'">评论({{ commentsCount }})
@@ -258,9 +258,26 @@
-
+ +
+

正在加载评论...

+
+ + +
+

{{ commentsError }}

+ +
+ + +
+

暂无评论,快来发表第一条评论吧!

+
+ + +
- +
@@ -958,9 +975,10 @@ import { useMessage } from 'naive-ui' // import { useAuth } from '@/composables/useAuth' // import { useUserStore } from '@/stores/user' import { CourseApi } from '@/api/modules/course' -import type { Course, CourseSection } from '@/api/types' +import type { Course, CourseSection, CourseComment } from '@/api/types' import QuillEditor from '@/components/common/QuillEditor.vue' import DPlayerVideo from '@/components/course/DPlayerVideo.vue' +import SafeAvatar from '@/components/common/SafeAvatar.vue' // import LoginModal from '@/components/auth/LoginModal.vue' // import RegisterModal from '@/components/auth/RegisterModal.vue' @@ -1225,35 +1243,28 @@ const overallProgress = computed(() => { // return `${hours}小时${minutes}分钟` // } -const displayComments = ref([ - { - id: 1, - username: '学习者小王', - avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=50&q=80', - time: '2天前', - content: '老师讲得很详细,从零基础到实际应用都有涉及,非常适合初学者!', - likes: 23, - type: 'comment' - }, - { - id: 2, - username: 'AI爱好者', - avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&auto=format&fit=crop&w=50&q=80', - time: '5天前', - content: '课程内容很实用,跟着做了几个项目,收获很大。推荐给想学AI的朋友们!', - likes: 18, - type: 'comment' - }, - { - id: 3, - username: '程序员小李', - avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&auto=format&fit=crop&w=50&q=80', - time: '1周前', - content: 'DeepSeek确实是个很强大的工具,通过这个课程学会了很多实用技巧。', - likes: 31, - type: 'comment' - } -]) +// 真实评论数据 +const comments = ref([]) +const commentsLoading = ref(false) +const commentsError = ref('') + +// 为了保持兼容性,将真实评论数据转换为显示格式 +const displayComments = computed(() => { + return comments.value.map(comment => ({ + id: comment.id, + username: comment.userName, + avatar: comment.userAvatar, + time: comment.timeAgo, + content: comment.content, + likes: comment.likeCount || 0, + type: comment.isTop ? 'note' : 'comment' + })) +}) + +// 评论数量计算属性 +const commentsCount = computed(() => { + return comments.value.length +}) // 新评论内容 const newComment = ref('') @@ -1274,22 +1285,63 @@ const handleTextareaClick = (event: MouseEvent) => { } } +// 加载课程评论列表 +const loadCourseComments = async () => { + if (!courseId.value || courseId.value.trim() === '') { + commentsError.value = '课程ID无效' + console.error('课程ID无效:', courseId.value) + return + } + + try { + commentsLoading.value = true + commentsError.value = '' + + console.log('调用API获取课程评论...') + const response = await CourseApi.getCourseComments(courseId.value) + console.log('评论API响应:', response) + + if (response.code === 0 || response.code === 200) { + if (response.data && Array.isArray(response.data)) { + // 按置顶状态和时间排序:置顶评论在前,然后按时间倒序 + const sortedComments = response.data.sort((a, b) => { + // 先按置顶状态排序 + if (a.isTop !== b.isTop) { + return a.isTop ? -1 : 1 // 置顶的在前 + } + // 再按创建时间倒序排序 + return new Date(b.createTime).getTime() - new Date(a.createTime).getTime() + }) + + comments.value = sortedComments + console.log('✅ 评论数据设置成功:', comments.value) + } else { + console.log('⚠️ API返回的评论数据为空') + comments.value = [] + } + } else { + console.log('⚠️ API返回错误') + commentsError.value = response.message || '获取评论失败' + comments.value = [] + } + } catch (err) { + console.error('加载课程评论失败:', err) + commentsError.value = '获取评论失败' + comments.value = [] + } finally { + commentsLoading.value = false + } +} + // 提交评论函数 const submitComment = () => { if (newComment.value.trim()) { - const newCommentObj = { - id: Date.now(), - username: '当前用户', - avatar: 'https://via.placeholder.com/40x40/1890ff/ffffff?text=我', - time: '刚刚', - content: newComment.value, - likes: 0, - type: 'comment' - } - displayComments.value.unshift(newCommentObj) - newComment.value = '' // 这里可以调用API提交评论 - console.log('评论已提交:', newCommentObj) + console.log('提交评论:', newComment.value) + // 提交成功后重新加载评论列表 + // await CourseApi.submitComment(courseId.value, newComment.value) + // loadCourseComments() + newComment.value = '' } } @@ -1975,6 +2027,7 @@ onMounted(() => { console.log('课程详情页加载完成,课程ID:', courseId.value) loadCourseDetail() loadCourseSections() + loadCourseComments() // 加载评论 // 检查是否需要刷新 const shouldRefresh = sessionStorage.getItem('refreshCourseExchanged') @@ -2903,6 +2956,64 @@ onActivated(() => { color: #0088D1; } +/* 课程描述内容样式 */ +.course-description-content { + padding: 0; + line-height: 1.6; + color: #333; + width: 100%; +} + +/* 课程描述中的图片样式 */ +.course-description-content img { + max-width: 100%; + height: auto; + display: block; + margin: 10px auto; + border-radius: 4px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +/* 课程描述中的段落样式 */ +.course-description-content p { + margin: 16px 0; + font-size: 14px; + line-height: 1.6; + color: #666; +} + +/* 课程描述中的标题样式 */ +.course-description-content h1, +.course-description-content h2, +.course-description-content h3, +.course-description-content h4, +.course-description-content h5, +.course-description-content h6 { + margin: 20px 0 10px 0; + color: #333; + font-weight: 600; +} + +/* 课程描述中的列表样式 */ +.course-description-content ul, +.course-description-content ol { + margin: 16px 0; + padding-left: 20px; +} + +.course-description-content li { + margin: 8px 0; + line-height: 1.6; +} + +/* 默认描述样式 */ +.default-description { + color: #666; + display: flex; + justify-content: space-between; + align-items: center; +} + .course-content-detail { margin-top: 16px; padding: 16px; @@ -6046,4 +6157,36 @@ onActivated(() => { font-size: 16px; margin: 0; } + +/* 评论状态样式 */ +.comments-loading, .comments-error, .no-comments { + padding: 40px 20px; + text-align: center; + color: #666; + font-size: 14px; +} + +.comments-error { + color: #ff4d4f; +} + +.comments-error .retry-btn { + margin-top: 10px; + padding: 8px 16px; + background: #1890ff; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + transition: background 0.2s; +} + +.comments-error .retry-btn:hover { + background: #40a9ff; +} + +.no-comments { + color: #999; +} \ No newline at end of file