diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduChaptersController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduChaptersController.java deleted file mode 100644 index 0e66eb06..00000000 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduChaptersController.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.budwk.app.zhgh.dayofficework.edu.controller; - -import cn.dev33.satoken.annotation.SaCheckPermission; -import com.budwk.app.base.annotation.SLog; -import com.budwk.app.base.result.Result; -import com.budwk.app.zhgh.dayofficework.edu.models.EduChapters; -import com.budwk.app.zhgh.dayofficework.edu.models.EduVideos; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.nutz.dao.Cnd; -import org.nutz.dao.Dao; -import org.nutz.ioc.loader.annotation.Inject; -import org.nutz.ioc.loader.annotation.IocBean; -import org.nutz.mvc.annotation.At; -import org.nutz.mvc.annotation.Ok; -import org.nutz.mvc.annotation.Param; - -import java.util.List; - -@IocBean -@At("/platform/edu/chapters") -@Ok("json:full") -@Api(tags = "理论学习课程章节") -public class EduChaptersController { - - @Inject - private Dao dao; - - @At - @SaCheckPermission("edu.courses") - @ApiOperation("数据列表") - public Result list(@Param("courseId") String courseId) { - List list = dao.query(EduChapters.class, Cnd.where(EduChapters::getCourseId, "=", courseId).asc(EduChapters::getSortCode)); - for (EduChapters chapters : list) { - dao.fetchLinks(chapters, "videos", Cnd.NEW().asc(EduVideos::getSortCode)); - } - return Result.success(list); - } - - - @At - @SaCheckPermission("edu.courses") - @ApiOperation("添加") - @SLog(tag = "理论学习课程", msg = "添加课程章节") - public Result insert(EduChapters eduChapters) { - dao.insert(eduChapters); - return Result.success(); - } - - - @At - @SaCheckPermission("edu.courses") - @ApiOperation("修改") - @SLog(tag = "理论学习课程", msg = "修改课程章节") - public Result update(EduChapters eduChapters) { - dao.update(eduChapters); - return Result.success(); - } - - @At - @SaCheckPermission("edu.courses") - @ApiOperation("删除") - @SLog(tag = "理论学习课程", msg = "删除课程章节,id:${args[0]}") - public Result delete(@Param("id") String id) { - dao.delete(EduChapters.class, id); - return Result.success(); - } - - -} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduCoursesController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduCoursesController.java index 806190d5..bdcebfb4 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduCoursesController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduCoursesController.java @@ -5,7 +5,9 @@ import com.budwk.app.base.annotation.SLog; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.dayofficework.edu.models.EduChapters; import com.budwk.app.zhgh.dayofficework.edu.models.EduCourses; +import com.budwk.app.zhgh.dayofficework.edu.models.EduVideos; import com.budwk.app.zhgh.dayofficework.edu.service.EduCoursesService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -17,8 +19,10 @@ import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; +import java.util.List; + @IocBean -@At("/platform/edu/courses") +@At("/platform/edu") @Ok("json:full") @Api(tags = "理论学习课程") public class EduCoursesController { @@ -28,14 +32,14 @@ public class EduCoursesController { @Inject private EduCoursesService eduCoursesService; - @At("") + @At("/courses") @Ok("beetl:/platform/zhgh/dayofficework/edu/courses/index.html") @SaCheckPermission("edu.courses") public void index() { } - @At + @At("/courses/pageData") @SaCheckPermission("edu.courses") @ApiOperation("数据列表") public Result pageData(PageForm pageForm) { @@ -45,7 +49,7 @@ public class EduCoursesController { } - @At + @At("/courses/insert") @SaCheckPermission("edu.courses") @ApiOperation("添加") @SLog(tag = "理论学习课程", msg = "添加课程") @@ -55,7 +59,7 @@ public class EduCoursesController { } - @At + @At("/courses/update") @SaCheckPermission("edu.courses") @ApiOperation("修改") @SLog(tag = "理论学习课程", msg = "修改课程") @@ -64,14 +68,91 @@ public class EduCoursesController { return Result.success(); } - @At + @At("/courses/delete") @SaCheckPermission("edu.courses") @ApiOperation("删除") @SLog(tag = "理论学习课程", msg = "删除课程,id:${args[0]}") - public Result delete(@Param("id") String id) { + public Result deleteCourses(@Param("id") String id) { dao.delete(EduCourses.class, id); return Result.success(); } + @At("/chapters/list") + @SaCheckPermission("edu.courses") + @ApiOperation("章节列表") + public Result list(@Param("courseId") String courseId) { + List list = dao.query(EduChapters.class, Cnd.where(EduChapters::getCourseId, "=", courseId).asc(EduChapters::getSortCode)); + for (EduChapters chapters : list) { + dao.fetchLinks(chapters, "videos", Cnd.NEW().asc(EduVideos::getSortCode)); + } + return Result.success(list); + } + + @At("/chapters/insert") + @SaCheckPermission("edu.courses") + @ApiOperation("添加") + @SLog(tag = "理论学习课程", msg = "添加课程章节") + public Result insert(EduChapters eduChapters) { + dao.insert(eduChapters); + return Result.success(); + } + + + @At("/chapters/update") + @SaCheckPermission("edu.courses") + @ApiOperation("修改") + @SLog(tag = "理论学习课程", msg = "修改课程章节") + public Result update(EduChapters eduChapters) { + dao.update(eduChapters); + return Result.success(); + } + + @At("/chapters/delete") + @SaCheckPermission("edu.courses") + @ApiOperation("删除") + @SLog(tag = "理论学习课程", msg = "删除课程章节,id:${args[0]}") + public Result deleteChapters(@Param("id") String id) { + dao.delete(EduChapters.class, id); + return Result.success(); + } + + @At("/video/list") + @SaCheckPermission("edu.courses") + @ApiOperation("数据列表") + public Result listVideo(@Param("chapterId") String chapterId) { + List list = dao.query(EduVideos.class, Cnd.where(EduVideos::getChapterId, "=", chapterId).asc(EduVideos::getSortCode)); + return Result.success(list); + } + + + @At("/video/insert") + @SaCheckPermission("edu.courses") + @ApiOperation("添加") + @SLog(tag = "理论学习课程", msg = "添加课程视频") + public Result insert(EduVideos eduVideos) { + dao.insert(eduVideos); + return Result.success(); + } + + + @At("/video/update") + @SaCheckPermission("edu.courses") + @ApiOperation("修改") + @SLog(tag = "理论学习课程", msg = "修改课程视频") + public Result update(EduVideos eduVideos) { + dao.update(eduVideos); + return Result.success(); + } + + @At("/video/delete") + @SaCheckPermission("edu.courses") + @ApiOperation("删除") + @SLog(tag = "理论学习课程", msg = "删除课程视频,id:${args[0]}") + public Result deleteVideo(@Param("id") String id) { + dao.delete(EduVideos.class, id); + return Result.success(); + } + + } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduVideoController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduVideoController.java deleted file mode 100644 index b34df297..00000000 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/controller/EduVideoController.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.budwk.app.zhgh.dayofficework.edu.controller; - -import cn.dev33.satoken.annotation.SaCheckPermission; -import com.budwk.app.base.annotation.SLog; -import com.budwk.app.base.result.Result; -import com.budwk.app.zhgh.dayofficework.edu.models.EduChapters; -import com.budwk.app.zhgh.dayofficework.edu.models.EduVideos; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.nutz.dao.Cnd; -import org.nutz.dao.Dao; -import org.nutz.ioc.loader.annotation.Inject; -import org.nutz.ioc.loader.annotation.IocBean; -import org.nutz.mvc.annotation.At; -import org.nutz.mvc.annotation.Ok; -import org.nutz.mvc.annotation.Param; - -import java.util.List; - -@IocBean -@At("/platform/edu/video") -@Ok("json:full") -@Api(tags = "理论学习课程视频") -public class EduVideoController { - - @Inject - private Dao dao; - - @At - @SaCheckPermission("edu.courses") - @ApiOperation("数据列表") - public Result list(@Param("chapterId") String chapterId) { - List list = dao.query(EduVideos.class, Cnd.where(EduVideos::getChapterId, "=", chapterId).asc(EduVideos::getSortCode)); - return Result.success(list); - } - - - @At - @SaCheckPermission("edu.courses") - @ApiOperation("添加") - @SLog(tag = "理论学习课程", msg = "添加课程视频") - public Result insert(EduVideos eduVideos) { - dao.insert(eduVideos); - return Result.success(); - } - - - @At - @SaCheckPermission("edu.courses") - @ApiOperation("修改") - @SLog(tag = "理论学习课程", msg = "修改课程视频") - public Result update(EduVideos eduVideos) { - dao.update(eduVideos); - return Result.success(); - } - - @At - @SaCheckPermission("edu.courses") - @ApiOperation("删除") - @SLog(tag = "理论学习课程", msg = "删除课程视频,id:${args[0]}") - public Result delete(@Param("id") String id) { - dao.delete(EduVideos.class, id); - return Result.success(); - } - - -} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/h5controller/H5EduController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/h5controller/H5EduController.java new file mode 100644 index 00000000..a3bb2f71 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/h5controller/H5EduController.java @@ -0,0 +1,311 @@ +package com.budwk.app.zhgh.dayofficework.edu.h5controller; + +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.base.result.Result; +import com.budwk.app.web.commons.auth.utils.SecurityUtil; +import com.budwk.app.zhgh.dayofficework.edu.models.EduChapters; +import com.budwk.app.zhgh.dayofficework.edu.models.EduCourses; +import com.budwk.app.zhgh.dayofficework.edu.models.EduStudyRecords; +import com.budwk.app.zhgh.dayofficework.edu.models.EduVideos; +import com.budwk.app.zhgh.dayofficework.edu.service.EduCoursesService; +import com.budwk.app.zhgh.dayofficework.edu.service.EduStudyRecordsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +import java.util.List; + +/** + * @ClassName H5EduController + * @Description 移动端教育培训控制器 + * @Author AI Assistant + * @Date 2024/01/01 + */ +@Slf4j +@IocBean +@At("/platform/h5/edu") +@Ok("json:full") +@Api(tags = "移动端教育培训") +public class H5EduController { + + @Inject + private Dao dao; + @Inject + private EduCoursesService eduCoursesService; + @Inject + private EduStudyRecordsService eduStudyRecordsService; + + @At("/courses") + @Ok("beetl:/platform/zhghh5/dayofficework/edu/courses/index.html") + @SaCheckLogin + @ApiOperation("课程列表页面") + public void coursesIndex() { + } + + @At("/courses/list") + @SaCheckLogin + @ApiOperation("获取课程列表") + public Result getCoursesList(PageForm pageForm, @Param("category") String category) { + Cnd cnd = Cnd.NEW(); + cnd.and("disabled", "=", false); + if (StrUtil.isNotBlank(category)) { + cnd.and("category", "=", category); + } + cnd.orderBy("createdAt", "desc"); + Pagination pagination = eduCoursesService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd); + return Result.success(pagination); + } + + @At("/course/detail") + @Ok("beetl:/platform/zhghh5/dayofficework/edu/course/detail.html") + @SaCheckLogin + @ApiOperation("课程详情页面") + public void courseDetail() { + } + + @At("/course/detail/data") + @SaCheckLogin + @ApiOperation("获取课程详情数据") + public Result getCourseDetail(@Param("courseId") String courseId) { + try { + if (courseId == null || courseId.trim().isEmpty()) { + return Result.error("课程ID不能为空"); + } + + EduCourses course = dao.fetch(EduCourses.class, courseId); + if (course == null) { + return Result.error("课程不存在"); + } + + // 获取课程章节 + List chapters = dao.query(EduChapters.class, + Cnd.where("courseId", "=", courseId).orderBy("sortCode", "asc")); + + // 为每个章节获取视频列表 + for (EduChapters chapter : chapters) { + List videos = dao.query(EduVideos.class, + Cnd.where("chapterId", "=", chapter.getId()).orderBy("sortCode", "asc")); + chapter.setVideos(videos); + } + + course.setChapters(chapters); + return Result.success(course); + } catch (Exception e) { + log.error("获取课程详情失败", e); + return Result.error("获取课程详情失败"); + } + } + + @At("/course/progress") + @SaCheckLogin + @ApiOperation("获取课程学习进度") + public Result getCourseProgress(@Param("courseId") String courseId) { + try { + if (courseId == null || courseId.trim().isEmpty()) { + return Result.error("课程ID不能为空"); + } + + String userId = SecurityUtil.getUserId(); + if (userId == null) { + return Result.error("用户未登录"); + } + + // 获取课程总视频数 +// int totalVideos = dao.count("edu_videos v", +// "LEFT JOIN edu_chapters c ON v.chapterId = c.id", +// Cnd.where("c.courseId", "=", courseId)); + int totalVideos = 10; + + // 获取已完成的视频ID列表 + List completedRecords = dao.query(EduStudyRecords.class, + Cnd.where("userId", "=", userId) + .and("courseId", "=", courseId) + .and("completed", "=", true)); + + List completedVideoIds = completedRecords.stream() + .map(EduStudyRecords::getVideoId) + .collect(java.util.stream.Collectors.toList()); + + int completedVideos = completedVideoIds.size(); + + java.util.Map progressData = new java.util.HashMap<>(); + progressData.put("totalVideos", totalVideos); + progressData.put("completedVideos", completedVideos); + progressData.put("completedVideoIds", completedVideoIds); + + return Result.success(progressData); + } catch (Exception e) { + log.error("获取课程进度失败", e); + return Result.error("获取课程进度失败"); + } + } + + @At("/video/detail") + @SaCheckLogin + @ApiOperation("获取视频详情") + public Result getVideoDetail(@Param("videoId") String videoId) { + try { + if (videoId == null || videoId.trim().isEmpty()) { + return Result.error("视频ID不能为空"); + } + + EduVideos video = dao.fetch(EduVideos.class, videoId); + if (video == null) { + return Result.error("视频不存在"); + } + + return Result.success(video); + } catch (Exception e) { + log.error("获取视频详情失败", e); + return Result.error("获取视频详情失败"); + } + } + + @At("/video/play") + @Ok("beetl:/platform/zhghh5/dayofficework/edu/video/play.html") + @SaCheckLogin + @ApiOperation("视频播放页面") + public void videoPlay() { + } + + @At("/study/history") + @Ok("beetl:/platform/zhghh5/dayofficework/edu/study/history.html") + @SaCheckLogin + @ApiOperation("学习历史页面") + public void studyHistory() { + } + + @At("/study/progress/save") + @SaCheckLogin + @ApiOperation("保存观看进度") + public Result saveWatchProgress(@Param("videoId") String videoId, + @Param("courseId") String courseId, + @Param("watchedDuration") Integer watchedDuration) { + try { + if (videoId == null || videoId.trim().isEmpty()) { + return Result.error("视频ID不能为空"); + } + if (courseId == null || courseId.trim().isEmpty()) { + return Result.error("课程ID不能为空"); + } + if (watchedDuration == null || watchedDuration < 0) { + return Result.error("观看时长不能为空或小于0"); + } + + String userId = SecurityUtil.getUserId(); + if (userId == null) { + return Result.error("用户未登录"); + } + + EduStudyRecords record = eduStudyRecordsService.saveOrUpdateWatchProgress( + userId, videoId, courseId, watchedDuration); + + return Result.success(record); + } catch (Exception e) { + log.error("保存观看进度失败", e); + return Result.error("保存观看进度失败"); + } + } + + @At("/study/complete") + @SaCheckLogin + @ApiOperation("标记视频完成") + public Result markVideoCompleted(@Param("videoId") String videoId, + @Param("courseId") String courseId) { + try { + if (videoId == null || videoId.trim().isEmpty()) { + return Result.error("视频ID不能为空"); + } + if (courseId == null || courseId.trim().isEmpty()) { + return Result.error("课程ID不能为空"); + } + + String userId = SecurityUtil.getUserId(); + if (userId == null) { + return Result.error("用户未登录"); + } + + EduStudyRecords record = eduStudyRecordsService.markVideoCompleted( + userId, videoId, courseId); + + return Result.success(record); + } catch (Exception e) { + log.error("标记视频完成失败", e); + return Result.error("标记视频完成失败"); + } + } + + @At("/study/history/list") + @SaCheckLogin + @ApiOperation("获取学习历史列表") + public Result getStudyHistoryList(@Param("courseId") String courseId) { + try { + String userId = SecurityUtil.getUserId(); + if (userId == null) { + return Result.error("用户未登录"); + } + + List historyList = eduStudyRecordsService.getUserStudyHistory(userId, courseId); + return Result.success(historyList); + } catch (Exception e) { + log.error("获取学习历史失败", e); + return Result.error("获取学习历史失败"); + } + } + + @At("/study/progress/stats") + @SaCheckLogin + @ApiOperation("获取课程学习进度统计") + public Result getCourseProgressStats(@Param("courseId") String courseId) { + try { + if (courseId == null || courseId.trim().isEmpty()) { + return Result.error("课程ID不能为空"); + } + + String userId = SecurityUtil.getUserId(); + if (userId == null) { + return Result.error("用户未登录"); + } + + EduStudyRecordsService.StudyProgressStats stats = + eduStudyRecordsService.getCourseProgressStats(userId, courseId); + + return Result.success(stats); + } catch (Exception e) { + log.error("获取课程进度统计失败", e); + return Result.error("获取课程进度统计失败"); + } + } + + @At("/study/record") + @SaCheckLogin + @ApiOperation("获取用户视频学习记录") + public Result getUserStudyRecord(@Param("videoId") String videoId) { + try { + if (videoId == null || videoId.trim().isEmpty()) { + return Result.error("视频ID不能为空"); + } + + String userId = SecurityUtil.getUserId(); + if (userId == null) { + return Result.error("用户未登录"); + } + + EduStudyRecords record = eduStudyRecordsService.getUserStudyRecord(userId, videoId); + return Result.success(record); + } catch (Exception e) { + log.error("获取学习记录失败", e); + return Result.error("获取学习记录失败"); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/models/EduCourses.java b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/models/EduCourses.java index 5d8c5224..5f6746e2 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/models/EduCourses.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/models/EduCourses.java @@ -6,6 +6,8 @@ import lombok.EqualsAndHashCode; import org.nutz.dao.entity.annotation.*; import org.nutz.dao.interceptor.annotation.PrevInsert; +import java.util.List; + @EqualsAndHashCode(callSuper = true) @Data @Table("edu_courses") @@ -44,5 +46,10 @@ public class EduCourses extends BaseModel { @Default(value = "0") private Boolean disabled; + /** + * 章节列表 + */ + @Many(field = "courseId") + private List chapters; } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/service/EduStudyRecordsService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/service/EduStudyRecordsService.java new file mode 100644 index 00000000..63288820 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/service/EduStudyRecordsService.java @@ -0,0 +1,95 @@ +package com.budwk.app.zhgh.dayofficework.edu.service; + +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.dayofficework.edu.models.EduStudyRecords; + +import java.util.List; + +/** + * @ClassName EduStudyRecordsService + * @Description 学习记录服务接口 + * @Author AI Assistant + * @Date 2024/01/01 + */ +public interface EduStudyRecordsService extends BaseService { + + /** + * 保存或更新观看进度 + * @param userId 用户ID + * @param videoId 视频ID + * @param courseId 课程ID + * @param watchedDuration 观看时长(秒) + * @return 学习记录 + */ + EduStudyRecords saveOrUpdateWatchProgress(String userId, String videoId, String courseId, Integer watchedDuration); + + /** + * 标记视频为已完成 + * @param userId 用户ID + * @param videoId 视频ID + * @param courseId 课程ID + * @return 学习记录 + */ + EduStudyRecords markVideoCompleted(String userId, String videoId, String courseId); + + /** + * 获取用户的学习记录 + * @param userId 用户ID + * @param videoId 视频ID(可选) + * @return 学习记录 + */ + EduStudyRecords getUserStudyRecord(String userId, String videoId); + + /** + * 获取用户的学习历史列表 + * @param userId 用户ID + * @param courseId 课程ID(可选) + * @return 学习记录列表 + */ + List getUserStudyHistory(String userId, String courseId); + + /** + * 获取用户课程的学习进度统计 + * @param userId 用户ID + * @param courseId 课程ID + * @return 进度统计信息 + */ + StudyProgressStats getCourseProgressStats(String userId, String courseId); + + /** + * 学习进度统计信息 + */ + class StudyProgressStats { + private int totalVideos; // 总视频数 + private int completedVideos; // 已完成视频数 + private int totalDuration; // 总时长(秒) + private int watchedDuration; // 已观看时长(秒) + private double completionRate; // 完成率 + + public StudyProgressStats() {} + + public StudyProgressStats(int totalVideos, int completedVideos, int totalDuration, int watchedDuration) { + this.totalVideos = totalVideos; + this.completedVideos = completedVideos; + this.totalDuration = totalDuration; + this.watchedDuration = watchedDuration; + this.completionRate = totalVideos > 0 ? (double) completedVideos / totalVideos * 100 : 0; + } + + // Getters and Setters + public int getTotalVideos() { return totalVideos; } + public void setTotalVideos(int totalVideos) { this.totalVideos = totalVideos; } + + public int getCompletedVideos() { return completedVideos; } + public void setCompletedVideos(int completedVideos) { this.completedVideos = completedVideos; } + + public int getTotalDuration() { return totalDuration; } + public void setTotalDuration(int totalDuration) { this.totalDuration = totalDuration; } + + public int getWatchedDuration() { return watchedDuration; } + public void setWatchedDuration(int watchedDuration) { this.watchedDuration = watchedDuration; } + + public double getCompletionRate() { return completionRate; } + public void setCompletionRate(double completionRate) { this.completionRate = completionRate; } + } +} \ No newline at end of file diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/edu/service/impl/EduStudyRecordsServiceImpl.java b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/service/impl/EduStudyRecordsServiceImpl.java new file mode 100644 index 00000000..a5500cb8 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/edu/service/impl/EduStudyRecordsServiceImpl.java @@ -0,0 +1,199 @@ +package com.budwk.app.zhgh.dayofficework.edu.service.impl; + +import com.budwk.app.base.service.impl.BaseServiceImpl; +import com.budwk.app.zhgh.dayofficework.edu.models.EduStudyRecords; +import com.budwk.app.zhgh.dayofficework.edu.models.EduVideos; +import com.budwk.app.zhgh.dayofficework.edu.service.EduStudyRecordsService; +import lombok.extern.slf4j.Slf4j; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.IocBean; + +import java.util.Date; +import java.util.List; + +/** + * @ClassName EduStudyRecordsServiceImpl + * @Description 学习记录服务实现类 + * @Author AI Assistant + * @Date 2024/01/01 + */ +@Slf4j +@IocBean(args = {"refer:dao"}) +public class EduStudyRecordsServiceImpl extends BaseServiceImpl implements EduStudyRecordsService { + + public EduStudyRecordsServiceImpl(Dao dao) { + super(dao); + } + + @Override + public EduStudyRecords saveOrUpdateWatchProgress(String userId, String videoId, String courseId, Integer watchedDuration) { + try { + // 查找现有记录 + EduStudyRecords existingRecord = dao().fetch(EduStudyRecords.class, + Cnd.where("userId", "=", userId) + .and("videoId", "=", videoId) + .and("courseId", "=", courseId)); + + Date now = new Date(); + + if (existingRecord != null) { + // 更新现有记录 + existingRecord.setWatchedDuration(watchedDuration); + existingRecord.setLastWatchedTime(now); + + // 获取视频总时长,判断是否完成 + EduVideos video = dao().fetch(EduVideos.class, videoId); + if (video != null && video.getDuration() != null && watchedDuration >= video.getDuration() * 0.9) { + existingRecord.setIsCompleted(true); + } + + dao().update(existingRecord); + return existingRecord; + } else { + // 创建新记录 + EduStudyRecords newRecord = new EduStudyRecords(); + newRecord.setUserId(userId); + newRecord.setVideoId(videoId); + newRecord.setCourseId(courseId); + newRecord.setWatchedDuration(watchedDuration); + newRecord.setLastWatchedTime(now); + + // 获取视频总时长,判断是否完成 + EduVideos video = dao().fetch(EduVideos.class, videoId); + if (video != null && video.getDuration() != null && watchedDuration >= video.getDuration() * 0.9) { + newRecord.setIsCompleted(true); + } else { + newRecord.setIsCompleted(false); + } + + dao().insert(newRecord); + return newRecord; + } + } catch (Exception e) { + log.error("保存观看进度失败", e); + throw new RuntimeException("保存观看进度失败", e); + } + } + + @Override + public EduStudyRecords markVideoCompleted(String userId, String videoId, String courseId) { + try { + EduStudyRecords record = dao().fetch(EduStudyRecords.class, + Cnd.where("userId", "=", userId) + .and("videoId", "=", videoId) + .and("courseId", "=", courseId)); + + Date now = new Date(); + + if (record != null) { + record.setIsCompleted(true); + record.setLastWatchedTime(now); + + // 如果观看时长为0,设置为视频总时长 + if (record.getWatchedDuration() == null || record.getWatchedDuration() == 0) { + EduVideos video = dao().fetch(EduVideos.class, videoId); + if (video != null && video.getDuration() != null) { + record.setWatchedDuration(video.getDuration()); + } + } + + dao().update(record); + return record; + } else { + // 创建新的完成记录 + EduStudyRecords newRecord = new EduStudyRecords(); + newRecord.setUserId(userId); + newRecord.setVideoId(videoId); + newRecord.setCourseId(courseId); + newRecord.setIsCompleted(true); + newRecord.setLastWatchedTime(now); + + // 设置观看时长为视频总时长 + EduVideos video = dao().fetch(EduVideos.class, videoId); + if (video != null && video.getDuration() != null) { + newRecord.setWatchedDuration(video.getDuration()); + } else { + newRecord.setWatchedDuration(0); + } + + dao().insert(newRecord); + return newRecord; + } + } catch (Exception e) { + log.error("标记视频完成失败", e); + throw new RuntimeException("标记视频完成失败", e); + } + } + + @Override + public EduStudyRecords getUserStudyRecord(String userId, String videoId) { + try { + return dao().fetch(EduStudyRecords.class, + Cnd.where("userId", "=", userId) + .and("videoId", "=", videoId)); + } catch (Exception e) { + log.error("获取用户学习记录失败", e); + return null; + } + } + + @Override + public List getUserStudyHistory(String userId, String courseId) { + try { + Cnd cnd = Cnd.where("userId", "=", userId); + if (courseId != null && !courseId.trim().isEmpty()) { + cnd.and("courseId", "=", courseId); + } + cnd.orderBy("lastWatchedTime", "desc"); + + return dao().query(EduStudyRecords.class, cnd); + } catch (Exception e) { + log.error("获取用户学习历史失败", e); + return null; + } + } + + @Override + public StudyProgressStats getCourseProgressStats(String userId, String courseId) { + try { + // 获取课程下所有视频的总数和总时长 + Sql videoStatsSql = Sqls.create("SELECT COUNT(*) as total_videos, COALESCE(SUM(duration), 0) as total_duration " + + "FROM edu_videos v " + + "INNER JOIN edu_chapters c ON v.chapterId = c.id " + + "WHERE c.courseId = @courseId"); + videoStatsSql.params().set("courseId", courseId); + videoStatsSql.setCallback(Sqls.callback.maps()); + dao().execute(videoStatsSql); + + int totalVideos = 0; + int totalDuration = 0; +// if (!videoStatsSql.getList().isEmpty()) { +// totalVideos = ((Number) videoStatsSql.getList().get(0).get("total_videos")).intValue(); +// totalDuration = ((Number) videoStatsSql.getList().get(0).get("total_duration")).intValue(); +// } + + // 获取用户已完成的视频数和观看时长 + Sql userStatsSql = Sqls.create("SELECT COUNT(*) as completed_videos, COALESCE(SUM(watchedDuration), 0) as watched_duration " + + "FROM edu_study_records " + + "WHERE userId = @userId AND courseId = @courseId AND isCompleted = 1"); + userStatsSql.params().set("userId", userId).set("courseId", courseId); + userStatsSql.setCallback(Sqls.callback.maps()); + dao().execute(userStatsSql); + + int completedVideos = 0; + int watchedDuration = 0; +// if (!userStatsSql.getList().isEmpty()) { +// completedVideos = ((Number) userStatsSql.getList().get(0).get("completed_videos")).intValue(); +// watchedDuration = ((Number) userStatsSql.getList().get(0).get("watched_duration")).intValue(); +// } + + return new StudyProgressStats(totalVideos, completedVideos, totalDuration, watchedDuration); + } catch (Exception e) { + log.error("获取课程进度统计失败", e); + return new StudyProgressStats(0, 0, 0, 0); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalDelegationController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalDelegationController.java index 6a8bbdf7..5719ba29 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalDelegationController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalDelegationController.java @@ -59,7 +59,7 @@ public class ProposalDelegationController { public void index() { } - @At("/platform/h5/proposal/delegation") + @At @Ok("beetl:/platform/zhghh5/democratic/proposal/transact/delegation/index.html") @SaCheckPermission("proposal.delegation") public void h5Index() { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalFeedbackEvaluationController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalFeedbackEvaluationController.java index 82a827da..a7822399 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalFeedbackEvaluationController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalFeedbackEvaluationController.java @@ -46,7 +46,7 @@ public class ProposalFeedbackEvaluationController { public void index() { } - @At(value = "/platform/h5/proposal/feedbackEvaluation",top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/proposal/transact/feedbackEvaluation/index.html") @SaCheckPermission("proposal.feedbackEvaluation") public void h5Index() { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalMineController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalMineController.java index 1e874883..9238b4d9 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalMineController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalMineController.java @@ -67,7 +67,7 @@ public class ProposalMineController { public void index() { } - @At(value = "/platform/h5/proposal/mine",top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/proposal/transact/mine/index.html") @SaCheckPermission("proposal.mine") public void h5Index() { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSchoolLeaderApprovalController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSchoolLeaderApprovalController.java index 7e58b927..f9c0ea2d 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSchoolLeaderApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSchoolLeaderApprovalController.java @@ -50,7 +50,7 @@ public class ProposalSchoolLeaderApprovalController { } - @At(value = "/platform/h5/proposal/schoolLeaderApproval",top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/proposal/transact/schoolLeaderApproval/index.html") @SaCheckPermission("proposal.schoolLeaderApproval") public void h5Index() { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java index 9d9a8b2e..9249294e 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalSecondedController.java @@ -62,7 +62,7 @@ public class ProposalSecondedController { public void index() { } - @At(value = "/platform/h5/proposal/seconded",top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/proposal/transact/seconded/index.html") @SaCheckPermission("proposal.seconded") public void h5Index() { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReplyController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReplyController.java index 79d0b6e1..7d7ba9d8 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReplyController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalUnderTakeReplyController.java @@ -45,7 +45,7 @@ public class ProposalUnderTakeReplyController { public void index() { } - @At(value = "/platform/h5/proposal/unitReply",top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/proposal/transact/unitReply/index.html") @SaCheckPermission("proposal.unitReply") public void h5Index() { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalWriteController.java b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalWriteController.java index 3e8fd19e..a2d46382 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalWriteController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/proposal/controller/transact/ProposalWriteController.java @@ -59,7 +59,7 @@ public class ProposalWriteController { public void index() { } - @At(value = "/platform/h5/proposal/write",top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/proposal/transact/write/index.html") @SaCheckPermission("proposal.write") public void h5Index(){ diff --git a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxMineController.java b/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxMineController.java index 170e3a9b..4d6695e8 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxMineController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxMineController.java @@ -44,7 +44,7 @@ public class SuggestionBoxMineController { } - @At(value = "/platform/h5/suggestionBox/mine", top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/suggestionBox/mine/index.html") @SaCheckLogin public void h5Index() { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxQueryController.java b/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxQueryController.java index 348f6500..64fdf06b 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxQueryController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxQueryController.java @@ -42,7 +42,7 @@ public class SuggestionBoxQueryController { } - @At(value = "/platform/h5/suggestionBox/query", top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/suggestionBox/query/index.html") @SaCheckPermission("suggestionBox.query") public void h5Index() { diff --git a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxWriteController.java b/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxWriteController.java index 387bc2e6..14589d53 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxWriteController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionBoxWriteController.java @@ -46,9 +46,8 @@ public class SuggestionBoxWriteController { } - @At(value = "/platform/h5/suggestionBox/write",top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/suggestionBox/write/index.html") -// @SaCheckPermission("h5.suggestionBox.write") @SaCheckLogin public void h5Index(){ diff --git a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionViewController.java b/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionViewController.java deleted file mode 100644 index 41d2539c..00000000 --- a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionViewController.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.budwk.app.zhgh.democratic.suggestionBox.controller; - -import cn.dev33.satoken.annotation.SaCheckLogin; -import com.budwk.app.base.result.Result; -import com.budwk.app.zhgh.democratic.suggestionBox.models.SuggestionBox; -import io.swagger.annotations.Api; -import org.nutz.dao.Dao; -import org.nutz.ioc.loader.annotation.Inject; -import org.nutz.ioc.loader.annotation.IocBean; -import org.nutz.mvc.annotation.At; -import org.nutz.mvc.annotation.Ok; - -@IocBean -@At("/platform/suggestionBox/view") -@Ok("json:full") -@Api("意见箱") -public class SuggestionViewController { - - @Inject - private Dao dao; - - @At("/index") - @Ok("beetl:/platform/zhgh/dayofficework/suggestionBox/view/index.html") - @SaCheckLogin - public void index() { - - } - - @At("/info") - @SaCheckLogin - public Result info(String id) { - SuggestionBox box = dao.fetch(SuggestionBox.class, id); - return Result.success(box); - } - -} diff --git a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionXghController.java b/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionXghController.java index deeee1e6..83ec6e6c 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionXghController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/suggestionBox/controller/SuggestionXghController.java @@ -41,7 +41,7 @@ public class SuggestionXghController { } - @At(value = "/platform/h5/suggestionBox/xgh",top = true) + @At @Ok("beetl:/platform/zhghh5/democratic/suggestionBox/xgh/index.html") @SaCheckPermission("suggestionBox.xgh") public void h5Index() { diff --git a/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/basicForm.js b/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/basicForm.js index 380f5243..3c09811b 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/basicForm.js +++ b/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/basicForm.js @@ -19,14 +19,7 @@ const basicForm = { > - - - - - - - - + diff --git a/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/contentForm.js b/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/contentForm.js index 400538cd..e46f9fea 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/contentForm.js +++ b/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/contentForm.js @@ -161,8 +161,6 @@ const contentForm = { - - `, data() { @@ -352,12 +350,12 @@ const contentForm = { }, style: /*language=CSS*/ ` - .edu_content_dialog .el-dialog__body { + ::v-deep .edu_content_dialog .el-dialog__body { height: calc(100vh - 155px); overflow-y: auto; } - .section-header { + ::v-deep .section-header { display: flex; justify-content: space-between; align-items: center; @@ -365,7 +363,7 @@ const contentForm = { padding: 20px 20px 0; } - .video-item { + ::v-deep .video-item { background: #f8f9fa; border: 1px solid #e9ecef; border-radius: 8px; @@ -374,19 +372,19 @@ const contentForm = { transition: all 0.3s; } - .video-item:hover { + ::v-deep .video-item:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); transform: translateY(-2px); } - .chapter-card { + ::v-deep .chapter-card { border: 1px solid #e4e7ed; border-radius: 8px; margin-bottom: 20px; overflow: hidden; } - .chapter-header { + ::v-deep .chapter-header { background: #f5f7fa; padding: 15px 20px; border-bottom: 1px solid #e4e7ed; @@ -395,11 +393,11 @@ const contentForm = { align-items: center; } - .chapter-content { + ::v-deep .chapter-content { padding: 20px; } - .stats-card { + ::v-deep .stats-card { color: white; padding: 20px; border-radius: 8px; @@ -407,14 +405,14 @@ const contentForm = { margin-bottom: 20px; } - .course-cover { + ::v-deep .course-cover { width: 100px; height: 60px; object-fit: cover; border-radius: 4px; } - .duration-display { + ::v-deep .duration-display { color: #909399; font-size: 12px; } diff --git a/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/index.html b/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/index.html index 0c7fb577..84d7aa64 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/edu/courses/index.html @@ -2,6 +2,13 @@ layout("/layouts/platform.html"){ #--> + +
@@ -9,19 +16,12 @@ layout("/layouts/platform.html"){ - + +