From 640fbc94f9e19ac24e732a35c27ad2e08d243796 Mon Sep 17 00:00:00 2001 From: zhonghua Date: Wed, 18 Mar 2026 18:38:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20CoursePackageServi?= =?UTF-8?q?ceImpl=20=E5=AE=9E=E7=8E=B0=20CoursePackageService=20=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E4=BF=AE=E5=A4=8D=E5=90=AF=E5=8A=A8=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- .../impl/CoursePackageServiceImpl.java | 395 ++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 reading-platform-java/src/main/java/com/reading/platform/service/impl/CoursePackageServiceImpl.java diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/CoursePackageServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/CoursePackageServiceImpl.java new file mode 100644 index 0000000..1abeaf0 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/CoursePackageServiceImpl.java @@ -0,0 +1,395 @@ +package com.reading.platform.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.reading.platform.common.enums.CourseStatus; +import com.reading.platform.common.enums.TenantPackageStatus; +import com.reading.platform.common.exception.BusinessException; +import com.reading.platform.dto.request.CourseCreateRequest; +import com.reading.platform.dto.request.CourseUpdateRequest; +import com.reading.platform.dto.response.CourseLessonResponse; +import com.reading.platform.dto.response.CourseResponse; +import com.reading.platform.dto.response.LessonStepResponse; +import com.reading.platform.entity.CourseCollectionPackage; +import com.reading.platform.entity.CourseLesson; +import com.reading.platform.entity.CoursePackage; +import com.reading.platform.entity.LessonStep; +import com.reading.platform.entity.TenantPackage; +import com.reading.platform.mapper.CourseCollectionPackageMapper; +import com.reading.platform.mapper.CoursePackageMapper; +import com.reading.platform.mapper.TenantPackageMapper; +import com.reading.platform.service.CourseLessonService; +import com.reading.platform.service.CoursePackageService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 课程包服务实现类 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class CoursePackageServiceImpl extends ServiceImpl + implements CoursePackageService { + + private final CoursePackageMapper coursePackageMapper; + private final CourseLessonService courseLessonService; + private final com.reading.platform.common.mapper.CoursePackageMapper coursePackageVoMapper; + private final CourseCollectionPackageMapper collectionPackageMapper; + private final TenantPackageMapper tenantPackageMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public CoursePackage createCourse(Long tenantId, CourseCreateRequest request) { + log.info("创建租户课程,tenantId={}, name={}", tenantId, request.getName()); + CoursePackage entity = buildEntityFromRequest(request); + entity.setTenantId(tenantId); + entity.setIsSystem(0); + entity.setStatus(CourseStatus.DRAFT.getCode()); + entity.setUsageCount(0); + coursePackageMapper.insert(entity); + log.info("课程创建成功,id={}", entity.getId()); + return entity; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public CoursePackage createSystemCourse(CourseCreateRequest request) { + log.info("创建系统课程,name={}", request.getName()); + CoursePackage entity = buildEntityFromRequest(request); + entity.setTenantId(null); + entity.setIsSystem(1); + entity.setStatus(CourseStatus.DRAFT.getCode()); + entity.setUsageCount(0); + coursePackageMapper.insert(entity); + log.info("系统课程创建成功,id={}", entity.getId()); + return entity; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public CoursePackage updateCourse(Long id, CourseUpdateRequest request) { + log.info("更新课程,id={}", id); + CoursePackage entity = getCourseById(id); + applyUpdateRequest(entity, request); + coursePackageMapper.updateById(entity); + log.info("课程更新成功,id={}", id); + return entity; + } + + @Override + public CoursePackage getCourseById(Long id) { + CoursePackage entity = coursePackageMapper.selectById(id); + if (entity == null) { + throw new BusinessException("课程不存在,id=" + id); + } + return entity; + } + + @Override + public CoursePackage getCourseByIdWithTenantCheck(Long id, Long tenantId) { + CoursePackage entity = getCourseById(id); + if (entity.getTenantId() != null && !entity.getTenantId().equals(tenantId)) { + throw new BusinessException("无权访问该课程"); + } + return entity; + } + + @Override + public CourseResponse getCourseByIdWithLessons(Long id) { + CoursePackage entity = getCourseById(id); + CourseResponse response = coursePackageVoMapper.toVO(entity); + List lessons = courseLessonService.findByCourseId(id); + List lessonResponses = lessons.stream() + .map(this::toLessonResponse) + .collect(Collectors.toList()); + response.setCourseLessons(lessonResponses); + return response; + } + + @Override + public Page getCoursePage(Long tenantId, Integer pageNum, Integer pageSize, + String keyword, String category, String status) { + int current = pageNum != null && pageNum > 0 ? pageNum : 1; + int size = pageSize != null && pageSize > 0 ? pageSize : 10; + Page page = new Page<>(current, size); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(CoursePackage::getTenantId, tenantId); + if (StringUtils.hasText(keyword)) { + wrapper.and(w -> w + .like(CoursePackage::getName, keyword) + .or().like(CoursePackage::getPictureBookName, keyword) + .or().like(CoursePackage::getCode, keyword)); + } + if (StringUtils.hasText(category)) { + wrapper.eq(CoursePackage::getCategory, category); + } + if (StringUtils.hasText(status)) { + wrapper.eq(CoursePackage::getStatus, status); + } + wrapper.orderByDesc(CoursePackage::getUpdatedAt); + return coursePackageMapper.selectPage(page, wrapper); + } + + @Override + public Page getSystemCoursePage(Integer pageNum, Integer pageSize, + String keyword, String category, String status, + boolean reviewOnly) { + int current = pageNum != null && pageNum > 0 ? pageNum : 1; + int size = pageSize != null && pageSize > 0 ? pageSize : 10; + Page page = new Page<>(current, size); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(CoursePackage::getIsSystem, 1); + if (StringUtils.hasText(keyword)) { + wrapper.and(w -> w + .like(CoursePackage::getName, keyword) + .or().like(CoursePackage::getPictureBookName, keyword) + .or().like(CoursePackage::getCode, keyword)); + } + if (StringUtils.hasText(category)) { + wrapper.eq(CoursePackage::getCategory, category); + } + if (StringUtils.hasText(status)) { + wrapper.eq(CoursePackage::getStatus, status); + } + if (reviewOnly) { + wrapper.eq(CoursePackage::getStatus, CourseStatus.PENDING.getCode()); + } + wrapper.orderByDesc(CoursePackage::getUpdatedAt); + return coursePackageMapper.selectPage(page, wrapper); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteCourse(Long id) { + getCourseById(id); + coursePackageMapper.deleteById(id); + log.info("课程删除成功,id={}", id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void publishCourse(Long id) { + CoursePackage entity = getCourseById(id); + entity.setStatus(CourseStatus.PUBLISHED.getCode()); + entity.setPublishedAt(LocalDateTime.now()); + coursePackageMapper.updateById(entity); + log.info("课程发布成功,id={}", id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void archiveCourse(Long id) { + CoursePackage entity = getCourseById(id); + entity.setStatus(CourseStatus.ARCHIVED.getCode()); + coursePackageMapper.updateById(entity); + log.info("课程归档成功,id={}", id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void rejectCourse(Long id, String comment) { + CoursePackage entity = getCourseById(id); + entity.setStatus(CourseStatus.REJECTED.getCode()); + entity.setReviewComment(comment); + entity.setReviewedAt(LocalDateTime.now()); + coursePackageMapper.updateById(entity); + log.info("课程驳回成功,id={}", id); + } + + @Override + public List getCoursesByTenantId(Long tenantId) { + return coursePackageMapper.selectList( + new LambdaQueryWrapper() + .eq(CoursePackage::getTenantId, tenantId) + .eq(CoursePackage::getStatus, CourseStatus.PUBLISHED.getCode()) + .orderByDesc(CoursePackage::getUsageCount)); + } + + @Override + public List getTenantPackageCourses(Long tenantId, String keyword, String grade) { + List collectionIds = tenantPackageMapper.selectList( + new LambdaQueryWrapper() + .eq(TenantPackage::getTenantId, tenantId) + .eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE.getCode()) + .isNotNull(TenantPackage::getCollectionId)) + .stream() + .map(TenantPackage::getCollectionId) + .distinct() + .collect(Collectors.toList()); + + if (collectionIds.isEmpty()) { + return new ArrayList<>(); + } + + List packageIds = collectionPackageMapper.selectList( + new LambdaQueryWrapper() + .in(CourseCollectionPackage::getCollectionId, collectionIds)) + .stream() + .map(CourseCollectionPackage::getPackageId) + .distinct() + .collect(Collectors.toList()); + + if (packageIds.isEmpty()) { + return new ArrayList<>(); + } + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(CoursePackage::getId, packageIds) + .eq(CoursePackage::getStatus, CourseStatus.PUBLISHED.getCode()); + + if (StringUtils.hasText(keyword)) { + wrapper.and(w -> w + .like(CoursePackage::getName, keyword) + .or().like(CoursePackage::getPictureBookName, keyword) + .or().like(CoursePackage::getCode, keyword)); + } + if (StringUtils.hasText(grade)) { + String gradeLower = grade.toLowerCase(); + wrapper.and(w -> w + .like(CoursePackage::getGradeTags, grade) + .or().like(CoursePackage::getGradeTags, gradeLower) + .or().like(CoursePackage::getGradeTags, "\"" + grade + "\"") + .or().like(CoursePackage::getGradeTags, "\"" + gradeLower + "\"")); + } + wrapper.orderByDesc(CoursePackage::getUsageCount); + return coursePackageMapper.selectList(wrapper); + } + + private CoursePackage buildEntityFromRequest(CourseCreateRequest request) { + CoursePackage entity = new CoursePackage(); + entity.setName(request.getName()); + entity.setCode(request.getCode()); + entity.setDescription(request.getDescription()); + entity.setCoverUrl(request.getCoverUrl()); + entity.setCoverImagePath(request.getCoverImagePath()); + entity.setCategory(request.getCategory()); + entity.setAgeRange(request.getAgeRange()); + entity.setDifficultyLevel(request.getDifficultyLevel()); + entity.setDurationMinutes(request.getDurationMinutes()); + entity.setObjectives(request.getObjectives()); + entity.setCoreContent(request.getCoreContent()); + entity.setIntroSummary(request.getIntroSummary()); + entity.setIntroHighlights(request.getIntroHighlights()); + entity.setIntroGoals(request.getIntroGoals()); + entity.setIntroSchedule(request.getIntroSchedule()); + entity.setIntroKeyPoints(request.getIntroKeyPoints()); + entity.setIntroMethods(request.getIntroMethods()); + entity.setIntroEvaluation(request.getIntroEvaluation()); + entity.setIntroNotes(request.getIntroNotes()); + entity.setScheduleRefData(request.getScheduleRefData()); + entity.setEnvironmentConstruction(request.getEnvironmentConstruction()); + entity.setThemeId(request.getThemeId()); + entity.setPictureBookName(request.getPictureBookName()); + entity.setEbookPaths(request.getEbookPaths()); + entity.setAudioPaths(request.getAudioPaths()); + entity.setVideoPaths(request.getVideoPaths()); + entity.setOtherResources(request.getOtherResources()); + entity.setPptPath(request.getPptPath()); + entity.setPptName(request.getPptName()); + entity.setPosterPaths(request.getPosterPaths()); + entity.setTools(request.getTools()); + entity.setStudentMaterials(request.getStudentMaterials()); + entity.setLessonPlanData(request.getLessonPlanData()); + entity.setActivitiesData(request.getActivitiesData()); + entity.setAssessmentData(request.getAssessmentData()); + entity.setGradeTags(request.getGradeTags()); + entity.setDomainTags(request.getDomainTags()); + entity.setHasCollectiveLesson(request.getHasCollectiveLesson() != null && request.getHasCollectiveLesson() ? 1 : 0); + return entity; + } + + private void applyUpdateRequest(CoursePackage entity, CourseUpdateRequest request) { + if (StringUtils.hasText(request.getName())) entity.setName(request.getName()); + if (request.getCode() != null) entity.setCode(request.getCode()); + if (request.getDescription() != null) entity.setDescription(request.getDescription()); + if (request.getCoverUrl() != null) entity.setCoverUrl(request.getCoverUrl()); + if (request.getCoverImagePath() != null) entity.setCoverImagePath(request.getCoverImagePath()); + if (request.getCategory() != null) entity.setCategory(request.getCategory()); + if (request.getAgeRange() != null) entity.setAgeRange(request.getAgeRange()); + if (request.getDifficultyLevel() != null) entity.setDifficultyLevel(request.getDifficultyLevel()); + if (request.getDurationMinutes() != null) entity.setDurationMinutes(request.getDurationMinutes()); + if (request.getObjectives() != null) entity.setObjectives(request.getObjectives()); + if (StringUtils.hasText(request.getStatus())) entity.setStatus(request.getStatus()); + if (request.getCoreContent() != null) entity.setCoreContent(request.getCoreContent()); + if (request.getIntroSummary() != null) entity.setIntroSummary(request.getIntroSummary()); + if (request.getIntroHighlights() != null) entity.setIntroHighlights(request.getIntroHighlights()); + if (request.getIntroGoals() != null) entity.setIntroGoals(request.getIntroGoals()); + if (request.getIntroSchedule() != null) entity.setIntroSchedule(request.getIntroSchedule()); + if (request.getIntroKeyPoints() != null) entity.setIntroKeyPoints(request.getIntroKeyPoints()); + if (request.getIntroMethods() != null) entity.setIntroMethods(request.getIntroMethods()); + if (request.getIntroEvaluation() != null) entity.setIntroEvaluation(request.getIntroEvaluation()); + if (request.getIntroNotes() != null) entity.setIntroNotes(request.getIntroNotes()); + if (request.getScheduleRefData() != null) entity.setScheduleRefData(request.getScheduleRefData()); + if (request.getEnvironmentConstruction() != null) entity.setEnvironmentConstruction(request.getEnvironmentConstruction()); + if (request.getThemeId() != null) entity.setThemeId(request.getThemeId()); + if (request.getPictureBookName() != null) entity.setPictureBookName(request.getPictureBookName()); + if (request.getEbookPaths() != null) entity.setEbookPaths(request.getEbookPaths()); + if (request.getAudioPaths() != null) entity.setAudioPaths(request.getAudioPaths()); + if (request.getVideoPaths() != null) entity.setVideoPaths(request.getVideoPaths()); + if (request.getOtherResources() != null) entity.setOtherResources(request.getOtherResources()); + if (request.getPptPath() != null) entity.setPptPath(request.getPptPath()); + if (request.getPptName() != null) entity.setPptName(request.getPptName()); + if (request.getPosterPaths() != null) entity.setPosterPaths(request.getPosterPaths()); + if (request.getTools() != null) entity.setTools(request.getTools()); + if (request.getStudentMaterials() != null) entity.setStudentMaterials(request.getStudentMaterials()); + if (request.getLessonPlanData() != null) entity.setLessonPlanData(request.getLessonPlanData()); + if (request.getActivitiesData() != null) entity.setActivitiesData(request.getActivitiesData()); + if (request.getAssessmentData() != null) entity.setAssessmentData(request.getAssessmentData()); + if (request.getGradeTags() != null) entity.setGradeTags(request.getGradeTags()); + if (request.getDomainTags() != null) entity.setDomainTags(request.getDomainTags()); + if (request.getHasCollectiveLesson() != null) entity.setHasCollectiveLesson(request.getHasCollectiveLesson() ? 1 : 0); + } + + private CourseLessonResponse toLessonResponse(CourseLesson lesson) { + List steps = courseLessonService.findSteps(lesson.getId()); + List stepResponses = steps.stream() + .map(s -> LessonStepResponse.builder() + .id(s.getId()) + .lessonId(s.getLessonId()) + .name(s.getName()) + .content(s.getContent()) + .duration(s.getDuration()) + .objective(s.getObjective()) + .resourceIds(s.getResourceIds()) + .sortOrder(s.getSortOrder()) + .createdAt(s.getCreatedAt()) + .updatedAt(s.getUpdatedAt()) + .build()) + .collect(Collectors.toList()); + + return CourseLessonResponse.builder() + .id(lesson.getId()) + .courseId(lesson.getCourseId()) + .lessonType(lesson.getLessonType()) + .name(lesson.getName()) + .description(lesson.getDescription()) + .duration(lesson.getDuration()) + .videoPath(lesson.getVideoPath()) + .videoName(lesson.getVideoName()) + .pptPath(lesson.getPptPath()) + .pptName(lesson.getPptName()) + .pdfPath(lesson.getPdfPath()) + .pdfName(lesson.getPdfName()) + .objectives(lesson.getObjectives()) + .preparation(lesson.getPreparation()) + .extension(lesson.getExtension()) + .reflection(lesson.getReflection()) + .assessmentData(lesson.getAssessmentData()) + .useTemplate(lesson.getUseTemplate()) + .sortOrder(lesson.getSortOrder()) + .steps(stepResponses) + .createdAt(lesson.getCreatedAt()) + .updatedAt(lesson.getUpdatedAt()) + .build(); + } +}