From 944c8b0911306101c844354f29bf94d7eacb8ccb Mon Sep 17 00:00:00 2001 From: Seoyoung2222 Date: Mon, 2 Dec 2024 21:42:27 +0900 Subject: [PATCH] =?UTF-8?q?BE:=20[feat]=20=EB=A9=94=EC=9D=B8=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EA=B5=AC=EC=84=B1=20#153?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/UserCourseRepository.java | 11 ++ .../home/controller/HomeController.java | 40 ++++++ .../domain/home/dto/CrewRankResponseDto.java | 15 ++ .../domain/home/dto/HomePageResponseDto.java | 14 ++ .../domain/home/dto/TodayRunResponseDto.java | 12 ++ .../R2R/domain/home/service/HomeService.java | 128 ++++++++++++++++++ 6 files changed, 220 insertions(+) create mode 100644 src/backend/src/main/java/RunningMachines/R2R/domain/home/controller/HomeController.java create mode 100644 src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/CrewRankResponseDto.java create mode 100644 src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/HomePageResponseDto.java create mode 100644 src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/TodayRunResponseDto.java create mode 100644 src/backend/src/main/java/RunningMachines/R2R/domain/home/service/HomeService.java diff --git a/src/backend/src/main/java/RunningMachines/R2R/domain/course/repository/UserCourseRepository.java b/src/backend/src/main/java/RunningMachines/R2R/domain/course/repository/UserCourseRepository.java index 4fd77190..c2fa7781 100644 --- a/src/backend/src/main/java/RunningMachines/R2R/domain/course/repository/UserCourseRepository.java +++ b/src/backend/src/main/java/RunningMachines/R2R/domain/course/repository/UserCourseRepository.java @@ -2,6 +2,17 @@ import RunningMachines.R2R.domain.course.entity.UserCourse; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.time.LocalDateTime; +import java.util.List; public interface UserCourseRepository extends JpaRepository { + @Query("SELECT uc FROM UserCourse uc WHERE uc.user.id = :userId AND uc.createdAt BETWEEN :startDateTime AND :endDateTime") + List findByUserIdAndDateRange( + @Param("userId") Long userId, + @Param("startDateTime") LocalDateTime startDateTime, + @Param("endDateTime") LocalDateTime endDateTime + ); } diff --git a/src/backend/src/main/java/RunningMachines/R2R/domain/home/controller/HomeController.java b/src/backend/src/main/java/RunningMachines/R2R/domain/home/controller/HomeController.java new file mode 100644 index 00000000..400b190a --- /dev/null +++ b/src/backend/src/main/java/RunningMachines/R2R/domain/home/controller/HomeController.java @@ -0,0 +1,40 @@ +package RunningMachines.R2R.domain.home.controller; + +import RunningMachines.R2R.domain.home.service.HomeService; +import RunningMachines.R2R.domain.user.service.AuthCommandService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +@RequestMapping("/home") +@RequiredArgsConstructor +public class HomeController { + private final HomeService homeService; + private final AuthCommandService authCommandService; + + @GetMapping("/user") + public ResponseEntity> getDailyUserRecords() { + // 현재 로그인한 사용자 ID 가져오기 + Long userId = authCommandService.getCurrentUser().getId(); + // 일일 기록 데이터 가져오기 + Map response = homeService.getDailyUserRecord(userId); + return ResponseEntity.ok(response); + } + + /** + * 주간 크루 기록 조회 + * @return 주간 거리 랭킹 및 페이스 랭킹 + */ + @GetMapping("/crews") + public ResponseEntity> getWeeklyCrewRecords() { + // 주간 크루 기록 데이터 가져오기 + Map response = homeService.getWeeklyCrewRecords(); + return ResponseEntity.ok(response); + } +} diff --git a/src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/CrewRankResponseDto.java b/src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/CrewRankResponseDto.java new file mode 100644 index 00000000..76b26f34 --- /dev/null +++ b/src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/CrewRankResponseDto.java @@ -0,0 +1,15 @@ +package RunningMachines.R2R.domain.home.dto; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class CrewRankResponseDto { + private Long crewId; + private String crewName; + private String crewProfileUrl; + private String value; + private double totalDistance; + private double averagePace; +} diff --git a/src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/HomePageResponseDto.java b/src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/HomePageResponseDto.java new file mode 100644 index 00000000..f3d53f1e --- /dev/null +++ b/src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/HomePageResponseDto.java @@ -0,0 +1,14 @@ +package RunningMachines.R2R.domain.home.dto; + +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Getter +@Builder +public class HomePageResponseDto { + private TodayRunResponseDto todayRun; + private List topDistanseCrews; + private List topPaceCrews; +} diff --git a/src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/TodayRunResponseDto.java b/src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/TodayRunResponseDto.java new file mode 100644 index 00000000..6c5829ec --- /dev/null +++ b/src/backend/src/main/java/RunningMachines/R2R/domain/home/dto/TodayRunResponseDto.java @@ -0,0 +1,12 @@ +package RunningMachines.R2R.domain.home.dto; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class TodayRunResponseDto { + private double totalDistance; + private String averagePace; + private int totalDuration; +} diff --git a/src/backend/src/main/java/RunningMachines/R2R/domain/home/service/HomeService.java b/src/backend/src/main/java/RunningMachines/R2R/domain/home/service/HomeService.java new file mode 100644 index 00000000..27d014f4 --- /dev/null +++ b/src/backend/src/main/java/RunningMachines/R2R/domain/home/service/HomeService.java @@ -0,0 +1,128 @@ +package RunningMachines.R2R.domain.home.service; + +import RunningMachines.R2R.domain.course.entity.UserCourse; +import RunningMachines.R2R.domain.course.repository.UserCourseRepository; +import RunningMachines.R2R.domain.crew.common.entity.Crew; +import RunningMachines.R2R.domain.crew.common.entity.CrewUser; +import RunningMachines.R2R.domain.crew.common.repository.CrewRepository; +import RunningMachines.R2R.domain.user.entity.User; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.ChronoField; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class HomeService { + private final UserCourseRepository userCourseRepository; + private final CrewRepository crewRepository; + + public Map getWeeklyCrewRecords() { + // Define start and end of the current week + LocalDateTime startOfWeek = LocalDate.now().with(ChronoField.DAY_OF_WEEK, 1).atStartOfDay(); + LocalDateTime endOfWeek = startOfWeek.plusDays(6).with(LocalTime.MAX); + + // Fetch all crews + List crews = crewRepository.findAll(); + + // Calculate rankings for distance and pace + List> distanceRankings = new ArrayList<>(); + List> paceRankings = new ArrayList<>(); + + for (Crew crew : crews) { + // Get all users in the crew + List crewUsers = crew.getCrewUsers().stream() + .map(cu -> cu.getUser()) + .collect(Collectors.toList()); + + // Calculate total distance and total duration + double totalDistance = crewUsers.stream() + .flatMap(user -> userCourseRepository.findByUserIdAndDateRange(user.getId(), startOfWeek, endOfWeek).stream()) + .mapToDouble(UserCourse::getDistance) + .sum(); + + int totalDuration = crewUsers.stream() + .flatMap(user -> userCourseRepository.findByUserIdAndDateRange(user.getId(), startOfWeek, endOfWeek).stream()) + .mapToInt(UserCourse::getDuration) + .sum(); + + String averagePace = formatPace(totalDistance, totalDuration); + + // Add to distance ranking + Map distanceRanking = new HashMap<>(); + distanceRanking.put("crewId", crew.getId()); + distanceRanking.put("title", crew.getTitle()); + distanceRanking.put("image", crew.getImages() != null ? crew.getImages().getImageUrl() : null); + distanceRanking.put("distance", String.format("%.2fKM", totalDistance)); + distanceRankings.add(distanceRanking); + + // Add to pace ranking + Map paceRanking = new HashMap<>(); + paceRanking.put("crewId", crew.getId()); + paceRanking.put("title", crew.getTitle()); + paceRanking.put("image", crew.getImages() != null ? crew.getImages().getImageUrl() : null); + paceRanking.put("averagePace", averagePace); + paceRankings.add(paceRanking); + } + + // Sort rankings + distanceRankings.sort(Comparator.comparing((Map m) -> Double.parseDouble(m.get("distance").toString().replace("KM", ""))).reversed()); + paceRankings.sort(Comparator.comparing((Map m) -> parsePaceToSeconds(m.get("averagePace").toString()))); + + // Prepare the response + Map response = new HashMap<>(); + response.put("distanceRankings", distanceRankings.stream().limit(3).collect(Collectors.toList())); + response.put("paceRankings", paceRankings.stream().limit(3).collect(Collectors.toList())); + + return response; + } + + public Map getDailyUserRecord(Long userId) { + // Define start and end of the current day + LocalDateTime startOfDay = LocalDate.now().atStartOfDay(); + LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX); + + // Fetch the user's daily records + List userCourses = userCourseRepository.findByUserIdAndDateRange(userId, startOfDay, endOfDay); + + // Calculate total distance, total duration, and average pace + double totalDistance = userCourses.stream().mapToDouble(UserCourse::getDistance).sum(); + int totalDuration = userCourses.stream().mapToInt(UserCourse::getDuration).sum(); // duration in minutes + String averagePace = formatPace(totalDistance, totalDuration); + + // Prepare the response + Map response = new HashMap<>(); + response.put("totalDistance", String.format("%.2fKM", totalDistance)); + response.put("totalDuration", formatDuration(totalDuration)); + response.put("averagePace", averagePace); + + return response; + } + + private String formatPace(double totalDistance, int totalDuration) { + if (totalDistance <= 0) return "0'00''"; + int totalSeconds = (int) (totalDuration * 60 / totalDistance); + int minutes = totalSeconds / 60; + int seconds = totalSeconds % 60; + return String.format("%d'%02d''", minutes, seconds); + } + + private int parsePaceToSeconds(String pace) { + String[] parts = pace.split("[']"); + int minutes = Integer.parseInt(parts[0]); + int seconds = Integer.parseInt(parts[1].replace("''", "")); + return minutes * 60 + seconds; + } + + private String formatDuration(int totalMinutes) { + int hours = totalMinutes / 60; + int minutes = totalMinutes % 60; + return String.format("%dh %02dm", hours, minutes); + } +} +