feat:新评论
This commit is contained in:
parent
2aab0f7152
commit
06dfacc074
@ -141,12 +141,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 课程描述 -->
|
||||
<!-- 课程描述
|
||||
<div class="course-description">
|
||||
<p>{{ course.description ||
|
||||
'本课程深度聚焦问题,让每一位教师了解并学习使用DeepSeek,结合办公自动化职业岗位标准,以实际工作任务为引导,强调课程内容的易用性和岗位要求的匹配性。课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书,技能大赛紧密结合,课程设置紧密对应实际全面共享,可为职业工作人员、在校学生、创行教师提供服务与学习支持。'
|
||||
}}</p>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- 讲师信息 -->
|
||||
<div class="instructors-section">
|
||||
@ -175,7 +175,7 @@
|
||||
<button class="tab-btn" :class="{ active: activeTab === 'intro' }"
|
||||
@click="activeTab = 'intro'">课程介绍</button>
|
||||
<button class="tab-btn" :class="{ active: activeTab === 'comments' }"
|
||||
@click="activeTab = 'comments'">评论(1251)</button>
|
||||
@click="activeTab = 'comments'">评论({{ commentsCount }})</button>
|
||||
</div>
|
||||
|
||||
<!-- 标签页内容区域 -->
|
||||
@ -222,9 +222,26 @@
|
||||
</div>
|
||||
|
||||
<div class="comment-list">
|
||||
<div class="comment-item" v-for="comment in displayComments" :key="comment.id">
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="commentsLoading" class="comments-loading">
|
||||
<p>正在加载评论...</p>
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<div v-else-if="commentsError" class="comments-error">
|
||||
<p>{{ commentsError }}</p>
|
||||
<button @click="loadCourseComments" class="retry-btn">重试</button>
|
||||
</div>
|
||||
|
||||
<!-- 无评论状态 -->
|
||||
<div v-else-if="displayComments.length === 0" class="no-comments">
|
||||
<p>暂无评论,快来发表第一条评论吧!</p>
|
||||
</div>
|
||||
|
||||
<!-- 评论列表 -->
|
||||
<div v-else class="comment-item" v-for="comment in displayComments" :key="comment.id">
|
||||
<div class="comment-avatar">
|
||||
<img :src="comment.avatar" :alt="comment.username" />
|
||||
<SafeAvatar :src="comment.avatar" :name="comment.username" :size="40" />
|
||||
</div>
|
||||
<div class="comment-content">
|
||||
<div class="comment-header">
|
||||
@ -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<CourseComment[]>([])
|
||||
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() // 加载评论
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
</style>
|
@ -142,7 +142,7 @@
|
||||
<button class="tab-btn" :class="{ active: courseActiveTab === 'subtitles' }"
|
||||
@click="courseActiveTab = 'subtitles'">字幕列表</button>
|
||||
<button class="tab-btn" :class="{ active: courseActiveTab === 'comments' }"
|
||||
@click="courseActiveTab = 'comments'">评论(1251)</button>
|
||||
@click="courseActiveTab = 'comments'">评论({{ commentsCount }})</button>
|
||||
</div>
|
||||
|
||||
<!-- 标签页内容区域 -->
|
||||
@ -258,9 +258,26 @@
|
||||
</div>
|
||||
|
||||
<div class="comment-list">
|
||||
<div class="comment-item" v-for="comment in displayComments" :key="comment.id">
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="commentsLoading" class="comments-loading">
|
||||
<p>正在加载评论...</p>
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<div v-else-if="commentsError" class="comments-error">
|
||||
<p>{{ commentsError }}</p>
|
||||
<button @click="loadCourseComments" class="retry-btn">重试</button>
|
||||
</div>
|
||||
|
||||
<!-- 无评论状态 -->
|
||||
<div v-else-if="displayComments.length === 0" class="no-comments">
|
||||
<p>暂无评论,快来发表第一条评论吧!</p>
|
||||
</div>
|
||||
|
||||
<!-- 评论列表 -->
|
||||
<div v-else class="comment-item" v-for="comment in displayComments" :key="comment.id">
|
||||
<div class="comment-avatar">
|
||||
<img :src="comment.avatar" :alt="comment.username" />
|
||||
<SafeAvatar :src="comment.avatar" :name="comment.username" :size="40" />
|
||||
</div>
|
||||
<div class="comment-content">
|
||||
<div class="comment-header">
|
||||
@ -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<CourseComment[]>([])
|
||||
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;
|
||||
}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user