feat: 新增复习任务统计接口
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.guo.learningprogresstracker.controller;
|
||||
|
||||
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
||||
import com.guo.learningprogresstracker.dto.ReviewTaskStats;
|
||||
import com.guo.learningprogresstracker.entity.CommonResult;
|
||||
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
||||
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
||||
@@ -32,6 +33,22 @@ public class ReviewController {
|
||||
return CommonResult.success(reviewService.getReviewFeed(limit));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务维度的复习统计汇总
|
||||
*/
|
||||
@GetMapping("/tasks")
|
||||
public CommonResult<List<ReviewTaskStats>> getReviewTaskStats() {
|
||||
return CommonResult.success(reviewService.getReviewTaskStats());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定任务的复习统计汇总
|
||||
*/
|
||||
@GetMapping("/tasks/{taskNum}")
|
||||
public CommonResult<ReviewTaskStats> getReviewTaskStats(@PathVariable String taskNum) {
|
||||
return CommonResult.success(reviewService.getReviewTaskStats(taskNum));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定任务下的所有报告和残片
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.guo.learningprogresstracker.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 任务维度的复习统计数据。
|
||||
*/
|
||||
@Data
|
||||
public class ReviewTaskStats {
|
||||
private String taskNum;
|
||||
private String taskName;
|
||||
private long reportCount;
|
||||
private long fragmentCount;
|
||||
private double effectiveTime;
|
||||
private long sessionCount;
|
||||
private double todayEffectiveTime;
|
||||
private double weekEffectiveTime;
|
||||
private double avgEffectiveTime;
|
||||
private double avgEffectivenessRatio;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.guo.learningprogresstracker.service;
|
||||
|
||||
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
||||
import com.guo.learningprogresstracker.dto.ReviewTaskStats;
|
||||
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
||||
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
||||
import com.guo.learningprogresstracker.exception.NotFindEntitiesException;
|
||||
@@ -17,6 +18,16 @@ public interface ReviewService {
|
||||
*/
|
||||
List<ReviewFeedItem> getReviewFeed(int limit);
|
||||
|
||||
/**
|
||||
* 获取所有任务的复习统计数据
|
||||
*/
|
||||
List<ReviewTaskStats> getReviewTaskStats();
|
||||
|
||||
/**
|
||||
* 获取指定任务的复习统计数据
|
||||
*/
|
||||
ReviewTaskStats getReviewTaskStats(String taskNum);
|
||||
|
||||
/**
|
||||
* 获取指定任务下的所有报告和残片
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.guo.learningprogresstracker.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
|
||||
import com.guo.learningprogresstracker.dto.ReviewTaskStats;
|
||||
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
|
||||
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
|
||||
import com.guo.learningprogresstracker.entity.StudySessionsEntity;
|
||||
@@ -14,7 +15,11 @@ import com.guo.learningprogresstracker.mapper.TasksMapper;
|
||||
import com.guo.learningprogresstracker.service.ReviewService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -46,6 +51,35 @@ public class ReviewServiceImpl implements ReviewService {
|
||||
return mergeAndConvert(reports, fragments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReviewTaskStats> getReviewTaskStats() {
|
||||
List<TaskEntity> tasks = tasksMapper.selectList(
|
||||
Wrappers.<TaskEntity>lambdaQuery()
|
||||
.orderByDesc(TaskEntity::getCalculatedPriority));
|
||||
|
||||
List<ReviewTaskStats> stats = tasks.stream()
|
||||
.map(this::newTaskStats)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
fillReviewTaskStats(stats);
|
||||
return stats;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReviewTaskStats getReviewTaskStats(String taskNum) {
|
||||
TaskEntity task = tasksMapper.selectList(
|
||||
Wrappers.<TaskEntity>lambdaQuery()
|
||||
.eq(TaskEntity::getTaskNum, taskNum)
|
||||
.last("LIMIT 1"))
|
||||
.stream()
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
ReviewTaskStats stats = newTaskStats(taskNum, task == null ? null : task.getTaskName());
|
||||
fillReviewTaskStats(Collections.singletonList(stats));
|
||||
return stats;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReviewFeedItem> getTaskReview(String taskNum) {
|
||||
List<String> sessionNums = studySessionsMapper.selectList(
|
||||
@@ -151,4 +185,101 @@ public class ReviewServiceImpl implements ReviewService {
|
||||
Comparator.nullsLast(Comparator.reverseOrder())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ReviewTaskStats newTaskStats(TaskEntity task) {
|
||||
return newTaskStats(task.getTaskNum(), task.getTaskName());
|
||||
}
|
||||
|
||||
private ReviewTaskStats newTaskStats(String taskNum, String taskName) {
|
||||
ReviewTaskStats stats = new ReviewTaskStats();
|
||||
stats.setTaskNum(taskNum);
|
||||
stats.setTaskName(taskName);
|
||||
return stats;
|
||||
}
|
||||
|
||||
private void fillReviewTaskStats(List<ReviewTaskStats> statsList) {
|
||||
Map<String, ReviewTaskStats> statsByTaskNum = statsList.stream()
|
||||
.filter(item -> StringUtils.hasText(item.getTaskNum()))
|
||||
.collect(Collectors.toMap(
|
||||
ReviewTaskStats::getTaskNum,
|
||||
item -> item,
|
||||
(a, b) -> a,
|
||||
LinkedHashMap::new));
|
||||
|
||||
if (statsByTaskNum.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<StudySessionsEntity> sessions = studySessionsMapper.selectList(
|
||||
Wrappers.<StudySessionsEntity>lambdaQuery()
|
||||
.in(StudySessionsEntity::getTaskNum, statsByTaskNum.keySet()));
|
||||
|
||||
LocalDateTime todayStart = LocalDate.now().atStartOfDay();
|
||||
LocalDateTime weekStart = LocalDate.now().with(DayOfWeek.MONDAY).atStartOfDay();
|
||||
Map<String, String> sessionToTaskNum = new HashMap<>();
|
||||
Map<String, Double> effectivenessRatioSum = new HashMap<>();
|
||||
|
||||
for (StudySessionsEntity session : sessions) {
|
||||
ReviewTaskStats stats = statsByTaskNum.get(session.getTaskNum());
|
||||
if (stats == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(session.getSessionNum())) {
|
||||
sessionToTaskNum.put(session.getSessionNum(), session.getTaskNum());
|
||||
}
|
||||
|
||||
double effectiveTime = session.getEffectiveTime();
|
||||
stats.setSessionCount(stats.getSessionCount() + 1);
|
||||
stats.setEffectiveTime(stats.getEffectiveTime() + effectiveTime);
|
||||
effectivenessRatioSum.merge(session.getTaskNum(), session.getEffectivenessRatio(), Double::sum);
|
||||
|
||||
LocalDateTime startTime = session.getStartTime();
|
||||
if (startTime != null && !startTime.isBefore(todayStart)) {
|
||||
stats.setTodayEffectiveTime(stats.getTodayEffectiveTime() + effectiveTime);
|
||||
}
|
||||
if (startTime != null && !startTime.isBefore(weekStart)) {
|
||||
stats.setWeekEffectiveTime(stats.getWeekEffectiveTime() + effectiveTime);
|
||||
}
|
||||
}
|
||||
|
||||
statsByTaskNum.forEach((taskNum, stats) -> {
|
||||
if (stats.getSessionCount() > 0) {
|
||||
stats.setAvgEffectiveTime(stats.getEffectiveTime() / stats.getSessionCount());
|
||||
stats.setAvgEffectivenessRatio(effectivenessRatioSum.getOrDefault(taskNum, 0D) / stats.getSessionCount());
|
||||
}
|
||||
});
|
||||
|
||||
fillReportAndFragmentCount(sessionToTaskNum, statsByTaskNum);
|
||||
}
|
||||
|
||||
private void fillReportAndFragmentCount(Map<String, String> sessionToTaskNum,
|
||||
Map<String, ReviewTaskStats> statsByTaskNum) {
|
||||
if (sessionToTaskNum.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> sessionNums = sessionToTaskNum.keySet();
|
||||
List<StudyReportsEntity> reports = studyReportsMapper.selectList(
|
||||
Wrappers.<StudyReportsEntity>lambdaQuery()
|
||||
.in(StudyReportsEntity::getSessionNum, sessionNums)
|
||||
.select(StudyReportsEntity::getSessionNum));
|
||||
for (StudyReportsEntity report : reports) {
|
||||
ReviewTaskStats stats = statsByTaskNum.get(sessionToTaskNum.get(report.getSessionNum()));
|
||||
if (stats != null) {
|
||||
stats.setReportCount(stats.getReportCount() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
List<StudyReportFragmentsEntity> fragments = studyReportFragmentsMapper.selectList(
|
||||
Wrappers.<StudyReportFragmentsEntity>lambdaQuery()
|
||||
.in(StudyReportFragmentsEntity::getSessionNum, sessionNums)
|
||||
.select(StudyReportFragmentsEntity::getSessionNum));
|
||||
for (StudyReportFragmentsEntity fragment : fragments) {
|
||||
ReviewTaskStats stats = statsByTaskNum.get(sessionToTaskNum.get(fragment.getSessionNum()));
|
||||
if (stats != null) {
|
||||
stats.setFragmentCount(stats.getFragmentCount() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user