diff --git a/schoolNewsServ/study/src/main/java/org/xyzh/study/service/impl/SCCourseServiceImpl.java b/schoolNewsServ/study/src/main/java/org/xyzh/study/service/impl/SCCourseServiceImpl.java index 8391c0e..d9aac3c 100644 --- a/schoolNewsServ/study/src/main/java/org/xyzh/study/service/impl/SCCourseServiceImpl.java +++ b/schoolNewsServ/study/src/main/java/org/xyzh/study/service/impl/SCCourseServiceImpl.java @@ -443,7 +443,15 @@ public class SCCourseServiceImpl implements SCCourseService { @Override public ResultDomain incrementLearnCount(String courseID) { // TODO: 实现增加课程学习人数 - return null; + ResultDomain resultDomain = new ResultDomain<>(); + int i = courseMapper.incrementLearnCount(courseID,1); + if (i > 0) { + TbCourse course = courseMapper.selectByCourseId(courseID); + resultDomain.success("开始学习", course); + return resultDomain; + } + resultDomain.fail("报名失败"); + return resultDomain; } @Override diff --git a/schoolNewsServ/study/src/main/java/org/xyzh/study/service/impl/SCLearningRecordServiceImpl.java b/schoolNewsServ/study/src/main/java/org/xyzh/study/service/impl/SCLearningRecordServiceImpl.java index 442d76c..49b4d44 100644 --- a/schoolNewsServ/study/src/main/java/org/xyzh/study/service/impl/SCLearningRecordServiceImpl.java +++ b/schoolNewsServ/study/src/main/java/org/xyzh/study/service/impl/SCLearningRecordServiceImpl.java @@ -69,8 +69,8 @@ public class SCLearningRecordServiceImpl implements LearningRecordService { resultDomain.fail("资源ID不能为空"); return resultDomain; } - if (learningRecord.getResourceType() == 2 && (learningRecord.getCourseID() == null || learningRecord.getChapterID() == null || learningRecord.getNodeID() == null)) { - resultDomain.fail("课程信息不能为空"); + if (learningRecord.getResourceType() == 2 && learningRecord.getCourseID() == null) { + resultDomain.fail("课程ID不能为空"); return resultDomain; } List records = learningRecordMapper.selectLearningRecords(learningRecord); diff --git a/schoolNewsWeb/src/views/admin/manage/study/StudyRecordsView.vue b/schoolNewsWeb/src/views/admin/manage/study/StudyRecordsView.vue index 13755ac..4b45a3c 100644 --- a/schoolNewsWeb/src/views/admin/manage/study/StudyRecordsView.vue +++ b/schoolNewsWeb/src/views/admin/manage/study/StudyRecordsView.vue @@ -273,6 +273,7 @@ function getRankClass(index: number): string { .rankings-section { .ranking-card { + height: 100%; .card-header { font-weight: 600; font-size: 16px; diff --git a/schoolNewsWeb/src/views/public/article/components/ArticleShow.vue b/schoolNewsWeb/src/views/public/article/components/ArticleShow.vue index 8bc7dad..f8f8553 100644 --- a/schoolNewsWeb/src/views/public/article/components/ArticleShow.vue +++ b/schoolNewsWeb/src/views/public/article/components/ArticleShow.vue @@ -484,8 +484,9 @@ function initVideoListeners() { const videos = articleContent.querySelectorAll('video'); if (videos.length === 0) { - // 没有视频,默认阅读即完成 + // 没有视频,默认阅读即完成(不emit事件,依赖父组件的滚动检测) hasVideoCompleted.value = true; + console.log('ℹ️ 文章中没有视频,完成条件:滚动到底部'); return; } diff --git a/schoolNewsWeb/src/views/public/course/components/CourseDetail.vue b/schoolNewsWeb/src/views/public/course/components/CourseDetail.vue index 93fba6a..d8fc8ff 100644 --- a/schoolNewsWeb/src/views/public/course/components/CourseDetail.vue +++ b/schoolNewsWeb/src/views/public/course/components/CourseDetail.vue @@ -312,11 +312,11 @@ async function handleCollect() { try { if (isCollected.value) { // 取消收藏 - const res = await userCollectionApi.removeCollection( - userInfo.value.id, - CollectionType.COURSE, - props.courseId - ); + const res = await userCollectionApi.removeCollection({ + userID: userInfo.value.id, + collectionType: CollectionType.COURSE, + collectionID: props.courseId + }); if (res.success) { isCollected.value = false; ElMessage.success('已取消收藏'); @@ -360,7 +360,8 @@ async function handleStartLearning() { await learningRecordApi.createRecord({ userID: userInfo.value.id, resourceType: 2, // 课程 - resourceID: props.courseId, + courseID: props.courseId, // 使用courseID而不是resourceID + resourceID: props.courseId, // 保留resourceID以兼容 progress: 0, duration: 0, isComplete: false diff --git a/schoolNewsWeb/src/views/public/course/components/CourseLearning.vue b/schoolNewsWeb/src/views/public/course/components/CourseLearning.vue index 558e61d..72609dd 100644 --- a/schoolNewsWeb/src/views/public/course/components/CourseLearning.vue +++ b/schoolNewsWeb/src/views/public/course/components/CourseLearning.vue @@ -98,10 +98,10 @@
-
@@ -195,7 +195,7 @@ import { Download, InfoFilled } from '@element-plus/icons-vue'; -import { ArticleShowView } from '@/views/public/article'; +import { ArticleShow } from '@/views/public/article'; import { courseApi } from '@/apis/study'; import { learningRecordApi, learningHistoryApi } from '@/apis/study'; import { resourceApi } from '@/apis/resource'; @@ -516,6 +516,12 @@ async function loadNodeContent() { if (!activeChapters.value.includes(currentChapterIndex.value)) { activeChapters.value.push(currentChapterIndex.value); } + + // 等待DOM更新后,检查是否需要自动标记完成(针对内容太短没有滚动条的情况) + await nextTick(); + setTimeout(() => { + checkAutoComplete(); + }, 500); // 延迟500ms,等待ArticleShow初始化完成 } // 选择节点 @@ -706,6 +712,48 @@ function hasScrollbar(): boolean { return contentAreaRef.value.scrollHeight > contentAreaRef.value.clientHeight; } +// 检查是否需要自动标记完成(针对内容太短没有滚动条的情况) +async function checkAutoComplete() { + // 如果当前节点已完成,跳过 + if (isCurrentNodeCompleted.value) { + return; + } + + if (!currentNode.value) return; + + // 对富文本类型(nodeType === 1)立即检查 + if (currentNode.value.nodeType === 1) { + if (!hasScrollbar()) { + console.log('📄 富文本内容较短无需滚动,自动标记为完成'); + const nodeKey = `${currentChapterIndex.value}-${currentNodeIndex.value}`; + await markNodeComplete(nodeKey); + } + } + + // 对文章类型(nodeType === 0),延迟检查(等待ArticleShow初始化视频监听器) + // 如果文章有视频,会在视频播放完成时emit事件,不会走到这里 + // 如果文章没有视频且没有滚动条,需要自动标记完成 + if (currentNode.value.nodeType === 0) { + // 保存当前节点信息,避免延迟后节点已改变 + const chapterIdx = currentChapterIndex.value; + const nodeIdx = currentNodeIndex.value; + const nodeKey = `${chapterIdx}-${nodeIdx}`; + + // 延迟1秒再检查,给ArticleShow足够时间初始化 + setTimeout(async () => { + // 再次检查是否已完成(可能已通过视频完成事件标记) + // 且确认当前还在同一个节点 + if (!completedNodes.value.has(nodeKey) && + currentChapterIndex.value === chapterIdx && + currentNodeIndex.value === nodeIdx && + !hasScrollbar()) { + console.log('📄 文章内容较短无需滚动且无视频,自动标记为完成'); + await markNodeComplete(nodeKey); + } + }, 1000); + } +} + // 处理内容区域滚动 function handleContentScroll(event: Event) { const target = event.target as HTMLElement;