diff --git a/src/main/java/com/onnoff/onnoff/domain/off/feed/repository/FeedRepository.java b/src/main/java/com/onnoff/onnoff/domain/off/feed/repository/FeedRepository.java index 3aaeb46..2c6648d 100644 --- a/src/main/java/com/onnoff/onnoff/domain/off/feed/repository/FeedRepository.java +++ b/src/main/java/com/onnoff/onnoff/domain/off/feed/repository/FeedRepository.java @@ -10,4 +10,6 @@ public interface FeedRepository extends JpaRepository { List findAllByUserAndDateOrderByCreatedAtAsc(User user, LocalDate date); + Integer countByUserAndDate(User user, LocalDate date); + Integer countByUserAndDateAndIsChecked(User user, LocalDate date, Boolean t); } diff --git a/src/main/java/com/onnoff/onnoff/domain/off/memoir/repository/MemoirAnswerRepository.java b/src/main/java/com/onnoff/onnoff/domain/off/memoir/repository/MemoirAnswerRepository.java index 622335e..c0bb37b 100644 --- a/src/main/java/com/onnoff/onnoff/domain/off/memoir/repository/MemoirAnswerRepository.java +++ b/src/main/java/com/onnoff/onnoff/domain/off/memoir/repository/MemoirAnswerRepository.java @@ -3,5 +3,8 @@ import com.onnoff.onnoff.domain.off.memoir.entity.MemoirAnswer; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + public interface MemoirAnswerRepository extends JpaRepository { + List findAllByMemoirId(Long memoirid); } diff --git a/src/main/java/com/onnoff/onnoff/domain/on/worklog/repository/WorklogRepository.java b/src/main/java/com/onnoff/onnoff/domain/on/worklog/repository/WorklogRepository.java index 8b3def7..4f6cab9 100644 --- a/src/main/java/com/onnoff/onnoff/domain/on/worklog/repository/WorklogRepository.java +++ b/src/main/java/com/onnoff/onnoff/domain/on/worklog/repository/WorklogRepository.java @@ -9,4 +9,7 @@ public interface WorklogRepository extends JpaRepository { List findAllByUserAndDateOrderByCreatedAt(User user, LocalDate date); + Integer countByUserAndDate(User user, LocalDate date); + Integer countByUserAndDateAndIsChecked(User user, LocalDate date, Boolean t); + } diff --git a/src/main/java/com/onnoff/onnoff/domain/stats/controller/StatsController.java b/src/main/java/com/onnoff/onnoff/domain/stats/controller/StatsController.java new file mode 100644 index 0000000..56b4538 --- /dev/null +++ b/src/main/java/com/onnoff/onnoff/domain/stats/controller/StatsController.java @@ -0,0 +1,41 @@ +package com.onnoff.onnoff.domain.stats.controller; + +import com.onnoff.onnoff.apiPayload.ApiResponse; +import com.onnoff.onnoff.domain.stats.dto.StatsResponseDTO; +import com.onnoff.onnoff.domain.stats.service.StatsService; +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/stats") +public class StatsController { + private final StatsService statsService; + + @GetMapping("/week") + @Operation(summary = "요일별 달성률") + public ApiResponse getWeekStats(){ + return ApiResponse.onSuccess(statsService.getWeekStats()); + } + + @GetMapping("/month") + @Operation(summary = "월별 달성률") + public ApiResponse getMonthStats(){ + return ApiResponse.onSuccess(statsService.getMonthStats(null)); + } + + @GetMapping("/month/prev") + @Operation(summary = "이전 달 달성률") + public ApiResponse moveToPrevMonth(@RequestParam(name = "date") LocalDate date){ + return ApiResponse.onSuccess(statsService.getMonthStats(date.minusMonths(1))); + } + + @GetMapping("/month/next") + @Operation(summary = "다음 달 달성률") + public ApiResponse moveToNextMonth(@RequestParam(name = "date") LocalDate date){ + return ApiResponse.onSuccess(statsService.getMonthStats(date.plusMonths(1))); + } +} \ No newline at end of file diff --git a/src/main/java/com/onnoff/onnoff/domain/stats/converter/StatsConverter.java b/src/main/java/com/onnoff/onnoff/domain/stats/converter/StatsConverter.java new file mode 100644 index 0000000..5f42f89 --- /dev/null +++ b/src/main/java/com/onnoff/onnoff/domain/stats/converter/StatsConverter.java @@ -0,0 +1,37 @@ +package com.onnoff.onnoff.domain.stats.converter; + +import com.onnoff.onnoff.domain.stats.dto.StatsResponseDTO; + +import java.time.LocalDate; +import java.util.List; + +public class StatsConverter { + public static StatsResponseDTO.WeekDTO getWeekStatsDTO(LocalDate today, Double on, Double off, + Integer weekOfMonth, List weekStats){ + StatsResponseDTO.WeekStatsDTO weekStatsDTO = StatsResponseDTO.WeekStatsDTO.builder() + .mon(weekStats.get(0)) + .tue(weekStats.get(1)) + .wed(weekStats.get(2)) + .thu(weekStats.get(3)) + .fri(weekStats.get(4)) + .sat(weekStats.get(5)) + .sun(weekStats.get(6)) + .build(); + + return StatsResponseDTO.WeekDTO.builder() + .today(today) + .on(on) + .off(off) + .weekOfMonth(weekOfMonth) + .weekStatsDTO(weekStatsDTO) + .build(); + } + + public static StatsResponseDTO.MonthDTO getMonthStatsDTO(LocalDate date, Integer avg, List monthStatsList){ + return StatsResponseDTO.MonthDTO.builder() + .date(date) + .avg(avg) + .monthStatsList(monthStatsList) + .build(); + } +} diff --git a/src/main/java/com/onnoff/onnoff/domain/stats/dto/StatsResponseDTO.java b/src/main/java/com/onnoff/onnoff/domain/stats/dto/StatsResponseDTO.java new file mode 100644 index 0000000..a5593ad --- /dev/null +++ b/src/main/java/com/onnoff/onnoff/domain/stats/dto/StatsResponseDTO.java @@ -0,0 +1,57 @@ +package com.onnoff.onnoff.domain.stats.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; +import java.util.List; + +public class StatsResponseDTO { + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class WeekStatsDTO{ + Double mon; + Double tue; + Double wed; + Double thu; + Double fri; + Double sat; + Double sun; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class WeekDTO{ + LocalDate today; + Double on; + Double off; + Integer weekOfMonth; + WeekStatsDTO weekStatsDTO; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class MonthStatsDTO{ + LocalDate date; + Double rate; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class MonthDTO{ + LocalDate date; + Integer avg; + List monthStatsList; + } +} diff --git a/src/main/java/com/onnoff/onnoff/domain/stats/service/StatsService.java b/src/main/java/com/onnoff/onnoff/domain/stats/service/StatsService.java new file mode 100644 index 0000000..9161e58 --- /dev/null +++ b/src/main/java/com/onnoff/onnoff/domain/stats/service/StatsService.java @@ -0,0 +1,10 @@ +package com.onnoff.onnoff.domain.stats.service; + +import com.onnoff.onnoff.domain.stats.dto.StatsResponseDTO; + +import java.time.LocalDate; + +public interface StatsService { + StatsResponseDTO.WeekDTO getWeekStats(); + StatsResponseDTO.MonthDTO getMonthStats(LocalDate date); +} diff --git a/src/main/java/com/onnoff/onnoff/domain/stats/service/StatsServiceImpl.java b/src/main/java/com/onnoff/onnoff/domain/stats/service/StatsServiceImpl.java new file mode 100644 index 0000000..36b12f1 --- /dev/null +++ b/src/main/java/com/onnoff/onnoff/domain/stats/service/StatsServiceImpl.java @@ -0,0 +1,123 @@ +package com.onnoff.onnoff.domain.stats.service; + +import com.onnoff.onnoff.auth.UserContext; +import com.onnoff.onnoff.domain.off.feed.repository.FeedRepository; +import com.onnoff.onnoff.domain.off.memoir.entity.Memoir; +import com.onnoff.onnoff.domain.off.memoir.entity.MemoirAnswer; +import com.onnoff.onnoff.domain.off.memoir.repository.MemoirAnswerRepository; +import com.onnoff.onnoff.domain.off.memoir.repository.MemoirRepository; +import com.onnoff.onnoff.domain.on.worklog.repository.WorklogRepository; +import com.onnoff.onnoff.domain.stats.converter.StatsConverter; +import com.onnoff.onnoff.domain.stats.dto.StatsResponseDTO; +import com.onnoff.onnoff.domain.user.User; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.temporal.WeekFields; +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class StatsServiceImpl implements StatsService{ + private final WorklogRepository worklogRepository; + private final FeedRepository feedRepository; + private final MemoirRepository memoirRepository; + private final MemoirAnswerRepository memoirAnswerRepository; + + @Override + public StatsResponseDTO.WeekDTO getWeekStats(){ + LocalDate today = LocalDate.now(); + + User user = UserContext.getUser(); + + Double on = worklogRepository.countByUserAndDateAndIsChecked(user, today, true) / worklogRepository.countByUserAndDate(user, today).doubleValue(); + if(on.isNaN()) { + on = 0.0; + } + Double off = feedRepository.countByUserAndDateAndIsChecked(user, today, true) / feedRepository.countByUserAndDate(user, today).doubleValue(); + if(off.isNaN()) { + off = 0.0; + } + + WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY, 1); + Integer weekOfMonth = today.get(weekFields.weekOfMonth()); + + List weekStats = new ArrayList<>(); + LocalDate monday = today.minusDays(today.getDayOfWeek().getValue() - 1); + for (int i=0; i<7; i++){ + if(i > today.getDayOfWeek().getValue() - 1){ + weekStats.add(0.0); + continue; + } + LocalDate date = monday.plusDays(i); + Double offW = feedRepository.countByUserAndDateAndIsChecked(user, date, true) / feedRepository.countByUserAndDate(user, date).doubleValue(); + if(offW.isNaN()){ + offW = 0.0; + } + + weekStats.add(offW); + } + + return StatsConverter.getWeekStatsDTO(today, on, off, weekOfMonth, weekStats); + } + + @Override + public StatsResponseDTO.MonthDTO getMonthStats(LocalDate date){ + if(date == null){ + date = LocalDate.now(); + } + + Double avg = 0.0; + + User user = UserContext.getUser(); + + List monthStatsList = new ArrayList<>(); + LocalDate localDate = date.minusDays(date.getDayOfMonth() - 1); + for(int i=0; i memoirAnswerList = memoirAnswerRepository.findAllByMemoirId(memoir.getId()).stream().toList(); + for(MemoirAnswer memoirAnswer: memoirAnswerList){ + if(memoirAnswer.getAnswer() != null){ + rate++; + } + } + + StatsResponseDTO.MonthStatsDTO stats = StatsResponseDTO.MonthStatsDTO.builder() + .date(localDate.plusDays(i)) + .rate(rate / 4.0) + .build(); + monthStatsList.add(stats); + + avg += rate / 4.0 * 100; + } + + if(date.equals(LocalDate.now())){ + //이번달은 오늘 기준으로 계산 + avg = avg / date.getDayOfMonth(); + } + else{ + //이외에는 한 달 기준으로 계산 + avg = avg / date.lengthOfMonth(); + } + + return StatsConverter.getMonthStatsDTO(date, Integer.parseInt(String.valueOf(Math.round(avg))), monthStatsList); + } +}