diff --git a/backend/src/main/java/sw_css/admin/milestone/application/MilestoneHistoryAdminQueryService.java b/backend/src/main/java/sw_css/admin/milestone/application/MilestoneHistoryAdminQueryService.java index be7ed504..fe0db93a 100644 --- a/backend/src/main/java/sw_css/admin/milestone/application/MilestoneHistoryAdminQueryService.java +++ b/backend/src/main/java/sw_css/admin/milestone/application/MilestoneHistoryAdminQueryService.java @@ -8,9 +8,11 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.stream.IntStream; import lombok.RequiredArgsConstructor; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; @@ -30,6 +32,7 @@ import sw_css.admin.milestone.application.dto.response.MilestoneHistoryResponse; import sw_css.admin.milestone.application.dto.response.MilestoneScoreResponse; import sw_css.admin.milestone.persistence.StudentAndMilestoneScoreInfo; +import sw_css.admin.milestone.persistence.StudentAndMilestoneTotalScoreInfoMapping; import sw_css.member.application.dto.response.StudentMemberReferenceResponse; import sw_css.milestone.application.dto.response.MilestoneScoreOfStudentResponse; import sw_css.milestone.domain.MilestoneCategory; @@ -173,31 +176,31 @@ public Page findAllMilestoneHistoryScores(final String s final Pageable pageable) { final LocalDate parsedStartDate = parseDate(startDate); final LocalDate parsedEndDate = parseDate(endDate); - final long categoryCount = milestoneCategoryRepository.count(); - final List milestoneHistoryInfos = milestoneScoreRepository.findMilestoneScoresWithStudentInfoByPeriod( - parsedStartDate, parsedEndDate, pageable.getPageNumber() * pageable.getPageSize() * categoryCount, - pageable.getPageSize() * categoryCount); + final List milestoneHistoryInfos = milestoneScoreRepository.findMilestoneScoresWithStudentInfoByPeriod( + parsedStartDate, parsedEndDate, pageable.getPageNumber() * pageable.getPageSize() * 1L, pageable.getPageSize() * 1L); + + System.out.println(milestoneHistoryInfos); + final Long totalMilestoneHistoryInfoCount = milestoneScoreRepository.countAllMilestoneScoresWithStudentInfoByPeriod(); - final Map> groupedMilestoneScoresByStudentId = milestoneHistoryInfos.stream() - .collect(groupingBy( - (info -> new StudentMemberReferenceResponse(info.studentId(), info.studentName())))); - final List content = groupedMilestoneScoresByStudentId.entrySet() - .stream() - .map(entry -> new MilestoneScoreResponse( - entry.getKey(), - entry.getValue() - .stream() - .map(info -> new MilestoneScoreOfStudentResponse( - info.categoryId(), info.categoryName(), info.milestoneGroup(), - info.limitScore(), info.score())) - .collect(groupingBy(MilestoneScoreOfStudentResponse::group)))) - .sorted(Comparator.comparing( - (MilestoneScoreResponse response) -> response.milestoneScores().entrySet().stream() - .flatMap(entry -> entry.getValue().stream()) - .mapToInt(MilestoneScoreOfStudentResponse::score) - .sum() - ).reversed()) - .toList(); + + final List content = milestoneHistoryInfos.stream().map(entry -> { + Long[] categoryIds = Arrays.stream(entry.categoryIds().split(",")).map(Long::valueOf).toArray(Long[]::new); + String[] categoryNames = entry.categoryNames().split(","); + MilestoneGroup[] milestoneGroups = Arrays.stream(entry.milestoneGroups().split(",")).map(MilestoneGroup::valueOf).toArray(MilestoneGroup[]::new); + Integer[] scores = Arrays.stream(entry.scores().split(",")).map(Integer::valueOf).toArray(Integer[]::new); + Integer[] limitScores = Arrays.stream(entry.limitScores().split(",")).map(Integer::valueOf).toArray(Integer[]::new); + + return new MilestoneScoreResponse( + new StudentMemberReferenceResponse(entry.studentId(), entry.studentName()), + IntStream.range(0, categoryIds.length).mapToObj(i -> new MilestoneScoreOfStudentResponse( + categoryIds[i], categoryNames[i], milestoneGroups[i], limitScores[i], scores[i])) + .sorted(Comparator.comparing(MilestoneScoreOfStudentResponse::id)) + .collect(groupingBy(MilestoneScoreOfStudentResponse::group)) + ); + }).toList(); + + System.out.println(content); + return new PageImpl<>(content, pageable, totalMilestoneHistoryInfoCount); } diff --git a/backend/src/main/java/sw_css/admin/milestone/persistence/StudentAndMilestoneTotalScoreInfoMapping.java b/backend/src/main/java/sw_css/admin/milestone/persistence/StudentAndMilestoneTotalScoreInfoMapping.java new file mode 100644 index 00000000..d35fea7f --- /dev/null +++ b/backend/src/main/java/sw_css/admin/milestone/persistence/StudentAndMilestoneTotalScoreInfoMapping.java @@ -0,0 +1,17 @@ +package sw_css.admin.milestone.persistence; + +import jakarta.persistence.ColumnResult; +import java.lang.reflect.Array; +import java.util.List; +import sw_css.milestone.domain.MilestoneGroup; + +public record StudentAndMilestoneTotalScoreInfoMapping( + Long studentId, + String studentName, + String categoryIds, + String categoryNames, + String milestoneGroups, + String limitScores, + String scores, + Long totalScore) { +} diff --git a/backend/src/main/java/sw_css/milestone/domain/MilestoneHistory.java b/backend/src/main/java/sw_css/milestone/domain/MilestoneHistory.java index ca310020..d6dd5e83 100644 --- a/backend/src/main/java/sw_css/milestone/domain/MilestoneHistory.java +++ b/backend/src/main/java/sw_css/milestone/domain/MilestoneHistory.java @@ -18,10 +18,12 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.Array; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; import sw_css.admin.milestone.domain.MilestoneHistoryExcelData; import sw_css.admin.milestone.persistence.StudentAndMilestoneScoreInfo; +import sw_css.admin.milestone.persistence.StudentAndMilestoneTotalScoreInfoMapping; import sw_css.base.BaseEntity; import sw_css.member.domain.StudentMember; import sw_css.milestone.exception.MilestoneHistoryException; @@ -47,6 +49,21 @@ @ColumnResult(name = "score", type = Integer.class) } )) +@SqlResultSetMapping( + name = "StudentAndMilestoneTotalScoreInfoMapping", + classes = @ConstructorResult( + targetClass = StudentAndMilestoneTotalScoreInfoMapping.class, + columns = { + @ColumnResult(name = "studentId", type = Long.class), + @ColumnResult(name = "studentName", type = String.class), + @ColumnResult(name = "categoryIds", type = String.class), + @ColumnResult(name = "categoryNames", type = String.class), + @ColumnResult(name = "milestoneGroups", type = String.class), + @ColumnResult(name = "limitScores", type = String.class), + @ColumnResult(name = "scores", type = String.class), + @ColumnResult(name = "totalScore", type = Long.class), + } + )) public class MilestoneHistory extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/backend/src/main/java/sw_css/milestone/domain/repository/MilestoneScoreRepository.java b/backend/src/main/java/sw_css/milestone/domain/repository/MilestoneScoreRepository.java index 1ab635a6..bd1ed122 100644 --- a/backend/src/main/java/sw_css/milestone/domain/repository/MilestoneScoreRepository.java +++ b/backend/src/main/java/sw_css/milestone/domain/repository/MilestoneScoreRepository.java @@ -3,11 +3,12 @@ import java.time.LocalDate; import java.util.List; import sw_css.admin.milestone.persistence.StudentAndMilestoneScoreInfo; +import sw_css.admin.milestone.persistence.StudentAndMilestoneTotalScoreInfoMapping; public interface MilestoneScoreRepository { - List findMilestoneScoresWithStudentInfoByPeriod(LocalDate startDate, - LocalDate endDate, Long page, - Long pageSize); + List findMilestoneScoresWithStudentInfoByPeriod(LocalDate startDate, + LocalDate endDate, Long page, + Long pageSize); List findAllMilestoneScoresWithStudentInfoByPeriod(LocalDate startDate, LocalDate endDate); diff --git a/backend/src/main/java/sw_css/milestone/persistence/MilestoneScoreRepositoryImpl.java b/backend/src/main/java/sw_css/milestone/persistence/MilestoneScoreRepositoryImpl.java index bdbdf269..a96c929c 100644 --- a/backend/src/main/java/sw_css/milestone/persistence/MilestoneScoreRepositoryImpl.java +++ b/backend/src/main/java/sw_css/milestone/persistence/MilestoneScoreRepositoryImpl.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import sw_css.admin.milestone.persistence.StudentAndMilestoneScoreInfo; +import sw_css.admin.milestone.persistence.StudentAndMilestoneTotalScoreInfoMapping; import sw_css.milestone.domain.repository.MilestoneScoreRepository; @Repository @@ -16,12 +17,13 @@ public class MilestoneScoreRepositoryImpl implements MilestoneScoreRepository { private EntityManager entityManager; @Override - public List findMilestoneScoresWithStudentInfoByPeriod(LocalDate startDate, - LocalDate endDate, - Long page, Long pageSize) { + public List findMilestoneScoresWithStudentInfoByPeriod(LocalDate startDate, + LocalDate endDate, + Long page, Long pageSize) { String sql = - "select test.studentId, test.studentName, test.category_id as categoryId, test.name as categoryName ,test.milestone_group as milestoneGroup, test.limit_score as limitScore, ifNull(least(if(sum(test.limit_count)=0,max(test.milestone_score),sum(test.milestone_score)),test.limit_score),0) as score from " + "select t.studentId, t.studentName, group_concat(t.categoryId) as categoryIds, group_concat(t.categoryName) as categoryNames, group_concat(t.milestoneGroup) as milestoneGroups, group_concat(t.limitScore) as limitScores, group_concat(t.score) as scores, sum(t.score) as totalScore from " + + "(SELECT test.studentId, test.studentName, test.category_id as categoryId, test.name as categoryName ,test.milestone_group as milestoneGroup, test.limit_score as limitScore, ifNull(least(if(sum(test.limit_count)=0,max(test.milestone_score),sum(test.milestone_score)),test.limit_score),0) as score from " + " (SELECT s2.studentId, s2.studentName,mc.limit_score,m.category_id,mc.name,mc.milestone_group, m.limit_count,m.score,least(sum(mh.count), greatest(m.limit_count,1)), least(sum(mh.count), greatest(m.limit_count,1))*m.score as milestone_score " + "FROM (SELECT DISTINCT(COALESCE(mh.student_id, sm.id)) as studentId, COALESCE(m.name,'') as studentName FROM student_member sm " + "LEFT JOIN milestone_history mh on mh.student_id=sm.id " @@ -35,10 +37,12 @@ public List findMilestoneScoresWithStudentInfoByPe + "LEFT JOIN milestone_history mh on m.id=mh.milestone_id and mh.student_id=s2.studentId and mh.activated_at <= :endDate AND mh.activated_at >= :startDate AND mh.is_deleted=false AND mh.status='APPROVED' " + "group by s2.studentId, studentName, m.id) as test " + "group by test.studentId, test.studentName, test.category_id " - + "order by test.studentId, test.category_id " + + "order by test.category_id) t " + + "group by t.studentId, t.studentName " + + "order by totalScore DESC " + "LIMIT :page, :pageSize"; - Query query = entityManager.createNativeQuery(sql, "StudentAndMilestoneScoreInfoMapping"); + Query query = entityManager.createNativeQuery(sql, "StudentAndMilestoneTotalScoreInfoMapping"); query.setParameter("startDate", startDate); query.setParameter("endDate", endDate); query.setParameter("page", page); diff --git a/backend/src/main/resources/data.sql b/backend/src/main/resources/data.sql index 6af9e695..5cd108e1 100644 --- a/backend/src/main/resources/data.sql +++ b/backend/src/main/resources/data.sql @@ -281,11 +281,11 @@ values (1, '비교과', 20, 2); insert into milestone (category_id, name, score, limit_count) values (2, '수준3 이상', 60, 0); insert into milestone (category_id, name, score, limit_count) -values (2, '수준2 이상', 50, 0); +values (2, '수준2 이상', 30, 0); insert into milestone (category_id, name, score, limit_count) values (3, 'PCCP Lv.3 이상', 60, 0); insert into milestone (category_id, name, score, limit_count) -values (3, 'PCCP Lv.1 이상', 50, 0); +values (3, 'PCCP Lv.1 이상', 40, 0); insert into milestone (category_id, name, score, limit_count) values (4, 'SW관련 경진대회 및 공모전 수상', 20, 3); insert into milestone (category_id, name, score, limit_count) diff --git a/backend/src/main/resources/static/files/history_standard.pdf b/backend/src/main/resources/static/files/history_standard.pdf index ab37a178..be9dbe12 100644 Binary files a/backend/src/main/resources/static/files/history_standard.pdf and b/backend/src/main/resources/static/files/history_standard.pdf differ diff --git a/frontend/public/images/milestone/milestone_img03.png b/frontend/public/images/milestone/milestone_img03.png index 053b4cff..1b28de20 100644 Binary files a/frontend/public/images/milestone/milestone_img03.png and b/frontend/public/images/milestone/milestone_img03.png differ diff --git a/frontend/src/app/(client)/(withSidebar)/milestone/page.tsx b/frontend/src/app/(client)/(withSidebar)/milestone/page.tsx index 7a51e510..9bf6d0b0 100644 --- a/frontend/src/app/(client)/(withSidebar)/milestone/page.tsx +++ b/frontend/src/app/(client)/(withSidebar)/milestone/page.tsx @@ -46,7 +46,7 @@ const Page = () => ( 로그인 후, 메인 페이지와 마이페이지에서 확인하실 수 있습니다. - +