diff --git a/src/main/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImpl.java b/src/main/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImpl.java index 13d02fa..76a8422 100644 --- a/src/main/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImpl.java +++ b/src/main/java/com/guo/learningprogresstracker/service/impl/ReviewServiceImpl.java @@ -1,49 +1,164 @@ package com.guo.learningprogresstracker.service.impl; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.guo.learningprogresstracker.dto.ReviewFeedItem; import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity; import com.guo.learningprogresstracker.entity.StudyReportsEntity; +import com.guo.learningprogresstracker.entity.StudySessionsEntity; +import com.guo.learningprogresstracker.entity.TaskEntity; import com.guo.learningprogresstracker.exception.NotFindEntitiesException; -import com.guo.learningprogresstracker.mapper.ReviewMapper; import com.guo.learningprogresstracker.mapper.StudyReportFragmentsMapper; import com.guo.learningprogresstracker.mapper.StudyReportsMapper; +import com.guo.learningprogresstracker.mapper.StudySessionsMapper; +import com.guo.learningprogresstracker.mapper.TasksMapper; import com.guo.learningprogresstracker.service.ReviewService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** - * 复习模块 Service 实现 + * 复习模块 Service 实现(纯 MyBatis-Plus Java API) */ @Service @RequiredArgsConstructor public class ReviewServiceImpl implements ReviewService { - private final ReviewMapper reviewMapper; private final StudyReportsMapper studyReportsMapper; private final StudyReportFragmentsMapper studyReportFragmentsMapper; + private final StudySessionsMapper studySessionsMapper; + private final TasksMapper tasksMapper; @Override public List getReviewFeed(int limit) { - return reviewMapper.selectReviewFeed(limit); + // created_by 条件由 TenantLineInnerInterceptor 自动注入 + List reports = studyReportsMapper.selectList( + Wrappers.lambdaQuery() + .orderByDesc(StudyReportsEntity::getCreatedTime) + .last("LIMIT " + limit)); + + List fragments = studyReportFragmentsMapper.selectList( + Wrappers.lambdaQuery() + .orderByDesc(StudyReportFragmentsEntity::getCreatedTime) + .last("LIMIT " + limit)); + + return mergeAndConvert(reports, fragments); } @Override public List getTaskReview(String taskNum) { - return reviewMapper.selectTaskReview(taskNum); + // 先查该任务下的所有 sessionNum + List sessionNums = studySessionsMapper.selectList( + Wrappers.lambdaQuery() + .eq(StudySessionsEntity::getTaskNum, taskNum) + .select(StudySessionsEntity::getSessionNum)) + .stream() + .map(StudySessionsEntity::getSessionNum) + .collect(Collectors.toList()); + + if (sessionNums.isEmpty()) { + return Collections.emptyList(); + } + + List reports = studyReportsMapper.selectList( + Wrappers.lambdaQuery() + .in(StudyReportsEntity::getSessionNum, sessionNums) + .orderByDesc(StudyReportsEntity::getCreatedTime)); + + List fragments = studyReportFragmentsMapper.selectList( + Wrappers.lambdaQuery() + .in(StudyReportFragmentsEntity::getSessionNum, sessionNums) + .orderByDesc(StudyReportFragmentsEntity::getCreatedTime)); + + return mergeAndConvert(reports, fragments); } @Override public StudyReportsEntity getReportDetail(int id) throws NotFindEntitiesException { + // 拦截器自动校验归属 return Optional.ofNullable(studyReportsMapper.selectById(id)) .orElseThrow(() -> new NotFindEntitiesException("学习报告[" + id + "]不存在")); } @Override public StudyReportFragmentsEntity getFragmentDetail(int id) throws NotFindEntitiesException { + // 拦截器自动校验归属 return Optional.ofNullable(studyReportFragmentsMapper.selectById(id)) .orElseThrow(() -> new NotFindEntitiesException("学习残片[" + id + "]不存在")); } + + /** + * 将报告和残片合并转换为 ReviewFeedItem 列表,按创建时间倒序排列 + */ + private List mergeAndConvert(List reports, + List fragments) { + // 收集所有 sessionNum,批量查询 session 和 task + Set allSessionNums = Stream.concat( + reports.stream().map(StudyReportsEntity::getSessionNum), + fragments.stream().map(StudyReportFragmentsEntity::getSessionNum) + ).collect(Collectors.toSet()); + + if (allSessionNums.isEmpty()) { + return Collections.emptyList(); + } + + // 批量查询 sessions,构建 sessionNum -> taskNum 映射 + Map sessionToTaskMap = studySessionsMapper.selectList( + Wrappers.lambdaQuery() + .in(StudySessionsEntity::getSessionNum, allSessionNums) + .select(StudySessionsEntity::getSessionNum, StudySessionsEntity::getTaskNum)) + .stream() + .collect(Collectors.toMap( + StudySessionsEntity::getSessionNum, + StudySessionsEntity::getTaskNum, + (a, b) -> a)); + + // 批量查询 tasks,构建 taskNum -> taskName 映射 + Set taskNums = new HashSet<>(sessionToTaskMap.values()); + Map taskNameMap = tasksMapper.selectList( + Wrappers.lambdaQuery() + .in(TaskEntity::getTaskNum, taskNums) + .select(TaskEntity::getTaskNum, TaskEntity::getTaskName)) + .stream() + .collect(Collectors.toMap( + TaskEntity::getTaskNum, + TaskEntity::getTaskName, + (a, b) -> a)); + + // 转换报告 + List reportItems = reports.stream().map(r -> { + ReviewFeedItem item = new ReviewFeedItem(); + item.setId(r.getId()); + item.setSessionNum(r.getSessionNum()); + item.setSourceType("REPORT"); + item.setContent(r.getContent()); + item.setCreatedTime(r.getCreatedTime()); + String taskNum = sessionToTaskMap.get(r.getSessionNum()); + item.setTaskNum(taskNum); + item.setTaskName(taskNum != null ? taskNameMap.get(taskNum) : null); + return item; + }).collect(Collectors.toList()); + + // 转换残片 + List fragmentItems = fragments.stream().map(f -> { + ReviewFeedItem item = new ReviewFeedItem(); + item.setId(f.getId()); + item.setSessionNum(f.getSessionNum()); + item.setSourceType("FRAGMENT"); + item.setContent(f.getContent()); + item.setCreatedTime(f.getCreatedTime()); + String taskNum = sessionToTaskMap.get(f.getSessionNum()); + item.setTaskNum(taskNum); + item.setTaskName(taskNum != null ? taskNameMap.get(taskNum) : null); + return item; + }).collect(Collectors.toList()); + + // 合并并按创建时间倒序 + return Stream.concat(reportItems.stream(), fragmentItems.stream()) + .sorted(Comparator.comparing(ReviewFeedItem::getCreatedTime, + Comparator.nullsLast(Comparator.reverseOrder()))) + .collect(Collectors.toList()); + } }